From bf01151bbb793c36431820bd814db775bf10a870 Mon Sep 17 00:00:00 2001 From: HybridChild Date: Sun, 27 Jul 2025 08:27:09 +0200 Subject: stm32/i2c_v1: Remove redundant timing config abstractions for DutyCycle and I2C mode --- embassy-stm32/src/i2c/v1.rs | 79 ++++++++++++++------------------------------- 1 file changed, 24 insertions(+), 55 deletions(-) diff --git a/embassy-stm32/src/i2c/v1.rs b/embassy-stm32/src/i2c/v1.rs index 081eb1191..a1ad9caef 100644 --- a/embassy-stm32/src/i2c/v1.rs +++ b/embassy-stm32/src/i2c/v1.rs @@ -14,7 +14,7 @@ use embedded_hal_1::i2c::Operation; use mode::Master; use super::*; -use crate::mode::Mode as PeriMode; +use crate::mode::Mode; use crate::pac::i2c; // /!\ /!\ @@ -42,7 +42,7 @@ pub unsafe fn on_interrupt() { }); } -impl<'d, M: PeriMode, IM: MasterMode> I2c<'d, M, IM> { +impl<'d, M: Mode, IM: MasterMode> I2c<'d, M, IM> { pub(crate) fn init(&mut self, config: Config) { self.info.regs.cr1().modify(|reg| { reg.set_pe(false); @@ -81,8 +81,8 @@ impl<'d, M: PeriMode, IM: MasterMode> I2c<'d, M, IM> { reg.set_freq(timings.freq); }); self.info.regs.ccr().modify(|reg| { - reg.set_f_s(timings.mode.f_s()); - reg.set_duty(timings.duty.duty()); + reg.set_f_s(timings.f_s); + reg.set_duty(timings.duty); reg.set_ccr(timings.ccr); }); self.info.regs.trise().modify(|reg| { @@ -701,40 +701,18 @@ impl<'d, IM: MasterMode> I2c<'d, Async, IM> { } } -enum Mode { - Fast, - Standard, -} - -impl Mode { - fn f_s(&self) -> i2c::vals::FS { - match self { - Mode::Fast => i2c::vals::FS::FAST, - Mode::Standard => i2c::vals::FS::STANDARD, - } - } -} - -enum Duty { - Duty2_1, - Duty16_9, -} - -impl Duty { - fn duty(&self) -> i2c::vals::Duty { - match self { - Duty::Duty2_1 => i2c::vals::Duty::DUTY2_1, - Duty::Duty16_9 => i2c::vals::Duty::DUTY16_9, - } - } -} +/// Timing configuration for I2C v1 hardware +/// +/// This struct encapsulates the complex timing calculations required for STM32 I2C v1 +/// peripherals, which use three separate registers (CR2.FREQ, CCR, TRISE) instead of +/// the unified TIMINGR register found in v2 hardware. struct Timings { - freq: u8, - mode: Mode, - trise: u8, - ccr: u16, - duty: Duty, + freq: u8, // APB frequency in MHz for CR2.FREQ register + f_s: i2c::vals::FS, // Standard or Fast mode selection + trise: u8, // Rise time compensation value + ccr: u16, // Clock control register value + duty: i2c::vals::Duty, // Fast mode duty cycle selection } impl Timings { @@ -754,12 +732,12 @@ impl Timings { let mut ccr; let duty; - let mode; + let f_s; // I2C clock control calculation if frequency <= 100_000 { - duty = Duty::Duty2_1; - mode = Mode::Standard; + duty = i2c::vals::Duty::DUTY2_1; + f_s = i2c::vals::FS::STANDARD; ccr = { let ccr = clock / (frequency * 2); if ccr < 4 { @@ -770,38 +748,29 @@ impl Timings { }; } else { const DUTYCYCLE: u8 = 0; - mode = Mode::Fast; + f_s = i2c::vals::FS::FAST; if DUTYCYCLE == 0 { - duty = Duty::Duty2_1; + duty = i2c::vals::Duty::DUTY2_1; ccr = clock / (frequency * 3); ccr = if ccr < 1 { 1 } else { ccr }; - - // Set clock to fast mode with appropriate parameters for selected speed (2:1 duty cycle) } else { - duty = Duty::Duty16_9; + duty = i2c::vals::Duty::DUTY16_9; ccr = clock / (frequency * 25); ccr = if ccr < 1 { 1 } else { ccr }; - - // Set clock to fast mode with appropriate parameters for selected speed (16:9 duty cycle) } } Self { freq: freq as u8, + f_s, trise: trise as u8, ccr: ccr as u16, duty, - mode, - //prescale: presc_reg, - //scll, - //sclh, - //sdadel, - //scldel, } } } -impl<'d, M: PeriMode> SetConfig for I2c<'d, M, Master> { +impl<'d, M: Mode> SetConfig for I2c<'d, M, Master> { type Config = Hertz; type ConfigError = (); fn set_config(&mut self, config: &Self::Config) -> Result<(), ()> { @@ -810,8 +779,8 @@ impl<'d, M: PeriMode> SetConfig for I2c<'d, M, Master> { reg.set_freq(timings.freq); }); self.info.regs.ccr().modify(|reg| { - reg.set_f_s(timings.mode.f_s()); - reg.set_duty(timings.duty.duty()); + reg.set_f_s(timings.f_s); + reg.set_duty(timings.duty); reg.set_ccr(timings.ccr); }); self.info.regs.trise().modify(|reg| { -- cgit From 399ec8d90f1c4f62fd20d21dabbb9ce64c6986eb Mon Sep 17 00:00:00 2001 From: HybridChild Date: Sun, 27 Jul 2025 10:35:52 +0200 Subject: stm32/i2c: Rename FrameOptions enum to OperationFraming --- embassy-stm32/src/i2c/mod.rs | 185 +++++++++++++++++++++++++------------------ embassy-stm32/src/i2c/v1.rs | 28 +++---- 2 files changed, 124 insertions(+), 89 deletions(-) diff --git a/embassy-stm32/src/i2c/mod.rs b/embassy-stm32/src/i2c/mod.rs index 5fb49f943..f51682900 100644 --- a/embassy-stm32/src/i2c/mod.rs +++ b/embassy-stm32/src/i2c/mod.rs @@ -435,88 +435,117 @@ impl<'d, IM: MasterMode> embedded_hal_async::i2c::I2c for I2c<'d, Async, IM> { } } -/// Frame type in I2C transaction. +/// Operation framing configuration for I2C transactions. /// -/// This tells each method what kind of framing to use, to generate a (repeated) start condition (ST -/// or SR), and/or a stop condition (SP). For read operations, this also controls whether to send an -/// ACK or NACK after the last byte received. +/// This determines the I2C frame boundaries for each operation within a transaction, +/// controlling the generation of start conditions (ST or SR), stop conditions (SP), +/// and ACK/NACK behavior for read operations. /// -/// For write operations, the following options are identical because they differ only in the (N)ACK -/// treatment relevant for read operations: +/// For write operations, some framing configurations are functionally identical +/// because they differ only in ACK/NACK treatment which is relevant only for reads: /// -/// - `FirstFrame` and `FirstAndNextFrame` -/// - `NextFrame` and `LastFrameNoStop` -/// -/// Abbreviations used below: +/// - `First` and `FirstAndNext` behave identically for writes +/// - `Next` and `LastNoStop` behave identically for writes /// +/// **Framing Legend:** /// - `ST` = start condition -/// - `SR` = repeated start condition +/// - `SR` = repeated start condition /// - `SP` = stop condition -/// - `ACK`/`NACK` = last byte in read operation +/// - `ACK/NACK` = acknowledgment behavior for the final byte of read operations #[derive(Copy, Clone)] #[allow(dead_code)] -enum FrameOptions { - /// `[ST/SR]+[NACK]+[SP]` First frame (of this type) in transaction and also last frame overall. - FirstAndLastFrame, - /// `[ST/SR]+[NACK]` First frame of this type in transaction, last frame in a read operation but - /// not the last frame overall. - FirstFrame, - /// `[ST/SR]+[ACK]` First frame of this type in transaction, neither last frame overall nor last - /// frame in a read operation. - FirstAndNextFrame, - /// `[ACK]` Middle frame in a read operation (neither first nor last). - NextFrame, - /// `[NACK]+[SP]` Last frame overall in this transaction but not the first frame. - LastFrame, - /// `[NACK]` Last frame in a read operation but not last frame overall in this transaction. - LastFrameNoStop, +enum OperationFraming { + /// `[ST/SR]+[NACK]+[SP]` - First operation of its type in the transaction and also the final operation overall. + FirstAndLast, + /// `[ST/SR]+[NACK]` - First operation of its type in the transaction, final operation in a read sequence, but not the final operation overall. + First, + /// `[ST/SR]+[ACK]` - First operation of its type in the transaction, but neither the final operation overall nor the final operation in a read sequence. + FirstAndNext, + /// `[ACK]` - Continuation operation in a read sequence (neither first nor last). + Next, + /// `[NACK]+[SP]` - Final operation overall in the transaction, but not the first operation of its type. + Last, + /// `[NACK]` - Final operation in a read sequence, but not the final operation overall in the transaction. + LastNoStop, } #[allow(dead_code)] -impl FrameOptions { - /// Sends start or repeated start condition before transfer. +impl OperationFraming { + /// Returns true if a start or repeated start condition should be generated before this operation. fn send_start(self) -> bool { match self { - Self::FirstAndLastFrame | Self::FirstFrame | Self::FirstAndNextFrame => true, - Self::NextFrame | Self::LastFrame | Self::LastFrameNoStop => false, + Self::FirstAndLast | Self::First | Self::FirstAndNext => true, + Self::Next | Self::Last | Self::LastNoStop => false, } } - /// Sends stop condition after transfer. + /// Returns true if a stop condition should be generated after this operation. fn send_stop(self) -> bool { match self { - Self::FirstAndLastFrame | Self::LastFrame => true, - Self::FirstFrame | Self::FirstAndNextFrame | Self::NextFrame | Self::LastFrameNoStop => false, + Self::FirstAndLast | Self::Last => true, + Self::First | Self::FirstAndNext | Self::Next | Self::LastNoStop => false, } } - /// Sends NACK after last byte received, indicating end of read operation. + /// Returns true if NACK should be sent after the last byte received in a read operation. + /// + /// This signals the end of a read sequence and releases the bus for the master's + /// next transmission (or stop condition). fn send_nack(self) -> bool { match self { - Self::FirstAndLastFrame | Self::FirstFrame | Self::LastFrame | Self::LastFrameNoStop => true, - Self::FirstAndNextFrame | Self::NextFrame => false, + Self::FirstAndLast | Self::First | Self::Last | Self::LastNoStop => true, + Self::FirstAndNext | Self::Next => false, } } } -/// Iterates over operations in transaction. +/// Analyzes I2C transaction operations and assigns appropriate framing to each. +/// +/// This function processes a sequence of I2C operations and determines the correct +/// framing configuration for each operation to ensure proper I2C protocol compliance. +/// It handles the complex logic of: +/// +/// - Generating start conditions for the first operation of each type (read/write) +/// - Generating stop conditions for the final operation in the entire transaction +/// - Managing ACK/NACK behavior for read operations, including merging consecutive reads +/// - Ensuring proper bus handoff between different operation types +/// +/// **Transaction Contract Compliance:** +/// The framing assignments ensure compliance with the embedded-hal I2C transaction contract, +/// where consecutive operations of the same type are logically merged while maintaining +/// proper protocol boundaries. /// -/// Returns necessary frame options for each operation to uphold the [transaction contract] and have -/// the right start/stop/(N)ACK conditions on the wire. +/// **Error Handling:** +/// Returns an error if any read operation has an empty buffer, as this would create +/// an invalid I2C transaction that could halt mid-execution. /// -/// [transaction contract]: embedded_hal_1::i2c::I2c::transaction +/// # Arguments +/// * `operations` - Mutable slice of I2C operations from embedded-hal +/// +/// # Returns +/// An iterator over (operation, framing) pairs, or an error if the transaction is invalid +/// +/// # Example +/// ```rust +/// for (op, framing) in assign_operation_framing(operations)? { +/// match op { +/// Operation::Read(buffer) => self.read_with_framing(addr, buffer, framing).await?, +/// Operation::Write(data) => self.write_with_framing(addr, data, framing).await?, +/// } +/// } +/// ``` #[allow(dead_code)] -fn operation_frames<'a, 'b: 'a>( +fn assign_operation_framing<'a, 'b: 'a>( operations: &'a mut [embedded_hal_1::i2c::Operation<'b>], -) -> Result, FrameOptions)>, Error> { +) -> Result, OperationFraming)>, Error> { use embedded_hal_1::i2c::Operation::{Read, Write}; - // Check empty read buffer before starting transaction. Otherwise, we would risk halting with an - // error in the middle of the transaction. + // Validate that no read operations have empty buffers before starting the transaction. + // Empty read operations would risk halting with an error mid-transaction. // - // In principle, we could allow empty read frames within consecutive read operations, as long as - // at least one byte remains in the final (merged) read operation, but that makes the logic more - // complicated and error-prone. + // Note: We could theoretically allow empty read operations within consecutive read + // sequences as long as the final merged read has at least one byte, but this would + // complicate the logic significantly and create error-prone edge cases. if operations.iter().any(|op| match op { Read(read) => read.is_empty(), Write(_) => false, @@ -525,46 +554,52 @@ fn operation_frames<'a, 'b: 'a>( } let mut operations = operations.iter_mut().peekable(); - - let mut next_first_frame = true; + let mut next_first_operation = true; Ok(iter::from_fn(move || { - let op = operations.next()?; + let current_op = operations.next()?; - // Is `op` first frame of its type? - let first_frame = next_first_frame; + // Determine if this is the first operation of its type (read or write) + let is_first_of_type = next_first_operation; let next_op = operations.peek(); - // Get appropriate frame options as combination of the following properties: + // Compute the appropriate framing based on three key properties: // - // - For each first operation of its type, generate a (repeated) start condition. - // - For the last operation overall in the entire transaction, generate a stop condition. - // - For read operations, check the next operation: if it is also a read operation, we merge - // these and send ACK for all bytes in the current operation; send NACK only for the final - // read operation's last byte (before write or end of entire transaction) to indicate last - // byte read and release the bus for transmission of the bus master's next byte (or stop). + // 1. **Start Condition**: Generate (repeated) start for first operation of each type + // 2. **Stop Condition**: Generate stop for the final operation in the entire transaction + // 3. **ACK/NACK for Reads**: For read operations, send ACK if more reads follow in the + // sequence, or NACK for the final read in a sequence (before write or transaction end) // - // We check the third property unconditionally, i.e. even for write opeartions. This is okay - // because the resulting frame options are identical for write operations. - let frame = match (first_frame, next_op) { - (true, None) => FrameOptions::FirstAndLastFrame, - (true, Some(Read(_))) => FrameOptions::FirstAndNextFrame, - (true, Some(Write(_))) => FrameOptions::FirstFrame, - // - (false, None) => FrameOptions::LastFrame, - (false, Some(Read(_))) => FrameOptions::NextFrame, - (false, Some(Write(_))) => FrameOptions::LastFrameNoStop, + // The third property is checked for all operations since the resulting framing + // configurations are identical for write operations regardless of ACK/NACK treatment. + let framing = match (is_first_of_type, next_op) { + // First operation of type, and it's also the final operation overall + (true, None) => OperationFraming::FirstAndLast, + // First operation of type, next operation is also a read (continue read sequence) + (true, Some(Read(_))) => OperationFraming::FirstAndNext, + // First operation of type, next operation is write (end current sequence) + (true, Some(Write(_))) => OperationFraming::First, + + // Continuation operation, and it's the final operation overall + (false, None) => OperationFraming::Last, + // Continuation operation, next operation is also a read (continue read sequence) + (false, Some(Read(_))) => OperationFraming::Next, + // Continuation operation, next operation is write (end current sequence, no stop) + (false, Some(Write(_))) => OperationFraming::LastNoStop, }; - // Pre-calculate if `next_op` is the first operation of its type. We do this here and not at - // the beginning of the loop because we hand out `op` as iterator value and cannot access it - // anymore in the next iteration. - next_first_frame = match (&op, next_op) { + // Pre-calculate whether the next operation will be the first of its type. + // This is done here because we consume `current_op` as the iterator value + // and cannot access it in the next iteration. + next_first_operation = match (¤t_op, next_op) { + // No next operation (_, None) => false, + // Operation type changes: next will be first of its type (Read(_), Some(Write(_))) | (Write(_), Some(Read(_))) => true, + // Operation type continues: next will not be first of its type (Read(_), Some(Read(_))) | (Write(_), Some(Write(_))) => false, }; - Some((op, frame)) + Some((current_op, framing)) })) } diff --git a/embassy-stm32/src/i2c/v1.rs b/embassy-stm32/src/i2c/v1.rs index a1ad9caef..7d2b731d5 100644 --- a/embassy-stm32/src/i2c/v1.rs +++ b/embassy-stm32/src/i2c/v1.rs @@ -151,7 +151,7 @@ impl<'d, M: Mode, IM: MasterMode> I2c<'d, M, IM> { Ok(sr1) } - fn write_bytes(&mut self, addr: u8, bytes: &[u8], timeout: Timeout, frame: FrameOptions) -> Result<(), Error> { + fn write_bytes(&mut self, addr: u8, bytes: &[u8], timeout: Timeout, frame: OperationFraming) -> Result<(), Error> { if frame.send_start() { // Send a START condition @@ -239,7 +239,7 @@ impl<'d, M: Mode, IM: MasterMode> I2c<'d, M, IM> { addr: u8, buffer: &mut [u8], timeout: Timeout, - frame: FrameOptions, + frame: OperationFraming, ) -> Result<(), Error> { let Some((last, buffer)) = buffer.split_last_mut() else { return Err(Error::Overrun); @@ -299,12 +299,12 @@ impl<'d, M: Mode, IM: MasterMode> I2c<'d, M, IM> { /// Blocking read. pub fn blocking_read(&mut self, addr: u8, read: &mut [u8]) -> Result<(), Error> { - self.blocking_read_timeout(addr, read, self.timeout(), FrameOptions::FirstAndLastFrame) + self.blocking_read_timeout(addr, read, self.timeout(), OperationFraming::FirstAndLast) } /// Blocking write. pub fn blocking_write(&mut self, addr: u8, write: &[u8]) -> Result<(), Error> { - self.write_bytes(addr, write, self.timeout(), FrameOptions::FirstAndLastFrame)?; + self.write_bytes(addr, write, self.timeout(), OperationFraming::FirstAndLast)?; // Fallthrough is success Ok(()) @@ -320,8 +320,8 @@ impl<'d, M: Mode, IM: MasterMode> I2c<'d, M, IM> { let timeout = self.timeout(); - self.write_bytes(addr, write, timeout, FrameOptions::FirstFrame)?; - self.blocking_read_timeout(addr, read, timeout, FrameOptions::FirstAndLastFrame)?; + self.write_bytes(addr, write, timeout, OperationFraming::First)?; + self.blocking_read_timeout(addr, read, timeout, OperationFraming::FirstAndLast)?; Ok(()) } @@ -334,7 +334,7 @@ impl<'d, M: Mode, IM: MasterMode> I2c<'d, M, IM> { pub fn blocking_transaction(&mut self, addr: u8, operations: &mut [Operation<'_>]) -> Result<(), Error> { let timeout = self.timeout(); - for (op, frame) in operation_frames(operations)? { + for (op, frame) in assign_operation_framing(operations)? { match op { Operation::Read(read) => self.blocking_read_timeout(addr, read, timeout, frame)?, Operation::Write(write) => self.write_bytes(addr, write, timeout, frame)?, @@ -356,7 +356,7 @@ impl<'d, M: Mode, IM: MasterMode> I2c<'d, M, IM> { } impl<'d, IM: MasterMode> I2c<'d, Async, IM> { - async fn write_frame(&mut self, address: u8, write: &[u8], frame: FrameOptions) -> Result<(), Error> { + async fn write_frame(&mut self, address: u8, write: &[u8], frame: OperationFraming) -> Result<(), Error> { self.info.regs.cr2().modify(|w| { // Note: Do not enable the ITBUFEN bit in the I2C_CR2 register if DMA is used for // reception. @@ -502,7 +502,7 @@ impl<'d, IM: MasterMode> I2c<'d, Async, IM> { /// Write. pub async fn write(&mut self, address: u8, write: &[u8]) -> Result<(), Error> { - self.write_frame(address, write, FrameOptions::FirstAndLastFrame) + self.write_frame(address, write, OperationFraming::FirstAndLast) .await?; Ok(()) @@ -510,13 +510,13 @@ impl<'d, IM: MasterMode> I2c<'d, Async, IM> { /// Read. pub async fn read(&mut self, address: u8, buffer: &mut [u8]) -> Result<(), Error> { - self.read_frame(address, buffer, FrameOptions::FirstAndLastFrame) + self.read_frame(address, buffer, OperationFraming::FirstAndLast) .await?; Ok(()) } - async fn read_frame(&mut self, address: u8, buffer: &mut [u8], frame: FrameOptions) -> Result<(), Error> { + async fn read_frame(&mut self, address: u8, buffer: &mut [u8], frame: OperationFraming) -> Result<(), Error> { if buffer.is_empty() { return Err(Error::Overrun); } @@ -680,8 +680,8 @@ impl<'d, IM: MasterMode> I2c<'d, Async, IM> { return Err(Error::Overrun); } - self.write_frame(address, write, FrameOptions::FirstFrame).await?; - self.read_frame(address, read, FrameOptions::FirstAndLastFrame).await + self.write_frame(address, write, OperationFraming::First).await?; + self.read_frame(address, read, OperationFraming::FirstAndLast).await } /// Transaction with operations. @@ -690,7 +690,7 @@ impl<'d, IM: MasterMode> I2c<'d, Async, IM> { /// /// [transaction contract]: embedded_hal_1::i2c::I2c::transaction pub async fn transaction(&mut self, addr: u8, operations: &mut [Operation<'_>]) -> Result<(), Error> { - for (op, frame) in operation_frames(operations)? { + for (op, frame) in assign_operation_framing(operations)? { match op { Operation::Read(read) => self.read_frame(addr, read, frame).await?, Operation::Write(write) => self.write_frame(addr, write, frame).await?, -- cgit From b690a0314f0f2e42137ad4b3e867e056c1d3c14e Mon Sep 17 00:00:00 2001 From: HybridChild Date: Sun, 27 Jul 2025 10:53:48 +0200 Subject: stm32/i2c: v1 and v2 now has separate definitions for the State struct --- embassy-stm32/src/i2c/mod.rs | 17 +++-------------- embassy-stm32/src/i2c/v1.rs | 15 +++++++++++++++ embassy-stm32/src/i2c/v2.rs | 15 +++++++++++++++ 3 files changed, 33 insertions(+), 14 deletions(-) diff --git a/embassy-stm32/src/i2c/mod.rs b/embassy-stm32/src/i2c/mod.rs index f51682900..58225d937 100644 --- a/embassy-stm32/src/i2c/mod.rs +++ b/embassy-stm32/src/i2c/mod.rs @@ -5,6 +5,9 @@ #[cfg_attr(any(i2c_v2, i2c_v3), path = "v2.rs")] mod _version; +// Type alias for the peri_trait! macro +type State = _version::State; + mod config; use core::future::Future; @@ -13,7 +16,6 @@ use core::marker::PhantomData; pub use config::*; use embassy_hal_internal::Peri; -use embassy_sync::waitqueue::AtomicWaker; #[cfg(feature = "time")] use embassy_time::{Duration, Instant}; use mode::MasterMode; @@ -274,19 +276,6 @@ impl Timeout { } } -struct State { - #[allow(unused)] - waker: AtomicWaker, -} - -impl State { - const fn new() -> Self { - Self { - waker: AtomicWaker::new(), - } - } -} - struct Info { regs: crate::pac::i2c::I2c, rcc: RccInfo, diff --git a/embassy-stm32/src/i2c/v1.rs b/embassy-stm32/src/i2c/v1.rs index 7d2b731d5..78abb85ea 100644 --- a/embassy-stm32/src/i2c/v1.rs +++ b/embassy-stm32/src/i2c/v1.rs @@ -17,6 +17,21 @@ use super::*; use crate::mode::Mode; use crate::pac::i2c; +use embassy_sync::waitqueue::AtomicWaker; + +/// I2C v2 peripheral state +pub(crate) struct State { + pub(crate) waker: AtomicWaker, +} + +impl State { + pub(crate) const fn new() -> Self { + Self { + waker: AtomicWaker::new(), + } + } +} + // /!\ /!\ // /!\ Implementation note! /!\ // /!\ /!\ diff --git a/embassy-stm32/src/i2c/v2.rs b/embassy-stm32/src/i2c/v2.rs index 3b09f1b34..72a7d05ab 100644 --- a/embassy-stm32/src/i2c/v2.rs +++ b/embassy-stm32/src/i2c/v2.rs @@ -12,6 +12,21 @@ use stm32_metapac::i2c::vals::{Addmode, Oamsk}; use super::*; use crate::pac::i2c; +use embassy_sync::waitqueue::AtomicWaker; + +/// I2C v2 peripheral state +pub(crate) struct State { + pub(crate) waker: AtomicWaker, +} + +impl State { + pub(crate) const fn new() -> Self { + Self { + waker: AtomicWaker::new(), + } + } +} + impl From for Oamsk { fn from(value: AddrMask) -> Self { match value { -- cgit From 593fb963b84741bb05d1cae1dbacafb92b4828c6 Mon Sep 17 00:00:00 2001 From: HybridChild Date: Sun, 27 Jul 2025 12:25:03 +0200 Subject: stm32/i2c: Add temporary trait for version-specific initialization during v1 rework --- embassy-stm32/src/i2c/mod.rs | 22 +++++++++++++++++++++- embassy-stm32/src/i2c/v1.rs | 38 ++++++++++++++++++++++++++++++-------- embassy-stm32/src/i2c/v2.rs | 4 ++++ 3 files changed, 55 insertions(+), 9 deletions(-) diff --git a/embassy-stm32/src/i2c/mod.rs b/embassy-stm32/src/i2c/mod.rs index 58225d937..660b8144a 100644 --- a/embassy-stm32/src/i2c/mod.rs +++ b/embassy-stm32/src/i2c/mod.rs @@ -29,6 +29,21 @@ use crate::rcc::{RccInfo, SealedRccPeripheral}; use crate::time::Hertz; use crate::{interrupt, peripherals}; +/// Temporary trait for version-specific initialization during I2C v1 async rework. +/// +/// This trait allows the shared constructor in mod.rs to call version-specific +/// initialization while we incrementally migrate v1 async operations to use +/// the new event-driven interrupt pattern. Will be removed once the rework +/// is complete and both blocking/async modes use unified initialization. +pub trait VersionSpecificInit { + /// Performs version and mode-specific initialization. + /// + /// For v1: Sets interrupt pattern flag based on blocking vs async mode. + /// For v2: No-op, does nothing. + fn version_specific_init(&mut self); +} + + /// I2C error. #[derive(Debug, PartialEq, Eq, Copy, Clone)] #[cfg_attr(feature = "defmt", derive(defmt::Format))] @@ -192,7 +207,10 @@ impl<'d> I2c<'d, Blocking, Master> { } } -impl<'d, M: Mode> I2c<'d, M, Master> { +impl<'d, M: Mode> I2c<'d, M, Master> +where + Self: VersionSpecificInit +{ /// Create a new I2C driver. fn new_inner( _peri: Peri<'d, T>, @@ -221,7 +239,9 @@ impl<'d, M: Mode> I2c<'d, M, Master> { sda, }, }; + this.enable_and_init(config); + this.version_specific_init(); this } diff --git a/embassy-stm32/src/i2c/v1.rs b/embassy-stm32/src/i2c/v1.rs index 78abb85ea..eaf787334 100644 --- a/embassy-stm32/src/i2c/v1.rs +++ b/embassy-stm32/src/i2c/v1.rs @@ -6,6 +6,7 @@ use core::future::poll_fn; use core::task::Poll; +use core::sync::atomic::{AtomicBool, Ordering}; use embassy_embedded_hal::SetConfig; use embassy_futures::select::{select, Either}; @@ -22,12 +23,14 @@ use embassy_sync::waitqueue::AtomicWaker; /// I2C v2 peripheral state pub(crate) struct State { pub(crate) waker: AtomicWaker, + pub use_new_interrupt_pattern: AtomicBool, } impl State { pub(crate) const fn new() -> Self { Self { waker: AtomicWaker::new(), + use_new_interrupt_pattern: AtomicBool::new(false), } } } @@ -44,17 +47,25 @@ impl State { // There's some more details there, and we might have a fix for you. But please let us know if you // hit a case like this! pub unsafe fn on_interrupt() { - let regs = T::info().regs; // i2c v2 only woke the task on transfer complete interrupts. v1 uses interrupts for a bunch of // other stuff, so we wake the task on every interrupt. - T::state().waker.wake(); - critical_section::with(|_| { - // Clear event interrupt flag. - regs.cr2().modify(|w| { - w.set_itevten(false); - w.set_iterren(false); + + let regs = T::info().regs; + let state = T::state(); + + if state.use_new_interrupt_pattern.load(Ordering::Relaxed) { + + } else { + critical_section::with(|_| { + // Clear event interrupt flag. + regs.cr2().modify(|w| { + w.set_itevten(false); + w.set_iterren(false); + }); }); - }); + } + + state.waker.wake(); } impl<'d, M: Mode, IM: MasterMode> I2c<'d, M, IM> { @@ -716,6 +727,17 @@ impl<'d, IM: MasterMode> I2c<'d, Async, IM> { } } +impl<'d> VersionSpecificInit for I2c<'d, Blocking, Master> { + fn version_specific_init(&mut self) { + self.state.use_new_interrupt_pattern.store(false, Ordering::Relaxed); + } +} + +impl<'d> VersionSpecificInit for I2c<'d, Async, Master> { + fn version_specific_init(&mut self) { + self.state.use_new_interrupt_pattern.store(true, Ordering::Relaxed); + } +} /// Timing configuration for I2C v1 hardware /// diff --git a/embassy-stm32/src/i2c/v2.rs b/embassy-stm32/src/i2c/v2.rs index 72a7d05ab..f23c58c9e 100644 --- a/embassy-stm32/src/i2c/v2.rs +++ b/embassy-stm32/src/i2c/v2.rs @@ -107,6 +107,10 @@ pub(crate) unsafe fn on_interrupt() { }); } +impl<'d, M: Mode> VersionSpecificInit for I2c<'d, M, Master> { + fn version_specific_init(&mut self) {} +} + impl<'d, M: Mode, IM: MasterMode> I2c<'d, M, IM> { pub(crate) fn init(&mut self, config: Config) { self.info.regs.cr1().modify(|reg| { -- cgit From 392548997ab65e5654a32848d93a05d5fb695a79 Mon Sep 17 00:00:00 2001 From: HybridChild Date: Mon, 28 Jul 2025 08:05:59 +0200 Subject: stm32/i2c_v1: Rename function parameters for consistent naming --- embassy-stm32/src/i2c/v1.rs | 108 ++++++++++++++++++++++---------------------- 1 file changed, 54 insertions(+), 54 deletions(-) diff --git a/embassy-stm32/src/i2c/v1.rs b/embassy-stm32/src/i2c/v1.rs index eaf787334..ef5624d97 100644 --- a/embassy-stm32/src/i2c/v1.rs +++ b/embassy-stm32/src/i2c/v1.rs @@ -177,8 +177,8 @@ impl<'d, M: Mode, IM: MasterMode> I2c<'d, M, IM> { Ok(sr1) } - fn write_bytes(&mut self, addr: u8, bytes: &[u8], timeout: Timeout, frame: OperationFraming) -> Result<(), Error> { - if frame.send_start() { + fn write_bytes(&mut self, address: u8, write_buffer: &[u8], timeout: Timeout, framing: OperationFraming) -> Result<(), Error> { + if framing.send_start() { // Send a START condition self.info.regs.cr1().modify(|reg| { @@ -196,7 +196,7 @@ impl<'d, M: Mode, IM: MasterMode> I2c<'d, M, IM> { } // Set up current address we're trying to talk to - self.info.regs.dr().write(|reg| reg.set_dr(addr << 1)); + self.info.regs.dr().write(|reg| reg.set_dr(address << 1)); // Wait until address was sent // Wait for the address to be acknowledged @@ -210,11 +210,11 @@ impl<'d, M: Mode, IM: MasterMode> I2c<'d, M, IM> { } // Send bytes - for c in bytes { + for c in write_buffer { self.send_byte(*c, timeout)?; } - if frame.send_stop() { + if framing.send_stop() { // Send a STOP condition self.info.regs.cr1().modify(|reg| reg.set_stop(true)); } @@ -262,16 +262,16 @@ impl<'d, M: Mode, IM: MasterMode> I2c<'d, M, IM> { fn blocking_read_timeout( &mut self, - addr: u8, - buffer: &mut [u8], + address: u8, + read_buffer: &mut [u8], timeout: Timeout, - frame: OperationFraming, + framing: OperationFraming, ) -> Result<(), Error> { - let Some((last, buffer)) = buffer.split_last_mut() else { + let Some((last_byte, read_buffer)) = read_buffer.split_last_mut() else { return Err(Error::Overrun); }; - if frame.send_start() { + if framing.send_start() { // Send a START condition and set ACK bit self.info.regs.cr1().modify(|reg| { reg.set_start(true); @@ -289,7 +289,7 @@ impl<'d, M: Mode, IM: MasterMode> I2c<'d, M, IM> { } // Set up current address we're trying to talk to - self.info.regs.dr().write(|reg| reg.set_dr((addr << 1) + 1)); + self.info.regs.dr().write(|reg| reg.set_dr((address << 1) + 1)); // Wait until address was sent // Wait for the address to be acknowledged @@ -302,52 +302,52 @@ impl<'d, M: Mode, IM: MasterMode> I2c<'d, M, IM> { } // Receive bytes into buffer - for c in buffer { + for c in read_buffer { *c = self.recv_byte(timeout)?; } // Prepare to send NACK then STOP after next byte self.info.regs.cr1().modify(|reg| { - if frame.send_nack() { + if framing.send_nack() { reg.set_ack(false); } - if frame.send_stop() { + if framing.send_stop() { reg.set_stop(true); } }); // Receive last byte - *last = self.recv_byte(timeout)?; + *last_byte = self.recv_byte(timeout)?; // Fallthrough is success Ok(()) } /// Blocking read. - pub fn blocking_read(&mut self, addr: u8, read: &mut [u8]) -> Result<(), Error> { - self.blocking_read_timeout(addr, read, self.timeout(), OperationFraming::FirstAndLast) + pub fn blocking_read(&mut self, address: u8, read_buffer: &mut [u8]) -> Result<(), Error> { + self.blocking_read_timeout(address, read_buffer, self.timeout(), OperationFraming::FirstAndLast) } /// Blocking write. - pub fn blocking_write(&mut self, addr: u8, write: &[u8]) -> Result<(), Error> { - self.write_bytes(addr, write, self.timeout(), OperationFraming::FirstAndLast)?; + pub fn blocking_write(&mut self, address: u8, write_buffer: &[u8]) -> Result<(), Error> { + self.write_bytes(address, write_buffer, self.timeout(), OperationFraming::FirstAndLast)?; // Fallthrough is success Ok(()) } /// Blocking write, restart, read. - pub fn blocking_write_read(&mut self, addr: u8, write: &[u8], read: &mut [u8]) -> Result<(), Error> { + pub fn blocking_write_read(&mut self, address: u8, write_buffer: &[u8], read_buffer: &mut [u8]) -> Result<(), Error> { // Check empty read buffer before starting transaction. Otherwise, we would not generate the // stop condition below. - if read.is_empty() { + if read_buffer.is_empty() { return Err(Error::Overrun); } let timeout = self.timeout(); - self.write_bytes(addr, write, timeout, OperationFraming::First)?; - self.blocking_read_timeout(addr, read, timeout, OperationFraming::FirstAndLast)?; + self.write_bytes(address, write_buffer, timeout, OperationFraming::First)?; + self.blocking_read_timeout(address, read_buffer, timeout, OperationFraming::FirstAndLast)?; Ok(()) } @@ -357,13 +357,13 @@ impl<'d, M: Mode, IM: MasterMode> I2c<'d, M, IM> { /// Consecutive operations of same type are merged. See [transaction contract] for details. /// /// [transaction contract]: embedded_hal_1::i2c::I2c::transaction - pub fn blocking_transaction(&mut self, addr: u8, operations: &mut [Operation<'_>]) -> Result<(), Error> { + pub fn blocking_transaction(&mut self, address: u8, operations: &mut [Operation<'_>]) -> Result<(), Error> { let timeout = self.timeout(); - for (op, frame) in assign_operation_framing(operations)? { + for (op, framing) in assign_operation_framing(operations)? { match op { - Operation::Read(read) => self.blocking_read_timeout(addr, read, timeout, frame)?, - Operation::Write(write) => self.write_bytes(addr, write, timeout, frame)?, + Operation::Read(read_buffer) => self.blocking_read_timeout(address, read_buffer, timeout, framing)?, + Operation::Write(write_buffer) => self.write_bytes(address, write_buffer, timeout, framing)?, } } @@ -382,7 +382,7 @@ impl<'d, M: Mode, IM: MasterMode> I2c<'d, M, IM> { } impl<'d, IM: MasterMode> I2c<'d, Async, IM> { - async fn write_frame(&mut self, address: u8, write: &[u8], frame: OperationFraming) -> Result<(), Error> { + async fn write_with_framing(&mut self, address: u8, write_buffer: &[u8], framing: OperationFraming) -> Result<(), Error> { self.info.regs.cr2().modify(|w| { // Note: Do not enable the ITBUFEN bit in the I2C_CR2 register if DMA is used for // reception. @@ -404,7 +404,7 @@ impl<'d, IM: MasterMode> I2c<'d, Async, IM> { }) }); - if frame.send_start() { + if framing.send_start() { // Send a START condition self.info.regs.cr1().modify(|reg| { reg.set_start(true); @@ -465,7 +465,7 @@ impl<'d, IM: MasterMode> I2c<'d, Async, IM> { // this address from the memory after each TxE event. let dst = self.info.regs.dr().as_ptr() as *mut u8; - self.tx_dma.as_mut().unwrap().write(write, dst, Default::default()) + self.tx_dma.as_mut().unwrap().write(write_buffer, dst, Default::default()) }; // Wait for bytes to be sent, or an error to occur. @@ -492,7 +492,7 @@ impl<'d, IM: MasterMode> I2c<'d, Async, IM> { w.set_dmaen(false); }); - if frame.send_stop() { + if framing.send_stop() { // The I2C transfer itself will take longer than the DMA transfer, so wait for that to finish too. // 18.3.8 “Master transmitter: In the interrupt routine after the EOT interrupt, disable DMA @@ -527,28 +527,28 @@ impl<'d, IM: MasterMode> I2c<'d, Async, IM> { } /// Write. - pub async fn write(&mut self, address: u8, write: &[u8]) -> Result<(), Error> { - self.write_frame(address, write, OperationFraming::FirstAndLast) + pub async fn write(&mut self, address: u8, write_buffer: &[u8]) -> Result<(), Error> { + self.write_with_framing(address, write_buffer, OperationFraming::FirstAndLast) .await?; Ok(()) } /// Read. - pub async fn read(&mut self, address: u8, buffer: &mut [u8]) -> Result<(), Error> { - self.read_frame(address, buffer, OperationFraming::FirstAndLast) + pub async fn read(&mut self, address: u8, read_buffer: &mut [u8]) -> Result<(), Error> { + self.read_with_framing(address, read_buffer, OperationFraming::FirstAndLast) .await?; Ok(()) } - async fn read_frame(&mut self, address: u8, buffer: &mut [u8], frame: OperationFraming) -> Result<(), Error> { - if buffer.is_empty() { + async fn read_with_framing(&mut self, address: u8, read_buffer: &mut [u8], framing: OperationFraming) -> Result<(), Error> { + if read_buffer.is_empty() { return Err(Error::Overrun); } // Some branches below depend on whether the buffer contains only a single byte. - let single_byte = buffer.len() == 1; + let single_byte = read_buffer.len() == 1; self.info.regs.cr2().modify(|w| { // Note: Do not enable the ITBUFEN bit in the I2C_CR2 register if DMA is used for @@ -560,7 +560,7 @@ impl<'d, IM: MasterMode> I2c<'d, Async, IM> { // If, in the I2C_CR2 register, the LAST bit is set, I2C automatically sends a NACK // after the next byte following EOT_1. The user can generate a Stop condition in // the DMA Transfer Complete interrupt routine if enabled. - w.set_last(frame.send_nack() && !single_byte); + w.set_last(framing.send_nack() && !single_byte); }); // Sentinel to disable transfer when an error occurs or future is canceled. @@ -573,7 +573,7 @@ impl<'d, IM: MasterMode> I2c<'d, Async, IM> { }) }); - if frame.send_start() { + if framing.send_start() { // Send a START condition and set ACK bit self.info.regs.cr1().modify(|reg| { reg.set_start(true); @@ -628,7 +628,7 @@ impl<'d, IM: MasterMode> I2c<'d, Async, IM> { // 18.3.8: When a single byte must be received: the NACK must be programmed during EV6 // event, i.e. program ACK=0 when ADDR=1, before clearing ADDR flag. - if frame.send_nack() && single_byte { + if framing.send_nack() && single_byte { self.info.regs.cr1().modify(|w| { w.set_ack(false); }); @@ -638,8 +638,8 @@ impl<'d, IM: MasterMode> I2c<'d, Async, IM> { self.info.regs.sr2().read(); } else { // Before starting reception of single byte (but without START condition, i.e. in case - // of continued frame), program NACK to emit at end of this byte. - if frame.send_nack() && single_byte { + // of merged operations), program NACK to emit at end of this byte. + if framing.send_nack() && single_byte { self.info.regs.cr1().modify(|w| { w.set_ack(false); }); @@ -649,7 +649,7 @@ impl<'d, IM: MasterMode> I2c<'d, Async, IM> { // 18.3.8: When a single byte must be received: [snip] Then the user can program the STOP // condition either after clearing ADDR flag, or in the DMA Transfer Complete interrupt // routine. - if frame.send_stop() && single_byte { + if framing.send_stop() && single_byte { self.info.regs.cr1().modify(|w| { w.set_stop(true); }); @@ -660,7 +660,7 @@ impl<'d, IM: MasterMode> I2c<'d, Async, IM> { // from this address from the memory after each RxE event. let src = self.info.regs.dr().as_ptr() as *mut u8; - self.rx_dma.as_mut().unwrap().read(src, buffer, Default::default()) + self.rx_dma.as_mut().unwrap().read(src, read_buffer, Default::default()) }; // Wait for bytes to be received, or an error to occur. @@ -686,7 +686,7 @@ impl<'d, IM: MasterMode> I2c<'d, Async, IM> { w.set_dmaen(false); }); - if frame.send_stop() && !single_byte { + if framing.send_stop() && !single_byte { self.info.regs.cr1().modify(|w| { w.set_stop(true); }); @@ -699,15 +699,15 @@ impl<'d, IM: MasterMode> I2c<'d, Async, IM> { } /// Write, restart, read. - pub async fn write_read(&mut self, address: u8, write: &[u8], read: &mut [u8]) -> Result<(), Error> { + pub async fn write_read(&mut self, address: u8, write_buffer: &[u8], read_buffer: &mut [u8]) -> Result<(), Error> { // Check empty read buffer before starting transaction. Otherwise, we would not generate the // stop condition below. - if read.is_empty() { + if read_buffer.is_empty() { return Err(Error::Overrun); } - self.write_frame(address, write, OperationFraming::First).await?; - self.read_frame(address, read, OperationFraming::FirstAndLast).await + self.write_with_framing(address, write_buffer, OperationFraming::First).await?; + self.read_with_framing(address, read_buffer, OperationFraming::FirstAndLast).await } /// Transaction with operations. @@ -715,11 +715,11 @@ impl<'d, IM: MasterMode> I2c<'d, Async, IM> { /// Consecutive operations of same type are merged. See [transaction contract] for details. /// /// [transaction contract]: embedded_hal_1::i2c::I2c::transaction - pub async fn transaction(&mut self, addr: u8, operations: &mut [Operation<'_>]) -> Result<(), Error> { - for (op, frame) in assign_operation_framing(operations)? { + pub async fn transaction(&mut self, address: u8, operations: &mut [Operation<'_>]) -> Result<(), Error> { + for (op, framing) in assign_operation_framing(operations)? { match op { - Operation::Read(read) => self.read_frame(addr, read, frame).await?, - Operation::Write(write) => self.write_frame(addr, write, frame).await?, + Operation::Read(read_buffer) => self.read_with_framing(address, read_buffer, framing).await?, + Operation::Write(write_buffer) => self.write_with_framing(address, write_buffer, framing).await?, } } -- cgit From c531af42c8dd2eaeb56ef1891396ac559918560e Mon Sep 17 00:00:00 2001 From: HybridChild Date: Thu, 7 Aug 2025 10:34:29 +0200 Subject: Revert "stm32/i2c: Add temporary trait for version-specific initialization during v1 rework" This reverts commit d38e1de962b92d1d48f1991ce09e494ea46d3f7f. --- embassy-stm32/src/i2c/mod.rs | 21 +-------------------- embassy-stm32/src/i2c/v1.rs | 38 ++++++++------------------------------ embassy-stm32/src/i2c/v2.rs | 4 ---- 3 files changed, 9 insertions(+), 54 deletions(-) diff --git a/embassy-stm32/src/i2c/mod.rs b/embassy-stm32/src/i2c/mod.rs index 660b8144a..675a392f9 100644 --- a/embassy-stm32/src/i2c/mod.rs +++ b/embassy-stm32/src/i2c/mod.rs @@ -29,21 +29,6 @@ use crate::rcc::{RccInfo, SealedRccPeripheral}; use crate::time::Hertz; use crate::{interrupt, peripherals}; -/// Temporary trait for version-specific initialization during I2C v1 async rework. -/// -/// This trait allows the shared constructor in mod.rs to call version-specific -/// initialization while we incrementally migrate v1 async operations to use -/// the new event-driven interrupt pattern. Will be removed once the rework -/// is complete and both blocking/async modes use unified initialization. -pub trait VersionSpecificInit { - /// Performs version and mode-specific initialization. - /// - /// For v1: Sets interrupt pattern flag based on blocking vs async mode. - /// For v2: No-op, does nothing. - fn version_specific_init(&mut self); -} - - /// I2C error. #[derive(Debug, PartialEq, Eq, Copy, Clone)] #[cfg_attr(feature = "defmt", derive(defmt::Format))] @@ -207,10 +192,7 @@ impl<'d> I2c<'d, Blocking, Master> { } } -impl<'d, M: Mode> I2c<'d, M, Master> -where - Self: VersionSpecificInit -{ +impl<'d, M: Mode> I2c<'d, M, Master> { /// Create a new I2C driver. fn new_inner( _peri: Peri<'d, T>, @@ -241,7 +223,6 @@ where }; this.enable_and_init(config); - this.version_specific_init(); this } diff --git a/embassy-stm32/src/i2c/v1.rs b/embassy-stm32/src/i2c/v1.rs index ef5624d97..f2fd0147e 100644 --- a/embassy-stm32/src/i2c/v1.rs +++ b/embassy-stm32/src/i2c/v1.rs @@ -6,7 +6,6 @@ use core::future::poll_fn; use core::task::Poll; -use core::sync::atomic::{AtomicBool, Ordering}; use embassy_embedded_hal::SetConfig; use embassy_futures::select::{select, Either}; @@ -23,14 +22,12 @@ use embassy_sync::waitqueue::AtomicWaker; /// I2C v2 peripheral state pub(crate) struct State { pub(crate) waker: AtomicWaker, - pub use_new_interrupt_pattern: AtomicBool, } impl State { pub(crate) const fn new() -> Self { Self { waker: AtomicWaker::new(), - use_new_interrupt_pattern: AtomicBool::new(false), } } } @@ -47,25 +44,17 @@ impl State { // There's some more details there, and we might have a fix for you. But please let us know if you // hit a case like this! pub unsafe fn on_interrupt() { + let regs = T::info().regs; // i2c v2 only woke the task on transfer complete interrupts. v1 uses interrupts for a bunch of // other stuff, so we wake the task on every interrupt. - - let regs = T::info().regs; - let state = T::state(); - - if state.use_new_interrupt_pattern.load(Ordering::Relaxed) { - - } else { - critical_section::with(|_| { - // Clear event interrupt flag. - regs.cr2().modify(|w| { - w.set_itevten(false); - w.set_iterren(false); - }); + T::state().waker.wake(); + critical_section::with(|_| { + // Clear event interrupt flag. + regs.cr2().modify(|w| { + w.set_itevten(false); + w.set_iterren(false); }); - } - - state.waker.wake(); + }); } impl<'d, M: Mode, IM: MasterMode> I2c<'d, M, IM> { @@ -727,17 +716,6 @@ impl<'d, IM: MasterMode> I2c<'d, Async, IM> { } } -impl<'d> VersionSpecificInit for I2c<'d, Blocking, Master> { - fn version_specific_init(&mut self) { - self.state.use_new_interrupt_pattern.store(false, Ordering::Relaxed); - } -} - -impl<'d> VersionSpecificInit for I2c<'d, Async, Master> { - fn version_specific_init(&mut self) { - self.state.use_new_interrupt_pattern.store(true, Ordering::Relaxed); - } -} /// Timing configuration for I2C v1 hardware /// diff --git a/embassy-stm32/src/i2c/v2.rs b/embassy-stm32/src/i2c/v2.rs index f23c58c9e..72a7d05ab 100644 --- a/embassy-stm32/src/i2c/v2.rs +++ b/embassy-stm32/src/i2c/v2.rs @@ -107,10 +107,6 @@ pub(crate) unsafe fn on_interrupt() { }); } -impl<'d, M: Mode> VersionSpecificInit for I2c<'d, M, Master> { - fn version_specific_init(&mut self) {} -} - impl<'d, M: Mode, IM: MasterMode> I2c<'d, M, IM> { pub(crate) fn init(&mut self, config: Config) { self.info.regs.cr1().modify(|reg| { -- cgit From b88c5195e030b6fac129ea9cb74eb169227f7335 Mon Sep 17 00:00:00 2001 From: HybridChild Date: Sun, 10 Aug 2025 08:31:35 +0200 Subject: stm32/i2c_v1: Add MultiMaster (Slave) mode implementation --- embassy-stm32/src/i2c/v1.rs | 341 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 341 insertions(+) diff --git a/embassy-stm32/src/i2c/v1.rs b/embassy-stm32/src/i2c/v1.rs index f2fd0147e..7b6ecf869 100644 --- a/embassy-stm32/src/i2c/v1.rs +++ b/embassy-stm32/src/i2c/v1.rs @@ -32,6 +32,21 @@ impl State { } } +#[derive(Debug, PartialEq)] +enum SlaveSendResult { + Acked, // Byte sent and ACK received from master + Nacked, // Byte sent but NACK received (normal end of transmission) + Stopped, // STOP condition detected + Restart, // RESTART condition detected +} + +#[derive(Debug, PartialEq)] +enum SlaveReceiveResult { + Byte(u8), // Data byte received + Stop, // STOP condition detected + Restart, // RESTART condition (new ADDR) detected +} + // /!\ /!\ // /!\ Implementation note! /!\ // /!\ /!\ @@ -370,6 +385,332 @@ impl<'d, M: Mode, IM: MasterMode> I2c<'d, M, IM> { } } +impl<'d, M: Mode> I2c<'d, M, Master> { + /// Configure the I2C driver for slave operations, allowing for the driver to be used as a slave and a master (multimaster) + pub fn into_slave_multimaster(mut self, slave_addr_config: SlaveAddrConfig) -> I2c<'d, M, MultiMaster> { + let mut slave = I2c { + info: self.info, + state: self.state, + kernel_clock: self.kernel_clock, + tx_dma: self.tx_dma.take(), // Use take() to move ownership + rx_dma: self.rx_dma.take(), // Use take() to move ownership + #[cfg(feature = "time")] + timeout: self.timeout, + _phantom: PhantomData, + _phantom2: PhantomData, + _drop_guard: self._drop_guard, // Move the drop guard + }; + slave.init_slave(slave_addr_config); + slave + } +} + +impl<'d, M: Mode, IM: MasterMode> I2c<'d, M, IM> { + pub(crate) fn init_slave(&mut self, config: SlaveAddrConfig) { + // Disable peripheral for configuration + self.info.regs.cr1().modify(|reg| { + reg.set_pe(false); + }); + + // Configure v1-specific slave settings + self.configure_addresses(config); + + // Enable slave mode interrupts and settings + self.info.regs.cr2().modify(|w| { + w.set_itevten(true); // Event interrupts + w.set_iterren(true); // Error interrupts + }); + + // Re-enable peripheral + self.info.regs.cr1().modify(|reg| { + reg.set_pe(true); + }); + } + + fn configure_oa1(&mut self, addr: Address) { + match addr { + Address::SevenBit(addr) => { + self.info.regs.oar1().write(|reg| { + // v1 uses left-shifted 7-bit address in bits [7:1] + // STM32 reference manual says bits 7:1 for address, bit 0 don't care for 7-bit + reg.set_add((addr as u16) << 1); + reg.set_addmode(i2c::vals::Addmode::BIT7); + }); + }, + Address::TenBit(addr) => { + self.info.regs.oar1().modify(|reg| { + reg.set_add(addr); // Set address bits [9:0] + reg.set_addmode(i2c::vals::Addmode::BIT10); + // Manually set bit 14 as required by reference manual + reg.0 |= 1 << 14; + }); + } + } + } + + fn configure_oa2_simple(&mut self, addr: u8) { + self.info.regs.oar2().write(|reg| { + // v1 OA2: 7-bit address only, no masking support + // Address goes in bits [7:1], enable dual addressing + reg.set_add2(addr); + reg.set_endual(i2c::vals::Endual::DUAL); + }); + } + + fn configure_addresses(&mut self, config: SlaveAddrConfig) { + match config.addr { + OwnAddresses::OA1(addr) => { + self.configure_oa1(addr); + // Disable OA2 if not needed + self.info.regs.oar2().write(|reg| { + reg.set_endual(i2c::vals::Endual::SINGLE); + }); + }, + OwnAddresses::OA2(oa2) => { + // v1 limitation: ignore mask, only support simple OA2 + if !matches!(oa2.mask, AddrMask::NOMASK) { + // Could log a warning here that masking is ignored in v1 + #[cfg(feature = "defmt")] + defmt::warn!("I2C v1 does not support OA2 address masking, ignoring mask setting"); + } + + // Must have a default OA1 when using OA2-only mode + // Set OA1 to a reserved address that won't conflict + self.info.regs.oar1().write(|reg| { + reg.set_add(0); // Address 0x00 is reserved, safe to use + reg.set_addmode(i2c::vals::Addmode::BIT7); + }); + + self.configure_oa2_simple(oa2.addr); + }, + OwnAddresses::Both { oa1, oa2 } => { + self.configure_oa1(oa1); + + // Same masking limitation applies + if !matches!(oa2.mask, AddrMask::NOMASK) { + #[cfg(feature = "defmt")] + defmt::warn!("I2C v1 does not support OA2 address masking, ignoring mask setting"); + } + + self.configure_oa2_simple(oa2.addr); + } + } + + // Configure general call if requested + if config.general_call { + self.info.regs.cr1().modify(|w| w.set_engc(true)); + } + } +} + +impl<'d, M: Mode> I2c<'d, M, MultiMaster> { + /// Listen for incoming I2C address match and return the command type + pub fn blocking_listen(&mut self) -> Result { + let timeout = self.timeout(); // Get timeout internally + self.blocking_listen_timeout(timeout) + } + + /// Respond to master read request (master wants to read from us) + pub fn blocking_respond_to_read(&mut self, data: &[u8]) -> Result { + let timeout = self.timeout(); // Get timeout internally + self.blocking_respond_to_read_timeout(data, timeout) + } + + /// Respond to master write request (master wants to write to us) + pub fn blocking_respond_to_write(&mut self, buffer: &mut [u8]) -> Result { + let timeout = self.timeout(); // Get timeout internally + self.blocking_respond_to_write_timeout(buffer, timeout) + } + + // Private implementation methods with Timeout parameter + fn blocking_listen_timeout(&mut self, timeout: Timeout) -> Result { + // Enable address match interrupt for slave mode + self.info.regs.cr2().modify(|w| { + w.set_itevten(true); // Enable event interrupts + }); + + // Wait for address match (ADDR flag) + loop { + let sr1 = Self::check_and_clear_error_flags(self.info)?; + + if sr1.addr() { + // Address matched! Read SR2 to get direction and clear ADDR + let sr2 = self.info.regs.sr2().read(); + let direction = if sr2.tra() { + SlaveCommandKind::Read // Master wants to read from us (we transmit) + } else { + SlaveCommandKind::Write // Master wants to write to us (we receive) + }; + + // Determine which address was matched + let matched_address = self.determine_matched_address(sr2)?; + + // ADDR is automatically cleared by reading SR1 then SR2 + return Ok(SlaveCommand { + kind: direction, + address: matched_address, + }); + } + + timeout.check()?; + } + } + + fn blocking_respond_to_read_timeout(&mut self, data: &[u8], timeout: Timeout) -> Result { + let mut bytes_sent = 0; + + for &byte in data { + match self.send_byte_or_nack(byte, timeout)? { + SlaveSendResult::Acked => { + bytes_sent += 1; + // Continue sending + }, + SlaveSendResult::Nacked | SlaveSendResult::Stopped => { + // Master finished reading or sent STOP + break; + } + SlaveSendResult::Restart => { + // Master wants to change direction (rare but possible) + break; + } + } + } + + Ok(bytes_sent) + } + + fn blocking_respond_to_write_timeout(&mut self, buffer: &mut [u8], timeout: Timeout) -> Result { + let mut bytes_received = 0; + while bytes_received < buffer.len() { + match self.recv_byte_or_stop(timeout)? { + SlaveReceiveResult::Byte(b) => { + buffer[bytes_received] = b; + bytes_received += 1; + }, + SlaveReceiveResult::Stop => break, + SlaveReceiveResult::Restart => break, + } + } + Ok(bytes_received) + } + + fn determine_matched_address(&self, sr2: stm32_metapac::i2c::regs::Sr2) -> Result { + // Check for general call first + if sr2.gencall() { + Ok(Address::SevenBit(0x00)) + } else if sr2.dualf() { + // OA2 was matched - verify it's actually enabled + let oar2 = self.info.regs.oar2().read(); + if oar2.endual() != i2c::vals::Endual::DUAL { + return Err(Error::Bus); // Hardware inconsistency + } + Ok(Address::SevenBit(oar2.add2())) + } else { + // OA1 was matched + let oar1 = self.info.regs.oar1().read(); + match oar1.addmode() { + i2c::vals::Addmode::BIT7 => { + Ok(Address::SevenBit((oar1.add() >> 1) as u8)) + }, + i2c::vals::Addmode::BIT10 => { + Ok(Address::TenBit(oar1.add())) + }, + } + } + } + + /// Send a byte in slave transmitter mode and check for ACK/NACK/STOP + fn send_byte_or_nack(&mut self, byte: u8, timeout: Timeout) -> Result { + // Wait until we're ready for sending (TXE flag set) + loop { + let sr1 = Self::check_and_clear_error_flags(self.info)?; + + // Check for STOP condition first + if sr1.stopf() { + self.info.regs.cr1().modify(|_w| {}); + return Ok(SlaveSendResult::Stopped); + } + + // Check for RESTART (new ADDR) + if sr1.addr() { + // Don't clear ADDR here - let next blocking_listen() handle it + return Ok(SlaveSendResult::Restart); + } + + // Check for NACK (AF flag) + if sr1.af() { + self.info.regs.sr1().modify(|w| w.set_af(false)); + return Ok(SlaveSendResult::Nacked); + } + + // Check if we can send data + if sr1.txe() { + break; // Ready to send + } + + timeout.check()?; + } + + // Send the byte + self.info.regs.dr().write(|w| w.set_dr(byte)); + + // Wait for byte transfer to complete (BTF flag or error) + loop { + let sr1 = Self::check_and_clear_error_flags(self.info)?; + + // Check for STOP condition + if sr1.stopf() { + self.info.regs.cr1().modify(|_w| {}); + return Ok(SlaveSendResult::Stopped); + } + + // Check for RESTART (new ADDR) + if sr1.addr() { + return Ok(SlaveSendResult::Restart); + } + + // Check for NACK (AF flag) + if sr1.af() { + self.info.regs.sr1().modify(|w| w.set_af(false)); + return Ok(SlaveSendResult::Nacked); + } + + // Check for byte transfer finished + if sr1.btf() { + return Ok(SlaveSendResult::Acked); + } + + timeout.check()?; + } + } + + /// Receive a byte in slave receiver mode or detect STOP condition + fn recv_byte_or_stop(&mut self, timeout: Timeout) -> Result { + loop { + let sr1 = Self::check_and_clear_error_flags(self.info)?; + + // Check for STOP condition first + if sr1.stopf() { + self.info.regs.cr1().modify(|_w| {}); + return Ok(SlaveReceiveResult::Stop); + } + + // Check for RESTART (new ADDR) + if sr1.addr() { + // Don't clear ADDR here - let next blocking_listen() handle it + return Ok(SlaveReceiveResult::Restart); + } + + if sr1.rxne() { + let byte = self.info.regs.dr().read().dr(); + return Ok(SlaveReceiveResult::Byte(byte)); + } + + timeout.check()?; + } + } +} + impl<'d, IM: MasterMode> I2c<'d, Async, IM> { async fn write_with_framing(&mut self, address: u8, write_buffer: &[u8], framing: OperationFraming) -> Result<(), Error> { self.info.regs.cr2().modify(|w| { -- cgit From 6570036f141befc76fd5f5237db0045c0b0f9a71 Mon Sep 17 00:00:00 2001 From: HybridChild Date: Sun, 10 Aug 2025 10:05:26 +0200 Subject: stm32/i2c_v1: Add defmt trace messages --- embassy-stm32/src/i2c/v1.rs | 75 +++++++++++++++++++++++++++++++++++++++------ 1 file changed, 65 insertions(+), 10 deletions(-) diff --git a/embassy-stm32/src/i2c/v1.rs b/embassy-stm32/src/i2c/v1.rs index 7b6ecf869..3aa003fa5 100644 --- a/embassy-stm32/src/i2c/v1.rs +++ b/embassy-stm32/src/i2c/v1.rs @@ -60,6 +60,7 @@ enum SlaveReceiveResult { // hit a case like this! pub unsafe fn on_interrupt() { let regs = T::info().regs; + trace!("i2c v1 interrupt triggered"); // i2c v2 only woke the task on transfer complete interrupts. v1 uses interrupts for a bunch of // other stuff, so we wake the task on every interrupt. T::state().waker.wake(); @@ -122,6 +123,7 @@ impl<'d, M: Mode, IM: MasterMode> I2c<'d, M, IM> { self.info.regs.cr1().modify(|reg| { reg.set_pe(true); }); + trace!("i2c v1 init complete"); } fn check_and_clear_error_flags(info: &'static Info) -> Result { @@ -407,6 +409,7 @@ impl<'d, M: Mode> I2c<'d, M, Master> { impl<'d, M: Mode, IM: MasterMode> I2c<'d, M, IM> { pub(crate) fn init_slave(&mut self, config: SlaveAddrConfig) { + trace!("i2c v1 slave init: config={:?}", config); // Disable peripheral for configuration self.info.regs.cr1().modify(|reg| { reg.set_pe(false); @@ -425,6 +428,7 @@ impl<'d, M: Mode, IM: MasterMode> I2c<'d, M, IM> { self.info.regs.cr1().modify(|reg| { reg.set_pe(true); }); + trace!("i2c v1 slave init complete"); } fn configure_oa1(&mut self, addr: Address) { @@ -471,7 +475,7 @@ impl<'d, M: Mode, IM: MasterMode> I2c<'d, M, IM> { if !matches!(oa2.mask, AddrMask::NOMASK) { // Could log a warning here that masking is ignored in v1 #[cfg(feature = "defmt")] - defmt::warn!("I2C v1 does not support OA2 address masking, ignoring mask setting"); + warn!("I2C v1 does not support OA2 address masking, ignoring mask setting"); } // Must have a default OA1 when using OA2-only mode @@ -506,24 +510,34 @@ impl<'d, M: Mode, IM: MasterMode> I2c<'d, M, IM> { impl<'d, M: Mode> I2c<'d, M, MultiMaster> { /// Listen for incoming I2C address match and return the command type pub fn blocking_listen(&mut self) -> Result { + trace!("i2c v1 slave: blocking_listen start"); let timeout = self.timeout(); // Get timeout internally - self.blocking_listen_timeout(timeout) + let result = self.blocking_listen_timeout(timeout); + trace!("i2c v1 slave: blocking_listen result={:?}", result); + result } /// Respond to master read request (master wants to read from us) pub fn blocking_respond_to_read(&mut self, data: &[u8]) -> Result { + trace!("i2c v1 slave: blocking_respond_to_read start, data_len={}", data.len()); let timeout = self.timeout(); // Get timeout internally - self.blocking_respond_to_read_timeout(data, timeout) + let result = self.blocking_respond_to_read_timeout(data, timeout); + trace!("i2c v1 slave: blocking_respond_to_read result={:?}", result); + result } /// Respond to master write request (master wants to write to us) pub fn blocking_respond_to_write(&mut self, buffer: &mut [u8]) -> Result { + trace!("i2c v1 slave: blocking_respond_to_write start, buffer_len={}", buffer.len()); let timeout = self.timeout(); // Get timeout internally - self.blocking_respond_to_write_timeout(buffer, timeout) + let result = self.blocking_respond_to_write_timeout(buffer, timeout); + trace!("i2c v1 slave: blocking_respond_to_write result={:?}", result); + result } // Private implementation methods with Timeout parameter fn blocking_listen_timeout(&mut self, timeout: Timeout) -> Result { + trace!("i2c v1 slave: listen_timeout start"); // Enable address match interrupt for slave mode self.info.regs.cr2().modify(|w| { w.set_itevten(true); // Enable event interrupts @@ -537,13 +551,16 @@ impl<'d, M: Mode> I2c<'d, M, MultiMaster> { // Address matched! Read SR2 to get direction and clear ADDR let sr2 = self.info.regs.sr2().read(); let direction = if sr2.tra() { + trace!("i2c v1 slave: address match - READ direction (master wants to read from us)"); SlaveCommandKind::Read // Master wants to read from us (we transmit) } else { + trace!("i2c v1 slave: address match - WRITE direction (master wants to write to us)"); SlaveCommandKind::Write // Master wants to write to us (we receive) }; // Determine which address was matched let matched_address = self.determine_matched_address(sr2)?; + trace!("i2c v1 slave: matched address={:?}", matched_address); // ADDR is automatically cleared by reading SR1 then SR2 return Ok(SlaveCommand { @@ -557,62 +574,86 @@ impl<'d, M: Mode> I2c<'d, M, MultiMaster> { } fn blocking_respond_to_read_timeout(&mut self, data: &[u8], timeout: Timeout) -> Result { + trace!("i2c v1 slave: respond_to_read_timeout start, data_len={}", data.len()); let mut bytes_sent = 0; for &byte in data { + trace!("i2c v1 slave: sending byte={:#x} ({})", byte, bytes_sent); match self.send_byte_or_nack(byte, timeout)? { SlaveSendResult::Acked => { bytes_sent += 1; + trace!("i2c v1 slave: byte acked, total_sent={}", bytes_sent); // Continue sending }, - SlaveSendResult::Nacked | SlaveSendResult::Stopped => { - // Master finished reading or sent STOP + SlaveSendResult::Nacked => { + trace!("i2c v1 slave: byte nacked, stopping transmission"); + break; + }, + SlaveSendResult::Stopped => { + trace!("i2c v1 slave: stop condition detected, stopping transmission"); break; } SlaveSendResult::Restart => { - // Master wants to change direction (rare but possible) + trace!("i2c v1 slave: restart detected, stopping transmission"); break; } } } + trace!("i2c v1 slave: respond_to_read_timeout complete, bytes_sent={}", bytes_sent); Ok(bytes_sent) } fn blocking_respond_to_write_timeout(&mut self, buffer: &mut [u8], timeout: Timeout) -> Result { + trace!("i2c v1 slave: respond_to_write_timeout start, buffer_len={}", buffer.len()); let mut bytes_received = 0; while bytes_received < buffer.len() { match self.recv_byte_or_stop(timeout)? { SlaveReceiveResult::Byte(b) => { + trace!("i2c v1 slave: received byte={:#x} ({})", b, bytes_received); buffer[bytes_received] = b; bytes_received += 1; }, - SlaveReceiveResult::Stop => break, - SlaveReceiveResult::Restart => break, + SlaveReceiveResult::Stop => { + trace!("i2c v1 slave: stop condition detected, stopping reception"); + break; + }, + SlaveReceiveResult::Restart => { + trace!("i2c v1 slave: restart detected, stopping reception"); + break; + }, } } + trace!("i2c v1 slave: respond_to_write_timeout complete, bytes_received={}", bytes_received); Ok(bytes_received) } fn determine_matched_address(&self, sr2: stm32_metapac::i2c::regs::Sr2) -> Result { + trace!("i2c v1 slave: determine_matched_address, sr2={:#x}", sr2.0); // Check for general call first if sr2.gencall() { + trace!("i2c v1 slave: general call address matched"); Ok(Address::SevenBit(0x00)) } else if sr2.dualf() { // OA2 was matched - verify it's actually enabled let oar2 = self.info.regs.oar2().read(); if oar2.endual() != i2c::vals::Endual::DUAL { + error!("i2c v1 slave: OA2 matched but not enabled - hardware inconsistency"); return Err(Error::Bus); // Hardware inconsistency } + trace!("i2c v1 slave: OA2 address matched: {:#x}", oar2.add2()); Ok(Address::SevenBit(oar2.add2())) } else { // OA1 was matched let oar1 = self.info.regs.oar1().read(); match oar1.addmode() { i2c::vals::Addmode::BIT7 => { - Ok(Address::SevenBit((oar1.add() >> 1) as u8)) + let addr = (oar1.add() >> 1) as u8; + trace!("i2c v1 slave: OA1 7-bit address matched: {:#x}", addr); + Ok(Address::SevenBit(addr)) }, i2c::vals::Addmode::BIT10 => { + trace!("i2c v1 slave: OA1 10-bit address matched: {:#x}", oar1.add()); Ok(Address::TenBit(oar1.add())) }, } @@ -621,30 +662,35 @@ impl<'d, M: Mode> I2c<'d, M, MultiMaster> { /// Send a byte in slave transmitter mode and check for ACK/NACK/STOP fn send_byte_or_nack(&mut self, byte: u8, timeout: Timeout) -> Result { + trace!("i2c v1 slave: send_byte_or_nack start, byte={:#x}", byte); // Wait until we're ready for sending (TXE flag set) loop { let sr1 = Self::check_and_clear_error_flags(self.info)?; // Check for STOP condition first if sr1.stopf() { + trace!("i2c v1 slave: STOP detected before send"); self.info.regs.cr1().modify(|_w| {}); return Ok(SlaveSendResult::Stopped); } // Check for RESTART (new ADDR) if sr1.addr() { + trace!("i2c v1 slave: RESTART detected before send"); // Don't clear ADDR here - let next blocking_listen() handle it return Ok(SlaveSendResult::Restart); } // Check for NACK (AF flag) if sr1.af() { + trace!("i2c v1 slave: NACK detected before send"); self.info.regs.sr1().modify(|w| w.set_af(false)); return Ok(SlaveSendResult::Nacked); } // Check if we can send data if sr1.txe() { + trace!("i2c v1 slave: TXE ready, sending byte"); break; // Ready to send } @@ -653,6 +699,7 @@ impl<'d, M: Mode> I2c<'d, M, MultiMaster> { // Send the byte self.info.regs.dr().write(|w| w.set_dr(byte)); + trace!("i2c v1 slave: byte written to DR, waiting for BTF"); // Wait for byte transfer to complete (BTF flag or error) loop { @@ -660,23 +707,27 @@ impl<'d, M: Mode> I2c<'d, M, MultiMaster> { // Check for STOP condition if sr1.stopf() { + trace!("i2c v1 slave: STOP detected after send"); self.info.regs.cr1().modify(|_w| {}); return Ok(SlaveSendResult::Stopped); } // Check for RESTART (new ADDR) if sr1.addr() { + trace!("i2c v1 slave: RESTART detected after send"); return Ok(SlaveSendResult::Restart); } // Check for NACK (AF flag) if sr1.af() { + trace!("i2c v1 slave: NACK detected after send"); self.info.regs.sr1().modify(|w| w.set_af(false)); return Ok(SlaveSendResult::Nacked); } // Check for byte transfer finished if sr1.btf() { + trace!("i2c v1 slave: BTF set, byte transfer complete"); return Ok(SlaveSendResult::Acked); } @@ -686,23 +737,27 @@ impl<'d, M: Mode> I2c<'d, M, MultiMaster> { /// Receive a byte in slave receiver mode or detect STOP condition fn recv_byte_or_stop(&mut self, timeout: Timeout) -> Result { + trace!("i2c v1 slave: recv_byte_or_stop start"); loop { let sr1 = Self::check_and_clear_error_flags(self.info)?; // Check for STOP condition first if sr1.stopf() { + trace!("i2c v1 slave: STOP detected during receive"); self.info.regs.cr1().modify(|_w| {}); return Ok(SlaveReceiveResult::Stop); } // Check for RESTART (new ADDR) if sr1.addr() { + trace!("i2c v1 slave: RESTART detected during receive"); // Don't clear ADDR here - let next blocking_listen() handle it return Ok(SlaveReceiveResult::Restart); } if sr1.rxne() { let byte = self.info.regs.dr().read().dr(); + trace!("i2c v1 slave: received byte={:#x}", byte); return Ok(SlaveReceiveResult::Byte(byte)); } -- cgit From d6d54392f15cb0430a50ba85e45d746aa09fc6ac Mon Sep 17 00:00:00 2001 From: HybridChild Date: Sun, 10 Aug 2025 10:48:12 +0200 Subject: stm32/i2c_v1: Fix bugs with slave address initialization and missing ACK bit --- embassy-stm32/src/i2c/v1.rs | 128 ++++++++++++++++++++++++++++++++++++-------- 1 file changed, 107 insertions(+), 21 deletions(-) diff --git a/embassy-stm32/src/i2c/v1.rs b/embassy-stm32/src/i2c/v1.rs index 3aa003fa5..2bc309258 100644 --- a/embassy-stm32/src/i2c/v1.rs +++ b/embassy-stm32/src/i2c/v1.rs @@ -408,57 +408,97 @@ impl<'d, M: Mode> I2c<'d, M, Master> { } impl<'d, M: Mode, IM: MasterMode> I2c<'d, M, IM> { + /// Enhanced slave configuration with proper v1 address setup pub(crate) fn init_slave(&mut self, config: SlaveAddrConfig) { trace!("i2c v1 slave init: config={:?}", config); + // Disable peripheral for configuration self.info.regs.cr1().modify(|reg| { reg.set_pe(false); }); - - // Configure v1-specific slave settings + + // Configure addresses with proper v1 format self.configure_addresses(config); - // Enable slave mode interrupts and settings - self.info.regs.cr2().modify(|w| { - w.set_itevten(true); // Event interrupts - w.set_iterren(true); // Error interrupts - }); + // Configure general call if requested + if config.general_call { + self.info.regs.cr1().modify(|w| w.set_engc(true)); + trace!("i2c v1 slave: General call enabled"); + } + + // Log final configuration before enabling + let cr1 = self.info.regs.cr1().read(); + let oar1 = self.info.regs.oar1().read(); + let oar2 = self.info.regs.oar2().read(); + trace!("i2c v1 slave: Pre-enable state - CR1={:#x}, OAR1={:#x}, OAR2={:#x}", + cr1.0, oar1.0, oar2.0); + trace!("i2c v1 slave: Address details - OAR1.ADD={:#x}, OAR1.ADDMODE={}, bit14={}", + oar1.add(), oar1.addmode() as u8, (oar1.0 >> 14) & 1); - // Re-enable peripheral self.info.regs.cr1().modify(|reg| { - reg.set_pe(true); + reg.set_pe(true); // Re-enable peripheral + reg.set_ack(true); // Critical for slave to ACK its address }); + + // Verify peripheral is enabled and ready + let cr1_final = self.info.regs.cr1().read(); + trace!("i2c v1 slave: Final state - CR1={:#x}, PE={}", cr1_final.0, cr1_final.pe()); + trace!("i2c v1 slave init complete"); } fn configure_oa1(&mut self, addr: Address) { match addr { Address::SevenBit(addr) => { + trace!("i2c v1 slave: Setting OA1 7-bit address: input={:#x}", addr); self.info.regs.oar1().write(|reg| { - // v1 uses left-shifted 7-bit address in bits [7:1] - // STM32 reference manual says bits 7:1 for address, bit 0 don't care for 7-bit - reg.set_add((addr as u16) << 1); + // For I2C v1, the 7-bit address goes in bits [7:1] of the ADD field + // The ADD field spans bits [9:0], so we put the address in the correct position + let hw_addr = (addr as u16) << 1; // This puts address in bits [7:1], bit [0] = 0 + reg.set_add(hw_addr); reg.set_addmode(i2c::vals::Addmode::BIT7); }); + + // CRITICAL: Set bit 14 as required by the reference manual + // "Bit 14: Should always be kept at 1 by software" + self.info.regs.oar1().modify(|reg| { + reg.0 |= 1 << 14; // Set bit 14 + }); + + let oar1_verify = self.info.regs.oar1().read(); + trace!("i2c v1 slave: OA1 configured - OAR1={:#x}, stored_addr={:#x}, bit14={}", + oar1_verify.0, oar1_verify.add(), (oar1_verify.0 >> 14) & 1); }, Address::TenBit(addr) => { - self.info.regs.oar1().modify(|reg| { - reg.set_add(addr); // Set address bits [9:0] + trace!("i2c v1 slave: Setting OA1 10-bit address: {:#x}", addr); + self.info.regs.oar1().write(|reg| { + reg.set_add(addr); // For 10-bit, full address goes in ADD field reg.set_addmode(i2c::vals::Addmode::BIT10); - // Manually set bit 14 as required by reference manual - reg.0 |= 1 << 14; }); + + // Set required bit 14 for 10-bit mode too + self.info.regs.oar1().modify(|reg| { + reg.0 |= 1 << 14; // Set bit 14 + }); + + let oar1_verify = self.info.regs.oar1().read(); + trace!("i2c v1 slave: OA1 10-bit configured - OAR1={:#x}, bit14={}", + oar1_verify.0, (oar1_verify.0 >> 14) & 1); } } } - + fn configure_oa2_simple(&mut self, addr: u8) { + trace!("i2c v1 slave: Setting OA2 address: {:#x}", addr); self.info.regs.oar2().write(|reg| { - // v1 OA2: 7-bit address only, no masking support - // Address goes in bits [7:1], enable dual addressing - reg.set_add2(addr); - reg.set_endual(i2c::vals::Endual::DUAL); + // For OA2, the address goes in bits [7:1] of the ADD2 field + reg.set_add2(addr); // ADD2 field automatically handles bits [7:1] placement + reg.set_endual(i2c::vals::Endual::DUAL); // Enable dual addressing }); + + let oar2_verify = self.info.regs.oar2().read(); + trace!("i2c v1 slave: OA2 configured - OAR2={:#x}, ADD2={:#x}, ENDUAL={}", + oar2_verify.0, oar2_verify.add2(), oar2_verify.endual() as u8); } fn configure_addresses(&mut self, config: SlaveAddrConfig) { @@ -507,6 +547,52 @@ impl<'d, M: Mode, IM: MasterMode> I2c<'d, M, IM> { } } +// Also add a verification function to check address configuration +impl<'d, M: Mode> I2c<'d, M, MultiMaster> { + /// Verify the slave address configuration is correct + pub fn verify_slave_config(&self) -> Result<(), Error> { + let oar1 = self.info.regs.oar1().read(); + let oar2 = self.info.regs.oar2().read(); + let cr1 = self.info.regs.cr1().read(); + + info!("I2C v1 Slave Configuration Verification:"); + info!(" CR1: {:#x} (PE={})", cr1.0, cr1.pe()); + info!(" OAR1: {:#x}", oar1.0); + info!(" ADD: {:#x}", oar1.add()); + info!(" ADDMODE: {} ({})", oar1.addmode() as u8, + if oar1.addmode() as u8 == 0 { "7-bit" } else { "10-bit" }); + info!(" Bit 14: {}", (oar1.0 >> 14) & 1); + info!(" OAR2: {:#x}", oar2.0); + info!(" ADD2: {:#x}", oar2.add2()); + info!(" ENDUAL: {} ({})", oar2.endual() as u8, + if oar2.endual() as u8 == 0 { "Single" } else { "Dual" }); + + // Check critical requirements + if !cr1.pe() { + error!("ERROR: I2C peripheral not enabled (PE=0)"); + return Err(Error::Bus); + } + + if (oar1.0 >> 14) & 1 == 0 { + error!("ERROR: OAR1 bit 14 not set (required by reference manual)"); + return Err(Error::Bus); + } + + // For 7-bit mode, verify address is in correct position + if oar1.addmode() as u8 == 0 { // 7-bit mode + let expected_addr = 0x42u16 << 1; // 0x84 + if oar1.add() != expected_addr { + error!("ERROR: OAR1 address mismatch - expected {:#x}, got {:#x}", + expected_addr, oar1.add()); + return Err(Error::Bus); + } + } + + info!("✓ Slave configuration appears correct"); + Ok(()) + } +} + impl<'d, M: Mode> I2c<'d, M, MultiMaster> { /// Listen for incoming I2C address match and return the command type pub fn blocking_listen(&mut self) -> Result { -- cgit From 46c95921f38d1548c9afc84c1c660f690fc49be4 Mon Sep 17 00:00:00 2001 From: HybridChild Date: Mon, 11 Aug 2025 11:40:56 +0200 Subject: stm32/i2c_v1: Fix bugs in slave read and write logic --- embassy-stm32/src/i2c/v1.rs | 170 +++++++++++++++++++++----------------------- 1 file changed, 82 insertions(+), 88 deletions(-) diff --git a/embassy-stm32/src/i2c/v1.rs b/embassy-stm32/src/i2c/v1.rs index 2bc309258..83f01f51c 100644 --- a/embassy-stm32/src/i2c/v1.rs +++ b/embassy-stm32/src/i2c/v1.rs @@ -408,7 +408,7 @@ impl<'d, M: Mode> I2c<'d, M, Master> { } impl<'d, M: Mode, IM: MasterMode> I2c<'d, M, IM> { - /// Enhanced slave configuration with proper v1 address setup + /// Slave configuration with v1 address setup pub(crate) fn init_slave(&mut self, config: SlaveAddrConfig) { trace!("i2c v1 slave init: config={:?}", config); @@ -547,52 +547,6 @@ impl<'d, M: Mode, IM: MasterMode> I2c<'d, M, IM> { } } -// Also add a verification function to check address configuration -impl<'d, M: Mode> I2c<'d, M, MultiMaster> { - /// Verify the slave address configuration is correct - pub fn verify_slave_config(&self) -> Result<(), Error> { - let oar1 = self.info.regs.oar1().read(); - let oar2 = self.info.regs.oar2().read(); - let cr1 = self.info.regs.cr1().read(); - - info!("I2C v1 Slave Configuration Verification:"); - info!(" CR1: {:#x} (PE={})", cr1.0, cr1.pe()); - info!(" OAR1: {:#x}", oar1.0); - info!(" ADD: {:#x}", oar1.add()); - info!(" ADDMODE: {} ({})", oar1.addmode() as u8, - if oar1.addmode() as u8 == 0 { "7-bit" } else { "10-bit" }); - info!(" Bit 14: {}", (oar1.0 >> 14) & 1); - info!(" OAR2: {:#x}", oar2.0); - info!(" ADD2: {:#x}", oar2.add2()); - info!(" ENDUAL: {} ({})", oar2.endual() as u8, - if oar2.endual() as u8 == 0 { "Single" } else { "Dual" }); - - // Check critical requirements - if !cr1.pe() { - error!("ERROR: I2C peripheral not enabled (PE=0)"); - return Err(Error::Bus); - } - - if (oar1.0 >> 14) & 1 == 0 { - error!("ERROR: OAR1 bit 14 not set (required by reference manual)"); - return Err(Error::Bus); - } - - // For 7-bit mode, verify address is in correct position - if oar1.addmode() as u8 == 0 { // 7-bit mode - let expected_addr = 0x42u16 << 1; // 0x84 - if oar1.add() != expected_addr { - error!("ERROR: OAR1 address mismatch - expected {:#x}, got {:#x}", - expected_addr, oar1.add()); - return Err(Error::Bus); - } - } - - info!("✓ Slave configuration appears correct"); - Ok(()) - } -} - impl<'d, M: Mode> I2c<'d, M, MultiMaster> { /// Listen for incoming I2C address match and return the command type pub fn blocking_listen(&mut self) -> Result { @@ -624,24 +578,26 @@ impl<'d, M: Mode> I2c<'d, M, MultiMaster> { // Private implementation methods with Timeout parameter fn blocking_listen_timeout(&mut self, timeout: Timeout) -> Result { trace!("i2c v1 slave: listen_timeout start"); - // Enable address match interrupt for slave mode + + // Disable interrupts for blocking operation self.info.regs.cr2().modify(|w| { - w.set_itevten(true); // Enable event interrupts + w.set_itevten(false); + w.set_iterren(false); }); // Wait for address match (ADDR flag) loop { - let sr1 = Self::check_and_clear_error_flags(self.info)?; + let sr1 = Self::check_slave_error_flags_and_get_sr1(self.info)?; if sr1.addr() { // Address matched! Read SR2 to get direction and clear ADDR let sr2 = self.info.regs.sr2().read(); let direction = if sr2.tra() { - trace!("i2c v1 slave: address match - READ direction (master wants to read from us)"); - SlaveCommandKind::Read // Master wants to read from us (we transmit) + trace!("i2c v1 slave: address match - READ direction"); + SlaveCommandKind::Read } else { - trace!("i2c v1 slave: address match - WRITE direction (master wants to write to us)"); - SlaveCommandKind::Write // Master wants to write to us (we receive) + trace!("i2c v1 slave: address match - WRITE direction"); + SlaveCommandKind::Write }; // Determine which address was matched @@ -672,22 +628,23 @@ impl<'d, M: Mode> I2c<'d, M, MultiMaster> { // Continue sending }, SlaveSendResult::Nacked => { - trace!("i2c v1 slave: byte nacked, stopping transmission"); - break; + bytes_sent += 1; // Count the NACKed byte as sent + trace!("i2c v1 slave: byte nacked by master (normal completion), total_sent={}", bytes_sent); + break; // Normal end of transmission }, SlaveSendResult::Stopped => { trace!("i2c v1 slave: stop condition detected, stopping transmission"); - break; + break; // Master sent STOP } SlaveSendResult::Restart => { trace!("i2c v1 slave: restart detected, stopping transmission"); - break; + break; // Master sent RESTART } } } trace!("i2c v1 slave: respond_to_read_timeout complete, bytes_sent={}", bytes_sent); - Ok(bytes_sent) + Ok(bytes_sent) // Always return success with byte count } fn blocking_respond_to_write_timeout(&mut self, buffer: &mut [u8], timeout: Timeout) -> Result { @@ -749,9 +706,10 @@ impl<'d, M: Mode> I2c<'d, M, MultiMaster> { /// Send a byte in slave transmitter mode and check for ACK/NACK/STOP fn send_byte_or_nack(&mut self, byte: u8, timeout: Timeout) -> Result { trace!("i2c v1 slave: send_byte_or_nack start, byte={:#x}", byte); + // Wait until we're ready for sending (TXE flag set) loop { - let sr1 = Self::check_and_clear_error_flags(self.info)?; + let sr1 = Self::check_slave_error_flags_and_get_sr1(self.info)?; // Check for STOP condition first if sr1.stopf() { @@ -763,14 +721,17 @@ impl<'d, M: Mode> I2c<'d, M, MultiMaster> { // Check for RESTART (new ADDR) if sr1.addr() { trace!("i2c v1 slave: RESTART detected before send"); - // Don't clear ADDR here - let next blocking_listen() handle it return Ok(SlaveSendResult::Restart); } - // Check for NACK (AF flag) - if sr1.af() { + // Check for NACK (AF flag) before writing + let sr1_current = self.info.regs.sr1().read(); + if sr1_current.af() { trace!("i2c v1 slave: NACK detected before send"); - self.info.regs.sr1().modify(|w| w.set_af(false)); + self.info.regs.sr1().write(|reg| { + reg.0 = !0; + reg.set_af(false); + }); return Ok(SlaveSendResult::Nacked); } @@ -785,11 +746,28 @@ impl<'d, M: Mode> I2c<'d, M, MultiMaster> { // Send the byte self.info.regs.dr().write(|w| w.set_dr(byte)); - trace!("i2c v1 slave: byte written to DR, waiting for BTF"); + trace!("i2c v1 slave: byte written to DR, waiting for completion"); - // Wait for byte transfer to complete (BTF flag or error) + // Wait for completion - but be more flexible about what constitutes "completion" + // In slave transmitter mode, we need to detect: + // 1. BTF - byte transfer finished (normal case) + // 2. AF (NACK) - master signals end of transaction + // 3. STOP - master terminates transaction + // 4. ADDR - master starts new transaction (restart) loop { - let sr1 = Self::check_and_clear_error_flags(self.info)?; + // Get current flags without error handling that clears AF + let sr1 = self.info.regs.sr1().read(); + + // Check for NACK FIRST - this is the most likely end condition + if sr1.af() { + trace!("i2c v1 slave: NACK detected after send"); + // Clear the AF flag + self.info.regs.sr1().write(|reg| { + reg.0 = !0; + reg.set_af(false); + }); + return Ok(SlaveSendResult::Nacked); + } // Check for STOP condition if sr1.stopf() { @@ -804,19 +782,21 @@ impl<'d, M: Mode> I2c<'d, M, MultiMaster> { return Ok(SlaveSendResult::Restart); } - // Check for NACK (AF flag) - if sr1.af() { - trace!("i2c v1 slave: NACK detected after send"); - self.info.regs.sr1().modify(|w| w.set_af(false)); - return Ok(SlaveSendResult::Nacked); - } - - // Check for byte transfer finished + // Check for byte transfer finished (normal ACK case) if sr1.btf() { - trace!("i2c v1 slave: BTF set, byte transfer complete"); + trace!("i2c v1 slave: BTF set, byte transfer complete (ACK)"); return Ok(SlaveSendResult::Acked); } + // Check for other error conditions that should be propagated + if sr1.timeout() || sr1.ovr() || sr1.arlo() || sr1.berr() { + // Use the error handling function for these + match Self::check_and_clear_error_flags(self.info) { + Ok(_) => {}, // Shouldn't happen given the flags we checked + Err(e) => return Err(e), + } + } + timeout.check()?; } } @@ -825,31 +805,45 @@ impl<'d, M: Mode> I2c<'d, M, MultiMaster> { fn recv_byte_or_stop(&mut self, timeout: Timeout) -> Result { trace!("i2c v1 slave: recv_byte_or_stop start"); loop { - let sr1 = Self::check_and_clear_error_flags(self.info)?; + let sr1 = Self::check_slave_error_flags_and_get_sr1(self.info)?; - // Check for STOP condition first - if sr1.stopf() { - trace!("i2c v1 slave: STOP detected during receive"); - self.info.regs.cr1().modify(|_w| {}); - return Ok(SlaveReceiveResult::Stop); + // Check for received data FIRST (handles race condition) + if sr1.rxne() { + let byte = self.info.regs.dr().read().dr(); + trace!("i2c v1 slave: received byte={:#x}", byte); + return Ok(SlaveReceiveResult::Byte(byte)); } - // Check for RESTART (new ADDR) + // Check for RESTART (new ADDR) before STOP if sr1.addr() { trace!("i2c v1 slave: RESTART detected during receive"); - // Don't clear ADDR here - let next blocking_listen() handle it return Ok(SlaveReceiveResult::Restart); } - if sr1.rxne() { - let byte = self.info.regs.dr().read().dr(); - trace!("i2c v1 slave: received byte={:#x}", byte); - return Ok(SlaveReceiveResult::Byte(byte)); + // Check for STOP condition LAST + if sr1.stopf() { + trace!("i2c v1 slave: STOP detected during receive"); + self.info.regs.cr1().modify(|_w| {}); + return Ok(SlaveReceiveResult::Stop); } timeout.check()?; } } + + /// Wrapper that treats AF (NACK) as normal protocol behavior in slave mode + fn check_slave_error_flags_and_get_sr1(info: &'static Info) -> Result { + match Self::check_and_clear_error_flags(info) { + Ok(sr1) => Ok(sr1), + Err(Error::Nack) => { + // AF flag was set and cleared by check_and_clear_error_flags + // In slave mode, this is normal protocol behavior, not an error + // Read SR1 again to get current state (AF should now be cleared) + Ok(info.regs.sr1().read()) + }, + Err(other_error) => Err(other_error), // Propagate real errors + } + } } impl<'d, IM: MasterMode> I2c<'d, Async, IM> { -- cgit From 4f7febc34eab0dd5822f313854338997f6dbf617 Mon Sep 17 00:00:00 2001 From: HybridChild Date: Mon, 11 Aug 2025 12:04:38 +0200 Subject: stm32/i2c_v1: Better handling of slave read and write overflow --- embassy-stm32/src/i2c/v1.rs | 64 +++++++++++++++++++++++++++++++++++++++------ 1 file changed, 56 insertions(+), 8 deletions(-) diff --git a/embassy-stm32/src/i2c/v1.rs b/embassy-stm32/src/i2c/v1.rs index 83f01f51c..9022c2f5d 100644 --- a/embassy-stm32/src/i2c/v1.rs +++ b/embassy-stm32/src/i2c/v1.rs @@ -618,14 +618,28 @@ impl<'d, M: Mode> I2c<'d, M, MultiMaster> { fn blocking_respond_to_read_timeout(&mut self, data: &[u8], timeout: Timeout) -> Result { trace!("i2c v1 slave: respond_to_read_timeout start, data_len={}", data.len()); let mut bytes_sent = 0; + let mut data_exhausted = false; - for &byte in data { - trace!("i2c v1 slave: sending byte={:#x} ({})", byte, bytes_sent); - match self.send_byte_or_nack(byte, timeout)? { + loop { + // Determine what byte to send + let byte_to_send = if bytes_sent < data.len() { + // Send real data + data[bytes_sent] + } else { + // Data exhausted - send padding bytes + if !data_exhausted { + trace!("i2c v1 slave: real data exhausted, sending padding bytes"); + data_exhausted = true; + } + 0x00 // Send zeros as padding (or 0xFF, or last byte repeated) + }; + + trace!("i2c v1 slave: sending byte={:#x} ({})", byte_to_send, bytes_sent); + match self.send_byte_or_nack(byte_to_send, timeout)? { SlaveSendResult::Acked => { bytes_sent += 1; trace!("i2c v1 slave: byte acked, total_sent={}", bytes_sent); - // Continue sending + // Continue sending more bytes }, SlaveSendResult::Nacked => { bytes_sent += 1; // Count the NACKed byte as sent @@ -644,13 +658,16 @@ impl<'d, M: Mode> I2c<'d, M, MultiMaster> { } trace!("i2c v1 slave: respond_to_read_timeout complete, bytes_sent={}", bytes_sent); - Ok(bytes_sent) // Always return success with byte count + Ok(bytes_sent) // Return total bytes sent (including padding) } fn blocking_respond_to_write_timeout(&mut self, buffer: &mut [u8], timeout: Timeout) -> Result { trace!("i2c v1 slave: respond_to_write_timeout start, buffer_len={}", buffer.len()); let mut bytes_received = 0; - while bytes_received < buffer.len() { + let buffer_capacity = buffer.len(); + let mut overflow_detected = false; + + while bytes_received < buffer_capacity { match self.recv_byte_or_stop(timeout)? { SlaveReceiveResult::Byte(b) => { trace!("i2c v1 slave: received byte={:#x} ({})", b, bytes_received); @@ -667,8 +684,39 @@ impl<'d, M: Mode> I2c<'d, M, MultiMaster> { }, } } - trace!("i2c v1 slave: respond_to_write_timeout complete, bytes_received={}", bytes_received); - Ok(bytes_received) + + // Handle buffer overflow - continue receiving but discard bytes + if bytes_received >= buffer_capacity { + loop { + match self.recv_byte_or_stop(timeout)? { + SlaveReceiveResult::Byte(b) => { + if !overflow_detected { + trace!("i2c v1 slave: buffer full, discarding excess bytes"); + overflow_detected = true; + } + trace!("i2c v1 slave: discarding overflow byte={:#x}", b); + // Byte is discarded but we still ACK it + }, + SlaveReceiveResult::Stop => { + trace!("i2c v1 slave: stop condition detected after overflow"); + break; + }, + SlaveReceiveResult::Restart => { + trace!("i2c v1 slave: restart detected after overflow"); + break; + }, + } + } + } + + if overflow_detected { + trace!("i2c v1 slave: transaction complete with overflow - received {} bytes, buffer held {}", + bytes_received, buffer_capacity); + } else { + trace!("i2c v1 slave: respond_to_write_timeout complete, bytes_received={}", bytes_received); + } + + Ok(bytes_received.min(buffer_capacity)) // Return stored bytes, not total received } fn determine_matched_address(&self, sr2: stm32_metapac::i2c::regs::Sr2) -> Result { -- cgit From fd7158063d38ece65f6f3f13422b2d744e8a144f Mon Sep 17 00:00:00 2001 From: HybridChild Date: Mon, 11 Aug 2025 19:56:52 +0200 Subject: stm32/i2c_v1: Clean up slave implementation --- embassy-stm32/src/i2c/v1.rs | 1382 +++++++++++++++++++++---------------------- 1 file changed, 665 insertions(+), 717 deletions(-) diff --git a/embassy-stm32/src/i2c/v1.rs b/embassy-stm32/src/i2c/v1.rs index 9022c2f5d..8f4128b45 100644 --- a/embassy-stm32/src/i2c/v1.rs +++ b/embassy-stm32/src/i2c/v1.rs @@ -32,21 +32,6 @@ impl State { } } -#[derive(Debug, PartialEq)] -enum SlaveSendResult { - Acked, // Byte sent and ACK received from master - Nacked, // Byte sent but NACK received (normal end of transmission) - Stopped, // STOP condition detected - Restart, // RESTART condition detected -} - -#[derive(Debug, PartialEq)] -enum SlaveReceiveResult { - Byte(u8), // Data byte received - Stop, // STOP condition detected - Restart, // RESTART condition (new ADDR) detected -} - // /!\ /!\ // /!\ Implementation note! /!\ // /!\ /!\ @@ -387,515 +372,175 @@ impl<'d, M: Mode, IM: MasterMode> I2c<'d, M, IM> { } } -impl<'d, M: Mode> I2c<'d, M, Master> { - /// Configure the I2C driver for slave operations, allowing for the driver to be used as a slave and a master (multimaster) - pub fn into_slave_multimaster(mut self, slave_addr_config: SlaveAddrConfig) -> I2c<'d, M, MultiMaster> { - let mut slave = I2c { - info: self.info, - state: self.state, - kernel_clock: self.kernel_clock, - tx_dma: self.tx_dma.take(), // Use take() to move ownership - rx_dma: self.rx_dma.take(), // Use take() to move ownership - #[cfg(feature = "time")] - timeout: self.timeout, - _phantom: PhantomData, - _phantom2: PhantomData, - _drop_guard: self._drop_guard, // Move the drop guard - }; - slave.init_slave(slave_addr_config); - slave - } -} - -impl<'d, M: Mode, IM: MasterMode> I2c<'d, M, IM> { - /// Slave configuration with v1 address setup - pub(crate) fn init_slave(&mut self, config: SlaveAddrConfig) { - trace!("i2c v1 slave init: config={:?}", config); - - // Disable peripheral for configuration - self.info.regs.cr1().modify(|reg| { - reg.set_pe(false); +impl<'d, IM: MasterMode> I2c<'d, Async, IM> { + async fn write_with_framing(&mut self, address: u8, write_buffer: &[u8], framing: OperationFraming) -> Result<(), Error> { + self.info.regs.cr2().modify(|w| { + // Note: Do not enable the ITBUFEN bit in the I2C_CR2 register if DMA is used for + // reception. + w.set_itbufen(false); + // DMA mode can be enabled for transmission by setting the DMAEN bit in the I2C_CR2 + // register. + w.set_dmaen(true); + // Sending NACK is not necessary (nor possible) for write transfer. + w.set_last(false); }); - - // Configure addresses with proper v1 format - self.configure_addresses(config); - - // Configure general call if requested - if config.general_call { - self.info.regs.cr1().modify(|w| w.set_engc(true)); - trace!("i2c v1 slave: General call enabled"); - } - - // Log final configuration before enabling - let cr1 = self.info.regs.cr1().read(); - let oar1 = self.info.regs.oar1().read(); - let oar2 = self.info.regs.oar2().read(); - trace!("i2c v1 slave: Pre-enable state - CR1={:#x}, OAR1={:#x}, OAR2={:#x}", - cr1.0, oar1.0, oar2.0); - trace!("i2c v1 slave: Address details - OAR1.ADD={:#x}, OAR1.ADDMODE={}, bit14={}", - oar1.add(), oar1.addmode() as u8, (oar1.0 >> 14) & 1); - self.info.regs.cr1().modify(|reg| { - reg.set_pe(true); // Re-enable peripheral - reg.set_ack(true); // Critical for slave to ACK its address + // Sentinel to disable transfer when an error occurs or future is canceled. + // TODO: Generate STOP condition on cancel? + let on_drop = OnDrop::new(|| { + self.info.regs.cr2().modify(|w| { + w.set_dmaen(false); + w.set_iterren(false); + w.set_itevten(false); + }) }); - - // Verify peripheral is enabled and ready - let cr1_final = self.info.regs.cr1().read(); - trace!("i2c v1 slave: Final state - CR1={:#x}, PE={}", cr1_final.0, cr1_final.pe()); - - trace!("i2c v1 slave init complete"); - } - fn configure_oa1(&mut self, addr: Address) { - match addr { - Address::SevenBit(addr) => { - trace!("i2c v1 slave: Setting OA1 7-bit address: input={:#x}", addr); - self.info.regs.oar1().write(|reg| { - // For I2C v1, the 7-bit address goes in bits [7:1] of the ADD field - // The ADD field spans bits [9:0], so we put the address in the correct position - let hw_addr = (addr as u16) << 1; // This puts address in bits [7:1], bit [0] = 0 - reg.set_add(hw_addr); - reg.set_addmode(i2c::vals::Addmode::BIT7); - }); - - // CRITICAL: Set bit 14 as required by the reference manual - // "Bit 14: Should always be kept at 1 by software" - self.info.regs.oar1().modify(|reg| { - reg.0 |= 1 << 14; // Set bit 14 - }); - - let oar1_verify = self.info.regs.oar1().read(); - trace!("i2c v1 slave: OA1 configured - OAR1={:#x}, stored_addr={:#x}, bit14={}", - oar1_verify.0, oar1_verify.add(), (oar1_verify.0 >> 14) & 1); - }, - Address::TenBit(addr) => { - trace!("i2c v1 slave: Setting OA1 10-bit address: {:#x}", addr); - self.info.regs.oar1().write(|reg| { - reg.set_add(addr); // For 10-bit, full address goes in ADD field - reg.set_addmode(i2c::vals::Addmode::BIT10); - }); - - // Set required bit 14 for 10-bit mode too - self.info.regs.oar1().modify(|reg| { - reg.0 |= 1 << 14; // Set bit 14 - }); - - let oar1_verify = self.info.regs.oar1().read(); - trace!("i2c v1 slave: OA1 10-bit configured - OAR1={:#x}, bit14={}", - oar1_verify.0, (oar1_verify.0 >> 14) & 1); + if framing.send_start() { + // Send a START condition + self.info.regs.cr1().modify(|reg| { + reg.set_start(true); + }); + + // Wait until START condition was generated + poll_fn(|cx| { + self.state.waker.register(cx.waker()); + + match Self::check_and_clear_error_flags(self.info) { + Err(e) => Poll::Ready(Err(e)), + Ok(sr1) => { + if sr1.start() { + Poll::Ready(Ok(())) + } else { + // When pending, (re-)enable interrupts to wake us up. + Self::enable_interrupts(self.info); + Poll::Pending + } + } + } + }) + .await?; + + // Check if we were the ones to generate START + if self.info.regs.cr1().read().start() || !self.info.regs.sr2().read().msl() { + return Err(Error::Arbitration); } - } - } - - fn configure_oa2_simple(&mut self, addr: u8) { - trace!("i2c v1 slave: Setting OA2 address: {:#x}", addr); - self.info.regs.oar2().write(|reg| { - // For OA2, the address goes in bits [7:1] of the ADD2 field - reg.set_add2(addr); // ADD2 field automatically handles bits [7:1] placement - reg.set_endual(i2c::vals::Endual::DUAL); // Enable dual addressing - }); - - let oar2_verify = self.info.regs.oar2().read(); - trace!("i2c v1 slave: OA2 configured - OAR2={:#x}, ADD2={:#x}, ENDUAL={}", - oar2_verify.0, oar2_verify.add2(), oar2_verify.endual() as u8); - } - fn configure_addresses(&mut self, config: SlaveAddrConfig) { - match config.addr { - OwnAddresses::OA1(addr) => { - self.configure_oa1(addr); - // Disable OA2 if not needed - self.info.regs.oar2().write(|reg| { - reg.set_endual(i2c::vals::Endual::SINGLE); - }); - }, - OwnAddresses::OA2(oa2) => { - // v1 limitation: ignore mask, only support simple OA2 - if !matches!(oa2.mask, AddrMask::NOMASK) { - // Could log a warning here that masking is ignored in v1 - #[cfg(feature = "defmt")] - warn!("I2C v1 does not support OA2 address masking, ignoring mask setting"); + // Set up current address we're trying to talk to + self.info.regs.dr().write(|reg| reg.set_dr(address << 1)); + + // Wait for the address to be acknowledged + poll_fn(|cx| { + self.state.waker.register(cx.waker()); + + match Self::check_and_clear_error_flags(self.info) { + Err(e) => Poll::Ready(Err(e)), + Ok(sr1) => { + if sr1.addr() { + Poll::Ready(Ok(())) + } else { + // When pending, (re-)enable interrupts to wake us up. + Self::enable_interrupts(self.info); + Poll::Pending + } + } } - - // Must have a default OA1 when using OA2-only mode - // Set OA1 to a reserved address that won't conflict - self.info.regs.oar1().write(|reg| { - reg.set_add(0); // Address 0x00 is reserved, safe to use - reg.set_addmode(i2c::vals::Addmode::BIT7); - }); - - self.configure_oa2_simple(oa2.addr); - }, - OwnAddresses::Both { oa1, oa2 } => { - self.configure_oa1(oa1); - - // Same masking limitation applies - if !matches!(oa2.mask, AddrMask::NOMASK) { - #[cfg(feature = "defmt")] - defmt::warn!("I2C v1 does not support OA2 address masking, ignoring mask setting"); + }) + .await?; + + // Clear condition by reading SR2 + self.info.regs.sr2().read(); + } + + let dma_transfer = unsafe { + // Set the I2C_DR register address in the DMA_SxPAR register. The data will be moved to + // this address from the memory after each TxE event. + let dst = self.info.regs.dr().as_ptr() as *mut u8; + + self.tx_dma.as_mut().unwrap().write(write_buffer, dst, Default::default()) + }; + + // Wait for bytes to be sent, or an error to occur. + let poll_error = poll_fn(|cx| { + self.state.waker.register(cx.waker()); + + match Self::check_and_clear_error_flags(self.info) { + Err(e) => Poll::Ready(Err::<(), Error>(e)), + Ok(_) => { + // When pending, (re-)enable interrupts to wake us up. + Self::enable_interrupts(self.info); + Poll::Pending } - - self.configure_oa2_simple(oa2.addr); } + }); + + // Wait for either the DMA transfer to successfully finish, or an I2C error to occur. + match select(dma_transfer, poll_error).await { + Either::Second(Err(e)) => Err(e), + _ => Ok(()), + }?; + + self.info.regs.cr2().modify(|w| { + w.set_dmaen(false); + }); + + if framing.send_stop() { + // The I2C transfer itself will take longer than the DMA transfer, so wait for that to finish too. + + // 18.3.8 “Master transmitter: In the interrupt routine after the EOT interrupt, disable DMA + // requests then wait for a BTF event before programming the Stop condition.” + poll_fn(|cx| { + self.state.waker.register(cx.waker()); + + match Self::check_and_clear_error_flags(self.info) { + Err(e) => Poll::Ready(Err(e)), + Ok(sr1) => { + if sr1.btf() { + Poll::Ready(Ok(())) + } else { + // When pending, (re-)enable interrupts to wake us up. + Self::enable_interrupts(self.info); + Poll::Pending + } + } + } + }) + .await?; + + self.info.regs.cr1().modify(|w| { + w.set_stop(true); + }); } - - // Configure general call if requested - if config.general_call { - self.info.regs.cr1().modify(|w| w.set_engc(true)); - } - } -} -impl<'d, M: Mode> I2c<'d, M, MultiMaster> { - /// Listen for incoming I2C address match and return the command type - pub fn blocking_listen(&mut self) -> Result { - trace!("i2c v1 slave: blocking_listen start"); - let timeout = self.timeout(); // Get timeout internally - let result = self.blocking_listen_timeout(timeout); - trace!("i2c v1 slave: blocking_listen result={:?}", result); - result + drop(on_drop); + + // Fallthrough is success + Ok(()) } - - /// Respond to master read request (master wants to read from us) - pub fn blocking_respond_to_read(&mut self, data: &[u8]) -> Result { - trace!("i2c v1 slave: blocking_respond_to_read start, data_len={}", data.len()); - let timeout = self.timeout(); // Get timeout internally - let result = self.blocking_respond_to_read_timeout(data, timeout); - trace!("i2c v1 slave: blocking_respond_to_read result={:?}", result); - result + + /// Write. + pub async fn write(&mut self, address: u8, write_buffer: &[u8]) -> Result<(), Error> { + self.write_with_framing(address, write_buffer, OperationFraming::FirstAndLast) + .await?; + + Ok(()) } - - /// Respond to master write request (master wants to write to us) - pub fn blocking_respond_to_write(&mut self, buffer: &mut [u8]) -> Result { - trace!("i2c v1 slave: blocking_respond_to_write start, buffer_len={}", buffer.len()); - let timeout = self.timeout(); // Get timeout internally - let result = self.blocking_respond_to_write_timeout(buffer, timeout); - trace!("i2c v1 slave: blocking_respond_to_write result={:?}", result); - result + + /// Read. + pub async fn read(&mut self, address: u8, read_buffer: &mut [u8]) -> Result<(), Error> { + self.read_with_framing(address, read_buffer, OperationFraming::FirstAndLast) + .await?; + + Ok(()) } - - // Private implementation methods with Timeout parameter - fn blocking_listen_timeout(&mut self, timeout: Timeout) -> Result { - trace!("i2c v1 slave: listen_timeout start"); - - // Disable interrupts for blocking operation - self.info.regs.cr2().modify(|w| { - w.set_itevten(false); - w.set_iterren(false); - }); - - // Wait for address match (ADDR flag) - loop { - let sr1 = Self::check_slave_error_flags_and_get_sr1(self.info)?; - - if sr1.addr() { - // Address matched! Read SR2 to get direction and clear ADDR - let sr2 = self.info.regs.sr2().read(); - let direction = if sr2.tra() { - trace!("i2c v1 slave: address match - READ direction"); - SlaveCommandKind::Read - } else { - trace!("i2c v1 slave: address match - WRITE direction"); - SlaveCommandKind::Write - }; - - // Determine which address was matched - let matched_address = self.determine_matched_address(sr2)?; - trace!("i2c v1 slave: matched address={:?}", matched_address); - - // ADDR is automatically cleared by reading SR1 then SR2 - return Ok(SlaveCommand { - kind: direction, - address: matched_address, - }); - } - - timeout.check()?; - } - } - - fn blocking_respond_to_read_timeout(&mut self, data: &[u8], timeout: Timeout) -> Result { - trace!("i2c v1 slave: respond_to_read_timeout start, data_len={}", data.len()); - let mut bytes_sent = 0; - let mut data_exhausted = false; - - loop { - // Determine what byte to send - let byte_to_send = if bytes_sent < data.len() { - // Send real data - data[bytes_sent] - } else { - // Data exhausted - send padding bytes - if !data_exhausted { - trace!("i2c v1 slave: real data exhausted, sending padding bytes"); - data_exhausted = true; - } - 0x00 // Send zeros as padding (or 0xFF, or last byte repeated) - }; - - trace!("i2c v1 slave: sending byte={:#x} ({})", byte_to_send, bytes_sent); - match self.send_byte_or_nack(byte_to_send, timeout)? { - SlaveSendResult::Acked => { - bytes_sent += 1; - trace!("i2c v1 slave: byte acked, total_sent={}", bytes_sent); - // Continue sending more bytes - }, - SlaveSendResult::Nacked => { - bytes_sent += 1; // Count the NACKed byte as sent - trace!("i2c v1 slave: byte nacked by master (normal completion), total_sent={}", bytes_sent); - break; // Normal end of transmission - }, - SlaveSendResult::Stopped => { - trace!("i2c v1 slave: stop condition detected, stopping transmission"); - break; // Master sent STOP - } - SlaveSendResult::Restart => { - trace!("i2c v1 slave: restart detected, stopping transmission"); - break; // Master sent RESTART - } - } - } - - trace!("i2c v1 slave: respond_to_read_timeout complete, bytes_sent={}", bytes_sent); - Ok(bytes_sent) // Return total bytes sent (including padding) - } - - fn blocking_respond_to_write_timeout(&mut self, buffer: &mut [u8], timeout: Timeout) -> Result { - trace!("i2c v1 slave: respond_to_write_timeout start, buffer_len={}", buffer.len()); - let mut bytes_received = 0; - let buffer_capacity = buffer.len(); - let mut overflow_detected = false; - - while bytes_received < buffer_capacity { - match self.recv_byte_or_stop(timeout)? { - SlaveReceiveResult::Byte(b) => { - trace!("i2c v1 slave: received byte={:#x} ({})", b, bytes_received); - buffer[bytes_received] = b; - bytes_received += 1; - }, - SlaveReceiveResult::Stop => { - trace!("i2c v1 slave: stop condition detected, stopping reception"); - break; - }, - SlaveReceiveResult::Restart => { - trace!("i2c v1 slave: restart detected, stopping reception"); - break; - }, - } - } - - // Handle buffer overflow - continue receiving but discard bytes - if bytes_received >= buffer_capacity { - loop { - match self.recv_byte_or_stop(timeout)? { - SlaveReceiveResult::Byte(b) => { - if !overflow_detected { - trace!("i2c v1 slave: buffer full, discarding excess bytes"); - overflow_detected = true; - } - trace!("i2c v1 slave: discarding overflow byte={:#x}", b); - // Byte is discarded but we still ACK it - }, - SlaveReceiveResult::Stop => { - trace!("i2c v1 slave: stop condition detected after overflow"); - break; - }, - SlaveReceiveResult::Restart => { - trace!("i2c v1 slave: restart detected after overflow"); - break; - }, - } - } - } - - if overflow_detected { - trace!("i2c v1 slave: transaction complete with overflow - received {} bytes, buffer held {}", - bytes_received, buffer_capacity); - } else { - trace!("i2c v1 slave: respond_to_write_timeout complete, bytes_received={}", bytes_received); - } - - Ok(bytes_received.min(buffer_capacity)) // Return stored bytes, not total received - } - - fn determine_matched_address(&self, sr2: stm32_metapac::i2c::regs::Sr2) -> Result { - trace!("i2c v1 slave: determine_matched_address, sr2={:#x}", sr2.0); - // Check for general call first - if sr2.gencall() { - trace!("i2c v1 slave: general call address matched"); - Ok(Address::SevenBit(0x00)) - } else if sr2.dualf() { - // OA2 was matched - verify it's actually enabled - let oar2 = self.info.regs.oar2().read(); - if oar2.endual() != i2c::vals::Endual::DUAL { - error!("i2c v1 slave: OA2 matched but not enabled - hardware inconsistency"); - return Err(Error::Bus); // Hardware inconsistency - } - trace!("i2c v1 slave: OA2 address matched: {:#x}", oar2.add2()); - Ok(Address::SevenBit(oar2.add2())) - } else { - // OA1 was matched - let oar1 = self.info.regs.oar1().read(); - match oar1.addmode() { - i2c::vals::Addmode::BIT7 => { - let addr = (oar1.add() >> 1) as u8; - trace!("i2c v1 slave: OA1 7-bit address matched: {:#x}", addr); - Ok(Address::SevenBit(addr)) - }, - i2c::vals::Addmode::BIT10 => { - trace!("i2c v1 slave: OA1 10-bit address matched: {:#x}", oar1.add()); - Ok(Address::TenBit(oar1.add())) - }, - } - } - } - - /// Send a byte in slave transmitter mode and check for ACK/NACK/STOP - fn send_byte_or_nack(&mut self, byte: u8, timeout: Timeout) -> Result { - trace!("i2c v1 slave: send_byte_or_nack start, byte={:#x}", byte); - - // Wait until we're ready for sending (TXE flag set) - loop { - let sr1 = Self::check_slave_error_flags_and_get_sr1(self.info)?; - - // Check for STOP condition first - if sr1.stopf() { - trace!("i2c v1 slave: STOP detected before send"); - self.info.regs.cr1().modify(|_w| {}); - return Ok(SlaveSendResult::Stopped); - } - - // Check for RESTART (new ADDR) - if sr1.addr() { - trace!("i2c v1 slave: RESTART detected before send"); - return Ok(SlaveSendResult::Restart); - } - - // Check for NACK (AF flag) before writing - let sr1_current = self.info.regs.sr1().read(); - if sr1_current.af() { - trace!("i2c v1 slave: NACK detected before send"); - self.info.regs.sr1().write(|reg| { - reg.0 = !0; - reg.set_af(false); - }); - return Ok(SlaveSendResult::Nacked); - } - - // Check if we can send data - if sr1.txe() { - trace!("i2c v1 slave: TXE ready, sending byte"); - break; // Ready to send - } - - timeout.check()?; - } - - // Send the byte - self.info.regs.dr().write(|w| w.set_dr(byte)); - trace!("i2c v1 slave: byte written to DR, waiting for completion"); - - // Wait for completion - but be more flexible about what constitutes "completion" - // In slave transmitter mode, we need to detect: - // 1. BTF - byte transfer finished (normal case) - // 2. AF (NACK) - master signals end of transaction - // 3. STOP - master terminates transaction - // 4. ADDR - master starts new transaction (restart) - loop { - // Get current flags without error handling that clears AF - let sr1 = self.info.regs.sr1().read(); - - // Check for NACK FIRST - this is the most likely end condition - if sr1.af() { - trace!("i2c v1 slave: NACK detected after send"); - // Clear the AF flag - self.info.regs.sr1().write(|reg| { - reg.0 = !0; - reg.set_af(false); - }); - return Ok(SlaveSendResult::Nacked); - } - - // Check for STOP condition - if sr1.stopf() { - trace!("i2c v1 slave: STOP detected after send"); - self.info.regs.cr1().modify(|_w| {}); - return Ok(SlaveSendResult::Stopped); - } - - // Check for RESTART (new ADDR) - if sr1.addr() { - trace!("i2c v1 slave: RESTART detected after send"); - return Ok(SlaveSendResult::Restart); - } - - // Check for byte transfer finished (normal ACK case) - if sr1.btf() { - trace!("i2c v1 slave: BTF set, byte transfer complete (ACK)"); - return Ok(SlaveSendResult::Acked); - } - - // Check for other error conditions that should be propagated - if sr1.timeout() || sr1.ovr() || sr1.arlo() || sr1.berr() { - // Use the error handling function for these - match Self::check_and_clear_error_flags(self.info) { - Ok(_) => {}, // Shouldn't happen given the flags we checked - Err(e) => return Err(e), - } - } - - timeout.check()?; - } - } - - /// Receive a byte in slave receiver mode or detect STOP condition - fn recv_byte_or_stop(&mut self, timeout: Timeout) -> Result { - trace!("i2c v1 slave: recv_byte_or_stop start"); - loop { - let sr1 = Self::check_slave_error_flags_and_get_sr1(self.info)?; - - // Check for received data FIRST (handles race condition) - if sr1.rxne() { - let byte = self.info.regs.dr().read().dr(); - trace!("i2c v1 slave: received byte={:#x}", byte); - return Ok(SlaveReceiveResult::Byte(byte)); - } - - // Check for RESTART (new ADDR) before STOP - if sr1.addr() { - trace!("i2c v1 slave: RESTART detected during receive"); - return Ok(SlaveReceiveResult::Restart); - } - - // Check for STOP condition LAST - if sr1.stopf() { - trace!("i2c v1 slave: STOP detected during receive"); - self.info.regs.cr1().modify(|_w| {}); - return Ok(SlaveReceiveResult::Stop); - } - - timeout.check()?; - } - } - - /// Wrapper that treats AF (NACK) as normal protocol behavior in slave mode - fn check_slave_error_flags_and_get_sr1(info: &'static Info) -> Result { - match Self::check_and_clear_error_flags(info) { - Ok(sr1) => Ok(sr1), - Err(Error::Nack) => { - // AF flag was set and cleared by check_and_clear_error_flags - // In slave mode, this is normal protocol behavior, not an error - // Read SR1 again to get current state (AF should now be cleared) - Ok(info.regs.sr1().read()) - }, - Err(other_error) => Err(other_error), // Propagate real errors - } - } -} - -impl<'d, IM: MasterMode> I2c<'d, Async, IM> { - async fn write_with_framing(&mut self, address: u8, write_buffer: &[u8], framing: OperationFraming) -> Result<(), Error> { + + async fn read_with_framing(&mut self, address: u8, read_buffer: &mut [u8], framing: OperationFraming) -> Result<(), Error> { + if read_buffer.is_empty() { + return Err(Error::Overrun); + } + + // Some branches below depend on whether the buffer contains only a single byte. + let single_byte = read_buffer.len() == 1; + self.info.regs.cr2().modify(|w| { // Note: Do not enable the ITBUFEN bit in the I2C_CR2 register if DMA is used for // reception. @@ -903,8 +548,10 @@ impl<'d, IM: MasterMode> I2c<'d, Async, IM> { // DMA mode can be enabled for transmission by setting the DMAEN bit in the I2C_CR2 // register. w.set_dmaen(true); - // Sending NACK is not necessary (nor possible) for write transfer. - w.set_last(false); + // If, in the I2C_CR2 register, the LAST bit is set, I2C automatically sends a NACK + // after the next byte following EOT_1. The user can generate a Stop condition in + // the DMA Transfer Complete interrupt routine if enabled. + w.set_last(framing.send_nack() && !single_byte); }); // Sentinel to disable transfer when an error occurs or future is canceled. @@ -918,9 +565,10 @@ impl<'d, IM: MasterMode> I2c<'d, Async, IM> { }); if framing.send_start() { - // Send a START condition + // Send a START condition and set ACK bit self.info.regs.cr1().modify(|reg| { reg.set_start(true); + reg.set_ack(true); }); // Wait until START condition was generated @@ -948,7 +596,7 @@ impl<'d, IM: MasterMode> I2c<'d, Async, IM> { } // Set up current address we're trying to talk to - self.info.regs.dr().write(|reg| reg.set_dr(address << 1)); + self.info.regs.dr().write(|reg| reg.set_dr((address << 1) + 1)); // Wait for the address to be acknowledged poll_fn(|cx| { @@ -969,25 +617,50 @@ impl<'d, IM: MasterMode> I2c<'d, Async, IM> { }) .await?; + // 18.3.8: When a single byte must be received: the NACK must be programmed during EV6 + // event, i.e. program ACK=0 when ADDR=1, before clearing ADDR flag. + if framing.send_nack() && single_byte { + self.info.regs.cr1().modify(|w| { + w.set_ack(false); + }); + } + // Clear condition by reading SR2 self.info.regs.sr2().read(); + } else { + // Before starting reception of single byte (but without START condition, i.e. in case + // of merged operations), program NACK to emit at end of this byte. + if framing.send_nack() && single_byte { + self.info.regs.cr1().modify(|w| { + w.set_ack(false); + }); + } + } + + // 18.3.8: When a single byte must be received: [snip] Then the user can program the STOP + // condition either after clearing ADDR flag, or in the DMA Transfer Complete interrupt + // routine. + if framing.send_stop() && single_byte { + self.info.regs.cr1().modify(|w| { + w.set_stop(true); + }); } let dma_transfer = unsafe { - // Set the I2C_DR register address in the DMA_SxPAR register. The data will be moved to - // this address from the memory after each TxE event. - let dst = self.info.regs.dr().as_ptr() as *mut u8; + // Set the I2C_DR register address in the DMA_SxPAR register. The data will be moved + // from this address from the memory after each RxE event. + let src = self.info.regs.dr().as_ptr() as *mut u8; - self.tx_dma.as_mut().unwrap().write(write_buffer, dst, Default::default()) + self.rx_dma.as_mut().unwrap().read(src, read_buffer, Default::default()) }; - // Wait for bytes to be sent, or an error to occur. + // Wait for bytes to be received, or an error to occur. let poll_error = poll_fn(|cx| { self.state.waker.register(cx.waker()); match Self::check_and_clear_error_flags(self.info) { Err(e) => Poll::Ready(Err::<(), Error>(e)), - Ok(_) => { + _ => { // When pending, (re-)enable interrupts to wake us up. Self::enable_interrupts(self.info); Poll::Pending @@ -995,7 +668,6 @@ impl<'d, IM: MasterMode> I2c<'d, Async, IM> { } }); - // Wait for either the DMA transfer to successfully finish, or an I2C error to occur. match select(dma_transfer, poll_error).await { Either::Second(Err(e)) => Err(e), _ => Ok(()), @@ -1005,29 +677,7 @@ impl<'d, IM: MasterMode> I2c<'d, Async, IM> { w.set_dmaen(false); }); - if framing.send_stop() { - // The I2C transfer itself will take longer than the DMA transfer, so wait for that to finish too. - - // 18.3.8 “Master transmitter: In the interrupt routine after the EOT interrupt, disable DMA - // requests then wait for a BTF event before programming the Stop condition.” - poll_fn(|cx| { - self.state.waker.register(cx.waker()); - - match Self::check_and_clear_error_flags(self.info) { - Err(e) => Poll::Ready(Err(e)), - Ok(sr1) => { - if sr1.btf() { - Poll::Ready(Ok(())) - } else { - // When pending, (re-)enable interrupts to wake us up. - Self::enable_interrupts(self.info); - Poll::Pending - } - } - } - }) - .await?; - + if framing.send_stop() && !single_byte { self.info.regs.cr1().modify(|w| { w.set_stop(true); }); @@ -1039,207 +689,505 @@ impl<'d, IM: MasterMode> I2c<'d, Async, IM> { Ok(()) } - /// Write. - pub async fn write(&mut self, address: u8, write_buffer: &[u8]) -> Result<(), Error> { - self.write_with_framing(address, write_buffer, OperationFraming::FirstAndLast) - .await?; + /// Write, restart, read. + pub async fn write_read(&mut self, address: u8, write_buffer: &[u8], read_buffer: &mut [u8]) -> Result<(), Error> { + // Check empty read buffer before starting transaction. Otherwise, we would not generate the + // stop condition below. + if read_buffer.is_empty() { + return Err(Error::Overrun); + } - Ok(()) + self.write_with_framing(address, write_buffer, OperationFraming::First).await?; + self.read_with_framing(address, read_buffer, OperationFraming::FirstAndLast).await } - /// Read. - pub async fn read(&mut self, address: u8, read_buffer: &mut [u8]) -> Result<(), Error> { - self.read_with_framing(address, read_buffer, OperationFraming::FirstAndLast) - .await?; + /// Transaction with operations. + /// + /// Consecutive operations of same type are merged. See [transaction contract] for details. + /// + /// [transaction contract]: embedded_hal_1::i2c::I2c::transaction + pub async fn transaction(&mut self, address: u8, operations: &mut [Operation<'_>]) -> Result<(), Error> { + for (op, framing) in assign_operation_framing(operations)? { + match op { + Operation::Read(read_buffer) => self.read_with_framing(address, read_buffer, framing).await?, + Operation::Write(write_buffer) => self.write_with_framing(address, write_buffer, framing).await?, + } + } Ok(()) } +} - async fn read_with_framing(&mut self, address: u8, read_buffer: &mut [u8], framing: OperationFraming) -> Result<(), Error> { - if read_buffer.is_empty() { - return Err(Error::Overrun); - } - - // Some branches below depend on whether the buffer contains only a single byte. - let single_byte = read_buffer.len() == 1; - - self.info.regs.cr2().modify(|w| { - // Note: Do not enable the ITBUFEN bit in the I2C_CR2 register if DMA is used for - // reception. - w.set_itbufen(false); - // DMA mode can be enabled for transmission by setting the DMAEN bit in the I2C_CR2 - // register. - w.set_dmaen(true); - // If, in the I2C_CR2 register, the LAST bit is set, I2C automatically sends a NACK - // after the next byte following EOT_1. The user can generate a Stop condition in - // the DMA Transfer Complete interrupt routine if enabled. - w.set_last(framing.send_nack() && !single_byte); - }); - - // Sentinel to disable transfer when an error occurs or future is canceled. - // TODO: Generate STOP condition on cancel? - let on_drop = OnDrop::new(|| { - self.info.regs.cr2().modify(|w| { - w.set_dmaen(false); - w.set_iterren(false); - w.set_itevten(false); - }) - }); - - if framing.send_start() { - // Send a START condition and set ACK bit - self.info.regs.cr1().modify(|reg| { - reg.set_start(true); - reg.set_ack(true); - }); +/// Result of attempting to send a byte in slave transmitter mode +#[derive(Debug, PartialEq)] +enum TransmitResult { + /// Byte sent and ACKed by master - continue transmission + Acknowledged, + /// Byte sent but NACKed by master - normal end of read transaction + NotAcknowledged, + /// STOP condition detected - master terminated transaction + Stopped, + /// RESTART condition detected - master starting new transaction + Restarted, +} - // Wait until START condition was generated - poll_fn(|cx| { - self.state.waker.register(cx.waker()); +/// Result of attempting to receive a byte in slave receiver mode +#[derive(Debug, PartialEq)] +enum ReceiveResult { + /// Data byte successfully received + Data(u8), + /// STOP condition detected - end of write transaction + Stopped, + /// RESTART condition detected - master starting new transaction + Restarted, +} - match Self::check_and_clear_error_flags(self.info) { - Err(e) => Poll::Ready(Err(e)), - Ok(sr1) => { - if sr1.start() { - Poll::Ready(Ok(())) - } else { - // When pending, (re-)enable interrupts to wake us up. - Self::enable_interrupts(self.info); - Poll::Pending - } - } - } - }) - .await?; +impl<'d, M: Mode> I2c<'d, M, Master> { + /// Configure the I2C driver for slave operations, allowing for the driver to be used as a slave and a master (multimaster) + pub fn into_slave_multimaster(mut self, slave_addr_config: SlaveAddrConfig) -> I2c<'d, M, MultiMaster> { + let mut slave = I2c { + info: self.info, + state: self.state, + kernel_clock: self.kernel_clock, + tx_dma: self.tx_dma.take(), // Use take() to move ownership + rx_dma: self.rx_dma.take(), // Use take() to move ownership + #[cfg(feature = "time")] + timeout: self.timeout, + _phantom: PhantomData, + _phantom2: PhantomData, + _drop_guard: self._drop_guard, // Move the drop guard + }; + slave.init_slave(slave_addr_config); + slave + } +} - // Check if we were the ones to generate START - if self.info.regs.cr1().read().start() || !self.info.regs.sr2().read().msl() { - return Err(Error::Arbitration); +impl<'d, M: Mode> I2c<'d, M, MultiMaster> { + /// Listen for incoming I2C address match and return the command type + /// + /// This method blocks until the slave address is matched by a master. + /// Returns the command type (Read/Write) and the matched address. + pub fn blocking_listen(&mut self) -> Result { + trace!("I2C slave: listening for address match"); + let result = self.blocking_listen_with_timeout(self.timeout()); + trace!("I2C slave: listen result={:?}", result); + result + } + + /// Respond to a master read request by transmitting data + /// + /// Sends the provided data to the master. If the master requests more bytes + /// than available, padding bytes (0x00) are sent until the master terminates + /// the transaction with NACK. + /// + /// Returns the total number of bytes transmitted (including padding). + pub fn blocking_respond_to_read(&mut self, data: &[u8]) -> Result { + trace!("I2C slave: responding to read, data_len={}", data.len()); + let result = self.transmit_to_master(data, self.timeout()); + trace!("I2C slave: read response complete, result={:?}", result); + result + } + + /// Respond to a master write request by receiving data + /// + /// Receives data from the master into the provided buffer. If the master + /// sends more bytes than the buffer can hold, excess bytes are acknowledged + /// but discarded. + /// + /// Returns the number of bytes stored in the buffer (not total received). + pub fn blocking_respond_to_write(&mut self, buffer: &mut [u8]) -> Result { + trace!("I2C slave: responding to write, buffer_len={}", buffer.len()); + let result = self.receive_from_master(buffer, self.timeout()); + trace!("I2C slave: write response complete, result={:?}", result); + result + } + + // Private implementation methods + + /// Wait for address match and determine transaction type + fn blocking_listen_with_timeout(&mut self, timeout: Timeout) -> Result { + // Ensure interrupts are disabled for blocking operation + self.disable_i2c_interrupts(); + + // Wait for address match (ADDR flag) + loop { + let sr1 = Self::read_status_and_handle_errors(self.info)?; + + if sr1.addr() { + // Address matched - read SR2 to get direction and clear ADDR flag + let sr2 = self.info.regs.sr2().read(); + let direction = if sr2.tra() { + SlaveCommandKind::Read + } else { + SlaveCommandKind::Write + }; + + let matched_address = self.decode_matched_address(sr2)?; + trace!("I2C slave: address matched, direction={:?}, addr={:?}", direction, matched_address); + + return Ok(SlaveCommand { + kind: direction, + address: matched_address, + }); } - - // Set up current address we're trying to talk to - self.info.regs.dr().write(|reg| reg.set_dr((address << 1) + 1)); - - // Wait for the address to be acknowledged - poll_fn(|cx| { - self.state.waker.register(cx.waker()); - - match Self::check_and_clear_error_flags(self.info) { - Err(e) => Poll::Ready(Err(e)), - Ok(sr1) => { - if sr1.addr() { - Poll::Ready(Ok(())) - } else { - // When pending, (re-)enable interrupts to wake us up. - Self::enable_interrupts(self.info); - Poll::Pending - } - } + + timeout.check()?; + } + } + + /// Transmit data to master in response to read request + fn transmit_to_master(&mut self, data: &[u8], timeout: Timeout) -> Result { + let mut bytes_transmitted = 0; + + loop { + // Determine next byte to send + let byte_to_send = if bytes_transmitted < data.len() { + data[bytes_transmitted] + } else { + 0x00 // Send padding bytes when data is exhausted + }; + + // Attempt to send the byte + match self.transmit_byte(byte_to_send, timeout)? { + TransmitResult::Acknowledged => { + bytes_transmitted += 1; + // Continue transmission + }, + TransmitResult::NotAcknowledged => { + bytes_transmitted += 1; // Count the NACKed byte + break; // Normal end of read transaction + }, + TransmitResult::Stopped | TransmitResult::Restarted => { + break; // Transaction terminated by master } - }) - .await?; - - // 18.3.8: When a single byte must be received: the NACK must be programmed during EV6 - // event, i.e. program ACK=0 when ADDR=1, before clearing ADDR flag. - if framing.send_nack() && single_byte { - self.info.regs.cr1().modify(|w| { - w.set_ack(false); - }); } - - // Clear condition by reading SR2 - self.info.regs.sr2().read(); - } else { - // Before starting reception of single byte (but without START condition, i.e. in case - // of merged operations), program NACK to emit at end of this byte. - if framing.send_nack() && single_byte { - self.info.regs.cr1().modify(|w| { - w.set_ack(false); - }); + } + + Ok(bytes_transmitted) + } + + /// Receive data from master during write request + fn receive_from_master(&mut self, buffer: &mut [u8], timeout: Timeout) -> Result { + let mut bytes_stored = 0; + + // Receive bytes that fit in buffer + while bytes_stored < buffer.len() { + match self.receive_byte(timeout)? { + ReceiveResult::Data(byte) => { + buffer[bytes_stored] = byte; + bytes_stored += 1; + }, + ReceiveResult::Stopped | ReceiveResult::Restarted => { + return Ok(bytes_stored); + }, } } - - // 18.3.8: When a single byte must be received: [snip] Then the user can program the STOP - // condition either after clearing ADDR flag, or in the DMA Transfer Complete interrupt - // routine. - if framing.send_stop() && single_byte { - self.info.regs.cr1().modify(|w| { - w.set_stop(true); - }); + + // Handle buffer overflow by discarding excess bytes + if bytes_stored == buffer.len() { + trace!("I2C slave: buffer full, discarding excess bytes"); + self.discard_excess_bytes(timeout)?; } - - let dma_transfer = unsafe { - // Set the I2C_DR register address in the DMA_SxPAR register. The data will be moved - // from this address from the memory after each RxE event. - let src = self.info.regs.dr().as_ptr() as *mut u8; - - self.rx_dma.as_mut().unwrap().read(src, read_buffer, Default::default()) - }; - - // Wait for bytes to be received, or an error to occur. - let poll_error = poll_fn(|cx| { - self.state.waker.register(cx.waker()); - - match Self::check_and_clear_error_flags(self.info) { - Err(e) => Poll::Ready(Err::<(), Error>(e)), - _ => { - // When pending, (re-)enable interrupts to wake us up. - Self::enable_interrupts(self.info); - Poll::Pending - } + + Ok(bytes_stored) + } + + /// Discard excess bytes when buffer is full + fn discard_excess_bytes(&mut self, timeout: Timeout) -> Result<(), Error> { + loop { + match self.receive_byte(timeout)? { + ReceiveResult::Data(_) => { + // Byte received and ACKed, but discarded + continue; + }, + ReceiveResult::Stopped | ReceiveResult::Restarted => { + break; // Transaction completed + }, } - }); - - match select(dma_transfer, poll_error).await { - Either::Second(Err(e)) => Err(e), - _ => Ok(()), - }?; - - self.info.regs.cr2().modify(|w| { - w.set_dmaen(false); - }); - - if framing.send_stop() && !single_byte { - self.info.regs.cr1().modify(|w| { - w.set_stop(true); - }); } - - drop(on_drop); - - // Fallthrough is success Ok(()) } - - /// Write, restart, read. - pub async fn write_read(&mut self, address: u8, write_buffer: &[u8], read_buffer: &mut [u8]) -> Result<(), Error> { - // Check empty read buffer before starting transaction. Otherwise, we would not generate the - // stop condition below. - if read_buffer.is_empty() { - return Err(Error::Overrun); + + /// Send a single byte and wait for master's response + fn transmit_byte(&mut self, byte: u8, timeout: Timeout) -> Result { + // Wait for transmit buffer ready + self.wait_for_transmit_ready(timeout)?; + + // Send the byte + self.info.regs.dr().write(|w| w.set_dr(byte)); + + // Wait for transmission completion or master response + self.wait_for_transmit_completion(timeout) + } + + /// Wait until transmit buffer is ready (TXE flag set) + fn wait_for_transmit_ready(&mut self, timeout: Timeout) -> Result<(), Error> { + loop { + let sr1 = Self::read_status_and_handle_errors(self.info)?; + + // Check for early termination conditions + if let Some(result) = Self::check_early_termination(sr1) { + return Err(self.handle_early_termination(result)); + } + + if sr1.txe() { + return Ok(()); // Ready to transmit + } + + timeout.check()?; } - - self.write_with_framing(address, write_buffer, OperationFraming::First).await?; - self.read_with_framing(address, read_buffer, OperationFraming::FirstAndLast).await } - - /// Transaction with operations. - /// - /// Consecutive operations of same type are merged. See [transaction contract] for details. - /// - /// [transaction contract]: embedded_hal_1::i2c::I2c::transaction - pub async fn transaction(&mut self, address: u8, operations: &mut [Operation<'_>]) -> Result<(), Error> { - for (op, framing) in assign_operation_framing(operations)? { - match op { - Operation::Read(read_buffer) => self.read_with_framing(address, read_buffer, framing).await?, - Operation::Write(write_buffer) => self.write_with_framing(address, write_buffer, framing).await?, + + /// Wait for byte transmission completion or master response + fn wait_for_transmit_completion(&mut self, timeout: Timeout) -> Result { + loop { + let sr1 = self.info.regs.sr1().read(); + + // Check flags in priority order + if sr1.af() { + self.clear_acknowledge_failure(); + return Ok(TransmitResult::NotAcknowledged); } + + if sr1.btf() { + return Ok(TransmitResult::Acknowledged); + } + + if sr1.stopf() { + self.clear_stop_flag(); + return Ok(TransmitResult::Stopped); + } + + if sr1.addr() { + return Ok(TransmitResult::Restarted); + } + + // Check for other error conditions + self.check_for_hardware_errors(sr1)?; + + timeout.check()?; + } + } + + /// Receive a single byte or detect transaction termination + fn receive_byte(&mut self, timeout: Timeout) -> Result { + loop { + let sr1 = Self::read_status_and_handle_errors(self.info)?; + + // Check for received data first (prioritize data over control signals) + if sr1.rxne() { + let byte = self.info.regs.dr().read().dr(); + return Ok(ReceiveResult::Data(byte)); + } + + // Check for transaction termination + if sr1.addr() { + return Ok(ReceiveResult::Restarted); + } + + if sr1.stopf() { + self.clear_stop_flag(); + return Ok(ReceiveResult::Stopped); + } + + timeout.check()?; + } + } + + /// Determine which slave address was matched based on SR2 flags + fn decode_matched_address(&self, sr2: i2c::regs::Sr2) -> Result { + if sr2.gencall() { + Ok(Address::SevenBit(0x00)) // General call address + } else if sr2.dualf() { + // OA2 (secondary address) was matched + let oar2 = self.info.regs.oar2().read(); + if oar2.endual() != i2c::vals::Endual::DUAL { + return Err(Error::Bus); // Hardware inconsistency + } + Ok(Address::SevenBit(oar2.add2())) + } else { + // OA1 (primary address) was matched + let oar1 = self.info.regs.oar1().read(); + match oar1.addmode() { + i2c::vals::Addmode::BIT7 => { + let addr = (oar1.add() >> 1) as u8; + Ok(Address::SevenBit(addr)) + }, + i2c::vals::Addmode::BIT10 => { + Ok(Address::TenBit(oar1.add())) + }, + } + } + } + + // Helper methods for hardware interaction + + /// Read status register and handle I2C errors (except NACK in slave mode) + fn read_status_and_handle_errors(info: &'static Info) -> Result { + match Self::check_and_clear_error_flags(info) { + Ok(sr1) => Ok(sr1), + Err(Error::Nack) => { + // In slave mode, NACK is normal protocol behavior, not an error + Ok(info.regs.sr1().read()) + }, + Err(other_error) => Err(other_error), + } + } + + /// Check for conditions that cause early termination of operations + fn check_early_termination(sr1: i2c::regs::Sr1) -> Option { + if sr1.stopf() { + Some(TransmitResult::Stopped) + } else if sr1.addr() { + Some(TransmitResult::Restarted) + } else if sr1.af() { + Some(TransmitResult::NotAcknowledged) + } else { + None + } + } + + /// Convert early termination to appropriate error + fn handle_early_termination(&mut self, result: TransmitResult) -> Error { + match result { + TransmitResult::Stopped => { + self.clear_stop_flag(); + Error::Bus // Unexpected STOP during setup + }, + TransmitResult::Restarted => { + Error::Bus // Unexpected RESTART during setup + }, + TransmitResult::NotAcknowledged => { + self.clear_acknowledge_failure(); + Error::Bus // Unexpected NACK during setup + }, + TransmitResult::Acknowledged => { + unreachable!() // This should never be passed to this function + } + } + } + + /// Check for hardware-level I2C errors during transmission + fn check_for_hardware_errors(&self, sr1: i2c::regs::Sr1) -> Result<(), Error> { + if sr1.timeout() || sr1.ovr() || sr1.arlo() || sr1.berr() { + // Delegate to existing error handling + Self::check_and_clear_error_flags(self.info)?; } - Ok(()) } + + /// Disable I2C event and error interrupts for blocking operations + fn disable_i2c_interrupts(&mut self) { + self.info.regs.cr2().modify(|w| { + w.set_itevten(false); + w.set_iterren(false); + }); + } + + /// Clear the acknowledge failure flag + fn clear_acknowledge_failure(&mut self) { + self.info.regs.sr1().write(|reg| { + reg.0 = !0; + reg.set_af(false); + }); + } + + /// Clear the stop condition flag + fn clear_stop_flag(&mut self) { + self.info.regs.cr1().modify(|_w| {}); + } } +// Address configuration methods +impl<'d, M: Mode, IM: MasterMode> I2c<'d, M, IM> { + /// Initialize slave mode with address configuration + pub(crate) fn init_slave(&mut self, config: SlaveAddrConfig) { + trace!("I2C slave: initializing with config={:?}", config); + + // Disable peripheral for configuration + self.info.regs.cr1().modify(|reg| reg.set_pe(false)); + + // Configure slave addresses + self.apply_address_configuration(config); + + // Enable peripheral with slave settings + self.info.regs.cr1().modify(|reg| { + reg.set_pe(true); + reg.set_ack(true); // Enable acknowledgment for slave mode + }); + + trace!("I2C slave: initialization complete"); + } + + /// Apply the complete address configuration for slave mode + fn apply_address_configuration(&mut self, config: SlaveAddrConfig) { + match config.addr { + OwnAddresses::OA1(addr) => { + self.configure_primary_address(addr); + self.disable_secondary_address(); + }, + OwnAddresses::OA2(oa2) => { + self.configure_default_primary_address(); + self.configure_secondary_address(oa2.addr); // v1 ignores mask + }, + OwnAddresses::Both { oa1, oa2 } => { + self.configure_primary_address(oa1); + self.configure_secondary_address(oa2.addr); // v1 ignores mask + } + } + + // Configure general call detection + if config.general_call { + self.info.regs.cr1().modify(|w| w.set_engc(true)); + } + } + + /// Configure the primary address (OA1) register + fn configure_primary_address(&mut self, addr: Address) { + match addr { + Address::SevenBit(addr) => { + self.info.regs.oar1().write(|reg| { + let hw_addr = (addr as u16) << 1; // Address in bits [7:1] + reg.set_add(hw_addr); + reg.set_addmode(i2c::vals::Addmode::BIT7); + }); + }, + Address::TenBit(addr) => { + self.info.regs.oar1().write(|reg| { + reg.set_add(addr); + reg.set_addmode(i2c::vals::Addmode::BIT10); + }); + } + } + + // Set required bit 14 as per reference manual + self.info.regs.oar1().modify(|reg| reg.0 |= 1 << 14); + } + + /// Configure the secondary address (OA2) register + fn configure_secondary_address(&mut self, addr: u8) { + self.info.regs.oar2().write(|reg| { + reg.set_add2(addr); + reg.set_endual(i2c::vals::Endual::DUAL); + }); + } + + /// Set a default primary address when using OA2-only mode + fn configure_default_primary_address(&mut self) { + self.info.regs.oar1().write(|reg| { + reg.set_add(0); // Reserved address, safe to use + reg.set_addmode(i2c::vals::Addmode::BIT7); + }); + self.info.regs.oar1().modify(|reg| reg.0 |= 1 << 14); + } + + /// Disable secondary address when not needed + fn disable_secondary_address(&mut self) { + self.info.regs.oar2().write(|reg| { + reg.set_endual(i2c::vals::Endual::SINGLE); + }); + } +} /// Timing configuration for I2C v1 hardware /// -- cgit From 03496864d765590744582c00a1b8f010d5014a0c Mon Sep 17 00:00:00 2001 From: HybridChild Date: Tue, 12 Aug 2025 06:49:00 +0200 Subject: stm32/i2c_v1: Add handling of zero-length read --- embassy-stm32/src/i2c/v1.rs | 62 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 62 insertions(+) diff --git a/embassy-stm32/src/i2c/v1.rs b/embassy-stm32/src/i2c/v1.rs index 8f4128b45..9b5a524df 100644 --- a/embassy-stm32/src/i2c/v1.rs +++ b/embassy-stm32/src/i2c/v1.rs @@ -783,6 +783,13 @@ impl<'d, M: Mode> I2c<'d, M, MultiMaster> { /// Returns the total number of bytes transmitted (including padding). pub fn blocking_respond_to_read(&mut self, data: &[u8]) -> Result { trace!("I2C slave: responding to read, data_len={}", data.len()); + + // Check for zero-length read BEFORE any transmission setup + if let Some(zero_length_result) = self.detect_zero_length_read(self.timeout())? { + trace!("I2C slave: zero-length read detected"); + return Ok(zero_length_result); + } + let result = self.transmit_to_master(data, self.timeout()); trace!("I2C slave: read response complete, result={:?}", result); result @@ -891,6 +898,61 @@ impl<'d, M: Mode> I2c<'d, M, MultiMaster> { Ok(bytes_stored) } + + /// Detect zero-length read pattern early + /// + /// Zero-length reads occur when a master sends START+ADDR+R followed immediately + /// by NACK+STOP without wanting any data. This must be detected before attempting + /// to transmit any bytes to avoid SDA line issues. + fn detect_zero_length_read(&mut self, _timeout: Timeout) -> Result, Error> { + // Quick check for immediate termination signals + let sr1 = self.info.regs.sr1().read(); + + // Check for immediate NACK (fastest zero-length pattern) + if sr1.af() { + self.clear_acknowledge_failure(); + return Ok(Some(0)); + } + + // Check for immediate STOP (alternative zero-length pattern) + if sr1.stopf() { + self.clear_stop_flag(); + return Ok(Some(0)); + } + + // Give a brief window for master to send termination signals + // This handles masters that have slight delays between address ACK and NACK + const ZERO_LENGTH_DETECTION_CYCLES: u32 = 100; // ~5-10µs window + + for _ in 0..ZERO_LENGTH_DETECTION_CYCLES { + let sr1 = self.info.regs.sr1().read(); + + // Immediate NACK indicates zero-length read + if sr1.af() { + self.clear_acknowledge_failure(); + return Ok(Some(0)); + } + + // Immediate STOP indicates zero-length read + if sr1.stopf() { + self.clear_stop_flag(); + return Ok(Some(0)); + } + + // If TXE becomes ready, master is waiting for data - not zero-length + if sr1.txe() { + return Ok(None); // Proceed with normal transmission + } + + // If RESTART detected, handle as zero-length + if sr1.addr() { + return Ok(Some(0)); + } + } + + // No zero-length pattern detected within the window + Ok(None) + } /// Discard excess bytes when buffer is full fn discard_excess_bytes(&mut self, timeout: Timeout) -> Result<(), Error> { -- cgit From 0ab366e28af266795106cb254b4a0d63f723d476 Mon Sep 17 00:00:00 2001 From: HybridChild Date: Wed, 13 Aug 2025 20:11:55 +0200 Subject: stm32/i2c_v1: Add async slave implementation --- embassy-stm32/src/i2c/v1.rs | 359 +++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 339 insertions(+), 20 deletions(-) diff --git a/embassy-stm32/src/i2c/v1.rs b/embassy-stm32/src/i2c/v1.rs index 9b5a524df..10a307396 100644 --- a/embassy-stm32/src/i2c/v1.rs +++ b/embassy-stm32/src/i2c/v1.rs @@ -362,14 +362,30 @@ impl<'d, M: Mode, IM: MasterMode> I2c<'d, M, IM> { } // Async - + + /// Can be used by both blocking and async implementations #[inline] // pretty sure this should always be inlined - fn enable_interrupts(info: &'static Info) -> () { - info.regs.cr2().modify(|w| { - w.set_iterren(true); - w.set_itevten(true); + fn enable_interrupts(info: &'static Info) { + // The interrupt handler disables interrupts globally, so we need to re-enable them + // This must be done in a critical section to avoid races + critical_section::with(|_| { + info.regs.cr2().modify(|w| { + w.set_iterren(true); + w.set_itevten(true); + }); }); + trace!("I2C slave: safely enabled interrupts"); } + + /// Can be used by both blocking and async implementations + fn clear_stop_flag(info: &'static Info) { + trace!("I2C slave: clearing STOPF flag (v1 sequence)"); + // v1 requires: READ SR1 then WRITE CR1 to clear STOPF + let _ = info.regs.sr1().read(); + info.regs.cr1().modify(|_| {}); // Dummy write to clear STOPF + trace!("I2C slave: STOPF flag cleared"); + } + } impl<'d, IM: MasterMode> I2c<'d, Async, IM> { @@ -829,7 +845,8 @@ impl<'d, M: Mode> I2c<'d, M, MultiMaster> { SlaveCommandKind::Write }; - let matched_address = self.decode_matched_address(sr2)?; + // Use the static method instead of the instance method + let matched_address = Self::decode_matched_address(sr2, self.info)?; trace!("I2C slave: address matched, direction={:?}, addr={:?}", direction, matched_address); return Ok(SlaveCommand { @@ -916,13 +933,13 @@ impl<'d, M: Mode> I2c<'d, M, MultiMaster> { // Check for immediate STOP (alternative zero-length pattern) if sr1.stopf() { - self.clear_stop_flag(); + Self::clear_stop_flag(self.info); return Ok(Some(0)); } // Give a brief window for master to send termination signals // This handles masters that have slight delays between address ACK and NACK - const ZERO_LENGTH_DETECTION_CYCLES: u32 = 100; // ~5-10µs window + const ZERO_LENGTH_DETECTION_CYCLES: u32 = 20; // ~5-10µs window for _ in 0..ZERO_LENGTH_DETECTION_CYCLES { let sr1 = self.info.regs.sr1().read(); @@ -935,7 +952,7 @@ impl<'d, M: Mode> I2c<'d, M, MultiMaster> { // Immediate STOP indicates zero-length read if sr1.stopf() { - self.clear_stop_flag(); + Self::clear_stop_flag(self.info); return Ok(Some(0)); } @@ -1016,7 +1033,7 @@ impl<'d, M: Mode> I2c<'d, M, MultiMaster> { } if sr1.stopf() { - self.clear_stop_flag(); + Self::clear_stop_flag(self.info); return Ok(TransmitResult::Stopped); } @@ -1048,7 +1065,7 @@ impl<'d, M: Mode> I2c<'d, M, MultiMaster> { } if sr1.stopf() { - self.clear_stop_flag(); + Self::clear_stop_flag(self.info); return Ok(ReceiveResult::Stopped); } @@ -1057,19 +1074,19 @@ impl<'d, M: Mode> I2c<'d, M, MultiMaster> { } /// Determine which slave address was matched based on SR2 flags - fn decode_matched_address(&self, sr2: i2c::regs::Sr2) -> Result { + fn decode_matched_address(sr2: i2c::regs::Sr2, info: &'static Info) -> Result { if sr2.gencall() { Ok(Address::SevenBit(0x00)) // General call address } else if sr2.dualf() { // OA2 (secondary address) was matched - let oar2 = self.info.regs.oar2().read(); + let oar2 = info.regs.oar2().read(); if oar2.endual() != i2c::vals::Endual::DUAL { return Err(Error::Bus); // Hardware inconsistency } Ok(Address::SevenBit(oar2.add2())) } else { // OA1 (primary address) was matched - let oar1 = self.info.regs.oar1().read(); + let oar1 = info.regs.oar1().read(); match oar1.addmode() { i2c::vals::Addmode::BIT7 => { let addr = (oar1.add() >> 1) as u8; @@ -1113,7 +1130,7 @@ impl<'d, M: Mode> I2c<'d, M, MultiMaster> { fn handle_early_termination(&mut self, result: TransmitResult) -> Error { match result { TransmitResult::Stopped => { - self.clear_stop_flag(); + Self::clear_stop_flag(self.info); Error::Bus // Unexpected STOP during setup }, TransmitResult::Restarted => { @@ -1153,11 +1170,6 @@ impl<'d, M: Mode> I2c<'d, M, MultiMaster> { reg.set_af(false); }); } - - /// Clear the stop condition flag - fn clear_stop_flag(&mut self) { - self.info.regs.cr1().modify(|_w| {}); - } } // Address configuration methods @@ -1176,6 +1188,7 @@ impl<'d, M: Mode, IM: MasterMode> I2c<'d, M, IM> { self.info.regs.cr1().modify(|reg| { reg.set_pe(true); reg.set_ack(true); // Enable acknowledgment for slave mode + reg.set_nostretch(false); // Allow clock stretching for processing time }); trace!("I2C slave: initialization complete"); @@ -1251,6 +1264,312 @@ impl<'d, M: Mode, IM: MasterMode> I2c<'d, M, IM> { } } +impl<'d> I2c<'d, Async, MultiMaster> { + /// Async listen for incoming I2C messages using interrupts + pub async fn listen(&mut self) -> Result { + trace!("I2C slave: starting listen for address match"); + + // Extract references needed by the closure + let state = self.state; + let info = self.info; + + Self::enable_interrupts(info); + trace!("I2C slave: enabled event and error interrupts"); + + // Sentinel to clean up interrupts on drop + let on_drop = OnDrop::new(|| { + critical_section::with(|_| { + info.regs.cr2().modify(|w| { + w.set_iterren(false); + w.set_itevten(false); + }); + }); + trace!("I2C slave: disabled interrupts on drop"); + }); + + let result = poll_fn(|cx| { + state.waker.register(cx.waker()); + + match Self::check_and_clear_error_flags(info) { + Err(e) => { + error!("I2C slave: error during listen: {:?}", e); + Poll::Ready(Err(e)) + }, + Ok(sr1) => { + if sr1.addr() { + trace!("I2C slave: ADDR flag detected - address matched"); + + // Address matched - determine direction + let sr2 = info.regs.sr2().read(); + let direction = if sr2.tra() { + trace!("I2C slave: direction = READ (master wants to read from us)"); + SlaveCommandKind::Read + } else { + trace!("I2C slave: direction = WRITE (master wants to write to us)"); + SlaveCommandKind::Write + }; + + let matched_address = match Self::decode_matched_address(sr2, info) { + Ok(addr) => { + trace!("I2C slave: matched address decoded: {:?}", addr); + addr + }, + Err(e) => { + error!("I2C slave: failed to decode matched address: {:?}", e); + return Poll::Ready(Err(e)); + } + }; + + trace!("I2C slave: listen complete - returning command"); + // Don't clear ADDR here - leave it for DMA setup + Poll::Ready(Ok(SlaveCommand { + kind: direction, + address: matched_address, + })) + } else { + // Re-enable interrupts and continue waiting + // Use safe method since handler disables them globally + Self::enable_interrupts(info); + Poll::Pending + } + } + } + }).await; + + drop(on_drop); + trace!("I2C slave: listen result: {:?}", result); + result + } + + /// Async respond to write command using RX DMA + pub async fn respond_to_write(&mut self, buffer: &mut [u8]) -> Result { + trace!("I2C slave: starting respond_to_write, buffer_len={}", buffer.len()); + + if buffer.is_empty() { + warn!("I2C slave: respond_to_write called with empty buffer"); + return Err(Error::Overrun); + } + + // Extract references needed by closures + let state = self.state; + let info = self.info; + + trace!("I2C slave: configuring registers for RX DMA"); + info.regs.cr2().modify(|w| { + w.set_itbufen(false); // Disable buffer interrupts for DMA + w.set_dmaen(true); // Enable DMA + w.set_last(false); // Not needed for slave writes + }); + + // Sentinel to clean up DMA on drop + let on_drop = OnDrop::new(|| { + critical_section::with(|_| { + info.regs.cr2().modify(|w| { + w.set_dmaen(false); + w.set_iterren(false); + w.set_itevten(false); + }); + }); + trace!("I2C slave: DMA and interrupts disabled on drop (respond_to_write)"); + }); + + // Clear ADDR flag to release clock stretching - DMA is now ready + trace!("I2C slave: clearing ADDR flag to release clock stretching"); + info.regs.sr2().read(); // Clear ADDR by reading SR2 + + // Set up RX DMA transfer (I2C DR -> buffer) + trace!("I2C slave: setting up RX DMA transfer"); + let dma_transfer = unsafe { + let src = info.regs.dr().as_ptr() as *mut u8; + self.rx_dma.as_mut().unwrap().read(src, buffer, Default::default()) + }; + + // Poll for I2C errors while DMA runs + let poll_error = poll_fn(|cx| { + state.waker.register(cx.waker()); + + match Self::check_and_clear_error_flags(info) { + Err(e) => { + error!("I2C slave: error during write operation: {:?}", e); + Poll::Ready(Err::<(), Error>(e)) + }, + Ok(sr1) => { + // Check for STOP condition (normal end of write) + if sr1.stopf() { + trace!("I2C slave: STOP condition detected - write transaction complete"); + Self::clear_stop_flag(info); + Poll::Ready(Ok(())) + } else if sr1.addr() { + trace!("I2C slave: RESTART condition detected - transitioning to read phase"); + Poll::Ready(Ok(())) + } else { + // Re-enable interrupts and continue monitoring + // Use safe method since handler disables them globally + Self::enable_interrupts(info); + Poll::Pending + } + } + } + }); + + trace!("I2C slave: starting select between DMA completion and I2C events"); + // Wait for either DMA completion or I2C termination condition (using master pattern) + match select(dma_transfer, poll_error).await { + Either::Second(Err(e)) => { + error!("I2C slave: I2C error occurred during write: {:?}", e); + critical_section::with(|_| { + info.regs.cr2().modify(|w| w.set_dmaen(false)); + }); + drop(on_drop); + Err(e) + } + Either::First(_) => { + trace!("I2C slave: DMA transfer completed first"); + critical_section::with(|_| { + info.regs.cr2().modify(|w| w.set_dmaen(false)); + }); + drop(on_drop); + + // For v1 hardware, determining exact bytes received is complex + // Return the buffer length as an approximation + let bytes_received = buffer.len(); + trace!("I2C slave: write complete, returning {} bytes (buffer length)", bytes_received); + Ok(bytes_received) + } + Either::Second(Ok(())) => { + trace!("I2C slave: I2C event (STOP/RESTART) occurred first"); + critical_section::with(|_| { + info.regs.cr2().modify(|w| w.set_dmaen(false)); + }); + drop(on_drop); + + // Transaction ended normally, return buffer length + let bytes_received = buffer.len(); + trace!("I2C slave: write complete via I2C event, returning {} bytes", bytes_received); + Ok(bytes_received) + } + } + } + + /// Async respond to read command using TX DMA + pub async fn respond_to_read(&mut self, data: &[u8]) -> Result { + trace!("I2C slave: starting respond_to_read, data_len={}", data.len()); + + if data.is_empty() { + warn!("I2C slave: respond_to_read called with empty data"); + return Err(Error::Overrun); + } + + // Extract references needed by closures + let state = self.state; + let info = self.info; + + trace!("I2C slave: configuring registers for TX DMA"); + info.regs.cr2().modify(|w| { + w.set_itbufen(false); // Disable buffer interrupts for DMA + w.set_dmaen(true); // Enable DMA + w.set_last(false); // Not applicable for slave transmit + }); + + // Sentinel to clean up DMA on drop + let on_drop = OnDrop::new(|| { + critical_section::with(|_| { + info.regs.cr2().modify(|w| { + w.set_dmaen(false); + w.set_iterren(false); + w.set_itevten(false); + }); + }); + trace!("I2C slave: DMA and interrupts disabled on drop (respond_to_read)"); + }); + + // Clear ADDR flag to release clock stretching + trace!("I2C slave: clearing ADDR flag to release clock stretching"); + info.regs.sr2().read(); + + // Set up TX DMA transfer (data -> I2C DR) + trace!("I2C slave: setting up TX DMA transfer"); + let dma_transfer = unsafe { + let dst = info.regs.dr().as_ptr() as *mut u8; + self.tx_dma.as_mut().unwrap().write(data, dst, Default::default()) + }; + + // Monitor for I2C events while DMA runs + let poll_completion = poll_fn(|cx| { + state.waker.register(cx.waker()); + + match Self::check_and_clear_error_flags(info) { + Err(Error::Nack) => { + trace!("I2C slave: NACK received - master stopped reading (normal)"); + Poll::Ready(Ok(())) + } + Err(e) => { + error!("I2C slave: error during read operation: {:?}", e); + Poll::Ready(Err(e)) + }, + Ok(sr1) => { + if sr1.stopf() { + trace!("I2C slave: STOP condition detected - read transaction complete"); + Self::clear_stop_flag(info); + Poll::Ready(Ok(())) + } else if sr1.addr() { + trace!("I2C slave: RESTART condition detected during read"); + Poll::Ready(Ok(())) + } else if sr1.af() { + trace!("I2C slave: acknowledge failure (NACK) - normal end of read"); + // Acknowledge failure (NACK) - normal end of read + info.regs.sr1().write(|reg| { + reg.0 = !0; + reg.set_af(false); + }); + Poll::Ready(Ok(())) + } else { + Self::enable_interrupts(info); + Poll::Pending + } + } + } + }); + + trace!("I2C slave: starting select between DMA completion and I2C events"); + // Wait for either DMA completion or I2C termination (using master pattern) + match select(dma_transfer, poll_completion).await { + Either::Second(Err(e)) => { + error!("I2C slave: I2C error occurred during read: {:?}", e); + critical_section::with(|_| { + info.regs.cr2().modify(|w| w.set_dmaen(false)); + }); + drop(on_drop); + Err(e) + } + Either::First(_) => { + trace!("I2C slave: DMA transfer completed first - all data sent"); + critical_section::with(|_| { + info.regs.cr2().modify(|w| w.set_dmaen(false)); + }); + drop(on_drop); + + let bytes_sent = data.len(); + trace!("I2C slave: read complete via DMA, sent {} bytes", bytes_sent); + Ok(bytes_sent) + } + Either::Second(Ok(())) => { + trace!("I2C slave: I2C event (STOP/NACK/RESTART) occurred first"); + critical_section::with(|_| { + info.regs.cr2().modify(|w| w.set_dmaen(false)); + }); + drop(on_drop); + + // For slave read, we can't easily determine exact bytes sent in v1 + // Return the full data length if no error occurred + let bytes_sent = data.len(); + trace!("I2C slave: read complete via I2C event, reporting {} bytes sent", bytes_sent); + Ok(bytes_sent) + } + } + } +} + /// Timing configuration for I2C v1 hardware /// /// This struct encapsulates the complex timing calculations required for STM32 I2C v1 -- cgit From a52497bd39701cd71a877a3d2bd264ae2dea716c Mon Sep 17 00:00:00 2001 From: HybridChild Date: Fri, 22 Aug 2025 12:44:06 +0200 Subject: stm32/i2c_v1: Add handling of excess Write and Read from Master --- embassy-stm32/src/i2c/v1.rs | 153 +++++++++++++++++++++++++++++++++++++------- 1 file changed, 129 insertions(+), 24 deletions(-) diff --git a/embassy-stm32/src/i2c/v1.rs b/embassy-stm32/src/i2c/v1.rs index 10a307396..c37b48728 100644 --- a/embassy-stm32/src/i2c/v1.rs +++ b/embassy-stm32/src/i2c/v1.rs @@ -1414,41 +1414,85 @@ impl<'d> I2c<'d, Async, MultiMaster> { trace!("I2C slave: starting select between DMA completion and I2C events"); // Wait for either DMA completion or I2C termination condition (using master pattern) - match select(dma_transfer, poll_error).await { + let dma_result = match select(dma_transfer, poll_error).await { Either::Second(Err(e)) => { error!("I2C slave: I2C error occurred during write: {:?}", e); critical_section::with(|_| { info.regs.cr2().modify(|w| w.set_dmaen(false)); }); drop(on_drop); - Err(e) + return Err(e); } Either::First(_) => { - trace!("I2C slave: DMA transfer completed first"); + trace!("I2C slave: DMA transfer completed first - buffer full"); critical_section::with(|_| { info.regs.cr2().modify(|w| w.set_dmaen(false)); }); - drop(on_drop); - // For v1 hardware, determining exact bytes received is complex - // Return the buffer length as an approximation + // DMA completed but master might still be sending more bytes + // We need to discard any excess bytes until STOP/RESTART + trace!("I2C slave: DMA complete, checking for excess bytes to discard"); + + let excess_discard = poll_fn(|cx| { + state.waker.register(cx.waker()); + + match Self::check_and_clear_error_flags(info) { + Err(e) => { + error!("I2C slave: error while discarding excess bytes: {:?}", e); + Poll::Ready(Err::<(), Error>(e)) + }, + Ok(sr1) => { + // Check for transaction termination first + if sr1.stopf() { + trace!("I2C slave: STOP condition detected while discarding excess"); + Self::clear_stop_flag(info); + return Poll::Ready(Ok(())); + } + + if sr1.addr() { + trace!("I2C slave: RESTART condition detected while discarding excess"); + return Poll::Ready(Ok(())); + } + + // If there's data to read, read and discard it + if sr1.rxne() { + let discarded_byte = info.regs.dr().read().dr(); + trace!("I2C slave: discarded excess byte: 0x{:02X}", discarded_byte); + // Continue polling for more bytes or termination + Self::enable_interrupts(info); + return Poll::Pending; + } + + // No immediate termination or data, keep waiting + Self::enable_interrupts(info); + Poll::Pending + } + } + }); + + // Wait for transaction to actually end + excess_discard.await?; + let bytes_received = buffer.len(); - trace!("I2C slave: write complete, returning {} bytes (buffer length)", bytes_received); + trace!("I2C slave: write complete after discarding excess, returning {} bytes", bytes_received); + drop(on_drop); Ok(bytes_received) } Either::Second(Ok(())) => { - trace!("I2C slave: I2C event (STOP/RESTART) occurred first"); + trace!("I2C slave: I2C event (STOP/RESTART) occurred before DMA completion"); critical_section::with(|_| { info.regs.cr2().modify(|w| w.set_dmaen(false)); }); - drop(on_drop); - // Transaction ended normally, return buffer length + // Transaction ended normally before buffer was full let bytes_received = buffer.len(); - trace!("I2C slave: write complete via I2C event, returning {} bytes", bytes_received); + trace!("I2C slave: write complete via early I2C event, returning {} bytes", bytes_received); + drop(on_drop); Ok(bytes_received) } - } + }; + + dma_result } /// Async respond to read command using TX DMA @@ -1533,40 +1577,101 @@ impl<'d> I2c<'d, Async, MultiMaster> { trace!("I2C slave: starting select between DMA completion and I2C events"); // Wait for either DMA completion or I2C termination (using master pattern) - match select(dma_transfer, poll_completion).await { + let dma_result = match select(dma_transfer, poll_completion).await { Either::Second(Err(e)) => { error!("I2C slave: I2C error occurred during read: {:?}", e); critical_section::with(|_| { info.regs.cr2().modify(|w| w.set_dmaen(false)); }); drop(on_drop); - Err(e) + return Err(e); } Either::First(_) => { trace!("I2C slave: DMA transfer completed first - all data sent"); critical_section::with(|_| { info.regs.cr2().modify(|w| w.set_dmaen(false)); }); - drop(on_drop); - let bytes_sent = data.len(); - trace!("I2C slave: read complete via DMA, sent {} bytes", bytes_sent); - Ok(bytes_sent) + // DMA completed but master might still be requesting more bytes + // We need to send padding bytes (0x00) until NACK/STOP/RESTART + trace!("I2C slave: DMA complete, entering padding phase"); + let mut padding_bytes_sent = 0; + + let padding_phase = poll_fn(|cx| { + state.waker.register(cx.waker()); + + match Self::check_and_clear_error_flags(info) { + Err(Error::Nack) => { + trace!("I2C slave: NACK received during padding - normal end"); + return Poll::Ready(Ok(())); + }, + Err(e) => { + error!("I2C slave: error while sending padding bytes: {:?}", e); + return Poll::Ready(Err::<(), Error>(e)); + }, + Ok(sr1) => { + // Check for transaction termination first + if sr1.af() { + trace!("I2C slave: acknowledge failure during padding - normal end"); + info.regs.sr1().write(|reg| { + reg.0 = !0; + reg.set_af(false); + }); + return Poll::Ready(Ok(())); + } + + if sr1.stopf() { + trace!("I2C slave: STOP condition detected during padding"); + Self::clear_stop_flag(info); + return Poll::Ready(Ok(())); + } + + if sr1.addr() { + trace!("I2C slave: RESTART condition detected during padding"); + return Poll::Ready(Ok(())); + } + + // If transmit buffer is empty, send a padding byte + if sr1.txe() { + info.regs.dr().write(|w| w.set_dr(0x00)); + padding_bytes_sent += 1; + trace!("I2C slave: sent padding byte #{}", padding_bytes_sent); + // Continue padding until transaction ends + Self::enable_interrupts(info); + return Poll::Pending; + } + + // No immediate termination or transmit request, keep waiting + Self::enable_interrupts(info); + Poll::Pending + } + } + }); + + // Wait for transaction to actually end + padding_phase.await?; + + let total_bytes_sent = data.len() + padding_bytes_sent; + trace!("I2C slave: read complete after sending {} padding bytes, total {} bytes sent", + padding_bytes_sent, total_bytes_sent); + drop(on_drop); + Ok(total_bytes_sent) } Either::Second(Ok(())) => { - trace!("I2C slave: I2C event (STOP/NACK/RESTART) occurred first"); + trace!("I2C slave: I2C event (STOP/NACK/RESTART) occurred before DMA completion"); critical_section::with(|_| { info.regs.cr2().modify(|w| w.set_dmaen(false)); }); - drop(on_drop); - // For slave read, we can't easily determine exact bytes sent in v1 - // Return the full data length if no error occurred + // Transaction ended normally before all data was sent let bytes_sent = data.len(); - trace!("I2C slave: read complete via I2C event, reporting {} bytes sent", bytes_sent); + trace!("I2C slave: read complete via early I2C event, sent {} bytes", bytes_sent); + drop(on_drop); Ok(bytes_sent) } - } + }; + + dma_result } } -- cgit From 8111bbc54594706d26d02a22ad8f1853317d3495 Mon Sep 17 00:00:00 2001 From: HybridChild Date: Fri, 22 Aug 2025 13:18:52 +0200 Subject: stm32/i2c_v1: Clean up Async MultiMaster implementation --- embassy-stm32/src/i2c/v1.rs | 732 ++++++++++++++++++++------------------------ 1 file changed, 340 insertions(+), 392 deletions(-) diff --git a/embassy-stm32/src/i2c/v1.rs b/embassy-stm32/src/i2c/v1.rs index c37b48728..0f2953ef6 100644 --- a/embassy-stm32/src/i2c/v1.rs +++ b/embassy-stm32/src/i2c/v1.rs @@ -758,6 +758,17 @@ enum ReceiveResult { Restarted, } +/// Enumeration of slave transaction termination conditions +#[derive(Debug, Clone, Copy, PartialEq)] +enum SlaveTermination { + /// STOP condition received - normal end of transaction + Stop, + /// RESTART condition received - master starting new transaction + Restart, + /// NACK received - normal end of read transaction + Nack, +} + impl<'d, M: Mode> I2c<'d, M, Master> { /// Configure the I2C driver for slave operations, allowing for the driver to be used as a slave and a master (multimaster) pub fn into_slave_multimaster(mut self, slave_addr_config: SlaveAddrConfig) -> I2c<'d, M, MultiMaster> { @@ -778,6 +789,98 @@ impl<'d, M: Mode> I2c<'d, M, Master> { } } +// Address configuration methods +impl<'d, M: Mode, IM: MasterMode> I2c<'d, M, IM> { + /// Initialize slave mode with address configuration + pub(crate) fn init_slave(&mut self, config: SlaveAddrConfig) { + trace!("I2C slave: initializing with config={:?}", config); + + // Disable peripheral for configuration + self.info.regs.cr1().modify(|reg| reg.set_pe(false)); + + // Configure slave addresses + self.apply_address_configuration(config); + + // Enable peripheral with slave settings + self.info.regs.cr1().modify(|reg| { + reg.set_pe(true); + reg.set_ack(true); // Enable acknowledgment for slave mode + reg.set_nostretch(false); // Allow clock stretching for processing time + }); + + trace!("I2C slave: initialization complete"); + } + + /// Apply the complete address configuration for slave mode + fn apply_address_configuration(&mut self, config: SlaveAddrConfig) { + match config.addr { + OwnAddresses::OA1(addr) => { + self.configure_primary_address(addr); + self.disable_secondary_address(); + }, + OwnAddresses::OA2(oa2) => { + self.configure_default_primary_address(); + self.configure_secondary_address(oa2.addr); // v1 ignores mask + }, + OwnAddresses::Both { oa1, oa2 } => { + self.configure_primary_address(oa1); + self.configure_secondary_address(oa2.addr); // v1 ignores mask + } + } + + // Configure general call detection + if config.general_call { + self.info.regs.cr1().modify(|w| w.set_engc(true)); + } + } + + /// Configure the primary address (OA1) register + fn configure_primary_address(&mut self, addr: Address) { + match addr { + Address::SevenBit(addr) => { + self.info.regs.oar1().write(|reg| { + let hw_addr = (addr as u16) << 1; // Address in bits [7:1] + reg.set_add(hw_addr); + reg.set_addmode(i2c::vals::Addmode::BIT7); + }); + }, + Address::TenBit(addr) => { + self.info.regs.oar1().write(|reg| { + reg.set_add(addr); + reg.set_addmode(i2c::vals::Addmode::BIT10); + }); + } + } + + // Set required bit 14 as per reference manual + self.info.regs.oar1().modify(|reg| reg.0 |= 1 << 14); + } + + /// Configure the secondary address (OA2) register + fn configure_secondary_address(&mut self, addr: u8) { + self.info.regs.oar2().write(|reg| { + reg.set_add2(addr); + reg.set_endual(i2c::vals::Endual::DUAL); + }); + } + + /// Set a default primary address when using OA2-only mode + fn configure_default_primary_address(&mut self) { + self.info.regs.oar1().write(|reg| { + reg.set_add(0); // Reserved address, safe to use + reg.set_addmode(i2c::vals::Addmode::BIT7); + }); + self.info.regs.oar1().modify(|reg| reg.0 |= 1 << 14); + } + + /// Disable secondary address when not needed + fn disable_secondary_address(&mut self) { + self.info.regs.oar2().write(|reg| { + reg.set_endual(i2c::vals::Endual::SINGLE); + }); + } +} + impl<'d, M: Mode> I2c<'d, M, MultiMaster> { /// Listen for incoming I2C address match and return the command type /// @@ -1170,165 +1273,85 @@ impl<'d, M: Mode> I2c<'d, M, MultiMaster> { reg.set_af(false); }); } -} -// Address configuration methods -impl<'d, M: Mode, IM: MasterMode> I2c<'d, M, IM> { - /// Initialize slave mode with address configuration - pub(crate) fn init_slave(&mut self, config: SlaveAddrConfig) { - trace!("I2C slave: initializing with config={:?}", config); - - // Disable peripheral for configuration - self.info.regs.cr1().modify(|reg| reg.set_pe(false)); - - // Configure slave addresses - self.apply_address_configuration(config); - - // Enable peripheral with slave settings - self.info.regs.cr1().modify(|reg| { - reg.set_pe(true); - reg.set_ack(true); // Enable acknowledgment for slave mode - reg.set_nostretch(false); // Allow clock stretching for processing time - }); - - trace!("I2C slave: initialization complete"); - } - - /// Apply the complete address configuration for slave mode - fn apply_address_configuration(&mut self, config: SlaveAddrConfig) { - match config.addr { - OwnAddresses::OA1(addr) => { - self.configure_primary_address(addr); - self.disable_secondary_address(); - }, - OwnAddresses::OA2(oa2) => { - self.configure_default_primary_address(); - self.configure_secondary_address(oa2.addr); // v1 ignores mask - }, - OwnAddresses::Both { oa1, oa2 } => { - self.configure_primary_address(oa1); - self.configure_secondary_address(oa2.addr); // v1 ignores mask - } - } - - // Configure general call detection - if config.general_call { - self.info.regs.cr1().modify(|w| w.set_engc(true)); - } - } - - /// Configure the primary address (OA1) register - fn configure_primary_address(&mut self, addr: Address) { - match addr { - Address::SevenBit(addr) => { - self.info.regs.oar1().write(|reg| { - let hw_addr = (addr as u16) << 1; // Address in bits [7:1] - reg.set_add(hw_addr); - reg.set_addmode(i2c::vals::Addmode::BIT7); - }); - }, - Address::TenBit(addr) => { - self.info.regs.oar1().write(|reg| { - reg.set_add(addr); - reg.set_addmode(i2c::vals::Addmode::BIT10); - }); - } - } - - // Set required bit 14 as per reference manual - self.info.regs.oar1().modify(|reg| reg.0 |= 1 << 14); - } - - /// Configure the secondary address (OA2) register - fn configure_secondary_address(&mut self, addr: u8) { - self.info.regs.oar2().write(|reg| { - reg.set_add2(addr); - reg.set_endual(i2c::vals::Endual::DUAL); + /// Configure DMA settings for slave operations (shared between read/write) + fn setup_slave_dma_base(&mut self) { + self.info.regs.cr2().modify(|w| { + w.set_itbufen(false); // Always disable buffer interrupts when using DMA + w.set_dmaen(true); // Enable DMA requests + w.set_last(false); // LAST bit not used in slave mode for v1 hardware }); } - /// Set a default primary address when using OA2-only mode - fn configure_default_primary_address(&mut self) { - self.info.regs.oar1().write(|reg| { - reg.set_add(0); // Reserved address, safe to use - reg.set_addmode(i2c::vals::Addmode::BIT7); + /// Disable DMA and interrupts in a critical section + fn disable_dma_and_interrupts(info: &'static Info) { + critical_section::with(|_| { + info.regs.cr2().modify(|w| { + w.set_dmaen(false); + w.set_iterren(false); + w.set_itevten(false); + }); }); - self.info.regs.oar1().modify(|reg| reg.0 |= 1 << 14); } - - /// Disable secondary address when not needed - fn disable_secondary_address(&mut self) { - self.info.regs.oar2().write(|reg| { - reg.set_endual(i2c::vals::Endual::SINGLE); - }); + + /// Check for early termination conditions during slave operations + /// Returns Some(result) if termination detected, None to continue + fn check_slave_termination_conditions(sr1: i2c::regs::Sr1) -> Option { + if sr1.stopf() { + Some(SlaveTermination::Stop) + } else if sr1.addr() { + Some(SlaveTermination::Restart) + } else if sr1.af() { + Some(SlaveTermination::Nack) + } else { + None + } } } impl<'d> I2c<'d, Async, MultiMaster> { /// Async listen for incoming I2C messages using interrupts + /// + /// Waits for a master to address this slave and returns the command type + /// (Read/Write) and the matched address. This method will suspend until + /// an address match occurs. pub async fn listen(&mut self) -> Result { - trace!("I2C slave: starting listen for address match"); - - // Extract references needed by the closure let state = self.state; let info = self.info; Self::enable_interrupts(info); - trace!("I2C slave: enabled event and error interrupts"); - // Sentinel to clean up interrupts on drop + // Ensure interrupts are cleaned up on early exit let on_drop = OnDrop::new(|| { - critical_section::with(|_| { - info.regs.cr2().modify(|w| { - w.set_iterren(false); - w.set_itevten(false); - }); - }); - trace!("I2C slave: disabled interrupts on drop"); + Self::disable_dma_and_interrupts(info); }); let result = poll_fn(|cx| { state.waker.register(cx.waker()); match Self::check_and_clear_error_flags(info) { - Err(e) => { - error!("I2C slave: error during listen: {:?}", e); - Poll::Ready(Err(e)) - }, + Err(e) => Poll::Ready(Err(e)), Ok(sr1) => { if sr1.addr() { - trace!("I2C slave: ADDR flag detected - address matched"); - - // Address matched - determine direction + // Address matched - determine direction and decode address let sr2 = info.regs.sr2().read(); let direction = if sr2.tra() { - trace!("I2C slave: direction = READ (master wants to read from us)"); SlaveCommandKind::Read } else { - trace!("I2C slave: direction = WRITE (master wants to write to us)"); SlaveCommandKind::Write }; let matched_address = match Self::decode_matched_address(sr2, info) { - Ok(addr) => { - trace!("I2C slave: matched address decoded: {:?}", addr); - addr - }, - Err(e) => { - error!("I2C slave: failed to decode matched address: {:?}", e); - return Poll::Ready(Err(e)); - } + Ok(addr) => addr, + Err(e) => return Poll::Ready(Err(e)), }; - trace!("I2C slave: listen complete - returning command"); - // Don't clear ADDR here - leave it for DMA setup + // Don't clear ADDR here - leave it for DMA setup in respond methods Poll::Ready(Ok(SlaveCommand { kind: direction, address: matched_address, })) } else { - // Re-enable interrupts and continue waiting - // Use safe method since handler disables them globally Self::enable_interrupts(info); Poll::Pending } @@ -1337,341 +1360,266 @@ impl<'d> I2c<'d, Async, MultiMaster> { }).await; drop(on_drop); - trace!("I2C slave: listen result: {:?}", result); result } /// Async respond to write command using RX DMA + /// + /// Receives data from the master into the provided buffer using DMA. + /// If the master sends more bytes than the buffer can hold, excess bytes + /// are acknowledged but discarded to prevent interrupt flooding. + /// + /// Returns the number of bytes stored in the buffer (not total received). pub async fn respond_to_write(&mut self, buffer: &mut [u8]) -> Result { - trace!("I2C slave: starting respond_to_write, buffer_len={}", buffer.len()); - if buffer.is_empty() { - warn!("I2C slave: respond_to_write called with empty buffer"); return Err(Error::Overrun); } - // Extract references needed by closures let state = self.state; let info = self.info; - trace!("I2C slave: configuring registers for RX DMA"); - info.regs.cr2().modify(|w| { - w.set_itbufen(false); // Disable buffer interrupts for DMA - w.set_dmaen(true); // Enable DMA - w.set_last(false); // Not needed for slave writes - }); + // Use shared DMA setup + self.setup_slave_dma_base(); - // Sentinel to clean up DMA on drop + // Ensure proper cleanup on exit let on_drop = OnDrop::new(|| { - critical_section::with(|_| { - info.regs.cr2().modify(|w| { - w.set_dmaen(false); - w.set_iterren(false); - w.set_itevten(false); - }); - }); - trace!("I2C slave: DMA and interrupts disabled on drop (respond_to_write)"); + Self::disable_dma_and_interrupts(info); }); - // Clear ADDR flag to release clock stretching - DMA is now ready - trace!("I2C slave: clearing ADDR flag to release clock stretching"); - info.regs.sr2().read(); // Clear ADDR by reading SR2 - - // Set up RX DMA transfer (I2C DR -> buffer) - trace!("I2C slave: setting up RX DMA transfer"); - let dma_transfer = unsafe { - let src = info.regs.dr().as_ptr() as *mut u8; - self.rx_dma.as_mut().unwrap().read(src, buffer, Default::default()) - }; - - // Poll for I2C errors while DMA runs - let poll_error = poll_fn(|cx| { - state.waker.register(cx.waker()); + // Clear ADDR flag to release clock stretching + info.regs.sr2().read(); - match Self::check_and_clear_error_flags(info) { - Err(e) => { - error!("I2C slave: error during write operation: {:?}", e); - Poll::Ready(Err::<(), Error>(e)) - }, - Ok(sr1) => { - // Check for STOP condition (normal end of write) - if sr1.stopf() { - trace!("I2C slave: STOP condition detected - write transaction complete"); - Self::clear_stop_flag(info); - Poll::Ready(Ok(())) - } else if sr1.addr() { - trace!("I2C slave: RESTART condition detected - transitioning to read phase"); - Poll::Ready(Ok(())) - } else { - // Re-enable interrupts and continue monitoring - // Use safe method since handler disables them globally - Self::enable_interrupts(info); - Poll::Pending - } - } - } - }); + // Start DMA transfer and monitor completion + let result = self.execute_slave_receive_transfer(buffer, state, info).await; - trace!("I2C slave: starting select between DMA completion and I2C events"); - // Wait for either DMA completion or I2C termination condition (using master pattern) - let dma_result = match select(dma_transfer, poll_error).await { - Either::Second(Err(e)) => { - error!("I2C slave: I2C error occurred during write: {:?}", e); - critical_section::with(|_| { - info.regs.cr2().modify(|w| w.set_dmaen(false)); - }); - drop(on_drop); - return Err(e); - } - Either::First(_) => { - trace!("I2C slave: DMA transfer completed first - buffer full"); - critical_section::with(|_| { - info.regs.cr2().modify(|w| w.set_dmaen(false)); - }); - - // DMA completed but master might still be sending more bytes - // We need to discard any excess bytes until STOP/RESTART - trace!("I2C slave: DMA complete, checking for excess bytes to discard"); - - let excess_discard = poll_fn(|cx| { - state.waker.register(cx.waker()); - - match Self::check_and_clear_error_flags(info) { - Err(e) => { - error!("I2C slave: error while discarding excess bytes: {:?}", e); - Poll::Ready(Err::<(), Error>(e)) - }, - Ok(sr1) => { - // Check for transaction termination first - if sr1.stopf() { - trace!("I2C slave: STOP condition detected while discarding excess"); - Self::clear_stop_flag(info); - return Poll::Ready(Ok(())); - } - - if sr1.addr() { - trace!("I2C slave: RESTART condition detected while discarding excess"); - return Poll::Ready(Ok(())); - } - - // If there's data to read, read and discard it - if sr1.rxne() { - let discarded_byte = info.regs.dr().read().dr(); - trace!("I2C slave: discarded excess byte: 0x{:02X}", discarded_byte); - // Continue polling for more bytes or termination - Self::enable_interrupts(info); - return Poll::Pending; - } - - // No immediate termination or data, keep waiting - Self::enable_interrupts(info); - Poll::Pending - } - } - }); - - // Wait for transaction to actually end - excess_discard.await?; - - let bytes_received = buffer.len(); - trace!("I2C slave: write complete after discarding excess, returning {} bytes", bytes_received); - drop(on_drop); - Ok(bytes_received) - } - Either::Second(Ok(())) => { - trace!("I2C slave: I2C event (STOP/RESTART) occurred before DMA completion"); - critical_section::with(|_| { - info.regs.cr2().modify(|w| w.set_dmaen(false)); - }); - - // Transaction ended normally before buffer was full - let bytes_received = buffer.len(); - trace!("I2C slave: write complete via early I2C event, returning {} bytes", bytes_received); - drop(on_drop); - Ok(bytes_received) - } - }; - - dma_result + drop(on_drop); + result } /// Async respond to read command using TX DMA + /// + /// Transmits data to the master using DMA. If the master requests more bytes + /// than available in the data buffer, padding bytes (0x00) are sent until + /// the master terminates the transaction with NACK, STOP, or RESTART. + /// + /// Returns the total number of bytes transmitted (data + padding). pub async fn respond_to_read(&mut self, data: &[u8]) -> Result { - trace!("I2C slave: starting respond_to_read, data_len={}", data.len()); - if data.is_empty() { - warn!("I2C slave: respond_to_read called with empty data"); return Err(Error::Overrun); } - // Extract references needed by closures let state = self.state; let info = self.info; - trace!("I2C slave: configuring registers for TX DMA"); - info.regs.cr2().modify(|w| { - w.set_itbufen(false); // Disable buffer interrupts for DMA - w.set_dmaen(true); // Enable DMA - w.set_last(false); // Not applicable for slave transmit - }); + // Use shared DMA setup + self.setup_slave_dma_base(); - // Sentinel to clean up DMA on drop + // Ensure proper cleanup on exit let on_drop = OnDrop::new(|| { - critical_section::with(|_| { - info.regs.cr2().modify(|w| { - w.set_dmaen(false); - w.set_iterren(false); - w.set_itevten(false); - }); - }); - trace!("I2C slave: DMA and interrupts disabled on drop (respond_to_read)"); + Self::disable_dma_and_interrupts(info); }); // Clear ADDR flag to release clock stretching - trace!("I2C slave: clearing ADDR flag to release clock stretching"); info.regs.sr2().read(); - // Set up TX DMA transfer (data -> I2C DR) - trace!("I2C slave: setting up TX DMA transfer"); + // Start DMA transfer and monitor completion + let result = self.execute_slave_transmit_transfer(data, state, info).await; + + drop(on_drop); + result + } + + // === Private Transfer Execution Methods === + + /// Execute complete slave receive transfer with excess byte handling + async fn execute_slave_receive_transfer( + &mut self, + buffer: &mut [u8], + state: &'static State, + info: &'static Info + ) -> Result { + // Start DMA transfer + let dma_transfer = unsafe { + let src = info.regs.dr().as_ptr() as *mut u8; + self.rx_dma.as_mut().unwrap().read(src, buffer, Default::default()) + }; + + // Monitor for I2C events during transfer + let i2c_monitor = Self::create_termination_monitor(state, info, &[SlaveTermination::Stop, SlaveTermination::Restart]); + + match select(dma_transfer, i2c_monitor).await { + Either::Second(Err(e)) => { + Self::disable_dma_and_interrupts(info); + Err(e) + } + Either::First(_) => { + // DMA completed first - handle potential excess bytes + Self::disable_dma_and_interrupts(info); + self.handle_excess_bytes(state, info).await?; + Ok(buffer.len()) + } + Either::Second(Ok(_)) => { + // I2C event occurred first - normal transaction end + Self::disable_dma_and_interrupts(info); + Ok(buffer.len()) + } + } + } + + /// Execute complete slave transmit transfer with padding byte handling + async fn execute_slave_transmit_transfer( + &mut self, + data: &[u8], + state: &'static State, + info: &'static Info + ) -> Result { + // Start DMA transfer let dma_transfer = unsafe { let dst = info.regs.dr().as_ptr() as *mut u8; self.tx_dma.as_mut().unwrap().write(data, dst, Default::default()) }; - // Monitor for I2C events while DMA runs - let poll_completion = poll_fn(|cx| { - state.waker.register(cx.waker()); + // Monitor for I2C events during transfer (NACK is normal for slave transmit) + let i2c_monitor = Self::create_termination_monitor(state, info, &[SlaveTermination::Stop, SlaveTermination::Restart, SlaveTermination::Nack]); + match select(dma_transfer, i2c_monitor).await { + Either::Second(Err(e)) => { + Self::disable_dma_and_interrupts(info); + Err(e) + } + Either::First(_) => { + // DMA completed first - handle potential padding bytes + Self::disable_dma_and_interrupts(info); + let padding_count = self.handle_padding_bytes(state, info).await?; + Ok(data.len() + padding_count) + } + Either::Second(Ok(_)) => { + // I2C event occurred first - normal transaction end + Self::disable_dma_and_interrupts(info); + Ok(data.len()) + } + } + } + + /// Create a future that monitors for specific slave termination conditions + fn create_termination_monitor( + state: &'static State, + info: &'static Info, + allowed_terminations: &'static [SlaveTermination], + ) -> impl Future> { + poll_fn(move |cx| { + state.waker.register(cx.waker()); + match Self::check_and_clear_error_flags(info) { - Err(Error::Nack) => { - trace!("I2C slave: NACK received - master stopped reading (normal)"); - Poll::Ready(Ok(())) + Err(Error::Nack) if allowed_terminations.contains(&SlaveTermination::Nack) => { + Poll::Ready(Ok(SlaveTermination::Nack)) } - Err(e) => { - error!("I2C slave: error during read operation: {:?}", e); - Poll::Ready(Err(e)) - }, + Err(e) => Poll::Ready(Err(e)), Ok(sr1) => { - if sr1.stopf() { - trace!("I2C slave: STOP condition detected - read transaction complete"); - Self::clear_stop_flag(info); - Poll::Ready(Ok(())) - } else if sr1.addr() { - trace!("I2C slave: RESTART condition detected during read"); - Poll::Ready(Ok(())) - } else if sr1.af() { - trace!("I2C slave: acknowledge failure (NACK) - normal end of read"); - // Acknowledge failure (NACK) - normal end of read - info.regs.sr1().write(|reg| { - reg.0 = !0; - reg.set_af(false); - }); - Poll::Ready(Ok(())) + if let Some(termination) = Self::check_slave_termination_conditions(sr1) { + if allowed_terminations.contains(&termination) { + // Handle the specific termination condition + match termination { + SlaveTermination::Stop => Self::clear_stop_flag(info), + SlaveTermination::Nack => { + info.regs.sr1().write(|reg| { + reg.0 = !0; + reg.set_af(false); + }); + } + SlaveTermination::Restart => { + // ADDR flag will be handled by next listen() call + } + } + Poll::Ready(Ok(termination)) + } else { + // Unexpected termination condition + Poll::Ready(Err(Error::Bus)) + } } else { Self::enable_interrupts(info); Poll::Pending } } } - }); + }) + } - trace!("I2C slave: starting select between DMA completion and I2C events"); - // Wait for either DMA completion or I2C termination (using master pattern) - let dma_result = match select(dma_transfer, poll_completion).await { - Either::Second(Err(e)) => { - error!("I2C slave: I2C error occurred during read: {:?}", e); - critical_section::with(|_| { - info.regs.cr2().modify(|w| w.set_dmaen(false)); - }); - drop(on_drop); - return Err(e); - } - Either::First(_) => { - trace!("I2C slave: DMA transfer completed first - all data sent"); - critical_section::with(|_| { - info.regs.cr2().modify(|w| w.set_dmaen(false)); - }); - - // DMA completed but master might still be requesting more bytes - // We need to send padding bytes (0x00) until NACK/STOP/RESTART - trace!("I2C slave: DMA complete, entering padding phase"); - let mut padding_bytes_sent = 0; - - let padding_phase = poll_fn(|cx| { - state.waker.register(cx.waker()); + /// Handle excess bytes after DMA buffer is full + /// + /// Reads and discards bytes until transaction termination to prevent interrupt flooding + async fn handle_excess_bytes(&mut self, state: &'static State, info: &'static Info) -> Result<(), Error> { + poll_fn(|cx| { + state.waker.register(cx.waker()); + + match Self::check_and_clear_error_flags(info) { + Err(e) => Poll::Ready(Err(e)), + Ok(sr1) => { + // Check for transaction termination first + if let Some(termination) = Self::check_slave_termination_conditions(sr1) { + match termination { + SlaveTermination::Stop => Self::clear_stop_flag(info), + SlaveTermination::Restart => {}, // Leave ADDR for next operation + SlaveTermination::Nack => unreachable!("NACK not expected during receive"), + } + return Poll::Ready(Ok(())); + } - match Self::check_and_clear_error_flags(info) { - Err(Error::Nack) => { - trace!("I2C slave: NACK received during padding - normal end"); - return Poll::Ready(Ok(())); - }, - Err(e) => { - error!("I2C slave: error while sending padding bytes: {:?}", e); - return Poll::Ready(Err::<(), Error>(e)); - }, - Ok(sr1) => { - // Check for transaction termination first - if sr1.af() { - trace!("I2C slave: acknowledge failure during padding - normal end"); + // If there's data to read, discard it + if sr1.rxne() { + let _discarded_byte = info.regs.dr().read().dr(); + Self::enable_interrupts(info); + return Poll::Pending; + } + + Self::enable_interrupts(info); + Poll::Pending + } + } + }).await + } + + /// Handle padding bytes after DMA data is exhausted + /// + /// Sends 0x00 bytes until transaction termination to prevent interrupt flooding + async fn handle_padding_bytes(&mut self, state: &'static State, info: &'static Info) -> Result { + let mut padding_count = 0; + + poll_fn(|cx| { + state.waker.register(cx.waker()); + + match Self::check_and_clear_error_flags(info) { + Err(Error::Nack) => Poll::Ready(Ok(padding_count)), // Normal termination + Err(e) => Poll::Ready(Err(e)), + Ok(sr1) => { + // Check for transaction termination first + if let Some(termination) = Self::check_slave_termination_conditions(sr1) { + match termination { + SlaveTermination::Stop => Self::clear_stop_flag(info), + SlaveTermination::Restart => {}, // Leave ADDR for next operation + SlaveTermination::Nack => { info.regs.sr1().write(|reg| { reg.0 = !0; reg.set_af(false); }); - return Poll::Ready(Ok(())); - } - - if sr1.stopf() { - trace!("I2C slave: STOP condition detected during padding"); - Self::clear_stop_flag(info); - return Poll::Ready(Ok(())); - } - - if sr1.addr() { - trace!("I2C slave: RESTART condition detected during padding"); - return Poll::Ready(Ok(())); - } - - // If transmit buffer is empty, send a padding byte - if sr1.txe() { - info.regs.dr().write(|w| w.set_dr(0x00)); - padding_bytes_sent += 1; - trace!("I2C slave: sent padding byte #{}", padding_bytes_sent); - // Continue padding until transaction ends - Self::enable_interrupts(info); - return Poll::Pending; } - - // No immediate termination or transmit request, keep waiting - Self::enable_interrupts(info); - Poll::Pending } + return Poll::Ready(Ok(padding_count)); } - }); - - // Wait for transaction to actually end - padding_phase.await?; - - let total_bytes_sent = data.len() + padding_bytes_sent; - trace!("I2C slave: read complete after sending {} padding bytes, total {} bytes sent", - padding_bytes_sent, total_bytes_sent); - drop(on_drop); - Ok(total_bytes_sent) - } - Either::Second(Ok(())) => { - trace!("I2C slave: I2C event (STOP/NACK/RESTART) occurred before DMA completion"); - critical_section::with(|_| { - info.regs.cr2().modify(|w| w.set_dmaen(false)); - }); - - // Transaction ended normally before all data was sent - let bytes_sent = data.len(); - trace!("I2C slave: read complete via early I2C event, sent {} bytes", bytes_sent); - drop(on_drop); - Ok(bytes_sent) + + // If transmit buffer is empty, send padding byte + if sr1.txe() { + info.regs.dr().write(|w| w.set_dr(0x00)); + padding_count += 1; + Self::enable_interrupts(info); + return Poll::Pending; + } + + Self::enable_interrupts(info); + Poll::Pending + } } - }; - - dma_result + }).await } } -- cgit From e630e1a6d48ca25a92bc0479608ca75b7179c869 Mon Sep 17 00:00:00 2001 From: HybridChild Date: Fri, 22 Aug 2025 13:45:43 +0200 Subject: stm32/i2c_v1: Update defmt logging for MultiMaster --- embassy-stm32/src/i2c/v1.rs | 128 ++++++++++++++++++++++++++------------------ 1 file changed, 75 insertions(+), 53 deletions(-) diff --git a/embassy-stm32/src/i2c/v1.rs b/embassy-stm32/src/i2c/v1.rs index 0f2953ef6..b362ab017 100644 --- a/embassy-stm32/src/i2c/v1.rs +++ b/embassy-stm32/src/i2c/v1.rs @@ -45,7 +45,7 @@ impl State { // hit a case like this! pub unsafe fn on_interrupt() { let regs = T::info().regs; - trace!("i2c v1 interrupt triggered"); + trace!("I2C interrupt triggered"); // i2c v2 only woke the task on transfer complete interrupts. v1 uses interrupts for a bunch of // other stuff, so we wake the task on every interrupt. T::state().waker.wake(); @@ -360,8 +360,6 @@ impl<'d, M: Mode, IM: MasterMode> I2c<'d, M, IM> { Ok(()) } - - // Async /// Can be used by both blocking and async implementations #[inline] // pretty sure this should always be inlined @@ -374,7 +372,6 @@ impl<'d, M: Mode, IM: MasterMode> I2c<'d, M, IM> { w.set_itevten(true); }); }); - trace!("I2C slave: safely enabled interrupts"); } /// Can be used by both blocking and async implementations @@ -383,7 +380,6 @@ impl<'d, M: Mode, IM: MasterMode> I2c<'d, M, IM> { // v1 requires: READ SR1 then WRITE CR1 to clear STOPF let _ = info.regs.sr1().read(); info.regs.cr1().modify(|_| {}); // Dummy write to clear STOPF - trace!("I2C slave: STOPF flag cleared"); } } @@ -760,6 +756,7 @@ enum ReceiveResult { /// Enumeration of slave transaction termination conditions #[derive(Debug, Clone, Copy, PartialEq)] +#[cfg_attr(feature = "defmt", derive(defmt::Format))] enum SlaveTermination { /// STOP condition received - normal end of transaction Stop, @@ -887,9 +884,9 @@ impl<'d, M: Mode> I2c<'d, M, MultiMaster> { /// This method blocks until the slave address is matched by a master. /// Returns the command type (Read/Write) and the matched address. pub fn blocking_listen(&mut self) -> Result { - trace!("I2C slave: listening for address match"); + trace!("I2C slave: starting blocking listen for address match"); let result = self.blocking_listen_with_timeout(self.timeout()); - trace!("I2C slave: listen result={:?}", result); + trace!("I2C slave: blocking listen complete, result={:?}", result); result } @@ -901,16 +898,15 @@ impl<'d, M: Mode> I2c<'d, M, MultiMaster> { /// /// Returns the total number of bytes transmitted (including padding). pub fn blocking_respond_to_read(&mut self, data: &[u8]) -> Result { - trace!("I2C slave: responding to read, data_len={}", data.len()); + trace!("I2C slave: starting blocking respond_to_read, data_len={}", data.len()); - // Check for zero-length read BEFORE any transmission setup if let Some(zero_length_result) = self.detect_zero_length_read(self.timeout())? { trace!("I2C slave: zero-length read detected"); return Ok(zero_length_result); } let result = self.transmit_to_master(data, self.timeout()); - trace!("I2C slave: read response complete, result={:?}", result); + trace!("I2C slave: blocking respond_to_read complete, result={:?}", result); result } @@ -922,9 +918,9 @@ impl<'d, M: Mode> I2c<'d, M, MultiMaster> { /// /// Returns the number of bytes stored in the buffer (not total received). pub fn blocking_respond_to_write(&mut self, buffer: &mut [u8]) -> Result { - trace!("I2C slave: responding to write, buffer_len={}", buffer.len()); + trace!("I2C slave: starting blocking respond_to_write, buffer_len={}", buffer.len()); let result = self.receive_from_master(buffer, self.timeout()); - trace!("I2C slave: write response complete, result={:?}", result); + trace!("I2C slave: blocking respond_to_write complete, result={:?}", result); result } @@ -965,31 +961,35 @@ impl<'d, M: Mode> I2c<'d, M, MultiMaster> { /// Transmit data to master in response to read request fn transmit_to_master(&mut self, data: &[u8], timeout: Timeout) -> Result { let mut bytes_transmitted = 0; + let mut padding_count = 0; loop { - // Determine next byte to send let byte_to_send = if bytes_transmitted < data.len() { data[bytes_transmitted] } else { + padding_count += 1; 0x00 // Send padding bytes when data is exhausted }; - // Attempt to send the byte match self.transmit_byte(byte_to_send, timeout)? { TransmitResult::Acknowledged => { bytes_transmitted += 1; - // Continue transmission }, TransmitResult::NotAcknowledged => { bytes_transmitted += 1; // Count the NACKed byte - break; // Normal end of read transaction + break; }, TransmitResult::Stopped | TransmitResult::Restarted => { - break; // Transaction terminated by master + break; } } } + if padding_count > 0 { + trace!("I2C slave: sent {} data bytes + {} padding bytes = {} total", + data.len(), padding_count, bytes_transmitted); + } + Ok(bytes_transmitted) } @@ -1076,14 +1076,19 @@ impl<'d, M: Mode> I2c<'d, M, MultiMaster> { /// Discard excess bytes when buffer is full fn discard_excess_bytes(&mut self, timeout: Timeout) -> Result<(), Error> { + let mut discarded_count = 0; + loop { match self.receive_byte(timeout)? { ReceiveResult::Data(_) => { - // Byte received and ACKed, but discarded + discarded_count += 1; continue; }, ReceiveResult::Stopped | ReceiveResult::Restarted => { - break; // Transaction completed + if discarded_count > 0 { + trace!("I2C slave: discarded {} excess bytes", discarded_count); + } + break; }, } } @@ -1316,12 +1321,12 @@ impl<'d> I2c<'d, Async, MultiMaster> { /// (Read/Write) and the matched address. This method will suspend until /// an address match occurs. pub async fn listen(&mut self) -> Result { + trace!("I2C slave: starting async listen for address match"); let state = self.state; let info = self.info; Self::enable_interrupts(info); - // Ensure interrupts are cleaned up on early exit let on_drop = OnDrop::new(|| { Self::disable_dma_and_interrupts(info); }); @@ -1330,10 +1335,12 @@ impl<'d> I2c<'d, Async, MultiMaster> { state.waker.register(cx.waker()); match Self::check_and_clear_error_flags(info) { - Err(e) => Poll::Ready(Err(e)), + Err(e) => { + error!("I2C slave: error during listen: {:?}", e); + Poll::Ready(Err(e)) + }, Ok(sr1) => { if sr1.addr() { - // Address matched - determine direction and decode address let sr2 = info.regs.sr2().read(); let direction = if sr2.tra() { SlaveCommandKind::Read @@ -1342,11 +1349,16 @@ impl<'d> I2c<'d, Async, MultiMaster> { }; let matched_address = match Self::decode_matched_address(sr2, info) { - Ok(addr) => addr, - Err(e) => return Poll::Ready(Err(e)), + Ok(addr) => { + trace!("I2C slave: address matched, direction={:?}, addr={:?}", direction, addr); + addr + }, + Err(e) => { + error!("I2C slave: failed to decode matched address: {:?}", e); + return Poll::Ready(Err(e)); + } }; - // Don't clear ADDR here - leave it for DMA setup in respond methods Poll::Ready(Ok(SlaveCommand { kind: direction, address: matched_address, @@ -1360,6 +1372,7 @@ impl<'d> I2c<'d, Async, MultiMaster> { }).await; drop(on_drop); + trace!("I2C slave: listen complete, result={:?}", result); result } @@ -1371,28 +1384,28 @@ impl<'d> I2c<'d, Async, MultiMaster> { /// /// Returns the number of bytes stored in the buffer (not total received). pub async fn respond_to_write(&mut self, buffer: &mut [u8]) -> Result { + trace!("I2C slave: starting respond_to_write, buffer_len={}", buffer.len()); + if buffer.is_empty() { + warn!("I2C slave: respond_to_write called with empty buffer"); return Err(Error::Overrun); } let state = self.state; let info = self.info; - // Use shared DMA setup self.setup_slave_dma_base(); - // Ensure proper cleanup on exit let on_drop = OnDrop::new(|| { Self::disable_dma_and_interrupts(info); }); - // Clear ADDR flag to release clock stretching info.regs.sr2().read(); - // Start DMA transfer and monitor completion let result = self.execute_slave_receive_transfer(buffer, state, info).await; drop(on_drop); + trace!("I2C slave: respond_to_write complete, result={:?}", result); result } @@ -1404,28 +1417,28 @@ impl<'d> I2c<'d, Async, MultiMaster> { /// /// Returns the total number of bytes transmitted (data + padding). pub async fn respond_to_read(&mut self, data: &[u8]) -> Result { + trace!("I2C slave: starting respond_to_read, data_len={}", data.len()); + if data.is_empty() { + warn!("I2C slave: respond_to_read called with empty data"); return Err(Error::Overrun); } let state = self.state; let info = self.info; - // Use shared DMA setup self.setup_slave_dma_base(); - // Ensure proper cleanup on exit let on_drop = OnDrop::new(|| { Self::disable_dma_and_interrupts(info); }); - // Clear ADDR flag to release clock stretching info.regs.sr2().read(); - // Start DMA transfer and monitor completion let result = self.execute_slave_transmit_transfer(data, state, info).await; drop(on_drop); + trace!("I2C slave: respond_to_read complete, result={:?}", result); result } @@ -1438,28 +1451,27 @@ impl<'d> I2c<'d, Async, MultiMaster> { state: &'static State, info: &'static Info ) -> Result { - // Start DMA transfer let dma_transfer = unsafe { let src = info.regs.dr().as_ptr() as *mut u8; self.rx_dma.as_mut().unwrap().read(src, buffer, Default::default()) }; - // Monitor for I2C events during transfer let i2c_monitor = Self::create_termination_monitor(state, info, &[SlaveTermination::Stop, SlaveTermination::Restart]); match select(dma_transfer, i2c_monitor).await { Either::Second(Err(e)) => { + error!("I2C slave: error during receive transfer: {:?}", e); Self::disable_dma_and_interrupts(info); Err(e) } Either::First(_) => { - // DMA completed first - handle potential excess bytes + trace!("I2C slave: DMA receive completed, handling excess bytes"); Self::disable_dma_and_interrupts(info); self.handle_excess_bytes(state, info).await?; Ok(buffer.len()) } - Either::Second(Ok(_)) => { - // I2C event occurred first - normal transaction end + Either::Second(Ok(termination)) => { + trace!("I2C slave: receive terminated by I2C event: {:?}", termination); Self::disable_dma_and_interrupts(info); Ok(buffer.len()) } @@ -1473,28 +1485,30 @@ impl<'d> I2c<'d, Async, MultiMaster> { state: &'static State, info: &'static Info ) -> Result { - // Start DMA transfer let dma_transfer = unsafe { let dst = info.regs.dr().as_ptr() as *mut u8; self.tx_dma.as_mut().unwrap().write(data, dst, Default::default()) }; - // Monitor for I2C events during transfer (NACK is normal for slave transmit) let i2c_monitor = Self::create_termination_monitor(state, info, &[SlaveTermination::Stop, SlaveTermination::Restart, SlaveTermination::Nack]); match select(dma_transfer, i2c_monitor).await { Either::Second(Err(e)) => { + error!("I2C slave: error during transmit transfer: {:?}", e); Self::disable_dma_and_interrupts(info); Err(e) } Either::First(_) => { - // DMA completed first - handle potential padding bytes + trace!("I2C slave: DMA transmit completed, handling padding bytes"); Self::disable_dma_and_interrupts(info); let padding_count = self.handle_padding_bytes(state, info).await?; - Ok(data.len() + padding_count) + let total_bytes = data.len() + padding_count; + trace!("I2C slave: sent {} data bytes + {} padding bytes = {} total", + data.len(), padding_count, total_bytes); + Ok(total_bytes) } - Either::Second(Ok(_)) => { - // I2C event occurred first - normal transaction end + Either::Second(Ok(termination)) => { + trace!("I2C slave: transmit terminated by I2C event: {:?}", termination); Self::disable_dma_and_interrupts(info); Ok(data.len()) } @@ -1549,25 +1563,32 @@ impl<'d> I2c<'d, Async, MultiMaster> { /// /// Reads and discards bytes until transaction termination to prevent interrupt flooding async fn handle_excess_bytes(&mut self, state: &'static State, info: &'static Info) -> Result<(), Error> { + let mut discarded_count = 0; + poll_fn(|cx| { state.waker.register(cx.waker()); match Self::check_and_clear_error_flags(info) { - Err(e) => Poll::Ready(Err(e)), + Err(e) => { + error!("I2C slave: error while discarding excess bytes: {:?}", e); + Poll::Ready(Err(e)) + }, Ok(sr1) => { - // Check for transaction termination first if let Some(termination) = Self::check_slave_termination_conditions(sr1) { match termination { SlaveTermination::Stop => Self::clear_stop_flag(info), - SlaveTermination::Restart => {}, // Leave ADDR for next operation + SlaveTermination::Restart => {}, SlaveTermination::Nack => unreachable!("NACK not expected during receive"), } + if discarded_count > 0 { + trace!("I2C slave: discarded {} excess bytes", discarded_count); + } return Poll::Ready(Ok(())); } - // If there's data to read, discard it if sr1.rxne() { let _discarded_byte = info.regs.dr().read().dr(); + discarded_count += 1; Self::enable_interrupts(info); return Poll::Pending; } @@ -1589,14 +1610,16 @@ impl<'d> I2c<'d, Async, MultiMaster> { state.waker.register(cx.waker()); match Self::check_and_clear_error_flags(info) { - Err(Error::Nack) => Poll::Ready(Ok(padding_count)), // Normal termination - Err(e) => Poll::Ready(Err(e)), + Err(Error::Nack) => Poll::Ready(Ok(padding_count)), + Err(e) => { + error!("I2C slave: error while sending padding bytes: {:?}", e); + Poll::Ready(Err(e)) + }, Ok(sr1) => { - // Check for transaction termination first if let Some(termination) = Self::check_slave_termination_conditions(sr1) { match termination { SlaveTermination::Stop => Self::clear_stop_flag(info), - SlaveTermination::Restart => {}, // Leave ADDR for next operation + SlaveTermination::Restart => {}, SlaveTermination::Nack => { info.regs.sr1().write(|reg| { reg.0 = !0; @@ -1607,7 +1630,6 @@ impl<'d> I2c<'d, Async, MultiMaster> { return Poll::Ready(Ok(padding_count)); } - // If transmit buffer is empty, send padding byte if sr1.txe() { info.regs.dr().write(|w| w.set_dr(0x00)); padding_count += 1; -- cgit From 572a40b4eee99b177733f50b08e29ff9b5ab6fa5 Mon Sep 17 00:00:00 2001 From: HybridChild Date: Sat, 23 Aug 2025 08:31:41 +0200 Subject: stm32/i2c_v1: Add async and blocking example code --- examples/stm32f4/src/bin/i2c_slave_async.rs | 123 +++++++++++++++++++++++++ examples/stm32f4/src/bin/i2c_slave_blocking.rs | 118 ++++++++++++++++++++++++ 2 files changed, 241 insertions(+) create mode 100644 examples/stm32f4/src/bin/i2c_slave_async.rs create mode 100644 examples/stm32f4/src/bin/i2c_slave_blocking.rs diff --git a/examples/stm32f4/src/bin/i2c_slave_async.rs b/examples/stm32f4/src/bin/i2c_slave_async.rs new file mode 100644 index 000000000..072c9875e --- /dev/null +++ b/examples/stm32f4/src/bin/i2c_slave_async.rs @@ -0,0 +1,123 @@ +//! I2C slave example using async operations with DMA +//! +//! This example demonstrates DMA-accelerated I2C slave operations, +//! which provide better performance and lower CPU overhead for +//! high-frequency I2C transactions. + +#![no_std] +#![no_main] + +use defmt_rtt as _; +use defmt::{error, info}; +use embassy_executor::Spawner; +use embassy_stm32::{bind_interrupts, peripherals}; +use embassy_stm32::i2c::{self, I2c, SlaveAddrConfig, SlaveCommand, SlaveCommandKind, Address}; +use embassy_stm32::time::Hertz; +use embassy_sync::blocking_mutex::raw::ThreadModeRawMutex; +use embassy_sync::mutex::Mutex; +use embassy_time::{Duration, Timer}; +use panic_probe as _; + +pub const I2C_SLAVE_ADDR: u8 = 0x42; +pub const BUFFER_SIZE: usize = 8; +static I2C_BUFFER: Mutex = Mutex::new([0; BUFFER_SIZE]); + +bind_interrupts!(struct Irqs { + I2C1_EV => i2c::EventInterruptHandler; + I2C1_ER => i2c::ErrorInterruptHandler; +}); + +#[embassy_executor::main] +async fn main(spawner: Spawner) { + let p = embassy_stm32::init(Default::default()); + + // Configure I2C + let mut i2c_config = i2c::Config::default(); + i2c_config.sda_pullup = false; + i2c_config.scl_pullup = false; + i2c_config.frequency = Hertz(100_000); // 100kHz I2C speed + + // Initialize I2C as master first + let i2c_master = I2c::new( + p.I2C1, + p.PB8, // SCL + p.PB9, // SDA + Irqs, + p.DMA1_CH6, // TX DMA + p.DMA1_CH0, // RX DMA + i2c_config, + ); + + // Convert to MultiMaster mode + let slave_config = SlaveAddrConfig::basic(I2C_SLAVE_ADDR); + let i2c_slave = i2c_master.into_slave_multimaster(slave_config); + + spawner.spawn(i2c_slave_task(i2c_slave)).unwrap(); +} + +#[embassy_executor::task] +pub async fn i2c_slave_task(mut i2c_slave: I2c<'static, embassy_stm32::mode::Async, i2c::mode::MultiMaster>) { + info!("Async I2C slave ready at address 0x{:02X}", I2C_SLAVE_ADDR); + + loop { + match i2c_slave.listen().await { + Ok(SlaveCommand { kind: SlaveCommandKind::Write, address }) => { + let addr_val = match address { + Address::SevenBit(addr) => addr, + Address::TenBit(addr) => (addr & 0xFF) as u8, + }; + + info!("I2C: Received write command - Address 0x{:02X}", addr_val); + + let mut data_buffer = I2C_BUFFER.lock().await; + + match i2c_slave.respond_to_write(&mut *data_buffer).await { + Ok(_) => { + info!("I2C: Data received - Buffer now contains: 0x{:02X}, 0x{:02X}, 0x{:02X}, 0x{:02X}, 0x{:02X}, 0x{:02X}, 0x{:02X}, 0x{:02X}", + data_buffer[0], data_buffer[1], data_buffer[2], data_buffer[3], data_buffer[4], data_buffer[5], data_buffer[6], data_buffer[7]); + } + Err(e) => { + error!("I2C: Write error: {}", format_i2c_error(&e)); + } + } + } + + Ok(SlaveCommand { kind: SlaveCommandKind::Read, address }) => { + let addr_val = match address { + Address::SevenBit(addr) => addr, + Address::TenBit(addr) => (addr & 0xFF) as u8, // Show low byte for 10-bit + }; + + info!("I2C: Received read command - Address 0x{:02X}", addr_val); + + let data_buffer = I2C_BUFFER.lock().await; + + match i2c_slave.respond_to_read(&data_buffer[..BUFFER_SIZE]).await { + Ok(_) => { + info!("I2C: Responded to read command"); + } + Err(e) => { + error!("I2C: Read error: {}", format_i2c_error(&e)); + } + } + } + + Err(e) => { + error!("I2C: Listen error: {}", format_i2c_error(&e)); + Timer::after(Duration::from_millis(100)).await; + } + } + } +} + +fn format_i2c_error(e: &embassy_stm32::i2c::Error) -> &'static str { + match e { + embassy_stm32::i2c::Error::Bus => "Bus", + embassy_stm32::i2c::Error::Arbitration => "Arbitration", + embassy_stm32::i2c::Error::Nack => "Nack", + embassy_stm32::i2c::Error::Timeout => "Timeout", + embassy_stm32::i2c::Error::Crc => "Crc", + embassy_stm32::i2c::Error::Overrun => "Overrun", + embassy_stm32::i2c::Error::ZeroLengthTransfer => "ZeroLengthTransfer", + } +} diff --git a/examples/stm32f4/src/bin/i2c_slave_blocking.rs b/examples/stm32f4/src/bin/i2c_slave_blocking.rs new file mode 100644 index 000000000..c55f2f6c1 --- /dev/null +++ b/examples/stm32f4/src/bin/i2c_slave_blocking.rs @@ -0,0 +1,118 @@ +//! Complete I2C slave example using blocking operations +//! +//! This example shows how to set up an STM32F4 as an I2C slave device +//! that can handle both read and write transactions from master devices. + +#![no_std] +#![no_main] + +use defmt_rtt as _; +use defmt::{error, info}; +use embassy_executor::Spawner; +use embassy_stm32::i2c::{self, I2c, SlaveAddrConfig, SlaveCommand, SlaveCommandKind, Address}; +use embassy_stm32::{bind_interrupts, peripherals}; +use embassy_stm32::time::Hertz; +use embassy_sync::blocking_mutex::raw::ThreadModeRawMutex; +use embassy_sync::mutex::Mutex; +use embassy_time::{Duration, Timer}; +use panic_probe as _; + +pub const I2C_SLAVE_ADDR: u8 = 0x42; +pub const BUFFER_SIZE: usize = 8; +static I2C_BUFFER: Mutex = Mutex::new([0; BUFFER_SIZE]); + +bind_interrupts!(struct Irqs { + I2C1_EV => i2c::EventInterruptHandler; + I2C1_ER => i2c::ErrorInterruptHandler; +}); + +#[embassy_executor::main] +async fn main(spawner: Spawner) { + let p = embassy_stm32::init(Default::default()); + + // Configure I2C + let mut i2c_config = i2c::Config::default(); + i2c_config.sda_pullup = false; + i2c_config.scl_pullup = false; + i2c_config.frequency = Hertz(100_000); + i2c_config.timeout = embassy_time::Duration::from_millis(30000); + + // Initialize I2C as master first + let i2c_master = I2c::new_blocking( + p.I2C1, + p.PB8, // SCL + p.PB9, // SDA + i2c_config, + ); + + // Convert to slave+master mode + let slave_config = SlaveAddrConfig::basic(I2C_SLAVE_ADDR); + let i2c_slave = i2c_master.into_slave_multimaster(slave_config); + + spawner.spawn(i2c_slave_task(i2c_slave)).unwrap(); +} + +#[embassy_executor::task] +pub async fn i2c_slave_task(mut i2c_slave: I2c<'static, embassy_stm32::mode::Blocking, i2c::mode::MultiMaster>) { + info!("Blocking I2C slave ready at address 0x{:02X}", I2C_SLAVE_ADDR); + + loop { + match i2c_slave.blocking_listen() { + Ok(SlaveCommand { kind: SlaveCommandKind::Write, address }) => { + let addr_val = match address { + Address::SevenBit(addr) => addr, + Address::TenBit(addr) => (addr & 0xFF) as u8, + }; + + info!("I2C: Received write command - Address 0x{:02X}", addr_val); + let mut data_buffer = I2C_BUFFER.lock().await; + + match i2c_slave.blocking_respond_to_write(&mut *data_buffer) { + Ok(bytes_received) => { + info!("I2C: Received {} bytes - Buffer now contains: 0x{:02X}, 0x{:02X}, 0x{:02X}, 0x{:02X}, 0x{:02X}, 0x{:02X}, 0x{:02X}, 0x{:02X}", + bytes_received, data_buffer[0], data_buffer[1], data_buffer[2], data_buffer[3], data_buffer[4], data_buffer[5], data_buffer[6], data_buffer[7]); + } + Err(e) => { + error!("I2C: Write error: {}", format_i2c_error(&e)); + } + } + } + + Ok(SlaveCommand { kind: SlaveCommandKind::Read, address }) => { + let addr_val = match address { + Address::SevenBit(addr) => addr, + Address::TenBit(addr) => (addr & 0xFF) as u8, // Show low byte for 10-bit + }; + + info!("I2C: Received read command - Address 0x{:02X}", addr_val); + let data_buffer = I2C_BUFFER.lock().await; + + match i2c_slave.blocking_respond_to_read(&data_buffer[..BUFFER_SIZE]) { + Ok(bytes_sent) => { + info!("I2C: Responded to read - {} bytes sent", bytes_sent); + } + Err(e) => { + error!("I2C: Read error: {}", format_i2c_error(&e)); + } + } + } + + Err(e) => { + error!("I2C: Listen error: {}", format_i2c_error(&e)); + Timer::after(Duration::from_millis(100)).await; + } + } + } +} + +fn format_i2c_error(e: &embassy_stm32::i2c::Error) -> &'static str { + match e { + embassy_stm32::i2c::Error::Bus => "Bus", + embassy_stm32::i2c::Error::Arbitration => "Arbitration", + embassy_stm32::i2c::Error::Nack => "Nack", + embassy_stm32::i2c::Error::Timeout => "Timeout", + embassy_stm32::i2c::Error::Crc => "Crc", + embassy_stm32::i2c::Error::Overrun => "Overrun", + embassy_stm32::i2c::Error::ZeroLengthTransfer => "ZeroLengthTransfer", + } +} -- cgit From fbefd6c36aa123e479e39d2bd8c37d987e36597c Mon Sep 17 00:00:00 2001 From: HybridChild Date: Sat, 23 Aug 2025 09:17:49 +0200 Subject: Revert "stm32/i2c: v1 and v2 now has separate definitions for the State struct" This reverts commit b690a0314f0f2e42137ad4b3e867e056c1d3c14e. --- embassy-stm32/src/i2c/mod.rs | 17 ++++++++++++++--- embassy-stm32/src/i2c/v1.rs | 15 --------------- embassy-stm32/src/i2c/v2.rs | 15 --------------- 3 files changed, 14 insertions(+), 33 deletions(-) diff --git a/embassy-stm32/src/i2c/mod.rs b/embassy-stm32/src/i2c/mod.rs index 675a392f9..4caa35efb 100644 --- a/embassy-stm32/src/i2c/mod.rs +++ b/embassy-stm32/src/i2c/mod.rs @@ -5,9 +5,6 @@ #[cfg_attr(any(i2c_v2, i2c_v3), path = "v2.rs")] mod _version; -// Type alias for the peri_trait! macro -type State = _version::State; - mod config; use core::future::Future; @@ -16,6 +13,7 @@ use core::marker::PhantomData; pub use config::*; use embassy_hal_internal::Peri; +use embassy_sync::waitqueue::AtomicWaker; #[cfg(feature = "time")] use embassy_time::{Duration, Instant}; use mode::MasterMode; @@ -277,6 +275,19 @@ impl Timeout { } } +struct State { + #[allow(unused)] + waker: AtomicWaker, +} + +impl State { + const fn new() -> Self { + Self { + waker: AtomicWaker::new(), + } + } +} + struct Info { regs: crate::pac::i2c::I2c, rcc: RccInfo, diff --git a/embassy-stm32/src/i2c/v1.rs b/embassy-stm32/src/i2c/v1.rs index b362ab017..879d1686b 100644 --- a/embassy-stm32/src/i2c/v1.rs +++ b/embassy-stm32/src/i2c/v1.rs @@ -17,21 +17,6 @@ use super::*; use crate::mode::Mode; use crate::pac::i2c; -use embassy_sync::waitqueue::AtomicWaker; - -/// I2C v2 peripheral state -pub(crate) struct State { - pub(crate) waker: AtomicWaker, -} - -impl State { - pub(crate) const fn new() -> Self { - Self { - waker: AtomicWaker::new(), - } - } -} - // /!\ /!\ // /!\ Implementation note! /!\ // /!\ /!\ diff --git a/embassy-stm32/src/i2c/v2.rs b/embassy-stm32/src/i2c/v2.rs index 72a7d05ab..3b09f1b34 100644 --- a/embassy-stm32/src/i2c/v2.rs +++ b/embassy-stm32/src/i2c/v2.rs @@ -12,21 +12,6 @@ use stm32_metapac::i2c::vals::{Addmode, Oamsk}; use super::*; use crate::pac::i2c; -use embassy_sync::waitqueue::AtomicWaker; - -/// I2C v2 peripheral state -pub(crate) struct State { - pub(crate) waker: AtomicWaker, -} - -impl State { - pub(crate) const fn new() -> Self { - Self { - waker: AtomicWaker::new(), - } - } -} - impl From for Oamsk { fn from(value: AddrMask) -> Self { match value { -- cgit From 109c2cbdc4711bd929308944c22d079e986ebeb9 Mon Sep 17 00:00:00 2001 From: HybridChild Date: Sat, 23 Aug 2025 10:01:53 +0200 Subject: stm32/i2c: Add core::fmt::Debug for enums --- embassy-stm32/src/i2c/config.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/embassy-stm32/src/i2c/config.rs b/embassy-stm32/src/i2c/config.rs index 4e3b736c7..74fac14b2 100644 --- a/embassy-stm32/src/i2c/config.rs +++ b/embassy-stm32/src/i2c/config.rs @@ -4,7 +4,7 @@ use crate::gpio::{AfType, OutputType, Speed}; use crate::time::Hertz; #[repr(u8)] -#[derive(Copy, Clone)] +#[derive(Debug, Copy, Clone)] #[cfg_attr(feature = "defmt", derive(defmt::Format))] /// Bits of the I2C OA2 register to mask out. pub enum AddrMask { @@ -60,7 +60,7 @@ impl Address { } } -#[derive(Copy, Clone)] +#[derive(Debug, Copy, Clone)] #[cfg_attr(feature = "defmt", derive(defmt::Format))] /// The second Own Address register. pub struct OA2 { @@ -70,7 +70,7 @@ pub struct OA2 { pub mask: AddrMask, } -#[derive(Copy, Clone)] +#[derive(Debug, Copy, Clone)] #[cfg_attr(feature = "defmt", derive(defmt::Format))] /// The Own Address(es) of the I2C peripheral. pub enum OwnAddresses { @@ -88,7 +88,7 @@ pub enum OwnAddresses { } /// Slave Configuration -#[derive(Copy, Clone)] +#[derive(Debug, Copy, Clone)] #[cfg_attr(feature = "defmt", derive(defmt::Format))] pub struct SlaveAddrConfig { /// Target Address(es) -- cgit From 5d3a1dd7e549de578c6a77d3998beddf1b1474d3 Mon Sep 17 00:00:00 2001 From: HybridChild Date: Sat, 23 Aug 2025 10:28:50 +0200 Subject: stm32/i2c: Remove rustdoc example for assign_operation_framing function --- embassy-stm32/src/i2c/mod.rs | 11 +---------- 1 file changed, 1 insertion(+), 10 deletions(-) diff --git a/embassy-stm32/src/i2c/mod.rs b/embassy-stm32/src/i2c/mod.rs index 4caa35efb..00330c97e 100644 --- a/embassy-stm32/src/i2c/mod.rs +++ b/embassy-stm32/src/i2c/mod.rs @@ -525,16 +525,7 @@ impl OperationFraming { /// /// # Returns /// An iterator over (operation, framing) pairs, or an error if the transaction is invalid -/// -/// # Example -/// ```rust -/// for (op, framing) in assign_operation_framing(operations)? { -/// match op { -/// Operation::Read(buffer) => self.read_with_framing(addr, buffer, framing).await?, -/// Operation::Write(data) => self.write_with_framing(addr, data, framing).await?, -/// } -/// } -/// ``` +/// #[allow(dead_code)] fn assign_operation_framing<'a, 'b: 'a>( operations: &'a mut [embedded_hal_1::i2c::Operation<'b>], -- cgit From a51c0320e907d895bb1f55e8960a69df5f5a276b Mon Sep 17 00:00:00 2001 From: HybridChild Date: Sat, 23 Aug 2025 10:36:56 +0200 Subject: stm32: Add entry in CHANGELOG.md file --- embassy-stm32/CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/embassy-stm32/CHANGELOG.md b/embassy-stm32/CHANGELOG.md index 9cd4d5951..c93334102 100644 --- a/embassy-stm32/CHANGELOG.md +++ b/embassy-stm32/CHANGELOG.md @@ -14,6 +14,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - fix: Fix performing a hash after performing a hmac - chore: Updated stm32-metapac and stm32-data dependencies - fix: Fix XSPI not disabling alternate bytes when they were previously enabled +- feat: Add I2C MultiMaster (Slave) support for I2C v1 ## 0.3.0 - 2025-08-12 -- cgit From 97d5de640a90ce31b81411a742b33d9b86d2b441 Mon Sep 17 00:00:00 2001 From: HybridChild Date: Sat, 23 Aug 2025 10:46:39 +0200 Subject: stm32: Run cargo fmt --- embassy-stm32/src/i2c/mod.rs | 12 +- embassy-stm32/src/i2c/v1.rs | 362 ++++++++++++++++++++++++------------------- 2 files changed, 212 insertions(+), 162 deletions(-) diff --git a/embassy-stm32/src/i2c/mod.rs b/embassy-stm32/src/i2c/mod.rs index 00330c97e..7f5cde1c5 100644 --- a/embassy-stm32/src/i2c/mod.rs +++ b/embassy-stm32/src/i2c/mod.rs @@ -442,7 +442,7 @@ impl<'d, IM: MasterMode> embedded_hal_async::i2c::I2c for I2c<'d, Async, IM> { /// controlling the generation of start conditions (ST or SR), stop conditions (SP), /// and ACK/NACK behavior for read operations. /// -/// For write operations, some framing configurations are functionally identical +/// For write operations, some framing configurations are functionally identical /// because they differ only in ACK/NACK treatment which is relevant only for reads: /// /// - `First` and `FirstAndNext` behave identically for writes @@ -489,7 +489,7 @@ impl OperationFraming { } /// Returns true if NACK should be sent after the last byte received in a read operation. - /// + /// /// This signals the end of a read sequence and releases the bus for the master's /// next transmission (or stop condition). fn send_nack(self) -> bool { @@ -525,7 +525,7 @@ impl OperationFraming { /// /// # Returns /// An iterator over (operation, framing) pairs, or an error if the transaction is invalid -/// +/// #[allow(dead_code)] fn assign_operation_framing<'a, 'b: 'a>( operations: &'a mut [embedded_hal_1::i2c::Operation<'b>], @@ -535,7 +535,7 @@ fn assign_operation_framing<'a, 'b: 'a>( // Validate that no read operations have empty buffers before starting the transaction. // Empty read operations would risk halting with an error mid-transaction. // - // Note: We could theoretically allow empty read operations within consecutive read + // Note: We could theoretically allow empty read operations within consecutive read // sequences as long as the final merged read has at least one byte, but this would // complicate the logic significantly and create error-prone edge cases. if operations.iter().any(|op| match op { @@ -558,7 +558,7 @@ fn assign_operation_framing<'a, 'b: 'a>( // Compute the appropriate framing based on three key properties: // // 1. **Start Condition**: Generate (repeated) start for first operation of each type - // 2. **Stop Condition**: Generate stop for the final operation in the entire transaction + // 2. **Stop Condition**: Generate stop for the final operation in the entire transaction // 3. **ACK/NACK for Reads**: For read operations, send ACK if more reads follow in the // sequence, or NACK for the final read in a sequence (before write or transaction end) // @@ -571,7 +571,7 @@ fn assign_operation_framing<'a, 'b: 'a>( (true, Some(Read(_))) => OperationFraming::FirstAndNext, // First operation of type, next operation is write (end current sequence) (true, Some(Write(_))) => OperationFraming::First, - + // Continuation operation, and it's the final operation overall (false, None) => OperationFraming::Last, // Continuation operation, next operation is also a read (continue read sequence) diff --git a/embassy-stm32/src/i2c/v1.rs b/embassy-stm32/src/i2c/v1.rs index 879d1686b..d1e15d6f2 100644 --- a/embassy-stm32/src/i2c/v1.rs +++ b/embassy-stm32/src/i2c/v1.rs @@ -153,7 +153,13 @@ impl<'d, M: Mode, IM: MasterMode> I2c<'d, M, IM> { Ok(sr1) } - fn write_bytes(&mut self, address: u8, write_buffer: &[u8], timeout: Timeout, framing: OperationFraming) -> Result<(), Error> { + fn write_bytes( + &mut self, + address: u8, + write_buffer: &[u8], + timeout: Timeout, + framing: OperationFraming, + ) -> Result<(), Error> { if framing.send_start() { // Send a START condition @@ -313,7 +319,12 @@ impl<'d, M: Mode, IM: MasterMode> I2c<'d, M, IM> { } /// Blocking write, restart, read. - pub fn blocking_write_read(&mut self, address: u8, write_buffer: &[u8], read_buffer: &mut [u8]) -> Result<(), Error> { + pub fn blocking_write_read( + &mut self, + address: u8, + write_buffer: &[u8], + read_buffer: &mut [u8], + ) -> Result<(), Error> { // Check empty read buffer before starting transaction. Otherwise, we would not generate the // stop condition below. if read_buffer.is_empty() { @@ -345,7 +356,7 @@ impl<'d, M: Mode, IM: MasterMode> I2c<'d, M, IM> { Ok(()) } - + /// Can be used by both blocking and async implementations #[inline] // pretty sure this should always be inlined fn enable_interrupts(info: &'static Info) { @@ -366,11 +377,15 @@ impl<'d, M: Mode, IM: MasterMode> I2c<'d, M, IM> { let _ = info.regs.sr1().read(); info.regs.cr1().modify(|_| {}); // Dummy write to clear STOPF } - } impl<'d, IM: MasterMode> I2c<'d, Async, IM> { - async fn write_with_framing(&mut self, address: u8, write_buffer: &[u8], framing: OperationFraming) -> Result<(), Error> { + async fn write_with_framing( + &mut self, + address: u8, + write_buffer: &[u8], + framing: OperationFraming, + ) -> Result<(), Error> { self.info.regs.cr2().modify(|w| { // Note: Do not enable the ITBUFEN bit in the I2C_CR2 register if DMA is used for // reception. @@ -453,7 +468,10 @@ impl<'d, IM: MasterMode> I2c<'d, Async, IM> { // this address from the memory after each TxE event. let dst = self.info.regs.dr().as_ptr() as *mut u8; - self.tx_dma.as_mut().unwrap().write(write_buffer, dst, Default::default()) + self.tx_dma + .as_mut() + .unwrap() + .write(write_buffer, dst, Default::default()) }; // Wait for bytes to be sent, or an error to occur. @@ -530,7 +548,12 @@ impl<'d, IM: MasterMode> I2c<'d, Async, IM> { Ok(()) } - async fn read_with_framing(&mut self, address: u8, read_buffer: &mut [u8], framing: OperationFraming) -> Result<(), Error> { + async fn read_with_framing( + &mut self, + address: u8, + read_buffer: &mut [u8], + framing: OperationFraming, + ) -> Result<(), Error> { if read_buffer.is_empty() { return Err(Error::Overrun); } @@ -694,8 +717,10 @@ impl<'d, IM: MasterMode> I2c<'d, Async, IM> { return Err(Error::Overrun); } - self.write_with_framing(address, write_buffer, OperationFraming::First).await?; - self.read_with_framing(address, read_buffer, OperationFraming::FirstAndLast).await + self.write_with_framing(address, write_buffer, OperationFraming::First) + .await?; + self.read_with_framing(address, read_buffer, OperationFraming::FirstAndLast) + .await } /// Transaction with operations. @@ -758,13 +783,13 @@ impl<'d, M: Mode> I2c<'d, M, Master> { info: self.info, state: self.state, kernel_clock: self.kernel_clock, - tx_dma: self.tx_dma.take(), // Use take() to move ownership - rx_dma: self.rx_dma.take(), // Use take() to move ownership + tx_dma: self.tx_dma.take(), // Use take() to move ownership + rx_dma: self.rx_dma.take(), // Use take() to move ownership #[cfg(feature = "time")] timeout: self.timeout, _phantom: PhantomData, _phantom2: PhantomData, - _drop_guard: self._drop_guard, // Move the drop guard + _drop_guard: self._drop_guard, // Move the drop guard }; slave.init_slave(slave_addr_config); slave @@ -776,46 +801,46 @@ impl<'d, M: Mode, IM: MasterMode> I2c<'d, M, IM> { /// Initialize slave mode with address configuration pub(crate) fn init_slave(&mut self, config: SlaveAddrConfig) { trace!("I2C slave: initializing with config={:?}", config); - + // Disable peripheral for configuration self.info.regs.cr1().modify(|reg| reg.set_pe(false)); - + // Configure slave addresses self.apply_address_configuration(config); - + // Enable peripheral with slave settings self.info.regs.cr1().modify(|reg| { reg.set_pe(true); reg.set_ack(true); // Enable acknowledgment for slave mode reg.set_nostretch(false); // Allow clock stretching for processing time }); - + trace!("I2C slave: initialization complete"); } - + /// Apply the complete address configuration for slave mode fn apply_address_configuration(&mut self, config: SlaveAddrConfig) { match config.addr { OwnAddresses::OA1(addr) => { self.configure_primary_address(addr); self.disable_secondary_address(); - }, + } OwnAddresses::OA2(oa2) => { self.configure_default_primary_address(); self.configure_secondary_address(oa2.addr); // v1 ignores mask - }, + } OwnAddresses::Both { oa1, oa2 } => { self.configure_primary_address(oa1); self.configure_secondary_address(oa2.addr); // v1 ignores mask } } - + // Configure general call detection if config.general_call { self.info.regs.cr1().modify(|w| w.set_engc(true)); } } - + /// Configure the primary address (OA1) register fn configure_primary_address(&mut self, addr: Address) { match addr { @@ -825,7 +850,7 @@ impl<'d, M: Mode, IM: MasterMode> I2c<'d, M, IM> { reg.set_add(hw_addr); reg.set_addmode(i2c::vals::Addmode::BIT7); }); - }, + } Address::TenBit(addr) => { self.info.regs.oar1().write(|reg| { reg.set_add(addr); @@ -833,11 +858,11 @@ impl<'d, M: Mode, IM: MasterMode> I2c<'d, M, IM> { }); } } - + // Set required bit 14 as per reference manual self.info.regs.oar1().modify(|reg| reg.0 |= 1 << 14); } - + /// Configure the secondary address (OA2) register fn configure_secondary_address(&mut self, addr: u8) { self.info.regs.oar2().write(|reg| { @@ -845,7 +870,7 @@ impl<'d, M: Mode, IM: MasterMode> I2c<'d, M, IM> { reg.set_endual(i2c::vals::Endual::DUAL); }); } - + /// Set a default primary address when using OA2-only mode fn configure_default_primary_address(&mut self) { self.info.regs.oar1().write(|reg| { @@ -854,7 +879,7 @@ impl<'d, M: Mode, IM: MasterMode> I2c<'d, M, IM> { }); self.info.regs.oar1().modify(|reg| reg.0 |= 1 << 14); } - + /// Disable secondary address when not needed fn disable_secondary_address(&mut self) { self.info.regs.oar2().write(|reg| { @@ -865,7 +890,7 @@ impl<'d, M: Mode, IM: MasterMode> I2c<'d, M, IM> { impl<'d, M: Mode> I2c<'d, M, MultiMaster> { /// Listen for incoming I2C address match and return the command type - /// + /// /// This method blocks until the slave address is matched by a master. /// Returns the command type (Read/Write) and the matched address. pub fn blocking_listen(&mut self) -> Result { @@ -874,7 +899,7 @@ impl<'d, M: Mode> I2c<'d, M, MultiMaster> { trace!("I2C slave: blocking listen complete, result={:?}", result); result } - + /// Respond to a master read request by transmitting data /// /// Sends the provided data to the master. If the master requests more bytes @@ -884,17 +909,17 @@ impl<'d, M: Mode> I2c<'d, M, MultiMaster> { /// Returns the total number of bytes transmitted (including padding). pub fn blocking_respond_to_read(&mut self, data: &[u8]) -> Result { trace!("I2C slave: starting blocking respond_to_read, data_len={}", data.len()); - + if let Some(zero_length_result) = self.detect_zero_length_read(self.timeout())? { trace!("I2C slave: zero-length read detected"); return Ok(zero_length_result); } - + let result = self.transmit_to_master(data, self.timeout()); trace!("I2C slave: blocking respond_to_read complete, result={:?}", result); result } - + /// Respond to a master write request by receiving data /// /// Receives data from the master into the provided buffer. If the master @@ -903,23 +928,26 @@ impl<'d, M: Mode> I2c<'d, M, MultiMaster> { /// /// Returns the number of bytes stored in the buffer (not total received). pub fn blocking_respond_to_write(&mut self, buffer: &mut [u8]) -> Result { - trace!("I2C slave: starting blocking respond_to_write, buffer_len={}", buffer.len()); + trace!( + "I2C slave: starting blocking respond_to_write, buffer_len={}", + buffer.len() + ); let result = self.receive_from_master(buffer, self.timeout()); trace!("I2C slave: blocking respond_to_write complete, result={:?}", result); result } - + // Private implementation methods - + /// Wait for address match and determine transaction type fn blocking_listen_with_timeout(&mut self, timeout: Timeout) -> Result { // Ensure interrupts are disabled for blocking operation self.disable_i2c_interrupts(); - + // Wait for address match (ADDR flag) loop { let sr1 = Self::read_status_and_handle_errors(self.info)?; - + if sr1.addr() { // Address matched - read SR2 to get direction and clear ADDR flag let sr2 = self.info.regs.sr2().read(); @@ -928,26 +956,30 @@ impl<'d, M: Mode> I2c<'d, M, MultiMaster> { } else { SlaveCommandKind::Write }; - + // Use the static method instead of the instance method let matched_address = Self::decode_matched_address(sr2, self.info)?; - trace!("I2C slave: address matched, direction={:?}, addr={:?}", direction, matched_address); - + trace!( + "I2C slave: address matched, direction={:?}, addr={:?}", + direction, + matched_address + ); + return Ok(SlaveCommand { kind: direction, address: matched_address, }); } - + timeout.check()?; } } - + /// Transmit data to master in response to read request fn transmit_to_master(&mut self, data: &[u8], timeout: Timeout) -> Result { let mut bytes_transmitted = 0; let mut padding_count = 0; - + loop { let byte_to_send = if bytes_transmitted < data.len() { data[bytes_transmitted] @@ -955,217 +987,221 @@ impl<'d, M: Mode> I2c<'d, M, MultiMaster> { padding_count += 1; 0x00 // Send padding bytes when data is exhausted }; - + match self.transmit_byte(byte_to_send, timeout)? { TransmitResult::Acknowledged => { bytes_transmitted += 1; - }, + } TransmitResult::NotAcknowledged => { bytes_transmitted += 1; // Count the NACKed byte break; - }, + } TransmitResult::Stopped | TransmitResult::Restarted => { break; } } } - + if padding_count > 0 { - trace!("I2C slave: sent {} data bytes + {} padding bytes = {} total", - data.len(), padding_count, bytes_transmitted); + trace!( + "I2C slave: sent {} data bytes + {} padding bytes = {} total", + data.len(), + padding_count, + bytes_transmitted + ); } - + Ok(bytes_transmitted) } - + /// Receive data from master during write request fn receive_from_master(&mut self, buffer: &mut [u8], timeout: Timeout) -> Result { let mut bytes_stored = 0; - + // Receive bytes that fit in buffer while bytes_stored < buffer.len() { match self.receive_byte(timeout)? { ReceiveResult::Data(byte) => { buffer[bytes_stored] = byte; bytes_stored += 1; - }, + } ReceiveResult::Stopped | ReceiveResult::Restarted => { return Ok(bytes_stored); - }, + } } } - + // Handle buffer overflow by discarding excess bytes if bytes_stored == buffer.len() { trace!("I2C slave: buffer full, discarding excess bytes"); self.discard_excess_bytes(timeout)?; } - + Ok(bytes_stored) } /// Detect zero-length read pattern early - /// + /// /// Zero-length reads occur when a master sends START+ADDR+R followed immediately /// by NACK+STOP without wanting any data. This must be detected before attempting /// to transmit any bytes to avoid SDA line issues. fn detect_zero_length_read(&mut self, _timeout: Timeout) -> Result, Error> { // Quick check for immediate termination signals let sr1 = self.info.regs.sr1().read(); - + // Check for immediate NACK (fastest zero-length pattern) if sr1.af() { self.clear_acknowledge_failure(); return Ok(Some(0)); } - + // Check for immediate STOP (alternative zero-length pattern) if sr1.stopf() { Self::clear_stop_flag(self.info); return Ok(Some(0)); } - + // Give a brief window for master to send termination signals // This handles masters that have slight delays between address ACK and NACK const ZERO_LENGTH_DETECTION_CYCLES: u32 = 20; // ~5-10µs window - + for _ in 0..ZERO_LENGTH_DETECTION_CYCLES { let sr1 = self.info.regs.sr1().read(); - + // Immediate NACK indicates zero-length read if sr1.af() { self.clear_acknowledge_failure(); return Ok(Some(0)); } - + // Immediate STOP indicates zero-length read if sr1.stopf() { Self::clear_stop_flag(self.info); return Ok(Some(0)); } - + // If TXE becomes ready, master is waiting for data - not zero-length if sr1.txe() { return Ok(None); // Proceed with normal transmission } - + // If RESTART detected, handle as zero-length if sr1.addr() { return Ok(Some(0)); } } - + // No zero-length pattern detected within the window Ok(None) } - + /// Discard excess bytes when buffer is full fn discard_excess_bytes(&mut self, timeout: Timeout) -> Result<(), Error> { let mut discarded_count = 0; - + loop { match self.receive_byte(timeout)? { ReceiveResult::Data(_) => { discarded_count += 1; continue; - }, + } ReceiveResult::Stopped | ReceiveResult::Restarted => { if discarded_count > 0 { trace!("I2C slave: discarded {} excess bytes", discarded_count); } break; - }, + } } } Ok(()) } - + /// Send a single byte and wait for master's response fn transmit_byte(&mut self, byte: u8, timeout: Timeout) -> Result { // Wait for transmit buffer ready self.wait_for_transmit_ready(timeout)?; - + // Send the byte self.info.regs.dr().write(|w| w.set_dr(byte)); - + // Wait for transmission completion or master response self.wait_for_transmit_completion(timeout) } - + /// Wait until transmit buffer is ready (TXE flag set) fn wait_for_transmit_ready(&mut self, timeout: Timeout) -> Result<(), Error> { loop { let sr1 = Self::read_status_and_handle_errors(self.info)?; - + // Check for early termination conditions if let Some(result) = Self::check_early_termination(sr1) { return Err(self.handle_early_termination(result)); } - + if sr1.txe() { return Ok(()); // Ready to transmit } - + timeout.check()?; } } - + /// Wait for byte transmission completion or master response fn wait_for_transmit_completion(&mut self, timeout: Timeout) -> Result { loop { let sr1 = self.info.regs.sr1().read(); - + // Check flags in priority order if sr1.af() { self.clear_acknowledge_failure(); return Ok(TransmitResult::NotAcknowledged); } - + if sr1.btf() { return Ok(TransmitResult::Acknowledged); } - + if sr1.stopf() { Self::clear_stop_flag(self.info); return Ok(TransmitResult::Stopped); } - + if sr1.addr() { return Ok(TransmitResult::Restarted); } - + // Check for other error conditions self.check_for_hardware_errors(sr1)?; - + timeout.check()?; } } - + /// Receive a single byte or detect transaction termination fn receive_byte(&mut self, timeout: Timeout) -> Result { loop { let sr1 = Self::read_status_and_handle_errors(self.info)?; - + // Check for received data first (prioritize data over control signals) if sr1.rxne() { let byte = self.info.regs.dr().read().dr(); return Ok(ReceiveResult::Data(byte)); } - + // Check for transaction termination if sr1.addr() { return Ok(ReceiveResult::Restarted); } - + if sr1.stopf() { Self::clear_stop_flag(self.info); return Ok(ReceiveResult::Stopped); } - + timeout.check()?; } } - + /// Determine which slave address was matched based on SR2 flags fn decode_matched_address(sr2: i2c::regs::Sr2, info: &'static Info) -> Result { if sr2.gencall() { @@ -1184,16 +1220,14 @@ impl<'d, M: Mode> I2c<'d, M, MultiMaster> { i2c::vals::Addmode::BIT7 => { let addr = (oar1.add() >> 1) as u8; Ok(Address::SevenBit(addr)) - }, - i2c::vals::Addmode::BIT10 => { - Ok(Address::TenBit(oar1.add())) - }, + } + i2c::vals::Addmode::BIT10 => Ok(Address::TenBit(oar1.add())), } } } - + // Helper methods for hardware interaction - + /// Read status register and handle I2C errors (except NACK in slave mode) fn read_status_and_handle_errors(info: &'static Info) -> Result { match Self::check_and_clear_error_flags(info) { @@ -1201,11 +1235,11 @@ impl<'d, M: Mode> I2c<'d, M, MultiMaster> { Err(Error::Nack) => { // In slave mode, NACK is normal protocol behavior, not an error Ok(info.regs.sr1().read()) - }, + } Err(other_error) => Err(other_error), } } - + /// Check for conditions that cause early termination of operations fn check_early_termination(sr1: i2c::regs::Sr1) -> Option { if sr1.stopf() { @@ -1218,27 +1252,27 @@ impl<'d, M: Mode> I2c<'d, M, MultiMaster> { None } } - + /// Convert early termination to appropriate error fn handle_early_termination(&mut self, result: TransmitResult) -> Error { match result { TransmitResult::Stopped => { Self::clear_stop_flag(self.info); Error::Bus // Unexpected STOP during setup - }, + } TransmitResult::Restarted => { Error::Bus // Unexpected RESTART during setup - }, + } TransmitResult::NotAcknowledged => { self.clear_acknowledge_failure(); Error::Bus // Unexpected NACK during setup - }, + } TransmitResult::Acknowledged => { unreachable!() // This should never be passed to this function } } } - + /// Check for hardware-level I2C errors during transmission fn check_for_hardware_errors(&self, sr1: i2c::regs::Sr1) -> Result<(), Error> { if sr1.timeout() || sr1.ovr() || sr1.arlo() || sr1.berr() { @@ -1247,7 +1281,7 @@ impl<'d, M: Mode> I2c<'d, M, MultiMaster> { } Ok(()) } - + /// Disable I2C event and error interrupts for blocking operations fn disable_i2c_interrupts(&mut self) { self.info.regs.cr2().modify(|w| { @@ -1255,7 +1289,7 @@ impl<'d, M: Mode> I2c<'d, M, MultiMaster> { w.set_iterren(false); }); } - + /// Clear the acknowledge failure flag fn clear_acknowledge_failure(&mut self) { self.info.regs.sr1().write(|reg| { @@ -1268,11 +1302,11 @@ impl<'d, M: Mode> I2c<'d, M, MultiMaster> { fn setup_slave_dma_base(&mut self) { self.info.regs.cr2().modify(|w| { w.set_itbufen(false); // Always disable buffer interrupts when using DMA - w.set_dmaen(true); // Enable DMA requests - w.set_last(false); // LAST bit not used in slave mode for v1 hardware + w.set_dmaen(true); // Enable DMA requests + w.set_last(false); // LAST bit not used in slave mode for v1 hardware }); } - + /// Disable DMA and interrupts in a critical section fn disable_dma_and_interrupts(info: &'static Info) { critical_section::with(|_| { @@ -1301,7 +1335,7 @@ impl<'d, M: Mode> I2c<'d, M, MultiMaster> { impl<'d> I2c<'d, Async, MultiMaster> { /// Async listen for incoming I2C messages using interrupts - /// + /// /// Waits for a master to address this slave and returns the command type /// (Read/Write) and the matched address. This method will suspend until /// an address match occurs. @@ -1309,7 +1343,7 @@ impl<'d> I2c<'d, Async, MultiMaster> { trace!("I2C slave: starting async listen for address match"); let state = self.state; let info = self.info; - + Self::enable_interrupts(info); let on_drop = OnDrop::new(|| { @@ -1323,7 +1357,7 @@ impl<'d> I2c<'d, Async, MultiMaster> { Err(e) => { error!("I2C slave: error during listen: {:?}", e); Poll::Ready(Err(e)) - }, + } Ok(sr1) => { if sr1.addr() { let sr2 = info.regs.sr2().read(); @@ -1332,18 +1366,18 @@ impl<'d> I2c<'d, Async, MultiMaster> { } else { SlaveCommandKind::Write }; - + let matched_address = match Self::decode_matched_address(sr2, info) { Ok(addr) => { trace!("I2C slave: address matched, direction={:?}, addr={:?}", direction, addr); addr - }, + } Err(e) => { error!("I2C slave: failed to decode matched address: {:?}", e); return Poll::Ready(Err(e)); } }; - + Poll::Ready(Ok(SlaveCommand { kind: direction, address: matched_address, @@ -1354,7 +1388,8 @@ impl<'d> I2c<'d, Async, MultiMaster> { } } } - }).await; + }) + .await; drop(on_drop); trace!("I2C slave: listen complete, result={:?}", result); @@ -1362,15 +1397,15 @@ impl<'d> I2c<'d, Async, MultiMaster> { } /// Async respond to write command using RX DMA - /// + /// /// Receives data from the master into the provided buffer using DMA. /// If the master sends more bytes than the buffer can hold, excess bytes /// are acknowledged but discarded to prevent interrupt flooding. - /// + /// /// Returns the number of bytes stored in the buffer (not total received). pub async fn respond_to_write(&mut self, buffer: &mut [u8]) -> Result { trace!("I2C slave: starting respond_to_write, buffer_len={}", buffer.len()); - + if buffer.is_empty() { warn!("I2C slave: respond_to_write called with empty buffer"); return Err(Error::Overrun); @@ -1395,15 +1430,15 @@ impl<'d> I2c<'d, Async, MultiMaster> { } /// Async respond to read command using TX DMA - /// + /// /// Transmits data to the master using DMA. If the master requests more bytes /// than available in the data buffer, padding bytes (0x00) are sent until /// the master terminates the transaction with NACK, STOP, or RESTART. - /// + /// /// Returns the total number of bytes transmitted (data + padding). pub async fn respond_to_read(&mut self, data: &[u8]) -> Result { trace!("I2C slave: starting respond_to_read, data_len={}", data.len()); - + if data.is_empty() { warn!("I2C slave: respond_to_read called with empty data"); return Err(Error::Overrun); @@ -1431,17 +1466,18 @@ impl<'d> I2c<'d, Async, MultiMaster> { /// Execute complete slave receive transfer with excess byte handling async fn execute_slave_receive_transfer( - &mut self, - buffer: &mut [u8], - state: &'static State, - info: &'static Info + &mut self, + buffer: &mut [u8], + state: &'static State, + info: &'static Info, ) -> Result { let dma_transfer = unsafe { let src = info.regs.dr().as_ptr() as *mut u8; self.rx_dma.as_mut().unwrap().read(src, buffer, Default::default()) }; - let i2c_monitor = Self::create_termination_monitor(state, info, &[SlaveTermination::Stop, SlaveTermination::Restart]); + let i2c_monitor = + Self::create_termination_monitor(state, info, &[SlaveTermination::Stop, SlaveTermination::Restart]); match select(dma_transfer, i2c_monitor).await { Either::Second(Err(e)) => { @@ -1465,17 +1501,25 @@ impl<'d> I2c<'d, Async, MultiMaster> { /// Execute complete slave transmit transfer with padding byte handling async fn execute_slave_transmit_transfer( - &mut self, - data: &[u8], - state: &'static State, - info: &'static Info + &mut self, + data: &[u8], + state: &'static State, + info: &'static Info, ) -> Result { let dma_transfer = unsafe { let dst = info.regs.dr().as_ptr() as *mut u8; self.tx_dma.as_mut().unwrap().write(data, dst, Default::default()) }; - let i2c_monitor = Self::create_termination_monitor(state, info, &[SlaveTermination::Stop, SlaveTermination::Restart, SlaveTermination::Nack]); + let i2c_monitor = Self::create_termination_monitor( + state, + info, + &[ + SlaveTermination::Stop, + SlaveTermination::Restart, + SlaveTermination::Nack, + ], + ); match select(dma_transfer, i2c_monitor).await { Either::Second(Err(e)) => { @@ -1488,8 +1532,12 @@ impl<'d> I2c<'d, Async, MultiMaster> { Self::disable_dma_and_interrupts(info); let padding_count = self.handle_padding_bytes(state, info).await?; let total_bytes = data.len() + padding_count; - trace!("I2C slave: sent {} data bytes + {} padding bytes = {} total", - data.len(), padding_count, total_bytes); + trace!( + "I2C slave: sent {} data bytes + {} padding bytes = {} total", + data.len(), + padding_count, + total_bytes + ); Ok(total_bytes) } Either::Second(Ok(termination)) => { @@ -1508,7 +1556,7 @@ impl<'d> I2c<'d, Async, MultiMaster> { ) -> impl Future> { poll_fn(move |cx| { state.waker.register(cx.waker()); - + match Self::check_and_clear_error_flags(info) { Err(Error::Nack) if allowed_terminations.contains(&SlaveTermination::Nack) => { Poll::Ready(Ok(SlaveTermination::Nack)) @@ -1545,24 +1593,24 @@ impl<'d> I2c<'d, Async, MultiMaster> { } /// Handle excess bytes after DMA buffer is full - /// + /// /// Reads and discards bytes until transaction termination to prevent interrupt flooding async fn handle_excess_bytes(&mut self, state: &'static State, info: &'static Info) -> Result<(), Error> { let mut discarded_count = 0; - + poll_fn(|cx| { state.waker.register(cx.waker()); - + match Self::check_and_clear_error_flags(info) { Err(e) => { error!("I2C slave: error while discarding excess bytes: {:?}", e); Poll::Ready(Err(e)) - }, + } Ok(sr1) => { if let Some(termination) = Self::check_slave_termination_conditions(sr1) { match termination { SlaveTermination::Stop => Self::clear_stop_flag(info), - SlaveTermination::Restart => {}, + SlaveTermination::Restart => {} SlaveTermination::Nack => unreachable!("NACK not expected during receive"), } if discarded_count > 0 { @@ -1570,41 +1618,42 @@ impl<'d> I2c<'d, Async, MultiMaster> { } return Poll::Ready(Ok(())); } - + if sr1.rxne() { let _discarded_byte = info.regs.dr().read().dr(); discarded_count += 1; Self::enable_interrupts(info); return Poll::Pending; } - + Self::enable_interrupts(info); Poll::Pending } } - }).await + }) + .await } /// Handle padding bytes after DMA data is exhausted - /// + /// /// Sends 0x00 bytes until transaction termination to prevent interrupt flooding async fn handle_padding_bytes(&mut self, state: &'static State, info: &'static Info) -> Result { let mut padding_count = 0; poll_fn(|cx| { state.waker.register(cx.waker()); - + match Self::check_and_clear_error_flags(info) { Err(Error::Nack) => Poll::Ready(Ok(padding_count)), Err(e) => { error!("I2C slave: error while sending padding bytes: {:?}", e); Poll::Ready(Err(e)) - }, + } Ok(sr1) => { if let Some(termination) = Self::check_slave_termination_conditions(sr1) { match termination { SlaveTermination::Stop => Self::clear_stop_flag(info), - SlaveTermination::Restart => {}, + SlaveTermination::Restart => {} SlaveTermination::Nack => { info.regs.sr1().write(|reg| { reg.0 = !0; @@ -1614,33 +1663,34 @@ impl<'d> I2c<'d, Async, MultiMaster> { } return Poll::Ready(Ok(padding_count)); } - + if sr1.txe() { info.regs.dr().write(|w| w.set_dr(0x00)); padding_count += 1; Self::enable_interrupts(info); return Poll::Pending; } - + Self::enable_interrupts(info); Poll::Pending } } - }).await + }) + .await } } /// Timing configuration for I2C v1 hardware -/// -/// This struct encapsulates the complex timing calculations required for STM32 I2C v1 -/// peripherals, which use three separate registers (CR2.FREQ, CCR, TRISE) instead of +/// +/// This struct encapsulates the complex timing calculations required for STM32 I2C v1 +/// peripherals, which use three separate registers (CR2.FREQ, CCR, TRISE) instead of /// the unified TIMINGR register found in v2 hardware. struct Timings { - freq: u8, // APB frequency in MHz for CR2.FREQ register - f_s: i2c::vals::FS, // Standard or Fast mode selection - trise: u8, // Rise time compensation value - ccr: u16, // Clock control register value - duty: i2c::vals::Duty, // Fast mode duty cycle selection + freq: u8, // APB frequency in MHz for CR2.FREQ register + f_s: i2c::vals::FS, // Standard or Fast mode selection + trise: u8, // Rise time compensation value + ccr: u16, // Clock control register value + duty: i2c::vals::Duty, // Fast mode duty cycle selection } impl Timings { -- cgit From 944ac0bf138ab78f602627fae97891024c8fd082 Mon Sep 17 00:00:00 2001 From: HybridChild Date: Sat, 23 Aug 2025 10:50:05 +0200 Subject: Run cargo fmt for examples --- examples/stm32f4/src/bin/i2c_slave_async.rs | 44 ++++++++++++++------------ examples/stm32f4/src/bin/i2c_slave_blocking.rs | 41 +++++++++++++----------- 2 files changed, 47 insertions(+), 38 deletions(-) diff --git a/examples/stm32f4/src/bin/i2c_slave_async.rs b/examples/stm32f4/src/bin/i2c_slave_async.rs index 072c9875e..c0719af5e 100644 --- a/examples/stm32f4/src/bin/i2c_slave_async.rs +++ b/examples/stm32f4/src/bin/i2c_slave_async.rs @@ -1,5 +1,5 @@ //! I2C slave example using async operations with DMA -//! +//! //! This example demonstrates DMA-accelerated I2C slave operations, //! which provide better performance and lower CPU overhead for //! high-frequency I2C transactions. @@ -7,12 +7,12 @@ #![no_std] #![no_main] -use defmt_rtt as _; use defmt::{error, info}; +use defmt_rtt as _; use embassy_executor::Spawner; -use embassy_stm32::{bind_interrupts, peripherals}; -use embassy_stm32::i2c::{self, I2c, SlaveAddrConfig, SlaveCommand, SlaveCommandKind, Address}; +use embassy_stm32::i2c::{self, Address, I2c, SlaveAddrConfig, SlaveCommand, SlaveCommandKind}; use embassy_stm32::time::Hertz; +use embassy_stm32::{bind_interrupts, peripherals}; use embassy_sync::blocking_mutex::raw::ThreadModeRawMutex; use embassy_sync::mutex::Mutex; use embassy_time::{Duration, Timer}; @@ -30,38 +30,39 @@ bind_interrupts!(struct Irqs { #[embassy_executor::main] async fn main(spawner: Spawner) { let p = embassy_stm32::init(Default::default()); - + // Configure I2C let mut i2c_config = i2c::Config::default(); i2c_config.sda_pullup = false; i2c_config.scl_pullup = false; i2c_config.frequency = Hertz(100_000); // 100kHz I2C speed - + // Initialize I2C as master first let i2c_master = I2c::new( - p.I2C1, - p.PB8, // SCL - p.PB9, // SDA - Irqs, - p.DMA1_CH6, // TX DMA + p.I2C1, p.PB8, // SCL + p.PB9, // SDA + Irqs, p.DMA1_CH6, // TX DMA p.DMA1_CH0, // RX DMA i2c_config, ); - + // Convert to MultiMaster mode let slave_config = SlaveAddrConfig::basic(I2C_SLAVE_ADDR); let i2c_slave = i2c_master.into_slave_multimaster(slave_config); - + spawner.spawn(i2c_slave_task(i2c_slave)).unwrap(); } #[embassy_executor::task] pub async fn i2c_slave_task(mut i2c_slave: I2c<'static, embassy_stm32::mode::Async, i2c::mode::MultiMaster>) { info!("Async I2C slave ready at address 0x{:02X}", I2C_SLAVE_ADDR); - + loop { match i2c_slave.listen().await { - Ok(SlaveCommand { kind: SlaveCommandKind::Write, address }) => { + Ok(SlaveCommand { + kind: SlaveCommandKind::Write, + address, + }) => { let addr_val = match address { Address::SevenBit(addr) => addr, Address::TenBit(addr) => (addr & 0xFF) as u8, @@ -70,7 +71,7 @@ pub async fn i2c_slave_task(mut i2c_slave: I2c<'static, embassy_stm32::mode::Asy info!("I2C: Received write command - Address 0x{:02X}", addr_val); let mut data_buffer = I2C_BUFFER.lock().await; - + match i2c_slave.respond_to_write(&mut *data_buffer).await { Ok(_) => { info!("I2C: Data received - Buffer now contains: 0x{:02X}, 0x{:02X}, 0x{:02X}, 0x{:02X}, 0x{:02X}, 0x{:02X}, 0x{:02X}, 0x{:02X}", @@ -81,8 +82,11 @@ pub async fn i2c_slave_task(mut i2c_slave: I2c<'static, embassy_stm32::mode::Asy } } } - - Ok(SlaveCommand { kind: SlaveCommandKind::Read, address }) => { + + Ok(SlaveCommand { + kind: SlaveCommandKind::Read, + address, + }) => { let addr_val = match address { Address::SevenBit(addr) => addr, Address::TenBit(addr) => (addr & 0xFF) as u8, // Show low byte for 10-bit @@ -91,7 +95,7 @@ pub async fn i2c_slave_task(mut i2c_slave: I2c<'static, embassy_stm32::mode::Asy info!("I2C: Received read command - Address 0x{:02X}", addr_val); let data_buffer = I2C_BUFFER.lock().await; - + match i2c_slave.respond_to_read(&data_buffer[..BUFFER_SIZE]).await { Ok(_) => { info!("I2C: Responded to read command"); @@ -101,7 +105,7 @@ pub async fn i2c_slave_task(mut i2c_slave: I2c<'static, embassy_stm32::mode::Asy } } } - + Err(e) => { error!("I2C: Listen error: {}", format_i2c_error(&e)); Timer::after(Duration::from_millis(100)).await; diff --git a/examples/stm32f4/src/bin/i2c_slave_blocking.rs b/examples/stm32f4/src/bin/i2c_slave_blocking.rs index c55f2f6c1..e027cd511 100644 --- a/examples/stm32f4/src/bin/i2c_slave_blocking.rs +++ b/examples/stm32f4/src/bin/i2c_slave_blocking.rs @@ -1,17 +1,17 @@ //! Complete I2C slave example using blocking operations -//! +//! //! This example shows how to set up an STM32F4 as an I2C slave device //! that can handle both read and write transactions from master devices. #![no_std] #![no_main] -use defmt_rtt as _; use defmt::{error, info}; +use defmt_rtt as _; use embassy_executor::Spawner; -use embassy_stm32::i2c::{self, I2c, SlaveAddrConfig, SlaveCommand, SlaveCommandKind, Address}; -use embassy_stm32::{bind_interrupts, peripherals}; +use embassy_stm32::i2c::{self, Address, I2c, SlaveAddrConfig, SlaveCommand, SlaveCommandKind}; use embassy_stm32::time::Hertz; +use embassy_stm32::{bind_interrupts, peripherals}; use embassy_sync::blocking_mutex::raw::ThreadModeRawMutex; use embassy_sync::mutex::Mutex; use embassy_time::{Duration, Timer}; @@ -29,36 +29,38 @@ bind_interrupts!(struct Irqs { #[embassy_executor::main] async fn main(spawner: Spawner) { let p = embassy_stm32::init(Default::default()); - + // Configure I2C let mut i2c_config = i2c::Config::default(); i2c_config.sda_pullup = false; i2c_config.scl_pullup = false; i2c_config.frequency = Hertz(100_000); i2c_config.timeout = embassy_time::Duration::from_millis(30000); - + // Initialize I2C as master first let i2c_master = I2c::new_blocking( - p.I2C1, - p.PB8, // SCL - p.PB9, // SDA + p.I2C1, p.PB8, // SCL + p.PB9, // SDA i2c_config, ); - + // Convert to slave+master mode let slave_config = SlaveAddrConfig::basic(I2C_SLAVE_ADDR); let i2c_slave = i2c_master.into_slave_multimaster(slave_config); - + spawner.spawn(i2c_slave_task(i2c_slave)).unwrap(); } #[embassy_executor::task] pub async fn i2c_slave_task(mut i2c_slave: I2c<'static, embassy_stm32::mode::Blocking, i2c::mode::MultiMaster>) { info!("Blocking I2C slave ready at address 0x{:02X}", I2C_SLAVE_ADDR); - + loop { match i2c_slave.blocking_listen() { - Ok(SlaveCommand { kind: SlaveCommandKind::Write, address }) => { + Ok(SlaveCommand { + kind: SlaveCommandKind::Write, + address, + }) => { let addr_val = match address { Address::SevenBit(addr) => addr, Address::TenBit(addr) => (addr & 0xFF) as u8, @@ -66,7 +68,7 @@ pub async fn i2c_slave_task(mut i2c_slave: I2c<'static, embassy_stm32::mode::Blo info!("I2C: Received write command - Address 0x{:02X}", addr_val); let mut data_buffer = I2C_BUFFER.lock().await; - + match i2c_slave.blocking_respond_to_write(&mut *data_buffer) { Ok(bytes_received) => { info!("I2C: Received {} bytes - Buffer now contains: 0x{:02X}, 0x{:02X}, 0x{:02X}, 0x{:02X}, 0x{:02X}, 0x{:02X}, 0x{:02X}, 0x{:02X}", @@ -77,8 +79,11 @@ pub async fn i2c_slave_task(mut i2c_slave: I2c<'static, embassy_stm32::mode::Blo } } } - - Ok(SlaveCommand { kind: SlaveCommandKind::Read, address }) => { + + Ok(SlaveCommand { + kind: SlaveCommandKind::Read, + address, + }) => { let addr_val = match address { Address::SevenBit(addr) => addr, Address::TenBit(addr) => (addr & 0xFF) as u8, // Show low byte for 10-bit @@ -86,7 +91,7 @@ pub async fn i2c_slave_task(mut i2c_slave: I2c<'static, embassy_stm32::mode::Blo info!("I2C: Received read command - Address 0x{:02X}", addr_val); let data_buffer = I2C_BUFFER.lock().await; - + match i2c_slave.blocking_respond_to_read(&data_buffer[..BUFFER_SIZE]) { Ok(bytes_sent) => { info!("I2C: Responded to read - {} bytes sent", bytes_sent); @@ -96,7 +101,7 @@ pub async fn i2c_slave_task(mut i2c_slave: I2c<'static, embassy_stm32::mode::Blo } } } - + Err(e) => { error!("I2C: Listen error: {}", format_i2c_error(&e)); Timer::after(Duration::from_millis(100)).await; -- cgit From 524db5a935e506036c282e3c0dfa9abc807ac7ee Mon Sep 17 00:00:00 2001 From: HybridChild Date: Sat, 23 Aug 2025 10:53:22 +0200 Subject: Fix formatting in examples --- examples/stm32f4/src/bin/i2c_slave_async.rs | 3 +-- examples/stm32f4/src/bin/i2c_slave_blocking.rs | 3 +-- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/examples/stm32f4/src/bin/i2c_slave_async.rs b/examples/stm32f4/src/bin/i2c_slave_async.rs index c0719af5e..1c48f1ac7 100644 --- a/examples/stm32f4/src/bin/i2c_slave_async.rs +++ b/examples/stm32f4/src/bin/i2c_slave_async.rs @@ -8,7 +8,7 @@ #![no_main] use defmt::{error, info}; -use defmt_rtt as _; +use {defmt_rtt as _, panic_probe as _}; use embassy_executor::Spawner; use embassy_stm32::i2c::{self, Address, I2c, SlaveAddrConfig, SlaveCommand, SlaveCommandKind}; use embassy_stm32::time::Hertz; @@ -16,7 +16,6 @@ use embassy_stm32::{bind_interrupts, peripherals}; use embassy_sync::blocking_mutex::raw::ThreadModeRawMutex; use embassy_sync::mutex::Mutex; use embassy_time::{Duration, Timer}; -use panic_probe as _; pub const I2C_SLAVE_ADDR: u8 = 0x42; pub const BUFFER_SIZE: usize = 8; diff --git a/examples/stm32f4/src/bin/i2c_slave_blocking.rs b/examples/stm32f4/src/bin/i2c_slave_blocking.rs index e027cd511..a6f4da747 100644 --- a/examples/stm32f4/src/bin/i2c_slave_blocking.rs +++ b/examples/stm32f4/src/bin/i2c_slave_blocking.rs @@ -7,7 +7,7 @@ #![no_main] use defmt::{error, info}; -use defmt_rtt as _; +use {defmt_rtt as _, panic_probe as _}; use embassy_executor::Spawner; use embassy_stm32::i2c::{self, Address, I2c, SlaveAddrConfig, SlaveCommand, SlaveCommandKind}; use embassy_stm32::time::Hertz; @@ -15,7 +15,6 @@ use embassy_stm32::{bind_interrupts, peripherals}; use embassy_sync::blocking_mutex::raw::ThreadModeRawMutex; use embassy_sync::mutex::Mutex; use embassy_time::{Duration, Timer}; -use panic_probe as _; pub const I2C_SLAVE_ADDR: u8 = 0x42; pub const BUFFER_SIZE: usize = 8; -- cgit From 3c8d078525c69867710bbd291dc135b3a5011702 Mon Sep 17 00:00:00 2001 From: HybridChild Date: Sat, 23 Aug 2025 10:55:00 +0200 Subject: Fix formatting in examples --- examples/stm32f4/src/bin/i2c_slave_async.rs | 2 +- examples/stm32f4/src/bin/i2c_slave_blocking.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/examples/stm32f4/src/bin/i2c_slave_async.rs b/examples/stm32f4/src/bin/i2c_slave_async.rs index 1c48f1ac7..db4a805b6 100644 --- a/examples/stm32f4/src/bin/i2c_slave_async.rs +++ b/examples/stm32f4/src/bin/i2c_slave_async.rs @@ -8,7 +8,6 @@ #![no_main] use defmt::{error, info}; -use {defmt_rtt as _, panic_probe as _}; use embassy_executor::Spawner; use embassy_stm32::i2c::{self, Address, I2c, SlaveAddrConfig, SlaveCommand, SlaveCommandKind}; use embassy_stm32::time::Hertz; @@ -16,6 +15,7 @@ use embassy_stm32::{bind_interrupts, peripherals}; use embassy_sync::blocking_mutex::raw::ThreadModeRawMutex; use embassy_sync::mutex::Mutex; use embassy_time::{Duration, Timer}; +use {defmt_rtt as _, panic_probe as _}; pub const I2C_SLAVE_ADDR: u8 = 0x42; pub const BUFFER_SIZE: usize = 8; diff --git a/examples/stm32f4/src/bin/i2c_slave_blocking.rs b/examples/stm32f4/src/bin/i2c_slave_blocking.rs index a6f4da747..a62087a29 100644 --- a/examples/stm32f4/src/bin/i2c_slave_blocking.rs +++ b/examples/stm32f4/src/bin/i2c_slave_blocking.rs @@ -7,7 +7,6 @@ #![no_main] use defmt::{error, info}; -use {defmt_rtt as _, panic_probe as _}; use embassy_executor::Spawner; use embassy_stm32::i2c::{self, Address, I2c, SlaveAddrConfig, SlaveCommand, SlaveCommandKind}; use embassy_stm32::time::Hertz; @@ -15,6 +14,7 @@ use embassy_stm32::{bind_interrupts, peripherals}; use embassy_sync::blocking_mutex::raw::ThreadModeRawMutex; use embassy_sync::mutex::Mutex; use embassy_time::{Duration, Timer}; +use {defmt_rtt as _, panic_probe as _}; pub const I2C_SLAVE_ADDR: u8 = 0x42; pub const BUFFER_SIZE: usize = 8; -- cgit From 14a047a9ad75709e0bde8b0fa71f3b4bddedc576 Mon Sep 17 00:00:00 2001 From: maor malka Date: Sun, 24 Aug 2025 21:36:33 -0400 Subject: stm32/adc/v3: added support for DMA based adc sampling --- embassy-stm32/src/adc/v3.rs | 274 +++++++++++++++++++++++++++++++++++- examples/stm32l4/src/bin/adc_dma.rs | 49 +++++++ 2 files changed, 322 insertions(+), 1 deletion(-) create mode 100644 examples/stm32l4/src/bin/adc_dma.rs diff --git a/embassy-stm32/src/adc/v3.rs b/embassy-stm32/src/adc/v3.rs index a2e42fe52..6d874dbba 100644 --- a/embassy-stm32/src/adc/v3.rs +++ b/embassy-stm32/src/adc/v3.rs @@ -3,10 +3,13 @@ use pac::adc::vals::Dmacfg; #[cfg(adc_v3)] use pac::adc::vals::{OversamplingRatio, OversamplingShift, Rovsm, Trovs}; +use core::marker::PhantomData; +use core::sync::atomic::{compiler_fence, Ordering}; + use super::{ blocking_delay_us, Adc, AdcChannel, AnyAdcChannel, Instance, Resolution, RxDma, SampleTime, SealedAdcChannel, }; -use crate::dma::Transfer; +use crate::dma::{ReadableRingBuffer, Transfer, TransferOptions}; use crate::{pac, rcc, Peri}; /// Default VREF voltage used for sample conversion to millivolts. @@ -107,6 +110,15 @@ pub enum Averaging { Samples128, Samples256, } + +#[cfg_attr(feature = "defmt", derive(defmt::Format))] +pub struct OverrunError; + +pub struct RingBufferedAdc<'d, T: Instance> { + _phantom: PhantomData, + ring_buf: ReadableRingBuffer<'d, u16>, +} + impl<'d, T: Instance> Adc<'d, T> { pub fn new(adc: Peri<'d, T>) -> Self { rcc::enable_and_reset::(); @@ -449,6 +461,122 @@ impl<'d, T: Instance> Adc<'d, T> { }); } + /// Configures the ADC to use a DMA ring buffer for continuous data acquisition. + /// + /// The `dma_buf` should be large enough to prevent DMA buffer overrun. + /// The length of the `dma_buf` should be a multiple of the ADC channel count. + /// For example, if 3 channels are measured, its length can be 3 * 40 = 120 measurements. + /// + /// `read` method is used to read out measurements from the DMA ring buffer, and its buffer should be exactly half of the `dma_buf` length. + /// It is critical to call `read` frequently to prevent DMA buffer overrun. + /// + /// [`read`]: #method.read + pub fn into_ring_buffered<'a>( + &mut self, + dma: Peri<'a, impl RxDma>, + dma_buf: &'a mut [u16], + sequence: impl ExactSizeIterator, SampleTime)>, + ) -> RingBufferedAdc<'a, T> { + assert!(!dma_buf.is_empty() && dma_buf.len() <= 0xFFFF); + assert!(sequence.len() != 0, "Asynchronous read sequence cannot be empty"); + assert!( + sequence.len() <= 16, + "Asynchronous read sequence cannot be more than 16 in length" + ); + // reset conversions and enable the adc + Self::cancel_conversions(); + self.enable(); + + //adc side setup + + // Set sequence length + #[cfg(not(any(adc_g0, adc_u0)))] + T::regs().sqr1().modify(|w| { + w.set_l(sequence.len() as u8 - 1); + }); + + #[cfg(any(adc_g0, adc_u0))] + let mut channel_mask = 0; + + // Configure channels and ranks + for (_i, (channel, sample_time)) in sequence.enumerate() { + Self::configure_channel(channel, sample_time); + + // Each channel is sampled according to sequence + #[cfg(not(any(adc_g0, adc_u0)))] + match _i { + 0..=3 => { + T::regs().sqr1().modify(|w| { + w.set_sq(_i, channel.channel()); + }); + } + 4..=8 => { + T::regs().sqr2().modify(|w| { + w.set_sq(_i - 4, channel.channel()); + }); + } + 9..=13 => { + T::regs().sqr3().modify(|w| { + w.set_sq(_i - 9, channel.channel()); + }); + } + 14..=15 => { + T::regs().sqr4().modify(|w| { + w.set_sq(_i - 14, channel.channel()); + }); + } + _ => unreachable!(), + } + } + + //dma side setup + let opts = TransferOptions { + half_transfer_ir: true, + circular: true, + ..Default::default() + }; + + // Safety: we forget the struct before this function returns. + let request = dma.request(); + + let ring_buf = + unsafe { ReadableRingBuffer::new(dma, request, T::regs().dr().as_ptr() as *mut u16, dma_buf, opts) }; + + // On G0 and U0 enabled channels are sampled from 0 to last channel. + // It is possible to add up to 8 sequences if CHSELRMOD = 1. + // However for supporting more than 8 channels alternative CHSELRMOD = 0 approach is used. + #[cfg(any(adc_g0, adc_u0))] + T::regs().chselr().modify(|reg| { + reg.set_chsel(channel_mask); + }); + + // Set continuous mode with Circular dma. + // Clear overrun flag before starting transfer. + T::regs().isr().modify(|reg| { + reg.set_ovr(true); + }); + + #[cfg(not(any(adc_g0, adc_u0)))] + T::regs().cfgr().modify(|reg| { + reg.set_discen(false); + reg.set_cont(true); + reg.set_dmacfg(Dmacfg::CIRCULAR); + reg.set_dmaen(true); + }); + #[cfg(any(adc_g0, adc_u0))] + T::regs().cfgr1().modify(|reg| { + reg.set_discen(false); + reg.set_cont(true); + reg.set_dmacfg(Dmacfg::CIRCULAR); + reg.set_dmaen(true); + }); + + RingBufferedAdc { + _phantom: PhantomData, + ring_buf, + } + } + fn configure_channel(channel: &mut impl AdcChannel, sample_time: SampleTime) { // RM0492, RM0481, etc. // "This option bit must be set to 1 when ADCx_INP0 or ADCx_INN1 channel is selected." @@ -553,3 +681,147 @@ impl<'d, T: Instance> Adc<'d, T> { } } } + +impl<'d, T: Instance> RingBufferedAdc<'d, T> { + #[inline] + fn start_continous_sampling(&mut self) { + // Start adc conversion + T::regs().cr().modify(|reg| { + reg.set_adstart(true); + }); + self.ring_buf.start(); + } + + #[inline] + pub fn stop_continous_sampling(&mut self) { + // Stop adc conversion + if T::regs().cr().read().adstart() && !T::regs().cr().read().addis() { + T::regs().cr().modify(|reg| { + reg.set_adstp(true); + }); + while T::regs().cr().read().adstart() {} + } + } + pub fn disable_adc(&mut self) { + self.stop_continous_sampling(); + self.ring_buf.clear(); + self.ring_buf.request_pause(); + } + + pub fn teardown_adc(&mut self) { + self.disable_adc(); + + //disable dma control + #[cfg(not(any(adc_g0, adc_u0)))] + T::regs().cfgr().modify(|reg| { + reg.set_dmaen(false); + }); + #[cfg(any(adc_g0, adc_u0))] + T::regs().cfgr1().modify(|reg| { + reg.set_dmaen(false); + }); + + //TODO: do we need to cleanup the DMA request here? + + compiler_fence(Ordering::SeqCst); + } + + /// Reads measurements from the DMA ring buffer. + /// + /// This method fills the provided `measurements` array with ADC readings from the DMA buffer. + /// The length of the `measurements` array should be exactly half of the DMA buffer length. Because interrupts are only generated if half or full DMA transfer completes. + /// + /// Each call to `read` will populate the `measurements` array in the same order as the channels defined with `sequence`. + /// There will be many sequences worth of measurements in this array because it only returns if at least half of the DMA buffer is filled. + /// For example if 2 channels are sampled `measurements` contain: `[sq0 sq1 sq0 sq1 sq0 sq1 ..]`. + /// + /// Note that the ADC Datarate can be very fast, it is suggested to use DMA mode inside tightly running tasks + /// Otherwise, you'll see constant Overrun errors occuring, this means that you're sampling too quickly for the task to handle, and you may need to increase the buffer size. + /// Example: + /// ```rust,ignore + /// const DMA_BUF_LEN: usize = 120; + /// use embassy_stm32::adc::{Adc, AdcChannel} + /// + /// let mut adc = Adc::new(p.ADC1); + /// let mut adc_pin0 = p.PA0.degrade_adc(); + /// let mut adc_pin1 = p.PA1.degrade_adc(); + /// let adc_dma_buf = [0u16; DMA_BUF_LEN]; + /// + /// let mut ring_buffered_adc: RingBufferedAdc = adc.into_ring_buffered( + /// p.DMA2_CH0, + /// adc_dma_buf, [ + /// (&mut *adc_pin0, SampleTime::CYCLES160_5), + /// (&mut *adc_pin1, SampleTime::CYCLES160_5), + /// ].into_iter()); + /// + /// + /// let mut measurements = [0u16; DMA_BUF_LEN / 2]; + /// loop { + /// match ring_buffered_adc.read(&mut measurements).await { + /// Ok(_) => { + /// defmt::info!("adc1: {}", measurements); + /// } + /// Err(e) => { + /// defmt::warn!("Error: {:?}", e); + /// } + /// } + /// } + /// ``` + /// + /// + /// [`teardown_adc`]: #method.teardown_adc + /// [`start_continous_sampling`]: #method.start_continous_sampling + pub async fn read(&mut self, measurements: &mut [u16]) -> Result { + assert_eq!( + self.ring_buf.capacity() / 2, + measurements.len(), + "Buffer size must be half the size of the ring buffer" + ); + + let r = T::regs(); + + // Start background receive if it was not already started + if !r.cr().read().adstart() { + self.start_continous_sampling(); + } + + self.ring_buf.read_exact(measurements).await.map_err(|_| OverrunError) + } + + /// Read bytes that are readily available in the ring buffer. + /// If no bytes are currently available in the buffer the call waits until the some + /// bytes are available (at least one byte and at most half the buffer size) + /// + /// Background receive is started if `start_continous_sampling()` has not been previously called. + /// + /// Receive in the background is terminated if an error is returned. + /// It must then manually be started again by calling `start_continous_sampling()` or by re-calling `blocking_read()`. + pub fn blocking_read(&mut self, buf: &mut [u16]) -> Result { + let r = T::regs(); + + // Start background receive if it was not already started + if !r.cr().read().adstart() { + self.start_continous_sampling(); + } + + loop { + match self.ring_buf.read(buf) { + Ok((0, _)) => {} + Ok((len, _)) => { + return Ok(len); + } + Err(_) => { + self.stop_continous_sampling(); + return Err(OverrunError); + } + } + } + } +} + +impl Drop for RingBufferedAdc<'_, T> { + fn drop(&mut self) { + self.teardown_adc(); + rcc::disable::(); + } +} diff --git a/examples/stm32l4/src/bin/adc_dma.rs b/examples/stm32l4/src/bin/adc_dma.rs new file mode 100644 index 000000000..1769c735a --- /dev/null +++ b/examples/stm32l4/src/bin/adc_dma.rs @@ -0,0 +1,49 @@ +#![no_std] +#![no_main] + +use defmt::*; +use embassy_executor::Spawner; +use embassy_stm32::adc::{Adc, AdcChannel, SampleTime}; +use embassy_stm32::Config; +use {defmt_rtt as _, panic_probe as _}; + +const DMA_BUF_LEN: usize = 512; + +#[embassy_executor::main] +async fn main(_spawner: Spawner) { + info!("Hello World!"); + + let config = Config::default(); + + let p = embassy_stm32::init(config); + + let mut adc = Adc::new(p.ADC1); + let mut adc_pin0 = p.PA0.degrade_adc(); + let mut adc_pin1 = p.PA1.degrade_adc(); + let mut adc_dma_buf = [0u16; DMA_BUF_LEN]; + let mut measurements = [0u16; DMA_BUF_LEN / 2]; + let mut ring_buffered_adc = adc.into_ring_buffered( + p.DMA1_CH1, + &mut adc_dma_buf, + [ + (&mut adc_pin0, SampleTime::CYCLES640_5), + (&mut adc_pin1, SampleTime::CYCLES640_5), + ] + .into_iter(), + ); + + info!("starting measurement loop"); + loop { + match ring_buffered_adc.read(&mut measurements).await { + Ok(_) => { + //note: originally there was a print here showing all the samples, + //but even that takes too much time and would cause adc overruns + info!("adc1 first 10 samples: {}",measurements[0..10]); + } + Err(e) => { + warn!("Error: {:?}", e); + } + } + } + +} -- cgit From 0b8da5ab8f6469bdf2adf7462e7ebedee93dde3f Mon Sep 17 00:00:00 2001 From: maor malka Date: Sun, 24 Aug 2025 21:42:30 -0400 Subject: stm32l4/example/adc_dma: missing clock configuration --- examples/stm32l4/src/bin/adc_dma.rs | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/examples/stm32l4/src/bin/adc_dma.rs b/examples/stm32l4/src/bin/adc_dma.rs index 1769c735a..a5b7b0c5e 100644 --- a/examples/stm32l4/src/bin/adc_dma.rs +++ b/examples/stm32l4/src/bin/adc_dma.rs @@ -13,8 +13,11 @@ const DMA_BUF_LEN: usize = 512; async fn main(_spawner: Spawner) { info!("Hello World!"); - let config = Config::default(); - + let mut config = Config::default(); + { + use embassy_stm32::rcc::*; + config.rcc.mux.adcsel = mux::Adcsel::SYS; + } let p = embassy_stm32::init(config); let mut adc = Adc::new(p.ADC1); @@ -36,14 +39,13 @@ async fn main(_spawner: Spawner) { loop { match ring_buffered_adc.read(&mut measurements).await { Ok(_) => { - //note: originally there was a print here showing all the samples, + //note: originally there was a print here showing all the samples, //but even that takes too much time and would cause adc overruns - info!("adc1 first 10 samples: {}",measurements[0..10]); + info!("adc1 first 10 samples: {}", measurements[0..10]); } Err(e) => { warn!("Error: {:?}", e); } } } - } -- cgit From 135070040688a4e5b50b84718526b630714d1a13 Mon Sep 17 00:00:00 2001 From: maor malka Date: Sun, 24 Aug 2025 21:53:19 -0400 Subject: stm32/adc/v3: build fix attempt --- embassy-stm32/src/adc/v3.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/embassy-stm32/src/adc/v3.rs b/embassy-stm32/src/adc/v3.rs index 6d874dbba..bc5b80ccd 100644 --- a/embassy-stm32/src/adc/v3.rs +++ b/embassy-stm32/src/adc/v3.rs @@ -9,6 +9,7 @@ use core::sync::atomic::{compiler_fence, Ordering}; use super::{ blocking_delay_us, Adc, AdcChannel, AnyAdcChannel, Instance, Resolution, RxDma, SampleTime, SealedAdcChannel, }; +#[cfg(adc_v3)] use crate::dma::{ReadableRingBuffer, Transfer, TransferOptions}; use crate::{pac, rcc, Peri}; -- cgit From e5d4ef42699859fbcbcee083842195c8d4f7b8b0 Mon Sep 17 00:00:00 2001 From: maor malka Date: Sun, 24 Aug 2025 22:00:08 -0400 Subject: stm32/adc/v3: build formatting fixes --- embassy-stm32/src/adc/v3.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/embassy-stm32/src/adc/v3.rs b/embassy-stm32/src/adc/v3.rs index bc5b80ccd..03864b171 100644 --- a/embassy-stm32/src/adc/v3.rs +++ b/embassy-stm32/src/adc/v3.rs @@ -1,11 +1,11 @@ +use core::marker::PhantomData; +use core::sync::atomic::{compiler_fence, Ordering}; + use cfg_if::cfg_if; use pac::adc::vals::Dmacfg; #[cfg(adc_v3)] use pac::adc::vals::{OversamplingRatio, OversamplingShift, Rovsm, Trovs}; -use core::marker::PhantomData; -use core::sync::atomic::{compiler_fence, Ordering}; - use super::{ blocking_delay_us, Adc, AdcChannel, AnyAdcChannel, Instance, Resolution, RxDma, SampleTime, SealedAdcChannel, }; -- cgit From 756ec7f1837a714f9c8304e2b2b21b542e0260d6 Mon Sep 17 00:00:00 2001 From: maor malka Date: Sun, 24 Aug 2025 22:04:15 -0400 Subject: stm32/adc/v3: updated changelog and cfg fence for DMA methods --- embassy-stm32/CHANGELOG.md | 1 + embassy-stm32/src/adc/v3.rs | 4 +++- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/embassy-stm32/CHANGELOG.md b/embassy-stm32/CHANGELOG.md index 9cd4d5951..90d38a425 100644 --- a/embassy-stm32/CHANGELOG.md +++ b/embassy-stm32/CHANGELOG.md @@ -14,6 +14,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - fix: Fix performing a hash after performing a hmac - chore: Updated stm32-metapac and stm32-data dependencies - fix: Fix XSPI not disabling alternate bytes when they were previously enabled +- feat: stm32/adc/v3: added support for Continous DMA configuration ## 0.3.0 - 2025-08-12 diff --git a/embassy-stm32/src/adc/v3.rs b/embassy-stm32/src/adc/v3.rs index 03864b171..8062fa169 100644 --- a/embassy-stm32/src/adc/v3.rs +++ b/embassy-stm32/src/adc/v3.rs @@ -471,7 +471,8 @@ impl<'d, T: Instance> Adc<'d, T> { /// `read` method is used to read out measurements from the DMA ring buffer, and its buffer should be exactly half of the `dma_buf` length. /// It is critical to call `read` frequently to prevent DMA buffer overrun. /// - /// [`read`]: #method.read + /// [`read`]: #method.read + #[cfg(adc_v3)] pub fn into_ring_buffered<'a>( &mut self, dma: Peri<'a, impl RxDma>, @@ -683,6 +684,7 @@ impl<'d, T: Instance> Adc<'d, T> { } } +#[cfg(adc_v3)] impl<'d, T: Instance> RingBufferedAdc<'d, T> { #[inline] fn start_continous_sampling(&mut self) { -- cgit From 75484f4f51847a92e2df1e8319debec61cd7aca2 Mon Sep 17 00:00:00 2001 From: maor malka Date: Sun, 24 Aug 2025 22:05:25 -0400 Subject: stm32/adc/v3: build formatting fixes --- embassy-stm32/src/adc/v3.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/embassy-stm32/src/adc/v3.rs b/embassy-stm32/src/adc/v3.rs index 8062fa169..a52141a34 100644 --- a/embassy-stm32/src/adc/v3.rs +++ b/embassy-stm32/src/adc/v3.rs @@ -471,7 +471,7 @@ impl<'d, T: Instance> Adc<'d, T> { /// `read` method is used to read out measurements from the DMA ring buffer, and its buffer should be exactly half of the `dma_buf` length. /// It is critical to call `read` frequently to prevent DMA buffer overrun. /// - /// [`read`]: #method.read + /// [`read`]: #method.read #[cfg(adc_v3)] pub fn into_ring_buffered<'a>( &mut self, -- cgit From 6b8d375813116fba0e04aa28e23ded8ab077729a Mon Sep 17 00:00:00 2001 From: maor malka Date: Tue, 26 Aug 2025 22:15:34 -0400 Subject: stm32/adc/v3: moved ringbuffered to seperate file --- embassy-stm32/src/adc/ringbuffered_v3.rs | 181 ++++++++++++++++++++++++++++++ embassy-stm32/src/adc/v3.rs | 182 ++----------------------------- 2 files changed, 189 insertions(+), 174 deletions(-) create mode 100644 embassy-stm32/src/adc/ringbuffered_v3.rs diff --git a/embassy-stm32/src/adc/ringbuffered_v3.rs b/embassy-stm32/src/adc/ringbuffered_v3.rs new file mode 100644 index 000000000..655ae712f --- /dev/null +++ b/embassy-stm32/src/adc/ringbuffered_v3.rs @@ -0,0 +1,181 @@ +use core::marker::PhantomData; +use core::sync::atomic::{compiler_fence, Ordering}; +use embassy_hal_internal::Peri; + +use crate::dma::{ReadableRingBuffer, TransferOptions}; + +use crate::adc::Instance; +use crate::adc::RxDma; +use crate::rcc; + +#[cfg_attr(feature = "defmt", derive(defmt::Format))] +pub struct OverrunError; + +pub struct RingBufferedAdc<'d, T: Instance> { + pub _phantom: PhantomData, + pub ring_buf: ReadableRingBuffer<'d, u16>, +} + +impl<'d, T: Instance> RingBufferedAdc<'d, T> { + pub fn new(dma: Peri<'d, impl RxDma>, dma_buf: &'d mut [u16]) -> Self { + //dma side setup + let opts = TransferOptions { + half_transfer_ir: true, + circular: true, + ..Default::default() + }; + + // Safety: we forget the struct before this function returns. + let request = dma.request(); + + let ring_buf = + unsafe { ReadableRingBuffer::new(dma, request, T::regs().dr().as_ptr() as *mut u16, dma_buf, opts) }; + + Self { + _phantom: PhantomData, + ring_buf, + } + } + + #[inline] + fn start_continous_sampling(&mut self) { + // Start adc conversion + T::regs().cr().modify(|reg| { + reg.set_adstart(true); + }); + self.ring_buf.start(); + } + + #[inline] + pub fn stop_continous_sampling(&mut self) { + // Stop adc conversion + if T::regs().cr().read().adstart() && !T::regs().cr().read().addis() { + T::regs().cr().modify(|reg| { + reg.set_adstp(true); + }); + while T::regs().cr().read().adstart() {} + } + } + pub fn disable_adc(&mut self) { + self.stop_continous_sampling(); + self.ring_buf.clear(); + self.ring_buf.request_pause(); + } + + pub fn teardown_adc(&mut self) { + self.disable_adc(); + + //disable dma control + #[cfg(not(any(adc_g0, adc_u0)))] + T::regs().cfgr().modify(|reg| { + reg.set_dmaen(false); + }); + #[cfg(any(adc_g0, adc_u0))] + T::regs().cfgr1().modify(|reg| { + reg.set_dmaen(false); + }); + + //TODO: do we need to cleanup the DMA request here? + + compiler_fence(Ordering::SeqCst); + } + + /// Reads measurements from the DMA ring buffer. + /// + /// This method fills the provided `measurements` array with ADC readings from the DMA buffer. + /// The length of the `measurements` array should be exactly half of the DMA buffer length. Because interrupts are only generated if half or full DMA transfer completes. + /// + /// Each call to `read` will populate the `measurements` array in the same order as the channels defined with `sequence`. + /// There will be many sequences worth of measurements in this array because it only returns if at least half of the DMA buffer is filled. + /// For example if 2 channels are sampled `measurements` contain: `[sq0 sq1 sq0 sq1 sq0 sq1 ..]`. + /// + /// Note that the ADC Datarate can be very fast, it is suggested to use DMA mode inside tightly running tasks + /// Otherwise, you'll see constant Overrun errors occuring, this means that you're sampling too quickly for the task to handle, and you may need to increase the buffer size. + /// Example: + /// ```rust,ignore + /// const DMA_BUF_LEN: usize = 120; + /// use embassy_stm32::adc::{Adc, AdcChannel} + /// + /// let mut adc = Adc::new(p.ADC1); + /// let mut adc_pin0 = p.PA0.degrade_adc(); + /// let mut adc_pin1 = p.PA1.degrade_adc(); + /// let adc_dma_buf = [0u16; DMA_BUF_LEN]; + /// + /// let mut ring_buffered_adc: RingBufferedAdc = adc.into_ring_buffered( + /// p.DMA2_CH0, + /// adc_dma_buf, [ + /// (&mut *adc_pin0, SampleTime::CYCLES160_5), + /// (&mut *adc_pin1, SampleTime::CYCLES160_5), + /// ].into_iter()); + /// + /// + /// let mut measurements = [0u16; DMA_BUF_LEN / 2]; + /// loop { + /// match ring_buffered_adc.read(&mut measurements).await { + /// Ok(_) => { + /// defmt::info!("adc1: {}", measurements); + /// } + /// Err(e) => { + /// defmt::warn!("Error: {:?}", e); + /// } + /// } + /// } + /// ``` + /// + /// + /// [`teardown_adc`]: #method.teardown_adc + /// [`start_continous_sampling`]: #method.start_continous_sampling + pub async fn read(&mut self, measurements: &mut [u16]) -> Result { + assert_eq!( + self.ring_buf.capacity() / 2, + measurements.len(), + "Buffer size must be half the size of the ring buffer" + ); + + let r = T::regs(); + + // Start background receive if it was not already started + if !r.cr().read().adstart() { + self.start_continous_sampling(); + } + + self.ring_buf.read_exact(measurements).await.map_err(|_| OverrunError) + } + + /// Read bytes that are readily available in the ring buffer. + /// If no bytes are currently available in the buffer the call waits until the some + /// bytes are available (at least one byte and at most half the buffer size) + /// + /// Background receive is started if `start_continous_sampling()` has not been previously called. + /// + /// Receive in the background is terminated if an error is returned. + /// It must then manually be started again by calling `start_continous_sampling()` or by re-calling `blocking_read()`. + pub fn blocking_read(&mut self, buf: &mut [u16]) -> Result { + let r = T::regs(); + + // Start background receive if it was not already started + if !r.cr().read().adstart() { + self.start_continous_sampling(); + } + + loop { + match self.ring_buf.read(buf) { + Ok((0, _)) => {} + Ok((len, _)) => { + return Ok(len); + } + Err(_) => { + self.stop_continous_sampling(); + return Err(OverrunError); + } + } + } + } +} + +impl Drop for RingBufferedAdc<'_, T> { + fn drop(&mut self) { + self.teardown_adc(); + rcc::disable::(); + } +} diff --git a/embassy-stm32/src/adc/v3.rs b/embassy-stm32/src/adc/v3.rs index a52141a34..30b04fc81 100644 --- a/embassy-stm32/src/adc/v3.rs +++ b/embassy-stm32/src/adc/v3.rs @@ -1,6 +1,3 @@ -use core::marker::PhantomData; -use core::sync::atomic::{compiler_fence, Ordering}; - use cfg_if::cfg_if; use pac::adc::vals::Dmacfg; #[cfg(adc_v3)] @@ -9,8 +6,14 @@ use pac::adc::vals::{OversamplingRatio, OversamplingShift, Rovsm, Trovs}; use super::{ blocking_delay_us, Adc, AdcChannel, AnyAdcChannel, Instance, Resolution, RxDma, SampleTime, SealedAdcChannel, }; + #[cfg(adc_v3)] -use crate::dma::{ReadableRingBuffer, Transfer, TransferOptions}; +mod ringbuffered_v3; + +#[cfg(adc_v3)] +use ringbuffered_v3::RingBufferedAdc; + +use crate::dma::Transfer; use crate::{pac, rcc, Peri}; /// Default VREF voltage used for sample conversion to millivolts. @@ -112,14 +115,6 @@ pub enum Averaging { Samples256, } -#[cfg_attr(feature = "defmt", derive(defmt::Format))] -pub struct OverrunError; - -pub struct RingBufferedAdc<'d, T: Instance> { - _phantom: PhantomData, - ring_buf: ReadableRingBuffer<'d, u16>, -} - impl<'d, T: Instance> Adc<'d, T> { pub fn new(adc: Peri<'d, T>) -> Self { rcc::enable_and_reset::(); @@ -531,19 +526,6 @@ impl<'d, T: Instance> Adc<'d, T> { } } - //dma side setup - let opts = TransferOptions { - half_transfer_ir: true, - circular: true, - ..Default::default() - }; - - // Safety: we forget the struct before this function returns. - let request = dma.request(); - - let ring_buf = - unsafe { ReadableRingBuffer::new(dma, request, T::regs().dr().as_ptr() as *mut u16, dma_buf, opts) }; - // On G0 and U0 enabled channels are sampled from 0 to last channel. // It is possible to add up to 8 sequences if CHSELRMOD = 1. // However for supporting more than 8 channels alternative CHSELRMOD = 0 approach is used. @@ -573,10 +555,7 @@ impl<'d, T: Instance> Adc<'d, T> { reg.set_dmaen(true); }); - RingBufferedAdc { - _phantom: PhantomData, - ring_buf, - } + RingBufferedAdc::new(dma, dma_buf) } fn configure_channel(channel: &mut impl AdcChannel, sample_time: SampleTime) { @@ -683,148 +662,3 @@ impl<'d, T: Instance> Adc<'d, T> { } } } - -#[cfg(adc_v3)] -impl<'d, T: Instance> RingBufferedAdc<'d, T> { - #[inline] - fn start_continous_sampling(&mut self) { - // Start adc conversion - T::regs().cr().modify(|reg| { - reg.set_adstart(true); - }); - self.ring_buf.start(); - } - - #[inline] - pub fn stop_continous_sampling(&mut self) { - // Stop adc conversion - if T::regs().cr().read().adstart() && !T::regs().cr().read().addis() { - T::regs().cr().modify(|reg| { - reg.set_adstp(true); - }); - while T::regs().cr().read().adstart() {} - } - } - pub fn disable_adc(&mut self) { - self.stop_continous_sampling(); - self.ring_buf.clear(); - self.ring_buf.request_pause(); - } - - pub fn teardown_adc(&mut self) { - self.disable_adc(); - - //disable dma control - #[cfg(not(any(adc_g0, adc_u0)))] - T::regs().cfgr().modify(|reg| { - reg.set_dmaen(false); - }); - #[cfg(any(adc_g0, adc_u0))] - T::regs().cfgr1().modify(|reg| { - reg.set_dmaen(false); - }); - - //TODO: do we need to cleanup the DMA request here? - - compiler_fence(Ordering::SeqCst); - } - - /// Reads measurements from the DMA ring buffer. - /// - /// This method fills the provided `measurements` array with ADC readings from the DMA buffer. - /// The length of the `measurements` array should be exactly half of the DMA buffer length. Because interrupts are only generated if half or full DMA transfer completes. - /// - /// Each call to `read` will populate the `measurements` array in the same order as the channels defined with `sequence`. - /// There will be many sequences worth of measurements in this array because it only returns if at least half of the DMA buffer is filled. - /// For example if 2 channels are sampled `measurements` contain: `[sq0 sq1 sq0 sq1 sq0 sq1 ..]`. - /// - /// Note that the ADC Datarate can be very fast, it is suggested to use DMA mode inside tightly running tasks - /// Otherwise, you'll see constant Overrun errors occuring, this means that you're sampling too quickly for the task to handle, and you may need to increase the buffer size. - /// Example: - /// ```rust,ignore - /// const DMA_BUF_LEN: usize = 120; - /// use embassy_stm32::adc::{Adc, AdcChannel} - /// - /// let mut adc = Adc::new(p.ADC1); - /// let mut adc_pin0 = p.PA0.degrade_adc(); - /// let mut adc_pin1 = p.PA1.degrade_adc(); - /// let adc_dma_buf = [0u16; DMA_BUF_LEN]; - /// - /// let mut ring_buffered_adc: RingBufferedAdc = adc.into_ring_buffered( - /// p.DMA2_CH0, - /// adc_dma_buf, [ - /// (&mut *adc_pin0, SampleTime::CYCLES160_5), - /// (&mut *adc_pin1, SampleTime::CYCLES160_5), - /// ].into_iter()); - /// - /// - /// let mut measurements = [0u16; DMA_BUF_LEN / 2]; - /// loop { - /// match ring_buffered_adc.read(&mut measurements).await { - /// Ok(_) => { - /// defmt::info!("adc1: {}", measurements); - /// } - /// Err(e) => { - /// defmt::warn!("Error: {:?}", e); - /// } - /// } - /// } - /// ``` - /// - /// - /// [`teardown_adc`]: #method.teardown_adc - /// [`start_continous_sampling`]: #method.start_continous_sampling - pub async fn read(&mut self, measurements: &mut [u16]) -> Result { - assert_eq!( - self.ring_buf.capacity() / 2, - measurements.len(), - "Buffer size must be half the size of the ring buffer" - ); - - let r = T::regs(); - - // Start background receive if it was not already started - if !r.cr().read().adstart() { - self.start_continous_sampling(); - } - - self.ring_buf.read_exact(measurements).await.map_err(|_| OverrunError) - } - - /// Read bytes that are readily available in the ring buffer. - /// If no bytes are currently available in the buffer the call waits until the some - /// bytes are available (at least one byte and at most half the buffer size) - /// - /// Background receive is started if `start_continous_sampling()` has not been previously called. - /// - /// Receive in the background is terminated if an error is returned. - /// It must then manually be started again by calling `start_continous_sampling()` or by re-calling `blocking_read()`. - pub fn blocking_read(&mut self, buf: &mut [u16]) -> Result { - let r = T::regs(); - - // Start background receive if it was not already started - if !r.cr().read().adstart() { - self.start_continous_sampling(); - } - - loop { - match self.ring_buf.read(buf) { - Ok((0, _)) => {} - Ok((len, _)) => { - return Ok(len); - } - Err(_) => { - self.stop_continous_sampling(); - return Err(OverrunError); - } - } - } - } -} - -impl Drop for RingBufferedAdc<'_, T> { - fn drop(&mut self) { - self.teardown_adc(); - rcc::disable::(); - } -} -- cgit From e48dc90edc3277d1b406900d16b35653aafdbe3a Mon Sep 17 00:00:00 2001 From: maor malka Date: Thu, 28 Aug 2025 18:15:43 -0400 Subject: stm32/adc/v3: rustfmt shananigans --- embassy-stm32/src/adc/ringbuffered_v3.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/embassy-stm32/src/adc/ringbuffered_v3.rs b/embassy-stm32/src/adc/ringbuffered_v3.rs index 655ae712f..7ff37f68d 100644 --- a/embassy-stm32/src/adc/ringbuffered_v3.rs +++ b/embassy-stm32/src/adc/ringbuffered_v3.rs @@ -1,11 +1,11 @@ use core::marker::PhantomData; use core::sync::atomic::{compiler_fence, Ordering}; + use embassy_hal_internal::Peri; +use crate::adc::{Instance, RxDma}; use crate::dma::{ReadableRingBuffer, TransferOptions}; -use crate::adc::Instance; -use crate::adc::RxDma; use crate::rcc; #[cfg_attr(feature = "defmt", derive(defmt::Format))] -- cgit From 1db247f5a493f178751ba083483009bfa31c7899 Mon Sep 17 00:00:00 2001 From: maor malka Date: Thu, 28 Aug 2025 18:16:56 -0400 Subject: rustfmt --- embassy-stm32/src/adc/ringbuffered_v3.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/embassy-stm32/src/adc/ringbuffered_v3.rs b/embassy-stm32/src/adc/ringbuffered_v3.rs index 7ff37f68d..d7af2322d 100644 --- a/embassy-stm32/src/adc/ringbuffered_v3.rs +++ b/embassy-stm32/src/adc/ringbuffered_v3.rs @@ -5,7 +5,6 @@ use embassy_hal_internal::Peri; use crate::adc::{Instance, RxDma}; use crate::dma::{ReadableRingBuffer, TransferOptions}; - use crate::rcc; #[cfg_attr(feature = "defmt", derive(defmt::Format))] -- cgit From 0d568022be9c9d7a39ec88bb3c4c2cb84d0699f2 Mon Sep 17 00:00:00 2001 From: Owen Phillips Date: Wed, 17 Sep 2025 20:09:30 -0700 Subject: docs(cyw43): clarify Control::join() docs Update doc comment to clarify that Control::join() can be used to join networks using the provided options, not only open networks. --- cyw43/CHANGELOG.md | 2 ++ cyw43/src/control.rs | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/cyw43/CHANGELOG.md b/cyw43/CHANGELOG.md index be7212afd..03363ad01 100644 --- a/cyw43/CHANGELOG.md +++ b/cyw43/CHANGELOG.md @@ -8,6 +8,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## Unreleased - ReleaseDate +- Updated documentation for Control::join() #4678 + ## 0.5.0 - 2025-08-28 - bump bt-hci to 0.4.0 diff --git a/cyw43/src/control.rs b/cyw43/src/control.rs index f77b487e2..e4dc0804f 100644 --- a/cyw43/src/control.rs +++ b/cyw43/src/control.rs @@ -295,7 +295,7 @@ impl<'a> Control<'a> { self.ioctl_set_u32(Ioctl::SetPm, 0, mode_num).await; } - /// Join an unprotected network with the provided ssid. + /// Join a network with the provided SSID using the specified options. pub async fn join(&mut self, ssid: &str, options: JoinOptions<'_>) -> Result<(), Error> { self.set_iovar_u32("ampdu_ba_wsize", 8).await; -- cgit From 6c801a0dba93680c8e41e611eada0576eab0f861 Mon Sep 17 00:00:00 2001 From: Dion Dokter Date: Thu, 18 Sep 2025 11:04:13 +0200 Subject: Add clone impl on shared i2c --- embassy-embedded-hal/src/shared_bus/asynch/i2c.rs | 18 ++++++++++++++++++ embassy-embedded-hal/src/shared_bus/blocking/i2c.rs | 18 ++++++++++++++++++ 2 files changed, 36 insertions(+) diff --git a/embassy-embedded-hal/src/shared_bus/asynch/i2c.rs b/embassy-embedded-hal/src/shared_bus/asynch/i2c.rs index 6de685ee1..48246270e 100644 --- a/embassy-embedded-hal/src/shared_bus/asynch/i2c.rs +++ b/embassy-embedded-hal/src/shared_bus/asynch/i2c.rs @@ -41,6 +41,12 @@ impl<'a, M: RawMutex, BUS> I2cDevice<'a, M, BUS> { } } +impl<'a, M: RawMutex, BUS> Clone for I2cDevice<'a, M, BUS> { + fn clone(&self) -> Self { + Self { bus: self.bus } + } +} + impl<'a, M: RawMutex, BUS> i2c::ErrorType for I2cDevice<'a, M, BUS> where BUS: i2c::ErrorType, @@ -113,6 +119,18 @@ impl<'a, M: RawMutex, BUS: SetConfig> I2cDeviceWithConfig<'a, M, BUS> { } } +impl<'a, M: RawMutex, BUS: SetConfig> Clone for I2cDeviceWithConfig<'a, M, BUS> +where + BUS::Config: Clone, +{ + fn clone(&self) -> Self { + Self { + bus: self.bus, + config: self.config.clone(), + } + } +} + impl<'a, M, BUS> i2c::ErrorType for I2cDeviceWithConfig<'a, M, BUS> where BUS: i2c::ErrorType, diff --git a/embassy-embedded-hal/src/shared_bus/blocking/i2c.rs b/embassy-embedded-hal/src/shared_bus/blocking/i2c.rs index 627767c8a..fa34cd416 100644 --- a/embassy-embedded-hal/src/shared_bus/blocking/i2c.rs +++ b/embassy-embedded-hal/src/shared_bus/blocking/i2c.rs @@ -36,6 +36,12 @@ impl<'a, M: RawMutex, BUS> I2cDevice<'a, M, BUS> { } } +impl<'a, M: RawMutex, BUS> Clone for I2cDevice<'a, M, BUS> { + fn clone(&self) -> Self { + Self { bus: self.bus } + } +} + impl<'a, M: RawMutex, BUS> ErrorType for I2cDevice<'a, M, BUS> where BUS: ErrorType, @@ -139,6 +145,18 @@ impl<'a, M: RawMutex, BUS: SetConfig> I2cDeviceWithConfig<'a, M, BUS> { } } +impl<'a, M: RawMutex, BUS: SetConfig> Clone for I2cDeviceWithConfig<'a, M, BUS> +where + BUS::Config: Clone, +{ + fn clone(&self) -> Self { + Self { + bus: self.bus, + config: self.config.clone(), + } + } +} + impl<'a, M, BUS> ErrorType for I2cDeviceWithConfig<'a, M, BUS> where M: RawMutex, -- cgit From b794997c56a7111b2c628b978486b7252ae98e26 Mon Sep 17 00:00:00 2001 From: Dion Dokter Date: Thu, 18 Sep 2025 11:06:33 +0200 Subject: Clippy fixes --- embassy-embedded-hal/src/flash/partition/asynch.rs | 6 +++--- embassy-embedded-hal/src/flash/partition/blocking.rs | 6 +++--- embassy-embedded-hal/src/shared_bus/asynch/spi.rs | 8 ++++---- embassy-embedded-hal/src/shared_bus/blocking/i2c.rs | 10 +++++----- embassy-embedded-hal/src/shared_bus/blocking/spi.rs | 8 ++++---- 5 files changed, 19 insertions(+), 19 deletions(-) diff --git a/embassy-embedded-hal/src/flash/partition/asynch.rs b/embassy-embedded-hal/src/flash/partition/asynch.rs index 82e27bb7c..a6fa2a562 100644 --- a/embassy-embedded-hal/src/flash/partition/asynch.rs +++ b/embassy-embedded-hal/src/flash/partition/asynch.rs @@ -119,7 +119,7 @@ mod tests { let mut read_buf = [0; 8]; partition.read(4, &mut read_buf).await.unwrap(); - assert!(read_buf.iter().position(|&x| x != 0xAA).is_none()); + assert!(!read_buf.iter().any(|&x| x != 0xAA)); } #[futures_test::test] @@ -133,7 +133,7 @@ mod tests { partition.write(4, &write_buf).await.unwrap(); let flash = flash.try_lock().unwrap(); - assert!(flash.mem[132..132 + 8].iter().position(|&x| x != 0xAA).is_none()); + assert!(!flash.mem[132..132 + 8].iter().any(|&x| x != 0xAA)); } #[futures_test::test] @@ -146,6 +146,6 @@ mod tests { partition.erase(0, 128).await.unwrap(); let flash = flash.try_lock().unwrap(); - assert!(flash.mem[128..256].iter().position(|&x| x != 0xFF).is_none()); + assert!(!flash.mem[128..256].iter().any(|&x| x != 0xFF)); } } diff --git a/embassy-embedded-hal/src/flash/partition/blocking.rs b/embassy-embedded-hal/src/flash/partition/blocking.rs index 951998166..cb30290a8 100644 --- a/embassy-embedded-hal/src/flash/partition/blocking.rs +++ b/embassy-embedded-hal/src/flash/partition/blocking.rs @@ -129,7 +129,7 @@ mod tests { let mut read_buf = [0; 8]; partition.read(4, &mut read_buf).unwrap(); - assert!(read_buf.iter().position(|&x| x != 0xAA).is_none()); + assert!(!read_buf.iter().any(|&x| x != 0xAA)); } #[test] @@ -143,7 +143,7 @@ mod tests { partition.write(4, &write_buf).unwrap(); let flash = flash.into_inner().take(); - assert!(flash.mem[132..132 + 8].iter().position(|&x| x != 0xAA).is_none()); + assert!(!flash.mem[132..132 + 8].iter().any(|&x| x != 0xAA)); } #[test] @@ -156,6 +156,6 @@ mod tests { partition.erase(0, 128).unwrap(); let flash = flash.into_inner().take(); - assert!(flash.mem[128..256].iter().position(|&x| x != 0xFF).is_none()); + assert!(!flash.mem[128..256].iter().any(|&x| x != 0xFF)); } } diff --git a/embassy-embedded-hal/src/shared_bus/asynch/spi.rs b/embassy-embedded-hal/src/shared_bus/asynch/spi.rs index 78709b7d3..0faefbc1e 100644 --- a/embassy-embedded-hal/src/shared_bus/asynch/spi.rs +++ b/embassy-embedded-hal/src/shared_bus/asynch/spi.rs @@ -112,11 +112,11 @@ where cs_drop.defuse(); let cs_res = self.cs.set_high(); - let op_res = op_res.map_err(SpiDeviceError::Spi)?; + op_res.map_err(SpiDeviceError::Spi)?; flush_res.map_err(SpiDeviceError::Spi)?; cs_res.map_err(SpiDeviceError::Cs)?; - Ok(op_res) + Ok(()) } } @@ -203,10 +203,10 @@ where cs_drop.defuse(); let cs_res = self.cs.set_high(); - let op_res = op_res.map_err(SpiDeviceError::Spi)?; + op_res.map_err(SpiDeviceError::Spi)?; flush_res.map_err(SpiDeviceError::Spi)?; cs_res.map_err(SpiDeviceError::Cs)?; - Ok(op_res) + Ok(()) } } diff --git a/embassy-embedded-hal/src/shared_bus/blocking/i2c.rs b/embassy-embedded-hal/src/shared_bus/blocking/i2c.rs index fa34cd416..dc634a209 100644 --- a/embassy-embedded-hal/src/shared_bus/blocking/i2c.rs +++ b/embassy-embedded-hal/src/shared_bus/blocking/i2c.rs @@ -81,33 +81,33 @@ where } } -impl<'a, M, BUS, E> embedded_hal_02::blocking::i2c::Write for I2cDevice<'_, M, BUS> +impl embedded_hal_02::blocking::i2c::Write for I2cDevice<'_, M, BUS> where M: RawMutex, BUS: embedded_hal_02::blocking::i2c::Write, { type Error = I2cDeviceError; - fn write<'w>(&mut self, addr: u8, bytes: &'w [u8]) -> Result<(), Self::Error> { + fn write(&mut self, addr: u8, bytes: &[u8]) -> Result<(), Self::Error> { self.bus .lock(|bus| bus.borrow_mut().write(addr, bytes).map_err(I2cDeviceError::I2c)) } } -impl<'a, M, BUS, E> embedded_hal_02::blocking::i2c::Read for I2cDevice<'_, M, BUS> +impl embedded_hal_02::blocking::i2c::Read for I2cDevice<'_, M, BUS> where M: RawMutex, BUS: embedded_hal_02::blocking::i2c::Read, { type Error = I2cDeviceError; - fn read<'w>(&mut self, addr: u8, bytes: &'w mut [u8]) -> Result<(), Self::Error> { + fn read(&mut self, addr: u8, bytes: &mut [u8]) -> Result<(), Self::Error> { self.bus .lock(|bus| bus.borrow_mut().read(addr, bytes).map_err(I2cDeviceError::I2c)) } } -impl<'a, M, BUS, E> embedded_hal_02::blocking::i2c::WriteRead for I2cDevice<'_, M, BUS> +impl embedded_hal_02::blocking::i2c::WriteRead for I2cDevice<'_, M, BUS> where M: RawMutex, BUS: embedded_hal_02::blocking::i2c::WriteRead, diff --git a/embassy-embedded-hal/src/shared_bus/blocking/spi.rs b/embassy-embedded-hal/src/shared_bus/blocking/spi.rs index eb9c0c4f4..ffe2aa1c6 100644 --- a/embassy-embedded-hal/src/shared_bus/blocking/spi.rs +++ b/embassy-embedded-hal/src/shared_bus/blocking/spi.rs @@ -82,11 +82,11 @@ where let flush_res = bus.flush(); let cs_res = self.cs.set_high(); - let op_res = op_res.map_err(SpiDeviceError::Spi)?; + op_res.map_err(SpiDeviceError::Spi)?; flush_res.map_err(SpiDeviceError::Spi)?; cs_res.map_err(SpiDeviceError::Cs)?; - Ok(op_res) + Ok(()) }) } } @@ -158,10 +158,10 @@ where let flush_res = bus.flush(); let cs_res = self.cs.set_high(); - let op_res = op_res.map_err(SpiDeviceError::Spi)?; + op_res.map_err(SpiDeviceError::Spi)?; flush_res.map_err(SpiDeviceError::Spi)?; cs_res.map_err(SpiDeviceError::Cs)?; - Ok(op_res) + Ok(()) }) } } -- cgit From bee6230cb6df0fc439e84b1fa8829b29db8cb680 Mon Sep 17 00:00:00 2001 From: Dion Dokter Date: Thu, 18 Sep 2025 11:08:59 +0200 Subject: Add to changelog --- embassy-embedded-hal/CHANGELOG.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/embassy-embedded-hal/CHANGELOG.md b/embassy-embedded-hal/CHANGELOG.md index ec79a5c81..95cd44a3c 100644 --- a/embassy-embedded-hal/CHANGELOG.md +++ b/embassy-embedded-hal/CHANGELOG.md @@ -8,6 +8,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## Unreleased - ReleaseDate +- Shared I2c busses now impl `Clone` + ## 0.5.0 - 2025-08-27 ## 0.4.0 - 2025-08-03 -- cgit From e5879db0f4b14199e3adfd446a4766cc5b3249f6 Mon Sep 17 00:00:00 2001 From: Ulf Lilleengen Date: Fri, 19 Sep 2025 09:53:25 +0200 Subject: chore: update to bt-hci 0.5.0 --- cyw43/CHANGELOG.md | 1 + cyw43/Cargo.toml | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/cyw43/CHANGELOG.md b/cyw43/CHANGELOG.md index 03363ad01..58a440335 100644 --- a/cyw43/CHANGELOG.md +++ b/cyw43/CHANGELOG.md @@ -9,6 +9,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## Unreleased - ReleaseDate - Updated documentation for Control::join() #4678 +- Bump bt-hci to 0.5.0 ## 0.5.0 - 2025-08-28 diff --git a/cyw43/Cargo.toml b/cyw43/Cargo.toml index 4d3a43733..0d0c26089 100644 --- a/cyw43/Cargo.toml +++ b/cyw43/Cargo.toml @@ -36,7 +36,7 @@ heapless = "0.8.0" # Bluetooth deps embedded-io-async = { version = "0.6.0", optional = true } -bt-hci = { version = "0.4.0", optional = true } +bt-hci = { version = "0.5.0", optional = true } [package.metadata.embassy] build = [ -- cgit From 6b3d2db4719046344ed93b3d0c8752ccffb2da48 Mon Sep 17 00:00:00 2001 From: Ulf Lilleengen Date: Fri, 19 Sep 2025 12:14:31 +0200 Subject: fix: add error handling for HCI transport --- cyw43/src/bluetooth.rs | 39 ++++++++++++++++++++++++++++++++++----- 1 file changed, 34 insertions(+), 5 deletions(-) diff --git a/cyw43/src/bluetooth.rs b/cyw43/src/bluetooth.rs index f617a8c7e..e530326db 100644 --- a/cyw43/src/bluetooth.rs +++ b/cyw43/src/bluetooth.rs @@ -3,12 +3,14 @@ use core::future::Future; use core::mem::MaybeUninit; use bt_hci::transport::WithIndicator; +use bt_hci::FromHciBytesError; use bt_hci::{ControllerToHostPacket, FromHciBytes, HostToControllerPacket, PacketKind, WriteHci}; use embassy_futures::yield_now; use embassy_sync::blocking_mutex::raw::NoopRawMutex; use embassy_sync::zerocopy_channel; use embassy_time::{Duration, Timer}; use embedded_hal_1::digital::OutputPin; +use embedded_io_async::ErrorKind; use crate::bus::Bus; pub use crate::bus::SpiBusCyw43; @@ -472,8 +474,33 @@ impl<'a> BtRunner<'a> { } } +/// HCI transport error. +#[cfg_attr(feature = "defmt", derive(defmt::Format))] +#[derive(Debug)] +pub enum Error { + /// I/O error. + Io(ErrorKind), +} + +impl From for Error { + fn from(e: FromHciBytesError) -> Self { + match e { + FromHciBytesError::InvalidSize => Error::Io(ErrorKind::InvalidInput), + FromHciBytesError::InvalidValue => Error::Io(ErrorKind::InvalidData), + } + } +} + impl<'d> embedded_io_async::ErrorType for BtDriver<'d> { - type Error = core::convert::Infallible; + type Error = Error; +} + +impl embedded_io_async::Error for Error { + fn kind(&self) -> ErrorKind { + match self { + Self::Io(e) => *e, + } + } } impl<'d> bt_hci::transport::Transport for BtDriver<'d> { @@ -486,9 +513,9 @@ impl<'d> bt_hci::transport::Transport for BtDriver<'d> { rx[..n].copy_from_slice(&buf.buf[..n]); ch.receive_done(); - let kind = PacketKind::from_hci_bytes_complete(&rx[..1]).unwrap(); - let (res, _) = ControllerToHostPacket::from_hci_bytes_with_kind(kind, &rx[1..n]).unwrap(); - Ok(res) + let kind = PacketKind::from_hci_bytes_complete(&rx[..1])?; + let (pkt, _) = ControllerToHostPacket::from_hci_bytes_with_kind(kind, &rx[1..n])?; + Ok(pkt) } } @@ -499,7 +526,9 @@ impl<'d> bt_hci::transport::Transport for BtDriver<'d> { let buf = ch.send().await; let buf_len = buf.buf.len(); let mut slice = &mut buf.buf[..]; - WithIndicator::new(val).write_hci(&mut slice).unwrap(); + WithIndicator::new(val) + .write_hci(&mut slice) + .map_err(|_| Error::Io(ErrorKind::Other))?; buf.len = buf_len - slice.len(); ch.send_done(); Ok(()) -- cgit From c77ee0cb32a012f0f1338753bb32a0713178eef3 Mon Sep 17 00:00:00 2001 From: Ulf Lilleengen Date: Fri, 19 Sep 2025 12:18:12 +0200 Subject: chore: add changelog item. --- cyw43/CHANGELOG.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/cyw43/CHANGELOG.md b/cyw43/CHANGELOG.md index 58a440335..dcf84b9ba 100644 --- a/cyw43/CHANGELOG.md +++ b/cyw43/CHANGELOG.md @@ -9,7 +9,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## Unreleased - ReleaseDate - Updated documentation for Control::join() #4678 -- Bump bt-hci to 0.5.0 +- Bump bt-hci to 0.5.0. +- Add error handling to HCI transport implementation. ## 0.5.0 - 2025-08-28 -- cgit From e46f3af64ff0c94e80cb1536ac42bbea12810653 Mon Sep 17 00:00:00 2001 From: Ulf Lilleengen Date: Fri, 19 Sep 2025 12:18:20 +0200 Subject: chore: rustfmt --- cyw43/src/bluetooth.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/cyw43/src/bluetooth.rs b/cyw43/src/bluetooth.rs index e530326db..d176c4b09 100644 --- a/cyw43/src/bluetooth.rs +++ b/cyw43/src/bluetooth.rs @@ -3,8 +3,7 @@ use core::future::Future; use core::mem::MaybeUninit; use bt_hci::transport::WithIndicator; -use bt_hci::FromHciBytesError; -use bt_hci::{ControllerToHostPacket, FromHciBytes, HostToControllerPacket, PacketKind, WriteHci}; +use bt_hci::{ControllerToHostPacket, FromHciBytes, FromHciBytesError, HostToControllerPacket, PacketKind, WriteHci}; use embassy_futures::yield_now; use embassy_sync::blocking_mutex::raw::NoopRawMutex; use embassy_sync::zerocopy_channel; -- cgit From 6e1d6be315957e587051df7bf96f4a87fc748117 Mon Sep 17 00:00:00 2001 From: Matthew Tran <0e4ef622@gmail.com> Date: Sat, 20 Sep 2025 11:55:59 -0500 Subject: nrf: add persist() method for gpio and ppi --- embassy-nrf/CHANGELOG.md | 1 + embassy-nrf/src/gpio.rs | 27 +++++++++++++++++++++++++++ embassy-nrf/src/ppi/dppi.rs | 9 +++++++++ embassy-nrf/src/ppi/mod.rs | 8 ++++++++ embassy-nrf/src/ppi/ppi.rs | 9 +++++++++ embassy-nrf/src/timer.rs | 4 ++-- 6 files changed, 56 insertions(+), 2 deletions(-) diff --git a/embassy-nrf/CHANGELOG.md b/embassy-nrf/CHANGELOG.md index befa34ecf..de8dfd391 100644 --- a/embassy-nrf/CHANGELOG.md +++ b/embassy-nrf/CHANGELOG.md @@ -10,6 +10,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - changed: nrf54l: Disable glitch detection and enable DC/DC in init. - changed: Add embassy-net-driver-channel implementation for IEEE 802.15.4 +- changed: add persist() method for gpio and ppi ## 0.7.0 - 2025-08-26 diff --git a/embassy-nrf/src/gpio.rs b/embassy-nrf/src/gpio.rs index 65f2d99f7..0cea38777 100644 --- a/embassy-nrf/src/gpio.rs +++ b/embassy-nrf/src/gpio.rs @@ -75,6 +75,15 @@ impl<'d> Input<'d> { } } +impl Input<'static> { + /// Persist the pin's configuration for the rest of the program's lifetime. This method should + /// be preferred over [`core::mem::forget()`] because the `'static` bound prevents accidental + /// reuse of the underlying peripheral. + pub fn persist(self) { + self.pin.persist() + } +} + /// Digital input or output level. #[derive(Clone, Copy, Debug, Eq, PartialEq)] #[cfg_attr(feature = "defmt", derive(defmt::Format))] @@ -264,6 +273,15 @@ impl<'d> Output<'d> { } } +impl Output<'static> { + /// Persist the pin's configuration for the rest of the program's lifetime. This method should + /// be preferred over [`core::mem::forget()`] because the `'static` bound prevents accidental + /// reuse of the underlying peripheral. + pub fn persist(self) { + self.pin.persist() + } +} + pub(crate) fn convert_drive(w: &mut pac::gpio::regs::PinCnf, drive: OutputDrive) { #[cfg(not(feature = "_nrf54l"))] { @@ -447,6 +465,15 @@ impl<'d> Flex<'d> { } } +impl Flex<'static> { + /// Persist the pin's configuration for the rest of the program's lifetime. This method should + /// be preferred over [`core::mem::forget()`] because the `'static` bound prevents accidental + /// reuse of the underlying peripheral. + pub fn persist(self) { + core::mem::forget(self); + } +} + impl<'d> Drop for Flex<'d> { fn drop(&mut self) { self.set_as_disconnected(); diff --git a/embassy-nrf/src/ppi/dppi.rs b/embassy-nrf/src/ppi/dppi.rs index 686f66987..078d2fd1c 100644 --- a/embassy-nrf/src/ppi/dppi.rs +++ b/embassy-nrf/src/ppi/dppi.rs @@ -59,6 +59,15 @@ impl<'d, C: Channel, const EVENT_COUNT: usize, const TASK_COUNT: usize> Ppi<'d, } } +impl Ppi<'static, C, EVENT_COUNT, TASK_COUNT> { + /// Persist the channel's configuration for the rest of the program's lifetime. This method + /// should be preferred over [`core::mem::forget()`] because the `'static` bound prevents + /// accidental reuse of the underlying peripheral. + pub fn persist(self) { + core::mem::forget(self); + } +} + impl<'d, C: Channel, const EVENT_COUNT: usize, const TASK_COUNT: usize> Drop for Ppi<'d, C, EVENT_COUNT, TASK_COUNT> { fn drop(&mut self) { self.disable(); diff --git a/embassy-nrf/src/ppi/mod.rs b/embassy-nrf/src/ppi/mod.rs index 531777205..2bcf72e9c 100644 --- a/embassy-nrf/src/ppi/mod.rs +++ b/embassy-nrf/src/ppi/mod.rs @@ -108,6 +108,14 @@ impl<'d, G: Group> PpiGroup<'d, G> { Task::from_reg(regs().tasks_chg(n).dis()) } } +impl PpiGroup<'static, G> { + /// Persist this group's configuration for the rest of the program's lifetime. This method + /// should be preferred over [`core::mem::forget()`] because the `'static` bound prevents + /// accidental reuse of the underlying peripheral. + pub fn persist(self) { + core::mem::forget(self); + } +} impl<'d, G: Group> Drop for PpiGroup<'d, G> { fn drop(&mut self) { diff --git a/embassy-nrf/src/ppi/ppi.rs b/embassy-nrf/src/ppi/ppi.rs index e04dacbc0..531c25444 100644 --- a/embassy-nrf/src/ppi/ppi.rs +++ b/embassy-nrf/src/ppi/ppi.rs @@ -68,6 +68,15 @@ impl<'d, C: Channel, const EVENT_COUNT: usize, const TASK_COUNT: usize> Ppi<'d, } } +impl Ppi<'static, C, EVENT_COUNT, TASK_COUNT> { + /// Persist the channel's configuration for the rest of the program's lifetime. This method + /// should be preferred over [`core::mem::forget()`] because the `'static` bound prevents + /// accidental reuse of the underlying peripheral. + pub fn persist(self) { + core::mem::forget(self); + } +} + impl<'d, C: Channel, const EVENT_COUNT: usize, const TASK_COUNT: usize> Drop for Ppi<'d, C, EVENT_COUNT, TASK_COUNT> { fn drop(&mut self) { self.disable(); diff --git a/embassy-nrf/src/timer.rs b/embassy-nrf/src/timer.rs index 5b58b0a50..de2875765 100644 --- a/embassy-nrf/src/timer.rs +++ b/embassy-nrf/src/timer.rs @@ -90,7 +90,7 @@ pub struct Timer<'d, T: Instance> { impl<'d, T: Instance> Timer<'d, T> { /// Create a new `Timer` driver. /// - /// This can be useful for triggering tasks via PPI + /// This can be useful for triggering tasks via PPI. /// `Uarte` uses this internally. pub fn new(timer: Peri<'d, T>) -> Self { Self::new_inner(timer, false) @@ -98,7 +98,7 @@ impl<'d, T: Instance> Timer<'d, T> { /// Create a new `Timer` driver in counter mode. /// - /// This can be useful for triggering tasks via PPI + /// This can be useful for triggering tasks via PPI. /// `Uarte` uses this internally. pub fn new_counter(timer: Peri<'d, T>) -> Self { Self::new_inner(timer, true) -- cgit From 9bb77f36f9697dd301f6c68a649030e2b5487782 Mon Sep 17 00:00:00 2001 From: 9names <60134748+9names@users.noreply.github.com> Date: Sun, 21 Sep 2025 13:24:29 +1000 Subject: rp: Use msplim for rp235x core1 stack guard --- embassy-rp/src/lib.rs | 14 +++----------- 1 file changed, 3 insertions(+), 11 deletions(-) diff --git a/embassy-rp/src/lib.rs b/embassy-rp/src/lib.rs index 6fb680b34..d03ba1fef 100644 --- a/embassy-rp/src/lib.rs +++ b/embassy-rp/src/lib.rs @@ -565,18 +565,10 @@ unsafe fn install_stack_guard(stack_bottom: *mut usize) -> Result<(), ()> { #[cfg(all(feature = "_rp235x", not(feature = "_test")))] #[inline(always)] unsafe fn install_stack_guard(stack_bottom: *mut usize) -> Result<(), ()> { - let core = unsafe { cortex_m::Peripherals::steal() }; + // The RP2350 arm cores are cortex-m33 and can use the MSPLIM register to guard the end of stack. + // We'll need to do something else for the riscv cores. + cortex_m::register::msplim::write(stack_bottom.addr() as u32); - // Fail if MPU is already configured - if core.MPU.ctrl.read() != 0 { - return Err(()); - } - - unsafe { - core.MPU.ctrl.write(5); // enable mpu with background default map - core.MPU.rbar.write(stack_bottom as u32 & !0xff); // set address - core.MPU.rlar.write(((stack_bottom as usize + 255) as u32) | 1); - } Ok(()) } -- cgit From c69d17e5fb11852ba14ddc3369a0c2dbfff4e29d Mon Sep 17 00:00:00 2001 From: 9names <60134748+9names@users.noreply.github.com> Date: Sun, 21 Sep 2025 13:27:54 +1000 Subject: examples/rp235x: Add multicore stack overflow example --- .../rp235x/src/bin/multicore_stack_overflow.rs | 72 ++++++++++++++++++++++ 1 file changed, 72 insertions(+) create mode 100644 examples/rp235x/src/bin/multicore_stack_overflow.rs diff --git a/examples/rp235x/src/bin/multicore_stack_overflow.rs b/examples/rp235x/src/bin/multicore_stack_overflow.rs new file mode 100644 index 000000000..dba44aa23 --- /dev/null +++ b/examples/rp235x/src/bin/multicore_stack_overflow.rs @@ -0,0 +1,72 @@ +//! This example tests stack overflow handling on core1 of the RP235x chip. + +#![no_std] +#![no_main] + +use defmt::*; +use embassy_executor::Executor; +use embassy_rp::gpio::{Level, Output}; +use embassy_rp::multicore::{spawn_core1, Stack}; +use embassy_time::Timer; +use static_cell::StaticCell; +use {defmt_rtt as _, panic_probe as _}; + +const CORE1_STACK_LENGTH: usize = 4096; + +static mut CORE1_STACK: Stack = Stack::new(); +static EXECUTOR0: StaticCell = StaticCell::new(); +static EXECUTOR1: StaticCell = StaticCell::new(); + +#[cortex_m_rt::entry] +fn main() -> ! { + let p = embassy_rp::init(Default::default()); + let led = Output::new(p.PIN_25, Level::Low); + + spawn_core1( + p.CORE1, + unsafe { &mut *core::ptr::addr_of_mut!(CORE1_STACK) }, + move || { + let executor1 = EXECUTOR1.init(Executor::new()); + executor1.run(|spawner| spawner.spawn(unwrap!(core1_task()))); + }, + ); + + let executor0 = EXECUTOR0.init(Executor::new()); + executor0.run(|spawner| spawner.spawn(unwrap!(core0_task(led)))); +} + +#[embassy_executor::task] +async fn core0_task(mut led: Output<'static>) { + info!("Hello from core 0"); + loop { + info!("core 0 still alive"); + led.set_high(); + Timer::after_millis(500).await; + led.set_low(); + Timer::after_millis(500).await; + } +} + +fn blow_my_stack() { + // Allocating an array a little larger than our stack should ensure a stack overflow when it is used. + let t = [0u8; CORE1_STACK_LENGTH + 64]; + + info!("Array initialised without error"); + // We need to use black_box to otherwise the compiler is too smart and will optimise all of this away. + // We shouldn't get to this code - the initialisation above will touch the stack guard. + for ref i in t { + let _data = core::hint::black_box(*i) + 1; + } +} + +#[embassy_executor::task] +async fn core1_task() { + info!("Hello from core 1"); + + blow_my_stack(); + + loop { + info!("core 1 still alive"); + Timer::after_millis(1000).await; + } +} -- cgit From a3ee22be1374222f68893b7c76bbb45914e6fead Mon Sep 17 00:00:00 2001 From: 9names <60134748+9names@users.noreply.github.com> Date: Sun, 21 Sep 2025 19:19:15 +1000 Subject: chore: update changelog --- embassy-rp/CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/embassy-rp/CHANGELOG.md b/embassy-rp/CHANGELOG.md index d1265ffc4..ea62c2387 100644 --- a/embassy-rp/CHANGELOG.md +++ b/embassy-rp/CHANGELOG.md @@ -12,6 +12,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Add PIO I2S input - Add PIO onewire parasite power strong pullup - add `wait_for_alarm` and `alarm_scheduled` methods to rtc module ([#4216](https://github.com/embassy-rs/embassy/pull/4216)) +- rp235x: use msplim for stack guard instead of MPU ## 0.8.0 - 2025-08-26 -- cgit From 9e94c1bda38ed3e41458f1681cd1714d1c03e1e8 Mon Sep 17 00:00:00 2001 From: Narottam Royal Date: Sun, 21 Sep 2025 23:13:06 +1200 Subject: Add support for USB CRS sync --- embassy-stm32/CHANGELOG.md | 1 + embassy-stm32/src/rcc/c0.rs | 14 ++++++++++++-- 2 files changed, 13 insertions(+), 2 deletions(-) diff --git a/embassy-stm32/CHANGELOG.md b/embassy-stm32/CHANGELOG.md index 190e68d6d..8fcc088fd 100644 --- a/embassy-stm32/CHANGELOG.md +++ b/embassy-stm32/CHANGELOG.md @@ -22,6 +22,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - fix: handle address and data-length errors in OSPI - feat: Allow OSPI DMA writes larger than 64kB using chunking - feat: More ADC enums for g0 PAC, API change for oversampling, allow separate sample times +- feat: Add USB CRS sync support for STM32C071 ## 0.4.0 - 2025-08-26 diff --git a/embassy-stm32/src/rcc/c0.rs b/embassy-stm32/src/rcc/c0.rs index c2295bab6..99f22273d 100644 --- a/embassy-stm32/src/rcc/c0.rs +++ b/embassy-stm32/src/rcc/c0.rs @@ -49,6 +49,10 @@ pub struct Config { /// System Clock Configuration pub sys: Sysclk, + /// HSI48 Configuration + #[cfg(crs)] + pub hsi48: Option, + pub ahb_pre: AHBPrescaler, pub apb1_pre: APBPrescaler, @@ -68,6 +72,8 @@ impl Config { }), hse: None, sys: Sysclk::HSISYS, + #[cfg(crs)] + hsi48: Some(crate::rcc::Hsi48Config::new()), ahb_pre: AHBPrescaler::DIV1, apb1_pre: APBPrescaler::DIV1, ls: crate::rcc::LsConfig::new(), @@ -127,6 +133,10 @@ pub(crate) unsafe fn init(config: Config) { } }; + // Configure HSI48 if required + #[cfg(crs)] + let hsi48 = config.hsi48.map(super::init_hsi48); + let rtc = config.ls.init(); let sys = match config.sys { @@ -185,13 +195,13 @@ pub(crate) unsafe fn init(config: Config) { hsi: hsi, hsiker: hsiker, hse: hse, + #[cfg(crs)] + hsi48: hsi48, rtc: rtc, // TODO lsi: None, lse: None, - #[cfg(crs)] - hsi48: None, ); RCC.ccipr() -- cgit From f7c3005345df07bad5c42612fd73974bd569affb Mon Sep 17 00:00:00 2001 From: Robin Mueller Date: Fri, 19 Sep 2025 17:38:24 +0200 Subject: add basic RTC driver for nRF --- embassy-nrf/CHANGELOG.md | 1 + embassy-nrf/src/chips/nrf51.rs | 3 + embassy-nrf/src/chips/nrf52805.rs | 3 + embassy-nrf/src/chips/nrf52810.rs | 3 + embassy-nrf/src/chips/nrf52811.rs | 3 + embassy-nrf/src/chips/nrf52820.rs | 3 + embassy-nrf/src/chips/nrf52832.rs | 4 + embassy-nrf/src/chips/nrf52833.rs | 4 + embassy-nrf/src/chips/nrf52840.rs | 4 + embassy-nrf/src/chips/nrf5340_app.rs | 3 + embassy-nrf/src/chips/nrf5340_net.rs | 3 + embassy-nrf/src/chips/nrf9120.rs | 3 + embassy-nrf/src/chips/nrf9160.rs | 3 + embassy-nrf/src/lib.rs | 2 + embassy-nrf/src/rtc.rs | 272 +++++++++++++++++++++++++++++++++++ examples/nrf52840/Cargo.toml | 1 + examples/nrf52840/src/bin/rtc.rs | 57 ++++++++ 17 files changed, 372 insertions(+) create mode 100644 embassy-nrf/src/rtc.rs create mode 100644 examples/nrf52840/src/bin/rtc.rs diff --git a/embassy-nrf/CHANGELOG.md b/embassy-nrf/CHANGELOG.md index de8dfd391..7c783c2d4 100644 --- a/embassy-nrf/CHANGELOG.md +++ b/embassy-nrf/CHANGELOG.md @@ -11,6 +11,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - changed: nrf54l: Disable glitch detection and enable DC/DC in init. - changed: Add embassy-net-driver-channel implementation for IEEE 802.15.4 - changed: add persist() method for gpio and ppi +- added: basic RTC driver ## 0.7.0 - 2025-08-26 diff --git a/embassy-nrf/src/chips/nrf51.rs b/embassy-nrf/src/chips/nrf51.rs index fd13ae5c4..393af4e75 100644 --- a/embassy-nrf/src/chips/nrf51.rs +++ b/embassy-nrf/src/chips/nrf51.rs @@ -110,6 +110,9 @@ impl_timer!(TIMER2, TIMER2, TIMER2); impl_rng!(RNG, RNG, RNG); +impl_rtc!(RTC0, RTC0, RTC0); +impl_rtc!(RTC1, RTC1, RTC1); + impl_pin!(P0_00, 0, 0); impl_pin!(P0_01, 0, 1); impl_pin!(P0_02, 0, 2); diff --git a/embassy-nrf/src/chips/nrf52805.rs b/embassy-nrf/src/chips/nrf52805.rs index 7e72df8fc..427298a56 100644 --- a/embassy-nrf/src/chips/nrf52805.rs +++ b/embassy-nrf/src/chips/nrf52805.rs @@ -156,6 +156,9 @@ impl_timer!(TIMER0, TIMER0, TIMER0); impl_timer!(TIMER1, TIMER1, TIMER1); impl_timer!(TIMER2, TIMER2, TIMER2); +impl_rtc!(RTC0, RTC0, RTC0); +impl_rtc!(RTC1, RTC1, RTC1); + impl_pin!(P0_00, 0, 0); impl_pin!(P0_01, 0, 1); impl_pin!(P0_02, 0, 2); diff --git a/embassy-nrf/src/chips/nrf52810.rs b/embassy-nrf/src/chips/nrf52810.rs index e388e44e8..c99b54265 100644 --- a/embassy-nrf/src/chips/nrf52810.rs +++ b/embassy-nrf/src/chips/nrf52810.rs @@ -166,6 +166,9 @@ impl_timer!(TIMER0, TIMER0, TIMER0); impl_timer!(TIMER1, TIMER1, TIMER1); impl_timer!(TIMER2, TIMER2, TIMER2); +impl_rtc!(RTC0, RTC0, RTC0); +impl_rtc!(RTC1, RTC1, RTC1); + impl_pin!(P0_00, 0, 0); impl_pin!(P0_01, 0, 1); impl_pin!(P0_02, 0, 2); diff --git a/embassy-nrf/src/chips/nrf52811.rs b/embassy-nrf/src/chips/nrf52811.rs index 96b8df30b..5f7a67f06 100644 --- a/embassy-nrf/src/chips/nrf52811.rs +++ b/embassy-nrf/src/chips/nrf52811.rs @@ -168,6 +168,9 @@ impl_timer!(TIMER0, TIMER0, TIMER0); impl_timer!(TIMER1, TIMER1, TIMER1); impl_timer!(TIMER2, TIMER2, TIMER2); +impl_rtc!(RTC0, RTC0, RTC0); +impl_rtc!(RTC1, RTC1, RTC1); + impl_pin!(P0_00, 0, 0); impl_pin!(P0_01, 0, 1); impl_pin!(P0_02, 0, 2); diff --git a/embassy-nrf/src/chips/nrf52820.rs b/embassy-nrf/src/chips/nrf52820.rs index ad461b153..1677fcf02 100644 --- a/embassy-nrf/src/chips/nrf52820.rs +++ b/embassy-nrf/src/chips/nrf52820.rs @@ -164,6 +164,9 @@ impl_timer!(TIMER1, TIMER1, TIMER1); impl_timer!(TIMER2, TIMER2, TIMER2); impl_timer!(TIMER3, TIMER3, TIMER3, extended); +impl_rtc!(RTC0, RTC0, RTC0); +impl_rtc!(RTC1, RTC1, RTC1); + impl_qdec!(QDEC, QDEC, QDEC); impl_rng!(RNG, RNG, RNG); diff --git a/embassy-nrf/src/chips/nrf52832.rs b/embassy-nrf/src/chips/nrf52832.rs index cf2abf23a..6b735e218 100644 --- a/embassy-nrf/src/chips/nrf52832.rs +++ b/embassy-nrf/src/chips/nrf52832.rs @@ -182,6 +182,10 @@ impl_twim!(TWISPI1, TWIM1, TWISPI1); impl_twis!(TWISPI0, TWIS0, TWISPI0); impl_twis!(TWISPI1, TWIS1, TWISPI1); +impl_rtc!(RTC0, RTC0, RTC0); +impl_rtc!(RTC1, RTC1, RTC1); +impl_rtc!(RTC2, RTC2, RTC2); + impl_pwm!(PWM0, PWM0, PWM0); impl_pwm!(PWM1, PWM1, PWM1); impl_pwm!(PWM2, PWM2, PWM2); diff --git a/embassy-nrf/src/chips/nrf52833.rs b/embassy-nrf/src/chips/nrf52833.rs index e46eb1d2b..b9c75f54b 100644 --- a/embassy-nrf/src/chips/nrf52833.rs +++ b/embassy-nrf/src/chips/nrf52833.rs @@ -223,6 +223,10 @@ impl_timer!(TIMER2, TIMER2, TIMER2); impl_timer!(TIMER3, TIMER3, TIMER3, extended); impl_timer!(TIMER4, TIMER4, TIMER4, extended); +impl_rtc!(RTC0, RTC0, RTC0); +impl_rtc!(RTC1, RTC1, RTC1); +impl_rtc!(RTC2, RTC2, RTC2); + impl_pin!(P0_00, 0, 0); impl_pin!(P0_01, 0, 1); impl_pin!(P0_02, 0, 2); diff --git a/embassy-nrf/src/chips/nrf52840.rs b/embassy-nrf/src/chips/nrf52840.rs index 88747843d..ccfa1f747 100644 --- a/embassy-nrf/src/chips/nrf52840.rs +++ b/embassy-nrf/src/chips/nrf52840.rs @@ -220,6 +220,10 @@ impl_timer!(TIMER2, TIMER2, TIMER2); impl_timer!(TIMER3, TIMER3, TIMER3, extended); impl_timer!(TIMER4, TIMER4, TIMER4, extended); +impl_rtc!(RTC0, RTC0, RTC0); +impl_rtc!(RTC1, RTC1, RTC1); +impl_rtc!(RTC2, RTC2, RTC2); + impl_qspi!(QSPI, QSPI, QSPI); impl_pdm!(PDM, PDM, PDM); diff --git a/embassy-nrf/src/chips/nrf5340_app.rs b/embassy-nrf/src/chips/nrf5340_app.rs index c0290b7a4..eb429db21 100644 --- a/embassy-nrf/src/chips/nrf5340_app.rs +++ b/embassy-nrf/src/chips/nrf5340_app.rs @@ -369,6 +369,9 @@ impl_timer!(TIMER0, TIMER0, TIMER0); impl_timer!(TIMER1, TIMER1, TIMER1); impl_timer!(TIMER2, TIMER2, TIMER2); +impl_rtc!(RTC0, RTC0, RTC0); +impl_rtc!(RTC1, RTC1, RTC1); + impl_qspi!(QSPI, QSPI, QSPI); impl_pdm!(PDM0, PDM0, PDM0); diff --git a/embassy-nrf/src/chips/nrf5340_net.rs b/embassy-nrf/src/chips/nrf5340_net.rs index d4c3e5353..a8de288a9 100644 --- a/embassy-nrf/src/chips/nrf5340_net.rs +++ b/embassy-nrf/src/chips/nrf5340_net.rs @@ -218,6 +218,9 @@ impl_timer!(TIMER0, TIMER0, TIMER0); impl_timer!(TIMER1, TIMER1, TIMER1); impl_timer!(TIMER2, TIMER2, TIMER2); +impl_rtc!(RTC0, RTC0, RTC0); +impl_rtc!(RTC1, RTC1, RTC1); + impl_rng!(RNG, RNG, RNG); impl_pin!(P0_00, 0, 0); diff --git a/embassy-nrf/src/chips/nrf9120.rs b/embassy-nrf/src/chips/nrf9120.rs index e8ddbf86f..9008a23a8 100644 --- a/embassy-nrf/src/chips/nrf9120.rs +++ b/embassy-nrf/src/chips/nrf9120.rs @@ -276,6 +276,9 @@ impl_timer!(TIMER0, TIMER0, TIMER0); impl_timer!(TIMER1, TIMER1, TIMER1); impl_timer!(TIMER2, TIMER2, TIMER2); +impl_rtc!(RTC0, RTC0, RTC0); +impl_rtc!(RTC1, RTC1, RTC1); + impl_pin!(P0_00, 0, 0); impl_pin!(P0_01, 0, 1); impl_pin!(P0_02, 0, 2); diff --git a/embassy-nrf/src/chips/nrf9160.rs b/embassy-nrf/src/chips/nrf9160.rs index 5d04a72e5..dbb06d71a 100644 --- a/embassy-nrf/src/chips/nrf9160.rs +++ b/embassy-nrf/src/chips/nrf9160.rs @@ -276,6 +276,9 @@ impl_timer!(TIMER0, TIMER0, TIMER0); impl_timer!(TIMER1, TIMER1, TIMER1); impl_timer!(TIMER2, TIMER2, TIMER2); +impl_rtc!(RTC0, RTC0, RTC0); +impl_rtc!(RTC1, RTC1, RTC1); + impl_pin!(P0_00, 0, 0); impl_pin!(P0_01, 0, 1); impl_pin!(P0_02, 0, 2); diff --git a/embassy-nrf/src/lib.rs b/embassy-nrf/src/lib.rs index 897e660b8..e0847a312 100644 --- a/embassy-nrf/src/lib.rs +++ b/embassy-nrf/src/lib.rs @@ -155,6 +155,8 @@ pub mod reset; #[cfg(not(any(feature = "_nrf5340-app", feature = "_nrf91")))] pub mod rng; #[cfg(not(feature = "_nrf54l"))] // TODO +pub mod rtc; +#[cfg(not(feature = "_nrf54l"))] // TODO #[cfg(not(any(feature = "_nrf51", feature = "nrf52820", feature = "_nrf5340-net")))] pub mod saadc; #[cfg(not(feature = "_nrf54l"))] // TODO diff --git a/embassy-nrf/src/rtc.rs b/embassy-nrf/src/rtc.rs new file mode 100644 index 000000000..5dd427fde --- /dev/null +++ b/embassy-nrf/src/rtc.rs @@ -0,0 +1,272 @@ +//! Low-level RTC driver. + +#![macro_use] + +use embassy_hal_internal::{Peri, PeripheralType}; + +use crate::chip::interrupt::typelevel::Interrupt as _; +use crate::pac; + +/// Prescaler has an invalid value which exceeds 12 bits. +#[derive(Debug, PartialEq, Eq)] +#[cfg_attr(feature = "defmt", derive(defmt::Format))] +pub struct PrescalerOutOfRangeError(u32); + +/// Compare value has an invalid value which exceeds 24 bits. +#[derive(Debug, PartialEq, Eq)] +#[cfg_attr(feature = "defmt", derive(defmt::Format))] +pub struct CompareOutOfRangeError(u32); + +/// Compare register is not implemented for RTC0. +#[derive(Debug, PartialEq, Eq)] +#[cfg_attr(feature = "defmt", derive(defmt::Format))] +pub struct CompareRegNotImplementedError; + +/// Interrupts/Events that can be generated by the RTCn peripheral. +#[derive(Debug, Copy, Clone, PartialEq, Eq)] +#[cfg_attr(feature = "defmt", derive(defmt::Format))] +pub enum Interrupt { + /// Tick interrupt. + Tick, + /// Overflow interrupt. + Overflow, + /// Compare 0 interrupt. + Compare0, + /// Compare 1 interrupt. + Compare1, + /// Compare 2 interrupt. + Compare2, + /// Compare 3 interrupt. Only implemented for RTC1 and RTC2. + Compare3, +} + +/// Compare registers available on the RTCn. +#[derive(Debug, Copy, Clone)] +#[cfg_attr(feature = "defmt", derive(defmt::Format))] +pub enum CompareChannel { + /// Channel 0 + _0, + /// Channel 1 + _1, + /// Channel 2 + _2, + /// Channel 3. Only implemented for RTC1 and RTC2. + _3, +} + +pub(crate) trait SealedInstance { + fn regs() -> pac::rtc::Rtc; +} + +/// Basic RTC instance. +#[allow(private_bounds)] +pub trait Instance: SealedInstance + PeripheralType + 'static + Send { + /// Interrupt for this peripheral. + type Interrupt: crate::interrupt::typelevel::Interrupt; + + /// Unsafely create a peripheral instance. + /// + /// # Safety + /// + /// Potentially allows to create multiple instances of the driver for the same peripheral + /// which can lead to undefined behavior. + unsafe fn steal() -> Peri<'static, Self>; +} + +macro_rules! impl_rtc { + ($type:ident, $pac_type:ident, $irq:ident) => { + impl crate::rtc::SealedInstance for peripherals::$type { + #[inline] + fn regs() -> pac::rtc::Rtc { + unsafe { pac::rtc::Rtc::from_ptr(pac::$pac_type.as_ptr()) } + } + } + + impl crate::rtc::Instance for peripherals::$type { + type Interrupt = crate::interrupt::typelevel::$irq; + + unsafe fn steal() -> embassy_hal_internal::Peri<'static, Self> { + unsafe { peripherals::$type::steal() } + } + } + }; +} + +/// nRF RTC driver. +/// +/// If the `time-driver-rtc1` feature is enabled, the creation of a driver with RTC1 will conflict +/// with the time driver implementation. +pub struct Rtc<'d, T: Instance>(Peri<'d, T>); + +impl<'d, T: Instance> Rtc<'d, T> { + /// Create a new `Rtc` driver. + /// + /// fRTC = 32_768 / (`prescaler` + 1 ) + pub fn new(rtc: Peri<'d, T>, prescaler: u32) -> Result { + if prescaler >= (1 << 12) { + return Err(PrescalerOutOfRangeError(prescaler)); + } + + T::regs().prescaler().write(|w| w.set_prescaler(prescaler as u16)); + Ok(Self(rtc)) + } + + /// Create a new `Rtc` driver, configuring it to run at the given frequency. + pub fn new_for_freq(rtc: Peri<'d, T>, freq_hz: u32) -> Result { + let prescaler = (32_768 / freq_hz).saturating_sub(1); + Self::new(rtc, prescaler) + } + + /// Steal the RTC peripheral, without checking if it's already taken. + /// + /// # Safety + /// + /// Potentially allows to create multiple instances of the driver for the same peripheral + /// which can lead to undefined behavior. + pub unsafe fn steal() -> Self { + Self(unsafe { T::steal() }) + } + + /// Direct access to the RTC registers. + #[inline] + pub fn regs(&mut self) -> pac::rtc::Rtc { + T::regs() + } + + /// Enable the RTC. + #[inline] + pub fn enable(&mut self) { + T::regs().tasks_start().write_value(1); + } + + /// Disable the RTC. + #[inline] + pub fn disable(&mut self) { + T::regs().tasks_stop().write_value(1); + } + + /// Enables interrupts for the given [RtcInterrupt] source. + /// + /// Optionally also enables the interrupt in the NVIC. + pub fn enable_interrupt(&mut self, int: Interrupt, enable_in_nvic: bool) { + let regs = T::regs(); + match int { + Interrupt::Tick => regs.intenset().write(|w| w.set_tick(true)), + Interrupt::Overflow => regs.intenset().write(|w| w.set_ovrflw(true)), + Interrupt::Compare0 => regs.intenset().write(|w| w.set_compare(0, true)), + Interrupt::Compare1 => regs.intenset().write(|w| w.set_compare(1, true)), + Interrupt::Compare2 => regs.intenset().write(|w| w.set_compare(2, true)), + Interrupt::Compare3 => regs.intenset().write(|w| w.set_compare(3, true)), + } + if enable_in_nvic { + unsafe { T::Interrupt::enable() }; + } + } + + /// Disables interrupts for the given [RtcInterrupt] source. + /// + /// Optionally also disables the interrupt in the NVIC. + pub fn disable_interrupt(&mut self, int: Interrupt, disable_in_nvic: bool) { + let regs = T::regs(); + match int { + Interrupt::Tick => regs.intenclr().write(|w| w.set_tick(true)), + Interrupt::Overflow => regs.intenclr().write(|w| w.set_ovrflw(true)), + Interrupt::Compare0 => regs.intenclr().write(|w| w.set_compare(0, true)), + Interrupt::Compare1 => regs.intenclr().write(|w| w.set_compare(1, true)), + Interrupt::Compare2 => regs.intenclr().write(|w| w.set_compare(2, true)), + Interrupt::Compare3 => regs.intenclr().write(|w| w.set_compare(3, true)), + } + if disable_in_nvic { + T::Interrupt::disable(); + } + } + + /// Enable the generation of a hardware event from a given stimulus. + pub fn enable_event(&mut self, evt: Interrupt) { + let regs = T::regs(); + match evt { + Interrupt::Tick => regs.evtenset().write(|w| w.set_tick(true)), + Interrupt::Overflow => regs.evtenset().write(|w| w.set_ovrflw(true)), + Interrupt::Compare0 => regs.evtenset().write(|w| w.set_compare(0, true)), + Interrupt::Compare1 => regs.evtenset().write(|w| w.set_compare(1, true)), + Interrupt::Compare2 => regs.evtenset().write(|w| w.set_compare(2, true)), + Interrupt::Compare3 => regs.evtenset().write(|w| w.set_compare(3, true)), + } + } + + /// Disable the generation of a hardware event from a given stimulus. + pub fn disable_event(&mut self, evt: Interrupt) { + let regs = T::regs(); + match evt { + Interrupt::Tick => regs.evtenclr().write(|w| w.set_tick(true)), + Interrupt::Overflow => regs.evtenclr().write(|w| w.set_ovrflw(true)), + Interrupt::Compare0 => regs.evtenclr().write(|w| w.set_compare(0, true)), + Interrupt::Compare1 => regs.evtenclr().write(|w| w.set_compare(1, true)), + Interrupt::Compare2 => regs.evtenclr().write(|w| w.set_compare(2, true)), + Interrupt::Compare3 => regs.evtenclr().write(|w| w.set_compare(3, true)), + } + } + + /// Resets the given event. + pub fn reset_event(&mut self, evt: Interrupt) { + let regs = T::regs(); + match evt { + Interrupt::Tick => regs.events_tick().write_value(0), + Interrupt::Overflow => regs.events_ovrflw().write_value(0), + Interrupt::Compare0 => regs.events_compare(0).write_value(0), + Interrupt::Compare1 => regs.events_compare(1).write_value(0), + Interrupt::Compare2 => regs.events_compare(2).write_value(0), + Interrupt::Compare3 => regs.events_compare(3).write_value(0), + } + } + + /// Checks if the given event has been triggered. + pub fn is_event_triggered(&self, evt: Interrupt) -> bool { + let regs = T::regs(); + let val = match evt { + Interrupt::Tick => regs.events_tick().read(), + Interrupt::Overflow => regs.events_ovrflw().read(), + Interrupt::Compare0 => regs.events_compare(0).read(), + Interrupt::Compare1 => regs.events_compare(1).read(), + Interrupt::Compare2 => regs.events_compare(2).read(), + Interrupt::Compare3 => regs.events_compare(3).read(), + }; + val == 1 + } + + /// Set the compare value of a given register. The compare registers have a width + /// of 24 bits. + pub fn set_compare(&mut self, reg: CompareChannel, val: u32) -> Result<(), CompareOutOfRangeError> { + if val >= (1 << 24) { + return Err(CompareOutOfRangeError(val)); + } + + let reg = match reg { + CompareChannel::_0 => 0, + CompareChannel::_1 => 1, + CompareChannel::_2 => 2, + CompareChannel::_3 => 3, + }; + + T::regs().cc(reg).write(|w| w.set_compare(val)); + Ok(()) + } + + /// Clear the Real Time Counter. + #[inline] + pub fn clear(&self) { + T::regs().tasks_clear().write_value(1); + } + + /// Obtain the current value of the Real Time Counter, 24 bits of range. + #[inline] + pub fn read(&self) -> u32 { + T::regs().counter().read().counter() + } + + /// Relase the RTC, returning the underlying peripheral instance. + #[inline] + pub fn release(self) -> Peri<'d, T> { + self.0 + } +} diff --git a/examples/nrf52840/Cargo.toml b/examples/nrf52840/Cargo.toml index 452e83b7e..ca3c6f863 100644 --- a/examples/nrf52840/Cargo.toml +++ b/examples/nrf52840/Cargo.toml @@ -35,6 +35,7 @@ embedded-hal-async = { version = "1.0" } embedded-hal-bus = { version = "0.1", features = ["async"] } num-integer = { version = "0.1.45", default-features = false } microfft = "0.5.0" +portable-atomic = "1" [profile.release] debug = 2 diff --git a/examples/nrf52840/src/bin/rtc.rs b/examples/nrf52840/src/bin/rtc.rs new file mode 100644 index 000000000..a3df7da14 --- /dev/null +++ b/examples/nrf52840/src/bin/rtc.rs @@ -0,0 +1,57 @@ +#![no_std] +#![no_main] + +use core::cell::RefCell; + +use embassy_executor::Spawner; +use embassy_nrf::gpio::{Level, Output, OutputDrive}; +use embassy_nrf::interrupt; +use embassy_nrf::rtc::Rtc; +use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex; +use embassy_sync::blocking_mutex::Mutex; +use portable_atomic::AtomicU64; +use {defmt_rtt as _, panic_probe as _}; + +// 64 bit counter which will never overflow. +static TICK_COUNTER: AtomicU64 = AtomicU64::new(0); +static RTC: Mutex>>> = + Mutex::new(RefCell::new(None)); + +#[embassy_executor::main] +async fn main(_spawner: Spawner) { + defmt::println!("nRF52840 RTC example"); + let p = embassy_nrf::init(Default::default()); + let mut led = Output::new(p.P0_13, Level::High, OutputDrive::Standard); + // Counter resolution is 125 ms. + let mut rtc = Rtc::new(p.RTC0, (1 << 12) - 1).unwrap(); + rtc.enable_interrupt(embassy_nrf::rtc::Interrupt::Tick, true); + rtc.enable_event(embassy_nrf::rtc::Interrupt::Tick); + rtc.enable(); + RTC.lock(|r| { + let mut rtc_borrow = r.borrow_mut(); + *rtc_borrow = Some(rtc); + }); + + let mut last_counter_val = 0; + loop { + let current = TICK_COUNTER.load(core::sync::atomic::Ordering::Relaxed); + if current != last_counter_val { + led.toggle(); + last_counter_val = current; + } + } +} + +#[interrupt] +fn RTC0() { + // For 64-bit, we do not need to worry about overflowing, at least not for realistic program + // lifetimes. + TICK_COUNTER.fetch_add(1, core::sync::atomic::Ordering::Relaxed); + RTC.lock(|r| { + let mut rtc_borrow = r.borrow_mut(); + rtc_borrow + .as_mut() + .unwrap() + .reset_event(embassy_nrf::rtc::Interrupt::Tick); + }); +} -- cgit From d1b55faace4b5059c726d94dd2d7f1ad3805ab48 Mon Sep 17 00:00:00 2001 From: Robin Mueller Date: Mon, 22 Sep 2025 00:43:02 +0200 Subject: code review changes --- embassy-nrf/src/chips/nrf51.rs | 2 ++ embassy-nrf/src/chips/nrf52805.rs | 4 +++- embassy-nrf/src/chips/nrf52810.rs | 2 ++ embassy-nrf/src/chips/nrf52811.rs | 2 ++ embassy-nrf/src/chips/nrf52820.rs | 2 ++ embassy-nrf/src/chips/nrf52832.rs | 2 ++ embassy-nrf/src/chips/nrf52833.rs | 2 ++ embassy-nrf/src/chips/nrf52840.rs | 2 ++ embassy-nrf/src/chips/nrf5340_app.rs | 2 ++ embassy-nrf/src/chips/nrf5340_net.rs | 2 ++ embassy-nrf/src/chips/nrf9120.rs | 2 ++ embassy-nrf/src/chips/nrf9160.rs | 2 ++ embassy-nrf/src/rtc.rs | 15 ++++----------- 13 files changed, 29 insertions(+), 12 deletions(-) diff --git a/embassy-nrf/src/chips/nrf51.rs b/embassy-nrf/src/chips/nrf51.rs index 393af4e75..3976e8ff0 100644 --- a/embassy-nrf/src/chips/nrf51.rs +++ b/embassy-nrf/src/chips/nrf51.rs @@ -8,6 +8,7 @@ pub const FLASH_SIZE: usize = 128 * 1024; embassy_hal_internal::peripherals! { // RTC RTC0, + #[cfg(not(feature = "time-driver-rtc1"))] RTC1, // WDT @@ -111,6 +112,7 @@ impl_timer!(TIMER2, TIMER2, TIMER2); impl_rng!(RNG, RNG, RNG); impl_rtc!(RTC0, RTC0, RTC0); +#[cfg(not(feature = "time-driver-rtc1"))] impl_rtc!(RTC1, RTC1, RTC1); impl_pin!(P0_00, 0, 0); diff --git a/embassy-nrf/src/chips/nrf52805.rs b/embassy-nrf/src/chips/nrf52805.rs index 427298a56..63ba6999a 100644 --- a/embassy-nrf/src/chips/nrf52805.rs +++ b/embassy-nrf/src/chips/nrf52805.rs @@ -12,6 +12,7 @@ pub const APPROTECT_MIN_BUILD_CODE: u8 = b'B'; embassy_hal_internal::peripherals! { // RTC RTC0, + #[cfg(not(feature="time-driver-rtc1"))] RTC1, // WDT @@ -157,6 +158,7 @@ impl_timer!(TIMER1, TIMER1, TIMER1); impl_timer!(TIMER2, TIMER2, TIMER2); impl_rtc!(RTC0, RTC0, RTC0); +#[cfg(not(feature = "time-driver-rtc1"))] impl_rtc!(RTC1, RTC1, RTC1); impl_pin!(P0_00, 0, 0); @@ -237,12 +239,12 @@ embassy_hal_internal::interrupt_mod!( TIMER0, TIMER1, TIMER2, - RTC0, TEMP, RNG, ECB, AAR_CCM, WDT, + RTC0, RTC1, QDEC, EGU0_SWI0, diff --git a/embassy-nrf/src/chips/nrf52810.rs b/embassy-nrf/src/chips/nrf52810.rs index c99b54265..7f744f9fb 100644 --- a/embassy-nrf/src/chips/nrf52810.rs +++ b/embassy-nrf/src/chips/nrf52810.rs @@ -12,6 +12,7 @@ pub const APPROTECT_MIN_BUILD_CODE: u8 = b'E'; embassy_hal_internal::peripherals! { // RTC RTC0, + #[cfg(not(feature="time-driver-rtc1"))] RTC1, // WDT @@ -167,6 +168,7 @@ impl_timer!(TIMER1, TIMER1, TIMER1); impl_timer!(TIMER2, TIMER2, TIMER2); impl_rtc!(RTC0, RTC0, RTC0); +#[cfg(not(feature = "time-driver-rtc1"))] impl_rtc!(RTC1, RTC1, RTC1); impl_pin!(P0_00, 0, 0); diff --git a/embassy-nrf/src/chips/nrf52811.rs b/embassy-nrf/src/chips/nrf52811.rs index 5f7a67f06..908167e31 100644 --- a/embassy-nrf/src/chips/nrf52811.rs +++ b/embassy-nrf/src/chips/nrf52811.rs @@ -12,6 +12,7 @@ pub const APPROTECT_MIN_BUILD_CODE: u8 = b'B'; embassy_hal_internal::peripherals! { // RTC RTC0, + #[cfg(not(feature="time-driver-rtc1"))] RTC1, // WDT @@ -169,6 +170,7 @@ impl_timer!(TIMER1, TIMER1, TIMER1); impl_timer!(TIMER2, TIMER2, TIMER2); impl_rtc!(RTC0, RTC0, RTC0); +#[cfg(not(feature = "time-driver-rtc1"))] impl_rtc!(RTC1, RTC1, RTC1); impl_pin!(P0_00, 0, 0); diff --git a/embassy-nrf/src/chips/nrf52820.rs b/embassy-nrf/src/chips/nrf52820.rs index 1677fcf02..22360575b 100644 --- a/embassy-nrf/src/chips/nrf52820.rs +++ b/embassy-nrf/src/chips/nrf52820.rs @@ -15,6 +15,7 @@ embassy_hal_internal::peripherals! { // RTC RTC0, + #[cfg(not(feature="time-driver-rtc1"))] RTC1, // WDT @@ -165,6 +166,7 @@ impl_timer!(TIMER2, TIMER2, TIMER2); impl_timer!(TIMER3, TIMER3, TIMER3, extended); impl_rtc!(RTC0, RTC0, RTC0); +#[cfg(not(feature = "time-driver-rtc1"))] impl_rtc!(RTC1, RTC1, RTC1); impl_qdec!(QDEC, QDEC, QDEC); diff --git a/embassy-nrf/src/chips/nrf52832.rs b/embassy-nrf/src/chips/nrf52832.rs index 6b735e218..1598df3fe 100644 --- a/embassy-nrf/src/chips/nrf52832.rs +++ b/embassy-nrf/src/chips/nrf52832.rs @@ -16,6 +16,7 @@ pub const APPROTECT_MIN_BUILD_CODE: u8 = b'G'; embassy_hal_internal::peripherals! { // RTC RTC0, + #[cfg(not(feature="time-driver-rtc1"))] RTC1, RTC2, @@ -183,6 +184,7 @@ impl_twis!(TWISPI0, TWIS0, TWISPI0); impl_twis!(TWISPI1, TWIS1, TWISPI1); impl_rtc!(RTC0, RTC0, RTC0); +#[cfg(not(feature = "time-driver-rtc1"))] impl_rtc!(RTC1, RTC1, RTC1); impl_rtc!(RTC2, RTC2, RTC2); diff --git a/embassy-nrf/src/chips/nrf52833.rs b/embassy-nrf/src/chips/nrf52833.rs index b9c75f54b..6931fb064 100644 --- a/embassy-nrf/src/chips/nrf52833.rs +++ b/embassy-nrf/src/chips/nrf52833.rs @@ -15,6 +15,7 @@ embassy_hal_internal::peripherals! { // RTC RTC0, + #[cfg(not(feature = "time-driver-rtc1"))] RTC1, RTC2, @@ -224,6 +225,7 @@ impl_timer!(TIMER3, TIMER3, TIMER3, extended); impl_timer!(TIMER4, TIMER4, TIMER4, extended); impl_rtc!(RTC0, RTC0, RTC0); +#[cfg(not(feature = "time-driver-rtc1"))] impl_rtc!(RTC1, RTC1, RTC1); impl_rtc!(RTC2, RTC2, RTC2); diff --git a/embassy-nrf/src/chips/nrf52840.rs b/embassy-nrf/src/chips/nrf52840.rs index ccfa1f747..5fa521aae 100644 --- a/embassy-nrf/src/chips/nrf52840.rs +++ b/embassy-nrf/src/chips/nrf52840.rs @@ -15,6 +15,7 @@ embassy_hal_internal::peripherals! { // RTC RTC0, + #[cfg(not(feature = "time-driver-rtc1"))] RTC1, RTC2, @@ -221,6 +222,7 @@ impl_timer!(TIMER3, TIMER3, TIMER3, extended); impl_timer!(TIMER4, TIMER4, TIMER4, extended); impl_rtc!(RTC0, RTC0, RTC0); +#[cfg(not(feature = "time-driver-rtc1"))] impl_rtc!(RTC1, RTC1, RTC1); impl_rtc!(RTC2, RTC2, RTC2); diff --git a/embassy-nrf/src/chips/nrf5340_app.rs b/embassy-nrf/src/chips/nrf5340_app.rs index eb429db21..730c9842d 100644 --- a/embassy-nrf/src/chips/nrf5340_app.rs +++ b/embassy-nrf/src/chips/nrf5340_app.rs @@ -168,6 +168,7 @@ embassy_hal_internal::peripherals! { // RTC RTC0, + #[cfg(not(feature = "time-driver-rtc1"))] RTC1, // WDT @@ -370,6 +371,7 @@ impl_timer!(TIMER1, TIMER1, TIMER1); impl_timer!(TIMER2, TIMER2, TIMER2); impl_rtc!(RTC0, RTC0, RTC0); +#[cfg(not(feature = "time-driver-rtc1"))] impl_rtc!(RTC1, RTC1, RTC1); impl_qspi!(QSPI, QSPI, QSPI); diff --git a/embassy-nrf/src/chips/nrf5340_net.rs b/embassy-nrf/src/chips/nrf5340_net.rs index a8de288a9..413afc5c5 100644 --- a/embassy-nrf/src/chips/nrf5340_net.rs +++ b/embassy-nrf/src/chips/nrf5340_net.rs @@ -59,6 +59,7 @@ pub const FLASH_SIZE: usize = 256 * 1024; embassy_hal_internal::peripherals! { // RTC RTC0, + #[cfg(not(feature = "time-driver-rtc1"))] RTC1, // WDT @@ -219,6 +220,7 @@ impl_timer!(TIMER1, TIMER1, TIMER1); impl_timer!(TIMER2, TIMER2, TIMER2); impl_rtc!(RTC0, RTC0, RTC0); +#[cfg(not(feature = "time-driver-rtc1"))] impl_rtc!(RTC1, RTC1, RTC1); impl_rng!(RNG, RNG, RNG); diff --git a/embassy-nrf/src/chips/nrf9120.rs b/embassy-nrf/src/chips/nrf9120.rs index 9008a23a8..5aee19d97 100644 --- a/embassy-nrf/src/chips/nrf9120.rs +++ b/embassy-nrf/src/chips/nrf9120.rs @@ -131,6 +131,7 @@ pub const FLASH_SIZE: usize = 1024 * 1024; embassy_hal_internal::peripherals! { // RTC RTC0, + #[cfg(not(feature = "time-driver-rtc1"))] RTC1, // WDT @@ -277,6 +278,7 @@ impl_timer!(TIMER1, TIMER1, TIMER1); impl_timer!(TIMER2, TIMER2, TIMER2); impl_rtc!(RTC0, RTC0, RTC0); +#[cfg(not(feature = "time-driver-rtc1"))] impl_rtc!(RTC1, RTC1, RTC1); impl_pin!(P0_00, 0, 0); diff --git a/embassy-nrf/src/chips/nrf9160.rs b/embassy-nrf/src/chips/nrf9160.rs index dbb06d71a..64aec217c 100644 --- a/embassy-nrf/src/chips/nrf9160.rs +++ b/embassy-nrf/src/chips/nrf9160.rs @@ -131,6 +131,7 @@ pub const FLASH_SIZE: usize = 1024 * 1024; embassy_hal_internal::peripherals! { // RTC RTC0, + #[cfg(not(feature = "time-driver-rtc1"))] RTC1, // WDT @@ -277,6 +278,7 @@ impl_timer!(TIMER1, TIMER1, TIMER1); impl_timer!(TIMER2, TIMER2, TIMER2); impl_rtc!(RTC0, RTC0, RTC0); +#[cfg(not(feature = "time-driver-rtc1"))] impl_rtc!(RTC1, RTC1, RTC1); impl_pin!(P0_00, 0, 0); diff --git a/embassy-nrf/src/rtc.rs b/embassy-nrf/src/rtc.rs index 5dd427fde..1a90d1e24 100644 --- a/embassy-nrf/src/rtc.rs +++ b/embassy-nrf/src/rtc.rs @@ -17,11 +17,6 @@ pub struct PrescalerOutOfRangeError(u32); #[cfg_attr(feature = "defmt", derive(defmt::Format))] pub struct CompareOutOfRangeError(u32); -/// Compare register is not implemented for RTC0. -#[derive(Debug, PartialEq, Eq)] -#[cfg_attr(feature = "defmt", derive(defmt::Format))] -pub struct CompareRegNotImplementedError; - /// Interrupts/Events that can be generated by the RTCn peripheral. #[derive(Debug, Copy, Clone, PartialEq, Eq)] #[cfg_attr(feature = "defmt", derive(defmt::Format))] @@ -93,15 +88,12 @@ macro_rules! impl_rtc { } /// nRF RTC driver. -/// -/// If the `time-driver-rtc1` feature is enabled, the creation of a driver with RTC1 will conflict -/// with the time driver implementation. pub struct Rtc<'d, T: Instance>(Peri<'d, T>); impl<'d, T: Instance> Rtc<'d, T> { /// Create a new `Rtc` driver. /// - /// fRTC = 32_768 / (`prescaler` + 1 ) + /// fRTC \[Hz\] = 32_768 / (`prescaler` + 1 ) pub fn new(rtc: Peri<'d, T>, prescaler: u32) -> Result { if prescaler >= (1 << 12) { return Err(PrescalerOutOfRangeError(prescaler)); @@ -128,6 +120,7 @@ impl<'d, T: Instance> Rtc<'d, T> { } /// Direct access to the RTC registers. + #[cfg(feature = "unstable-pac")] #[inline] pub fn regs(&mut self) -> pac::rtc::Rtc { T::regs() @@ -145,7 +138,7 @@ impl<'d, T: Instance> Rtc<'d, T> { T::regs().tasks_stop().write_value(1); } - /// Enables interrupts for the given [RtcInterrupt] source. + /// Enables interrupts for the given [Interrupt] source. /// /// Optionally also enables the interrupt in the NVIC. pub fn enable_interrupt(&mut self, int: Interrupt, enable_in_nvic: bool) { @@ -163,7 +156,7 @@ impl<'d, T: Instance> Rtc<'d, T> { } } - /// Disables interrupts for the given [RtcInterrupt] source. + /// Disables interrupts for the given [Interrupt] source. /// /// Optionally also disables the interrupt in the NVIC. pub fn disable_interrupt(&mut self, int: Interrupt, disable_in_nvic: bool) { -- cgit From fd1c1635419f8281edda3892f08a91f0e315667a Mon Sep 17 00:00:00 2001 From: Dario Nieuwenhuis Date: Mon, 22 Sep 2025 00:32:50 +0200 Subject: ci: add cargo manifest check --- .github/ci/build-nightly.sh | 2 +- .github/ci/build-xtensa.sh | 2 +- .github/ci/build.sh | 2 +- .github/ci/crlf.sh | 17 ----------------- .github/ci/janitor.sh | 15 +++++++++++++++ 5 files changed, 18 insertions(+), 20 deletions(-) delete mode 100755 .github/ci/crlf.sh create mode 100755 .github/ci/janitor.sh diff --git a/.github/ci/build-nightly.sh b/.github/ci/build-nightly.sh index 2d7c4db3f..801d470a1 100755 --- a/.github/ci/build-nightly.sh +++ b/.github/ci/build-nightly.sh @@ -23,7 +23,7 @@ fi hashtime restore /ci/cache/filetime.json || true hashtime save /ci/cache/filetime.json -cargo install --git https://github.com/embassy-rs/cargo-embassy-devtool --locked --rev 280829ad163f1444999468a57d28fb7c412babbe +cargo install --git https://github.com/embassy-rs/cargo-embassy-devtool --locked --rev 2357881abb81a0a3672ff992e199963f9f63bb10 ./ci-nightly.sh diff --git a/.github/ci/build-xtensa.sh b/.github/ci/build-xtensa.sh index b6626639d..1a97b21b1 100755 --- a/.github/ci/build-xtensa.sh +++ b/.github/ci/build-xtensa.sh @@ -25,7 +25,7 @@ fi hashtime restore /ci/cache/filetime.json || true hashtime save /ci/cache/filetime.json -cargo install --git https://github.com/embassy-rs/cargo-embassy-devtool --locked --rev 280829ad163f1444999468a57d28fb7c412babbe +cargo install --git https://github.com/embassy-rs/cargo-embassy-devtool --locked --rev 2357881abb81a0a3672ff992e199963f9f63bb10 ./ci-xtensa.sh diff --git a/.github/ci/build.sh b/.github/ci/build.sh index 59bcefed6..72ffa9f1b 100755 --- a/.github/ci/build.sh +++ b/.github/ci/build.sh @@ -28,7 +28,7 @@ fi hashtime restore /ci/cache/filetime.json || true hashtime save /ci/cache/filetime.json -cargo install --git https://github.com/embassy-rs/cargo-embassy-devtool --locked --rev 280829ad163f1444999468a57d28fb7c412babbe +cargo install --git https://github.com/embassy-rs/cargo-embassy-devtool --locked --rev 2357881abb81a0a3672ff992e199963f9f63bb10 ./ci.sh diff --git a/.github/ci/crlf.sh b/.github/ci/crlf.sh deleted file mode 100755 index 69838ce88..000000000 --- a/.github/ci/crlf.sh +++ /dev/null @@ -1,17 +0,0 @@ -#!/bin/bash -## on push branch~=gh-readonly-queue/main/.* -## on pull_request - -set -euo pipefail - -FILES_WITH_CRLF=$(find ! -path "./.git/*" -not -type d | xargs file -N | (grep " CRLF " || true)) - -if [ -z "$FILES_WITH_CRLF" ]; then - echo -e "No files with CRLF endings found." - exit 0 -else - NR_FILES=$(echo "$FILES_WITH_CRLF" | wc -l) - echo -e "ERROR: Found ${NR_FILES} files with CRLF endings." - echo "$FILES_WITH_CRLF" - exit "$NR_FILES" -fi diff --git a/.github/ci/janitor.sh b/.github/ci/janitor.sh new file mode 100755 index 000000000..58ecb8475 --- /dev/null +++ b/.github/ci/janitor.sh @@ -0,0 +1,15 @@ +#!/bin/bash +## on push branch~=gh-readonly-queue/main/.* +## on pull_request + +set -euo pipefail + +export RUSTUP_HOME=/ci/cache/rustup +export CARGO_HOME=/ci/cache/cargo +export CARGO_TARGET_DIR=/ci/cache/target +export PATH=$CARGO_HOME/bin:$PATH + +cargo install --git https://github.com/embassy-rs/cargo-embassy-devtool --locked --rev 2357881abb81a0a3672ff992e199963f9f63bb10 + +cargo embassy-devtool check-crlf +cargo embassy-devtool check-manifest -- cgit From 4d71f432ad05cd8cce50b13cf6de6a1422f3b401 Mon Sep 17 00:00:00 2001 From: Dario Nieuwenhuis Date: Mon, 22 Sep 2025 00:47:08 +0200 Subject: Update manifests to satisfy new checks. --- cyw43-pio/Cargo.toml | 3 +++ embassy-boot-nrf/Cargo.toml | 3 ++- embassy-boot/Cargo.toml | 2 ++ embassy-embedded-hal/Cargo.toml | 1 + embassy-executor/Cargo.toml | 6 ++++++ embassy-futures/Cargo.toml | 4 ++++ embassy-hal-internal/Cargo.toml | 3 +++ embassy-imxrt/Cargo.toml | 2 +- embassy-net-driver-channel/Cargo.toml | 4 ++++ embassy-net-driver/Cargo.toml | 3 +++ embassy-net-enc28j60/Cargo.toml | 4 ++++ embassy-net-wiznet/Cargo.toml | 3 +++ embassy-net/Cargo.toml | 2 ++ embassy-nrf/Cargo.toml | 2 ++ embassy-nxp/Cargo.toml | 1 + embassy-rp/Cargo.toml | 4 ++++ embassy-stm32/Cargo.toml | 4 ++++ embassy-sync/Cargo.toml | 2 ++ embassy-time/Cargo.toml | 5 +++++ embassy-usb-dfu/Cargo.toml | 3 +++ embassy-usb-driver/Cargo.toml | 3 +++ embassy-usb-synopsys-otg/Cargo.toml | 4 ++++ embassy-usb/Cargo.toml | 1 + examples/mimxrt1011/Cargo.toml | 2 +- examples/mimxrt1062-evk/Cargo.toml | 2 +- examples/mimxrt6/Cargo.toml | 2 +- tests/perf-client/Cargo.toml | 1 + tests/perf-server/Cargo.toml | 1 + tests/utils/Cargo.toml | 1 + 29 files changed, 73 insertions(+), 5 deletions(-) diff --git a/cyw43-pio/Cargo.toml b/cyw43-pio/Cargo.toml index 40dd02f61..6ab5c453e 100644 --- a/cyw43-pio/Cargo.toml +++ b/cyw43-pio/Cargo.toml @@ -15,6 +15,9 @@ embassy-rp = { version = "0.8.0", path = "../embassy-rp" } fixed = "1.23.1" defmt = { version = "1.0.1", optional = true } +[features] +defmt = ["dep:defmt"] + [package.metadata.embassy] build = [ {target = "thumbv6m-none-eabi", features = ["embassy-rp/rp2040"]}, diff --git a/embassy-boot-nrf/Cargo.toml b/embassy-boot-nrf/Cargo.toml index 3b631ef0c..49dff061a 100644 --- a/embassy-boot-nrf/Cargo.toml +++ b/embassy-boot-nrf/Cargo.toml @@ -52,6 +52,7 @@ defmt = [ "embassy-boot/defmt", "embassy-nrf/defmt", ] +log = ["dep:log"] softdevice = [ - "nrf-softdevice-mbr", + "dep:nrf-softdevice-mbr", ] diff --git a/embassy-boot/Cargo.toml b/embassy-boot/Cargo.toml index ed0242c13..a18438c81 100644 --- a/embassy-boot/Cargo.toml +++ b/embassy-boot/Cargo.toml @@ -45,6 +45,8 @@ critical-section = { version = "1.1.1", features = ["std"] } ed25519-dalek = { version = "2", default-features = false, features = ["std", "rand_core", "digest"] } [features] +defmt = ["dep:defmt"] +log = ["dep:log"] ed25519-dalek = ["dep:ed25519-dalek", "_verify"] ed25519-salty = ["dep:salty", "_verify"] flash-erase-zero = [] diff --git a/embassy-embedded-hal/Cargo.toml b/embassy-embedded-hal/Cargo.toml index a66e01717..8b8122567 100644 --- a/embassy-embedded-hal/Cargo.toml +++ b/embassy-embedded-hal/Cargo.toml @@ -25,6 +25,7 @@ src_base_git = "https://github.com/embassy-rs/embassy/blob/$COMMIT/embassy-embed target = "x86_64-unknown-linux-gnu" [features] +defmt = ["dep:defmt"] time = ["dep:embassy-time"] [dependencies] diff --git a/embassy-executor/Cargo.toml b/embassy-executor/Cargo.toml index f6dce5c0e..61d060630 100644 --- a/embassy-executor/Cargo.toml +++ b/embassy-executor/Cargo.toml @@ -123,6 +123,12 @@ rustversion = "1.0.21" ## Enable nightly-only features nightly = ["embassy-executor-macros/nightly"] +## Enable defmt logging +defmt = ["dep:defmt"] + +## Enable log logging +log = ["dep:log"] + # Enables turbo wakers, which requires patching core. Not surfaced in the docs by default due to # being an complicated advanced and undocumented feature. # See: https://github.com/embassy-rs/embassy/pull/1263 diff --git a/embassy-futures/Cargo.toml b/embassy-futures/Cargo.toml index 2d62b28e5..07d5219cf 100644 --- a/embassy-futures/Cargo.toml +++ b/embassy-futures/Cargo.toml @@ -26,3 +26,7 @@ features = ["defmt"] [dependencies] defmt = { version = "1.0.1", optional = true } log = { version = "0.4.14", optional = true } + +[features] +defmt = ["dep:defmt"] +log = ["dep:log"] diff --git a/embassy-hal-internal/Cargo.toml b/embassy-hal-internal/Cargo.toml index b4c52ccfa..11dcc2466 100644 --- a/embassy-hal-internal/Cargo.toml +++ b/embassy-hal-internal/Cargo.toml @@ -14,6 +14,9 @@ categories = [ [features] +defmt = ["dep:defmt"] +log = ["dep:log"] + # Define the number of NVIC priority bits. prio-bits-0 = [] prio-bits-1 = [] diff --git a/embassy-imxrt/Cargo.toml b/embassy-imxrt/Cargo.toml index 8a9c1252e..7561640dd 100644 --- a/embassy-imxrt/Cargo.toml +++ b/embassy-imxrt/Cargo.toml @@ -2,7 +2,7 @@ name = "embassy-imxrt" version = "0.1.0" edition = "2021" -license = "MIT" +license = "MIT OR Apache-2.0" description = "Embassy Hardware Abstraction Layer (HAL) for the IMXRT microcontroller" keywords = ["embedded", "async", "imxrt", "rt600", "embedded-hal"] categories = ["embedded", "hardware-support", "no-std", "asynchronous"] diff --git a/embassy-net-driver-channel/Cargo.toml b/embassy-net-driver-channel/Cargo.toml index cf498c59f..1e40c2d87 100644 --- a/embassy-net-driver-channel/Cargo.toml +++ b/embassy-net-driver-channel/Cargo.toml @@ -28,3 +28,7 @@ log = { version = "0.4.14", optional = true } embassy-sync = { version = "0.7.2", path = "../embassy-sync" } embassy-futures = { version = "0.1.2", path = "../embassy-futures" } embassy-net-driver = { version = "0.2.0", path = "../embassy-net-driver" } + +[features] +defmt = ["dep:defmt"] +log = ["dep:log"] diff --git a/embassy-net-driver/Cargo.toml b/embassy-net-driver/Cargo.toml index 34bc6c91a..a36e412ad 100644 --- a/embassy-net-driver/Cargo.toml +++ b/embassy-net-driver/Cargo.toml @@ -23,3 +23,6 @@ features = ["defmt"] [dependencies] defmt = { version = "1.0.1", optional = true } + +[features] +defmt = ["dep:defmt"] diff --git a/embassy-net-enc28j60/Cargo.toml b/embassy-net-enc28j60/Cargo.toml index a3e3285a3..e7bad118b 100644 --- a/embassy-net-enc28j60/Cargo.toml +++ b/embassy-net-enc28j60/Cargo.toml @@ -19,6 +19,10 @@ embassy-futures = { version = "0.1.2", path = "../embassy-futures" } defmt = { version = "1.0.1", optional = true } log = { version = "0.4.14", optional = true } +[features] +defmt = ["dep:defmt", "embassy-net-driver/defmt"] +log = ["dep:log"] + [package.metadata.embassy_docs] src_base = "https://github.com/embassy-rs/embassy/blob/embassy-net-enc28j60-v$VERSION/embassy-net-enc28j60/src/" src_base_git = "https://github.com/embassy-rs/embassy/blob/$COMMIT/embassy-net-enc28j60/src/" diff --git a/embassy-net-wiznet/Cargo.toml b/embassy-net-wiznet/Cargo.toml index 36c349df1..6e6dccebd 100644 --- a/embassy-net-wiznet/Cargo.toml +++ b/embassy-net-wiznet/Cargo.toml @@ -17,6 +17,9 @@ embassy-time = { version = "0.5.0", path = "../embassy-time" } embassy-futures = { version = "0.1.2", path = "../embassy-futures" } defmt = { version = "1.0.1", optional = true } +[features] +defmt = ["dep:defmt", "embassy-net-driver-channel/defmt"] + [package.metadata.embassy_docs] src_base = "https://github.com/embassy-rs/embassy/blob/embassy-net-wiznet-v$VERSION/embassy-net-wiznet/src/" src_base_git = "https://github.com/embassy-rs/embassy/blob/$COMMIT/embassy-net-wiznet/src/" diff --git a/embassy-net/Cargo.toml b/embassy-net/Cargo.toml index 61a2c858a..31ce7e9a6 100644 --- a/embassy-net/Cargo.toml +++ b/embassy-net/Cargo.toml @@ -53,6 +53,8 @@ features = ["defmt", "tcp", "udp", "raw", "dns", "icmp", "dhcpv4", "proto-ipv6", [features] ## Enable defmt defmt = ["dep:defmt", "smoltcp/defmt", "embassy-net-driver/defmt", "embassy-time/defmt", "heapless/defmt-03", "defmt?/ip_in_core"] +## Enable log +log = ["dep:log"] ## Trace all raw received and transmitted packets using defmt or log. packet-trace = [] diff --git a/embassy-nrf/Cargo.toml b/embassy-nrf/Cargo.toml index 4afd28fbd..1af633500 100644 --- a/embassy-nrf/Cargo.toml +++ b/embassy-nrf/Cargo.toml @@ -66,6 +66,8 @@ time = ["dep:embassy-time", "embassy-embedded-hal/time"] ## Enable defmt defmt = ["dep:defmt", "embassy-hal-internal/defmt", "embassy-sync/defmt", "embassy-usb-driver/defmt", "embassy-embedded-hal/defmt"] +## Enable log +log = ["dep:log"] ## Reexport the PAC for the currently enabled chip at `embassy_nrf::pac` (unstable) unstable-pac = [] diff --git a/embassy-nxp/Cargo.toml b/embassy-nxp/Cargo.toml index 455915f29..073fdabe4 100644 --- a/embassy-nxp/Cargo.toml +++ b/embassy-nxp/Cargo.toml @@ -2,6 +2,7 @@ name = "embassy-nxp" version = "0.1.0" edition = "2021" +license = "MIT OR Apache-2.0" publish = false diff --git a/embassy-rp/Cargo.toml b/embassy-rp/Cargo.toml index 101914a36..f6b0900f2 100644 --- a/embassy-rp/Cargo.toml +++ b/embassy-rp/Cargo.toml @@ -45,6 +45,10 @@ rt = [ "rp-pac/rt" ] ## Enable [defmt support](https://docs.rs/defmt) and enables `defmt` debug-log messages and formatting in embassy drivers. defmt = ["dep:defmt", "embassy-usb-driver/defmt", "embassy-hal-internal/defmt"] +## Enable log support +log = ["dep:log"] +## Enable chrono support +chrono = ["dep:chrono"] ## Configure the [`critical-section`](https://docs.rs/critical-section) crate to use an implementation that is safe for multicore use on rp2040. critical-section-impl = ["critical-section/restore-state-u8"] diff --git a/embassy-stm32/Cargo.toml b/embassy-stm32/Cargo.toml index 6cd8ed262..369fabc50 100644 --- a/embassy-stm32/Cargo.toml +++ b/embassy-stm32/Cargo.toml @@ -225,6 +225,10 @@ defmt = [ "embassy-usb-synopsys-otg/defmt", "stm32-metapac/defmt" ] +## Use log for logging +log = ["dep:log"] +## Enable chrono support +chrono = ["dep:chrono"] exti = [] low-power = [ "dep:embassy-executor", "embassy-executor?/arch-cortex-m", "time" ] diff --git a/embassy-sync/Cargo.toml b/embassy-sync/Cargo.toml index 6494da727..64d76baba 100644 --- a/embassy-sync/Cargo.toml +++ b/embassy-sync/Cargo.toml @@ -27,6 +27,8 @@ src_base_git = "https://github.com/embassy-rs/embassy/blob/$COMMIT/embassy-sync/ target = "thumbv7em-none-eabi" [features] +defmt = ["dep:defmt"] +log = ["dep:log"] std = [] turbowakers = [] diff --git a/embassy-time/Cargo.toml b/embassy-time/Cargo.toml index 2d7c3c1fa..bad6ecf97 100644 --- a/embassy-time/Cargo.toml +++ b/embassy-time/Cargo.toml @@ -31,6 +31,11 @@ target = "x86_64-unknown-linux-gnu" features = ["defmt", "std"] [features] +## Enable defmt +defmt = ["dep:defmt"] +## Enable log +log = ["dep:log"] + ## Display the time since startup next to defmt log messages. ## At most 1 `defmt-timestamp-uptime-*` feature can be used. ## `defmt-timestamp-uptime` is provided for backwards compatibility (provides the same format as `uptime-us`). diff --git a/embassy-usb-dfu/Cargo.toml b/embassy-usb-dfu/Cargo.toml index 4a65c6895..e70ab970e 100644 --- a/embassy-usb-dfu/Cargo.toml +++ b/embassy-usb-dfu/Cargo.toml @@ -49,6 +49,9 @@ esp32c3-hal = { version = "0.13.0", optional = true, default-features = false } dfu = [] application = [] defmt = ["dep:defmt", "embassy-boot/defmt", "embassy-usb/defmt"] +log = ["dep:log"] +cortex-m = ["dep:cortex-m"] +esp32c3-hal = ["dep:esp32c3-hal"] ed25519-dalek = ["embassy-boot/ed25519-dalek", "_verify"] ed25519-salty = ["embassy-boot/ed25519-salty", "_verify"] diff --git a/embassy-usb-driver/Cargo.toml b/embassy-usb-driver/Cargo.toml index de69bf694..6e4c31273 100644 --- a/embassy-usb-driver/Cargo.toml +++ b/embassy-usb-driver/Cargo.toml @@ -21,3 +21,6 @@ features = ["defmt"] [dependencies] embedded-io-async = "0.6.1" defmt = { version = "1", optional = true } + +[features] +defmt = ["dep:defmt"] diff --git a/embassy-usb-synopsys-otg/Cargo.toml b/embassy-usb-synopsys-otg/Cargo.toml index ec518ac93..61b14a215 100644 --- a/embassy-usb-synopsys-otg/Cargo.toml +++ b/embassy-usb-synopsys-otg/Cargo.toml @@ -23,3 +23,7 @@ embassy-usb-driver = { version = "0.2.0", path = "../embassy-usb-driver" } defmt = { version = "1.0.1", optional = true } log = { version = "0.4.14", optional = true } + +[features] +defmt = ["dep:defmt", "embassy-usb-driver/defmt"] +log = ["dep:log"] diff --git a/embassy-usb/Cargo.toml b/embassy-usb/Cargo.toml index e309eec93..bff48c4a6 100644 --- a/embassy-usb/Cargo.toml +++ b/embassy-usb/Cargo.toml @@ -31,6 +31,7 @@ features = ["defmt", "usbd-hid"] [features] defmt = ["dep:defmt", "embassy-usb-driver/defmt"] +log = ["dep:log"] usbd-hid = ["dep:usbd-hid", "dep:ssmarshal"] default = ["usbd-hid"] diff --git a/examples/mimxrt1011/Cargo.toml b/examples/mimxrt1011/Cargo.toml index 488f3167b..3038f5d4d 100644 --- a/examples/mimxrt1011/Cargo.toml +++ b/examples/mimxrt1011/Cargo.toml @@ -2,7 +2,7 @@ name = "embassy-imxrt1011-examples" version = "0.1.0" edition = "2021" -license = "MIT or Apache-2.0" +license = "MIT OR Apache-2.0" publish = false [dependencies] diff --git a/examples/mimxrt1062-evk/Cargo.toml b/examples/mimxrt1062-evk/Cargo.toml index ec6c5c872..82a24490d 100644 --- a/examples/mimxrt1062-evk/Cargo.toml +++ b/examples/mimxrt1062-evk/Cargo.toml @@ -2,7 +2,7 @@ name = "embassy-imxrt1062-evk-examples" version = "0.1.0" edition = "2021" -license = "MIT or Apache-2.0" +license = "MIT OR Apache-2.0" publish = false [dependencies] diff --git a/examples/mimxrt6/Cargo.toml b/examples/mimxrt6/Cargo.toml index 28de9d273..3f7ad8485 100644 --- a/examples/mimxrt6/Cargo.toml +++ b/examples/mimxrt6/Cargo.toml @@ -2,7 +2,7 @@ name = "embassy-imxrt-examples" version = "0.1.0" edition = "2021" -license = "MIT or Apache-2.0" +license = "MIT OR Apache-2.0" publish = false [dependencies] diff --git a/tests/perf-client/Cargo.toml b/tests/perf-client/Cargo.toml index 581b60d6f..c426fdd74 100644 --- a/tests/perf-client/Cargo.toml +++ b/tests/perf-client/Cargo.toml @@ -2,6 +2,7 @@ name = "perf-client" version = "0.1.0" edition = "2021" +license = "MIT OR Apache-2.0" publish = false [dependencies] diff --git a/tests/perf-server/Cargo.toml b/tests/perf-server/Cargo.toml index 22614a33a..f048eade2 100644 --- a/tests/perf-server/Cargo.toml +++ b/tests/perf-server/Cargo.toml @@ -2,6 +2,7 @@ name = "perf-server" version = "0.1.0" edition = "2021" +license = "MIT OR Apache-2.0" publish = false [dependencies] diff --git a/tests/utils/Cargo.toml b/tests/utils/Cargo.toml index f76feaa20..ddb990e0f 100644 --- a/tests/utils/Cargo.toml +++ b/tests/utils/Cargo.toml @@ -2,6 +2,7 @@ name = "test-utils" version = "0.1.0" edition = "2021" +license = "MIT OR Apache-2.0" publish = false [dependencies] -- cgit From 27df9288f343c2855d1daec00d127541826d664f Mon Sep 17 00:00:00 2001 From: Dario Nieuwenhuis Date: Mon, 22 Sep 2025 00:56:14 +0200 Subject: aaaaaa --- .github/ci/build-nightly.sh | 2 +- .github/ci/build-xtensa.sh | 2 +- .github/ci/build.sh | 2 +- .github/ci/janitor.sh | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/ci/build-nightly.sh b/.github/ci/build-nightly.sh index 801d470a1..257d7ebd3 100755 --- a/.github/ci/build-nightly.sh +++ b/.github/ci/build-nightly.sh @@ -23,7 +23,7 @@ fi hashtime restore /ci/cache/filetime.json || true hashtime save /ci/cache/filetime.json -cargo install --git https://github.com/embassy-rs/cargo-embassy-devtool --locked --rev 2357881abb81a0a3672ff992e199963f9f63bb10 +cargo install --git https://github.com/embassy-rs/cargo-embassy-devtool --locked --rev 3ca80f7065acbe0b69b7da463fab60e744f9de79 ./ci-nightly.sh diff --git a/.github/ci/build-xtensa.sh b/.github/ci/build-xtensa.sh index 1a97b21b1..339e28467 100755 --- a/.github/ci/build-xtensa.sh +++ b/.github/ci/build-xtensa.sh @@ -25,7 +25,7 @@ fi hashtime restore /ci/cache/filetime.json || true hashtime save /ci/cache/filetime.json -cargo install --git https://github.com/embassy-rs/cargo-embassy-devtool --locked --rev 2357881abb81a0a3672ff992e199963f9f63bb10 +cargo install --git https://github.com/embassy-rs/cargo-embassy-devtool --locked --rev 3ca80f7065acbe0b69b7da463fab60e744f9de79 ./ci-xtensa.sh diff --git a/.github/ci/build.sh b/.github/ci/build.sh index 72ffa9f1b..d7201aedb 100755 --- a/.github/ci/build.sh +++ b/.github/ci/build.sh @@ -28,7 +28,7 @@ fi hashtime restore /ci/cache/filetime.json || true hashtime save /ci/cache/filetime.json -cargo install --git https://github.com/embassy-rs/cargo-embassy-devtool --locked --rev 2357881abb81a0a3672ff992e199963f9f63bb10 +cargo install --git https://github.com/embassy-rs/cargo-embassy-devtool --locked --rev 3ca80f7065acbe0b69b7da463fab60e744f9de79 ./ci.sh diff --git a/.github/ci/janitor.sh b/.github/ci/janitor.sh index 58ecb8475..bd04f47fc 100755 --- a/.github/ci/janitor.sh +++ b/.github/ci/janitor.sh @@ -9,7 +9,7 @@ export CARGO_HOME=/ci/cache/cargo export CARGO_TARGET_DIR=/ci/cache/target export PATH=$CARGO_HOME/bin:$PATH -cargo install --git https://github.com/embassy-rs/cargo-embassy-devtool --locked --rev 2357881abb81a0a3672ff992e199963f9f63bb10 +cargo install --git https://github.com/embassy-rs/cargo-embassy-devtool --locked --rev 3ca80f7065acbe0b69b7da463fab60e744f9de79 cargo embassy-devtool check-crlf cargo embassy-devtool check-manifest -- cgit From 54a95927f054dd7229fd5e26c3acee509f71c82f Mon Sep 17 00:00:00 2001 From: Dario Nieuwenhuis Date: Mon, 22 Sep 2025 00:56:34 +0200 Subject: ci: use devtool to build docs. --- .github/ci/doc.sh | 54 +++--------------------------------------------------- 1 file changed, 3 insertions(+), 51 deletions(-) diff --git a/.github/ci/doc.sh b/.github/ci/doc.sh index 876c261a1..70ce110d1 100755 --- a/.github/ci/doc.sh +++ b/.github/ci/doc.sh @@ -9,62 +9,14 @@ set -euxo pipefail export RUSTUP_HOME=/ci/cache/rustup export CARGO_HOME=/ci/cache/cargo export CARGO_TARGET_DIR=/ci/cache/target -export BUILDER_THREADS=4 -export BUILDER_COMPRESS=true +export PATH=$CARGO_HOME/bin:$PATH mv rust-toolchain-nightly.toml rust-toolchain.toml -# force rustup to download the toolchain before starting building. -# Otherwise, the docs builder is running multiple instances of cargo rustdoc concurrently. -# They all see the toolchain is not installed and try to install it in parallel -# which makes rustup very sad -rustc --version > /dev/null +cargo install --git https://github.com/embassy-rs/cargo-embassy-devtool --locked --rev 3ca80f7065acbe0b69b7da463fab60e744f9de79 -docserver build -i ./embassy-boot -o webroot/crates/embassy-boot/git.zup -docserver build -i ./embassy-boot-nrf -o webroot/crates/embassy-boot-nrf/git.zup -docserver build -i ./embassy-boot-rp -o webroot/crates/embassy-boot-rp/git.zup -docserver build -i ./embassy-boot-stm32 -o webroot/crates/embassy-boot-stm32/git.zup -docserver build -i ./embassy-embedded-hal -o webroot/crates/embassy-embedded-hal/git.zup -docserver build -i ./embassy-executor -o webroot/crates/embassy-executor/git.zup -docserver build -i ./embassy-futures -o webroot/crates/embassy-futures/git.zup -docserver build -i ./embassy-nrf -o webroot/crates/embassy-nrf/git.zup -docserver build -i ./embassy-rp -o webroot/crates/embassy-rp/git.zup -docserver build -i ./embassy-mspm0 -o webroot/crates/embassy-mspm0/git.zup -docserver build -i ./embassy-nxp -o webroot/crates/embassy-nxp/git.zup -docserver build -i ./embassy-sync -o webroot/crates/embassy-sync/git.zup -docserver build -i ./cyw43 -o webroot/crates/cyw43/git.zup -docserver build -i ./cyw43-pio -o webroot/crates/cyw43-pio/git.zup -docserver build -i ./embassy-stm32-wpan -o webroot/crates/embassy-stm32-wpan/git.zup --output-static webroot/static - -docserver build -i ./embassy-time -o webroot/crates/embassy-time/git.zup -docserver build -i ./embassy-time-driver -o webroot/crates/embassy-time-driver/git.zup -docserver build -i ./embassy-time-queue-utils -o webroot/crates/embassy-time-queue-utils/git.zup - -docserver build -i ./embassy-usb -o webroot/crates/embassy-usb/git.zup -docserver build -i ./embassy-usb-dfu -o webroot/crates/embassy-usb-dfu/git.zup -docserver build -i ./embassy-usb-driver -o webroot/crates/embassy-usb-driver/git.zup -docserver build -i ./embassy-usb-logger -o webroot/crates/embassy-usb-logger/git.zup -docserver build -i ./embassy-usb-synopsys-otg -o webroot/crates/embassy-usb-synopsys-otg/git.zup - -docserver build -i ./embassy-net -o webroot/crates/embassy-net/git.zup -docserver build -i ./embassy-net-nrf91 -o webroot/crates/embassy-net-nrf91/git.zup -docserver build -i ./embassy-net-driver -o webroot/crates/embassy-net-driver/git.zup -docserver build -i ./embassy-net-driver-channel -o webroot/crates/embassy-net-driver-channel/git.zup -docserver build -i ./embassy-net-wiznet -o webroot/crates/embassy-net-wiznet/git.zup -docserver build -i ./embassy-net-ppp -o webroot/crates/embassy-net-ppp/git.zup -docserver build -i ./embassy-net-tuntap -o webroot/crates/embassy-net-tuntap/git.zup -docserver build -i ./embassy-net-enc28j60 -o webroot/crates/embassy-net-enc28j60/git.zup -docserver build -i ./embassy-net-esp-hosted -o webroot/crates/embassy-net-esp-hosted/git.zup -docserver build -i ./embassy-net-adin1110 -o webroot/crates/embassy-net-adin1110/git.zup +cargo embassy-devtool doc -o webroot export KUBECONFIG=/ci/secrets/kubeconfig.yml POD=$(kubectl -n embassy get po -l app=docserver -o jsonpath={.items[0].metadata.name}) kubectl cp webroot/crates $POD:/data kubectl cp webroot/static $POD:/data - -# build and upload stm32 last -# so that it doesn't prevent other crates from getting docs updates when it breaks. - -rm -rf webroot -docserver build -i ./embassy-stm32 -o webroot/crates/embassy-stm32/git.zup -POD=$(kubectl -n embassy get po -l app=docserver -o jsonpath={.items[0].metadata.name}) -kubectl cp webroot/crates $POD:/data -- cgit From 0850f3b537feb66160b721c280d07d7c85518151 Mon Sep 17 00:00:00 2001 From: Dario Nieuwenhuis Date: Mon, 22 Sep 2025 01:00:38 +0200 Subject: Update Rust. --- embassy-executor/tests/ui/spawn_nonsend.stderr | 6 +++--- embassy-executor/tests/ui/unsafe_op_in_unsafe_task.stderr | 2 +- embassy-sync/tests/ui/sync_impl/lazy_lock_function.stderr | 8 ++++---- rust-toolchain-nightly.toml | 2 +- rust-toolchain.toml | 2 +- 5 files changed, 10 insertions(+), 10 deletions(-) diff --git a/embassy-executor/tests/ui/spawn_nonsend.stderr b/embassy-executor/tests/ui/spawn_nonsend.stderr index 25bd7d78d..5a3131602 100644 --- a/embassy-executor/tests/ui/spawn_nonsend.stderr +++ b/embassy-executor/tests/ui/spawn_nonsend.stderr @@ -9,7 +9,7 @@ warning: unused import: `core::future::Future` error[E0277]: `*mut ()` cannot be sent between threads safely --> tests/ui/spawn_nonsend.rs:13:13 | -7 | #[embassy_executor::task] + 7 | #[embassy_executor::task] | ------------------------- within this `impl Sized` ... 13 | s.spawn(task(core::ptr::null_mut()).unwrap()); @@ -21,7 +21,7 @@ error[E0277]: `*mut ()` cannot be sent between threads safely note: required because it's used within this closure --> tests/ui/spawn_nonsend.rs:7:1 | -7 | #[embassy_executor::task] + 7 | #[embassy_executor::task] | ^^^^^^^^^^^^^^^^^^^^^^^^^ note: required because it appears within the type `impl Sized` --> src/raw/mod.rs @@ -31,7 +31,7 @@ note: required because it appears within the type `impl Sized` note: required because it appears within the type `impl Sized` --> tests/ui/spawn_nonsend.rs:7:1 | -7 | #[embassy_executor::task] + 7 | #[embassy_executor::task] | ^^^^^^^^^^^^^^^^^^^^^^^^^ note: required by a bound in `SendSpawner::spawn` --> src/spawner.rs diff --git a/embassy-executor/tests/ui/unsafe_op_in_unsafe_task.stderr b/embassy-executor/tests/ui/unsafe_op_in_unsafe_task.stderr index d987a4b95..033395584 100644 --- a/embassy-executor/tests/ui/unsafe_op_in_unsafe_task.stderr +++ b/embassy-executor/tests/ui/unsafe_op_in_unsafe_task.stderr @@ -4,7 +4,7 @@ error[E0133]: call to unsafe function `std::ptr::const_ptr::::rea 7 | (&x as *const i32).read(); | ^^^^^^^^^^^^^^^^^^^^^^^^^ call to unsafe function | - = note: for more information, see + = note: for more information, see = note: consult the function's documentation for information on how to avoid undefined behavior note: an unsafe function restricts its caller, but its body is safe by default --> tests/ui/unsafe_op_in_unsafe_task.rs:5:1 diff --git a/embassy-sync/tests/ui/sync_impl/lazy_lock_function.stderr b/embassy-sync/tests/ui/sync_impl/lazy_lock_function.stderr index daf79ad28..417fb8e31 100644 --- a/embassy-sync/tests/ui/sync_impl/lazy_lock_function.stderr +++ b/embassy-sync/tests/ui/sync_impl/lazy_lock_function.stderr @@ -1,10 +1,10 @@ error[E0277]: `*const u8` cannot be shared between threads safely --> tests/ui/sync_impl/lazy_lock_function.rs:8:16 | -6 | let closure_capturing_non_sync_variable = || unsafe { core::ptr::read(x_ptr) }; + 6 | let closure_capturing_non_sync_variable = || unsafe { core::ptr::read(x_ptr) }; | -- within this `{closure@$DIR/tests/ui/sync_impl/lazy_lock_function.rs:6:47: 6:49}` -7 | -8 | check_sync(LazyLock::new(closure_capturing_non_sync_variable)); + 7 | + 8 | check_sync(LazyLock::new(closure_capturing_non_sync_variable)); | ---------- ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `*const u8` cannot be shared between threads safely | | | required by a bound introduced by this call @@ -14,7 +14,7 @@ error[E0277]: `*const u8` cannot be shared between threads safely note: required because it's used within this closure --> tests/ui/sync_impl/lazy_lock_function.rs:6:47 | -6 | let closure_capturing_non_sync_variable = || unsafe { core::ptr::read(x_ptr) }; + 6 | let closure_capturing_non_sync_variable = || unsafe { core::ptr::read(x_ptr) }; | ^^ = note: required for `embassy_sync::lazy_lock::LazyLock` to implement `Sync` note: required by a bound in `check_sync` diff --git a/rust-toolchain-nightly.toml b/rust-toolchain-nightly.toml index 411cc6946..d3e88c7e1 100644 --- a/rust-toolchain-nightly.toml +++ b/rust-toolchain-nightly.toml @@ -1,5 +1,5 @@ [toolchain] -channel = "nightly-2025-06-29" +channel = "nightly-2025-08-05" components = [ "rust-src", "rustfmt", "llvm-tools", "miri" ] targets = [ "thumbv7em-none-eabi", diff --git a/rust-toolchain.toml b/rust-toolchain.toml index e24864037..5d925c934 100644 --- a/rust-toolchain.toml +++ b/rust-toolchain.toml @@ -1,5 +1,5 @@ [toolchain] -channel = "1.88" +channel = "1.90" components = [ "rust-src", "rustfmt", "llvm-tools" ] targets = [ "thumbv7em-none-eabi", -- cgit From a0a204f586301ee4e014c3673c2ecd3ad90c504c Mon Sep 17 00:00:00 2001 From: Rogan Morrow Date: Mon, 22 Sep 2025 13:36:22 +1000 Subject: add as_nanos and from_nanos where missing --- embassy-time/src/duration.rs | 5 +++++ embassy-time/src/instant.rs | 14 +++++++++++++- 2 files changed, 18 insertions(+), 1 deletion(-) diff --git a/embassy-time/src/duration.rs b/embassy-time/src/duration.rs index 5b140eeff..b3ea0468d 100644 --- a/embassy-time/src/duration.rs +++ b/embassy-time/src/duration.rs @@ -37,6 +37,11 @@ impl Duration { self.ticks * (1_000_000 / GCD_1M) / (TICK_HZ / GCD_1M) } + /// Convert the `Duration` to nanoseconds, rounding down. + pub const fn as_nanos(&self) -> u64 { + self.ticks * (1_000_000_000 / GCD_1G) / (TICK_HZ / GCD_1G) + } + /// Creates a duration from the specified number of clock ticks pub const fn from_ticks(ticks: u64) -> Duration { Duration { ticks } diff --git a/embassy-time/src/instant.rs b/embassy-time/src/instant.rs index 6571bea62..a311b365c 100644 --- a/embassy-time/src/instant.rs +++ b/embassy-time/src/instant.rs @@ -1,7 +1,7 @@ use core::fmt; use core::ops::{Add, AddAssign, Sub, SubAssign}; -use super::{Duration, GCD_1K, GCD_1M, TICK_HZ}; +use super::{Duration, GCD_1K, GCD_1M, GCD_1G, TICK_HZ}; #[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord)] #[cfg_attr(feature = "defmt", derive(defmt::Format))] @@ -29,6 +29,13 @@ impl Instant { Self { ticks } } + /// Create an Instant from a nanosecond count since system boot. + pub const fn from_nanos(nanos: u64) -> Self { + Self { + ticks: nanos * (TICK_HZ / GCD_1G) / (1_000_000_000 / GCD_1G), + } + } + /// Create an Instant from a microsecond count since system boot. pub const fn from_micros(micros: u64) -> Self { Self { @@ -101,6 +108,11 @@ impl Instant { self.ticks * (1_000_000 / GCD_1M) / (TICK_HZ / GCD_1M) } + /// Nanoseconds since system boot. + pub const fn as_nanos(&self) -> u64 { + self.ticks * (1_000_000_000 / GCD_1G) / (TICK_HZ / GCD_1G) + } + /// Duration between this Instant and another Instant /// Panics on over/underflow. pub fn duration_since(&self, earlier: Instant) -> Duration { -- cgit From 57f1517f70bafb0709014f7a44e2d1c8a4841739 Mon Sep 17 00:00:00 2001 From: Rogan Morrow Date: Mon, 22 Sep 2025 13:43:57 +1000 Subject: fix rustfmt and add changelog --- embassy-time/CHANGELOG.md | 2 ++ embassy-time/src/instant.rs | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/embassy-time/CHANGELOG.md b/embassy-time/CHANGELOG.md index 572571215..4a50da8ef 100644 --- a/embassy-time/CHANGELOG.md +++ b/embassy-time/CHANGELOG.md @@ -8,6 +8,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## Unreleased - ReleaseDate +- Add as_nanos and from_nanos where missing + ## 0.5.0 - 2025-08-26 - Allow inlining on time driver boundary diff --git a/embassy-time/src/instant.rs b/embassy-time/src/instant.rs index a311b365c..4e6670032 100644 --- a/embassy-time/src/instant.rs +++ b/embassy-time/src/instant.rs @@ -1,7 +1,7 @@ use core::fmt; use core::ops::{Add, AddAssign, Sub, SubAssign}; -use super::{Duration, GCD_1K, GCD_1M, GCD_1G, TICK_HZ}; +use super::{Duration, GCD_1G, GCD_1K, GCD_1M, TICK_HZ}; #[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord)] #[cfg_attr(feature = "defmt", derive(defmt::Format))] -- cgit From c692a97b654adc50f997852a360ce3277cb73db4 Mon Sep 17 00:00:00 2001 From: Matthew Tran <0e4ef622@gmail.com> Date: Sun, 21 Sep 2025 23:01:03 -0500 Subject: nrf: impl Drop for Timer --- embassy-nrf/src/timer.rs | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/embassy-nrf/src/timer.rs b/embassy-nrf/src/timer.rs index de2875765..b6a77bd2e 100644 --- a/embassy-nrf/src/timer.rs +++ b/embassy-nrf/src/timer.rs @@ -104,7 +104,7 @@ impl<'d, T: Instance> Timer<'d, T> { Self::new_inner(timer, true) } - fn new_inner(timer: Peri<'d, T>, _is_counter: bool) -> Self { + fn new_inner(timer: Peri<'d, T>, is_counter: bool) -> Self { let regs = T::regs(); let this = Self { _p: timer }; @@ -114,7 +114,7 @@ impl<'d, T: Instance> Timer<'d, T> { this.stop(); regs.mode().write(|w| { - w.set_mode(match _is_counter { + w.set_mode(match is_counter { #[cfg(not(feature = "_nrf51"))] true => vals::Mode::LOW_POWER_COUNTER, #[cfg(feature = "_nrf51")] @@ -218,6 +218,12 @@ impl<'d, T: Instance> Timer<'d, T> { } } +impl<'d, T: Instance> Drop for Timer<'d, T> { + fn drop(&mut self) { + self.stop(); + } +} + /// A representation of a timer's Capture/Compare (CC) register. /// /// A CC register holds a 32-bit value. -- cgit From d463a57879c0e02c188f63ab99c40d6ab91ea54e Mon Sep 17 00:00:00 2001 From: Matthew Tran <0e4ef622@gmail.com> Date: Sun, 21 Sep 2025 23:01:11 -0500 Subject: nrf: add persist() method for gpiote and timer --- embassy-nrf/src/gpiote.rs | 18 ++++++++++++++++++ embassy-nrf/src/timer.rs | 9 +++++++++ 2 files changed, 27 insertions(+) diff --git a/embassy-nrf/src/gpiote.rs b/embassy-nrf/src/gpiote.rs index d169b49f9..43e43f0bf 100644 --- a/embassy-nrf/src/gpiote.rs +++ b/embassy-nrf/src/gpiote.rs @@ -193,6 +193,15 @@ pub struct InputChannel<'d> { pin: Input<'d>, } +impl InputChannel<'static> { + /// Persist the channel's configuration for the rest of the program's lifetime. This method + /// should be preferred over [`core::mem::forget()`] because the `'static` bound prevents + /// accidental reuse of the underlying peripheral. + pub fn persist(self) { + core::mem::forget(self); + } +} + impl<'d> Drop for InputChannel<'d> { fn drop(&mut self) { let g = regs(); @@ -263,6 +272,15 @@ pub struct OutputChannel<'d> { _pin: Output<'d>, } +impl OutputChannel<'static> { + /// Persist the channel's configuration for the rest of the program's lifetime. This method + /// should be preferred over [`core::mem::forget()`] because the `'static` bound prevents + /// accidental reuse of the underlying peripheral. + pub fn persist(self) { + core::mem::forget(self); + } +} + impl<'d> Drop for OutputChannel<'d> { fn drop(&mut self) { let g = regs(); diff --git a/embassy-nrf/src/timer.rs b/embassy-nrf/src/timer.rs index b6a77bd2e..5d6afe49b 100644 --- a/embassy-nrf/src/timer.rs +++ b/embassy-nrf/src/timer.rs @@ -218,6 +218,15 @@ impl<'d, T: Instance> Timer<'d, T> { } } +impl Timer<'static, T> { + /// Persist the timer's configuration for the rest of the program's lifetime. This method + /// should be preferred over [`core::mem::forget()`] because the `'static` bound prevents + /// accidental reuse of the underlying peripheral. + pub fn persist(self) { + core::mem::forget(self); + } +} + impl<'d, T: Instance> Drop for Timer<'d, T> { fn drop(&mut self) { self.stop(); -- cgit From 99f7e150c56b09a968e05f98b9f924f17c43296e Mon Sep 17 00:00:00 2001 From: Matthew Tran <0e4ef622@gmail.com> Date: Sun, 21 Sep 2025 23:04:03 -0500 Subject: nrf: Update changelog --- embassy-nrf/CHANGELOG.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/embassy-nrf/CHANGELOG.md b/embassy-nrf/CHANGELOG.md index de8dfd391..0cc1d56bb 100644 --- a/embassy-nrf/CHANGELOG.md +++ b/embassy-nrf/CHANGELOG.md @@ -10,7 +10,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - changed: nrf54l: Disable glitch detection and enable DC/DC in init. - changed: Add embassy-net-driver-channel implementation for IEEE 802.15.4 -- changed: add persist() method for gpio and ppi +- changed: add persist() method for gpio, gpiote, timer and ppi +- changed: impl Drop for Timer ## 0.7.0 - 2025-08-26 -- cgit From 4d9563805cee8a14f7c59a5b28227b99a6ffbf75 Mon Sep 17 00:00:00 2001 From: Dario Nieuwenhuis Date: Mon, 22 Sep 2025 12:55:20 +0200 Subject: time: add Instant::try_from_nanos --- embassy-time/src/instant.rs | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/embassy-time/src/instant.rs b/embassy-time/src/instant.rs index 4e6670032..de5ebebf8 100644 --- a/embassy-time/src/instant.rs +++ b/embassy-time/src/instant.rs @@ -57,6 +57,17 @@ impl Instant { } } + /// Try to create an Instant from a nanosecond count since system boot. + /// Fails if the number of nanoseconds is too large. + pub const fn try_from_nanos(nanos: u64) -> Option { + let Some(value) = nanos.checked_mul(TICK_HZ / GCD_1G) else { + return None; + }; + Some(Self { + ticks: value / (1_000_000_000 / GCD_1G), + }) + } + /// Try to create an Instant from a microsecond count since system boot. /// Fails if the number of microseconds is too large. pub const fn try_from_micros(micros: u64) -> Option { -- cgit From 76d47ea1fa84b0940f3d9e3d830aa0b182f280b8 Mon Sep 17 00:00:00 2001 From: Robin Mueller Date: Sat, 20 Sep 2025 22:07:02 +0200 Subject: add missing timer API --- embassy-nrf/CHANGELOG.md | 2 ++ embassy-nrf/src/timer.rs | 17 ++++++++++++++--- 2 files changed, 16 insertions(+), 3 deletions(-) diff --git a/embassy-nrf/CHANGELOG.md b/embassy-nrf/CHANGELOG.md index 0fedf9360..825d9d713 100644 --- a/embassy-nrf/CHANGELOG.md +++ b/embassy-nrf/CHANGELOG.md @@ -14,6 +14,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - added: basic RTC driver - changed: add persist() method for gpio, gpiote, timer and ppi - changed: impl Drop for Timer +- added: expose `regs` for timer driver +- added: timer driver CC `clear_events` method ## 0.7.0 - 2025-08-26 diff --git a/embassy-nrf/src/timer.rs b/embassy-nrf/src/timer.rs index 5d6afe49b..1d1f77ea8 100644 --- a/embassy-nrf/src/timer.rs +++ b/embassy-nrf/src/timer.rs @@ -81,8 +81,6 @@ pub enum Frequency { /// /// It has either 4 or 6 Capture/Compare registers, which can be used to capture the current state of the counter /// or trigger an event when the counter reaches a certain value. - -/// Timer driver. pub struct Timer<'d, T: Instance> { _p: Peri<'d, T>, } @@ -145,6 +143,13 @@ impl<'d, T: Instance> Timer<'d, T> { this } + /// Direct access to the register block. + #[cfg(feature = "unstable-pac")] + #[inline] + pub fn regs(&mut self) -> pac::timer::Timer { + T::regs() + } + /// Starts the timer. pub fn start(&self) { T::regs().tasks_start().write_value(1) @@ -248,7 +253,7 @@ pub struct Cc<'d, T: Instance> { impl<'d, T: Instance> Cc<'d, T> { /// Get the current value stored in the register. pub fn read(&self) -> u32 { - return T::regs().cc(self.n).read(); + T::regs().cc(self.n).read() } /// Set the value stored in the register. @@ -278,6 +283,12 @@ impl<'d, T: Instance> Cc<'d, T> { Event::from_reg(T::regs().events_compare(self.n)) } + /// Clear the COMPARE event for this CC register. + #[inline] + pub fn clear_events(&self) { + T::regs().events_compare(self.n).write_value(0); + } + /// Enable the shortcut between this CC register's COMPARE event and the timer's CLEAR task. /// /// This means that when the COMPARE event is fired, the CLEAR task will be triggered. -- cgit From 9ae4edfa73d33f6fe66eb70a896b14267f6cdec2 Mon Sep 17 00:00:00 2001 From: Robin Mueller Date: Tue, 23 Sep 2025 11:21:57 +0200 Subject: doc fixes --- embassy-nrf/src/gpio.rs | 4 ++-- embassy-nrf/src/i2s.rs | 2 +- embassy-nrf/src/lib.rs | 2 +- embassy-nrf/src/twim.rs | 4 ++-- embassy-nrf/src/twis.rs | 2 +- embassy-nrf/src/usb/vbus_detect.rs | 2 +- 6 files changed, 8 insertions(+), 8 deletions(-) diff --git a/embassy-nrf/src/gpio.rs b/embassy-nrf/src/gpio.rs index 0cea38777..ab5e7ed4b 100644 --- a/embassy-nrf/src/gpio.rs +++ b/embassy-nrf/src/gpio.rs @@ -217,7 +217,7 @@ pub struct Output<'d> { } impl<'d> Output<'d> { - /// Create GPIO output driver for a [Pin] with the provided [Level] and [OutputDriver] configuration. + /// Create GPIO output driver for a [Pin] with the provided [Level] and [OutputDrive] configuration. #[inline] pub fn new(pin: Peri<'d, impl Pin>, initial_output: Level, drive: OutputDrive) -> Self { let mut pin = Flex::new(pin); @@ -781,7 +781,7 @@ impl<'d> embedded_hal_1::digital::ErrorType for Flex<'d> { type Error = Infallible; } -/// Implement [`InputPin`] for [`Flex`]; +/// Implement [embedded_hal_1::digital::InputPin] for [`Flex`]; /// /// If the pin is not in input mode the result is unspecified. impl<'d> embedded_hal_1::digital::InputPin for Flex<'d> { diff --git a/embassy-nrf/src/i2s.rs b/embassy-nrf/src/i2s.rs index a7dde8cd7..53de8deee 100644 --- a/embassy-nrf/src/i2s.rs +++ b/embassy-nrf/src/i2s.rs @@ -252,7 +252,7 @@ impl ApproxSampleRate { /// /// Those are non standard sample rates that can be configured without error. /// -/// For custom master clock configuration, please refer to [Mode]. +/// For custom master clock configuration, please refer to [vals::Mode]. #[derive(Clone, Copy)] pub enum ExactSampleRate { /// 8000 Hz diff --git a/embassy-nrf/src/lib.rs b/embassy-nrf/src/lib.rs index e0847a312..7c26a6184 100644 --- a/embassy-nrf/src/lib.rs +++ b/embassy-nrf/src/lib.rs @@ -207,7 +207,7 @@ mod chip; /// Macro to bind interrupts to handlers. /// /// This defines the right interrupt handlers, and creates a unit struct (like `struct Irqs;`) -/// and implements the right [`Binding`]s for it. You can pass this struct to drivers to +/// and implements the right [crate::interrupt::typelevel::Binding]s for it. You can pass this struct to drivers to /// prove at compile-time that the right interrupts have been bound. /// /// Example of how to bind one interrupt: diff --git a/embassy-nrf/src/twim.rs b/embassy-nrf/src/twim.rs index 3d5e841d1..3fc59a39a 100644 --- a/embassy-nrf/src/twim.rs +++ b/embassy-nrf/src/twim.rs @@ -558,7 +558,7 @@ impl<'d, T: Instance> Twim<'d, T> { /// Execute the provided operations on the I2C bus with timeout. /// - /// See [`blocking_transaction`]. + /// See [Self::blocking_transaction]. #[cfg(feature = "time")] pub fn blocking_transaction_timeout( &mut self, @@ -632,7 +632,7 @@ impl<'d, T: Instance> Twim<'d, T> { /// Write to an I2C slave with timeout. /// - /// See [`blocking_write`]. + /// See [Self::blocking_write]. #[cfg(feature = "time")] pub fn blocking_write_timeout(&mut self, address: u8, buffer: &[u8], timeout: Duration) -> Result<(), Error> { self.blocking_transaction_timeout(address, &mut [Operation::Write(buffer)], timeout) diff --git a/embassy-nrf/src/twis.rs b/embassy-nrf/src/twis.rs index 3e4d537ae..c77d0f048 100644 --- a/embassy-nrf/src/twis.rs +++ b/embassy-nrf/src/twis.rs @@ -700,7 +700,7 @@ impl<'d, T: Instance> Twis<'d, T> { /// Respond to an I2C master READ command with timeout. /// Returns the number of bytes written. - /// See [`blocking_respond_to_read`]. + /// See [Self::blocking_respond_to_read]. #[cfg(feature = "time")] pub fn blocking_respond_to_read_timeout(&mut self, buffer: &[u8], timeout: Duration) -> Result { self.setup_respond(buffer, false)?; diff --git a/embassy-nrf/src/usb/vbus_detect.rs b/embassy-nrf/src/usb/vbus_detect.rs index 8794beb2d..33cf91ee2 100644 --- a/embassy-nrf/src/usb/vbus_detect.rs +++ b/embassy-nrf/src/usb/vbus_detect.rs @@ -68,7 +68,7 @@ impl interrupt::typelevel::Handler for InterruptHandler { /// [`VbusDetect`] implementation using the native hardware POWER peripheral. /// /// Unsuitable for usage with the nRF softdevice, since it reserves exclusive acces -/// to POWER. In that case, use [`VbusDetectSignal`]. +/// to POWER. In that case, use [SoftwareVbusDetect]. pub struct HardwareVbusDetect { _private: (), } -- cgit From 99febbe3a42ac05b723e6e76088d159eb0acfa5e Mon Sep 17 00:00:00 2001 From: Robin Mueller Date: Tue, 23 Sep 2025 13:55:55 +0200 Subject: more docs fixes --- embassy-embedded-hal/src/adapter/yielding_async.rs | 2 +- embassy-sync/src/blocking_mutex/mod.rs | 4 ++-- embassy-sync/src/blocking_mutex/raw.rs | 4 ++-- embassy-sync/src/rwlock.rs | 2 -- embassy-time-driver/src/lib.rs | 2 +- embassy-usb-driver/src/lib.rs | 4 ++-- 6 files changed, 8 insertions(+), 10 deletions(-) diff --git a/embassy-embedded-hal/src/adapter/yielding_async.rs b/embassy-embedded-hal/src/adapter/yielding_async.rs index 87f822a63..e0ca3aedc 100644 --- a/embassy-embedded-hal/src/adapter/yielding_async.rs +++ b/embassy-embedded-hal/src/adapter/yielding_async.rs @@ -2,7 +2,7 @@ use embassy_futures::yield_now; /// Wrapper that yields for each operation to the wrapped instance /// -/// This can be used in combination with BlockingAsync to enforce yields +/// This can be used in combination with [super::BlockingAsync] to enforce yields /// between long running blocking operations. pub struct YieldingAsync { wrapped: T, diff --git a/embassy-sync/src/blocking_mutex/mod.rs b/embassy-sync/src/blocking_mutex/mod.rs index 11809c763..62bfc26fb 100644 --- a/embassy-sync/src/blocking_mutex/mod.rs +++ b/embassy-sync/src/blocking_mutex/mod.rs @@ -135,9 +135,9 @@ impl Mutex { // There's still a ThreadModeRawMutex for use with the generic Mutex (handy with Channel, for example), // but that will require T: Send even though it shouldn't be needed. -#[cfg(any(cortex_m, feature = "std"))] +#[cfg(any(cortex_m, doc, feature = "std"))] pub use thread_mode_mutex::*; -#[cfg(any(cortex_m, feature = "std"))] +#[cfg(any(cortex_m, doc, feature = "std"))] mod thread_mode_mutex { use super::*; diff --git a/embassy-sync/src/blocking_mutex/raw.rs b/embassy-sync/src/blocking_mutex/raw.rs index 50f965e00..fbb9ece15 100644 --- a/embassy-sync/src/blocking_mutex/raw.rs +++ b/embassy-sync/src/blocking_mutex/raw.rs @@ -89,7 +89,7 @@ unsafe impl RawMutex for NoopRawMutex { // ================ -#[cfg(any(cortex_m, feature = "std"))] +#[cfg(any(cortex_m, doc, feature = "std"))] mod thread_mode { use super::*; @@ -147,5 +147,5 @@ mod thread_mode { return unsafe { (0xE000ED04 as *const u32).read_volatile() } & 0x1FF == 0; } } -#[cfg(any(cortex_m, feature = "std"))] +#[cfg(any(cortex_m, doc, feature = "std"))] pub use thread_mode::*; diff --git a/embassy-sync/src/rwlock.rs b/embassy-sync/src/rwlock.rs index 0d784a7dc..e43388c4d 100644 --- a/embassy-sync/src/rwlock.rs +++ b/embassy-sync/src/rwlock.rs @@ -37,8 +37,6 @@ struct State { /// Use [`NoopRawMutex`](crate::blocking_mutex::raw::NoopRawMutex) when data is only shared between tasks running on the same executor. /// /// Use [`ThreadModeRawMutex`](crate::blocking_mutex::raw::ThreadModeRawMutex) when data is shared between tasks running on the same executor but you want a singleton. -/// - pub struct RwLock where M: RawMutex, diff --git a/embassy-time-driver/src/lib.rs b/embassy-time-driver/src/lib.rs index 32cb68296..44d9a156a 100644 --- a/embassy-time-driver/src/lib.rs +++ b/embassy-time-driver/src/lib.rs @@ -6,7 +6,7 @@ //! //! - Define a struct `MyDriver` //! - Implement [`Driver`] for it -//! - Register it as the global driver with [`time_driver_impl`](crate::time_driver_impl). +//! - Register it as the global driver with [`time_driver_impl`]. //! //! If your driver has a single set tick rate, enable the corresponding [`tick-hz-*`](crate#tick-rate) feature, //! which will prevent users from needing to configure it themselves (or selecting an incorrect configuration). diff --git a/embassy-usb-driver/src/lib.rs b/embassy-usb-driver/src/lib.rs index 3ad96c61d..59845a268 100644 --- a/embassy-usb-driver/src/lib.rs +++ b/embassy-usb-driver/src/lib.rs @@ -205,7 +205,7 @@ pub trait Bus { /// /// # Errors /// - /// * [`Unsupported`](crate::Unsupported) - This UsbBus implementation doesn't support + /// * [`Unsupported`] - This UsbBus implementation doesn't support /// simulating a disconnect or it has not been enabled at creation time. fn force_reset(&mut self) -> Result<(), Unsupported> { Err(Unsupported) @@ -215,7 +215,7 @@ pub trait Bus { /// /// # Errors /// - /// * [`Unsupported`](crate::Unsupported) - This UsbBus implementation doesn't support + /// * [`Unsupported`] - This UsbBus implementation doesn't support /// remote wakeup or it has not been enabled at creation time. async fn remote_wakeup(&mut self) -> Result<(), Unsupported>; } -- cgit From d5e4558f1807a99a10636efcc1ff6ec514b07d56 Mon Sep 17 00:00:00 2001 From: Dániel Buga Date: Tue, 23 Sep 2025 16:23:18 +0200 Subject: Fix docs --- embassy-executor/src/raw/mod.rs | 2 -- 1 file changed, 2 deletions(-) diff --git a/embassy-executor/src/raw/mod.rs b/embassy-executor/src/raw/mod.rs index 9f36c60bc..dbd70cbf4 100644 --- a/embassy-executor/src/raw/mod.rs +++ b/embassy-executor/src/raw/mod.rs @@ -564,8 +564,6 @@ impl Executor { /// /// # Safety /// - /// You must call `initialize` before calling this method. - /// /// You must NOT call `poll` reentrantly on the same executor. /// /// In particular, note that `poll` may call the pender synchronously. Therefore, you -- cgit From 1d494594e8b96255fefb994ddcc2f46e4dec3772 Mon Sep 17 00:00:00 2001 From: Bjorn Beishline <75190918+BjornTheProgrammer@users.noreply.github.com> Date: Tue, 23 Sep 2025 14:17:33 -0700 Subject: Add reset_to_usb_boot to rp235x --- embassy-rp/CHANGELOG.md | 1 + embassy-rp/src/rom_data/rp235x.rs | 32 ++++++++++++++++++++++++++++++++ 2 files changed, 33 insertions(+) diff --git a/embassy-rp/CHANGELOG.md b/embassy-rp/CHANGELOG.md index ea62c2387..e932bcaa3 100644 --- a/embassy-rp/CHANGELOG.md +++ b/embassy-rp/CHANGELOG.md @@ -13,6 +13,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Add PIO onewire parasite power strong pullup - add `wait_for_alarm` and `alarm_scheduled` methods to rtc module ([#4216](https://github.com/embassy-rs/embassy/pull/4216)) - rp235x: use msplim for stack guard instead of MPU +- Add reset_to_usb_boot for rp235x ([#4705](https://github.com/embassy-rs/embassy/pull/4705)) ## 0.8.0 - 2025-08-26 diff --git a/embassy-rp/src/rom_data/rp235x.rs b/embassy-rp/src/rom_data/rp235x.rs index b16fee8f7..c0a1ed6fb 100644 --- a/embassy-rp/src/rom_data/rp235x.rs +++ b/embassy-rp/src/rom_data/rp235x.rs @@ -750,3 +750,35 @@ pub fn is_secure_mode() -> bool { pub fn is_secure_mode() -> bool { false } + +// These and the reset_to_usb_boot function are found from https://github.com/raspberrypi/pico-sdk/blob/master/src/rp2_common/pico_bootrom/bootrom.c#L35-L51 +// The following has just been translated to rust from the original c++ +const BOOTSEL_FLAG_GPIO_PIN_SPECIFIED: u32 = 0x20; +const REBOOT2_FLAG_REBOOT_TYPE_BOOTSEL: u32 = 0x2; +const REBOOT2_FLAG_NO_RETURN_ON_SUCCESS: u32 = 0x100; + +/// Resets the RP235x and uses the watchdog facility to re-start in BOOTSEL mode: +/// * gpio_activity_pin_mask is provided to enable an 'activity light' via GPIO attached LED +/// for the USB Mass Storage Device: +/// * 0 No pins are used as per cold boot. +/// * Otherwise a single bit set indicating which GPIO pin should be set to output and +/// raised whenever there is mass storage activity from the host. +/// * disable_interface_mask may be used to control the exposed USB interfaces: +/// * 0 To enable both interfaces (as per cold boot). +/// * 1 To disable the USB Mass Storage Interface. +/// * 2 to Disable the USB PICOBOOT Interface. +pub fn reset_to_usb_boot(mut usb_activity_gpio_pin_mask: u32, disable_interface_mask: u32) { + let mut flags = disable_interface_mask; + + if usb_activity_gpio_pin_mask != 0 { + flags = flags | BOOTSEL_FLAG_GPIO_PIN_SPECIFIED; + usb_activity_gpio_pin_mask = usb_activity_gpio_pin_mask.trailing_zeros() + } + + reboot( + REBOOT2_FLAG_REBOOT_TYPE_BOOTSEL | REBOOT2_FLAG_NO_RETURN_ON_SUCCESS, + 10, + flags, + usb_activity_gpio_pin_mask, + ); +} -- cgit From 987009df7bf77dc963e5cff5c3cbdf565839c17c Mon Sep 17 00:00:00 2001 From: Abraham Hamidi Date: Fri, 19 Sep 2025 16:13:34 -0500 Subject: feat(nrf/spim): erase Instance type from Spim --- embassy-nrf/CHANGELOG.md | 1 + embassy-nrf/src/spim.rs | 64 +++++++++++++++----------- examples/nrf52840/src/bin/ethernet_enc28j60.rs | 2 +- examples/nrf52840/src/bin/wifi_esp_hosted.rs | 2 +- tests/nrf/src/bin/ethernet_enc28j60_perf.rs | 2 +- tests/nrf/src/bin/wifi_esp_hosted_perf.rs | 2 +- 6 files changed, 41 insertions(+), 32 deletions(-) diff --git a/embassy-nrf/CHANGELOG.md b/embassy-nrf/CHANGELOG.md index 825d9d713..b8d03a1f8 100644 --- a/embassy-nrf/CHANGELOG.md +++ b/embassy-nrf/CHANGELOG.md @@ -8,6 +8,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## Unreleased - ReleaseDate +- changed: erase Instance type from Spim - changed: nrf54l: Disable glitch detection and enable DC/DC in init. - changed: Add embassy-net-driver-channel implementation for IEEE 802.15.4 - changed: add persist() method for gpio and ppi diff --git a/embassy-nrf/src/spim.rs b/embassy-nrf/src/spim.rs index 59f5b6d58..c410e49fd 100644 --- a/embassy-nrf/src/spim.rs +++ b/embassy-nrf/src/spim.rs @@ -99,13 +99,16 @@ impl interrupt::typelevel::Handler for InterruptHandl } /// SPIM driver. -pub struct Spim<'d, T: Instance> { - _p: Peri<'d, T>, +pub struct Spim<'d> { + r: pac::spim::Spim, + irq: interrupt::Interrupt, + state: &'static State, + _p: PhantomData<&'d ()>, } -impl<'d, T: Instance> Spim<'d, T> { +impl<'d> Spim<'d> { /// Create a new SPIM driver. - pub fn new( + pub fn new( spim: Peri<'d, T>, _irq: impl interrupt::typelevel::Binding> + 'd, sck: Peri<'d, impl GpioPin>, @@ -117,7 +120,7 @@ impl<'d, T: Instance> Spim<'d, T> { } /// Create a new SPIM driver, capable of TX only (MOSI only). - pub fn new_txonly( + pub fn new_txonly( spim: Peri<'d, T>, _irq: impl interrupt::typelevel::Binding> + 'd, sck: Peri<'d, impl GpioPin>, @@ -128,7 +131,7 @@ impl<'d, T: Instance> Spim<'d, T> { } /// Create a new SPIM driver, capable of RX only (MISO only). - pub fn new_rxonly( + pub fn new_rxonly( spim: Peri<'d, T>, _irq: impl interrupt::typelevel::Binding> + 'd, sck: Peri<'d, impl GpioPin>, @@ -139,7 +142,7 @@ impl<'d, T: Instance> Spim<'d, T> { } /// Create a new SPIM driver, capable of TX only (MOSI only), without SCK pin. - pub fn new_txonly_nosck( + pub fn new_txonly_nosck( spim: Peri<'d, T>, _irq: impl interrupt::typelevel::Binding> + 'd, mosi: Peri<'d, impl GpioPin>, @@ -148,8 +151,8 @@ impl<'d, T: Instance> Spim<'d, T> { Self::new_inner(spim, None, None, Some(mosi.into()), config) } - fn new_inner( - spim: Peri<'d, T>, + fn new_inner( + _spim: Peri<'d, T>, sck: Option>, miso: Option>, mosi: Option>, @@ -201,7 +204,12 @@ impl<'d, T: Instance> Spim<'d, T> { // Enable SPIM instance. r.enable().write(|w| w.set_enable(vals::Enable::ENABLED)); - let mut spim = Self { _p: spim }; + let mut spim = Self { + r: T::regs(), + irq: T::Interrupt::IRQ, + state: T::state(), + _p: PhantomData {}, + }; // Apply runtime peripheral configuration Self::set_config(&mut spim, &config).unwrap(); @@ -218,7 +226,7 @@ impl<'d, T: Instance> Spim<'d, T> { fn prepare_dma_transfer(&mut self, rx: *mut [u8], tx: *const [u8], offset: usize, length: usize) { compiler_fence(Ordering::SeqCst); - let r = T::regs(); + let r = self.r; fn xfer_params(ptr: u32, total: usize, offset: usize, length: usize) -> (u32, usize) { if total > offset { @@ -246,7 +254,7 @@ impl<'d, T: Instance> Spim<'d, T> { #[cfg(feature = "_nrf52832_anomaly_109")] if offset == 0 { - let s = T::state(); + let s = self.state; r.events_started().write_value(0); @@ -279,7 +287,7 @@ impl<'d, T: Instance> Spim<'d, T> { } // Wait for 'end' event. - while T::regs().events_end().read() == 0 {} + while self.r.events_end().read() == 0 {} compiler_fence(Ordering::SeqCst); } @@ -315,7 +323,7 @@ impl<'d, T: Instance> Spim<'d, T> { #[cfg(feature = "_nrf52832_anomaly_109")] if offset == 0 { poll_fn(|cx| { - let s = T::state(); + let s = self.state; s.waker.register(cx.waker()); @@ -326,8 +334,8 @@ impl<'d, T: Instance> Spim<'d, T> { // Wait for 'end' event. poll_fn(|cx| { - T::state().waker.register(cx.waker()); - if T::regs().events_end().read() != 0 { + self.state.waker.register(cx.waker()); + if self.r.events_end().read() != 0 { return Poll::Ready(()); } @@ -430,9 +438,9 @@ impl<'d, T: Instance> Spim<'d, T> { #[cfg(feature = "_nrf52832_anomaly_109")] fn nrf52832_dma_workaround_status(&mut self) -> Poll<()> { - let r = T::regs(); + let r = self.r; if r.events_started().read() != 0 { - let s = T::state(); + let s = self.state; // Handle the first "fake" transmission r.events_started().write_value(0); @@ -451,14 +459,14 @@ impl<'d, T: Instance> Spim<'d, T> { } } -impl<'d, T: Instance> Drop for Spim<'d, T> { +impl<'d> Drop for Spim<'d> { fn drop(&mut self) { trace!("spim drop"); // TODO check for abort, wait for xxxstopped // disable! - let r = T::regs(); + let r = self.r; r.enable().write(|w| w.set_enable(vals::Enable::DISABLED)); gpio::deconfigure_pin(r.psel().sck().read()); @@ -466,7 +474,7 @@ impl<'d, T: Instance> Drop for Spim<'d, T> { gpio::deconfigure_pin(r.psel().mosi().read()); // Disable all events interrupts - T::Interrupt::disable(); + cortex_m::peripheral::NVIC::mask(self.irq); trace!("spim drop: done"); } @@ -526,7 +534,7 @@ macro_rules! impl_spim { mod eh02 { use super::*; - impl<'d, T: Instance> embedded_hal_02::blocking::spi::Transfer for Spim<'d, T> { + impl<'d> embedded_hal_02::blocking::spi::Transfer for Spim<'d> { type Error = Error; fn transfer<'w>(&mut self, words: &'w mut [u8]) -> Result<&'w [u8], Self::Error> { self.blocking_transfer_in_place(words)?; @@ -534,7 +542,7 @@ mod eh02 { } } - impl<'d, T: Instance> embedded_hal_02::blocking::spi::Write for Spim<'d, T> { + impl<'d> embedded_hal_02::blocking::spi::Write for Spim<'d> { type Error = Error; fn write(&mut self, words: &[u8]) -> Result<(), Self::Error> { @@ -551,11 +559,11 @@ impl embedded_hal_1::spi::Error for Error { } } -impl<'d, T: Instance> embedded_hal_1::spi::ErrorType for Spim<'d, T> { +impl<'d> embedded_hal_1::spi::ErrorType for Spim<'d> { type Error = Error; } -impl<'d, T: Instance> embedded_hal_1::spi::SpiBus for Spim<'d, T> { +impl<'d> embedded_hal_1::spi::SpiBus for Spim<'d> { fn flush(&mut self) -> Result<(), Self::Error> { Ok(()) } @@ -577,7 +585,7 @@ impl<'d, T: Instance> embedded_hal_1::spi::SpiBus for Spim<'d, T> { } } -impl<'d, T: Instance> embedded_hal_async::spi::SpiBus for Spim<'d, T> { +impl<'d> embedded_hal_async::spi::SpiBus for Spim<'d> { async fn flush(&mut self) -> Result<(), Error> { Ok(()) } @@ -599,11 +607,11 @@ impl<'d, T: Instance> embedded_hal_async::spi::SpiBus for Spim<'d, T> { } } -impl<'d, T: Instance> SetConfig for Spim<'d, T> { +impl<'d> SetConfig for Spim<'d> { type Config = Config; type ConfigError = (); fn set_config(&mut self, config: &Self::Config) -> Result<(), Self::ConfigError> { - let r = T::regs(); + let r = self.r; // Configure mode. let mode = config.mode; r.config().write(|w| { diff --git a/examples/nrf52840/src/bin/ethernet_enc28j60.rs b/examples/nrf52840/src/bin/ethernet_enc28j60.rs index 3bb255a72..e59afd37f 100644 --- a/examples/nrf52840/src/bin/ethernet_enc28j60.rs +++ b/examples/nrf52840/src/bin/ethernet_enc28j60.rs @@ -25,7 +25,7 @@ bind_interrupts!(struct Irqs { async fn net_task( mut runner: embassy_net::Runner< 'static, - Enc28j60, Output<'static>, Delay>, Output<'static>>, + Enc28j60, Output<'static>, Delay>, Output<'static>>, >, ) -> ! { runner.run().await diff --git a/examples/nrf52840/src/bin/wifi_esp_hosted.rs b/examples/nrf52840/src/bin/wifi_esp_hosted.rs index 2dd9abfaa..1bc35746a 100644 --- a/examples/nrf52840/src/bin/wifi_esp_hosted.rs +++ b/examples/nrf52840/src/bin/wifi_esp_hosted.rs @@ -27,7 +27,7 @@ bind_interrupts!(struct Irqs { async fn wifi_task( runner: hosted::Runner< 'static, - ExclusiveDevice, Output<'static>, Delay>, + ExclusiveDevice, Output<'static>, Delay>, Input<'static>, Output<'static>, >, diff --git a/tests/nrf/src/bin/ethernet_enc28j60_perf.rs b/tests/nrf/src/bin/ethernet_enc28j60_perf.rs index 5f3fa1fd3..bd6a2effd 100644 --- a/tests/nrf/src/bin/ethernet_enc28j60_perf.rs +++ b/tests/nrf/src/bin/ethernet_enc28j60_perf.rs @@ -22,7 +22,7 @@ bind_interrupts!(struct Irqs { RNG => embassy_nrf::rng::InterruptHandler; }); -type MyDriver = Enc28j60, Output<'static>, Delay>, Output<'static>>; +type MyDriver = Enc28j60, Output<'static>, Delay>, Output<'static>>; #[embassy_executor::task] async fn net_task(mut runner: embassy_net::Runner<'static, MyDriver>) -> ! { diff --git a/tests/nrf/src/bin/wifi_esp_hosted_perf.rs b/tests/nrf/src/bin/wifi_esp_hosted_perf.rs index 34c33a4ad..091a70ce9 100644 --- a/tests/nrf/src/bin/wifi_esp_hosted_perf.rs +++ b/tests/nrf/src/bin/wifi_esp_hosted_perf.rs @@ -29,7 +29,7 @@ const WIFI_PASSWORD: &str = "V8YxhKt5CdIAJFud"; async fn wifi_task( runner: hosted::Runner< 'static, - ExclusiveDevice, Output<'static>, Delay>, + ExclusiveDevice, Output<'static>, Delay>, Input<'static>, Output<'static>, >, -- cgit From fc8c3e1e4babaa6344bdbab49a9542a29c88cc25 Mon Sep 17 00:00:00 2001 From: Piotr Esden-Tempski Date: Wed, 24 Sep 2025 16:43:19 -0700 Subject: stm32-metapack: Corrects the RTC register map for l4p and l4q. It also includes improvements in accuracy of the l412 and l422 RTC register map. --- embassy-stm32/CHANGELOG.md | 2 ++ embassy-stm32/Cargo.toml | 4 ++-- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/embassy-stm32/CHANGELOG.md b/embassy-stm32/CHANGELOG.md index 8fcc088fd..835d9c704 100644 --- a/embassy-stm32/CHANGELOG.md +++ b/embassy-stm32/CHANGELOG.md @@ -23,6 +23,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - feat: Allow OSPI DMA writes larger than 64kB using chunking - feat: More ADC enums for g0 PAC, API change for oversampling, allow separate sample times - feat: Add USB CRS sync support for STM32C071 +- fix: RTC register definition for STM32L4P5 and L4Q5 as they use v3 register map. +- fix: Cut down the capabilities of the STM32L412 and L422 RTC as those are missing binary timer mode and underflow interrupt. ## 0.4.0 - 2025-08-26 diff --git a/embassy-stm32/Cargo.toml b/embassy-stm32/Cargo.toml index 369fabc50..b029f33b0 100644 --- a/embassy-stm32/Cargo.toml +++ b/embassy-stm32/Cargo.toml @@ -174,7 +174,7 @@ futures-util = { version = "0.3.30", default-features = false } sdio-host = "0.9.0" critical-section = "1.1" #stm32-metapac = { version = "18" } -stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-3cf72eac610259fd78ef16f1c63be69a144d75f7" } +stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-b46fcc32f329f05fbdca4c007ed4bc305b0ade85" } vcell = "0.1.3" nb = "1.0.0" @@ -204,7 +204,7 @@ proc-macro2 = "1.0.36" quote = "1.0.15" #stm32-metapac = { version = "18", default-features = false, features = ["metadata"]} -stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-3cf72eac610259fd78ef16f1c63be69a144d75f7", default-features = false, features = ["metadata"] } +stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-b46fcc32f329f05fbdca4c007ed4bc305b0ade85", default-features = false, features = ["metadata"] } [features] default = ["rt"] -- cgit From f3d3b8899358ce8540bf5b2107a71b02ff941213 Mon Sep 17 00:00:00 2001 From: Roi Bachynskyi Date: Mon, 15 Sep 2025 00:38:23 +0300 Subject: lpc55: dma and async usart --- embassy-nxp/CHANGELOG.md | 1 + embassy-nxp/Cargo.toml | 1 + embassy-nxp/src/chips/lpc55.rs | 30 +++ embassy-nxp/src/dma.rs | 5 + embassy-nxp/src/dma/lpc55.rs | 377 +++++++++++++++++++++++++++++++ embassy-nxp/src/lib.rs | 72 ++++++ embassy-nxp/src/usart/lpc55.rs | 310 +++++++++++++++++++++++-- examples/lpc55s69/src/bin/usart_async.rs | 70 ++++++ 8 files changed, 846 insertions(+), 20 deletions(-) create mode 100644 embassy-nxp/src/dma.rs create mode 100644 embassy-nxp/src/dma/lpc55.rs create mode 100644 examples/lpc55s69/src/bin/usart_async.rs diff --git a/embassy-nxp/CHANGELOG.md b/embassy-nxp/CHANGELOG.md index ab97c4185..0fb677cd8 100644 --- a/embassy-nxp/CHANGELOG.md +++ b/embassy-nxp/CHANGELOG.md @@ -7,5 +7,6 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## Unreleased - ReleaseDate +- LPC55: DMA Controller and asynchronous version of USART - Moved NXP LPC55S69 from `lpc55-pac` to `nxp-pac` - First release with changelog. diff --git a/embassy-nxp/Cargo.toml b/embassy-nxp/Cargo.toml index 073fdabe4..f3c828313 100644 --- a/embassy-nxp/Cargo.toml +++ b/embassy-nxp/Cargo.toml @@ -29,6 +29,7 @@ cortex-m-rt = "0.7.0" critical-section = "1.1.2" embassy-hal-internal = { version = "0.3.0", path = "../embassy-hal-internal", features = ["cortex-m", "prio-bits-2"] } embassy-sync = { version = "0.7.2", path = "../embassy-sync" } +embassy-futures = { version = "0.1.2", path = "../embassy-futures"} defmt = { version = "1", optional = true } log = { version = "0.4.27", optional = true } embassy-time = { version = "0.5.0", path = "../embassy-time", optional = true } diff --git a/embassy-nxp/src/chips/lpc55.rs b/embassy-nxp/src/chips/lpc55.rs index 711bff3e7..9f4e7269f 100644 --- a/embassy-nxp/src/chips/lpc55.rs +++ b/embassy-nxp/src/chips/lpc55.rs @@ -1,5 +1,9 @@ pub use nxp_pac as pac; +embassy_hal_internal::interrupt_mod!( + FLEXCOMM0, FLEXCOMM1, FLEXCOMM2, FLEXCOMM3, FLEXCOMM4, FLEXCOMM5, FLEXCOMM6, FLEXCOMM7 +); + embassy_hal_internal::peripherals! { // External pins. These are not only GPIOs, they are multi-purpose pins and can be used by other // peripheral types (e.g. I2C). @@ -68,6 +72,32 @@ embassy_hal_internal::peripherals! { PIO1_30, PIO1_31, + // Direct Memory Access (DMA) channels. They are used for asynchronous modes of peripherals. + DMA_CH0, + DMA_CH1, + DMA_CH2, + DMA_CH3, + DMA_CH4, + DMA_CH5, + DMA_CH6, + DMA_CH7, + DMA_CH8, + DMA_CH9, + DMA_CH10, + DMA_CH11, + DMA_CH12, + DMA_CH13, + DMA_CH14, + DMA_CH15, + DMA_CH16, + DMA_CH17, + DMA_CH18, + DMA_CH19, + DMA_CH20, + DMA_CH21, + DMA_CH22, + + // Universal Synchronous/Asynchronous Receiver/Transmitter (USART) instances. USART0, USART1, USART2, diff --git a/embassy-nxp/src/dma.rs b/embassy-nxp/src/dma.rs new file mode 100644 index 000000000..e2df65fc9 --- /dev/null +++ b/embassy-nxp/src/dma.rs @@ -0,0 +1,5 @@ +//! Direct Memory Access (DMA) driver. + +#[cfg_attr(feature = "lpc55-core0", path = "./dma/lpc55.rs")] +mod inner; +pub use inner::*; diff --git a/embassy-nxp/src/dma/lpc55.rs b/embassy-nxp/src/dma/lpc55.rs new file mode 100644 index 000000000..578d1fd88 --- /dev/null +++ b/embassy-nxp/src/dma/lpc55.rs @@ -0,0 +1,377 @@ +use core::cell::RefCell; +use core::future::Future; +use core::pin::Pin; +use core::sync::atomic::{compiler_fence, Ordering}; +use core::task::{Context, Poll}; + +use critical_section::Mutex; +use embassy_hal_internal::interrupt::InterruptExt; +use embassy_hal_internal::{impl_peripheral, PeripheralType}; +use embassy_sync::waitqueue::AtomicWaker; + +use crate::pac::{DMA0, SYSCON, *}; +use crate::{peripherals, Peri}; + +#[interrupt] +fn DMA0() { + let inta = DMA0.inta0().read().ia(); + for channel in 0..CHANNEL_COUNT { + if (DMA0.errint0().read().err() & (1 << channel)) != 0 { + panic!("DMA: error on DMA_0 channel {}", channel); + } + + if (inta & (1 << channel)) != 0 { + CHANNEL_WAKERS[channel].wake(); + DMA0.inta0().modify(|w| w.set_ia(1 << channel)); + } + } +} + +pub(crate) fn init() { + assert_eq!(core::mem::size_of::(), 16, "Descriptor must be 16 bytes"); + assert_eq!( + core::mem::align_of::(), + 16, + "Descriptor must be 16-byte aligned" + ); + assert_eq!( + core::mem::align_of::(), + 512, + "Table must be 512-byte aligned" + ); + // Start clock for DMA + SYSCON.ahbclkctrl0().modify(|w| w.set_dma0(true)); + // Reset DMA + SYSCON + .presetctrl0() + .modify(|w| w.set_dma0_rst(syscon::vals::Dma0Rst::ASSERTED)); + SYSCON + .presetctrl0() + .modify(|w| w.set_dma0_rst(syscon::vals::Dma0Rst::RELEASED)); + + // Address bits 31:9 of the beginning of the DMA descriptor table + critical_section::with(|cs| { + DMA0.srambase() + .write(|w| w.set_offset((DMA_DESCRIPTORS.borrow(cs).as_ptr() as u32) >> 9)); + }); + // Enable DMA controller + DMA0.ctrl().modify(|w| w.set_enable(true)); + + unsafe { + crate::pac::interrupt::DMA0.enable(); + } + info!("DMA initialized"); +} + +/// 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> { + copy_inner( + ch, + from as *const u32, + to as *mut W as *mut u32, + to.len(), + W::size(), + false, + 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> { + copy_inner( + ch, + from as *const W as *const u32, + to as *mut u32, + from.len(), + W::size(), + true, + false, + ) +} + +/// 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); + copy_inner( + ch, + from.as_ptr() as *const u32, + to.as_mut_ptr() as *mut u32, + from_len, + W::size(), + true, + true, + ) +} + +fn copy_inner<'a, C: Channel>( + ch: Peri<'a, C>, + from: *const u32, + to: *mut u32, + len: usize, + data_size: crate::pac::dma::vals::Width, + incr_src: bool, + incr_dest: bool, +) -> Transfer<'a, C> { + let p = ch.regs(); + + // Buffer ending address = buffer starting address + (XFERCOUNT * the transfer increment) + // XREFCOUNT = the number of transfers performed - 1. + // The 1st transfer is included in the starting address. + let source_end_addr = if incr_src { + from as u32 + len as u32 - 1 + } else { + from as u32 + }; + let dest_end_addr = if incr_dest { + to as u32 + len as u32 - 1 + } else { + to as u32 + }; + + compiler_fence(Ordering::SeqCst); + + critical_section::with(|cs| { + DMA_DESCRIPTORS.borrow(cs).borrow_mut().descriptors[ch.number() as usize] = DmaDescriptor { + reserved: 0, + source_end_addr, + dest_end_addr, + next_desc: 0, // Since only single transfers are made, there is no need for reload descriptor address. + } + }); + + compiler_fence(Ordering::SeqCst); + + p.cfg().modify(|w| { + // Peripheral DMA requests are enabled. + // DMA requests that pace transfers can be interpreted then. + w.set_periphreqen(true); + // There is no need to have them on. + // No complex transfers are performed for now. + w.set_hwtrigen(false); + w.set_chpriority(0); + }); + + p.xfercfg().modify(|w| { + // This bit indicates whether the current channel descriptor is + // valid and can potentially be acted upon, + // if all other activation criteria are fulfilled. + w.set_cfgvalid(true); + // Indicates whether the channel’s control structure will be reloaded + // when the current descriptor is exhausted. + // Reloading allows ping-pong and linked transfers. + w.set_reload(false); + // There is no hardware distinction between interrupt A and B. + // They can be used by software to assist with more complex descriptor usage. + // By convention, interrupt A may be used when only one interrupt flag is needed. + w.set_setinta(true); + w.set_setintb(false); + w.set_width(data_size); + w.set_srcinc(if incr_src { + dma::vals::Srcinc::WIDTH_X_1 + } else { + dma::vals::Srcinc::NO_INCREMENT + }); + w.set_dstinc(if incr_dest { + dma::vals::Dstinc::WIDTH_X_1 + } else { + dma::vals::Dstinc::NO_INCREMENT + }); + // Total number of transfers to be performed, minus 1 encoded. + w.set_xfercount((len as u16) - 1); + // Before triggering the channel, it has to be enabled. + w.set_swtrig(false); + }); + + compiler_fence(Ordering::SeqCst); + DMA0.enableset0().write(|w| w.set_ena(1 << ch.number())); + DMA0.intenset0().write(|w| w.set_inten(1 << ch.number())); + + compiler_fence(Ordering::SeqCst); + // Start transfer. + DMA0.settrig0().write(|w| w.set_trig(1 << ch.number())); + 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 } + } +} + +impl<'a, C: Channel> Drop for Transfer<'a, C> { + fn drop(&mut self) { + DMA0.enableclr0().write(|w| w.set_clr(1 << self.channel.number())); + while (DMA0.busy0().read().bsy() & (1 << self.channel.number())) != 0 {} + DMA0.abort0().write(|w| w.set_abortctrl(1 << self.channel.number())); + } +} + +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 { + // We need to register/re-register the waker for each poll because any + // calls to wake will deregister the waker. + CHANNEL_WAKERS[self.channel.number() as usize].register(cx.waker()); + // Check if it is busy or not. + if (DMA0.busy0().read().bsy() & (1 << self.channel.number())) != 0 { + Poll::Pending + } else { + Poll::Ready(()) + } + } +} + +// Total number of channles including both DMA0 and DMA1. +// In spite of using only DMA0 channels, the descriptor table +// should be of this size. +pub(crate) const CHANNEL_COUNT: usize = 32; + +static CHANNEL_WAKERS: [AtomicWaker; CHANNEL_COUNT] = [const { AtomicWaker::new() }; CHANNEL_COUNT]; + +// See section 22.5.2 (table 450) +// UM11126, Rev. 2.8 +// The size of a descriptor must be aligned to a multiple of 16 bytes. +#[repr(C, align(16))] +#[derive(Clone, Copy)] +struct DmaDescriptor { + /// 0x0 Reserved. + reserved: u32, + /// 0x4 Source data end address. + source_end_addr: u32, + /// 0x8 Destination end address. + dest_end_addr: u32, + /// 0xC Link to next descriptor. + next_desc: u32, +} + +// See section 22.6.3 +// UM11126, Rev. 2.8 +// The table must begin on a 512 byte boundary. +#[repr(C, align(512))] +struct DmaDescriptorTable { + descriptors: [DmaDescriptor; CHANNEL_COUNT], +} + +// DMA descriptors are stored in on-chip SRAM. +static DMA_DESCRIPTORS: Mutex> = Mutex::new(RefCell::new(DmaDescriptorTable { + descriptors: [DmaDescriptor { + reserved: 0, + source_end_addr: 0, + dest_end_addr: 0, + next_desc: 0, + }; CHANNEL_COUNT], +})); + +trait SealedChannel {} +trait SealedWord {} + +/// DMA channel interface. +#[allow(private_bounds)] +pub trait Channel: PeripheralType + SealedChannel + Into + Sized + 'static { + /// Channel number. + fn number(&self) -> u8; + + /// Channel registry block. + fn regs(&self) -> crate::pac::dma::Channel { + crate::pac::DMA0.channel(self.number() as _) + } +} + +/// DMA word. +#[allow(private_bounds)] +pub trait Word: SealedWord { + /// Word size. + fn size() -> crate::pac::dma::vals::Width; +} + +impl SealedWord for u8 {} +impl Word for u8 { + fn size() -> crate::pac::dma::vals::Width { + crate::pac::dma::vals::Width::BIT_8 + } +} + +impl SealedWord for u16 {} +impl Word for u16 { + fn size() -> crate::pac::dma::vals::Width { + crate::pac::dma::vals::Width::BIT_16 + } +} + +impl SealedWord for u32 {} +impl Word for u32 { + fn size() -> crate::pac::dma::vals::Width { + crate::pac::dma::vals::Width::BIT_32 + } +} + +/// Type erased DMA channel. +pub struct AnyChannel { + number: u8, +} + +impl_peripheral!(AnyChannel); + +impl SealedChannel for AnyChannel {} +impl Channel for AnyChannel { + fn number(&self) -> u8 { + self.number + } +} + +macro_rules! channel { + ($name:ident, $num:expr) => { + impl SealedChannel for peripherals::$name {} + impl Channel for peripherals::$name { + fn number(&self) -> u8 { + $num + } + } + + impl From for crate::dma::AnyChannel { + fn from(val: peripherals::$name) -> Self { + Self { number: val.number() } + } + } + }; +} + +channel!(DMA_CH0, 0); +channel!(DMA_CH1, 1); +channel!(DMA_CH2, 2); +channel!(DMA_CH3, 3); +channel!(DMA_CH4, 4); +channel!(DMA_CH5, 5); +channel!(DMA_CH6, 6); +channel!(DMA_CH7, 7); +channel!(DMA_CH8, 8); +channel!(DMA_CH9, 9); +channel!(DMA_CH10, 10); +channel!(DMA_CH11, 11); +channel!(DMA_CH12, 12); +channel!(DMA_CH13, 13); +channel!(DMA_CH14, 14); +channel!(DMA_CH15, 15); +channel!(DMA_CH16, 16); +channel!(DMA_CH17, 17); +channel!(DMA_CH18, 18); +channel!(DMA_CH19, 19); +channel!(DMA_CH20, 20); +channel!(DMA_CH21, 21); +channel!(DMA_CH22, 22); diff --git a/embassy-nxp/src/lib.rs b/embassy-nxp/src/lib.rs index 74142a10b..f0f0afb6c 100644 --- a/embassy-nxp/src/lib.rs +++ b/embassy-nxp/src/lib.rs @@ -3,6 +3,8 @@ // This mod MUST go first, so that the others see its macros. pub(crate) mod fmt; +#[cfg(feature = "lpc55-core0")] +pub mod dma; pub mod gpio; #[cfg(feature = "lpc55-core0")] pub mod pint; @@ -20,6 +22,9 @@ mod time_driver; #[cfg_attr(feature = "mimxrt1062", path = "chips/mimxrt1062.rs")] mod chip; +// TODO: Remove when this module is implemented for other chips +#[cfg(feature = "lpc55-core0")] +pub use chip::interrupt; #[cfg(feature = "unstable-pac")] pub use chip::pac; #[cfg(not(feature = "unstable-pac"))] @@ -27,6 +32,67 @@ pub(crate) use chip::pac; pub use chip::{peripherals, Peripherals}; pub use embassy_hal_internal::{Peri, PeripheralType}; +/// Macro to bind interrupts to handlers. +/// (Copied from `embassy-rp`) +/// This defines the right interrupt handlers, and creates a unit struct (like `struct Irqs;`) +/// and implements the right [`Binding`]s for it. You can pass this struct to drivers to +/// prove at compile-time that the right interrupts have been bound. +/// +/// Example of how to bind one interrupt: +/// +/// ```rust,ignore +/// use embassy_nxp::{bind_interrupts, usart, peripherals}; +/// +/// bind_interrupts!( +/// /// Binds the USART Interrupts. +/// struct Irqs { +/// FLEXCOMM0 => usart::InterruptHandler; +/// } +/// ); +/// ``` +#[macro_export] +macro_rules! bind_interrupts { + ($(#[$attr:meta])* $vis:vis struct $name:ident { + $( + $(#[cfg($cond_irq:meta)])? + $irq:ident => $( + $(#[cfg($cond_handler:meta)])? + $handler:ty + ),*; + )* + }) => { + #[derive(Copy, Clone)] + $(#[$attr])* + $vis struct $name; + + $( + #[allow(non_snake_case)] + #[no_mangle] + $(#[cfg($cond_irq)])? + unsafe extern "C" fn $irq() { + unsafe { + $( + $(#[cfg($cond_handler)])? + <$handler as $crate::interrupt::typelevel::Handler<$crate::interrupt::typelevel::$irq>>::on_interrupt(); + + )* + } + } + + $(#[cfg($cond_irq)])? + $crate::bind_interrupts!(@inner + $( + $(#[cfg($cond_handler)])? + unsafe impl $crate::interrupt::typelevel::Binding<$crate::interrupt::typelevel::$irq, $handler> for $name {} + )* + ); + )* + }; + (@inner $($t:tt)*) => { + $($t)* + } +} + /// Initialize the `embassy-nxp` HAL with the provided configuration. /// /// This returns the peripheral singletons that can be used for creating drivers. @@ -92,6 +158,9 @@ pub fn init(_config: config::Config) -> Peripherals { #[cfg(feature = "_time_driver")] time_driver::init(); + #[cfg(feature = "lpc55-core0")] + dma::init(); + peripherals } @@ -133,5 +202,8 @@ macro_rules! impl_mode { /// Blocking mode. pub struct Blocking; +/// Asynchronous mode. +pub struct Async; impl_mode!(Blocking); +impl_mode!(Async); diff --git a/embassy-nxp/src/usart/lpc55.rs b/embassy-nxp/src/usart/lpc55.rs index 428b80c4b..9034ed429 100644 --- a/embassy-nxp/src/usart/lpc55.rs +++ b/embassy-nxp/src/usart/lpc55.rs @@ -1,14 +1,24 @@ +use core::fmt::Debug; +use core::future::poll_fn; use core::marker::PhantomData; +use core::sync::atomic::{AtomicBool, Ordering}; +use core::task::Poll; +use embassy_futures::select::{select, Either}; +use embassy_hal_internal::interrupt::InterruptExt; use embassy_hal_internal::{Peri, PeripheralType}; +use embassy_sync::waitqueue::AtomicWaker; use embedded_io::{self, ErrorKind}; +use crate::dma::{AnyChannel, Channel}; use crate::gpio::{match_iocon, AnyPin, Bank, SealedPin}; +use crate::interrupt::typelevel::{Binding, Interrupt as _}; +use crate::interrupt::Interrupt; use crate::pac::flexcomm::Flexcomm as FlexcommReg; use crate::pac::iocon::vals::PioFunc; use crate::pac::usart::Usart as UsartReg; use crate::pac::*; -use crate::{Blocking, Mode}; +use crate::{Async, Blocking, Mode}; /// Serial error #[derive(Debug, Eq, PartialEq, Copy, Clone)] @@ -101,6 +111,12 @@ impl Default for Config { } } +/// Internal DMA state of UART RX. +pub struct DmaState { + rx_err_waker: AtomicWaker, + rx_err: AtomicBool, +} + /// # Type parameters /// 'd: the lifetime marker ensuring correct borrow checking for peripherals used at compile time /// T: the peripheral instance type allowing usage of peripheral specific registers @@ -112,24 +128,33 @@ pub struct Usart<'d, M: Mode> { pub struct UsartTx<'d, M: Mode> { info: &'static Info, - phantom: PhantomData<(&'d (), M)>, + tx_dma: Option>, + phantom: PhantomData, } pub struct UsartRx<'d, M: Mode> { info: &'static Info, - phantom: PhantomData<(&'d (), M)>, + dma_state: &'static DmaState, + rx_dma: Option>, + phantom: PhantomData, } impl<'d, M: Mode> UsartTx<'d, M> { - pub fn new(_usart: Peri<'d, T>, tx: Peri<'d, impl TxPin>, config: Config) -> Self { + pub fn new( + _usart: Peri<'d, T>, + tx: Peri<'d, impl TxPin>, + tx_dma: Peri<'d, impl Channel>, + config: Config, + ) -> Self { Usart::::init::(Some(tx.into()), None, config); - Self::new_inner(T::info()) + Self::new_inner(T::info(), Some(tx_dma.into())) } #[inline] - fn new_inner(info: &'static Info) -> Self { + fn new_inner(info: &'static Info, tx_dma: Option>) -> Self { Self { info, + tx_dma, phantom: PhantomData, } } @@ -155,20 +180,65 @@ impl<'d, M: Mode> UsartTx<'d, M> { impl<'d> UsartTx<'d, Blocking> { pub fn new_blocking(_usart: Peri<'d, T>, tx: Peri<'d, impl TxPin>, config: Config) -> Self { Usart::::init::(Some(tx.into()), None, config); - Self::new_inner(T::info()) + Self::new_inner(T::info(), None) } } +impl<'d> UsartTx<'d, Async> { + /// Write to UART TX from the provided buffer using DMA. + pub async fn write(&mut self, buffer: &[u8]) -> Result<(), Error> { + // Unwrap() can be used because UsartTx::new() in Async mode always sets it to Some + let ch = self.tx_dma.as_mut().unwrap().reborrow(); + let transfer = unsafe { + // Enable to pace DMA transfers. + self.info.usart_reg.fifocfg().modify(|w| w.set_dmatx(true)); + // If future is not assigned to a variable, the data register pointer + // is held across an await and makes the future non-Send. + crate::dma::write(ch, buffer, self.info.usart_reg.fifowr().as_ptr() as *mut _) + }; + transfer.await; + Ok(()) + } +} impl<'d, M: Mode> UsartRx<'d, M> { - pub fn new(_usart: Peri<'d, T>, rx: Peri<'d, impl RxPin>, config: Config) -> Self { + pub fn new( + _usart: Peri<'d, T>, + rx: Peri<'d, impl RxPin>, + has_irq: bool, + rx_dma: Peri<'d, impl Channel>, + config: Config, + ) -> Self { Usart::::init::(None, Some(rx.into()), config); - Self::new_inner(T::info()) + Self::new_inner(T::info(), T::dma_state(), has_irq, Some(rx_dma.into())) } - #[inline] - fn new_inner(info: &'static Info) -> Self { + fn new_inner( + info: &'static Info, + dma_state: &'static DmaState, + has_irq: bool, + rx_dma: Option>, + ) -> Self { + core::debug_assert_eq!(has_irq, rx_dma.is_some()); + if has_irq { + // Disable all the related interrupts for now. + info.usart_reg.intenclr().write(|w| { + w.set_framerrclr(true); + w.set_parityerrclr(true); + w.set_rxnoiseclr(true); + }); + info.usart_reg.fifointenclr().modify(|w| { + w.set_rxlvl(true); + w.set_rxerr(true); + }); + info.interrupt.unpend(); + unsafe { + info.interrupt.enable(); + } + } Self { info, + dma_state, + rx_dma, phantom: PhantomData, } } @@ -211,7 +281,120 @@ impl<'d, M: Mode> UsartRx<'d, M> { impl<'d> UsartRx<'d, Blocking> { pub fn new_blocking(_usart: Peri<'d, T>, rx: Peri<'d, impl RxPin>, config: Config) -> Self { Usart::::init::(None, Some(rx.into()), config); - Self::new_inner(T::info()) + Self::new_inner(T::info(), T::dma_state(), false, None) + } +} + +/// Interrupt handler. +pub struct InterruptHandler { + _uart: PhantomData, +} + +impl crate::interrupt::typelevel::Handler for InterruptHandler { + unsafe fn on_interrupt() { + let regs = T::info().usart_reg; + if !regs.fifocfg().read().dmarx() { + return; + } + let state = T::dma_state(); + state.rx_err.store(true, Ordering::Relaxed); + state.rx_err_waker.wake(); + // Disable the error interrupts instead of clearing the flags. Clearing the + // flags would allow the DMA transfer to continue, potentially signaling + // completion before we can check for errors that happened *during* the transfer. + regs.intenclr().write(|w| { + w.set_framerrclr(true); + w.set_rxnoiseclr(true); + w.set_parityerrclr(true); + }); + regs.fifointenclr().write(|w| w.set_rxerr(true)); + } +} + +impl<'d> UsartRx<'d, Async> { + /// Read from USART RX into the provided buffer. + pub async fn read(&mut self, buffer: &mut [u8]) -> Result<(), Error> { + // Clear error flags before the FIFO is drained. Errors that have accumulated + // in the flags will also be present in the FIFO. + self.dma_state.rx_err.store(false, Ordering::Relaxed); + self.info.usart_reg.intenclr().write(|w| { + w.set_framerrclr(true); + w.set_parityerrclr(true); + w.set_rxnoiseclr(true); + }); + self.info.usart_reg.fifointenclr().modify(|w| w.set_rxerr(true)); + // Then drain the fifo. It is necessary to read at most 16 bytes (the size of FIFO). + // Errors that apply to FIFO bytes will be reported directly. + let buffer = match { + let limit = buffer.len().min(16); + self.drain_fifo(&mut buffer[0..limit]) + } { + Ok(len) if len < buffer.len() => &mut buffer[len..], + Ok(_) => return Ok(()), + Err((_i, e)) => return Err(e), + }; + + // Start a DMA transfer. If errors have happened in the interim some error + // interrupt flags will have been raised, and those will be picked up immediately + // by the interrupt handler. + // Unwrap() can be used because UsartRx::new() in Async mode always sets it to Some + let ch = self.rx_dma.as_mut().unwrap().reborrow(); + + self.info.usart_reg.intenset().write(|w| { + w.set_framerren(true); + w.set_parityerren(true); + w.set_rxnoiseen(true); + }); + self.info.usart_reg.fifointenset().modify(|w| w.set_rxerr(true)); + self.info.usart_reg.fifocfg().modify(|w| w.set_dmarx(true)); + let transfer = unsafe { + // If we don't assign future to a variable, the data register pointer + // is held across an await and makes the future non-Send. + crate::dma::read(ch, self.info.usart_reg.fiford().as_ptr() as *const _, buffer) + }; + + // wait for either the transfer to complete or an error to happen. + let transfer_result = select( + transfer, + poll_fn(|cx| { + self.dma_state.rx_err_waker.register(cx.waker()); + match self.dma_state.rx_err.swap(false, Ordering::Relaxed) { + false => Poll::Pending, + e => Poll::Ready(e), + } + }), + ) + .await; + + let errors = match transfer_result { + Either::First(()) => { + // The DMA controller finished, BUT if an error occurred on the LAST + // byte, then we may still need to grab the error state! + self.dma_state.rx_err.swap(false, Ordering::Relaxed) + } + Either::Second(e) => { + // There is an error, which means this is the error that + // was problematic. + e + } + }; + + // If we got no error, just return at this point + if !errors { + return Ok(()); + } + + // If we DID get an error, we need to figure out which one it was. + if self.info.usart_reg.intstat().read().framerrint() { + return Err(Error::Framing); + } else if self.info.usart_reg.intstat().read().parityerrint() { + return Err(Error::Parity); + } else if self.info.usart_reg.intstat().read().rxnoiseint() { + return Err(Error::Noise); + } else if self.info.usart_reg.fifointstat().read().rxerr() { + return Err(Error::Overrun); + } + unreachable!("unrecognized rx error"); } } @@ -222,7 +405,29 @@ impl<'d> Usart<'d, Blocking> { rx: Peri<'d, impl RxPin>, config: Config, ) -> Self { - Self::new_inner(usart, tx.into(), rx.into(), config) + Self::new_inner(usart, tx.into(), rx.into(), false, None, None, config) + } +} + +impl<'d> Usart<'d, Async> { + pub fn new( + uart: Peri<'d, T>, + tx: Peri<'d, impl TxPin>, + rx: Peri<'d, impl RxPin>, + _irq: impl Binding>, + tx_dma: Peri<'d, impl TxChannel>, + rx_dma: Peri<'d, impl RxChannel>, + config: Config, + ) -> Self { + Self::new_inner( + uart, + tx.into(), + rx.into(), + true, + Some(tx_dma.into()), + Some(rx_dma.into()), + config, + ) } } @@ -231,12 +436,15 @@ impl<'d, M: Mode> Usart<'d, M> { _usart: Peri<'d, T>, mut tx: Peri<'d, AnyPin>, mut rx: Peri<'d, AnyPin>, + has_irq: bool, + tx_dma: Option>, + rx_dma: Option>, config: Config, ) -> Self { Self::init::(Some(tx.reborrow()), Some(rx.reborrow()), config); Self { - tx: UsartTx::new_inner(T::info()), - rx: UsartRx::new_inner(T::info()), + tx: UsartTx::new_inner(T::info(), tx_dma), + rx: UsartRx::new_inner(T::info(), T::dma_state(), has_irq, rx_dma), } } @@ -390,9 +598,11 @@ impl<'d, M: Mode> Usart<'d, M> { SYSCON .presetctrl1() .modify(|w| w.set_fc_rst(instance_number, syscon::vals::FcRst::RELEASED)); - flexcomm_register - .pselid() - .modify(|w| w.set_persel(flexcomm::vals::Persel::USART)); + flexcomm_register.pselid().modify(|w| { + w.set_persel(flexcomm::vals::Persel::USART); + // This will lock the peripheral PERSEL and will not allow any changes until the board is reset. + w.set_lock(true); + }); } fn configure_usart(info: &'static Info, config: &Config) { @@ -471,6 +681,8 @@ impl<'d, M: Mode> Usart<'d, M> { }); registers.cfg().modify(|w| w.set_enable(true)); + registers.fifointenset().modify(|w| w.set_rxerr(true)); + // Drain RX FIFO in case it still has some unrelevant data while registers.fifostat().read().rxnotempty() { let _ = registers.fiford().read().0; @@ -513,6 +725,17 @@ impl<'d, M: Mode> Usart<'d, M> { } } +impl<'d> Usart<'d, Async> { + /// Write to UART TX from the provided buffer. + pub async fn write(&mut self, buffer: &[u8]) -> Result<(), Error> { + self.tx.write(buffer).await + } + + /// Read from UART RX into the provided buffer. + pub async fn read(&mut self, buffer: &mut [u8]) -> Result<(), Error> { + self.rx.read(buffer).await + } +} impl<'d, M: Mode> embedded_hal_02::blocking::serial::Write for UsartTx<'d, M> { type Error = Error; @@ -584,10 +807,12 @@ impl<'d> embedded_io::Read for Usart<'d, Blocking> { struct Info { usart_reg: UsartReg, fc_reg: FlexcommReg, + interrupt: Interrupt, } trait SealedInstance { fn info() -> &'static Info; + fn dma_state() -> &'static DmaState; fn instance_number() -> usize; fn tx_pin_func() -> PioFunc; fn rx_pin_func() -> PioFunc; @@ -595,7 +820,10 @@ trait SealedInstance { /// UART instance. #[allow(private_bounds)] -pub trait Instance: SealedInstance + PeripheralType {} +pub trait Instance: SealedInstance + PeripheralType { + /// Interrupt for this instance. + type Interrupt: crate::interrupt::typelevel::Interrupt; +} macro_rules! impl_instance { ($inst:ident, $fc:ident, $tx_pin:ident, $rx_pin:ident, $fc_num:expr) => { @@ -604,9 +832,18 @@ macro_rules! impl_instance { static INFO: Info = Info { usart_reg: crate::pac::$inst, fc_reg: crate::pac::$fc, + interrupt: crate::interrupt::typelevel::$fc::IRQ, }; &INFO } + + fn dma_state() -> &'static DmaState { + static STATE: DmaState = DmaState { + rx_err_waker: AtomicWaker::new(), + rx_err: AtomicBool::new(false), + }; + &STATE + } #[inline] fn instance_number() -> usize { $fc_num @@ -620,7 +857,9 @@ macro_rules! impl_instance { PioFunc::$rx_pin } } - impl $crate::usart::Instance for $crate::peripherals::$inst {} + impl $crate::usart::Instance for $crate::peripherals::$inst { + type Interrupt = crate::interrupt::typelevel::$fc; + } }; } @@ -663,3 +902,34 @@ impl_pin!(PIO1_16, USART6, Tx); impl_pin!(PIO1_13, USART6, Rx); impl_pin!(PIO0_19, USART7, Tx); impl_pin!(PIO0_20, USART7, Rx); + +/// Trait for TX DMA channels. +pub trait TxChannel: crate::dma::Channel {} +/// Trait for RX DMA channels. +pub trait RxChannel: crate::dma::Channel {} + +macro_rules! impl_channel { + ($dma:ident, $instance:ident, Tx) => { + impl TxChannel for crate::peripherals::$dma {} + }; + ($dma:ident, $instance:ident, Rx) => { + impl RxChannel for crate::peripherals::$dma {} + }; +} + +impl_channel!(DMA_CH4, USART0, Rx); +impl_channel!(DMA_CH5, USART0, Tx); +impl_channel!(DMA_CH6, USART1, Rx); +impl_channel!(DMA_CH7, USART1, Tx); +impl_channel!(DMA_CH10, USART2, Rx); +impl_channel!(DMA_CH11, USART2, Tx); +impl_channel!(DMA_CH8, USART3, Rx); +impl_channel!(DMA_CH9, USART3, Tx); +impl_channel!(DMA_CH12, USART4, Rx); +impl_channel!(DMA_CH13, USART4, Tx); +impl_channel!(DMA_CH14, USART5, Rx); +impl_channel!(DMA_CH15, USART5, Tx); +impl_channel!(DMA_CH16, USART6, Rx); +impl_channel!(DMA_CH17, USART6, Tx); +impl_channel!(DMA_CH18, USART7, Rx); +impl_channel!(DMA_CH19, USART7, Tx); diff --git a/examples/lpc55s69/src/bin/usart_async.rs b/examples/lpc55s69/src/bin/usart_async.rs new file mode 100644 index 000000000..b06abd477 --- /dev/null +++ b/examples/lpc55s69/src/bin/usart_async.rs @@ -0,0 +1,70 @@ +#![no_std] +#![no_main] + +use core::str::from_utf8_mut; + +use defmt::*; +use embassy_executor::Spawner; +use embassy_nxp::bind_interrupts; +use embassy_nxp::gpio::{Level, Output}; +use embassy_nxp::peripherals::USART2; +use embassy_nxp::usart::{Config, InterruptHandler, Usart}; +use embassy_time::Timer; +use {defmt_rtt as _, panic_halt as _}; + +bind_interrupts!(struct Irqs { + FLEXCOMM2 => InterruptHandler; + } +); + +#[embassy_executor::task] +async fn blinky_task(mut led: Output<'static>) { + loop { + info!("[TASK] led off!"); + led.set_high(); + Timer::after_millis(500).await; + + info!("[TASK] led on!"); + led.set_low(); + Timer::after_millis(500).await; + } +} + +#[embassy_executor::main] +async fn main(spawner: Spawner) { + let p = embassy_nxp::init(Default::default()); + let mut usart = Usart::new( + p.USART2, + p.PIO0_27, + p.PIO1_24, + Irqs, + p.DMA_CH11, + p.DMA_CH10, + Config::default(), + ); + let led = Output::new(p.PIO1_6, Level::Low); + spawner.spawn(blinky_task(led).unwrap()); + info!("[MAIN] Entering main loop"); + loop { + let tx_buf = b"Hello, Ferris!"; + let mut rx_buf = [0u8; 14]; + info!("[MAIN] Write a message"); + usart.write(tx_buf).await.unwrap(); + Timer::after_millis(500).await; + + info!("[MAIN] Read a message"); + match usart.read(&mut rx_buf).await { + Ok(_) => match from_utf8_mut(&mut rx_buf) { + Ok(str) => { + info!("[MAIN] The message is: {}", str); + } + Err(_) => { + error!("[MAIN] Error in converting to UTF8"); + } + }, + Err(e) => warn!("[MAIN] Error: {}", e), + } + + Timer::after_millis(500).await; + } +} -- cgit From 085ab9f617357cf94b8b4e44424850e48add2fae Mon Sep 17 00:00:00 2001 From: Dario Nieuwenhuis Date: Fri, 26 Sep 2025 01:14:12 +0200 Subject: stm32: update metapac, add L4+ to CI. --- embassy-stm32/Cargo.toml | 8 ++++++-- embassy-stm32/src/rcc/bd.rs | 10 +++++----- embassy-stm32/src/rtc/low_power.rs | 36 +++++++++++------------------------- embassy-stm32/src/rtc/mod.rs | 21 ++++++++------------- embassy-stm32/src/rtc/v2.rs | 8 ++++---- 5 files changed, 34 insertions(+), 49 deletions(-) diff --git a/embassy-stm32/Cargo.toml b/embassy-stm32/Cargo.toml index b029f33b0..82bc73708 100644 --- a/embassy-stm32/Cargo.toml +++ b/embassy-stm32/Cargo.toml @@ -66,6 +66,10 @@ build = [ {target = "thumbv7em-none-eabi", features = ["defmt", "exti", "stm32l431cb", "time", "time-driver-any"]}, {target = "thumbv7em-none-eabi", features = ["defmt", "exti", "stm32l476vg", "time", "time-driver-any"]}, {target = "thumbv7em-none-eabi", features = ["defmt", "exti", "stm32l422cb", "time", "time-driver-any"]}, + {target = "thumbv7em-none-eabi", features = ["defmt", "exti", "stm32l4p5ae", "time", "time-driver-any", "single-bank"]}, + {target = "thumbv7em-none-eabi", features = ["defmt", "exti", "stm32l4q5zg", "time", "time-driver-any", "single-bank"]}, + {target = "thumbv7em-none-eabi", features = ["defmt", "exti", "stm32l4r9vi", "time", "time-driver-any", "dual-bank"]}, + {target = "thumbv7em-none-eabi", features = ["defmt", "exti", "stm32l4s7vi", "time", "time-driver-any", "dual-bank"]}, {target = "thumbv7em-none-eabi", features = ["defmt", "exti", "stm32wb15cc", "time", "time-driver-any"]}, {target = "thumbv6m-none-eabi", features = ["defmt", "exti", "stm32l072cz", "time", "time-driver-any"]}, {target = "thumbv6m-none-eabi", features = ["defmt", "exti", "stm32l041f6", "time", "time-driver-any"]}, @@ -174,7 +178,7 @@ futures-util = { version = "0.3.30", default-features = false } sdio-host = "0.9.0" critical-section = "1.1" #stm32-metapac = { version = "18" } -stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-b46fcc32f329f05fbdca4c007ed4bc305b0ade85" } +stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-b9f6b0c542d85ee695d71c35ced195e0cef51ac0" } vcell = "0.1.3" nb = "1.0.0" @@ -204,7 +208,7 @@ proc-macro2 = "1.0.36" quote = "1.0.15" #stm32-metapac = { version = "18", default-features = false, features = ["metadata"]} -stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-b46fcc32f329f05fbdca4c007ed4bc305b0ade85", default-features = false, features = ["metadata"] } +stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-b9f6b0c542d85ee695d71c35ced195e0cef51ac0", default-features = false, features = ["metadata"] } [features] default = ["rt"] diff --git a/embassy-stm32/src/rcc/bd.rs b/embassy-stm32/src/rcc/bd.rs index e2c704405..63fc195dd 100644 --- a/embassy-stm32/src/rcc/bd.rs +++ b/embassy-stm32/src/rcc/bd.rs @@ -52,9 +52,9 @@ impl From for crate::pac::rcc::vals::Lsedrv { } } -#[cfg(not(any(rtc_v2l0, rtc_v2l1, stm32c0)))] +#[cfg(not(any(rtc_v2_l0, rtc_v2_l1, stm32c0)))] type Bdcr = crate::pac::rcc::regs::Bdcr; -#[cfg(any(rtc_v2l0, rtc_v2l1))] +#[cfg(any(rtc_v2_l0, rtc_v2_l1))] type Bdcr = crate::pac::rcc::regs::Csr; #[cfg(any(stm32c0))] type Bdcr = crate::pac::rcc::regs::Csr1; @@ -76,9 +76,9 @@ fn unlock() { } fn bdcr() -> Reg { - #[cfg(any(rtc_v2l0, rtc_v2l1))] + #[cfg(any(rtc_v2_l0, rtc_v2_l1))] return crate::pac::RCC.csr(); - #[cfg(not(any(rtc_v2l0, rtc_v2l1, stm32c0)))] + #[cfg(not(any(rtc_v2_l0, rtc_v2_l1, stm32c0)))] return crate::pac::RCC.bdcr(); #[cfg(any(stm32c0))] return crate::pac::RCC.csr1(); @@ -273,7 +273,7 @@ impl LsConfig { if self.rtc != RtcClockSource::DISABLE { bdcr().modify(|w| { - #[cfg(any(rtc_v2h7, rtc_v2l4, rtc_v2wb, rtc_v3, rtc_v3u5))] + #[cfg(any(rtc_v2_h7, rtc_v2_l4, rtc_v2_wb, rtc_v3_base, rtc_v3_u5))] assert!(!w.lsecsson(), "RTC is not compatible with LSE CSS, yet."); #[cfg(not(rcc_wba))] diff --git a/embassy-stm32/src/rtc/low_power.rs b/embassy-stm32/src/rtc/low_power.rs index 78ccd3e6c..a81ac6746 100644 --- a/embassy-stm32/src/rtc/low_power.rs +++ b/embassy-stm32/src/rtc/low_power.rs @@ -1,4 +1,8 @@ +#[cfg(feature = "time")] +use embassy_time::{Duration, TICK_HZ}; + use super::{bcd2_to_byte, DateTimeError, Rtc, RtcError}; +use crate::interrupt::typelevel::Interrupt; use crate::peripherals::RTC; use crate::rtc::SealedInstance; @@ -11,7 +15,7 @@ pub(super) struct RtcInstant { } impl RtcInstant { - #[cfg(not(rtc_v2f2))] + #[cfg(not(rtc_v2_f2))] const fn from(second: u8, subsecond: u16) -> Result { if second > 59 { Err(DateTimeError::InvalidSecond) @@ -38,8 +42,6 @@ impl core::ops::Sub for RtcInstant { type Output = embassy_time::Duration; fn sub(self, rhs: Self) -> Self::Output { - use embassy_time::{Duration, TICK_HZ}; - let second = if self.second < rhs.second { self.second + 60 } else { @@ -129,11 +131,6 @@ impl Rtc { requested_duration: embassy_time::Duration, cs: critical_section::CriticalSection, ) { - use embassy_time::{Duration, TICK_HZ}; - - #[cfg(any(rtc_v3, rtc_v3u5, rtc_v3l5))] - use crate::pac::rtc::vals::Calrf; - // Panic if the rcc mod knows we're not using low-power rtc #[cfg(any(rcc_wb, rcc_f4, rcc_f410))] unsafe { crate::rcc::get_freqs() }.rtc.to_hertz().unwrap(); @@ -150,17 +147,15 @@ impl Rtc { self.write(false, |regs| { regs.cr().modify(|w| w.set_wute(false)); - #[cfg(any( - rtc_v2f0, rtc_v2f2, rtc_v2f3, rtc_v2f4, rtc_v2f7, rtc_v2h7, rtc_v2l0, rtc_v2l1, rtc_v2l4, rtc_v2wb - ))] + #[cfg(rtc_v2)] { regs.isr().modify(|w| w.set_wutf(false)); while !regs.isr().read().wutwf() {} } - #[cfg(any(rtc_v3, rtc_v3u5, rtc_v3l5))] + #[cfg(rtc_v3)] { - regs.scr().write(|w| w.set_cwutf(Calrf::CLEAR)); + regs.scr().write(|w| w.set_cwutf(crate::pac::rtc::vals::Calrf::CLEAR)); while !regs.icsr().read().wutwf() {} } @@ -185,10 +180,6 @@ impl Rtc { /// stop the wakeup alarm and return the time elapsed since `start_wakeup_alarm` /// was called, otherwise none pub(crate) fn stop_wakeup_alarm(&self, cs: critical_section::CriticalSection) -> Option { - use crate::interrupt::typelevel::Interrupt; - #[cfg(any(rtc_v3, rtc_v3u5, rtc_v3l5))] - use crate::pac::rtc::vals::Calrf; - let instant = self.instant().unwrap(); if RTC::regs().cr().read().wute() { trace!("rtc: stop wakeup alarm at {}", instant); @@ -197,13 +188,10 @@ impl Rtc { regs.cr().modify(|w| w.set_wutie(false)); regs.cr().modify(|w| w.set_wute(false)); - #[cfg(any( - rtc_v2f0, rtc_v2f2, rtc_v2f3, rtc_v2f4, rtc_v2f7, rtc_v2h7, rtc_v2l0, rtc_v2l1, rtc_v2l4, rtc_v2wb - ))] + #[cfg(rtc_v2)] regs.isr().modify(|w| w.set_wutf(false)); - - #[cfg(any(rtc_v3, rtc_v3u5, rtc_v3l5))] - regs.scr().write(|w| w.set_cwutf(Calrf::CLEAR)); + #[cfg(rtc_v3)] + regs.scr().write(|w| w.set_cwutf(crate::pac::rtc::vals::Calrf::CLEAR)); // Check RM for EXTI and/or NVIC section, "Event event input mapping" or "EXTI interrupt/event mapping" or something similar, // there is a table for every "Event input" / "EXTI Line". @@ -222,8 +210,6 @@ impl Rtc { } pub(crate) fn enable_wakeup_line(&self) { - use crate::interrupt::typelevel::Interrupt; - ::WakeupInterrupt::unpend(); unsafe { ::WakeupInterrupt::enable() }; diff --git a/embassy-stm32/src/rtc/mod.rs b/embassy-stm32/src/rtc/mod.rs index 449f3008a..92dec0960 100644 --- a/embassy-stm32/src/rtc/mod.rs +++ b/embassy-stm32/src/rtc/mod.rs @@ -18,14 +18,9 @@ use crate::pac::rtc::regs::{Dr, Tr}; use crate::time::Hertz; /// refer to AN4759 to compare features of RTC2 and RTC3 -#[cfg_attr(any(rtc_v1), path = "v1.rs")] -#[cfg_attr( - any( - rtc_v2f0, rtc_v2f2, rtc_v2f3, rtc_v2f4, rtc_v2f7, rtc_v2h7, rtc_v2l0, rtc_v2l1, rtc_v2l4, rtc_v2wb - ), - path = "v2.rs" -)] -#[cfg_attr(any(rtc_v3, rtc_v3u5, rtc_v3l5, rtc_v3h7rs, rtc_v3c0), path = "v3.rs")] +#[cfg_attr(rtc_v1, path = "v1.rs")] +#[cfg_attr(rtc_v2, path = "v2.rs")] +#[cfg_attr(rtc_v3, path = "v3.rs")] mod _version; #[allow(unused_imports)] pub use _version::*; @@ -72,12 +67,12 @@ impl RtcTimeProvider { // Calculate second fraction and multiply to microseconds // Formula from RM0410 - #[cfg(not(rtc_v2f2))] + #[cfg(not(rtc_v2_f2))] let us = { let prediv = RTC::regs().prer().read().prediv_s() as f32; (((prediv - _ss as f32) / (prediv + 1.0)) * 1e6).min(999_999.0) as u32 }; - #[cfg(rtc_v2f2)] + #[cfg(rtc_v2_f2)] let us = 0; DateTime::from(year, month, day, weekday, hour, minute, second, us).map_err(RtcError::InvalidDateTime) @@ -87,9 +82,9 @@ impl RtcTimeProvider { fn read(&self, mut f: impl FnMut(Dr, Tr, u16) -> Result) -> Result { let r = RTC::regs(); - #[cfg(not(rtc_v2f2))] + #[cfg(not(rtc_v2_f2))] let read_ss = || r.ssr().read().ss(); - #[cfg(rtc_v2f2)] + #[cfg(rtc_v2_f2)] let read_ss = || 0; let mut ss = read_ss(); @@ -168,7 +163,7 @@ impl Rtc { this.configure(async_psc, sync_psc); // Wait for the clock to update after initialization - #[cfg(not(rtc_v2f2))] + #[cfg(not(rtc_v2_f2))] { let now = this.time_provider().read(|_, _, ss| Ok(ss)).unwrap(); while now == this.time_provider().read(|_, _, ss| Ok(ss)).unwrap() {} diff --git a/embassy-stm32/src/rtc/v2.rs b/embassy-stm32/src/rtc/v2.rs index 28380a3c0..23f6ccb0c 100644 --- a/embassy-stm32/src/rtc/v2.rs +++ b/embassy-stm32/src/rtc/v2.rs @@ -11,11 +11,11 @@ impl super::Rtc { pub(super) fn configure(&mut self, async_psc: u8, sync_psc: u16) { self.write(true, |rtc| { rtc.cr().modify(|w| { - #[cfg(not(rtc_v2f2))] + #[cfg(not(rtc_v2_f2))] w.set_bypshad(true); - #[cfg(rtc_v2f2)] + #[cfg(rtc_v2_f2)] w.set_fmt(false); - #[cfg(not(rtc_v2f2))] + #[cfg(not(rtc_v2_f2))] w.set_fmt(stm32_metapac::rtc::vals::Fmt::TWENTY_FOUR_HOUR); w.set_osel(Osel::DISABLED); w.set_pol(Pol::HIGH); @@ -36,7 +36,7 @@ impl super::Rtc { /// /// To perform a calibration when `async_prescaler` is less then 3, `sync_prescaler` /// has to be reduced accordingly (see RM0351 Rev 9, sec 38.3.12). - #[cfg(not(rtc_v2f2))] + #[cfg(not(rtc_v2_f2))] pub fn calibrate(&mut self, mut clock_drift: f32, period: super::RtcCalibrationCyclePeriod) { const RTC_CALR_MIN_PPM: f32 = -487.1; const RTC_CALR_MAX_PPM: f32 = 488.5; -- cgit From 0cb88e7daf2cb46b9f6e06905b3d0113bb8dd643 Mon Sep 17 00:00:00 2001 From: Ulf Lilleengen Date: Fri, 26 Sep 2025 11:00:26 +0200 Subject: fix: update bt-hci to 0.6 Fixes an issue for controllers that emit unexpected command complete events. --- cyw43/CHANGELOG.md | 2 +- cyw43/Cargo.toml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/cyw43/CHANGELOG.md b/cyw43/CHANGELOG.md index dcf84b9ba..5c77b7093 100644 --- a/cyw43/CHANGELOG.md +++ b/cyw43/CHANGELOG.md @@ -9,7 +9,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## Unreleased - ReleaseDate - Updated documentation for Control::join() #4678 -- Bump bt-hci to 0.5.0. +- Bump bt-hci to 0.6.0. - Add error handling to HCI transport implementation. ## 0.5.0 - 2025-08-28 diff --git a/cyw43/Cargo.toml b/cyw43/Cargo.toml index 0d0c26089..c59c15a71 100644 --- a/cyw43/Cargo.toml +++ b/cyw43/Cargo.toml @@ -36,7 +36,7 @@ heapless = "0.8.0" # Bluetooth deps embedded-io-async = { version = "0.6.0", optional = true } -bt-hci = { version = "0.5.0", optional = true } +bt-hci = { version = "0.6.0", optional = true } [package.metadata.embassy] build = [ -- cgit From 03d0637d6eed2fe9d44f077aa9ad39bdc8631304 Mon Sep 17 00:00:00 2001 From: Dario Nieuwenhuis Date: Fri, 26 Sep 2025 21:21:53 +0200 Subject: Update nightly. --- embassy-executor/tests/ui/spawn_nonsend.rs | 2 -- embassy-executor/tests/ui/spawn_nonsend.stderr | 22 +++++++--------------- rust-toolchain-nightly.toml | 2 +- 3 files changed, 8 insertions(+), 18 deletions(-) diff --git a/embassy-executor/tests/ui/spawn_nonsend.rs b/embassy-executor/tests/ui/spawn_nonsend.rs index 601041941..a06c0b37a 100644 --- a/embassy-executor/tests/ui/spawn_nonsend.rs +++ b/embassy-executor/tests/ui/spawn_nonsend.rs @@ -1,7 +1,5 @@ #![cfg_attr(feature = "nightly", feature(impl_trait_in_assoc_type))] -use core::future::Future; - use embassy_executor::SendSpawner; #[embassy_executor::task] diff --git a/embassy-executor/tests/ui/spawn_nonsend.stderr b/embassy-executor/tests/ui/spawn_nonsend.stderr index 5a3131602..31efadd49 100644 --- a/embassy-executor/tests/ui/spawn_nonsend.stderr +++ b/embassy-executor/tests/ui/spawn_nonsend.stderr @@ -1,27 +1,19 @@ -warning: unused import: `core::future::Future` - --> tests/ui/spawn_nonsend.rs:3:5 - | -3 | use core::future::Future; - | ^^^^^^^^^^^^^^^^^^^^ - | - = note: `#[warn(unused_imports)]` on by default - error[E0277]: `*mut ()` cannot be sent between threads safely - --> tests/ui/spawn_nonsend.rs:13:13 + --> tests/ui/spawn_nonsend.rs:11:13 | - 7 | #[embassy_executor::task] + 5 | #[embassy_executor::task] | ------------------------- within this `impl Sized` ... -13 | s.spawn(task(core::ptr::null_mut()).unwrap()); +11 | s.spawn(task(core::ptr::null_mut()).unwrap()); | ----- ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `*mut ()` cannot be sent between threads safely | | | required by a bound introduced by this call | = help: within `impl Sized`, the trait `Send` is not implemented for `*mut ()` note: required because it's used within this closure - --> tests/ui/spawn_nonsend.rs:7:1 + --> tests/ui/spawn_nonsend.rs:5:1 | - 7 | #[embassy_executor::task] + 5 | #[embassy_executor::task] | ^^^^^^^^^^^^^^^^^^^^^^^^^ note: required because it appears within the type `impl Sized` --> src/raw/mod.rs @@ -29,9 +21,9 @@ note: required because it appears within the type `impl Sized` | pub unsafe fn _spawn_async_fn(&'static self, future: FutFn) -> Result, SpawnError> | ^^^^^^^^^^ note: required because it appears within the type `impl Sized` - --> tests/ui/spawn_nonsend.rs:7:1 + --> tests/ui/spawn_nonsend.rs:5:1 | - 7 | #[embassy_executor::task] + 5 | #[embassy_executor::task] | ^^^^^^^^^^^^^^^^^^^^^^^^^ note: required by a bound in `SendSpawner::spawn` --> src/spawner.rs diff --git a/rust-toolchain-nightly.toml b/rust-toolchain-nightly.toml index d3e88c7e1..dde431bba 100644 --- a/rust-toolchain-nightly.toml +++ b/rust-toolchain-nightly.toml @@ -1,5 +1,5 @@ [toolchain] -channel = "nightly-2025-08-05" +channel = "nightly-2025-09-26" components = [ "rust-src", "rustfmt", "llvm-tools", "miri" ] targets = [ "thumbv7em-none-eabi", -- cgit From 34911c581c1066a9650ac2103d125d5bbb9a229c Mon Sep 17 00:00:00 2001 From: Dario Nieuwenhuis Date: Fri, 26 Sep 2025 21:49:40 +0200 Subject: Fix docs build. --- .github/ci/build-nightly.sh | 2 +- .github/ci/build-xtensa.sh | 2 +- .github/ci/build.sh | 2 +- .github/ci/doc.sh | 2 +- .github/ci/janitor.sh | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/.github/ci/build-nightly.sh b/.github/ci/build-nightly.sh index 257d7ebd3..8cca1b445 100755 --- a/.github/ci/build-nightly.sh +++ b/.github/ci/build-nightly.sh @@ -23,7 +23,7 @@ fi hashtime restore /ci/cache/filetime.json || true hashtime save /ci/cache/filetime.json -cargo install --git https://github.com/embassy-rs/cargo-embassy-devtool --locked --rev 3ca80f7065acbe0b69b7da463fab60e744f9de79 +cargo install --git https://github.com/embassy-rs/cargo-embassy-devtool --locked --rev 676e6d602bf016dc71f1e98f2c7f191d7bd20707 ./ci-nightly.sh diff --git a/.github/ci/build-xtensa.sh b/.github/ci/build-xtensa.sh index 339e28467..dbd2f7ffc 100755 --- a/.github/ci/build-xtensa.sh +++ b/.github/ci/build-xtensa.sh @@ -25,7 +25,7 @@ fi hashtime restore /ci/cache/filetime.json || true hashtime save /ci/cache/filetime.json -cargo install --git https://github.com/embassy-rs/cargo-embassy-devtool --locked --rev 3ca80f7065acbe0b69b7da463fab60e744f9de79 +cargo install --git https://github.com/embassy-rs/cargo-embassy-devtool --locked --rev 676e6d602bf016dc71f1e98f2c7f191d7bd20707 ./ci-xtensa.sh diff --git a/.github/ci/build.sh b/.github/ci/build.sh index d7201aedb..d5e0e0bd2 100755 --- a/.github/ci/build.sh +++ b/.github/ci/build.sh @@ -28,7 +28,7 @@ fi hashtime restore /ci/cache/filetime.json || true hashtime save /ci/cache/filetime.json -cargo install --git https://github.com/embassy-rs/cargo-embassy-devtool --locked --rev 3ca80f7065acbe0b69b7da463fab60e744f9de79 +cargo install --git https://github.com/embassy-rs/cargo-embassy-devtool --locked --rev 676e6d602bf016dc71f1e98f2c7f191d7bd20707 ./ci.sh diff --git a/.github/ci/doc.sh b/.github/ci/doc.sh index 70ce110d1..dab47e86d 100755 --- a/.github/ci/doc.sh +++ b/.github/ci/doc.sh @@ -12,7 +12,7 @@ export CARGO_TARGET_DIR=/ci/cache/target export PATH=$CARGO_HOME/bin:$PATH mv rust-toolchain-nightly.toml rust-toolchain.toml -cargo install --git https://github.com/embassy-rs/cargo-embassy-devtool --locked --rev 3ca80f7065acbe0b69b7da463fab60e744f9de79 +cargo install --git https://github.com/embassy-rs/cargo-embassy-devtool --locked --rev 676e6d602bf016dc71f1e98f2c7f191d7bd20707 cargo embassy-devtool doc -o webroot diff --git a/.github/ci/janitor.sh b/.github/ci/janitor.sh index bd04f47fc..305c6b227 100755 --- a/.github/ci/janitor.sh +++ b/.github/ci/janitor.sh @@ -9,7 +9,7 @@ export CARGO_HOME=/ci/cache/cargo export CARGO_TARGET_DIR=/ci/cache/target export PATH=$CARGO_HOME/bin:$PATH -cargo install --git https://github.com/embassy-rs/cargo-embassy-devtool --locked --rev 3ca80f7065acbe0b69b7da463fab60e744f9de79 +cargo install --git https://github.com/embassy-rs/cargo-embassy-devtool --locked --rev 676e6d602bf016dc71f1e98f2c7f191d7bd20707 cargo embassy-devtool check-crlf cargo embassy-devtool check-manifest -- cgit From fff0a1522dd9e32a15004130d0c097f903e422b0 Mon Sep 17 00:00:00 2001 From: Nathan Samson Date: Sat, 27 Sep 2025 00:36:20 +0200 Subject: Fixes #4709. Creating an open AP after joining a WPA network doesn't work This fixes the issue by always resetting the security value when creating a new open AP. --- cyw43/CHANGELOG.md | 1 + cyw43/src/control.rs | 2 ++ 2 files changed, 3 insertions(+) diff --git a/cyw43/CHANGELOG.md b/cyw43/CHANGELOG.md index 5c77b7093..1045fd30b 100644 --- a/cyw43/CHANGELOG.md +++ b/cyw43/CHANGELOG.md @@ -11,6 +11,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Updated documentation for Control::join() #4678 - Bump bt-hci to 0.6.0. - Add error handling to HCI transport implementation. +- Reset WPA security on AP creation #4709 ## 0.5.0 - 2025-08-28 diff --git a/cyw43/src/control.rs b/cyw43/src/control.rs index e4dc0804f..fd0d4d532 100644 --- a/cyw43/src/control.rs +++ b/cyw43/src/control.rs @@ -470,6 +470,8 @@ impl<'a> Control<'a> { pfi.passphrase[..passphrase.as_bytes().len()].copy_from_slice(passphrase.as_bytes()); self.ioctl(IoctlType::Set, Ioctl::SetWsecPmk, 0, &mut pfi.to_bytes()) .await; + } else { + self.ioctl_set_u32(Ioctl::SetAuth, 0, 0).await; } // Change mutlicast rate from 1 Mbps to 11 Mbps -- cgit From e5328c78259c7e288bf54c83bc80c2d2311abdf2 Mon Sep 17 00:00:00 2001 From: Dario Nieuwenhuis Date: Sat, 27 Sep 2025 17:34:36 +0200 Subject: nrf/twim: erase instance generics --- embassy-nrf/src/twim.rs | 75 +++++++++++++++++++++++++++---------------------- 1 file changed, 41 insertions(+), 34 deletions(-) diff --git a/embassy-nrf/src/twim.rs b/embassy-nrf/src/twim.rs index 3fc59a39a..ffc9b39f6 100644 --- a/embassy-nrf/src/twim.rs +++ b/embassy-nrf/src/twim.rs @@ -2,7 +2,7 @@ #![macro_use] -use core::future::{poll_fn, Future}; +use core::future::poll_fn; use core::marker::PhantomData; use core::sync::atomic::compiler_fence; use core::sync::atomic::Ordering::SeqCst; @@ -112,12 +112,15 @@ impl interrupt::typelevel::Handler for InterruptHandl } /// TWI driver. -pub struct Twim<'d, T: Instance> { - _p: Peri<'d, T>, +pub struct Twim<'d> { + r: pac::twim::Twim, + irq: interrupt::Interrupt, + state: &'static State, tx_ram_buffer: &'d mut [u8], + _p: PhantomData<&'d ()>, } -impl<'d, T: Instance> Twim<'d, T> { +impl<'d> Twim<'d> { /// Create a new TWI driver. /// /// `tx_ram_buffer` is required if any write operations will be performed with data that is not in RAM. @@ -125,8 +128,8 @@ impl<'d, T: Instance> Twim<'d, T> { /// needs to be at least as large as the largest write operation that will be executed with a buffer /// that is not in RAM. If all write operations will be performed from RAM, an empty buffer (`&[]`) may /// be used. - pub fn new( - twim: Peri<'d, T>, + pub fn new( + _twim: Peri<'d, T>, _irq: impl interrupt::typelevel::Binding> + 'd, sda: Peri<'d, impl GpioPin>, scl: Peri<'d, impl GpioPin>, @@ -167,8 +170,11 @@ impl<'d, T: Instance> Twim<'d, T> { r.enable().write(|w| w.set_enable(vals::Enable::ENABLED)); let mut twim = Self { - _p: twim, + r: T::regs(), + irq: T::Interrupt::IRQ, + state: T::state(), tx_ram_buffer, + _p: PhantomData {}, }; // Apply runtime peripheral configuration @@ -201,7 +207,7 @@ impl<'d, T: Instance> Twim<'d, T> { return Err(Error::TxBufferTooLong); } - let r = T::regs(); + let r = self.r; // We're giving the register a pointer to the stack. Since we're // waiting for the I2C transaction to end before this stack pointer @@ -228,7 +234,7 @@ impl<'d, T: Instance> Twim<'d, T> { return Err(Error::RxBufferTooLong); } - let r = T::regs(); + let r = self.r; // We're giving the register a pointer to the stack. Since we're // waiting for the I2C transaction to end before this stack pointer @@ -250,7 +256,7 @@ impl<'d, T: Instance> Twim<'d, T> { } fn clear_errorsrc(&mut self) { - let r = T::regs(); + let r = self.r; r.errorsrc().write(|w| { w.set_anack(true); w.set_dnack(true); @@ -259,8 +265,8 @@ impl<'d, T: Instance> Twim<'d, T> { } /// Get Error instance, if any occurred. - fn check_errorsrc() -> Result<(), Error> { - let r = T::regs(); + fn check_errorsrc(&mut self) -> Result<(), Error> { + let r = self.r; let err = r.errorsrc().read(); if err.anack() { @@ -276,7 +282,7 @@ impl<'d, T: Instance> Twim<'d, T> { } fn check_rx(&self, len: usize) -> Result<(), Error> { - let r = T::regs(); + let r = self.r; if r.rxd().amount().read().0 != len as u32 { Err(Error::Receive) } else { @@ -285,7 +291,7 @@ impl<'d, T: Instance> Twim<'d, T> { } fn check_tx(&self, len: usize) -> Result<(), Error> { - let r = T::regs(); + let r = self.r; if r.txd().amount().read().0 != len as u32 { Err(Error::Transmit) } else { @@ -295,7 +301,7 @@ impl<'d, T: Instance> Twim<'d, T> { /// Wait for stop or error fn blocking_wait(&mut self) { - let r = T::regs(); + let r = self.r; loop { if r.events_suspended().read() != 0 || r.events_stopped().read() != 0 { r.events_suspended().write_value(0); @@ -312,7 +318,7 @@ impl<'d, T: Instance> Twim<'d, T> { /// Wait for stop or error #[cfg(feature = "time")] fn blocking_wait_timeout(&mut self, timeout: Duration) -> Result<(), Error> { - let r = T::regs(); + let r = self.r; let deadline = Instant::now() + timeout; loop { if r.events_suspended().read() != 0 || r.events_stopped().read() != 0 { @@ -333,10 +339,10 @@ impl<'d, T: Instance> Twim<'d, T> { } /// Wait for stop or error - fn async_wait(&mut self) -> impl Future> { - poll_fn(move |cx| { - let r = T::regs(); - let s = T::state(); + async fn async_wait(&mut self) -> Result<(), Error> { + poll_fn(|cx| { + let r = self.r; + let s = self.state; s.end_waker.register(cx.waker()); if r.events_suspended().read() != 0 || r.events_stopped().read() != 0 { @@ -349,15 +355,16 @@ impl<'d, T: Instance> Twim<'d, T> { if r.events_error().read() != 0 { r.events_error().write_value(0); r.tasks_stop().write_value(1); - if let Err(e) = Self::check_errorsrc() { + if let Err(e) = self.check_errorsrc() { return Poll::Ready(Err(e)); } else { - panic!("Found events_error bit without an error in errorsrc reg"); + return Poll::Ready(Err(Error::Timeout)); } } Poll::Pending }) + .await } fn setup_operations( @@ -367,7 +374,7 @@ impl<'d, T: Instance> Twim<'d, T> { last_op: Option<&Operation<'_>>, inten: bool, ) -> Result { - let r = T::regs(); + let r = self.r; compiler_fence(SeqCst); @@ -511,7 +518,7 @@ impl<'d, T: Instance> Twim<'d, T> { fn check_operations(&mut self, operations: &[Operation<'_>]) -> Result<(), Error> { compiler_fence(SeqCst); - Self::check_errorsrc()?; + self.check_errorsrc()?; assert!(operations.len() == 1 || operations.len() == 2); match operations { @@ -696,14 +703,14 @@ impl<'d, T: Instance> Twim<'d, T> { } } -impl<'a, T: Instance> Drop for Twim<'a, T> { +impl<'a> Drop for Twim<'a> { fn drop(&mut self) { trace!("twim drop"); // TODO: check for abort // disable! - let r = T::regs(); + let r = self.r; r.enable().write(|w| w.set_enable(vals::Enable::DISABLED)); gpio::deconfigure_pin(r.psel().sda().read()); @@ -759,7 +766,7 @@ macro_rules! impl_twim { mod eh02 { use super::*; - impl<'a, T: Instance> embedded_hal_02::blocking::i2c::Write for Twim<'a, T> { + impl<'a> embedded_hal_02::blocking::i2c::Write for Twim<'a> { type Error = Error; fn write(&mut self, addr: u8, bytes: &[u8]) -> Result<(), Error> { @@ -767,7 +774,7 @@ mod eh02 { } } - impl<'a, T: Instance> embedded_hal_02::blocking::i2c::Read for Twim<'a, T> { + impl<'a> embedded_hal_02::blocking::i2c::Read for Twim<'a> { type Error = Error; fn read(&mut self, addr: u8, bytes: &mut [u8]) -> Result<(), Error> { @@ -775,7 +782,7 @@ mod eh02 { } } - impl<'a, T: Instance> embedded_hal_02::blocking::i2c::WriteRead for Twim<'a, T> { + impl<'a> embedded_hal_02::blocking::i2c::WriteRead for Twim<'a> { type Error = Error; fn write_read<'w>(&mut self, addr: u8, bytes: &'w [u8], buffer: &'w mut [u8]) -> Result<(), Error> { @@ -804,27 +811,27 @@ impl embedded_hal_1::i2c::Error for Error { } } -impl<'d, T: Instance> embedded_hal_1::i2c::ErrorType for Twim<'d, T> { +impl<'d> embedded_hal_1::i2c::ErrorType for Twim<'d> { type Error = Error; } -impl<'d, T: Instance> embedded_hal_1::i2c::I2c for Twim<'d, T> { +impl<'d> embedded_hal_1::i2c::I2c for Twim<'d> { fn transaction(&mut self, address: u8, operations: &mut [Operation<'_>]) -> Result<(), Self::Error> { self.blocking_transaction(address, operations) } } -impl<'d, T: Instance> embedded_hal_async::i2c::I2c for Twim<'d, T> { +impl<'d> embedded_hal_async::i2c::I2c for Twim<'d> { async fn transaction(&mut self, address: u8, operations: &mut [Operation<'_>]) -> Result<(), Self::Error> { self.transaction(address, operations).await } } -impl<'d, T: Instance> SetConfig for Twim<'d, T> { +impl<'d> SetConfig for Twim<'d> { type Config = Config; type ConfigError = (); fn set_config(&mut self, config: &Self::Config) -> Result<(), Self::ConfigError> { - let r = T::regs(); + let r = self.r; r.frequency().write(|w| w.set_frequency(config.frequency)); Ok(()) -- cgit From 36d368d70e56181554b690687ef2c88a84704b0c Mon Sep 17 00:00:00 2001 From: pkj Date: Sun, 28 Sep 2025 21:13:17 +0800 Subject: stm32/timer: Support 32-bit timers in SimplePwm waveform_up method Add TimerBits matching following waveform method pattern to handle both 16-bit and 32-bit timer DMA transfers with appropriate pointer types. --- embassy-stm32/src/timer/simple_pwm.rs | 35 +++++++++++++++++++++++++++-------- 1 file changed, 27 insertions(+), 8 deletions(-) diff --git a/embassy-stm32/src/timer/simple_pwm.rs b/embassy-stm32/src/timer/simple_pwm.rs index e6165e42b..19c1610f7 100644 --- a/embassy-stm32/src/timer/simple_pwm.rs +++ b/embassy-stm32/src/timer/simple_pwm.rs @@ -339,14 +339,33 @@ impl<'d, T: GeneralInstance4Channel> SimplePwm<'d, T> { ..Default::default() }; - Transfer::new_write( - dma, - req, - duty, - self.inner.regs_1ch().ccr(channel.index()).as_ptr() as *mut u16, - dma_transfer_option, - ) - .await + match self.inner.bits() { + TimerBits::Bits16 => { + Transfer::new_write( + dma, + req, + duty, + self.inner.regs_gp16().ccr(cc_channel.index()).as_ptr() as *mut u16, + dma_transfer_option, + ) + .await + } + #[cfg(not(any(stm32l0)))] + TimerBits::Bits32 => { + #[cfg(not(any(bdma, gpdma)))] + panic!("unsupported timer bits"); + + #[cfg(any(bdma, gpdma))] + Transfer::new_write( + dma, + req, + duty, + self.inner.regs_gp16().ccr(cc_channel.index()).as_ptr() as *mut u32, + dma_transfer_option, + ) + .await + } + }; }; // restore output compare state -- cgit From 04171d903d3676d87aa0fd85719878d3087028f3 Mon Sep 17 00:00:00 2001 From: pkj Date: Sun, 28 Sep 2025 21:21:09 +0800 Subject: fix: correct register access for SimplePwm 32-bit timer support - Replace `regs_gp16().ccr()` with `regs_1ch().ccr()` for proper register access - Fix variable name from `cc_channel` to `channel` - Ensure PWM waveform generation works correctly with 32-bit timer mode --- embassy-stm32/src/timer/simple_pwm.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/embassy-stm32/src/timer/simple_pwm.rs b/embassy-stm32/src/timer/simple_pwm.rs index 19c1610f7..e60bb5b06 100644 --- a/embassy-stm32/src/timer/simple_pwm.rs +++ b/embassy-stm32/src/timer/simple_pwm.rs @@ -345,7 +345,7 @@ impl<'d, T: GeneralInstance4Channel> SimplePwm<'d, T> { dma, req, duty, - self.inner.regs_gp16().ccr(cc_channel.index()).as_ptr() as *mut u16, + self.inner.regs_1ch().ccr(channel.index()).as_ptr() as *mut u16, dma_transfer_option, ) .await @@ -360,7 +360,7 @@ impl<'d, T: GeneralInstance4Channel> SimplePwm<'d, T> { dma, req, duty, - self.inner.regs_gp16().ccr(cc_channel.index()).as_ptr() as *mut u32, + self.inner.regs_1ch().ccr(channel.index()).as_ptr() as *mut u32, dma_transfer_option, ) .await -- cgit From b07192079f0fc6ce210104786540aa7be8938d40 Mon Sep 17 00:00:00 2001 From: Dario Nieuwenhuis Date: Sat, 27 Sep 2025 18:37:33 +0200 Subject: nrf/uart,timer: erase instance generics. --- embassy-nrf/src/buffered_uarte.rs | 229 ++++++++++++++++----------- embassy-nrf/src/timer.rs | 82 +++++----- embassy-nrf/src/twim.rs | 2 - embassy-nrf/src/uarte.rs | 148 ++++++++++------- examples/nrf52840/src/bin/uart_split.rs | 2 +- examples/nrf9160/src/bin/modem_tcp_client.rs | 2 +- 6 files changed, 274 insertions(+), 191 deletions(-) diff --git a/embassy-nrf/src/buffered_uarte.rs b/embassy-nrf/src/buffered_uarte.rs index 29e126903..40c679190 100644 --- a/embassy-nrf/src/buffered_uarte.rs +++ b/embassy-nrf/src/buffered_uarte.rs @@ -23,6 +23,7 @@ pub use pac::uarte::vals::{Baudrate, ConfigParity as Parity}; use crate::gpio::{AnyPin, Pin as GpioPin}; use crate::interrupt::typelevel::Interrupt; +use crate::interrupt::InterruptExt; use crate::ppi::{ self, AnyConfigurableChannel, AnyGroup, Channel, ConfigurableChannel, Event, Group, Ppi, PpiGroup, Task, }; @@ -207,21 +208,21 @@ impl interrupt::typelevel::Handler for Interrupt } /// Buffered UARTE driver. -pub struct BufferedUarte<'d, U: UarteInstance, T: TimerInstance> { - tx: BufferedUarteTx<'d, U>, - rx: BufferedUarteRx<'d, U, T>, +pub struct BufferedUarte<'d> { + tx: BufferedUarteTx<'d>, + rx: BufferedUarteRx<'d>, } -impl<'d, U: UarteInstance, T: TimerInstance> Unpin for BufferedUarte<'d, U, T> {} +impl<'d> Unpin for BufferedUarte<'d> {} -impl<'d, U: UarteInstance, T: TimerInstance> BufferedUarte<'d, U, T> { +impl<'d> BufferedUarte<'d> { /// Create a new BufferedUarte without hardware flow control. /// /// # Panics /// /// Panics if `rx_buffer.len()` is odd. #[allow(clippy::too_many_arguments)] - pub fn new( + pub fn new( uarte: Peri<'d, U>, timer: Peri<'d, T>, ppi_ch1: Peri<'d, impl ConfigurableChannel>, @@ -256,7 +257,7 @@ impl<'d, U: UarteInstance, T: TimerInstance> BufferedUarte<'d, U, T> { /// /// Panics if `rx_buffer.len()` is odd. #[allow(clippy::too_many_arguments)] - pub fn new_with_rtscts( + pub fn new_with_rtscts( uarte: Peri<'d, U>, timer: Peri<'d, T>, ppi_ch1: Peri<'d, impl ConfigurableChannel>, @@ -288,7 +289,7 @@ impl<'d, U: UarteInstance, T: TimerInstance> BufferedUarte<'d, U, T> { } #[allow(clippy::too_many_arguments)] - fn new_inner( + fn new_inner( peri: Peri<'d, U>, timer: Peri<'d, T>, ppi_ch1: Peri<'d, AnyConfigurableChannel>, @@ -302,30 +303,33 @@ impl<'d, U: UarteInstance, T: TimerInstance> BufferedUarte<'d, U, T> { rx_buffer: &'d mut [u8], tx_buffer: &'d mut [u8], ) -> Self { - configure(U::regs(), config, cts.is_some()); + let r = U::regs(); + let irq = U::Interrupt::IRQ; + let state = U::state(); + + configure(r, config, cts.is_some()); let tx = BufferedUarteTx::new_innerer(unsafe { peri.clone_unchecked() }, txd, cts, tx_buffer); let rx = BufferedUarteRx::new_innerer(peri, timer, ppi_ch1, ppi_ch2, ppi_group, rxd, rts, rx_buffer); - U::regs().enable().write(|w| w.set_enable(vals::Enable::ENABLED)); - U::Interrupt::pend(); - unsafe { U::Interrupt::enable() }; + r.enable().write(|w| w.set_enable(vals::Enable::ENABLED)); + irq.pend(); + unsafe { irq.enable() }; - U::state().tx_rx_refcount.store(2, Ordering::Relaxed); + state.tx_rx_refcount.store(2, Ordering::Relaxed); Self { tx, rx } } /// Adjust the baud rate to the provided value. pub fn set_baudrate(&mut self, baudrate: Baudrate) { - let r = U::regs(); - r.baudrate().write(|w| w.set_baudrate(baudrate)); + self.tx.set_baudrate(baudrate); } /// Split the UART in reader and writer parts. /// /// This allows reading and writing concurrently from independent tasks. - pub fn split(self) -> (BufferedUarteRx<'d, U, T>, BufferedUarteTx<'d, U>) { + pub fn split(self) -> (BufferedUarteRx<'d>, BufferedUarteTx<'d>) { (self.rx, self.tx) } @@ -333,7 +337,7 @@ impl<'d, U: UarteInstance, T: TimerInstance> BufferedUarte<'d, U, T> { /// /// The returned halves borrow from `self`, so you can drop them and go back to using /// the "un-split" `self`. This allows temporarily splitting the UART. - pub fn split_by_ref(&mut self) -> (&mut BufferedUarteRx<'d, U, T>, &mut BufferedUarteTx<'d, U>) { + pub fn split_by_ref(&mut self) -> (&mut BufferedUarteRx<'d>, &mut BufferedUarteTx<'d>) { (&mut self.rx, &mut self.tx) } @@ -369,13 +373,17 @@ impl<'d, U: UarteInstance, T: TimerInstance> BufferedUarte<'d, U, T> { } /// Reader part of the buffered UARTE driver. -pub struct BufferedUarteTx<'d, U: UarteInstance> { - _peri: Peri<'d, U>, +pub struct BufferedUarteTx<'d> { + r: pac::uarte::Uarte, + _irq: interrupt::Interrupt, + state: &'static crate::uarte::State, + buffered_state: &'static State, + _p: PhantomData<&'d ()>, } -impl<'d, U: UarteInstance> BufferedUarteTx<'d, U> { +impl<'d> BufferedUarteTx<'d> { /// Create a new BufferedUarteTx without hardware flow control. - pub fn new( + pub fn new( uarte: Peri<'d, U>, txd: Peri<'d, impl GpioPin>, _irq: impl interrupt::typelevel::Binding> + 'd, @@ -390,7 +398,7 @@ impl<'d, U: UarteInstance> BufferedUarteTx<'d, U> { /// # Panics /// /// Panics if `rx_buffer.len()` is odd. - pub fn new_with_cts( + pub fn new_with_cts( uarte: Peri<'d, U>, txd: Peri<'d, impl GpioPin>, cts: Peri<'d, impl GpioPin>, @@ -401,41 +409,48 @@ impl<'d, U: UarteInstance> BufferedUarteTx<'d, U> { Self::new_inner(uarte, txd.into(), Some(cts.into()), config, tx_buffer) } - fn new_inner( + fn new_inner( peri: Peri<'d, U>, txd: Peri<'d, AnyPin>, cts: Option>, config: Config, tx_buffer: &'d mut [u8], ) -> Self { - configure(U::regs(), config, cts.is_some()); + let r = U::regs(); + let irq = U::Interrupt::IRQ; + let state = U::state(); + let _buffered_state = U::buffered_state(); + + configure(r, config, cts.is_some()); let this = Self::new_innerer(peri, txd, cts, tx_buffer); - U::regs().enable().write(|w| w.set_enable(vals::Enable::ENABLED)); - U::Interrupt::pend(); - unsafe { U::Interrupt::enable() }; + r.enable().write(|w| w.set_enable(vals::Enable::ENABLED)); + irq.pend(); + unsafe { irq.enable() }; - U::state().tx_rx_refcount.store(1, Ordering::Relaxed); + state.tx_rx_refcount.store(1, Ordering::Relaxed); this } - fn new_innerer( - peri: Peri<'d, U>, + fn new_innerer( + _peri: Peri<'d, U>, txd: Peri<'d, AnyPin>, cts: Option>, tx_buffer: &'d mut [u8], ) -> Self { let r = U::regs(); + let irq = U::Interrupt::IRQ; + let state = U::state(); + let buffered_state = U::buffered_state(); configure_tx_pins(r, txd, cts); // Initialize state - let s = U::buffered_state(); - s.tx_count.store(0, Ordering::Relaxed); + buffered_state.tx_count.store(0, Ordering::Relaxed); let len = tx_buffer.len(); - unsafe { s.tx_buf.init(tx_buffer.as_mut_ptr(), len) }; + unsafe { buffered_state.tx_buf.init(tx_buffer.as_mut_ptr(), len) }; r.events_txstarted().write_value(0); @@ -444,15 +459,21 @@ impl<'d, U: UarteInstance> BufferedUarteTx<'d, U> { w.set_endtx(true); }); - Self { _peri: peri } + Self { + r, + _irq: irq, + state, + buffered_state, + _p: PhantomData, + } } /// Write a buffer into this writer, returning how many bytes were written. - pub fn write<'a>(&'a mut self, buf: &'a [u8]) -> impl Future> + 'a { + pub fn write<'a>(&'a mut self, buf: &'a [u8]) -> impl Future> + 'a + use<'a, 'd> { poll_fn(move |cx| { //trace!("poll_write: {:?}", buf.len()); - let ss = U::state(); - let s = U::buffered_state(); + let ss = self.state; + let s = self.buffered_state; let mut tx = unsafe { s.tx_buf.writer() }; let tx_buf = tx.push_slice(); @@ -469,7 +490,7 @@ impl<'d, U: UarteInstance> BufferedUarteTx<'d, U> { //trace!("poll_write: queued {:?}", n); compiler_fence(Ordering::SeqCst); - U::Interrupt::pend(); + self._irq.pend(); Poll::Ready(Ok(n)) }) @@ -478,7 +499,7 @@ impl<'d, U: UarteInstance> BufferedUarteTx<'d, U> { /// Try writing a buffer without waiting, returning how many bytes were written. pub fn try_write(&mut self, buf: &[u8]) -> Result { //trace!("poll_write: {:?}", buf.len()); - let s = U::buffered_state(); + let s = self.buffered_state; let mut tx = unsafe { s.tx_buf.writer() }; let tx_buf = tx.push_slice(); @@ -493,17 +514,17 @@ impl<'d, U: UarteInstance> BufferedUarteTx<'d, U> { //trace!("poll_write: queued {:?}", n); compiler_fence(Ordering::SeqCst); - U::Interrupt::pend(); + self._irq.pend(); Ok(n) } /// Flush this output stream, ensuring that all intermediately buffered contents reach their destination. pub fn flush(&mut self) -> impl Future> + '_ { + let ss = self.state; + let s = self.buffered_state; poll_fn(move |cx| { //trace!("poll_flush"); - let ss = U::state(); - let s = U::buffered_state(); if !s.tx_buf.is_empty() { //trace!("poll_flush: pending"); ss.tx_waker.register(cx.waker()); @@ -513,11 +534,16 @@ impl<'d, U: UarteInstance> BufferedUarteTx<'d, U> { Poll::Ready(Ok(())) }) } + + /// Adjust the baud rate to the provided value. + pub fn set_baudrate(&mut self, baudrate: Baudrate) { + self.r.baudrate().write(|w| w.set_baudrate(baudrate)); + } } -impl<'a, U: UarteInstance> Drop for BufferedUarteTx<'a, U> { +impl<'a> Drop for BufferedUarteTx<'a> { fn drop(&mut self) { - let r = U::regs(); + let r = self.r; r.intenclr().write(|w| { w.set_txdrdy(true); @@ -528,31 +554,34 @@ impl<'a, U: UarteInstance> Drop for BufferedUarteTx<'a, U> { r.tasks_stoptx().write_value(1); while r.events_txstopped().read() == 0 {} - let s = U::buffered_state(); + let s = self.buffered_state; unsafe { s.tx_buf.deinit() } - let s = U::state(); + let s = self.state; drop_tx_rx(r, s); } } /// Reader part of the buffered UARTE driver. -pub struct BufferedUarteRx<'d, U: UarteInstance, T: TimerInstance> { - _peri: Peri<'d, U>, - timer: Timer<'d, T>, +pub struct BufferedUarteRx<'d> { + r: pac::uarte::Uarte, + state: &'static crate::uarte::State, + buffered_state: &'static State, + timer: Timer<'d>, _ppi_ch1: Ppi<'d, AnyConfigurableChannel, 1, 1>, _ppi_ch2: Ppi<'d, AnyConfigurableChannel, 1, 2>, _ppi_group: PpiGroup<'d, AnyGroup>, + _p: PhantomData<&'d ()>, } -impl<'d, U: UarteInstance, T: TimerInstance> BufferedUarteRx<'d, U, T> { +impl<'d> BufferedUarteRx<'d> { /// Create a new BufferedUarte without hardware flow control. /// /// # Panics /// /// Panics if `rx_buffer.len()` is odd. #[allow(clippy::too_many_arguments)] - pub fn new( + pub fn new( uarte: Peri<'d, U>, timer: Peri<'d, T>, ppi_ch1: Peri<'d, impl ConfigurableChannel>, @@ -582,7 +611,7 @@ impl<'d, U: UarteInstance, T: TimerInstance> BufferedUarteRx<'d, U, T> { /// /// Panics if `rx_buffer.len()` is odd. #[allow(clippy::too_many_arguments)] - pub fn new_with_rts( + pub fn new_with_rts( uarte: Peri<'d, U>, timer: Peri<'d, T>, ppi_ch1: Peri<'d, impl ConfigurableChannel>, @@ -608,7 +637,7 @@ impl<'d, U: UarteInstance, T: TimerInstance> BufferedUarteRx<'d, U, T> { } #[allow(clippy::too_many_arguments)] - fn new_inner( + fn new_inner( peri: Peri<'d, U>, timer: Peri<'d, T>, ppi_ch1: Peri<'d, AnyConfigurableChannel>, @@ -619,22 +648,27 @@ impl<'d, U: UarteInstance, T: TimerInstance> BufferedUarteRx<'d, U, T> { config: Config, rx_buffer: &'d mut [u8], ) -> Self { - configure(U::regs(), config, rts.is_some()); + let r = U::regs(); + let irq = U::Interrupt::IRQ; + let state = U::state(); + let _buffered_state = U::buffered_state(); + + configure(r, config, rts.is_some()); let this = Self::new_innerer(peri, timer, ppi_ch1, ppi_ch2, ppi_group, rxd, rts, rx_buffer); - U::regs().enable().write(|w| w.set_enable(vals::Enable::ENABLED)); - U::Interrupt::pend(); - unsafe { U::Interrupt::enable() }; + r.enable().write(|w| w.set_enable(vals::Enable::ENABLED)); + irq.pend(); + unsafe { irq.enable() }; - U::state().tx_rx_refcount.store(1, Ordering::Relaxed); + state.tx_rx_refcount.store(1, Ordering::Relaxed); this } #[allow(clippy::too_many_arguments)] - fn new_innerer( - peri: Peri<'d, U>, + fn new_innerer( + _peri: Peri<'d, U>, timer: Peri<'d, T>, ppi_ch1: Peri<'d, AnyConfigurableChannel>, ppi_ch2: Peri<'d, AnyConfigurableChannel>, @@ -646,16 +680,17 @@ impl<'d, U: UarteInstance, T: TimerInstance> BufferedUarteRx<'d, U, T> { assert!(rx_buffer.len() % 2 == 0); let r = U::regs(); + let state = U::state(); + let buffered_state = U::buffered_state(); configure_rx_pins(r, rxd, rts); // Initialize state - let s = U::buffered_state(); - s.rx_started_count.store(0, Ordering::Relaxed); - s.rx_ended_count.store(0, Ordering::Relaxed); - s.rx_started.store(false, Ordering::Relaxed); + buffered_state.rx_started_count.store(0, Ordering::Relaxed); + buffered_state.rx_ended_count.store(0, Ordering::Relaxed); + buffered_state.rx_started.store(false, Ordering::Relaxed); let rx_len = rx_buffer.len().min(EASY_DMA_SIZE * 2); - unsafe { s.rx_buf.init(rx_buffer.as_mut_ptr(), rx_len) }; + unsafe { buffered_state.rx_buf.init(rx_buffer.as_mut_ptr(), rx_len) }; // clear errors let errors = r.errorsrc().read(); @@ -683,7 +718,9 @@ impl<'d, U: UarteInstance, T: TimerInstance> BufferedUarteRx<'d, U, T> { let mut ppi_ch1 = Ppi::new_one_to_one(ppi_ch1, Event::from_reg(r.events_rxdrdy()), timer.task_count()); ppi_ch1.enable(); - s.rx_ppi_ch.store(ppi_ch2.number() as u8, Ordering::Relaxed); + buffered_state + .rx_ppi_ch + .store(ppi_ch2.number() as u8, Ordering::Relaxed); let mut ppi_group = PpiGroup::new(ppi_group); let mut ppi_ch2 = Ppi::new_one_to_two( ppi_ch2, @@ -695,11 +732,14 @@ impl<'d, U: UarteInstance, T: TimerInstance> BufferedUarteRx<'d, U, T> { ppi_group.add_channel(&ppi_ch2); Self { - _peri: peri, + r, + state, + buffered_state, timer, _ppi_ch1: ppi_ch1, _ppi_ch2: ppi_ch2, _ppi_group: ppi_group, + _p: PhantomData, } } @@ -714,17 +754,17 @@ impl<'d, U: UarteInstance, T: TimerInstance> BufferedUarteRx<'d, U, T> { /// Return the contents of the internal buffer, filling it with more data from the inner reader if it is empty. pub fn fill_buf(&mut self) -> impl Future> { + let r = self.r; + let s = self.buffered_state; + let ss = self.state; + let timer = &self.timer; poll_fn(move |cx| { compiler_fence(Ordering::SeqCst); //trace!("poll_read"); - let r = U::regs(); - let s = U::buffered_state(); - let ss = U::state(); - // Read the RXDRDY counter. - T::regs().tasks_capture(0).write_value(1); - let mut end = T::regs().cc(0).read() as usize; + timer.cc(0).capture(); + let mut end = timer.cc(0).read() as usize; //trace!(" rxdrdy count = {:?}", end); // We've set a compare channel that resets the counter to 0 when it reaches `len*2`. @@ -771,24 +811,24 @@ impl<'d, U: UarteInstance, T: TimerInstance> BufferedUarteRx<'d, U, T> { return; } - let s = U::buffered_state(); + let s = self.buffered_state; let mut rx = unsafe { s.rx_buf.reader() }; rx.pop_done(amt); - U::regs().intenset().write(|w| w.set_rxstarted(true)); + self.r.intenset().write(|w| w.set_rxstarted(true)); } /// we are ready to read if there is data in the buffer - fn read_ready() -> Result { - let state = U::buffered_state(); + fn read_ready(&self) -> Result { + let state = self.buffered_state; Ok(!state.rx_buf.is_empty()) } } -impl<'a, U: UarteInstance, T: TimerInstance> Drop for BufferedUarteRx<'a, U, T> { +impl<'a> Drop for BufferedUarteRx<'a> { fn drop(&mut self) { self._ppi_group.disable_all(); - let r = U::regs(); + let r = self.r; self.timer.stop(); @@ -801,10 +841,10 @@ impl<'a, U: UarteInstance, T: TimerInstance> Drop for BufferedUarteRx<'a, U, T> r.tasks_stoprx().write_value(1); while r.events_rxto().read() == 0 {} - let s = U::buffered_state(); + let s = self.buffered_state; unsafe { s.rx_buf.deinit() } - let s = U::state(); + let s = self.state; drop_tx_rx(r, s); } } @@ -818,43 +858,44 @@ mod _embedded_io { } } - impl<'d, U: UarteInstance, T: TimerInstance> embedded_io_async::ErrorType for BufferedUarte<'d, U, T> { + impl<'d> embedded_io_async::ErrorType for BufferedUarte<'d> { type Error = Error; } - impl<'d, U: UarteInstance, T: TimerInstance> embedded_io_async::ErrorType for BufferedUarteRx<'d, U, T> { + impl<'d> embedded_io_async::ErrorType for BufferedUarteRx<'d> { type Error = Error; } - impl<'d, U: UarteInstance> embedded_io_async::ErrorType for BufferedUarteTx<'d, U> { + impl<'d> embedded_io_async::ErrorType for BufferedUarteTx<'d> { type Error = Error; } - impl<'d, U: UarteInstance, T: TimerInstance> embedded_io_async::Read for BufferedUarte<'d, U, T> { + impl<'d> embedded_io_async::Read for BufferedUarte<'d> { async fn read(&mut self, buf: &mut [u8]) -> Result { self.read(buf).await } } - impl<'d: 'd, U: UarteInstance, T: TimerInstance> embedded_io_async::Read for BufferedUarteRx<'d, U, T> { + impl<'d> embedded_io_async::Read for BufferedUarteRx<'d> { async fn read(&mut self, buf: &mut [u8]) -> Result { self.read(buf).await } } - impl<'d, U: UarteInstance, T: TimerInstance + 'd> embedded_io_async::ReadReady for BufferedUarte<'d, U, T> { + impl<'d> embedded_io_async::ReadReady for BufferedUarte<'d> { fn read_ready(&mut self) -> Result { - BufferedUarteRx::<'d, U, T>::read_ready() + self.rx.read_ready() } } - impl<'d, U: UarteInstance, T: TimerInstance + 'd> embedded_io_async::ReadReady for BufferedUarteRx<'d, U, T> { + impl<'d> embedded_io_async::ReadReady for BufferedUarteRx<'d> { fn read_ready(&mut self) -> Result { - Self::read_ready() + let state = self.buffered_state; + Ok(!state.rx_buf.is_empty()) } } - impl<'d, U: UarteInstance, T: TimerInstance> embedded_io_async::BufRead for BufferedUarte<'d, U, T> { + impl<'d> embedded_io_async::BufRead for BufferedUarte<'d> { async fn fill_buf(&mut self) -> Result<&[u8], Self::Error> { self.fill_buf().await } @@ -864,7 +905,7 @@ mod _embedded_io { } } - impl<'d: 'd, U: UarteInstance, T: TimerInstance> embedded_io_async::BufRead for BufferedUarteRx<'d, U, T> { + impl<'d> embedded_io_async::BufRead for BufferedUarteRx<'d> { async fn fill_buf(&mut self) -> Result<&[u8], Self::Error> { self.fill_buf().await } @@ -874,7 +915,7 @@ mod _embedded_io { } } - impl<'d, U: UarteInstance, T: TimerInstance> embedded_io_async::Write for BufferedUarte<'d, U, T> { + impl<'d> embedded_io_async::Write for BufferedUarte<'d> { async fn write(&mut self, buf: &[u8]) -> Result { self.write(buf).await } @@ -884,7 +925,7 @@ mod _embedded_io { } } - impl<'d: 'd, U: UarteInstance> embedded_io_async::Write for BufferedUarteTx<'d, U> { + impl<'d> embedded_io_async::Write for BufferedUarteTx<'d> { async fn write(&mut self, buf: &[u8]) -> Result { self.write(buf).await } diff --git a/embassy-nrf/src/timer.rs b/embassy-nrf/src/timer.rs index 1d1f77ea8..0b0bb9780 100644 --- a/embassy-nrf/src/timer.rs +++ b/embassy-nrf/src/timer.rs @@ -6,6 +6,8 @@ #![macro_use] +use core::marker::PhantomData; + use embassy_hal_internal::{Peri, PeripheralType}; use crate::pac; @@ -81,16 +83,18 @@ pub enum Frequency { /// /// It has either 4 or 6 Capture/Compare registers, which can be used to capture the current state of the counter /// or trigger an event when the counter reaches a certain value. -pub struct Timer<'d, T: Instance> { - _p: Peri<'d, T>, +pub struct Timer<'d> { + r: pac::timer::Timer, + ccs: usize, + _p: PhantomData<&'d ()>, } -impl<'d, T: Instance> Timer<'d, T> { +impl<'d> Timer<'d> { /// Create a new `Timer` driver. /// /// This can be useful for triggering tasks via PPI. /// `Uarte` uses this internally. - pub fn new(timer: Peri<'d, T>) -> Self { + pub fn new(timer: Peri<'d, T>) -> Self { Self::new_inner(timer, false) } @@ -98,14 +102,18 @@ impl<'d, T: Instance> Timer<'d, T> { /// /// This can be useful for triggering tasks via PPI. /// `Uarte` uses this internally. - pub fn new_counter(timer: Peri<'d, T>) -> Self { + pub fn new_counter(timer: Peri<'d, T>) -> Self { Self::new_inner(timer, true) } - fn new_inner(timer: Peri<'d, T>, is_counter: bool) -> Self { + fn new_inner(_timer: Peri<'d, T>, is_counter: bool) -> Self { let regs = T::regs(); - let this = Self { _p: timer }; + let this = Self { + r: regs, + ccs: T::CCS, + _p: PhantomData, + }; // Stop the timer before doing anything else, // since changing BITMODE while running can cause 'unpredictable behaviour' according to the specification. @@ -131,7 +139,7 @@ impl<'d, T: Instance> Timer<'d, T> { // Default to the max frequency of the lower power clock this.set_frequency(Frequency::F1MHz); - for n in 0..T::CCS { + for n in 0..this.ccs { let cc = this.cc(n); // Initialize all the shorts as disabled. cc.unshort_compare_clear(); @@ -147,43 +155,43 @@ impl<'d, T: Instance> Timer<'d, T> { #[cfg(feature = "unstable-pac")] #[inline] pub fn regs(&mut self) -> pac::timer::Timer { - T::regs() + self.r } /// Starts the timer. pub fn start(&self) { - T::regs().tasks_start().write_value(1) + self.r.tasks_start().write_value(1) } /// Stops the timer. pub fn stop(&self) { - T::regs().tasks_stop().write_value(1) + self.r.tasks_stop().write_value(1) } /// Reset the timer's counter to 0. pub fn clear(&self) { - T::regs().tasks_clear().write_value(1) + self.r.tasks_clear().write_value(1) } /// Returns the START task, for use with PPI. /// /// When triggered, this task starts the timer. pub fn task_start(&self) -> Task<'d> { - Task::from_reg(T::regs().tasks_start()) + Task::from_reg(self.r.tasks_start()) } /// Returns the STOP task, for use with PPI. /// /// When triggered, this task stops the timer. pub fn task_stop(&self) -> Task<'d> { - Task::from_reg(T::regs().tasks_stop()) + Task::from_reg(self.r.tasks_stop()) } /// Returns the CLEAR task, for use with PPI. /// /// When triggered, this task resets the timer's counter to 0. pub fn task_clear(&self) -> Task<'d> { - Task::from_reg(T::regs().tasks_clear()) + Task::from_reg(self.r.tasks_clear()) } /// Returns the COUNT task, for use with PPI. @@ -191,7 +199,7 @@ impl<'d, T: Instance> Timer<'d, T> { /// When triggered, this task increments the timer's counter by 1. /// Only works in counter mode. pub fn task_count(&self) -> Task<'d> { - Task::from_reg(T::regs().tasks_count()) + Task::from_reg(self.r.tasks_count()) } /// Change the timer's frequency. @@ -201,7 +209,7 @@ impl<'d, T: Instance> Timer<'d, T> { pub fn set_frequency(&self, frequency: Frequency) { self.stop(); - T::regs() + self.r .prescaler() // SAFETY: `frequency` is a variant of `Frequency`, // whose values are all in the range of 0-9 (the valid range of `prescaler`). @@ -212,18 +220,19 @@ impl<'d, T: Instance> Timer<'d, T> { /// /// # Panics /// Panics if `n` >= the number of CC registers this timer has (4 for a normal timer, 6 for an extended timer). - pub fn cc(&self, n: usize) -> Cc<'d, T> { - if n >= T::CCS { - panic!("Cannot get CC register {} of timer with {} CC registers.", n, T::CCS); + pub fn cc(&self, n: usize) -> Cc<'d> { + if n >= self.ccs { + panic!("Cannot get CC register {} of timer with {} CC registers.", n, self.ccs); } Cc { n, - _p: unsafe { self._p.clone_unchecked() }, + r: self.r, + _p: PhantomData, } } } -impl Timer<'static, T> { +impl Timer<'static> { /// Persist the timer's configuration for the rest of the program's lifetime. This method /// should be preferred over [`core::mem::forget()`] because the `'static` bound prevents /// accidental reuse of the underlying peripheral. @@ -232,7 +241,7 @@ impl Timer<'static, T> { } } -impl<'d, T: Instance> Drop for Timer<'d, T> { +impl<'d> Drop for Timer<'d> { fn drop(&mut self) { self.stop(); } @@ -245,27 +254,28 @@ impl<'d, T: Instance> Drop for Timer<'d, T> { /// /// The timer will fire the register's COMPARE event when its counter reaches the value stored in the register. /// When the register's CAPTURE task is triggered, the timer will store the current value of its counter in the register -pub struct Cc<'d, T: Instance> { +pub struct Cc<'d> { n: usize, - _p: Peri<'d, T>, + r: pac::timer::Timer, + _p: PhantomData<&'d ()>, } -impl<'d, T: Instance> Cc<'d, T> { +impl<'d> Cc<'d> { /// Get the current value stored in the register. pub fn read(&self) -> u32 { - T::regs().cc(self.n).read() + self.r.cc(self.n).read() } /// Set the value stored in the register. /// /// `event_compare` will fire when the timer's counter reaches this value. pub fn write(&self, value: u32) { - T::regs().cc(self.n).write_value(value); + self.r.cc(self.n).write_value(value); } /// Capture the current value of the timer's counter in this register, and return it. pub fn capture(&self) -> u32 { - T::regs().tasks_capture(self.n).write_value(1); + self.r.tasks_capture(self.n).write_value(1); self.read() } @@ -273,20 +283,20 @@ impl<'d, T: Instance> Cc<'d, T> { /// /// When triggered, this task will capture the current value of the timer's counter in this register. pub fn task_capture(&self) -> Task<'d> { - Task::from_reg(T::regs().tasks_capture(self.n)) + Task::from_reg(self.r.tasks_capture(self.n)) } /// Returns this CC register's COMPARE event, for use with PPI. /// /// This event will fire when the timer's counter reaches the value in this CC register. pub fn event_compare(&self) -> Event<'d> { - Event::from_reg(T::regs().events_compare(self.n)) + Event::from_reg(self.r.events_compare(self.n)) } /// Clear the COMPARE event for this CC register. #[inline] pub fn clear_events(&self) { - T::regs().events_compare(self.n).write_value(0); + self.r.events_compare(self.n).write_value(0); } /// Enable the shortcut between this CC register's COMPARE event and the timer's CLEAR task. @@ -295,12 +305,12 @@ impl<'d, T: Instance> Cc<'d, T> { /// /// So, when the timer's counter reaches the value stored in this register, the timer's counter will be reset to 0. pub fn short_compare_clear(&self) { - T::regs().shorts().modify(|w| w.set_compare_clear(self.n, true)) + self.r.shorts().modify(|w| w.set_compare_clear(self.n, true)) } /// Disable the shortcut between this CC register's COMPARE event and the timer's CLEAR task. pub fn unshort_compare_clear(&self) { - T::regs().shorts().modify(|w| w.set_compare_clear(self.n, false)) + self.r.shorts().modify(|w| w.set_compare_clear(self.n, false)) } /// Enable the shortcut between this CC register's COMPARE event and the timer's STOP task. @@ -309,11 +319,11 @@ impl<'d, T: Instance> Cc<'d, T> { /// /// So, when the timer's counter reaches the value stored in this register, the timer will stop counting up. pub fn short_compare_stop(&self) { - T::regs().shorts().modify(|w| w.set_compare_stop(self.n, true)) + self.r.shorts().modify(|w| w.set_compare_stop(self.n, true)) } /// Disable the shortcut between this CC register's COMPARE event and the timer's STOP task. pub fn unshort_compare_stop(&self) { - T::regs().shorts().modify(|w| w.set_compare_stop(self.n, false)) + self.r.shorts().modify(|w| w.set_compare_stop(self.n, false)) } } diff --git a/embassy-nrf/src/twim.rs b/embassy-nrf/src/twim.rs index ffc9b39f6..943ea9d31 100644 --- a/embassy-nrf/src/twim.rs +++ b/embassy-nrf/src/twim.rs @@ -114,7 +114,6 @@ impl interrupt::typelevel::Handler for InterruptHandl /// TWI driver. pub struct Twim<'d> { r: pac::twim::Twim, - irq: interrupt::Interrupt, state: &'static State, tx_ram_buffer: &'d mut [u8], _p: PhantomData<&'d ()>, @@ -171,7 +170,6 @@ impl<'d> Twim<'d> { let mut twim = Self { r: T::regs(), - irq: T::Interrupt::IRQ, state: T::state(), tx_ram_buffer, _p: PhantomData {}, diff --git a/embassy-nrf/src/uarte.rs b/embassy-nrf/src/uarte.rs index 927a0ac08..66fb3b3f2 100644 --- a/embassy-nrf/src/uarte.rs +++ b/embassy-nrf/src/uarte.rs @@ -132,28 +132,32 @@ impl interrupt::typelevel::Handler for InterruptHandl } /// UARTE driver. -pub struct Uarte<'d, T: Instance> { - tx: UarteTx<'d, T>, - rx: UarteRx<'d, T>, +pub struct Uarte<'d> { + tx: UarteTx<'d>, + rx: UarteRx<'d>, } /// Transmitter part of the UARTE driver. /// /// This can be obtained via [`Uarte::split`], or created directly. -pub struct UarteTx<'d, T: Instance> { - _p: Peri<'d, T>, +pub struct UarteTx<'d> { + r: pac::uarte::Uarte, + state: &'static State, + _p: PhantomData<&'d ()>, } /// Receiver part of the UARTE driver. /// /// This can be obtained via [`Uarte::split`], or created directly. -pub struct UarteRx<'d, T: Instance> { - _p: Peri<'d, T>, +pub struct UarteRx<'d> { + r: pac::uarte::Uarte, + state: &'static State, + _p: PhantomData<&'d ()>, } -impl<'d, T: Instance> Uarte<'d, T> { +impl<'d> Uarte<'d> { /// Create a new UARTE without hardware flow control - pub fn new( + pub fn new( uarte: Peri<'d, T>, rxd: Peri<'d, impl GpioPin>, txd: Peri<'d, impl GpioPin>, @@ -164,7 +168,7 @@ impl<'d, T: Instance> Uarte<'d, T> { } /// Create a new UARTE with hardware flow control (RTS/CTS) - pub fn new_with_rtscts( + pub fn new_with_rtscts( uarte: Peri<'d, T>, rxd: Peri<'d, impl GpioPin>, txd: Peri<'d, impl GpioPin>, @@ -183,8 +187,8 @@ impl<'d, T: Instance> Uarte<'d, T> { ) } - fn new_inner( - uarte: Peri<'d, T>, + fn new_inner( + _uarte: Peri<'d, T>, rxd: Peri<'d, AnyPin>, txd: Peri<'d, AnyPin>, cts: Option>, @@ -211,16 +215,22 @@ impl<'d, T: Instance> Uarte<'d, T> { Self { tx: UarteTx { - _p: unsafe { uarte.clone_unchecked() }, + r: T::regs(), + state: T::state(), + _p: PhantomData {}, + }, + rx: UarteRx { + r: T::regs(), + state: T::state(), + _p: PhantomData {}, }, - rx: UarteRx { _p: uarte }, } } /// Split the Uarte into the transmitter and receiver parts. /// /// This is useful to concurrently transmit and receive from independent tasks. - pub fn split(self) -> (UarteTx<'d, T>, UarteRx<'d, T>) { + pub fn split(self) -> (UarteTx<'d>, UarteRx<'d>) { (self.tx, self.rx) } @@ -228,7 +238,7 @@ impl<'d, T: Instance> Uarte<'d, T> { /// /// The returned halves borrow from `self`, so you can drop them and go back to using /// the "un-split" `self`. This allows temporarily splitting the UART. - pub fn split_by_ref(&mut self) -> (&mut UarteTx<'d, T>, &mut UarteRx<'d, T>) { + pub fn split_by_ref(&mut self) -> (&mut UarteTx<'d>, &mut UarteRx<'d>) { (&mut self.tx, &mut self.rx) } @@ -240,13 +250,13 @@ impl<'d, T: Instance> Uarte<'d, T> { timer: Peri<'d, U>, ppi_ch1: Peri<'d, impl ConfigurableChannel + 'd>, ppi_ch2: Peri<'d, impl ConfigurableChannel + 'd>, - ) -> (UarteTx<'d, T>, UarteRxWithIdle<'d, T, U>) { + ) -> (UarteTx<'d>, UarteRxWithIdle<'d>) { (self.tx, self.rx.with_idle(timer, ppi_ch1, ppi_ch2)) } /// Return the endtx event for use with PPI pub fn event_endtx(&self) -> Event<'_> { - let r = T::regs(); + let r = self.tx.r; Event::from_reg(r.events_endtx()) } @@ -343,9 +353,9 @@ pub(crate) fn configure(r: pac::uarte::Uarte, config: Config, hardware_flow_cont apply_workaround_for_enable_anomaly(r); } -impl<'d, T: Instance> UarteTx<'d, T> { +impl<'d> UarteTx<'d> { /// Create a new tx-only UARTE without hardware flow control - pub fn new( + pub fn new( uarte: Peri<'d, T>, _irq: impl interrupt::typelevel::Binding> + 'd, txd: Peri<'d, impl GpioPin>, @@ -355,7 +365,7 @@ impl<'d, T: Instance> UarteTx<'d, T> { } /// Create a new tx-only UARTE with hardware flow control (RTS/CTS) - pub fn new_with_rtscts( + pub fn new_with_rtscts( uarte: Peri<'d, T>, _irq: impl interrupt::typelevel::Binding> + 'd, txd: Peri<'d, impl GpioPin>, @@ -365,7 +375,12 @@ impl<'d, T: Instance> UarteTx<'d, T> { Self::new_inner(uarte, txd.into(), Some(cts.into()), config) } - fn new_inner(uarte: Peri<'d, T>, txd: Peri<'d, AnyPin>, cts: Option>, config: Config) -> Self { + fn new_inner( + _uarte: Peri<'d, T>, + txd: Peri<'d, AnyPin>, + cts: Option>, + config: Config, + ) -> Self { let r = T::regs(); configure(r, config, cts.is_some()); @@ -378,7 +393,11 @@ impl<'d, T: Instance> UarteTx<'d, T> { let s = T::state(); s.tx_rx_refcount.store(1, Ordering::Relaxed); - Self { _p: uarte } + Self { + r: T::regs(), + state: T::state(), + _p: PhantomData {}, + } } /// Write all bytes in the buffer. @@ -409,8 +428,8 @@ impl<'d, T: Instance> UarteTx<'d, T> { let ptr = buffer.as_ptr(); let len = buffer.len(); - let r = T::regs(); - let s = T::state(); + let r = self.r; + let s = self.state; let drop = OnDrop::new(move || { trace!("write drop: stopping"); @@ -479,7 +498,7 @@ impl<'d, T: Instance> UarteTx<'d, T> { let ptr = buffer.as_ptr(); let len = buffer.len(); - let r = T::regs(); + let r = self.r; r.txd().ptr().write_value(ptr as u32); r.txd().maxcnt().write(|w| w.set_maxcnt(len as _)); @@ -501,11 +520,11 @@ impl<'d, T: Instance> UarteTx<'d, T> { } } -impl<'a, T: Instance> Drop for UarteTx<'a, T> { +impl<'a> Drop for UarteTx<'a> { fn drop(&mut self) { trace!("uarte tx drop"); - let r = T::regs(); + let r = self.r; let did_stoptx = r.events_txstarted().read() != 0; trace!("did_stoptx {}", did_stoptx); @@ -513,15 +532,15 @@ impl<'a, T: Instance> Drop for UarteTx<'a, T> { // Wait for txstopped, if needed. while did_stoptx && r.events_txstopped().read() == 0 {} - let s = T::state(); + let s = self.state; drop_tx_rx(r, s); } } -impl<'d, T: Instance> UarteRx<'d, T> { +impl<'d> UarteRx<'d> { /// Create a new rx-only UARTE without hardware flow control - pub fn new( + pub fn new( uarte: Peri<'d, T>, _irq: impl interrupt::typelevel::Binding> + 'd, rxd: Peri<'d, impl GpioPin>, @@ -531,7 +550,7 @@ impl<'d, T: Instance> UarteRx<'d, T> { } /// Create a new rx-only UARTE with hardware flow control (RTS/CTS) - pub fn new_with_rtscts( + pub fn new_with_rtscts( uarte: Peri<'d, T>, _irq: impl interrupt::typelevel::Binding> + 'd, rxd: Peri<'d, impl GpioPin>, @@ -543,13 +562,18 @@ impl<'d, T: Instance> UarteRx<'d, T> { /// Check for errors and clear the error register if an error occured. fn check_and_clear_errors(&mut self) -> Result<(), Error> { - let r = T::regs(); + let r = self.r; let err_bits = r.errorsrc().read(); r.errorsrc().write_value(err_bits); ErrorSource::from_bits_truncate(err_bits.0).check() } - fn new_inner(uarte: Peri<'d, T>, rxd: Peri<'d, AnyPin>, rts: Option>, config: Config) -> Self { + fn new_inner( + _uarte: Peri<'d, T>, + rxd: Peri<'d, AnyPin>, + rts: Option>, + config: Config, + ) -> Self { let r = T::regs(); configure(r, config, rts.is_some()); @@ -562,7 +586,11 @@ impl<'d, T: Instance> UarteRx<'d, T> { let s = T::state(); s.tx_rx_refcount.store(1, Ordering::Relaxed); - Self { _p: uarte } + Self { + r: T::regs(), + state: T::state(), + _p: PhantomData {}, + } } /// Upgrade to an instance that supports idle line detection. @@ -571,10 +599,10 @@ impl<'d, T: Instance> UarteRx<'d, T> { timer: Peri<'d, U>, ppi_ch1: Peri<'d, impl ConfigurableChannel + 'd>, ppi_ch2: Peri<'d, impl ConfigurableChannel + 'd>, - ) -> UarteRxWithIdle<'d, T, U> { + ) -> UarteRxWithIdle<'d> { let timer = Timer::new(timer); - let r = T::regs(); + let r = self.r; // BAUDRATE register values are `baudrate * 2^32 / 16000000` // source: https://devzone.nordicsemi.com/f/nordic-q-a/391/uart-baudrate-register-values @@ -605,11 +633,15 @@ impl<'d, T: Instance> UarteRx<'d, T> { ); ppi_ch2.enable(); + let state = self.state; + UarteRxWithIdle { rx: self, timer, - ppi_ch1, + ppi_ch1: ppi_ch1, _ppi_ch2: ppi_ch2, + r: r, + state: state, } } @@ -625,8 +657,8 @@ impl<'d, T: Instance> UarteRx<'d, T> { let ptr = buffer.as_ptr(); let len = buffer.len(); - let r = T::regs(); - let s = T::state(); + let r = self.r; + let s = self.state; let drop = OnDrop::new(move || { trace!("read drop: stopping"); @@ -692,7 +724,7 @@ impl<'d, T: Instance> UarteRx<'d, T> { let ptr = buffer.as_ptr(); let len = buffer.len(); - let r = T::regs(); + let r = self.r; r.rxd().ptr().write_value(ptr as u32); r.rxd().maxcnt().write(|w| w.set_maxcnt(len as _)); @@ -718,11 +750,11 @@ impl<'d, T: Instance> UarteRx<'d, T> { } } -impl<'a, T: Instance> Drop for UarteRx<'a, T> { +impl<'a> Drop for UarteRx<'a> { fn drop(&mut self) { trace!("uarte rx drop"); - let r = T::regs(); + let r = self.r; let did_stoprx = r.events_rxstarted().read() != 0; trace!("did_stoprx {}", did_stoprx); @@ -730,7 +762,7 @@ impl<'a, T: Instance> Drop for UarteRx<'a, T> { // Wait for rxto, if needed. while did_stoprx && r.events_rxto().read() == 0 {} - let s = T::state(); + let s = self.state; drop_tx_rx(r, s); } @@ -739,14 +771,16 @@ impl<'a, T: Instance> Drop for UarteRx<'a, T> { /// Receiver part of the UARTE driver, with `read_until_idle` support. /// /// This can be obtained via [`Uarte::split_with_idle`]. -pub struct UarteRxWithIdle<'d, T: Instance, U: TimerInstance> { - rx: UarteRx<'d, T>, - timer: Timer<'d, U>, +pub struct UarteRxWithIdle<'d> { + rx: UarteRx<'d>, + timer: Timer<'d>, ppi_ch1: Ppi<'d, AnyConfigurableChannel, 1, 2>, _ppi_ch2: Ppi<'d, AnyConfigurableChannel, 1, 1>, + r: pac::uarte::Uarte, + state: &'static State, } -impl<'d, T: Instance, U: TimerInstance> UarteRxWithIdle<'d, T, U> { +impl<'d> UarteRxWithIdle<'d> { /// Read bytes until the buffer is filled. pub async fn read(&mut self, buffer: &mut [u8]) -> Result<(), Error> { self.ppi_ch1.disable(); @@ -773,8 +807,8 @@ impl<'d, T: Instance, U: TimerInstance> UarteRxWithIdle<'d, T, U> { let ptr = buffer.as_ptr(); let len = buffer.len(); - let r = T::regs(); - let s = T::state(); + let r = self.r; + let s = self.state; self.ppi_ch1.enable(); @@ -846,7 +880,7 @@ impl<'d, T: Instance, U: TimerInstance> UarteRxWithIdle<'d, T, U> { let ptr = buffer.as_ptr(); let len = buffer.len(); - let r = T::regs(); + let r = self.r; self.ppi_ch1.enable(); @@ -997,7 +1031,7 @@ macro_rules! impl_uarte { mod eh02 { use super::*; - impl<'d, T: Instance> embedded_hal_02::blocking::serial::Write for Uarte<'d, T> { + impl<'d> embedded_hal_02::blocking::serial::Write for Uarte<'d> { type Error = Error; fn bwrite_all(&mut self, buffer: &[u8]) -> Result<(), Self::Error> { @@ -1009,7 +1043,7 @@ mod eh02 { } } - impl<'d, T: Instance> embedded_hal_02::blocking::serial::Write for UarteTx<'d, T> { + impl<'d> embedded_hal_02::blocking::serial::Write for UarteTx<'d> { type Error = Error; fn bwrite_all(&mut self, buffer: &[u8]) -> Result<(), Self::Error> { @@ -1038,22 +1072,22 @@ mod _embedded_io { } } - impl<'d, U: Instance> embedded_io_async::ErrorType for Uarte<'d, U> { + impl<'d> embedded_io_async::ErrorType for Uarte<'d> { type Error = Error; } - impl<'d, U: Instance> embedded_io_async::ErrorType for UarteTx<'d, U> { + impl<'d> embedded_io_async::ErrorType for UarteTx<'d> { type Error = Error; } - impl<'d, U: Instance> embedded_io_async::Write for Uarte<'d, U> { + impl<'d> embedded_io_async::Write for Uarte<'d> { async fn write(&mut self, buf: &[u8]) -> Result { self.write(buf).await?; Ok(buf.len()) } } - impl<'d: 'd, U: Instance> embedded_io_async::Write for UarteTx<'d, U> { + impl<'d> embedded_io_async::Write for UarteTx<'d> { async fn write(&mut self, buf: &[u8]) -> Result { self.write(buf).await?; Ok(buf.len()) diff --git a/examples/nrf52840/src/bin/uart_split.rs b/examples/nrf52840/src/bin/uart_split.rs index 51af90727..d75143126 100644 --- a/examples/nrf52840/src/bin/uart_split.rs +++ b/examples/nrf52840/src/bin/uart_split.rs @@ -52,7 +52,7 @@ async fn main(spawner: Spawner) { } #[embassy_executor::task] -async fn reader(mut rx: UarteRx<'static, UARTE0>) { +async fn reader(mut rx: UarteRx<'static>) { let mut buf = [0; 8]; loop { info!("reading..."); diff --git a/examples/nrf9160/src/bin/modem_tcp_client.rs b/examples/nrf9160/src/bin/modem_tcp_client.rs index 7d4815699..460a4cfae 100644 --- a/examples/nrf9160/src/bin/modem_tcp_client.rs +++ b/examples/nrf9160/src/bin/modem_tcp_client.rs @@ -32,7 +32,7 @@ bind_interrupts!(struct Irqs { }); #[embassy_executor::task] -async fn trace_task(mut uart: BufferedUarteTx<'static, peripherals::SERIAL0>, reader: TraceReader<'static>) -> ! { +async fn trace_task(mut uart: BufferedUarteTx<'static>, reader: TraceReader<'static>) -> ! { let mut rx = [0u8; 1024]; loop { let n = reader.read(&mut rx[..]).await; -- cgit From fd574ffd091b579f30655e349aef16fbfc2bbb75 Mon Sep 17 00:00:00 2001 From: Dario Nieuwenhuis Date: Sat, 27 Sep 2025 18:48:24 +0200 Subject: nrf/spis: erase instance generics --- embassy-nrf/src/spis.rs | 50 +++++++++++++++++++++++++++---------------------- 1 file changed, 28 insertions(+), 22 deletions(-) diff --git a/embassy-nrf/src/spis.rs b/embassy-nrf/src/spis.rs index 2a3928d25..713163a55 100644 --- a/embassy-nrf/src/spis.rs +++ b/embassy-nrf/src/spis.rs @@ -96,14 +96,16 @@ impl interrupt::typelevel::Handler for InterruptHandl } } -/// SPIS driver. -pub struct Spis<'d, T: Instance> { - _p: Peri<'d, T>, +/// Serial Peripheral Interface in slave mode. +pub struct Spis<'d> { + r: pac::spis::Spis, + state: &'static State, + _p: PhantomData<&'d ()>, } -impl<'d, T: Instance> Spis<'d, T> { +impl<'d> Spis<'d> { /// Create a new SPIS driver. - pub fn new( + pub fn new( spis: Peri<'d, T>, _irq: impl interrupt::typelevel::Binding> + 'd, cs: Peri<'d, impl GpioPin>, @@ -123,7 +125,7 @@ impl<'d, T: Instance> Spis<'d, T> { } /// Create a new SPIS driver, capable of TX only (MISO only). - pub fn new_txonly( + pub fn new_txonly( spis: Peri<'d, T>, _irq: impl interrupt::typelevel::Binding> + 'd, cs: Peri<'d, impl GpioPin>, @@ -135,7 +137,7 @@ impl<'d, T: Instance> Spis<'d, T> { } /// Create a new SPIS driver, capable of RX only (MOSI only). - pub fn new_rxonly( + pub fn new_rxonly( spis: Peri<'d, T>, _irq: impl interrupt::typelevel::Binding> + 'd, cs: Peri<'d, impl GpioPin>, @@ -147,7 +149,7 @@ impl<'d, T: Instance> Spis<'d, T> { } /// Create a new SPIS driver, capable of TX only (MISO only) without SCK pin. - pub fn new_txonly_nosck( + pub fn new_txonly_nosck( spis: Peri<'d, T>, _irq: impl interrupt::typelevel::Binding> + 'd, cs: Peri<'d, impl GpioPin>, @@ -157,8 +159,8 @@ impl<'d, T: Instance> Spis<'d, T> { Self::new_inner(spis, cs.into(), None, Some(miso.into()), None, config) } - fn new_inner( - spis: Peri<'d, T>, + fn new_inner( + _spis: Peri<'d, T>, cs: Peri<'d, AnyPin>, sck: Option>, miso: Option>, @@ -191,10 +193,14 @@ impl<'d, T: Instance> Spis<'d, T> { // Enable SPIS instance. r.enable().write(|w| w.set_enable(vals::Enable::ENABLED)); - let mut spis = Self { _p: spis }; + let mut spis = Self { + r: T::regs(), + state: T::state(), + _p: PhantomData, + }; // Apply runtime peripheral configuration - Self::set_config(&mut spis, &config).unwrap(); + spis.set_config(&config).unwrap(); // Disable all events interrupts. r.intenclr().write(|w| w.0 = 0xFFFF_FFFF); @@ -212,7 +218,7 @@ impl<'d, T: Instance> Spis<'d, T> { compiler_fence(Ordering::SeqCst); - let r = T::regs(); + let r = self.r; // Set up the DMA write. if tx.len() > EASY_DMA_SIZE { @@ -239,7 +245,7 @@ impl<'d, T: Instance> Spis<'d, T> { fn blocking_inner_from_ram(&mut self, rx: *mut [u8], tx: *const [u8]) -> Result<(usize, usize), Error> { compiler_fence(Ordering::SeqCst); - let r = T::regs(); + let r = self.r; // Acquire semaphore. if r.semstat().read().0 != 1 { @@ -276,8 +282,8 @@ impl<'d, T: Instance> Spis<'d, T> { } async fn async_inner_from_ram(&mut self, rx: *mut [u8], tx: *const [u8]) -> Result<(usize, usize), Error> { - let r = T::regs(); - let s = T::state(); + let r = self.r; + let s = self.state; // Clear status register. r.status().write(|w| { @@ -420,21 +426,21 @@ impl<'d, T: Instance> Spis<'d, T> { /// Checks if last transaction overread. pub fn is_overread(&mut self) -> bool { - T::regs().status().read().overread() + self.r.status().read().overread() } /// Checks if last transaction overflowed. pub fn is_overflow(&mut self) -> bool { - T::regs().status().read().overflow() + self.r.status().read().overflow() } } -impl<'d, T: Instance> Drop for Spis<'d, T> { +impl<'d> Drop for Spis<'d> { fn drop(&mut self) { trace!("spis drop"); // Disable - let r = T::regs(); + let r = self.r; r.enable().write(|w| w.set_enable(vals::Enable::DISABLED)); gpio::deconfigure_pin(r.psel().sck().read()); @@ -489,11 +495,11 @@ macro_rules! impl_spis { // ==================== -impl<'d, T: Instance> SetConfig for Spis<'d, T> { +impl<'d> SetConfig for Spis<'d> { type Config = Config; type ConfigError = (); fn set_config(&mut self, config: &Self::Config) -> Result<(), Self::ConfigError> { - let r = T::regs(); + let r = self.r; // Configure mode. let mode = config.mode; r.config().write(|w| { -- cgit From 00db482c2b701b6e8f7013ba63d6e1efe3b5c62d Mon Sep 17 00:00:00 2001 From: Dario Nieuwenhuis Date: Sat, 27 Sep 2025 19:20:11 +0200 Subject: nrf/twis: erase instance generics --- embassy-nrf/src/twis.rs | 65 ++++++++++++++++++++++++++----------------------- 1 file changed, 34 insertions(+), 31 deletions(-) diff --git a/embassy-nrf/src/twis.rs b/embassy-nrf/src/twis.rs index c77d0f048..dd4978b3e 100644 --- a/embassy-nrf/src/twis.rs +++ b/embassy-nrf/src/twis.rs @@ -140,14 +140,16 @@ impl interrupt::typelevel::Handler for InterruptHandl } /// TWIS driver. -pub struct Twis<'d, T: Instance> { - _p: Peri<'d, T>, +pub struct Twis<'d> { + r: pac::twis::Twis, + state: &'static State, + _p: PhantomData<&'d ()>, } -impl<'d, T: Instance> Twis<'d, T> { +impl<'d> Twis<'d> { /// Create a new TWIS driver. - pub fn new( - twis: Peri<'d, T>, + pub fn new( + _twis: Peri<'d, T>, _irq: impl interrupt::typelevel::Binding> + 'd, sda: Peri<'d, impl GpioPin>, scl: Peri<'d, impl GpioPin>, @@ -206,7 +208,11 @@ impl<'d, T: Instance> Twis<'d, T> { T::Interrupt::unpend(); unsafe { T::Interrupt::enable() }; - Self { _p: twis } + Self { + r: T::regs(), + state: T::state(), + _p: PhantomData, + } } /// Set TX buffer, checking that it is in RAM and has suitable length. @@ -217,7 +223,7 @@ impl<'d, T: Instance> Twis<'d, T> { return Err(Error::TxBufferTooLong); } - let r = T::regs(); + let r = self.r; // We're giving the register a pointer to the stack. Since we're // waiting for the I2C transaction to end before this stack pointer @@ -244,7 +250,7 @@ impl<'d, T: Instance> Twis<'d, T> { return Err(Error::RxBufferTooLong); } - let r = T::regs(); + let r = self.r; // We're giving the register a pointer to the stack. Since we're // waiting for the I2C transaction to end before this stack pointer @@ -266,7 +272,7 @@ impl<'d, T: Instance> Twis<'d, T> { } fn clear_errorsrc(&mut self) { - let r = T::regs(); + let r = self.r; r.errorsrc().write(|w| { w.set_overflow(true); w.set_overread(true); @@ -276,18 +282,18 @@ impl<'d, T: Instance> Twis<'d, T> { /// Returns matched address for latest command. pub fn address_match(&self) -> u8 { - let r = T::regs(); + let r = self.r; r.address(r.match_().read().0 as usize).read().address() } /// Returns the index of the address matched in the latest command. pub fn address_match_index(&self) -> usize { - T::regs().match_().read().0 as _ + self.r.match_().read().0 as _ } /// Wait for read, write, stop or error fn blocking_listen_wait(&mut self) -> Result { - let r = T::regs(); + let r = self.r; loop { if r.events_error().read() != 0 { r.events_error().write_value(0); @@ -312,7 +318,7 @@ impl<'d, T: Instance> Twis<'d, T> { /// Wait for stop, repeated start or error fn blocking_listen_wait_end(&mut self, status: Status) -> Result { - let r = T::regs(); + let r = self.r; loop { // stop if an error occurred if r.events_error().read() != 0 { @@ -338,7 +344,7 @@ impl<'d, T: Instance> Twis<'d, T> { /// Wait for stop or error fn blocking_wait(&mut self) -> Result { - let r = T::regs(); + let r = self.r; loop { // stop if an error occurred if r.events_error().read() != 0 { @@ -363,7 +369,7 @@ impl<'d, T: Instance> Twis<'d, T> { /// Wait for stop or error with timeout #[cfg(feature = "time")] fn blocking_wait_timeout(&mut self, timeout: Duration) -> Result { - let r = T::regs(); + let r = self.r; let deadline = Instant::now() + timeout; loop { // stop if an error occurred @@ -392,7 +398,7 @@ impl<'d, T: Instance> Twis<'d, T> { /// Wait for read, write, stop or error with timeout #[cfg(feature = "time")] fn blocking_listen_wait_timeout(&mut self, timeout: Duration) -> Result { - let r = T::regs(); + let r = self.r; let deadline = Instant::now() + timeout; loop { if r.events_error().read() != 0 { @@ -423,7 +429,7 @@ impl<'d, T: Instance> Twis<'d, T> { /// Wait for stop, repeated start or error with timeout #[cfg(feature = "time")] fn blocking_listen_wait_end_timeout(&mut self, status: Status, timeout: Duration) -> Result { - let r = T::regs(); + let r = self.r; let deadline = Instant::now() + timeout; loop { // stop if an error occurred @@ -453,10 +459,9 @@ impl<'d, T: Instance> Twis<'d, T> { /// Wait for stop or error fn async_wait(&mut self) -> impl Future> { + let r = self.r; + let s = self.state; poll_fn(move |cx| { - let r = T::regs(); - let s = T::state(); - s.waker.register(cx.waker()); // stop if an error occurred @@ -483,10 +488,9 @@ impl<'d, T: Instance> Twis<'d, T> { /// Wait for read or write fn async_listen_wait(&mut self) -> impl Future> { + let r = self.r; + let s = self.state; poll_fn(move |cx| { - let r = T::regs(); - let s = T::state(); - s.waker.register(cx.waker()); // stop if an error occurred @@ -510,10 +514,9 @@ impl<'d, T: Instance> Twis<'d, T> { /// Wait for stop, repeated start or error fn async_listen_wait_end(&mut self, status: Status) -> impl Future> { + let r = self.r; + let s = self.state; poll_fn(move |cx| { - let r = T::regs(); - let s = T::state(); - s.waker.register(cx.waker()); // stop if an error occurred @@ -540,7 +543,7 @@ impl<'d, T: Instance> Twis<'d, T> { } fn setup_respond_from_ram(&mut self, buffer: &[u8], inten: bool) -> Result<(), Error> { - let r = T::regs(); + let r = self.r; compiler_fence(SeqCst); @@ -584,7 +587,7 @@ impl<'d, T: Instance> Twis<'d, T> { } fn setup_listen(&mut self, buffer: &mut [u8], inten: bool) -> Result<(), Error> { - let r = T::regs(); + let r = self.r; compiler_fence(SeqCst); // Set up the DMA read. @@ -620,7 +623,7 @@ impl<'d, T: Instance> Twis<'d, T> { } fn setup_listen_end(&mut self, inten: bool) -> Result<(), Error> { - let r = T::regs(); + let r = self.r; compiler_fence(SeqCst); // Clear events @@ -753,14 +756,14 @@ impl<'d, T: Instance> Twis<'d, T> { } } -impl<'a, T: Instance> Drop for Twis<'a, T> { +impl<'a> Drop for Twis<'a> { fn drop(&mut self) { trace!("twis drop"); // TODO: check for abort // disable! - let r = T::regs(); + let r = self.r; r.enable().write(|w| w.set_enable(vals::Enable::DISABLED)); gpio::deconfigure_pin(r.psel().sda().read()); -- cgit From 65a80f698e9087f09689a616a9f383c32b59ede8 Mon Sep 17 00:00:00 2001 From: Dario Nieuwenhuis Date: Sat, 27 Sep 2025 21:13:53 +0200 Subject: nrf/ipc: erase instance generics --- embassy-nrf/src/ipc.rs | 132 ++++++++++++++++++++++++++----------------------- 1 file changed, 70 insertions(+), 62 deletions(-) diff --git a/embassy-nrf/src/ipc.rs b/embassy-nrf/src/ipc.rs index a8a08c911..a40c36c99 100644 --- a/embassy-nrf/src/ipc.rs +++ b/embassy-nrf/src/ipc.rs @@ -134,97 +134,99 @@ impl interrupt::typelevel::Handler for InterruptHandl /// IPC driver #[non_exhaustive] -pub struct Ipc<'d, T: Instance> { +pub struct Ipc<'d> { /// Event 0 - pub event0: Event<'d, T>, + pub event0: Event<'d>, /// Event 1 - pub event1: Event<'d, T>, + pub event1: Event<'d>, /// Event 2 - pub event2: Event<'d, T>, + pub event2: Event<'d>, /// Event 3 - pub event3: Event<'d, T>, + pub event3: Event<'d>, /// Event 4 - pub event4: Event<'d, T>, + pub event4: Event<'d>, /// Event 5 - pub event5: Event<'d, T>, + pub event5: Event<'d>, /// Event 6 - pub event6: Event<'d, T>, + pub event6: Event<'d>, /// Event 7 - pub event7: Event<'d, T>, + pub event7: Event<'d>, /// Event 8 - pub event8: Event<'d, T>, + pub event8: Event<'d>, /// Event 9 - pub event9: Event<'d, T>, + pub event9: Event<'d>, /// Event 10 - pub event10: Event<'d, T>, + pub event10: Event<'d>, /// Event 11 - pub event11: Event<'d, T>, + pub event11: Event<'d>, /// Event 12 - pub event12: Event<'d, T>, + pub event12: Event<'d>, /// Event 13 - pub event13: Event<'d, T>, + pub event13: Event<'d>, /// Event 14 - pub event14: Event<'d, T>, + pub event14: Event<'d>, /// Event 15 - pub event15: Event<'d, T>, + pub event15: Event<'d>, } -impl<'d, T: Instance> Ipc<'d, T> { +impl<'d> Ipc<'d> { /// Create a new IPC driver. - pub fn new( + pub fn new( _p: Peri<'d, T>, _irq: impl interrupt::typelevel::Binding> + 'd, ) -> Self { T::Interrupt::unpend(); unsafe { T::Interrupt::enable() }; - let _phantom = PhantomData; + let r = T::regs(); + let state = T::state(); #[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 }, + let result = Self { // attributes on expressions are experimental + event0: Event { number: EventNumber::Event0, r, state, _phantom: PhantomData }, + event1: Event { number: EventNumber::Event1, r, state, _phantom: PhantomData }, + event2: Event { number: EventNumber::Event2, r, state, _phantom: PhantomData }, + event3: Event { number: EventNumber::Event3, r, state, _phantom: PhantomData }, + event4: Event { number: EventNumber::Event4, r, state, _phantom: PhantomData }, + event5: Event { number: EventNumber::Event5, r, state, _phantom: PhantomData }, + event6: Event { number: EventNumber::Event6, r, state, _phantom: PhantomData }, + event7: Event { number: EventNumber::Event7, r, state, _phantom: PhantomData }, + event8: Event { number: EventNumber::Event8, r, state, _phantom: PhantomData }, + event9: Event { number: EventNumber::Event9, r, state, _phantom: PhantomData }, + event10: Event { number: EventNumber::Event10, r, state, _phantom: PhantomData }, + event11: Event { number: EventNumber::Event11, r, state, _phantom: PhantomData }, + event12: Event { number: EventNumber::Event12, r, state, _phantom: PhantomData }, + event13: Event { number: EventNumber::Event13, r, state, _phantom: PhantomData }, + event14: Event { number: EventNumber::Event14, r, state, _phantom: PhantomData }, + event15: Event { number: EventNumber::Event15, r, state, _phantom: PhantomData }, }; - r + result } } /// IPC event -pub struct Event<'d, T: Instance> { +pub struct Event<'d> { number: EventNumber, - _phantom: PhantomData<&'d T>, + r: pac::ipc::Ipc, + state: &'static State, + _phantom: PhantomData<&'d ()>, } -impl<'d, T: Instance> Event<'d, T> { +impl<'d> Event<'d> { /// Trigger the event. pub fn trigger(&self) { let nr = self.number; - T::regs().tasks_send(nr as usize).write_value(1); + self.r.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); + self.r.intenset().write(|w| w.0 = 1 << nr); poll_fn(|cx| { - T::state().wakers[nr].register(cx.waker()); + self.state.wakers[nr].register(cx.waker()); - if regs.events_receive(nr).read() == 1 { - regs.events_receive(nr).write_value(0x00); + if self.r.events_receive(nr).read() == 1 { + self.r.events_receive(nr).write_value(0x00); Poll::Ready(()) } else { Poll::Pending @@ -239,16 +241,17 @@ impl<'d, T: Instance> Event<'d, T> { } /// Create a handle that can trigger the event. - pub fn trigger_handle(&self) -> EventTrigger<'d, T> { + pub fn trigger_handle(&self) -> EventTrigger<'d> { EventTrigger { number: self.number, + r: self.r, _phantom: PhantomData, } } /// Configure the channels the event will broadcast to pub fn configure_trigger>(&mut self, channels: I) { - T::regs().send_cnf(self.number as usize).write(|w| { + self.r.send_cnf(self.number as usize).write(|w| { for channel in channels { w.0 |= channel.mask(); } @@ -257,7 +260,7 @@ impl<'d, T: Instance> Event<'d, T> { /// Configure the channels the event will listen on pub fn configure_wait>(&mut self, channels: I) { - T::regs().receive_cnf(self.number as usize).write(|w| { + self.r.receive_cnf(self.number as usize).write(|w| { for channel in channels { w.0 |= channel.mask(); } @@ -267,22 +270,25 @@ impl<'d, T: Instance> Event<'d, T> { /// 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)) + ppi::Task::from_reg(self.r.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)) + ppi::Event::from_reg(self.r.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 } + pub fn reborrow(&mut self) -> Event<'_> { + Event { + number: self.number, + r: self.r, + state: self.state, + _phantom: PhantomData, + } } /// Steal an IPC event by number. @@ -290,9 +296,11 @@ impl<'d, T: Instance> Event<'d, T> { /// # Safety /// /// The event number must not be in use by another [`Event`]. - pub unsafe fn steal(number: EventNumber) -> Self { + pub unsafe fn steal(number: EventNumber) -> Self { Self { number, + r: T::regs(), + state: T::state(), _phantom: PhantomData, } } @@ -301,17 +309,17 @@ impl<'d, T: Instance> Event<'d, T> { /// 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> { +pub struct EventTrigger<'d> { number: EventNumber, - _phantom: PhantomData<&'d T>, + r: pac::ipc::Ipc, + _phantom: PhantomData<&'d ()>, } -impl EventTrigger<'_, T> { +impl EventTrigger<'_> { /// Trigger the event. pub fn trigger(&self) { let nr = self.number; - T::regs().tasks_send(nr as usize).write_value(1); + self.r.tasks_send(nr as usize).write_value(1); } /// Returns the [`EventNumber`] of the event. -- cgit From 34ed1a1f05d909cba7ce3198b434126d47faf264 Mon Sep 17 00:00:00 2001 From: Dario Nieuwenhuis Date: Sat, 27 Sep 2025 21:14:03 +0200 Subject: nrf/egu: erase instance generics --- embassy-nrf/src/egu.rs | 42 ++++++++++++++++++++++++------------------ 1 file changed, 24 insertions(+), 18 deletions(-) diff --git a/embassy-nrf/src/egu.rs b/embassy-nrf/src/egu.rs index 028396c7c..f7372fca1 100644 --- a/embassy-nrf/src/egu.rs +++ b/embassy-nrf/src/egu.rs @@ -13,21 +13,26 @@ use crate::ppi::{Event, Task}; use crate::{interrupt, pac, Peri}; /// An instance of the EGU. -pub struct Egu<'d, T: Instance> { - _p: Peri<'d, T>, +pub struct Egu<'d> { + r: pac::egu::Egu, + _phantom: PhantomData<&'d ()>, } -impl<'d, T: Instance> Egu<'d, T> { +impl<'d> Egu<'d> { /// Create a new EGU instance. - pub fn new(_p: Peri<'d, T>) -> Self { - Self { _p } + pub fn new(_p: Peri<'d, T>) -> Self { + Self { + r: T::regs(), + _phantom: PhantomData, + } } /// Get a handle to a trigger for the EGU. - pub fn trigger(&mut self, number: TriggerNumber) -> Trigger<'d, T> { + pub fn trigger(&mut self, number: TriggerNumber) -> Trigger<'d> { Trigger { number, - _p: PhantomData, + r: self.r, + _phantom: PhantomData, } } } @@ -57,36 +62,37 @@ macro_rules! impl_egu { } /// Represents a trigger within the EGU. -pub struct Trigger<'d, T: Instance> { +pub struct Trigger<'d> { number: TriggerNumber, - _p: PhantomData<&'d T>, + r: pac::egu::Egu, + _phantom: PhantomData<&'d ()>, } -impl<'d, T: Instance> Trigger<'d, T> { +impl<'d> Trigger<'d> { /// Get task for this trigger to use with PPI. pub fn task(&self) -> Task<'d> { let nr = self.number as usize; - let regs = T::regs(); - Task::from_reg(regs.tasks_trigger(nr)) + Task::from_reg(self.r.tasks_trigger(nr)) } /// Get event for this trigger to use with PPI. pub fn event(&self) -> Event<'d> { let nr = self.number as usize; - let regs = T::regs(); - Event::from_reg(regs.events_triggered(nr)) + Event::from_reg(self.r.events_triggered(nr)) } /// Enable interrupts for this trigger pub fn enable_interrupt(&mut self) { - let regs = T::regs(); - regs.intenset().modify(|w| w.set_triggered(self.number as usize, true)); + self.r + .intenset() + .modify(|w| w.set_triggered(self.number as usize, true)); } /// Enable interrupts for this trigger pub fn disable_interrupt(&mut self) { - let regs = T::regs(); - regs.intenset().modify(|w| w.set_triggered(self.number as usize, false)); + self.r + .intenset() + .modify(|w| w.set_triggered(self.number as usize, false)); } } -- cgit From b552373f9a7c5491367d8f5a04111eb27b63f5e2 Mon Sep 17 00:00:00 2001 From: Dario Nieuwenhuis Date: Sat, 27 Sep 2025 21:15:53 +0200 Subject: nrf/pdm: erase instance generics --- embassy-nrf/src/pdm.rs | 107 ++++++++++++++++++++++++++----------------------- 1 file changed, 56 insertions(+), 51 deletions(-) diff --git a/embassy-nrf/src/pdm.rs b/embassy-nrf/src/pdm.rs index c2a4ba65f..b6ee52850 100644 --- a/embassy-nrf/src/pdm.rs +++ b/embassy-nrf/src/pdm.rs @@ -53,8 +53,10 @@ impl interrupt::typelevel::Handler for InterruptHandl } /// PDM microphone interface -pub struct Pdm<'d, T: Instance> { - _peri: Peri<'d, T>, +pub struct Pdm<'d> { + r: pac::pdm::Pdm, + state: &'static State, + _phantom: PhantomData<&'d ()>, } /// PDM error @@ -86,9 +88,9 @@ pub enum SamplerState { Stopped, } -impl<'d, T: Instance> Pdm<'d, T> { +impl<'d> Pdm<'d> { /// Create PDM driver - pub fn new( + pub fn new( pdm: Peri<'d, T>, _irq: impl interrupt::typelevel::Binding> + 'd, clk: Peri<'d, impl GpioPin>, @@ -98,7 +100,7 @@ impl<'d, T: Instance> Pdm<'d, T> { Self::new_inner(pdm, clk.into(), din.into(), config) } - fn new_inner(pdm: Peri<'d, T>, clk: Peri<'d, AnyPin>, din: Peri<'d, AnyPin>, config: Config) -> Self { + fn new_inner(_pdm: Peri<'d, T>, clk: Peri<'d, AnyPin>, din: Peri<'d, AnyPin>, config: Config) -> Self { let r = T::regs(); // setup gpio pins @@ -133,7 +135,11 @@ impl<'d, T: Instance> Pdm<'d, T> { r.enable().write(|w| w.set_enable(true)); - Self { _peri: pdm } + Self { + r: T::regs(), + state: T::state(), + _phantom: PhantomData, + } } fn _set_gain(r: pac::pdm::Pdm, gain_left: I7F1, gain_right: I7F1) { @@ -147,26 +153,26 @@ impl<'d, T: Instance> Pdm<'d, T> { /// Adjust the gain of the PDM microphone on the fly pub fn set_gain(&mut self, gain_left: I7F1, gain_right: I7F1) { - Self::_set_gain(T::regs(), gain_left, gain_right) + Self::_set_gain(self.r, gain_left, gain_right) } /// Start sampling microphone data into a dummy buffer. /// Useful to start the microphone and keep it active between recording samples. pub async fn start(&mut self) { - let r = T::regs(); - // start dummy sampling because microphone needs some setup time - r.sample().ptr().write_value(DUMMY_BUFFER.as_ptr() as u32); - r.sample().maxcnt().write(|w| w.set_buffsize(DUMMY_BUFFER.len() as _)); + self.r.sample().ptr().write_value(DUMMY_BUFFER.as_ptr() as u32); + self.r + .sample() + .maxcnt() + .write(|w| w.set_buffsize(DUMMY_BUFFER.len() as _)); - r.tasks_start().write_value(1); + self.r.tasks_start().write_value(1); } /// Stop sampling microphone data inta a dummy buffer pub async fn stop(&mut self) { - let r = T::regs(); - r.tasks_stop().write_value(1); - r.events_started().write_value(0); + self.r.tasks_stop().write_value(1); + self.r.events_started().write_value(0); } /// Sample data into the given buffer @@ -178,12 +184,11 @@ impl<'d, T: Instance> Pdm<'d, T> { return Err(Error::BufferTooLong); } - let r = T::regs(); - - if r.events_started().read() == 0 { + if self.r.events_started().read() == 0 { return Err(Error::NotRunning); } + let r = self.r; let drop = OnDrop::new(move || { r.intenclr().write(|w| w.set_end(true)); r.events_stopped().write_value(0); @@ -198,34 +203,37 @@ impl<'d, T: Instance> Pdm<'d, T> { // setup user buffer let ptr = buffer.as_ptr(); let len = buffer.len(); - r.sample().ptr().write_value(ptr as u32); - r.sample().maxcnt().write(|w| w.set_buffsize(len as _)); + self.r.sample().ptr().write_value(ptr as u32); + self.r.sample().maxcnt().write(|w| w.set_buffsize(len as _)); // wait till the current sample is finished and the user buffer sample is started - Self::wait_for_sample().await; + self.wait_for_sample().await; // reset the buffer back to the dummy buffer - r.sample().ptr().write_value(DUMMY_BUFFER.as_ptr() as u32); - r.sample().maxcnt().write(|w| w.set_buffsize(DUMMY_BUFFER.len() as _)); + self.r.sample().ptr().write_value(DUMMY_BUFFER.as_ptr() as u32); + self.r + .sample() + .maxcnt() + .write(|w| w.set_buffsize(DUMMY_BUFFER.len() as _)); // wait till the user buffer is sampled - Self::wait_for_sample().await; + self.wait_for_sample().await; drop.defuse(); Ok(()) } - async fn wait_for_sample() { - let r = T::regs(); - - r.events_end().write_value(0); - r.intenset().write(|w| w.set_end(true)); + async fn wait_for_sample(&mut self) { + self.r.events_end().write_value(0); + self.r.intenset().write(|w| w.set_end(true)); compiler_fence(Ordering::SeqCst); + let state = self.state; + let r = self.r; poll_fn(|cx| { - T::state().waker.register(cx.waker()); + state.waker.register(cx.waker()); if r.events_end().read() != 0 { return Poll::Ready(()); } @@ -255,20 +263,18 @@ impl<'d, T: Instance> Pdm<'d, T> { where S: FnMut(&[i16; N]) -> SamplerState, { - let r = T::regs(); - - if r.events_started().read() != 0 { + if self.r.events_started().read() != 0 { return Err(Error::AlreadyRunning); } - r.sample().ptr().write_value(bufs[0].as_mut_ptr() as u32); - r.sample().maxcnt().write(|w| w.set_buffsize(N as _)); + self.r.sample().ptr().write_value(bufs[0].as_mut_ptr() as u32); + self.r.sample().maxcnt().write(|w| w.set_buffsize(N as _)); // Reset and enable the events - r.events_end().write_value(0); - r.events_started().write_value(0); - r.events_stopped().write_value(0); - r.intenset().write(|w| { + self.r.events_end().write_value(0); + self.r.events_started().write_value(0); + self.r.events_stopped().write_value(0); + self.r.intenset().write(|w| { w.set_end(true); w.set_started(true); w.set_stopped(true); @@ -278,23 +284,24 @@ impl<'d, T: Instance> Pdm<'d, T> { // wouldn't happen anyway compiler_fence(Ordering::SeqCst); - r.tasks_start().write_value(1); + self.r.tasks_start().write_value(1); let mut current_buffer = 0; let mut done = false; - let drop = OnDrop::new(|| { + let r = self.r; + let drop = OnDrop::new(move || { r.tasks_stop().write_value(1); // N.B. It would be better if this were async, but Drop only support sync code while r.events_stopped().read() != 0 {} }); + let state = self.state; + let r = self.r; // Wait for events and complete when the sampler indicates it has had enough poll_fn(|cx| { - let r = T::regs(); - - T::state().waker.register(cx.waker()); + state.waker.register(cx.waker()); if r.events_end().read() != 0 { compiler_fence(Ordering::SeqCst); @@ -411,16 +418,14 @@ impl From for vals::Edge { } } -impl<'d, T: Instance> Drop for Pdm<'d, T> { +impl<'d> Drop for Pdm<'d> { fn drop(&mut self) { - let r = T::regs(); - - r.tasks_stop().write_value(1); + self.r.tasks_stop().write_value(1); - r.enable().write(|w| w.set_enable(false)); + self.r.enable().write(|w| w.set_enable(false)); - r.psel().din().write_value(DISCONNECTED); - r.psel().clk().write_value(DISCONNECTED); + self.r.psel().din().write_value(DISCONNECTED); + self.r.psel().clk().write_value(DISCONNECTED); } } -- cgit From 6ee0d15f4975daa52a22c42e57c673f5ecc86b9d Mon Sep 17 00:00:00 2001 From: Dario Nieuwenhuis Date: Sat, 27 Sep 2025 21:17:11 +0200 Subject: nrf/pwm: erase instance generics --- embassy-nrf/src/pwm.rs | 147 ++++++++++++++++++++----------------------------- 1 file changed, 60 insertions(+), 87 deletions(-) diff --git a/embassy-nrf/src/pwm.rs b/embassy-nrf/src/pwm.rs index d6b40b5c0..d67cb546b 100644 --- a/embassy-nrf/src/pwm.rs +++ b/embassy-nrf/src/pwm.rs @@ -15,8 +15,8 @@ use crate::{interrupt, pac}; /// SimplePwm is the traditional pwm interface you're probably used to, allowing /// to simply set a duty cycle across up to four channels. -pub struct SimplePwm<'d, T: Instance> { - _peri: Peri<'d, T>, +pub struct SimplePwm<'d> { + r: pac::pwm::Pwm, duty: [u16; 4], ch0: Option>, ch1: Option>, @@ -26,8 +26,8 @@ pub struct SimplePwm<'d, T: Instance> { /// SequencePwm allows you to offload the updating of a sequence of duty cycles /// to up to four channels, as well as repeat that sequence n times. -pub struct SequencePwm<'d, T: Instance> { - _peri: Peri<'d, T>, +pub struct SequencePwm<'d> { + r: pac::pwm::Pwm, ch0: Option>, ch1: Option>, ch2: Option>, @@ -51,16 +51,16 @@ const MAX_SEQUENCE_LEN: usize = 32767; /// The used pwm clock frequency pub const PWM_CLK_HZ: u32 = 16_000_000; -impl<'d, T: Instance> SequencePwm<'d, T> { +impl<'d> SequencePwm<'d> { /// Create a new 1-channel PWM #[allow(unused_unsafe)] - pub fn new_1ch(pwm: Peri<'d, T>, ch0: Peri<'d, impl GpioPin>, config: Config) -> Result { + pub fn new_1ch(pwm: Peri<'d, T>, ch0: Peri<'d, impl GpioPin>, config: Config) -> Result { Self::new_inner(pwm, Some(ch0.into()), None, None, None, config) } /// Create a new 2-channel PWM #[allow(unused_unsafe)] - pub fn new_2ch( + pub fn new_2ch( pwm: Peri<'d, T>, ch0: Peri<'d, impl GpioPin>, ch1: Peri<'d, impl GpioPin>, @@ -71,7 +71,7 @@ impl<'d, T: Instance> SequencePwm<'d, T> { /// Create a new 3-channel PWM #[allow(unused_unsafe)] - pub fn new_3ch( + pub fn new_3ch( pwm: Peri<'d, T>, ch0: Peri<'d, impl GpioPin>, ch1: Peri<'d, impl GpioPin>, @@ -83,7 +83,7 @@ impl<'d, T: Instance> SequencePwm<'d, T> { /// Create a new 4-channel PWM #[allow(unused_unsafe)] - pub fn new_4ch( + pub fn new_4ch( pwm: Peri<'d, T>, ch0: Peri<'d, impl GpioPin>, ch1: Peri<'d, impl GpioPin>, @@ -101,7 +101,7 @@ impl<'d, T: Instance> SequencePwm<'d, T> { ) } - fn new_inner( + fn new_inner( _pwm: Peri<'d, T>, ch0: Option>, ch1: Option>, @@ -174,7 +174,7 @@ impl<'d, T: Instance> SequencePwm<'d, T> { r.countertop().write(|w| w.set_countertop(config.max_duty)); Ok(Self { - _peri: _pwm, + r: T::regs(), ch0, ch1, ch2, @@ -185,57 +185,43 @@ impl<'d, T: Instance> SequencePwm<'d, T> { /// Returns reference to `Stopped` event endpoint for PPI. #[inline(always)] pub fn event_stopped(&self) -> Event<'d> { - let r = T::regs(); - - Event::from_reg(r.events_stopped()) + Event::from_reg(self.r.events_stopped()) } /// Returns reference to `LoopsDone` event endpoint for PPI. #[inline(always)] pub fn event_loops_done(&self) -> Event<'d> { - let r = T::regs(); - - Event::from_reg(r.events_loopsdone()) + Event::from_reg(self.r.events_loopsdone()) } /// Returns reference to `PwmPeriodEnd` event endpoint for PPI. #[inline(always)] pub fn event_pwm_period_end(&self) -> Event<'d> { - let r = T::regs(); - - Event::from_reg(r.events_pwmperiodend()) + Event::from_reg(self.r.events_pwmperiodend()) } /// Returns reference to `Seq0 End` event endpoint for PPI. #[inline(always)] pub fn event_seq_end(&self) -> Event<'d> { - let r = T::regs(); - - Event::from_reg(r.events_seqend(0)) + Event::from_reg(self.r.events_seqend(0)) } /// Returns reference to `Seq1 End` event endpoint for PPI. #[inline(always)] pub fn event_seq1_end(&self) -> Event<'d> { - let r = T::regs(); - - Event::from_reg(r.events_seqend(1)) + Event::from_reg(self.r.events_seqend(1)) } /// Returns reference to `Seq0 Started` event endpoint for PPI. #[inline(always)] pub fn event_seq0_started(&self) -> Event<'d> { - let r = T::regs(); - - Event::from_reg(r.events_seqstarted(0)) + Event::from_reg(self.r.events_seqstarted(0)) } /// Returns reference to `Seq1 Started` event endpoint for PPI. #[inline(always)] pub fn event_seq1_started(&self) -> Event<'d> { - let r = T::regs(); - - Event::from_reg(r.events_seqstarted(1)) + Event::from_reg(self.r.events_seqstarted(1)) } /// Returns reference to `Seq0 Start` task endpoint for PPI. @@ -244,9 +230,7 @@ impl<'d, T: Instance> SequencePwm<'d, T> { /// Interacting with the sequence while it runs puts it in an unknown state #[inline(always)] pub unsafe fn task_start_seq0(&self) -> Task<'d> { - let r = T::regs(); - - Task::from_reg(r.tasks_seqstart(0)) + Task::from_reg(self.r.tasks_seqstart(0)) } /// Returns reference to `Seq1 Started` task endpoint for PPI. @@ -255,9 +239,7 @@ impl<'d, T: Instance> SequencePwm<'d, T> { /// Interacting with the sequence while it runs puts it in an unknown state #[inline(always)] pub unsafe fn task_start_seq1(&self) -> Task<'d> { - let r = T::regs(); - - Task::from_reg(r.tasks_seqstart(1)) + Task::from_reg(self.r.tasks_seqstart(1)) } /// Returns reference to `NextStep` task endpoint for PPI. @@ -266,9 +248,7 @@ impl<'d, T: Instance> SequencePwm<'d, T> { /// Interacting with the sequence while it runs puts it in an unknown state #[inline(always)] pub unsafe fn task_next_step(&self) -> Task<'d> { - let r = T::regs(); - - Task::from_reg(r.tasks_nextstep()) + Task::from_reg(self.r.tasks_nextstep()) } /// Returns reference to `Stop` task endpoint for PPI. @@ -277,36 +257,34 @@ impl<'d, T: Instance> SequencePwm<'d, T> { /// Interacting with the sequence while it runs puts it in an unknown state #[inline(always)] pub unsafe fn task_stop(&self) -> Task<'d> { - let r = T::regs(); - - Task::from_reg(r.tasks_stop()) + Task::from_reg(self.r.tasks_stop()) } } -impl<'a, T: Instance> Drop for SequencePwm<'a, T> { +impl<'a> Drop for SequencePwm<'a> { fn drop(&mut self) { - let r = T::regs(); - if let Some(pin) = &self.ch0 { pin.set_low(); pin.conf().write(|_| ()); - r.psel().out(0).write_value(DISCONNECTED); + self.r.psel().out(0).write_value(DISCONNECTED); } if let Some(pin) = &self.ch1 { pin.set_low(); pin.conf().write(|_| ()); - r.psel().out(1).write_value(DISCONNECTED); + self.r.psel().out(1).write_value(DISCONNECTED); } if let Some(pin) = &self.ch2 { pin.set_low(); pin.conf().write(|_| ()); - r.psel().out(2).write_value(DISCONNECTED); + self.r.psel().out(2).write_value(DISCONNECTED); } if let Some(pin) = &self.ch3 { pin.set_low(); pin.conf().write(|_| ()); - r.psel().out(3).write_value(DISCONNECTED); + self.r.psel().out(3).write_value(DISCONNECTED); } + + self.r.enable().write(|w| w.set_enable(false)); } } @@ -384,13 +362,13 @@ impl<'s> Sequence<'s> { /// A single sequence that can be started and stopped. /// Takes one sequence along with its configuration. #[non_exhaustive] -pub struct SingleSequencer<'d, 's, T: Instance> { - sequencer: Sequencer<'d, 's, T>, +pub struct SingleSequencer<'d, 's> { + sequencer: Sequencer<'d, 's>, } -impl<'d, 's, T: Instance> SingleSequencer<'d, 's, T> { +impl<'d, 's> SingleSequencer<'d, 's> { /// Create a new sequencer - pub fn new(pwm: &'s mut SequencePwm<'d, T>, words: &'s [u16], config: SequenceConfig) -> Self { + pub fn new(pwm: &'s mut SequencePwm<'d>, words: &'s [u16], config: SequenceConfig) -> Self { Self { sequencer: Sequencer::new(pwm, Sequence::new(words, config), None), } @@ -423,16 +401,16 @@ impl<'d, 's, T: Instance> SingleSequencer<'d, 's, T> { /// In the case where no second sequence is provided then the first sequence /// is used. #[non_exhaustive] -pub struct Sequencer<'d, 's, T: Instance> { - _pwm: &'s mut SequencePwm<'d, T>, +pub struct Sequencer<'d, 's> { + _pwm: &'s mut SequencePwm<'d>, sequence0: Sequence<'s>, sequence1: Option>, } -impl<'d, 's, T: Instance> Sequencer<'d, 's, T> { +impl<'d, 's> Sequencer<'d, 's> { /// Create a new double sequence. In the absence of sequence 1, sequence 0 /// will be used twice in the one loop. - pub fn new(pwm: &'s mut SequencePwm<'d, T>, sequence0: Sequence<'s>, sequence1: Option>) -> Self { + pub fn new(pwm: &'s mut SequencePwm<'d>, sequence0: Sequence<'s>, sequence1: Option>) -> Self { Sequencer { _pwm: pwm, sequence0, @@ -459,7 +437,7 @@ impl<'d, 's, T: Instance> Sequencer<'d, 's, T> { self.stop(); - let r = T::regs(); + let r = self._pwm.r; r.seq(0).refresh().write(|w| w.0 = sequence0.config.refresh); r.seq(0).enddelay().write(|w| w.0 = sequence0.config.end_delay); @@ -499,7 +477,7 @@ impl<'d, 's, T: Instance> Sequencer<'d, 's, T> { /// `start` so that they may be further mutated. #[inline(always)] pub fn stop(&self) { - let r = T::regs(); + let r = self._pwm.r; r.shorts().write(|_| ()); @@ -510,7 +488,7 @@ impl<'d, 's, T: Instance> Sequencer<'d, 's, T> { } } -impl<'d, 's, T: Instance> Drop for Sequencer<'d, 's, T> { +impl<'d, 's> Drop for Sequencer<'d, 's> { fn drop(&mut self) { self.stop(); } @@ -589,22 +567,22 @@ pub enum CounterMode { UpAndDown, } -impl<'d, T: Instance> SimplePwm<'d, T> { +impl<'d> SimplePwm<'d> { /// Create a new 1-channel PWM #[allow(unused_unsafe)] - pub fn new_1ch(pwm: Peri<'d, T>, ch0: Peri<'d, impl GpioPin>) -> Self { + pub fn new_1ch(pwm: Peri<'d, T>, ch0: Peri<'d, impl GpioPin>) -> Self { unsafe { Self::new_inner(pwm, Some(ch0.into()), None, None, None) } } /// Create a new 2-channel PWM #[allow(unused_unsafe)] - pub fn new_2ch(pwm: Peri<'d, T>, ch0: Peri<'d, impl GpioPin>, ch1: Peri<'d, impl GpioPin>) -> Self { + pub fn new_2ch(pwm: Peri<'d, T>, ch0: Peri<'d, impl GpioPin>, ch1: Peri<'d, impl GpioPin>) -> Self { Self::new_inner(pwm, Some(ch0.into()), Some(ch1.into()), None, None) } /// Create a new 3-channel PWM #[allow(unused_unsafe)] - pub fn new_3ch( + pub fn new_3ch( pwm: Peri<'d, T>, ch0: Peri<'d, impl GpioPin>, ch1: Peri<'d, impl GpioPin>, @@ -615,7 +593,7 @@ impl<'d, T: Instance> SimplePwm<'d, T> { /// Create a new 4-channel PWM #[allow(unused_unsafe)] - pub fn new_4ch( + pub fn new_4ch( pwm: Peri<'d, T>, ch0: Peri<'d, impl GpioPin>, ch1: Peri<'d, impl GpioPin>, @@ -633,7 +611,7 @@ impl<'d, T: Instance> SimplePwm<'d, T> { } } - fn new_inner( + fn new_inner( _pwm: Peri<'d, T>, ch0: Option>, ch1: Option>, @@ -656,7 +634,7 @@ impl<'d, T: Instance> SimplePwm<'d, T> { } let pwm = Self { - _peri: _pwm, + r: T::regs(), ch0, ch1, ch2, @@ -691,22 +669,19 @@ impl<'d, T: Instance> SimplePwm<'d, T> { /// Returns the enable state of the pwm counter #[inline(always)] pub fn is_enabled(&self) -> bool { - let r = T::regs(); - r.enable().read().enable() + self.r.enable().read().enable() } /// Enables the PWM generator. #[inline(always)] pub fn enable(&self) { - let r = T::regs(); - r.enable().write(|w| w.set_enable(true)); + self.r.enable().write(|w| w.set_enable(true)); } /// Disables the PWM generator. Does NOT clear the last duty cycle from the pin. #[inline(always)] pub fn disable(&self) { - let r = T::regs(); - r.enable().write(|w| w.set_enable(false)); + self.r.enable().write(|w| w.set_enable(false)); } /// Returns the current duty of the channel @@ -716,32 +691,30 @@ impl<'d, T: Instance> SimplePwm<'d, T> { /// Sets duty cycle (15 bit) for a PWM channel. pub fn set_duty(&mut self, channel: usize, duty: u16) { - let r = T::regs(); - self.duty[channel] = duty & 0x7FFF; // reload ptr in case self was moved - r.seq(0).ptr().write_value((self.duty).as_ptr() as u32); + self.r.seq(0).ptr().write_value((self.duty).as_ptr() as u32); // defensive before seqstart compiler_fence(Ordering::SeqCst); - r.events_seqend(0).write_value(0); + self.r.events_seqend(0).write_value(0); // tasks_seqstart() doesn't exist in all svds so write its bit instead - r.tasks_seqstart(0).write_value(1); + self.r.tasks_seqstart(0).write_value(1); // defensive wait until waveform is loaded after seqstart so set_duty // can't be called again while dma is still reading if self.is_enabled() { - while r.events_seqend(0).read() == 0 {} + while self.r.events_seqend(0).read() == 0 {} } } /// Sets the PWM clock prescaler. #[inline(always)] pub fn set_prescaler(&self, div: Prescaler) { - T::regs() + self.r .prescaler() .write(|w| w.set_prescaler(vals::Prescaler::from_bits(div as u8))); } @@ -749,7 +722,7 @@ impl<'d, T: Instance> SimplePwm<'d, T> { /// Gets the PWM clock prescaler. #[inline(always)] pub fn prescaler(&self) -> Prescaler { - match T::regs().prescaler().read().prescaler().to_bits() { + match self.r.prescaler().read().prescaler().to_bits() { 0 => Prescaler::Div1, 1 => Prescaler::Div2, 2 => Prescaler::Div4, @@ -765,13 +738,13 @@ impl<'d, T: Instance> SimplePwm<'d, T> { /// Sets the maximum duty cycle value. #[inline(always)] pub fn set_max_duty(&self, duty: u16) { - T::regs().countertop().write(|w| w.set_countertop(duty.min(32767u16))); + self.r.countertop().write(|w| w.set_countertop(duty.min(32767u16))); } /// Returns the maximum duty cycle value. #[inline(always)] pub fn max_duty(&self) -> u16 { - T::regs().countertop().read().countertop() + self.r.countertop().read().countertop() } /// Sets the PWM output frequency. @@ -823,9 +796,9 @@ impl<'d, T: Instance> SimplePwm<'d, T> { } } -impl<'a, T: Instance> Drop for SimplePwm<'a, T> { +impl<'a> Drop for SimplePwm<'a> { fn drop(&mut self) { - let r = T::regs(); + let r = &self.r; self.disable(); -- cgit From 6a262521811a435f2cfedd7e25fb70a1aab957ca Mon Sep 17 00:00:00 2001 From: Dario Nieuwenhuis Date: Sat, 27 Sep 2025 21:17:54 +0200 Subject: nrf/qdec: erase instance generics --- embassy-nrf/src/qdec.rs | 39 +++++++++++++++++++++++---------------- 1 file changed, 23 insertions(+), 16 deletions(-) diff --git a/embassy-nrf/src/qdec.rs b/embassy-nrf/src/qdec.rs index 69bfab0bb..0ebd7afb8 100644 --- a/embassy-nrf/src/qdec.rs +++ b/embassy-nrf/src/qdec.rs @@ -16,8 +16,10 @@ use crate::pac::qdec::vals; use crate::{interrupt, pac}; /// Quadrature decoder driver. -pub struct Qdec<'d, T: Instance> { - _p: Peri<'d, T>, +pub struct Qdec<'d> { + r: pac::qdec::Qdec, + state: &'static State, + _phantom: PhantomData<&'d ()>, } /// QDEC config @@ -59,9 +61,9 @@ impl interrupt::typelevel::Handler for InterruptHandl } } -impl<'d, T: Instance> Qdec<'d, T> { +impl<'d> Qdec<'d> { /// Create a new QDEC. - pub fn new( + pub fn new( qdec: Peri<'d, T>, _irq: impl interrupt::typelevel::Binding> + 'd, a: Peri<'d, impl GpioPin>, @@ -72,7 +74,7 @@ impl<'d, T: Instance> Qdec<'d, T> { } /// Create a new QDEC, with a pin for LED output. - pub fn new_with_led( + pub fn new_with_led( qdec: Peri<'d, T>, _irq: impl interrupt::typelevel::Binding> + 'd, a: Peri<'d, impl GpioPin>, @@ -83,8 +85,8 @@ impl<'d, T: Instance> Qdec<'d, T> { Self::new_inner(qdec, a.into(), b.into(), Some(led.into()), config) } - fn new_inner( - p: Peri<'d, T>, + fn new_inner( + _p: Peri<'d, T>, a: Peri<'d, AnyPin>, b: Peri<'d, AnyPin>, led: Option>, @@ -147,7 +149,11 @@ impl<'d, T: Instance> Qdec<'d, T> { // Start sampling r.tasks_start().write_value(1); - Self { _p: p } + Self { + r: T::regs(), + state: T::state(), + _phantom: PhantomData, + } } /// Perform an asynchronous read of the decoder. @@ -173,17 +179,18 @@ impl<'d, T: Instance> Qdec<'d, T> { /// # }; /// ``` pub async fn read(&mut self) -> i16 { - let t = T::regs(); - t.intenset().write(|w| w.set_reportrdy(true)); - t.tasks_readclracc().write_value(1); + self.r.intenset().write(|w| w.set_reportrdy(true)); + self.r.tasks_readclracc().write_value(1); - poll_fn(|cx| { - T::state().waker.register(cx.waker()); - if t.events_reportrdy().read() == 0 { + let state = self.state; + let r = self.r; + poll_fn(move |cx| { + state.waker.register(cx.waker()); + if r.events_reportrdy().read() == 0 { Poll::Pending } else { - t.events_reportrdy().write_value(0); - let acc = t.accread().read(); + r.events_reportrdy().write_value(0); + let acc = r.accread().read(); Poll::Ready(acc as i16) } }) -- cgit From 19fdd8d96c778697610386c829f6a0a655c39940 Mon Sep 17 00:00:00 2001 From: Dario Nieuwenhuis Date: Sat, 27 Sep 2025 21:18:29 +0200 Subject: nrf/qspi: erase instance generics --- embassy-nrf/src/qspi.rs | 109 +++++++++++++++++++++++------------------------- 1 file changed, 52 insertions(+), 57 deletions(-) diff --git a/embassy-nrf/src/qspi.rs b/embassy-nrf/src/qspi.rs index e6e829f6e..94ad3f0d6 100755 --- a/embassy-nrf/src/qspi.rs +++ b/embassy-nrf/src/qspi.rs @@ -138,16 +138,18 @@ impl interrupt::typelevel::Handler for InterruptHandl } /// QSPI flash driver. -pub struct Qspi<'d, T: Instance> { - _peri: Peri<'d, T>, +pub struct Qspi<'d> { + r: pac::qspi::Qspi, + state: &'static State, dpm_enabled: bool, capacity: u32, + _phantom: PhantomData<&'d ()>, } -impl<'d, T: Instance> Qspi<'d, T> { +impl<'d> Qspi<'d> { /// Create a new QSPI driver. - pub fn new( - qspi: Peri<'d, T>, + pub fn new( + _qspi: Peri<'d, T>, _irq: impl interrupt::typelevel::Binding> + 'd, sck: Peri<'d, impl GpioPin>, csn: Peri<'d, impl GpioPin>, @@ -214,9 +216,11 @@ impl<'d, T: Instance> Qspi<'d, T> { r.enable().write(|w| w.set_enable(true)); let res = Self { - _peri: qspi, + r: T::regs(), + state: T::state(), dpm_enabled: config.deep_power_down.is_some(), capacity: config.capacity, + _phantom: PhantomData, }; r.events_ready().write_value(0); @@ -274,14 +278,13 @@ impl<'d, T: Instance> Qspi<'d, T> { } } - let r = T::regs(); - r.cinstrdat0().write(|w| w.0 = dat0); - r.cinstrdat1().write(|w| w.0 = dat1); + self.r.cinstrdat0().write(|w| w.0 = dat0); + self.r.cinstrdat1().write(|w| w.0 = dat1); - r.events_ready().write_value(0); - r.intenset().write(|w| w.set_ready(true)); + self.r.events_ready().write_value(0); + self.r.intenset().write(|w| w.set_ready(true)); - r.cinstrconf().write(|w| { + self.r.cinstrconf().write(|w| { w.set_opcode(opcode); w.set_length(vals::Length::from_bits(len + 1)); w.set_lio2(true); @@ -295,10 +298,8 @@ impl<'d, T: Instance> Qspi<'d, T> { } fn custom_instruction_finish(&mut self, resp: &mut [u8]) -> Result<(), Error> { - let r = T::regs(); - - let dat0 = r.cinstrdat0().read().0; - let dat1 = r.cinstrdat1().read().0; + let dat0 = self.r.cinstrdat0().read().0; + let dat1 = self.r.cinstrdat1().read().0; for i in 0..4 { if i < resp.len() { resp[i] = (dat0 >> (i * 8)) as u8; @@ -313,9 +314,9 @@ impl<'d, T: Instance> Qspi<'d, T> { } fn wait_ready(&mut self) -> impl Future { + let r = self.r; + let s = self.state; poll_fn(move |cx| { - let r = T::regs(); - let s = T::state(); s.waker.register(cx.waker()); if r.events_ready().read() != 0 { return Poll::Ready(()); @@ -326,7 +327,7 @@ impl<'d, T: Instance> Qspi<'d, T> { fn blocking_wait_ready() { loop { - let r = T::regs(); + let r = pac::QSPI; if r.events_ready().read() != 0 { break; } @@ -339,15 +340,13 @@ impl<'d, T: Instance> Qspi<'d, T> { assert_eq!(data.len() as u32 % 4, 0); assert_eq!(address % 4, 0); - let r = T::regs(); - - r.read().src().write_value(address); - r.read().dst().write_value(data.as_ptr() as u32); - r.read().cnt().write(|w| w.set_cnt(data.len() as u32)); + self.r.read().src().write_value(address); + self.r.read().dst().write_value(data.as_ptr() as u32); + self.r.read().cnt().write(|w| w.set_cnt(data.len() as u32)); - r.events_ready().write_value(0); - r.intenset().write(|w| w.set_ready(true)); - r.tasks_readstart().write_value(1); + self.r.events_ready().write_value(0); + self.r.intenset().write(|w| w.set_ready(true)); + self.r.tasks_readstart().write_value(1); Ok(()) } @@ -358,14 +357,13 @@ impl<'d, T: Instance> Qspi<'d, T> { assert_eq!(data.len() as u32 % 4, 0); assert_eq!(address % 4, 0); - let r = T::regs(); - r.write().src().write_value(data.as_ptr() as u32); - r.write().dst().write_value(address); - r.write().cnt().write(|w| w.set_cnt(data.len() as u32)); + self.r.write().src().write_value(data.as_ptr() as u32); + self.r.write().dst().write_value(address); + self.r.write().cnt().write(|w| w.set_cnt(data.len() as u32)); - r.events_ready().write_value(0); - r.intenset().write(|w| w.set_ready(true)); - r.tasks_writestart().write_value(1); + self.r.events_ready().write_value(0); + self.r.intenset().write(|w| w.set_ready(true)); + self.r.tasks_writestart().write_value(1); Ok(()) } @@ -374,13 +372,12 @@ impl<'d, T: Instance> Qspi<'d, T> { // TODO: Return these as errors instead. assert_eq!(address % 4096, 0); - let r = T::regs(); - r.erase().ptr().write_value(address); - r.erase().len().write(|w| w.set_len(vals::Len::_4KB)); + self.r.erase().ptr().write_value(address); + self.r.erase().len().write(|w| w.set_len(vals::Len::_4KB)); - r.events_ready().write_value(0); - r.intenset().write(|w| w.set_ready(true)); - r.tasks_erasestart().write_value(1); + self.r.events_ready().write_value(0); + self.r.intenset().write(|w| w.set_ready(true)); + self.r.tasks_erasestart().write_value(1); Ok(()) } @@ -520,19 +517,17 @@ impl<'d, T: Instance> Qspi<'d, T> { } } -impl<'d, T: Instance> Drop for Qspi<'d, T> { +impl<'d> Drop for Qspi<'d> { fn drop(&mut self) { - let r = T::regs(); - if self.dpm_enabled { trace!("qspi: doing deep powerdown..."); - r.ifconfig1().modify(|w| w.set_dpmen(true)); + self.r.ifconfig1().modify(|w| w.set_dpmen(true)); // Wait for DPM enter. // Unfortunately we must spin. There's no way to do this interrupt-driven. // The READY event does NOT fire on DPM enter (but it does fire on DPM exit :shrug:) - while !r.status().read().dpm() {} + while !self.r.status().read().dpm() {} // Wait MORE for DPM enter. // I have absolutely no idea why, but the wait above is not enough :'( @@ -541,29 +536,29 @@ impl<'d, T: Instance> Drop for Qspi<'d, T> { } // it seems events_ready is not generated in response to deactivate. nrfx doesn't wait for it. - r.tasks_deactivate().write_value(1); + self.r.tasks_deactivate().write_value(1); // Workaround https://docs.nordicsemi.com/bundle/errata_nRF52840_Rev3/page/ERR/nRF52840/Rev3/latest/anomaly_840_122.html // Note that the doc has 2 register writes, but the first one is really the write to tasks_deactivate, // so we only do the second one here. unsafe { ptr::write_volatile(0x40029054 as *mut u32, 1) } - r.enable().write(|w| w.set_enable(false)); + self.r.enable().write(|w| w.set_enable(false)); // Note: we do NOT deconfigure CSN here. If DPM is in use and we disconnect CSN, // leaving it floating, the flash chip might read it as zero which would cause it to // spuriously exit DPM. - gpio::deconfigure_pin(r.psel().sck().read()); - gpio::deconfigure_pin(r.psel().io0().read()); - gpio::deconfigure_pin(r.psel().io1().read()); - gpio::deconfigure_pin(r.psel().io2().read()); - gpio::deconfigure_pin(r.psel().io3().read()); + gpio::deconfigure_pin(self.r.psel().sck().read()); + gpio::deconfigure_pin(self.r.psel().io0().read()); + gpio::deconfigure_pin(self.r.psel().io1().read()); + gpio::deconfigure_pin(self.r.psel().io2().read()); + gpio::deconfigure_pin(self.r.psel().io3().read()); trace!("qspi: dropped"); } } -impl<'d, T: Instance> ErrorType for Qspi<'d, T> { +impl<'d> ErrorType for Qspi<'d> { type Error = Error; } @@ -573,7 +568,7 @@ impl NorFlashError for Error { } } -impl<'d, T: Instance> ReadNorFlash for Qspi<'d, T> { +impl<'d> ReadNorFlash for Qspi<'d> { const READ_SIZE: usize = 4; fn read(&mut self, offset: u32, bytes: &mut [u8]) -> Result<(), Self::Error> { @@ -586,7 +581,7 @@ impl<'d, T: Instance> ReadNorFlash for Qspi<'d, T> { } } -impl<'d, T: Instance> NorFlash for Qspi<'d, T> { +impl<'d> NorFlash for Qspi<'d> { const WRITE_SIZE: usize = 4; const ERASE_SIZE: usize = 4096; @@ -611,7 +606,7 @@ mod _eh1 { use super::*; - impl<'d, T: Instance> AsyncNorFlash for Qspi<'d, T> { + impl<'d> AsyncNorFlash for Qspi<'d> { const WRITE_SIZE: usize = ::WRITE_SIZE; const ERASE_SIZE: usize = ::ERASE_SIZE; @@ -627,7 +622,7 @@ mod _eh1 { } } - impl<'d, T: Instance> AsyncReadNorFlash for Qspi<'d, T> { + impl<'d> AsyncReadNorFlash for Qspi<'d> { const READ_SIZE: usize = 4; async fn read(&mut self, address: u32, data: &mut [u8]) -> Result<(), Self::Error> { self.read(address, data).await -- cgit From 37fd0c7bce19d4618669a29bdd01945fb477eea6 Mon Sep 17 00:00:00 2001 From: Dario Nieuwenhuis Date: Sat, 27 Sep 2025 21:19:13 +0200 Subject: nrf/rng: erase instance generics --- embassy-nrf/src/rng.rs | 56 +++++++++++++++++++++++++++----------------------- 1 file changed, 30 insertions(+), 26 deletions(-) diff --git a/embassy-nrf/src/rng.rs b/embassy-nrf/src/rng.rs index 9d3130e6e..8070c1afe 100644 --- a/embassy-nrf/src/rng.rs +++ b/embassy-nrf/src/rng.rs @@ -56,21 +56,23 @@ impl interrupt::typelevel::Handler for InterruptHandl /// A wrapper around an nRF RNG peripheral. /// /// It has a non-blocking API, and a blocking api through `rand`. -pub struct Rng<'d, T: Instance, M: Mode> { - _peri: Peri<'d, T>, - _phantom: PhantomData, +pub struct Rng<'d, M: Mode> { + r: pac::rng::Rng, + state: &'static State, + _phantom: PhantomData<(&'d (), M)>, } -impl<'d, T: Instance> Rng<'d, T, Blocking> { +impl<'d> Rng<'d, Blocking> { /// Creates a new RNG driver from the `RNG` peripheral and interrupt. /// /// SAFETY: The future returned from `fill_bytes` must not have its lifetime end without running its destructor, /// e.g. using `mem::forget`. /// /// The synchronous API is safe. - pub fn new_blocking(rng: Peri<'d, T>) -> Self { + pub fn new_blocking(_rng: Peri<'d, T>) -> Self { let this = Self { - _peri: rng, + r: T::regs(), + state: T::state(), _phantom: PhantomData, }; @@ -80,19 +82,20 @@ impl<'d, T: Instance> Rng<'d, T, Blocking> { } } -impl<'d, T: Instance> Rng<'d, T, Async> { +impl<'d> Rng<'d, Async> { /// Creates a new RNG driver from the `RNG` peripheral and interrupt. /// /// SAFETY: The future returned from `fill_bytes` must not have its lifetime end without running its destructor, /// e.g. using `mem::forget`. /// /// The synchronous API is safe. - pub fn new( - rng: Peri<'d, T>, + pub fn new( + _rng: Peri<'d, T>, _irq: impl interrupt::typelevel::Binding> + 'd, ) -> Self { let this = Self { - _peri: rng, + r: T::regs(), + state: T::state(), _phantom: PhantomData, }; @@ -106,11 +109,11 @@ impl<'d, T: Instance> Rng<'d, T, Async> { } fn enable_irq(&self) { - T::regs().intenset().write(|w| w.set_valrdy(true)); + self.r.intenset().write(|w| w.set_valrdy(true)); } fn disable_irq(&self) { - T::regs().intenclr().write(|w| w.set_valrdy(true)); + self.r.intenclr().write(|w| w.set_valrdy(true)); } /// Fill the buffer with random bytes. @@ -120,10 +123,11 @@ impl<'d, T: Instance> Rng<'d, T, Async> { } let range = dest.as_mut_ptr_range(); + let state = self.state; // Even if we've preempted the interrupt, it can't preempt us again, // so we don't need to worry about the order we write these in. critical_section::with(|cs| { - let mut state = T::state().borrow_mut(cs); + let mut state = state.borrow_mut(cs); state.ptr = range.start; state.end = range.end; }); @@ -136,7 +140,7 @@ impl<'d, T: Instance> Rng<'d, T, Async> { self.disable_irq(); critical_section::with(|cs| { - let mut state = T::state().borrow_mut(cs); + let mut state = state.borrow_mut(cs); state.ptr = ptr::null_mut(); state.end = ptr::null_mut(); }); @@ -144,7 +148,7 @@ impl<'d, T: Instance> Rng<'d, T, Async> { poll_fn(|cx| { critical_section::with(|cs| { - let mut s = T::state().borrow_mut(cs); + let mut s = state.borrow_mut(cs); s.waker.register(cx.waker()); if s.ptr == s.end { // We're done. @@ -161,13 +165,13 @@ impl<'d, T: Instance> Rng<'d, T, Async> { } } -impl<'d, T: Instance, M: Mode> Rng<'d, T, M> { +impl<'d, M: Mode> Rng<'d, M> { fn stop(&self) { - T::regs().tasks_stop().write_value(1) + self.r.tasks_stop().write_value(1) } fn start(&self) { - T::regs().tasks_start().write_value(1) + self.r.tasks_start().write_value(1) } /// Enable or disable the RNG's bias correction. @@ -177,7 +181,7 @@ impl<'d, T: Instance, M: Mode> Rng<'d, T, M> { /// /// Defaults to disabled. pub fn set_bias_correction(&self, enable: bool) { - T::regs().config().write(|w| w.set_dercen(enable)) + self.r.config().write(|w| w.set_dercen(enable)) } /// Fill the buffer with random bytes, blocking version. @@ -185,7 +189,7 @@ impl<'d, T: Instance, M: Mode> Rng<'d, T, M> { self.start(); for byte in dest.iter_mut() { - let regs = T::regs(); + let regs = self.r; while regs.events_valrdy().read() == 0 {} regs.events_valrdy().write_value(0); *byte = regs.value().read().value(); @@ -210,18 +214,18 @@ impl<'d, T: Instance, M: Mode> Rng<'d, T, M> { } } -impl<'d, T: Instance, M: Mode> Drop for Rng<'d, T, M> { +impl<'d, M: Mode> Drop for Rng<'d, M> { fn drop(&mut self) { self.stop(); critical_section::with(|cs| { - let mut state = T::state().borrow_mut(cs); + let mut state = self.state.borrow_mut(cs); state.ptr = ptr::null_mut(); state.end = ptr::null_mut(); }); } } -impl<'d, T: Instance, M: Mode> rand_core_06::RngCore for Rng<'d, T, M> { +impl<'d, M: Mode> rand_core_06::RngCore for Rng<'d, M> { fn fill_bytes(&mut self, dest: &mut [u8]) { self.blocking_fill_bytes(dest); } @@ -237,9 +241,9 @@ impl<'d, T: Instance, M: Mode> rand_core_06::RngCore for Rng<'d, T, M> { } } -impl<'d, T: Instance, M: Mode> rand_core_06::CryptoRng for Rng<'d, T, M> {} +impl<'d, M: Mode> rand_core_06::CryptoRng for Rng<'d, M> {} -impl<'d, T: Instance, M: Mode> rand_core_09::RngCore for Rng<'d, T, M> { +impl<'d, M: Mode> rand_core_09::RngCore for Rng<'d, M> { fn fill_bytes(&mut self, dest: &mut [u8]) { self.blocking_fill_bytes(dest); } @@ -251,7 +255,7 @@ impl<'d, T: Instance, M: Mode> rand_core_09::RngCore for Rng<'d, T, M> { } } -impl<'d, T: Instance, M: Mode> rand_core_09::CryptoRng for Rng<'d, T, M> {} +impl<'d, M: Mode> rand_core_09::CryptoRng for Rng<'d, M> {} /// Peripheral static state pub(crate) struct State { -- cgit From efe5b18f5d050bf19a5031f683ac24e23aad6746 Mon Sep 17 00:00:00 2001 From: Dario Nieuwenhuis Date: Sun, 28 Sep 2025 21:03:12 +0200 Subject: nrf/rtc: erase instance generic --- embassy-nrf/src/rtc.rs | 67 +++++++++++++++++++++++----------------- examples/nrf52840/src/bin/rtc.rs | 3 +- 2 files changed, 39 insertions(+), 31 deletions(-) diff --git a/embassy-nrf/src/rtc.rs b/embassy-nrf/src/rtc.rs index 1a90d1e24..652de511b 100644 --- a/embassy-nrf/src/rtc.rs +++ b/embassy-nrf/src/rtc.rs @@ -2,10 +2,13 @@ #![macro_use] +use core::marker::PhantomData; + +use embassy_hal_internal::interrupt::InterruptExt; use embassy_hal_internal::{Peri, PeripheralType}; -use crate::chip::interrupt::typelevel::Interrupt as _; -use crate::pac; +use crate::interrupt::typelevel::Interrupt as _; +use crate::{interrupt, pac}; /// Prescaler has an invalid value which exceeds 12 bits. #[derive(Debug, PartialEq, Eq)] @@ -88,23 +91,31 @@ macro_rules! impl_rtc { } /// nRF RTC driver. -pub struct Rtc<'d, T: Instance>(Peri<'d, T>); +pub struct Rtc<'d> { + r: pac::rtc::Rtc, + irq: interrupt::Interrupt, + _phantom: PhantomData<&'d ()>, +} -impl<'d, T: Instance> Rtc<'d, T> { +impl<'d> Rtc<'d> { /// Create a new `Rtc` driver. /// /// fRTC \[Hz\] = 32_768 / (`prescaler` + 1 ) - pub fn new(rtc: Peri<'d, T>, prescaler: u32) -> Result { + pub fn new(_rtc: Peri<'d, T>, prescaler: u32) -> Result { if prescaler >= (1 << 12) { return Err(PrescalerOutOfRangeError(prescaler)); } T::regs().prescaler().write(|w| w.set_prescaler(prescaler as u16)); - Ok(Self(rtc)) + Ok(Self { + r: T::regs(), + irq: T::Interrupt::IRQ, + _phantom: PhantomData, + }) } /// Create a new `Rtc` driver, configuring it to run at the given frequency. - pub fn new_for_freq(rtc: Peri<'d, T>, freq_hz: u32) -> Result { + pub fn new_for_freq(rtc: Peri<'d, T>, freq_hz: u32) -> Result { let prescaler = (32_768 / freq_hz).saturating_sub(1); Self::new(rtc, prescaler) } @@ -115,34 +126,38 @@ impl<'d, T: Instance> Rtc<'d, T> { /// /// Potentially allows to create multiple instances of the driver for the same peripheral /// which can lead to undefined behavior. - pub unsafe fn steal() -> Self { - Self(unsafe { T::steal() }) + pub unsafe fn steal() -> Self { + Self { + r: T::regs(), + irq: T::Interrupt::IRQ, + _phantom: PhantomData, + } } /// Direct access to the RTC registers. #[cfg(feature = "unstable-pac")] #[inline] pub fn regs(&mut self) -> pac::rtc::Rtc { - T::regs() + self.r } /// Enable the RTC. #[inline] pub fn enable(&mut self) { - T::regs().tasks_start().write_value(1); + self.r.tasks_start().write_value(1); } /// Disable the RTC. #[inline] pub fn disable(&mut self) { - T::regs().tasks_stop().write_value(1); + self.r.tasks_stop().write_value(1); } /// Enables interrupts for the given [Interrupt] source. /// /// Optionally also enables the interrupt in the NVIC. pub fn enable_interrupt(&mut self, int: Interrupt, enable_in_nvic: bool) { - let regs = T::regs(); + let regs = self.r; match int { Interrupt::Tick => regs.intenset().write(|w| w.set_tick(true)), Interrupt::Overflow => regs.intenset().write(|w| w.set_ovrflw(true)), @@ -152,7 +167,7 @@ impl<'d, T: Instance> Rtc<'d, T> { Interrupt::Compare3 => regs.intenset().write(|w| w.set_compare(3, true)), } if enable_in_nvic { - unsafe { T::Interrupt::enable() }; + unsafe { self.irq.enable() }; } } @@ -160,7 +175,7 @@ impl<'d, T: Instance> Rtc<'d, T> { /// /// Optionally also disables the interrupt in the NVIC. pub fn disable_interrupt(&mut self, int: Interrupt, disable_in_nvic: bool) { - let regs = T::regs(); + let regs = self.r; match int { Interrupt::Tick => regs.intenclr().write(|w| w.set_tick(true)), Interrupt::Overflow => regs.intenclr().write(|w| w.set_ovrflw(true)), @@ -170,13 +185,13 @@ impl<'d, T: Instance> Rtc<'d, T> { Interrupt::Compare3 => regs.intenclr().write(|w| w.set_compare(3, true)), } if disable_in_nvic { - T::Interrupt::disable(); + self.irq.disable(); } } /// Enable the generation of a hardware event from a given stimulus. pub fn enable_event(&mut self, evt: Interrupt) { - let regs = T::regs(); + let regs = self.r; match evt { Interrupt::Tick => regs.evtenset().write(|w| w.set_tick(true)), Interrupt::Overflow => regs.evtenset().write(|w| w.set_ovrflw(true)), @@ -189,7 +204,7 @@ impl<'d, T: Instance> Rtc<'d, T> { /// Disable the generation of a hardware event from a given stimulus. pub fn disable_event(&mut self, evt: Interrupt) { - let regs = T::regs(); + let regs = self.r; match evt { Interrupt::Tick => regs.evtenclr().write(|w| w.set_tick(true)), Interrupt::Overflow => regs.evtenclr().write(|w| w.set_ovrflw(true)), @@ -202,7 +217,7 @@ impl<'d, T: Instance> Rtc<'d, T> { /// Resets the given event. pub fn reset_event(&mut self, evt: Interrupt) { - let regs = T::regs(); + let regs = self.r; match evt { Interrupt::Tick => regs.events_tick().write_value(0), Interrupt::Overflow => regs.events_ovrflw().write_value(0), @@ -215,7 +230,7 @@ impl<'d, T: Instance> Rtc<'d, T> { /// Checks if the given event has been triggered. pub fn is_event_triggered(&self, evt: Interrupt) -> bool { - let regs = T::regs(); + let regs = self.r; let val = match evt { Interrupt::Tick => regs.events_tick().read(), Interrupt::Overflow => regs.events_ovrflw().read(), @@ -241,25 +256,19 @@ impl<'d, T: Instance> Rtc<'d, T> { CompareChannel::_3 => 3, }; - T::regs().cc(reg).write(|w| w.set_compare(val)); + self.r.cc(reg).write(|w| w.set_compare(val)); Ok(()) } /// Clear the Real Time Counter. #[inline] pub fn clear(&self) { - T::regs().tasks_clear().write_value(1); + self.r.tasks_clear().write_value(1); } /// Obtain the current value of the Real Time Counter, 24 bits of range. #[inline] pub fn read(&self) -> u32 { - T::regs().counter().read().counter() - } - - /// Relase the RTC, returning the underlying peripheral instance. - #[inline] - pub fn release(self) -> Peri<'d, T> { - self.0 + self.r.counter().read().counter() } } diff --git a/examples/nrf52840/src/bin/rtc.rs b/examples/nrf52840/src/bin/rtc.rs index a3df7da14..9d475df7f 100644 --- a/examples/nrf52840/src/bin/rtc.rs +++ b/examples/nrf52840/src/bin/rtc.rs @@ -14,8 +14,7 @@ use {defmt_rtt as _, panic_probe as _}; // 64 bit counter which will never overflow. static TICK_COUNTER: AtomicU64 = AtomicU64::new(0); -static RTC: Mutex>>> = - Mutex::new(RefCell::new(None)); +static RTC: Mutex>>> = Mutex::new(RefCell::new(None)); #[embassy_executor::main] async fn main(_spawner: Spawner) { -- cgit From 2b7e27db4ae8b0a39606490b17dbad562d64f1bd Mon Sep 17 00:00:00 2001 From: Dario Nieuwenhuis Date: Sun, 28 Sep 2025 21:03:59 +0200 Subject: nrf/wdt: erase instance generic --- embassy-nrf/src/wdt.rs | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-) diff --git a/embassy-nrf/src/wdt.rs b/embassy-nrf/src/wdt.rs index 7ab9adc29..dc99a16f5 100644 --- a/embassy-nrf/src/wdt.rs +++ b/embassy-nrf/src/wdt.rs @@ -66,11 +66,11 @@ impl Default for Config { } /// Watchdog driver. -pub struct Watchdog { - _wdt: Peri<'static, T>, +pub struct Watchdog { + r: pac::wdt::Wdt, } -impl Watchdog { +impl Watchdog { /// Try to create a new watchdog driver. /// /// This function will return an error if the watchdog is already active @@ -79,7 +79,7 @@ impl Watchdog { /// /// `N` must be between 1 and 8, inclusive. #[inline] - pub fn try_new( + pub fn try_new( wdt: Peri<'static, T>, config: Config, ) -> Result<(Self, [WatchdogHandle; N]), Peri<'static, T>> { @@ -116,7 +116,7 @@ impl Watchdog { r.tasks_start().write_value(1); } - let this = Self { _wdt: wdt }; + let this = Self { r: T::REGS }; let mut handles = [const { WatchdogHandle { index: 0 } }; N]; for i in 0..N { @@ -135,7 +135,7 @@ impl Watchdog { /// interrupt has been enabled. #[inline(always)] pub fn enable_interrupt(&mut self) { - T::REGS.intenset().write(|w| w.set_timeout(true)); + self.r.intenset().write(|w| w.set_timeout(true)); } /// Disable the watchdog interrupt. @@ -143,7 +143,7 @@ impl Watchdog { /// NOTE: This has no effect on the reset caused by the Watchdog. #[inline(always)] pub fn disable_interrupt(&mut self) { - T::REGS.intenclr().write(|w| w.set_timeout(true)); + self.r.intenclr().write(|w| w.set_timeout(true)); } /// Is the watchdog still awaiting pets from any handle? @@ -152,9 +152,8 @@ impl Watchdog { /// handles to prevent a reset this time period. #[inline(always)] pub fn awaiting_pets(&self) -> bool { - let r = T::REGS; - let enabled = r.rren().read().0; - let status = r.reqstatus().read().0; + let enabled = self.r.rren().read().0; + let status = self.r.reqstatus().read().0; (status & enabled) == 0 } } -- cgit From 6d9bf03a3becbb2ffd35a6f42a03da4e383dc46e Mon Sep 17 00:00:00 2001 From: Dario Nieuwenhuis Date: Sun, 28 Sep 2025 22:11:27 +0200 Subject: nrf/i2s: erase instance generic --- embassy-nrf/src/i2s.rs | 176 +++++++++++++++++++++++++++---------------------- 1 file changed, 98 insertions(+), 78 deletions(-) diff --git a/embassy-nrf/src/i2s.rs b/embassy-nrf/src/i2s.rs index 53de8deee..1bfa18491 100644 --- a/embassy-nrf/src/i2s.rs +++ b/embassy-nrf/src/i2s.rs @@ -381,7 +381,7 @@ pub struct InterruptHandler { impl interrupt::typelevel::Handler for InterruptHandler { unsafe fn on_interrupt() { - let device = Device::::new(); + let device = Device::new(T::regs()); let s = T::state(); if device.is_tx_ptr_updated() { @@ -405,8 +405,9 @@ impl interrupt::typelevel::Handler for InterruptHandl } /// I2S driver. -pub struct I2S<'d, T: Instance> { - i2s: Peri<'d, T>, +pub struct I2S<'d> { + r: pac::i2s::I2s, + state: &'static State, mck: Option>, sck: Peri<'d, AnyPin>, lrck: Peri<'d, AnyPin>, @@ -416,10 +417,10 @@ pub struct I2S<'d, T: Instance> { config: Config, } -impl<'d, T: Instance> I2S<'d, T> { +impl<'d> I2S<'d> { /// Create a new I2S in master mode - pub fn new_master( - i2s: Peri<'d, T>, + pub fn new_master( + _i2s: Peri<'d, T>, _irq: impl interrupt::typelevel::Binding> + 'd, mck: Peri<'d, impl GpioPin>, sck: Peri<'d, impl GpioPin>, @@ -427,8 +428,12 @@ impl<'d, T: Instance> I2S<'d, T> { master_clock: MasterClock, config: Config, ) -> Self { + T::Interrupt::unpend(); + unsafe { T::Interrupt::enable() }; + Self { - i2s, + r: T::regs(), + state: T::state(), mck: Some(mck.into()), sck: sck.into(), lrck: lrck.into(), @@ -440,15 +445,19 @@ impl<'d, T: Instance> I2S<'d, T> { } /// Create a new I2S in slave mode - pub fn new_slave( - i2s: Peri<'d, T>, + pub fn new_slave( + _i2s: Peri<'d, T>, _irq: impl interrupt::typelevel::Binding> + 'd, sck: Peri<'d, impl GpioPin>, lrck: Peri<'d, impl GpioPin>, config: Config, ) -> Self { + T::Interrupt::unpend(); + unsafe { T::Interrupt::enable() }; + Self { - i2s, + r: T::regs(), + state: T::state(), mck: None, sck: sck.into(), lrck: lrck.into(), @@ -464,10 +473,13 @@ impl<'d, T: Instance> I2S<'d, T> { mut self, sdout: Peri<'d, impl GpioPin>, buffers: MultiBuffering, - ) -> OutputStream<'d, T, S, NB, NS> { + ) -> OutputStream<'d, S, NB, NS> { self.sdout = Some(sdout.into()); + let p = self.build(); OutputStream { - _p: self.build(), + r: p.0, + state: p.1, + _phantom: PhantomData, buffers, } } @@ -477,11 +489,14 @@ impl<'d, T: Instance> I2S<'d, T> { mut self, sdin: Peri<'d, impl GpioPin>, buffers: MultiBuffering, - ) -> InputStream<'d, T, S, NB, NS> { + ) -> InputStream<'d, S, NB, NS> { self.sdin = Some(sdin.into()); + let p = self.build(); InputStream { - _p: self.build(), + r: p.0, + state: p.1, buffers, + _phantom: PhantomData, } } @@ -492,30 +507,33 @@ impl<'d, T: Instance> I2S<'d, T> { sdout: Peri<'d, impl GpioPin>, buffers_out: MultiBuffering, buffers_in: MultiBuffering, - ) -> FullDuplexStream<'d, T, S, NB, NS> { + ) -> FullDuplexStream<'d, S, NB, NS> { self.sdout = Some(sdout.into()); self.sdin = Some(sdin.into()); + let p = self.build(); FullDuplexStream { - _p: self.build(), + r: p.0, + state: p.1, + _phantom: PhantomData, buffers_out, buffers_in, } } - fn build(self) -> Peri<'d, T> { + fn build(self) -> (pac::i2s::I2s, &'static State) { self.apply_config(); self.select_pins(); self.setup_interrupt(); - let device = Device::::new(); + let device = Device::new(self.r); device.enable(); - self.i2s + (self.r, self.state) } fn apply_config(&self) { - let c = T::regs().config(); + let c = self.r.config(); match &self.master_clock { Some(MasterClock { freq, ratio }) => { c.mode().write(|w| w.set_mode(vals::Mode::MASTER)); @@ -535,7 +553,7 @@ impl<'d, T: Instance> I2S<'d, T> { } fn select_pins(&self) { - let psel = T::regs().psel(); + let psel = self.r.psel(); psel.mck().write_value(self.mck.psel_bits()); psel.sck().write_value(self.sck.psel_bits()); psel.lrck().write_value(self.lrck.psel_bits()); @@ -544,10 +562,9 @@ impl<'d, T: Instance> I2S<'d, T> { } fn setup_interrupt(&self) { - T::Interrupt::unpend(); - unsafe { T::Interrupt::enable() }; + // Interrupt is already set up in constructor - let device = Device::::new(); + let device = Device::new(self.r); device.disable_tx_ptr_interrupt(); device.disable_rx_ptr_interrupt(); device.disable_stopped_interrupt(); @@ -561,16 +578,16 @@ impl<'d, T: Instance> I2S<'d, T> { device.enable_stopped_interrupt(); } - async fn stop() { + async fn stop(r: pac::i2s::I2s, state: &State) { compiler_fence(Ordering::SeqCst); - let device = Device::::new(); + let device = Device::new(r); device.stop(); - T::state().started.store(false, Ordering::Relaxed); + state.started.store(false, Ordering::Relaxed); poll_fn(|cx| { - T::state().stop_waker.register(cx.waker()); + state.stop_waker.register(cx.waker()); if device.is_stopped() { trace!("STOP: Ready"); @@ -586,7 +603,7 @@ impl<'d, T: Instance> I2S<'d, T> { device.disable(); } - async fn send_from_ram(buffer_ptr: *const [S]) -> Result<(), Error> + async fn send_from_ram(r: pac::i2s::I2s, state: &State, buffer_ptr: *const [S]) -> Result<(), Error> where S: Sample, { @@ -596,22 +613,22 @@ impl<'d, T: Instance> I2S<'d, T> { compiler_fence(Ordering::SeqCst); - let device = Device::::new(); + let device = Device::new(r); device.update_tx(buffer_ptr)?; - Self::wait_tx_ptr_update().await; + Self::wait_tx_ptr_update(r, state).await; compiler_fence(Ordering::SeqCst); Ok(()) } - async fn wait_tx_ptr_update() { + async fn wait_tx_ptr_update(r: pac::i2s::I2s, state: &State) { let drop = OnDrop::new(move || { trace!("TX DROP: Stopping"); - let device = Device::::new(); + let device = Device::new(r); device.disable_tx_ptr_interrupt(); device.reset_tx_ptr_event(); device.disable_tx(); @@ -623,9 +640,9 @@ impl<'d, T: Instance> I2S<'d, T> { }); poll_fn(|cx| { - T::state().tx_waker.register(cx.waker()); + state.tx_waker.register(cx.waker()); - let device = Device::::new(); + let device = Device::new(r); if device.is_tx_ptr_updated() { trace!("TX POLL: Ready"); device.reset_tx_ptr_event(); @@ -641,7 +658,7 @@ impl<'d, T: Instance> I2S<'d, T> { drop.defuse(); } - async fn receive_from_ram(buffer_ptr: *mut [S]) -> Result<(), Error> + async fn receive_from_ram(r: pac::i2s::I2s, state: &State, buffer_ptr: *mut [S]) -> Result<(), Error> where S: Sample, { @@ -652,22 +669,22 @@ impl<'d, T: Instance> I2S<'d, T> { compiler_fence(Ordering::SeqCst); - let device = Device::::new(); + let device = Device::new(r); device.update_rx(buffer_ptr)?; - Self::wait_rx_ptr_update().await; + Self::wait_rx_ptr_update(r, state).await; compiler_fence(Ordering::SeqCst); Ok(()) } - async fn wait_rx_ptr_update() { + async fn wait_rx_ptr_update(r: pac::i2s::I2s, state: &State) { let drop = OnDrop::new(move || { trace!("RX DROP: Stopping"); - let device = Device::::new(); + let device = Device::new(r); device.disable_rx_ptr_interrupt(); device.reset_rx_ptr_event(); device.disable_rx(); @@ -679,9 +696,9 @@ impl<'d, T: Instance> I2S<'d, T> { }); poll_fn(|cx| { - T::state().rx_waker.register(cx.waker()); + state.rx_waker.register(cx.waker()); - let device = Device::::new(); + let device = Device::new(r); if device.is_rx_ptr_updated() { trace!("RX POLL: Ready"); device.reset_rx_ptr_event(); @@ -699,12 +716,14 @@ impl<'d, T: Instance> I2S<'d, T> { } /// I2S output -pub struct OutputStream<'d, T: Instance, S: Sample, const NB: usize, const NS: usize> { - _p: Peri<'d, T>, +pub struct OutputStream<'d, S: Sample, const NB: usize, const NS: usize> { + r: pac::i2s::I2s, + state: &'static State, buffers: MultiBuffering, + _phantom: PhantomData<&'d ()>, } -impl<'d, T: Instance, S: Sample, const NB: usize, const NS: usize> OutputStream<'d, T, S, NB, NS> { +impl<'d, S: Sample, const NB: usize, const NS: usize> OutputStream<'d, S, NB, NS> { /// Get a mutable reference to the current buffer. pub fn buffer(&mut self) -> &mut [S] { self.buffers.get_mut() @@ -715,10 +734,9 @@ impl<'d, T: Instance, S: Sample, const NB: usize, const NS: usize> OutputStream< where S: Sample, { - let device = Device::::new(); + let device = Device::new(self.r); - let s = T::state(); - if s.started.load(Ordering::Relaxed) { + if self.state.started.load(Ordering::Relaxed) { self.stop().await; } @@ -727,11 +745,11 @@ impl<'d, T: Instance, S: Sample, const NB: usize, const NS: usize> OutputStream< device.update_tx(self.buffers.switch())?; - s.started.store(true, Ordering::Relaxed); + self.state.started.store(true, Ordering::Relaxed); device.start(); - I2S::::wait_tx_ptr_update().await; + I2S::wait_tx_ptr_update(self.r, self.state).await; Ok(()) } @@ -739,7 +757,7 @@ impl<'d, T: Instance, S: Sample, const NB: usize, const NS: usize> OutputStream< /// Stops the I2S transfer and waits until it has stopped. #[inline(always)] pub async fn stop(&self) { - I2S::::stop().await + I2S::stop(self.r, self.state).await } /// Sends the current buffer for transmission in the DMA. @@ -748,17 +766,19 @@ impl<'d, T: Instance, S: Sample, const NB: usize, const NS: usize> OutputStream< where S: Sample, { - I2S::::send_from_ram(self.buffers.switch()).await + I2S::send_from_ram(self.r, self.state, self.buffers.switch()).await } } /// I2S input -pub struct InputStream<'d, T: Instance, S: Sample, const NB: usize, const NS: usize> { - _p: Peri<'d, T>, +pub struct InputStream<'d, S: Sample, const NB: usize, const NS: usize> { + r: pac::i2s::I2s, + state: &'static State, buffers: MultiBuffering, + _phantom: PhantomData<&'d ()>, } -impl<'d, T: Instance, S: Sample, const NB: usize, const NS: usize> InputStream<'d, T, S, NB, NS> { +impl<'d, S: Sample, const NB: usize, const NS: usize> InputStream<'d, S, NB, NS> { /// Get a mutable reference to the current buffer. pub fn buffer(&mut self) -> &mut [S] { self.buffers.get_mut() @@ -769,10 +789,9 @@ impl<'d, T: Instance, S: Sample, const NB: usize, const NS: usize> InputStream<' where S: Sample, { - let device = Device::::new(); + let device = Device::new(self.r); - let s = T::state(); - if s.started.load(Ordering::Relaxed) { + if self.state.started.load(Ordering::Relaxed) { self.stop().await; } @@ -781,11 +800,11 @@ impl<'d, T: Instance, S: Sample, const NB: usize, const NS: usize> InputStream<' device.update_rx(self.buffers.switch())?; - s.started.store(true, Ordering::Relaxed); + self.state.started.store(true, Ordering::Relaxed); device.start(); - I2S::::wait_rx_ptr_update().await; + I2S::wait_rx_ptr_update(self.r, self.state).await; Ok(()) } @@ -793,7 +812,7 @@ impl<'d, T: Instance, S: Sample, const NB: usize, const NS: usize> InputStream<' /// Stops the I2S transfer and waits until it has stopped. #[inline(always)] pub async fn stop(&self) { - I2S::::stop().await + I2S::stop(self.r, self.state).await } /// Sets the current buffer for reception from the DMA. @@ -803,18 +822,20 @@ impl<'d, T: Instance, S: Sample, const NB: usize, const NS: usize> InputStream<' where S: Sample, { - I2S::::receive_from_ram(self.buffers.switch_mut()).await + I2S::receive_from_ram(self.r, self.state, self.buffers.switch_mut()).await } } /// I2S full duplex stream (input & output) -pub struct FullDuplexStream<'d, T: Instance, S: Sample, const NB: usize, const NS: usize> { - _p: Peri<'d, T>, +pub struct FullDuplexStream<'d, S: Sample, const NB: usize, const NS: usize> { + r: pac::i2s::I2s, + state: &'static State, buffers_out: MultiBuffering, buffers_in: MultiBuffering, + _phantom: PhantomData<&'d ()>, } -impl<'d, T: Instance, S: Sample, const NB: usize, const NS: usize> FullDuplexStream<'d, T, S, NB, NS> { +impl<'d, S: Sample, const NB: usize, const NS: usize> FullDuplexStream<'d, S, NB, NS> { /// Get the current output and input buffers. pub fn buffers(&mut self) -> (&mut [S], &[S]) { (self.buffers_out.get_mut(), self.buffers_in.get()) @@ -825,10 +846,9 @@ impl<'d, T: Instance, S: Sample, const NB: usize, const NS: usize> FullDuplexStr where S: Sample, { - let device = Device::::new(); + let device = Device::new(self.r); - let s = T::state(); - if s.started.load(Ordering::Relaxed) { + if self.state.started.load(Ordering::Relaxed) { self.stop().await; } @@ -839,12 +859,12 @@ impl<'d, T: Instance, S: Sample, const NB: usize, const NS: usize> FullDuplexStr device.update_tx(self.buffers_out.switch())?; device.update_rx(self.buffers_in.switch_mut())?; - s.started.store(true, Ordering::Relaxed); + self.state.started.store(true, Ordering::Relaxed); device.start(); - I2S::::wait_tx_ptr_update().await; - I2S::::wait_rx_ptr_update().await; + I2S::wait_tx_ptr_update(self.r, self.state).await; + I2S::wait_rx_ptr_update(self.r, self.state).await; Ok(()) } @@ -852,7 +872,7 @@ impl<'d, T: Instance, S: Sample, const NB: usize, const NS: usize> FullDuplexStr /// Stops the I2S transfer and waits until it has stopped. #[inline(always)] pub async fn stop(&self) { - I2S::::stop().await + I2S::stop(self.r, self.state).await } /// Sets the current buffers for output and input for transmission/reception from the DMA. @@ -861,18 +881,18 @@ impl<'d, T: Instance, S: Sample, const NB: usize, const NS: usize> FullDuplexStr where S: Sample, { - I2S::::send_from_ram(self.buffers_out.switch()).await?; - I2S::::receive_from_ram(self.buffers_in.switch_mut()).await?; + I2S::send_from_ram(self.r, self.state, self.buffers_out.switch()).await?; + I2S::receive_from_ram(self.r, self.state, self.buffers_in.switch_mut()).await?; Ok(()) } } /// Helper encapsulating common I2S device operations. -struct Device(pac::i2s::I2s, PhantomData); +struct Device(pac::i2s::I2s); -impl Device { - fn new() -> Self { - Self(T::regs(), PhantomData) +impl Device { + fn new(r: pac::i2s::I2s) -> Self { + Self(r) } #[inline(always)] -- cgit From b2727640ed5ff514ca2bbaacc058bfa546767e4d Mon Sep 17 00:00:00 2001 From: Dario Nieuwenhuis Date: Sun, 28 Sep 2025 22:25:25 +0200 Subject: nrf/radio: erase instance generic --- embassy-nrf/src/embassy_net_802154_driver.rs | 8 ++-- embassy-nrf/src/radio/ieee802154.rs | 58 +++++++++++++++------------- examples/nrf52840/src/bin/sixlowpan.rs | 2 +- 3 files changed, 37 insertions(+), 31 deletions(-) diff --git a/embassy-nrf/src/embassy_net_802154_driver.rs b/embassy-nrf/src/embassy_net_802154_driver.rs index 8662be787..b3fc5df2c 100644 --- a/embassy-nrf/src/embassy_net_802154_driver.rs +++ b/embassy-nrf/src/embassy_net_802154_driver.rs @@ -32,12 +32,12 @@ impl State { /// Background runner for the driver. /// /// You must call `.run()` in a background task for the driver to operate. -pub struct Runner<'d, T: nrf::radio::Instance> { - radio: nrf::radio::ieee802154::Radio<'d, T>, +pub struct Runner<'d> { + radio: nrf::radio::ieee802154::Radio<'d>, ch: ch::Runner<'d, MTU>, } -impl<'d, T: nrf::radio::Instance> Runner<'d, T> { +impl<'d> Runner<'d> { /// Drives the radio. Needs to run to use the driver. pub async fn run(mut self) -> ! { let (state_chan, mut rx_chan, mut tx_chan) = self.ch.split(); @@ -84,7 +84,7 @@ pub async fn new<'a, const N_RX: usize, const N_TX: usize, T: nrf::radio::Instan radio: nrf::Peri<'a, T>, irq: Irq, state: &'a mut State, -) -> Result<(Device<'a>, Runner<'a, T>), ()> +) -> Result<(Device<'a>, Runner<'a>), ()> where Irq: interrupt::typelevel::Binding> + 'a, { diff --git a/embassy-nrf/src/radio/ieee802154.rs b/embassy-nrf/src/radio/ieee802154.rs index 7f4f8f462..62af03a5a 100644 --- a/embassy-nrf/src/radio/ieee802154.rs +++ b/embassy-nrf/src/radio/ieee802154.rs @@ -1,15 +1,17 @@ //! IEEE 802.15.4 radio driver +use core::marker::PhantomData; use core::sync::atomic::{compiler_fence, Ordering}; use core::task::Poll; use embassy_hal_internal::drop::OnDrop; -use super::{Error, Instance, InterruptHandler, TxPower}; +use super::{Error, InterruptHandler, TxPower}; use crate::interrupt::typelevel::Interrupt; use crate::interrupt::{self}; use crate::pac::radio::vals; pub use crate::pac::radio::vals::State as RadioState; +use crate::radio::Instance; use crate::Peri; /// Default (IEEE compliant) Start of Frame Delimiter @@ -32,18 +34,20 @@ pub enum Cca { } /// IEEE 802.15.4 radio driver. -pub struct Radio<'d, T: Instance> { - _p: Peri<'d, T>, +pub struct Radio<'d> { + r: crate::pac::radio::Radio, + state: &'static crate::radio::State, needs_enable: bool, + phantom: PhantomData<&'d ()>, } -impl<'d, T: Instance> Radio<'d, T> { +impl<'d> Radio<'d> { /// Create a new IEEE 802.15.4 radio driver. - pub fn new( - radio: Peri<'d, T>, + pub fn new( + _radio: Peri<'d, T>, _irq: impl interrupt::typelevel::Binding> + 'd, ) -> Self { - let r = T::regs(); + let r = crate::pac::RADIO; // Disable and enable to reset peripheral r.power().write(|w| w.set_power(false)); @@ -89,12 +93,14 @@ impl<'d, T: Instance> Radio<'d, T> { }); // Enable NVIC interrupt - T::Interrupt::unpend(); - unsafe { T::Interrupt::enable() }; + crate::interrupt::typelevel::RADIO::unpend(); + unsafe { crate::interrupt::typelevel::RADIO::enable() }; let mut radio = Self { - _p: radio, + r: crate::pac::RADIO, + state: T::state(), needs_enable: false, + phantom: PhantomData, }; radio.set_sfd(DEFAULT_SFD); @@ -107,7 +113,7 @@ impl<'d, T: Instance> Radio<'d, T> { /// Changes the radio channel pub fn set_channel(&mut self, channel: u8) { - let r = T::regs(); + let r = self.r; if channel < 11 || channel > 26 { panic!("Bad 802.15.4 channel"); } @@ -121,7 +127,7 @@ impl<'d, T: Instance> Radio<'d, T> { /// Changes the Clear Channel Assessment method pub fn set_cca(&mut self, cca: Cca) { - let r = T::regs(); + let r = self.r; self.needs_enable = true; match cca { Cca::CarrierSense => r.ccactrl().write(|w| w.set_ccamode(vals::Ccamode::CARRIER_MODE)), @@ -138,19 +144,19 @@ impl<'d, T: Instance> Radio<'d, T> { /// Changes the Start of Frame Delimiter (SFD) pub fn set_sfd(&mut self, sfd: u8) { - let r = T::regs(); + let r = self.r; r.sfd().write(|w| w.set_sfd(sfd)); } /// Clear interrupts pub fn clear_all_interrupts(&mut self) { - let r = T::regs(); + let r = self.r; r.intenclr().write(|w| w.0 = 0xffff_ffff); } /// Changes the radio transmission power pub fn set_transmission_power(&mut self, power: i8) { - let r = T::regs(); + let r = self.r; self.needs_enable = true; let tx_power: TxPower = match power { @@ -201,12 +207,12 @@ impl<'d, T: Instance> Radio<'d, T> { /// Get the current radio state fn state(&self) -> RadioState { - T::regs().state().read().state() + self.r.state().read().state() } /// Moves the radio from any state to the DISABLED state fn disable(&mut self) { - let r = T::regs(); + let r = self.r; // See figure 110 in nRF52840-PS loop { match self.state() { @@ -238,15 +244,15 @@ impl<'d, T: Instance> Radio<'d, T> { } fn set_buffer(&mut self, buffer: &[u8]) { - let r = T::regs(); + let r = self.r; r.packetptr().write_value(buffer.as_ptr() as u32); } /// Moves the radio to the RXIDLE state fn receive_prepare(&mut self) { // clear related events - T::regs().events_ccabusy().write_value(0); - T::regs().events_phyend().write_value(0); + self.r.events_ccabusy().write_value(0); + self.r.events_phyend().write_value(0); // NOTE to avoid errata 204 (see rev1 v1.4) we do TX_IDLE -> DISABLED -> RXIDLE let disable = match self.state() { RadioState::DISABLED => false, @@ -263,7 +269,7 @@ impl<'d, T: Instance> Radio<'d, T> { fn receive_start(&mut self, packet: &mut Packet) { // NOTE we do NOT check the address of `packet` because the mutable reference ensures it's // allocated in RAM - let r = T::regs(); + let r = self.r; self.receive_prepare(); @@ -290,7 +296,7 @@ impl<'d, T: Instance> Radio<'d, T> { /// Cancel receiving packet fn receive_cancel() { - let r = T::regs(); + let r = crate::pac::RADIO; r.shorts().write(|_| {}); r.tasks_stop().write_value(1); loop { @@ -309,8 +315,8 @@ impl<'d, T: Instance> Radio<'d, T> { /// validated by the hardware; otherwise it returns the `Err` variant. In either case, `packet` /// will be updated with the received packet's data pub async fn receive(&mut self, packet: &mut Packet) -> Result<(), Error> { - let s = T::state(); - let r = T::regs(); + let s = self.state; + let r = self.r; // Start the read self.receive_start(packet); @@ -356,8 +362,8 @@ impl<'d, T: Instance> Radio<'d, T> { // NOTE we do NOT check the address of `packet` because the mutable reference ensures it's // allocated in RAM pub async fn try_send(&mut self, packet: &mut Packet) -> Result<(), Error> { - let s = T::state(); - let r = T::regs(); + let s = self.state; + let r = self.r; // enable radio to perform cca self.receive_prepare(); diff --git a/examples/nrf52840/src/bin/sixlowpan.rs b/examples/nrf52840/src/bin/sixlowpan.rs index 00a597366..12e385e01 100644 --- a/examples/nrf52840/src/bin/sixlowpan.rs +++ b/examples/nrf52840/src/bin/sixlowpan.rs @@ -21,7 +21,7 @@ bind_interrupts!(struct Irqs { }); #[embassy_executor::task] -async fn ieee802154_task(runner: net::Runner<'static, peripherals::RADIO>) -> ! { +async fn ieee802154_task(runner: net::Runner<'static>) -> ! { runner.run().await } -- cgit From 864eaef3a3f7678bcc4ff20b5180b1ce50332fce Mon Sep 17 00:00:00 2001 From: Dario Nieuwenhuis Date: Sun, 28 Sep 2025 22:43:10 +0200 Subject: nrf/usb: erase instance generics --- embassy-nrf/CHANGELOG.md | 2 +- embassy-nrf/src/usb/mod.rs | 149 ++++++++++++---------- examples/nrf52840/src/bin/usb_ethernet.rs | 2 +- examples/nrf52840/src/bin/usb_serial.rs | 6 +- examples/nrf52840/src/bin/usb_serial_multitask.rs | 2 +- examples/nrf52840/src/bin/usb_serial_winusb.rs | 6 +- 6 files changed, 87 insertions(+), 80 deletions(-) diff --git a/embassy-nrf/CHANGELOG.md b/embassy-nrf/CHANGELOG.md index b8d03a1f8..21b299f36 100644 --- a/embassy-nrf/CHANGELOG.md +++ b/embassy-nrf/CHANGELOG.md @@ -8,7 +8,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## Unreleased - ReleaseDate -- changed: erase Instance type from Spim +- changed: Remove `T: Instance` generic params in all drivers. - changed: nrf54l: Disable glitch detection and enable DC/DC in init. - changed: Add embassy-net-driver-channel implementation for IEEE 802.15.4 - changed: add persist() method for gpio and ppi diff --git a/embassy-nrf/src/usb/mod.rs b/embassy-nrf/src/usb/mod.rs index c6970fc0f..2a32fe922 100644 --- a/embassy-nrf/src/usb/mod.rs +++ b/embassy-nrf/src/usb/mod.rs @@ -86,17 +86,18 @@ impl interrupt::typelevel::Handler for InterruptHandl } /// USB driver. -pub struct Driver<'d, T: Instance, V: VbusDetect> { - _p: Peri<'d, T>, +pub struct Driver<'d, V: VbusDetect> { + regs: pac::usbd::Usbd, alloc_in: Allocator, alloc_out: Allocator, vbus_detect: V, + _phantom: PhantomData<&'d ()>, } -impl<'d, T: Instance, V: VbusDetect> Driver<'d, T, V> { +impl<'d, V: VbusDetect> Driver<'d, V> { /// Create a new USB driver. - pub fn new( - usb: Peri<'d, T>, + pub fn new( + _usb: Peri<'d, T>, _irq: impl interrupt::typelevel::Binding> + 'd, vbus_detect: V, ) -> Self { @@ -104,19 +105,20 @@ impl<'d, T: Instance, V: VbusDetect> Driver<'d, T, V> { unsafe { T::Interrupt::enable() }; Self { - _p: usb, + regs: crate::pac::USBD, alloc_in: Allocator::new(), alloc_out: Allocator::new(), vbus_detect, + _phantom: PhantomData, } } } -impl<'d, T: Instance, V: VbusDetect + 'd> driver::Driver<'d> for Driver<'d, T, V> { - type EndpointOut = Endpoint<'d, T, Out>; - type EndpointIn = Endpoint<'d, T, In>; - type ControlPipe = ControlPipe<'d, T>; - type Bus = Bus<'d, T, V>; +impl<'d, V: VbusDetect + 'd> driver::Driver<'d> for Driver<'d, V> { + type EndpointOut = Endpoint<'d, Out>; + type EndpointIn = Endpoint<'d, In>; + type ControlPipe = ControlPipe<'d>; + type Bus = Bus<'d, V>; fn alloc_endpoint_in( &mut self, @@ -127,12 +129,15 @@ impl<'d, T: Instance, V: VbusDetect + 'd> driver::Driver<'d> for Driver<'d, T, V ) -> Result { let index = self.alloc_in.allocate(ep_type, ep_addr)?; let ep_addr = EndpointAddress::from_parts(index, Direction::In); - Ok(Endpoint::new(EndpointInfo { - addr: ep_addr, - ep_type, - max_packet_size: packet_size, - interval_ms, - })) + Ok(Endpoint::new( + self.regs, + EndpointInfo { + addr: ep_addr, + ep_type, + max_packet_size: packet_size, + interval_ms, + }, + )) } fn alloc_endpoint_out( @@ -144,39 +149,45 @@ impl<'d, T: Instance, V: VbusDetect + 'd> driver::Driver<'d> for Driver<'d, T, V ) -> Result { let index = self.alloc_out.allocate(ep_type, ep_addr)?; let ep_addr = EndpointAddress::from_parts(index, Direction::Out); - Ok(Endpoint::new(EndpointInfo { - addr: ep_addr, - ep_type, - max_packet_size: packet_size, - interval_ms, - })) + Ok(Endpoint::new( + self.regs, + EndpointInfo { + addr: ep_addr, + ep_type, + max_packet_size: packet_size, + interval_ms, + }, + )) } fn start(self, control_max_packet_size: u16) -> (Self::Bus, Self::ControlPipe) { ( Bus { - _p: unsafe { self._p.clone_unchecked() }, + regs: self.regs, power_available: false, vbus_detect: self.vbus_detect, + _phantom: PhantomData, }, ControlPipe { - _p: self._p, + regs: self.regs, max_packet_size: control_max_packet_size, + _phantom: PhantomData, }, ) } } /// USB bus. -pub struct Bus<'d, T: Instance, V: VbusDetect> { - _p: Peri<'d, T>, +pub struct Bus<'d, V: VbusDetect> { + regs: pac::usbd::Usbd, power_available: bool, vbus_detect: V, + _phantom: PhantomData<&'d ()>, } -impl<'d, T: Instance, V: VbusDetect> driver::Bus for Bus<'d, T, V> { +impl<'d, V: VbusDetect> driver::Bus for Bus<'d, V> { async fn enable(&mut self) { - let regs = T::regs(); + let regs = self.regs; errata::pre_enable(); @@ -215,14 +226,14 @@ impl<'d, T: Instance, V: VbusDetect> driver::Bus for Bus<'d, T, V> { } async fn disable(&mut self) { - let regs = T::regs(); + let regs = self.regs; regs.enable().write(|x| x.set_enable(false)); } fn poll(&mut self) -> impl Future { poll_fn(|cx| { BUS_WAKER.register(cx.waker()); - let regs = T::regs(); + let regs = self.regs; if regs.events_usbreset().read() != 0 { regs.events_usbreset().write_value(0); @@ -280,7 +291,7 @@ impl<'d, T: Instance, V: VbusDetect> driver::Bus for Bus<'d, T, V> { } fn endpoint_set_stalled(&mut self, ep_addr: EndpointAddress, stalled: bool) { - let regs = T::regs(); + let regs = self.regs; if ep_addr.index() == 0 { if stalled { regs.tasks_ep0stall().write_value(1); @@ -298,7 +309,7 @@ impl<'d, T: Instance, V: VbusDetect> driver::Bus for Bus<'d, T, V> { } fn endpoint_is_stalled(&mut self, ep_addr: EndpointAddress) -> bool { - let regs = T::regs(); + let regs = self.regs; let i = ep_addr.index(); match ep_addr.direction() { Direction::Out => regs.halted().epout(i).read().getstatus() == vals::Getstatus::HALTED, @@ -307,7 +318,7 @@ impl<'d, T: Instance, V: VbusDetect> driver::Bus for Bus<'d, T, V> { } fn endpoint_set_enabled(&mut self, ep_addr: EndpointAddress, enabled: bool) { - let regs = T::regs(); + let regs = self.regs; let i = ep_addr.index(); let mask = 1 << i; @@ -359,7 +370,7 @@ impl<'d, T: Instance, V: VbusDetect> driver::Bus for Bus<'d, T, V> { #[inline] async fn remote_wakeup(&mut self) -> Result<(), Unsupported> { - let regs = T::regs(); + let regs = self.regs; if regs.lowpower().read().lowpower() == vals::Lowpower::LOW_POWER { errata::pre_wakeup(); @@ -368,7 +379,7 @@ impl<'d, T: Instance, V: VbusDetect> driver::Bus for Bus<'d, T, V> { poll_fn(|cx| { BUS_WAKER.register(cx.waker()); - let regs = T::regs(); + let regs = self.regs; let r = regs.eventcause().read(); if regs.events_usbreset().read() != 0 { @@ -441,21 +452,23 @@ impl EndpointDir for Out { } /// USB endpoint. -pub struct Endpoint<'d, T: Instance, Dir> { - _phantom: PhantomData<(&'d mut T, Dir)>, +pub struct Endpoint<'d, Dir> { + regs: pac::usbd::Usbd, info: EndpointInfo, + _phantom: PhantomData<(&'d (), Dir)>, } -impl<'d, T: Instance, Dir> Endpoint<'d, T, Dir> { - fn new(info: EndpointInfo) -> Self { +impl<'d, Dir> Endpoint<'d, Dir> { + fn new(regs: pac::usbd::Usbd, info: EndpointInfo) -> Self { Self { + regs, info, _phantom: PhantomData, } } } -impl<'d, T: Instance, Dir: EndpointDir> driver::Endpoint for Endpoint<'d, T, Dir> { +impl<'d, Dir: EndpointDir> driver::Endpoint for Endpoint<'d, Dir> { fn info(&self) -> &EndpointInfo { &self.info } @@ -466,14 +479,14 @@ impl<'d, T: Instance, Dir: EndpointDir> driver::Endpoint for Endpoint<'d, T, Dir } #[allow(private_bounds)] -impl<'d, T: Instance, Dir: EndpointDir> Endpoint<'d, T, Dir> { - fn wait_enabled_state(&mut self, state: bool) -> impl Future { +impl<'d, Dir: EndpointDir> Endpoint<'d, Dir> { + fn wait_enabled_state(&mut self, state: bool) -> impl Future + use<'_, 'd, Dir> { let i = self.info.addr.index(); assert!(i != 0); poll_fn(move |cx| { Dir::waker(i).register(cx.waker()); - if Dir::is_enabled(T::regs(), i) == state { + if Dir::is_enabled(self.regs, i) == state { Poll::Ready(()) } else { Poll::Pending @@ -482,12 +495,12 @@ impl<'d, T: Instance, Dir: EndpointDir> Endpoint<'d, T, Dir> { } /// Wait for the endpoint to be disabled - pub fn wait_disabled(&mut self) -> impl Future { + pub fn wait_disabled(&mut self) -> impl Future + use<'_, 'd, Dir> { self.wait_enabled_state(false) } } -impl<'d, T: Instance, Dir> Endpoint<'d, T, Dir> { +impl<'d, Dir> Endpoint<'d, Dir> { async fn wait_data_ready(&mut self) -> Result<(), ()> where Dir: EndpointDir, @@ -497,7 +510,7 @@ impl<'d, T: Instance, Dir> Endpoint<'d, T, Dir> { poll_fn(|cx| { Dir::waker(i).register(cx.waker()); let r = READY_ENDPOINTS.load(Ordering::Acquire); - if !Dir::is_enabled(T::regs(), i) { + if !Dir::is_enabled(self.regs, i) { Poll::Ready(Err(())) } else if r & Dir::mask(i) != 0 { Poll::Ready(Ok(())) @@ -514,9 +527,7 @@ impl<'d, T: Instance, Dir> Endpoint<'d, T, Dir> { } } -unsafe fn read_dma(i: usize, buf: &mut [u8]) -> Result { - let regs = T::regs(); - +unsafe fn read_dma(regs: pac::usbd::Usbd, i: usize, buf: &mut [u8]) -> Result { // Check that the packet fits into the buffer let size = regs.size().epout(i).read().0 as usize; if size > buf.len() { @@ -539,8 +550,7 @@ unsafe fn read_dma(i: usize, buf: &mut [u8]) -> Result(i: usize, buf: &[u8]) { - let regs = T::regs(); +unsafe fn write_dma(regs: pac::usbd::Usbd, i: usize, buf: &[u8]) { assert!(buf.len() <= 64); let mut ram_buf: MaybeUninit<[u8; 64]> = MaybeUninit::uninit(); @@ -566,43 +576,44 @@ unsafe fn write_dma(i: usize, buf: &[u8]) { dma_end(); } -impl<'d, T: Instance> driver::EndpointOut for Endpoint<'d, T, Out> { +impl<'d> driver::EndpointOut for Endpoint<'d, Out> { async fn read(&mut self, buf: &mut [u8]) -> Result { let i = self.info.addr.index(); assert!(i != 0); self.wait_data_ready().await.map_err(|_| EndpointError::Disabled)?; - unsafe { read_dma::(i, buf) } + unsafe { read_dma(self.regs, i, buf) } } } -impl<'d, T: Instance> driver::EndpointIn for Endpoint<'d, T, In> { +impl<'d> driver::EndpointIn for Endpoint<'d, In> { async fn write(&mut self, buf: &[u8]) -> Result<(), EndpointError> { let i = self.info.addr.index(); assert!(i != 0); self.wait_data_ready().await.map_err(|_| EndpointError::Disabled)?; - unsafe { write_dma::(i, buf) } + unsafe { write_dma(self.regs, i, buf) } Ok(()) } } /// USB control pipe. -pub struct ControlPipe<'d, T: Instance> { - _p: Peri<'d, T>, +pub struct ControlPipe<'d> { + regs: pac::usbd::Usbd, max_packet_size: u16, + _phantom: PhantomData<&'d ()>, } -impl<'d, T: Instance> driver::ControlPipe for ControlPipe<'d, T> { +impl<'d> driver::ControlPipe for ControlPipe<'d> { fn max_packet_size(&self) -> usize { usize::from(self.max_packet_size) } async fn setup(&mut self) -> [u8; 8] { - let regs = T::regs(); + let regs = self.regs; // Reset shorts regs.shorts().write(|_| ()); @@ -611,7 +622,7 @@ impl<'d, T: Instance> driver::ControlPipe for ControlPipe<'d, T> { regs.intenset().write(|w| w.set_ep0setup(true)); poll_fn(|cx| { EP0_WAKER.register(cx.waker()); - let regs = T::regs(); + let regs = self.regs; if regs.events_ep0setup().read() != 0 { Poll::Ready(()) } else { @@ -636,7 +647,7 @@ impl<'d, T: Instance> driver::ControlPipe for ControlPipe<'d, T> { } async fn data_out(&mut self, buf: &mut [u8], _first: bool, _last: bool) -> Result { - let regs = T::regs(); + let regs = self.regs; regs.events_ep0datadone().write_value(0); @@ -651,7 +662,7 @@ impl<'d, T: Instance> driver::ControlPipe for ControlPipe<'d, T> { }); poll_fn(|cx| { EP0_WAKER.register(cx.waker()); - let regs = T::regs(); + let regs = self.regs; if regs.events_ep0datadone().read() != 0 { Poll::Ready(Ok(())) } else if regs.events_usbreset().read() != 0 { @@ -666,17 +677,17 @@ impl<'d, T: Instance> driver::ControlPipe for ControlPipe<'d, T> { }) .await?; - unsafe { read_dma::(0, buf) } + unsafe { read_dma(self.regs, 0, buf) } } async fn data_in(&mut self, buf: &[u8], _first: bool, last: bool) -> Result<(), EndpointError> { - let regs = T::regs(); + let regs = self.regs; regs.events_ep0datadone().write_value(0); regs.shorts().write(|w| w.set_ep0datadone_ep0status(last)); // This starts a TX on EP0. events_ep0datadone notifies when done. - unsafe { write_dma::(0, buf) } + unsafe { write_dma(self.regs, 0, buf) } regs.intenset().write(|w| { w.set_usbreset(true); @@ -687,7 +698,7 @@ impl<'d, T: Instance> driver::ControlPipe for ControlPipe<'d, T> { poll_fn(|cx| { cx.waker().wake_by_ref(); EP0_WAKER.register(cx.waker()); - let regs = T::regs(); + let regs = self.regs; if regs.events_ep0datadone().read() != 0 { Poll::Ready(Ok(())) } else if regs.events_usbreset().read() != 0 { @@ -704,12 +715,12 @@ impl<'d, T: Instance> driver::ControlPipe for ControlPipe<'d, T> { } async fn accept(&mut self) { - let regs = T::regs(); + let regs = self.regs; regs.tasks_ep0status().write_value(1); } async fn reject(&mut self) { - let regs = T::regs(); + let regs = self.regs; regs.tasks_ep0stall().write_value(1); } diff --git a/examples/nrf52840/src/bin/usb_ethernet.rs b/examples/nrf52840/src/bin/usb_ethernet.rs index 87aa4c6c5..a75b967b4 100644 --- a/examples/nrf52840/src/bin/usb_ethernet.rs +++ b/examples/nrf52840/src/bin/usb_ethernet.rs @@ -22,7 +22,7 @@ bind_interrupts!(struct Irqs { RNG => rng::InterruptHandler; }); -type MyDriver = Driver<'static, peripherals::USBD, HardwareVbusDetect>; +type MyDriver = Driver<'static, HardwareVbusDetect>; const MTU: usize = 1514; diff --git a/examples/nrf52840/src/bin/usb_serial.rs b/examples/nrf52840/src/bin/usb_serial.rs index 8d05df791..e7c2d0854 100644 --- a/examples/nrf52840/src/bin/usb_serial.rs +++ b/examples/nrf52840/src/bin/usb_serial.rs @@ -5,7 +5,7 @@ use defmt::{info, panic}; use embassy_executor::Spawner; use embassy_futures::join::join; use embassy_nrf::usb::vbus_detect::{HardwareVbusDetect, VbusDetect}; -use embassy_nrf::usb::{Driver, Instance}; +use embassy_nrf::usb::Driver; use embassy_nrf::{bind_interrupts, pac, peripherals, usb}; use embassy_usb::class::cdc_acm::{CdcAcmClass, State}; use embassy_usb::driver::EndpointError; @@ -89,9 +89,7 @@ impl From for Disconnected { } } -async fn echo<'d, T: Instance + 'd, P: VbusDetect + 'd>( - class: &mut CdcAcmClass<'d, Driver<'d, T, P>>, -) -> Result<(), Disconnected> { +async fn echo<'d, V: VbusDetect + 'd>(class: &mut CdcAcmClass<'d, Driver<'d, V>>) -> Result<(), Disconnected> { let mut buf = [0; 64]; loop { let n = class.read_packet(&mut buf).await?; diff --git a/examples/nrf52840/src/bin/usb_serial_multitask.rs b/examples/nrf52840/src/bin/usb_serial_multitask.rs index 00a91a233..b6a983854 100644 --- a/examples/nrf52840/src/bin/usb_serial_multitask.rs +++ b/examples/nrf52840/src/bin/usb_serial_multitask.rs @@ -17,7 +17,7 @@ bind_interrupts!(struct Irqs { CLOCK_POWER => usb::vbus_detect::InterruptHandler; }); -type MyDriver = Driver<'static, peripherals::USBD, HardwareVbusDetect>; +type MyDriver = Driver<'static, HardwareVbusDetect>; #[embassy_executor::task] async fn usb_task(mut device: UsbDevice<'static, MyDriver>) { diff --git a/examples/nrf52840/src/bin/usb_serial_winusb.rs b/examples/nrf52840/src/bin/usb_serial_winusb.rs index 8a20ce673..e30e08a01 100644 --- a/examples/nrf52840/src/bin/usb_serial_winusb.rs +++ b/examples/nrf52840/src/bin/usb_serial_winusb.rs @@ -5,7 +5,7 @@ use defmt::{info, panic}; use embassy_executor::Spawner; use embassy_futures::join::join; use embassy_nrf::usb::vbus_detect::{HardwareVbusDetect, VbusDetect}; -use embassy_nrf::usb::{Driver, Instance}; +use embassy_nrf::usb::Driver; use embassy_nrf::{bind_interrupts, pac, peripherals, usb}; use embassy_usb::class::cdc_acm::{CdcAcmClass, State}; use embassy_usb::driver::EndpointError; @@ -108,9 +108,7 @@ impl From for Disconnected { } } -async fn echo<'d, T: Instance + 'd, P: VbusDetect + 'd>( - class: &mut CdcAcmClass<'d, Driver<'d, T, P>>, -) -> Result<(), Disconnected> { +async fn echo<'d, V: VbusDetect + 'd>(class: &mut CdcAcmClass<'d, Driver<'d, V>>) -> Result<(), Disconnected> { let mut buf = [0; 64]; loop { let n = class.read_packet(&mut buf).await?; -- cgit From 1fe05cfedbcfb35dba3bee3ed6b7f4f293e9bb78 Mon Sep 17 00:00:00 2001 From: Brian Schwind Date: Mon, 29 Sep 2025 21:11:09 +0900 Subject: Make the Qei struct own the channel 1 and 2 pins --- embassy-stm32/src/timer/qei.rs | 25 ++++++++++++++++++------- tests/stm32/src/bin/afio.rs | 4 ++-- 2 files changed, 20 insertions(+), 9 deletions(-) diff --git a/embassy-stm32/src/timer/qei.rs b/embassy-stm32/src/timer/qei.rs index 82b5968b0..d63a2b45d 100644 --- a/embassy-stm32/src/timer/qei.rs +++ b/embassy-stm32/src/timer/qei.rs @@ -55,20 +55,27 @@ impl SealedQeiChannel for Ch2 {} /// Quadrature decoder driver. pub struct Qei<'d, T: GeneralInstance4Channel> { inner: Timer<'d, T>, + _ch1: Peri<'d, AnyPin>, + _ch2: Peri<'d, AnyPin>, } impl<'d, T: GeneralInstance4Channel> Qei<'d, T> { /// Create a new quadrature decoder driver. #[allow(unused)] - pub fn new<#[cfg(afio)] A>( + pub fn new( tim: Peri<'d, T>, - ch1: if_afio!(QeiPin<'d, T, Ch1, A>), - ch2: if_afio!(QeiPin<'d, T, Ch2, A>), + ch1: Peri<'d, if_afio!(impl TimerPin)>, + ch2: Peri<'d, if_afio!(impl TimerPin)>, ) -> Self { - Self::new_inner(tim) - } + // Configure the pins to be used for the QEI peripheral. + critical_section::with(|_| { + ch1.set_low(); + set_as_af!(ch1, AfType::input(Pull::None)); + + ch2.set_low(); + set_as_af!(ch2, AfType::input(Pull::None)); + }); - fn new_inner(tim: Peri<'d, T>) -> Self { let inner = Timer::new(tim); let r = inner.regs_gp16(); @@ -94,7 +101,11 @@ impl<'d, T: GeneralInstance4Channel> Qei<'d, T> { r.arr().modify(|w| w.set_arr(u16::MAX)); r.cr1().modify(|w| w.set_cen(true)); - Self { inner } + Self { + inner, + _ch1: ch1.into(), + _ch2: ch2.into(), + } } /// Get direction. diff --git a/tests/stm32/src/bin/afio.rs b/tests/stm32/src/bin/afio.rs index cc44dc59c..356c39443 100644 --- a/tests/stm32/src/bin/afio.rs +++ b/tests/stm32/src/bin/afio.rs @@ -260,8 +260,8 @@ async fn main(_spawner: Spawner) { reset_afio_registers(); Qei::new::>( p.TIM1.reborrow(), - QeiPin::new(p.PA8.reborrow()), - QeiPin::new(p.PA9.reborrow()), + p.PA8.reborrow(), + p.PA9.reborrow(), ); defmt::assert_eq!(AFIO.mapr().read().tim1_remap(), 1); } -- cgit From a791e9f1fc17eda2b05df97a72b94264ee6a4c12 Mon Sep 17 00:00:00 2001 From: Brian Schwind Date: Mon, 29 Sep 2025 21:17:15 +0900 Subject: Remove the QeiPin struct --- embassy-stm32/src/timer/qei.rs | 23 ----------------------- 1 file changed, 23 deletions(-) diff --git a/embassy-stm32/src/timer/qei.rs b/embassy-stm32/src/timer/qei.rs index d63a2b45d..25e8c3705 100644 --- a/embassy-stm32/src/timer/qei.rs +++ b/embassy-stm32/src/timer/qei.rs @@ -1,7 +1,5 @@ //! Quadrature decoder using a timer. -use core::marker::PhantomData; - use stm32_metapac::timer::vals; use super::low_level::Timer; @@ -19,27 +17,6 @@ pub enum Direction { Downcounting, } -/// Wrapper for using a pin with QEI. -pub struct QeiPin<'d, T, Channel, #[cfg(afio)] A> { - #[allow(unused)] - pin: Peri<'d, AnyPin>, - phantom: PhantomData, -} - -impl<'d, T: GeneralInstance4Channel, C: QeiChannel, #[cfg(afio)] A> if_afio!(QeiPin<'d, T, C, A>) { - /// Create a new QEI pin instance. - pub fn new(pin: Peri<'d, if_afio!(impl TimerPin)>) -> Self { - critical_section::with(|_| { - pin.set_low(); - set_as_af!(pin, AfType::input(Pull::None)); - }); - QeiPin { - pin: pin.into(), - phantom: PhantomData, - } - } -} - trait SealedQeiChannel: TimerChannel {} /// Marker trait for a timer channel eligible for use with QEI. -- cgit From b8f78c4f7c1f13beb4af8ef50f992f62c0ab53f6 Mon Sep 17 00:00:00 2001 From: Ulf Lilleengen Date: Mon, 29 Sep 2025 14:53:24 +0200 Subject: fix: remove instance generic for multiwrite implementation --- embassy-nrf/Cargo.toml | 1 + embassy-nrf/src/qspi.rs | 4 ++-- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/embassy-nrf/Cargo.toml b/embassy-nrf/Cargo.toml index 1af633500..e2580a36e 100644 --- a/embassy-nrf/Cargo.toml +++ b/embassy-nrf/Cargo.toml @@ -34,6 +34,7 @@ build = [ {target = "thumbv7em-none-eabi", features = ["defmt", "gpiote", "nrf52840", "time"]}, {target = "thumbv7em-none-eabi", features = ["defmt", "gpiote", "nrf52840", "time-driver-rtc1"]}, {target = "thumbv7em-none-eabi", features = ["defmt", "gpiote", "nrf52840", "time", "time-driver-rtc1"]}, + {target = "thumbv7em-none-eabi", features = ["defmt", "gpiote", "nrf52840", "time", "time-driver-rtc1","qspi-multiwrite-flash"]}, {target = "thumbv6m-none-eabi", features = ["defmt", "nrf51", "time", "time-driver-rtc1"]}, {target = "thumbv6m-none-eabi", features = ["defmt", "nrf51", "time"]}, {target = "thumbv6m-none-eabi", features = ["nrf51", "time"]}, diff --git a/embassy-nrf/src/qspi.rs b/embassy-nrf/src/qspi.rs index 94ad3f0d6..6f4524716 100755 --- a/embassy-nrf/src/qspi.rs +++ b/embassy-nrf/src/qspi.rs @@ -599,7 +599,7 @@ impl<'d> NorFlash for Qspi<'d> { } #[cfg(feature = "qspi-multiwrite-flash")] -impl<'d, T: Instance> embedded_storage::nor_flash::MultiwriteNorFlash for Qspi<'d, T> {} +impl<'d> embedded_storage::nor_flash::MultiwriteNorFlash for Qspi<'d> {} mod _eh1 { use embedded_storage_async::nor_flash::{NorFlash as AsyncNorFlash, ReadNorFlash as AsyncReadNorFlash}; @@ -634,7 +634,7 @@ mod _eh1 { } #[cfg(feature = "qspi-multiwrite-flash")] - impl<'d, T: Instance> embedded_storage_async::nor_flash::MultiwriteNorFlash for Qspi<'d, T> {} + impl<'d> embedded_storage_async::nor_flash::MultiwriteNorFlash for Qspi<'d> {} } /// Peripheral static state -- cgit From 165fa1debd7f8aa6131c467825477a25e1862539 Mon Sep 17 00:00:00 2001 From: Brian Schwind Date: Mon, 29 Sep 2025 22:05:27 +0900 Subject: Add a Config struct for the Qei peripheral --- embassy-stm32/src/timer/qei.rs | 65 ++++++++++++++++++++++++++++++++++++++---- 1 file changed, 60 insertions(+), 5 deletions(-) diff --git a/embassy-stm32/src/timer/qei.rs b/embassy-stm32/src/timer/qei.rs index 25e8c3705..2e438bc74 100644 --- a/embassy-stm32/src/timer/qei.rs +++ b/embassy-stm32/src/timer/qei.rs @@ -1,6 +1,6 @@ //! Quadrature decoder using a timer. -use stm32_metapac::timer::vals; +use stm32_metapac::timer::vals::{self, Sms}; use super::low_level::Timer; pub use super::{Ch1, Ch2}; @@ -9,6 +9,51 @@ use crate::gpio::{AfType, AnyPin, Pull}; use crate::timer::TimerChannel; use crate::Peri; +/// Qei driver config. +#[cfg_attr(feature = "defmt", derive(defmt::Format))] +#[derive(Clone, Copy)] +pub struct Config { + /// Configures the internal pull up/down resistor for Qei's channel 1 pin. + pub ch1_pull: Pull, + /// Configures the internal pull up/down resistor for Qei's channel 2 pin. + pub ch2_pull: Pull, + /// Specifies the encoder mode to use for the Qei peripheral. + pub mode: QeiMode, +} + +impl Default for Config { + /// Arbitrary defaults to preserve backwards compatibility + fn default() -> Self { + Self { + ch1_pull: Pull::None, + ch2_pull: Pull::None, + mode: QeiMode::Mode3, + } + } +} + +/// See STMicro AN4013 for §2.3 for more information +#[cfg_attr(feature = "defmt", derive(defmt::Format))] +#[derive(Clone, Copy)] +pub enum QeiMode { + /// Direct alias for [`Sms::ENCODER_MODE_1`] + Mode1, + /// Direct alias for [`Sms::ENCODER_MODE_2`] + Mode2, + /// Direct alias for [`Sms::ENCODER_MODE_3`] + Mode3, +} + +impl From for Sms { + fn from(mode: QeiMode) -> Self { + match mode { + QeiMode::Mode1 => Sms::ENCODER_MODE_1, + QeiMode::Mode2 => Sms::ENCODER_MODE_2, + QeiMode::Mode3 => Sms::ENCODER_MODE_3, + } + } +} + /// Counting direction pub enum Direction { /// Counting up. @@ -37,20 +82,30 @@ pub struct Qei<'d, T: GeneralInstance4Channel> { } impl<'d, T: GeneralInstance4Channel> Qei<'d, T> { - /// Create a new quadrature decoder driver. + /// Create a new quadrature decoder driver, with a given [`Config`]. #[allow(unused)] pub fn new( tim: Peri<'d, T>, ch1: Peri<'d, if_afio!(impl TimerPin)>, ch2: Peri<'d, if_afio!(impl TimerPin)>, + ) -> Self { + Self::new_with_config(tim, ch1, ch2, Default::default()) + } + /// Create a new quadrature decoder driver, with a given [`Config`]. + #[allow(unused)] + pub fn new_with_config( + tim: Peri<'d, T>, + ch1: Peri<'d, if_afio!(impl TimerPin)>, + ch2: Peri<'d, if_afio!(impl TimerPin)>, + config: Config, ) -> Self { // Configure the pins to be used for the QEI peripheral. critical_section::with(|_| { ch1.set_low(); - set_as_af!(ch1, AfType::input(Pull::None)); + set_as_af!(ch1, AfType::input(config.ch1_pull)); ch2.set_low(); - set_as_af!(ch2, AfType::input(Pull::None)); + set_as_af!(ch2, AfType::input(config.ch2_pull)); }); let inner = Timer::new(tim); @@ -72,7 +127,7 @@ impl<'d, T: GeneralInstance4Channel> Qei<'d, T> { }); r.smcr().modify(|w| { - w.set_sms(vals::Sms::ENCODER_MODE_3); + w.set_sms(config.mode.into()); }); r.arr().modify(|w| w.set_arr(u16::MAX)); -- cgit From fc34aa360a28a293211f037204317f9090b876e7 Mon Sep 17 00:00:00 2001 From: Brian Schwind Date: Mon, 29 Sep 2025 22:16:29 +0900 Subject: Update embassy-stm32/CHANGELOG.md --- embassy-stm32/CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/embassy-stm32/CHANGELOG.md b/embassy-stm32/CHANGELOG.md index 835d9c704..80261ae41 100644 --- a/embassy-stm32/CHANGELOG.md +++ b/embassy-stm32/CHANGELOG.md @@ -25,6 +25,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - feat: Add USB CRS sync support for STM32C071 - fix: RTC register definition for STM32L4P5 and L4Q5 as they use v3 register map. - fix: Cut down the capabilities of the STM32L412 and L422 RTC as those are missing binary timer mode and underflow interrupt. +- fix: Allow configuration of the internal pull up/down resistors on the pins for the Qei peripheral, as well as the Qei decoder mode. ## 0.4.0 - 2025-08-26 -- cgit From 6bb08523c9d93fbddc9fac41b3d33c7c4bf91520 Mon Sep 17 00:00:00 2001 From: Brian Schwind Date: Mon, 29 Sep 2025 22:22:56 +0900 Subject: Code formatting --- tests/stm32/src/bin/afio.rs | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/tests/stm32/src/bin/afio.rs b/tests/stm32/src/bin/afio.rs index 356c39443..feddbc802 100644 --- a/tests/stm32/src/bin/afio.rs +++ b/tests/stm32/src/bin/afio.rs @@ -258,11 +258,7 @@ async fn main(_spawner: Spawner) { { // partial remap reset_afio_registers(); - Qei::new::>( - p.TIM1.reborrow(), - p.PA8.reborrow(), - p.PA9.reborrow(), - ); + Qei::new::>(p.TIM1.reborrow(), p.PA8.reborrow(), p.PA9.reborrow()); defmt::assert_eq!(AFIO.mapr().read().tim1_remap(), 1); } -- cgit From 61bc254879b328a944a36a81080abbadc6431ccf Mon Sep 17 00:00:00 2001 From: Brian Schwind Date: Mon, 29 Sep 2025 22:24:19 +0900 Subject: Remove 'new_with_config()', just use 'new()' --- embassy-stm32/src/timer/qei.rs | 9 --------- 1 file changed, 9 deletions(-) diff --git a/embassy-stm32/src/timer/qei.rs b/embassy-stm32/src/timer/qei.rs index 2e438bc74..bb152731c 100644 --- a/embassy-stm32/src/timer/qei.rs +++ b/embassy-stm32/src/timer/qei.rs @@ -88,15 +88,6 @@ impl<'d, T: GeneralInstance4Channel> Qei<'d, T> { tim: Peri<'d, T>, ch1: Peri<'d, if_afio!(impl TimerPin)>, ch2: Peri<'d, if_afio!(impl TimerPin)>, - ) -> Self { - Self::new_with_config(tim, ch1, ch2, Default::default()) - } - /// Create a new quadrature decoder driver, with a given [`Config`]. - #[allow(unused)] - pub fn new_with_config( - tim: Peri<'d, T>, - ch1: Peri<'d, if_afio!(impl TimerPin)>, - ch2: Peri<'d, if_afio!(impl TimerPin)>, config: Config, ) -> Self { // Configure the pins to be used for the QEI peripheral. -- cgit From 2cd2894d33e69c8481c360026015397f0742876a Mon Sep 17 00:00:00 2001 From: Brian Schwind Date: Mon, 29 Sep 2025 22:42:59 +0900 Subject: Fix an afio test --- tests/stm32/src/bin/afio.rs | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/tests/stm32/src/bin/afio.rs b/tests/stm32/src/bin/afio.rs index feddbc802..81d50874b 100644 --- a/tests/stm32/src/bin/afio.rs +++ b/tests/stm32/src/bin/afio.rs @@ -12,8 +12,9 @@ use embassy_stm32::time::khz; use embassy_stm32::timer::complementary_pwm::{ComplementaryPwm, ComplementaryPwmPin}; use embassy_stm32::timer::input_capture::{CapturePin, InputCapture}; use embassy_stm32::timer::pwm_input::PwmInput; -use embassy_stm32::timer::qei::{Qei, QeiPin}; +use embassy_stm32::timer::qei::Qei; use embassy_stm32::timer::simple_pwm::{PwmPin, SimplePwm}; +use embassy_stm32::timer::{Ch1, Ch2}; use embassy_stm32::usart::{Uart, UartRx, UartTx}; use embassy_stm32::{bind_interrupts, Peripherals}; @@ -258,7 +259,12 @@ async fn main(_spawner: Spawner) { { // partial remap reset_afio_registers(); - Qei::new::>(p.TIM1.reborrow(), p.PA8.reborrow(), p.PA9.reborrow()); + Qei::new::>( + p.TIM1.reborrow(), + p.PA8.reborrow(), + p.PA9.reborrow(), + Default::default(), + ); defmt::assert_eq!(AFIO.mapr().read().tim1_remap(), 1); } -- cgit From 8fae6f5a3f7055dc8250cd8926624010b14db6dc Mon Sep 17 00:00:00 2001 From: Michael Kefeder Date: Sun, 28 Sep 2025 18:32:40 +0200 Subject: Reset SAADC in Drop impl for nrf52, workaround for anomaly 241. --- embassy-nrf/CHANGELOG.md | 1 + embassy-nrf/src/saadc.rs | 13 ++++++ examples/nrf52810/src/bin/saadc_lowpower.rs | 62 +++++++++++++++++++++++++++++ 3 files changed, 76 insertions(+) create mode 100644 examples/nrf52810/src/bin/saadc_lowpower.rs diff --git a/embassy-nrf/CHANGELOG.md b/embassy-nrf/CHANGELOG.md index b8d03a1f8..3ad3c8005 100644 --- a/embassy-nrf/CHANGELOG.md +++ b/embassy-nrf/CHANGELOG.md @@ -17,6 +17,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - changed: impl Drop for Timer - added: expose `regs` for timer driver - added: timer driver CC `clear_events` method +- changed: Saadc reset in Drop impl, anomaly 241 - high power usage ## 0.7.0 - 2025-08-26 diff --git a/embassy-nrf/src/saadc.rs b/embassy-nrf/src/saadc.rs index 92b6fb01f..d84246572 100644 --- a/embassy-nrf/src/saadc.rs +++ b/embassy-nrf/src/saadc.rs @@ -457,6 +457,19 @@ impl<'d> Saadc<'d, 1> { impl<'d, const N: usize> Drop for Saadc<'d, N> { fn drop(&mut self) { + // Reset of SAADC. + // + // This is needed when more than one pin is sampled to avoid needless power consumption. + // More information can be found in [nrf52 Anomaly 241](https://docs.nordicsemi.com/bundle/errata_nRF52810_Rev1/page/ERR/nRF52810/Rev1/latest/anomaly_810_241.html). + // The workaround seems like it copies the configuration before reset and reapplies it after. + // This method consumes the instance forcing a reconfiguration at compile time, hence we only + // call what is the reset portion of the workaround. + #[cfg(feature = "_nrf52")] + { + unsafe { core::ptr::write_volatile(0x40007FFC as *mut u32, 0) } + unsafe { core::ptr::read_volatile(0x40007FFC as *const ()) } + unsafe { core::ptr::write_volatile(0x40007FFC as *mut u32, 1) } + } let r = Self::regs(); r.enable().write(|w| w.set_enable(false)); for i in 0..N { diff --git a/examples/nrf52810/src/bin/saadc_lowpower.rs b/examples/nrf52810/src/bin/saadc_lowpower.rs new file mode 100644 index 000000000..d7e7f09a4 --- /dev/null +++ b/examples/nrf52810/src/bin/saadc_lowpower.rs @@ -0,0 +1,62 @@ +//! Run SAADC on multiple pins only every 3rd time, to show anomaly 241 workaround. +//! +//! To correctly measure the MCU current on the NRF52DK follow the instructions +//! +//! otherwise you will measure the whole board, including the segger j-link chip for example + +#![no_std] +#![no_main] + +use defmt::info; +use embassy_executor::Spawner; +use embassy_nrf::gpio::{Level, Output, OutputDrive}; +use embassy_nrf::saadc::{Oversample, Saadc}; +use embassy_nrf::{bind_interrupts, saadc}; +use embassy_time::Timer; +use {defmt_rtt as _, panic_probe as _}; + +bind_interrupts!(struct Irqs { + SAADC => saadc::InterruptHandler; +}); + +#[embassy_executor::main] +async fn main(_p: Spawner) { + let mut p = embassy_nrf::init(Default::default()); + + // For PPK2 digital channel plot to track when SAADC is on/off. + let mut ppk2_d0 = Output::new(p.P0_27, Level::Low, OutputDrive::Standard); + let mut num_loops: usize = 0; + loop { + num_loops += 1; + if num_loops.is_multiple_of(3) { + ppk2_d0.set_high(); + let battery_pin = p.P0_02.reborrow(); + let sensor1_pin = p.P0_03.reborrow(); + let mut adc_config = saadc::Config::default(); + adc_config.oversample = Oversample::OVER4X; + let battery = saadc::ChannelConfig::single_ended(battery_pin); + let sensor1 = saadc::ChannelConfig::single_ended(sensor1_pin); + let mut saadc = Saadc::new(p.SAADC.reborrow(), Irqs, adc_config, [battery, sensor1]); + // Indicated: wait for ADC calibration. + saadc.calibrate().await; + let mut buf = [0; 2]; + info!("sampling..."); + saadc.sample(&mut buf).await; + info!("data: {:x}", buf); + + // Sleep to show the high power usage on the plot, even though sampling is done. + Timer::after_millis(100).await; + ppk2_d0.set_low(); + // disable the following line to show the anomaly on the power profiler plot. + core::mem::drop(saadc); + // Sleep to show the power usage when drop did not happen. + Timer::after_millis(100).await; + // worst case drop happens here + } else { + info!("waiting"); + } + // Sleep for 1 second. The executor ensures the core sleeps with a WFE when it has nothing to do. + // During this sleep, the nRF chip should only use ~3uA + Timer::after_secs(1).await; + } +} -- cgit From 55ee252434834cc9548acdc7b5da8ccd09043ca1 Mon Sep 17 00:00:00 2001 From: Michael Kefeder Date: Mon, 29 Sep 2025 21:30:24 +0200 Subject: fixup: documentation more precise --- embassy-nrf/src/saadc.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/embassy-nrf/src/saadc.rs b/embassy-nrf/src/saadc.rs index d84246572..fd48faabb 100644 --- a/embassy-nrf/src/saadc.rs +++ b/embassy-nrf/src/saadc.rs @@ -462,7 +462,7 @@ impl<'d, const N: usize> Drop for Saadc<'d, N> { // This is needed when more than one pin is sampled to avoid needless power consumption. // More information can be found in [nrf52 Anomaly 241](https://docs.nordicsemi.com/bundle/errata_nRF52810_Rev1/page/ERR/nRF52810/Rev1/latest/anomaly_810_241.html). // The workaround seems like it copies the configuration before reset and reapplies it after. - // This method consumes the instance forcing a reconfiguration at compile time, hence we only + // The instance is dropped, forcing a reconfiguration at compile time, hence we only // call what is the reset portion of the workaround. #[cfg(feature = "_nrf52")] { -- cgit From 0ba74a4127a244781fc125208a73cc51c8a0deac Mon Sep 17 00:00:00 2001 From: Ulf Lilleengen Date: Tue, 30 Sep 2025 10:31:33 +0200 Subject: chore: prepare crate releases --- docs/examples/basic/Cargo.toml | 2 +- embassy-boot-nrf/CHANGELOG.md | 4 ++++ embassy-boot-nrf/Cargo.toml | 4 ++-- embassy-nrf/CHANGELOG.md | 2 ++ embassy-nrf/Cargo.toml | 2 +- examples/boot/application/nrf/Cargo.toml | 4 ++-- examples/nrf-rtos-trace/Cargo.toml | 2 +- examples/nrf51/Cargo.toml | 2 +- examples/nrf52810/Cargo.toml | 2 +- examples/nrf52840-edf/Cargo.toml | 2 +- examples/nrf52840-rtic/Cargo.toml | 2 +- examples/nrf52840/Cargo.toml | 2 +- examples/nrf5340/Cargo.toml | 2 +- examples/nrf54l15/Cargo.toml | 2 +- examples/nrf9151/ns/Cargo.toml | 2 +- examples/nrf9151/s/Cargo.toml | 2 +- examples/nrf9160/Cargo.toml | 2 +- tests/nrf/Cargo.toml | 2 +- 18 files changed, 24 insertions(+), 18 deletions(-) diff --git a/docs/examples/basic/Cargo.toml b/docs/examples/basic/Cargo.toml index b6dbeda2a..b90180853 100644 --- a/docs/examples/basic/Cargo.toml +++ b/docs/examples/basic/Cargo.toml @@ -9,7 +9,7 @@ publish = false [dependencies] embassy-executor = { version = "0.9.0", path = "../../../embassy-executor", features = ["defmt", "arch-cortex-m", "executor-thread"] } embassy-time = { version = "0.5.0", path = "../../../embassy-time", features = ["defmt"] } -embassy-nrf = { version = "0.7.0", path = "../../../embassy-nrf", features = ["defmt", "nrf52840", "time-driver-rtc1", "gpiote"] } +embassy-nrf = { version = "0.8.0", path = "../../../embassy-nrf", features = ["defmt", "nrf52840", "time-driver-rtc1", "gpiote"] } defmt = "1.0.1" defmt-rtt = "1.0.0" diff --git a/embassy-boot-nrf/CHANGELOG.md b/embassy-boot-nrf/CHANGELOG.md index 8cc1e73c0..54b7c8067 100644 --- a/embassy-boot-nrf/CHANGELOG.md +++ b/embassy-boot-nrf/CHANGELOG.md @@ -8,6 +8,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## Unreleased - ReleaseDate +## 0.9.0 - 2025-09-30 + +- Bumped embassy-nrf to 0.8.0 + ## 0.8.0 - 2025-08-26 ## 0.1.1 - 2025-08-15 diff --git a/embassy-boot-nrf/Cargo.toml b/embassy-boot-nrf/Cargo.toml index 49dff061a..466f18631 100644 --- a/embassy-boot-nrf/Cargo.toml +++ b/embassy-boot-nrf/Cargo.toml @@ -1,7 +1,7 @@ [package] edition = "2021" name = "embassy-boot-nrf" -version = "0.8.0" +version = "0.9.0" description = "Bootloader lib for nRF chips" license = "MIT OR Apache-2.0" repository = "https://github.com/embassy-rs/embassy" @@ -36,7 +36,7 @@ defmt = { version = "1.0.1", optional = true } log = { version = "0.4.17", optional = true } embassy-sync = { version = "0.7.2", path = "../embassy-sync" } -embassy-nrf = { version = "0.7.0", path = "../embassy-nrf", default-features = false } +embassy-nrf = { version = "0.8.0", path = "../embassy-nrf", default-features = false } embassy-boot = { version = "0.6.1", path = "../embassy-boot" } cortex-m = { version = "0.7.6" } cortex-m-rt = { version = "0.7" } diff --git a/embassy-nrf/CHANGELOG.md b/embassy-nrf/CHANGELOG.md index bdd031480..b3d4045fa 100644 --- a/embassy-nrf/CHANGELOG.md +++ b/embassy-nrf/CHANGELOG.md @@ -8,6 +8,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## Unreleased - ReleaseDate +## 0.8.0 - 2025-09-30 + - changed: Remove `T: Instance` generic params in all drivers. - changed: nrf54l: Disable glitch detection and enable DC/DC in init. - changed: Add embassy-net-driver-channel implementation for IEEE 802.15.4 diff --git a/embassy-nrf/Cargo.toml b/embassy-nrf/Cargo.toml index e2580a36e..362fabcf7 100644 --- a/embassy-nrf/Cargo.toml +++ b/embassy-nrf/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "embassy-nrf" -version = "0.7.0" +version = "0.8.0" edition = "2021" license = "MIT OR Apache-2.0" description = "Embassy Hardware Abstraction Layer (HAL) for nRF series microcontrollers" diff --git a/examples/boot/application/nrf/Cargo.toml b/examples/boot/application/nrf/Cargo.toml index b0cc63a6c..f5f89ecb5 100644 --- a/examples/boot/application/nrf/Cargo.toml +++ b/examples/boot/application/nrf/Cargo.toml @@ -9,9 +9,9 @@ publish = false embassy-sync = { version = "0.7.2", path = "../../../../embassy-sync" } embassy-executor = { version = "0.9.0", path = "../../../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "arch-cortex-m", "executor-thread"] } embassy-time = { version = "0.5.0", path = "../../../../embassy-time", features = [] } -embassy-nrf = { version = "0.7.0", path = "../../../../embassy-nrf", features = ["time-driver-rtc1", "gpiote", ] } +embassy-nrf = { version = "0.8.0", path = "../../../../embassy-nrf", features = ["time-driver-rtc1", "gpiote", ] } embassy-boot = { version = "0.6.1", path = "../../../../embassy-boot", features = [] } -embassy-boot-nrf = { version = "0.8.0", path = "../../../../embassy-boot-nrf", features = [] } +embassy-boot-nrf = { version = "0.9.0", path = "../../../../embassy-boot-nrf", features = [] } embassy-embedded-hal = { version = "0.5.0", path = "../../../../embassy-embedded-hal" } defmt = { version = "1.0.1", optional = true } diff --git a/examples/nrf-rtos-trace/Cargo.toml b/examples/nrf-rtos-trace/Cargo.toml index c9eeaaac7..d2d0ae093 100644 --- a/examples/nrf-rtos-trace/Cargo.toml +++ b/examples/nrf-rtos-trace/Cargo.toml @@ -19,7 +19,7 @@ log = [ embassy-sync = { version = "0.7.2", path = "../../embassy-sync" } embassy-executor = { version = "0.9.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "rtos-trace"] } embassy-time = { version = "0.5.0", path = "../../embassy-time" } -embassy-nrf = { version = "0.7.0", path = "../../embassy-nrf", features = ["nrf52840", "time-driver-rtc1", "gpiote", "unstable-pac"] } +embassy-nrf = { version = "0.8.0", path = "../../embassy-nrf", features = ["nrf52840", "time-driver-rtc1", "gpiote", "unstable-pac"] } cortex-m = { version = "0.7.6", features = ["inline-asm", "critical-section-single-core"] } cortex-m-rt = "0.7.0" diff --git a/examples/nrf51/Cargo.toml b/examples/nrf51/Cargo.toml index dded6de59..082d85e5b 100644 --- a/examples/nrf51/Cargo.toml +++ b/examples/nrf51/Cargo.toml @@ -8,7 +8,7 @@ publish = false [dependencies] embassy-executor = { version = "0.9.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "executor-interrupt", "defmt"] } embassy-time = { version = "0.5.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime"] } -embassy-nrf = { version = "0.7.0", path = "../../embassy-nrf", features = ["defmt", "nrf51", "gpiote", "time-driver-rtc1", "unstable-pac", "time", "rt"] } +embassy-nrf = { version = "0.8.0", path = "../../embassy-nrf", features = ["defmt", "nrf51", "gpiote", "time-driver-rtc1", "unstable-pac", "time", "rt"] } defmt = "1.0.1" defmt-rtt = "1.0.0" diff --git a/examples/nrf52810/Cargo.toml b/examples/nrf52810/Cargo.toml index aa1a4bf73..7835320e5 100644 --- a/examples/nrf52810/Cargo.toml +++ b/examples/nrf52810/Cargo.toml @@ -10,7 +10,7 @@ embassy-futures = { version = "0.1.2", path = "../../embassy-futures" } embassy-sync = { version = "0.7.2", path = "../../embassy-sync", features = ["defmt"] } embassy-executor = { version = "0.9.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "executor-interrupt", "defmt"] } embassy-time = { version = "0.5.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime"] } -embassy-nrf = { version = "0.7.0", path = "../../embassy-nrf", features = ["defmt", "nrf52810", "time-driver-rtc1", "gpiote", "unstable-pac", "time"] } +embassy-nrf = { version = "0.8.0", path = "../../embassy-nrf", features = ["defmt", "nrf52810", "time-driver-rtc1", "gpiote", "unstable-pac", "time"] } defmt = "1.0.1" defmt-rtt = "1.0.0" diff --git a/examples/nrf52840-edf/Cargo.toml b/examples/nrf52840-edf/Cargo.toml index 1e8803233..67a624d6d 100644 --- a/examples/nrf52840-edf/Cargo.toml +++ b/examples/nrf52840-edf/Cargo.toml @@ -9,7 +9,7 @@ publish = false # NOTE: "scheduler-deadline" and "embassy-time-driver" features are enabled embassy-executor = { version = "0.9.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "executor-interrupt", "defmt", "scheduler-deadline", "embassy-time-driver"] } embassy-time = { version = "0.5.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime"] } -embassy-nrf = { version = "0.7.0", path = "../../embassy-nrf", features = ["defmt", "nrf52840", "time-driver-rtc1", "gpiote", "unstable-pac", "time"] } +embassy-nrf = { version = "0.8.0", path = "../../embassy-nrf", features = ["defmt", "nrf52840", "time-driver-rtc1", "gpiote", "unstable-pac", "time"] } defmt = "1.0.1" defmt-rtt = "1.0.0" diff --git a/examples/nrf52840-rtic/Cargo.toml b/examples/nrf52840-rtic/Cargo.toml index f6937c263..d860626a1 100644 --- a/examples/nrf52840-rtic/Cargo.toml +++ b/examples/nrf52840-rtic/Cargo.toml @@ -12,7 +12,7 @@ embassy-futures = { version = "0.1.2", path = "../../embassy-futures" } embassy-sync = { version = "0.7.2", path = "../../embassy-sync", features = ["defmt"] } embassy-time = { version = "0.5.0", path = "../../embassy-time", features = [ "defmt", "defmt-timestamp-uptime"] } embassy-time-queue-utils = { version = "0.3.0", path = "../../embassy-time-queue-utils", features = ["generic-queue-8"] } -embassy-nrf = { version = "0.7.0", path = "../../embassy-nrf", features = [ "defmt", "nrf52840", "time-driver-rtc1", "gpiote", "unstable-pac", "time"] } +embassy-nrf = { version = "0.8.0", path = "../../embassy-nrf", features = [ "defmt", "nrf52840", "time-driver-rtc1", "gpiote", "unstable-pac", "time"] } defmt = "1.0.1" defmt-rtt = "1.0.0" diff --git a/examples/nrf52840/Cargo.toml b/examples/nrf52840/Cargo.toml index ca3c6f863..5b3e176c0 100644 --- a/examples/nrf52840/Cargo.toml +++ b/examples/nrf52840/Cargo.toml @@ -10,7 +10,7 @@ embassy-futures = { version = "0.1.2", path = "../../embassy-futures" } embassy-sync = { version = "0.7.2", path = "../../embassy-sync", features = ["defmt"] } embassy-executor = { version = "0.9.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "executor-interrupt", "defmt"] } embassy-time = { version = "0.5.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime"] } -embassy-nrf = { version = "0.7.0", path = "../../embassy-nrf", features = ["defmt", "nrf52840", "time-driver-rtc1", "gpiote", "unstable-pac", "time", "net-driver"] } +embassy-nrf = { version = "0.8.0", path = "../../embassy-nrf", features = ["defmt", "nrf52840", "time-driver-rtc1", "gpiote", "unstable-pac", "time", "net-driver"] } embassy-net = { version = "0.7.1", path = "../../embassy-net", features = ["defmt", "tcp", "dhcpv4", "medium-ethernet","udp", "medium-ieee802154", "proto-ipv6"] } embassy-usb = { version = "0.5.1", path = "../../embassy-usb", features = ["defmt"] } embedded-io = { version = "0.6.0", features = ["defmt-03"] } diff --git a/examples/nrf5340/Cargo.toml b/examples/nrf5340/Cargo.toml index 425015667..256fee08d 100644 --- a/examples/nrf5340/Cargo.toml +++ b/examples/nrf5340/Cargo.toml @@ -10,7 +10,7 @@ embassy-futures = { version = "0.1.2", path = "../../embassy-futures" } embassy-sync = { version = "0.7.2", path = "../../embassy-sync", features = ["defmt"] } embassy-executor = { version = "0.9.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "defmt"] } embassy-time = { version = "0.5.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime"] } -embassy-nrf = { version = "0.7.0", path = "../../embassy-nrf", features = ["defmt", "nrf5340-app-s", "time-driver-rtc1", "gpiote", "unstable-pac"] } +embassy-nrf = { version = "0.8.0", path = "../../embassy-nrf", features = ["defmt", "nrf5340-app-s", "time-driver-rtc1", "gpiote", "unstable-pac"] } embassy-net = { version = "0.7.1", path = "../../embassy-net", features = ["defmt", "tcp", "dhcpv4", "medium-ethernet"] } embassy-usb = { version = "0.5.1", path = "../../embassy-usb", features = ["defmt"] } embedded-io-async = { version = "0.6.1" } diff --git a/examples/nrf54l15/Cargo.toml b/examples/nrf54l15/Cargo.toml index 7f67b41f6..9c24cdab4 100644 --- a/examples/nrf54l15/Cargo.toml +++ b/examples/nrf54l15/Cargo.toml @@ -8,7 +8,7 @@ publish = false [dependencies] embassy-executor = { version = "0.9.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "executor-interrupt", "defmt"] } embassy-time = { version = "0.5.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime"] } -embassy-nrf = { version = "0.7.0", path = "../../embassy-nrf", features = ["defmt", "nrf54l15-app-s", "time-driver-rtc1", "gpiote", "unstable-pac", "time"] } +embassy-nrf = { version = "0.8.0", path = "../../embassy-nrf", features = ["defmt", "nrf54l15-app-s", "time-driver-rtc1", "gpiote", "unstable-pac", "time"] } defmt = "1.0.1" defmt-rtt = "1.0.0" diff --git a/examples/nrf9151/ns/Cargo.toml b/examples/nrf9151/ns/Cargo.toml index 8e420477f..89a6c7c94 100644 --- a/examples/nrf9151/ns/Cargo.toml +++ b/examples/nrf9151/ns/Cargo.toml @@ -8,7 +8,7 @@ publish = false [dependencies] embassy-executor = { version = "0.9.0", path = "../../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "executor-interrupt", "defmt"] } embassy-time = { version = "0.5.0", path = "../../../embassy-time", features = ["defmt", "defmt-timestamp-uptime"] } -embassy-nrf = { version = "0.7.0", path = "../../../embassy-nrf", features = ["defmt", "nrf9120-ns", "time-driver-rtc1", "gpiote", "unstable-pac", "time"] } +embassy-nrf = { version = "0.8.0", path = "../../../embassy-nrf", features = ["defmt", "nrf9120-ns", "time-driver-rtc1", "gpiote", "unstable-pac", "time"] } defmt = "1.0.1" defmt-rtt = "1.0.0" diff --git a/examples/nrf9151/s/Cargo.toml b/examples/nrf9151/s/Cargo.toml index e4ca85553..870311c5d 100644 --- a/examples/nrf9151/s/Cargo.toml +++ b/examples/nrf9151/s/Cargo.toml @@ -8,7 +8,7 @@ publish = false [dependencies] embassy-executor = { version = "0.9.0", path = "../../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "executor-interrupt", "defmt"] } embassy-time = { version = "0.5.0", path = "../../../embassy-time", features = ["defmt", "defmt-timestamp-uptime"] } -embassy-nrf = { version = "0.7.0", path = "../../../embassy-nrf", features = ["defmt", "nrf9120-s", "time-driver-rtc1", "gpiote", "unstable-pac", "time"] } +embassy-nrf = { version = "0.8.0", path = "../../../embassy-nrf", features = ["defmt", "nrf9120-s", "time-driver-rtc1", "gpiote", "unstable-pac", "time"] } defmt = "1.0.1" defmt-rtt = "1.0.0" diff --git a/examples/nrf9160/Cargo.toml b/examples/nrf9160/Cargo.toml index d7b63a7ac..274e26dd6 100644 --- a/examples/nrf9160/Cargo.toml +++ b/examples/nrf9160/Cargo.toml @@ -8,7 +8,7 @@ publish = false [dependencies] embassy-executor = { version = "0.9.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "executor-interrupt", "defmt"] } embassy-time = { version = "0.5.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime"] } -embassy-nrf = { version = "0.7.0", path = "../../embassy-nrf", features = ["defmt", "nrf9160-s", "time-driver-rtc1", "gpiote", "unstable-pac", "time"] } +embassy-nrf = { version = "0.8.0", path = "../../embassy-nrf", features = ["defmt", "nrf9160-s", "time-driver-rtc1", "gpiote", "unstable-pac", "time"] } embassy-net-nrf91 = { version = "0.1.0", path = "../../embassy-net-nrf91", features = ["defmt"] } embassy-net = { version = "0.7.1", path = "../../embassy-net", features = ["defmt", "tcp", "proto-ipv4", "medium-ip"] } diff --git a/tests/nrf/Cargo.toml b/tests/nrf/Cargo.toml index efc297ccf..8acf27ce7 100644 --- a/tests/nrf/Cargo.toml +++ b/tests/nrf/Cargo.toml @@ -12,7 +12,7 @@ embassy-futures = { version = "0.1.2", path = "../../embassy-futures" } embassy-sync = { version = "0.7.2", path = "../../embassy-sync", features = ["defmt", ] } embassy-executor = { version = "0.9.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "defmt"] } embassy-time = { version = "0.5.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime"] } -embassy-nrf = { version = "0.7.0", path = "../../embassy-nrf", features = ["defmt", "time-driver-rtc1", "gpiote", "unstable-pac"] } +embassy-nrf = { version = "0.8.0", path = "../../embassy-nrf", features = ["defmt", "time-driver-rtc1", "gpiote", "unstable-pac"] } embedded-io-async = { version = "0.6.1", features = ["defmt-03"] } embassy-net = { version = "0.7.1", path = "../../embassy-net", features = ["defmt", "tcp", "dhcpv4", "medium-ethernet", ] } embassy-net-esp-hosted = { version = "0.2.1", path = "../../embassy-net-esp-hosted", features = ["defmt"] } -- cgit From 02b08a5a43427de77c194849674d0da0de84e07d Mon Sep 17 00:00:00 2001 From: Daniel Nilsson Date: Wed, 17 Sep 2025 20:52:40 +0200 Subject: stm32: add config to MCO to control the drive strength. --- embassy-stm32/CHANGELOG.md | 1 + embassy-stm32/src/rcc/mco.rs | 23 ++++++++++++++++++++--- examples/stm32f4/src/bin/mco.rs | 18 +++++++++++++++--- examples/stm32h5/src/bin/mco.rs | 29 +++++++++++++++++++++++++++++ examples/stm32h7/src/bin/camera.rs | 11 +++++++++-- examples/stm32h7/src/bin/mco.rs | 10 ++++++++-- examples/stm32h7rs/src/bin/mco.rs | 10 ++++++++-- examples/stm32l4/src/bin/mco.rs | 10 ++++++++-- 8 files changed, 98 insertions(+), 14 deletions(-) create mode 100644 examples/stm32h5/src/bin/mco.rs diff --git a/embassy-stm32/CHANGELOG.md b/embassy-stm32/CHANGELOG.md index 80261ae41..1443472f5 100644 --- a/embassy-stm32/CHANGELOG.md +++ b/embassy-stm32/CHANGELOG.md @@ -26,6 +26,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - fix: RTC register definition for STM32L4P5 and L4Q5 as they use v3 register map. - fix: Cut down the capabilities of the STM32L412 and L422 RTC as those are missing binary timer mode and underflow interrupt. - fix: Allow configuration of the internal pull up/down resistors on the pins for the Qei peripheral, as well as the Qei decoder mode. +- feat: stm32/rcc/mco: Added support for IO driver strength when using Master Clock Out IO. This changes signature on Mco::new taking a McoConfig struct ([#4679](https://github.com/embassy-rs/embassy/pull/4679)) ## 0.4.0 - 2025-08-26 diff --git a/embassy-stm32/src/rcc/mco.rs b/embassy-stm32/src/rcc/mco.rs index 59ccc8cb5..fa4b45a20 100644 --- a/embassy-stm32/src/rcc/mco.rs +++ b/embassy-stm32/src/rcc/mco.rs @@ -91,12 +91,29 @@ pub struct Mco<'d, T: McoInstance> { impl<'d, T: McoInstance> Mco<'d, T> { /// Create a new MCO instance. - pub fn new(_peri: Peri<'d, T>, pin: Peri<'d, impl McoPin>, source: T::Source, prescaler: McoPrescaler) -> Self { + pub fn new(_peri: Peri<'d, T>, pin: Peri<'d, impl McoPin>, source: T::Source, config: McoConfig) -> Self { critical_section::with(|_| unsafe { - T::_apply_clock_settings(source, prescaler); - set_as_af!(pin, AfType::output(OutputType::PushPull, Speed::VeryHigh)); + T::_apply_clock_settings(source, config.prescaler); + set_as_af!(pin, AfType::output(OutputType::PushPull, config.speed)); }); Self { phantom: PhantomData } } } + +#[non_exhaustive] +pub struct McoConfig { + /// Master Clock Out prescaler + pub prescaler: McoPrescaler, + /// IO Drive Strength + pub speed: Speed, +} + +impl Default for McoConfig { + fn default() -> Self { + Self { + prescaler: McoPrescaler::DIV1, + speed: Speed::VeryHigh, + } + } +} diff --git a/examples/stm32f4/src/bin/mco.rs b/examples/stm32f4/src/bin/mco.rs index eb7bb6261..a2e229770 100644 --- a/examples/stm32f4/src/bin/mco.rs +++ b/examples/stm32f4/src/bin/mco.rs @@ -4,7 +4,7 @@ use defmt::*; use embassy_executor::Spawner; use embassy_stm32::gpio::{Level, Output, Speed}; -use embassy_stm32::rcc::{Mco, Mco1Source, Mco2Source, McoPrescaler}; +use embassy_stm32::rcc::{Mco, Mco1Source, Mco2Source, McoConfig, McoPrescaler}; use embassy_time::Timer; use {defmt_rtt as _, panic_probe as _}; @@ -13,8 +13,20 @@ async fn main(_spawner: Spawner) { let p = embassy_stm32::init(Default::default()); info!("Hello World!"); - let _mco1 = Mco::new(p.MCO1, p.PA8, Mco1Source::HSI, McoPrescaler::DIV1); - let _mco2 = Mco::new(p.MCO2, p.PC9, Mco2Source::PLL, McoPrescaler::DIV4); + let config_mco1 = { + let mut config = McoConfig::default(); + config.prescaler = McoPrescaler::DIV1; + config + }; + + let config_mco2 = { + let mut config = McoConfig::default(); + config.prescaler = McoPrescaler::DIV4; + config + }; + + let _mco1 = Mco::new(p.MCO1, p.PA8, Mco1Source::HSI, config_mco1); + let _mco2 = Mco::new(p.MCO2, p.PC9, Mco2Source::PLL, config_mco2); let mut led = Output::new(p.PB7, Level::High, Speed::Low); loop { diff --git a/examples/stm32h5/src/bin/mco.rs b/examples/stm32h5/src/bin/mco.rs new file mode 100644 index 000000000..1137ba25c --- /dev/null +++ b/examples/stm32h5/src/bin/mco.rs @@ -0,0 +1,29 @@ +#![no_std] +#![no_main] + +use defmt::*; +use embassy_executor::Spawner; +use embassy_stm32::gpio::Speed; +use embassy_stm32::rcc::{Mco, Mco2Source, McoConfig}; +use {defmt_rtt as _, panic_probe as _}; + +#[embassy_executor::main] +async fn main(_spawner: Spawner) { + let p = embassy_stm32::init(Default::default()); + + /* Default "VeryHigh" drive strength and prescaler DIV1 */ + // let _mco = Mco::new(p.MCO2, p.PC9, Mco2Source::SYS, McoConfig::default()); + + /* Choose Speed::Low drive strength */ + let config = { + let mut config = McoConfig::default(); + config.speed = Speed::Low; + config + }; + + let _mco = Mco::new(p.MCO2, p.PC9, Mco2Source::SYS, config); + + info!("Clock out with low drive strength set on Master Clock Out 2 pin as AF on PC9"); + + loop {} +} diff --git a/examples/stm32h7/src/bin/camera.rs b/examples/stm32h7/src/bin/camera.rs index 8f2e265d6..039008d17 100644 --- a/examples/stm32h7/src/bin/camera.rs +++ b/examples/stm32h7/src/bin/camera.rs @@ -5,7 +5,7 @@ use embassy_executor::Spawner; use embassy_stm32::dcmi::{self, *}; use embassy_stm32::gpio::{Level, Output, Speed}; use embassy_stm32::i2c::I2c; -use embassy_stm32::rcc::{Mco, Mco1Source, McoPrescaler}; +use embassy_stm32::rcc::{Mco, Mco1Source, McoConfig, McoPrescaler}; use embassy_stm32::{bind_interrupts, i2c, peripherals, Config}; use embassy_time::Timer; use ov7725::*; @@ -48,7 +48,14 @@ async fn main(_spawner: Spawner) { let p = embassy_stm32::init(config); defmt::info!("Hello World!"); - let mco = Mco::new(p.MCO1, p.PA8, Mco1Source::HSI, McoPrescaler::DIV3); + + let mco_config = { + let mut config = McoConfig::default(); + config.prescaler = McoPrescaler::DIV3; + config + }; + + let mco = Mco::new(p.MCO1, p.PA8, Mco1Source::HSI, mco_config); let mut led = Output::new(p.PE3, Level::High, Speed::Low); let cam_i2c = I2c::new(p.I2C1, p.PB8, p.PB9, Irqs, p.DMA1_CH1, p.DMA1_CH2, Default::default()); diff --git a/examples/stm32h7/src/bin/mco.rs b/examples/stm32h7/src/bin/mco.rs index a6ee27625..cafcb90f6 100644 --- a/examples/stm32h7/src/bin/mco.rs +++ b/examples/stm32h7/src/bin/mco.rs @@ -4,7 +4,7 @@ use defmt::*; use embassy_executor::Spawner; use embassy_stm32::gpio::{Level, Output, Speed}; -use embassy_stm32::rcc::{Mco, Mco1Source, McoPrescaler}; +use embassy_stm32::rcc::{Mco, Mco1Source, McoConfig, McoPrescaler}; use embassy_time::Timer; use {defmt_rtt as _, panic_probe as _}; @@ -15,7 +15,13 @@ async fn main(_spawner: Spawner) { let mut led = Output::new(p.PB14, Level::High, Speed::Low); - let _mco = Mco::new(p.MCO1, p.PA8, Mco1Source::HSI, McoPrescaler::DIV8); + let config = { + let mut config = McoConfig::default(); + config.prescaler = McoPrescaler::DIV8; + config + }; + + let _mco = Mco::new(p.MCO1, p.PA8, Mco1Source::HSI, config); loop { info!("high"); diff --git a/examples/stm32h7rs/src/bin/mco.rs b/examples/stm32h7rs/src/bin/mco.rs index a6ee27625..cafcb90f6 100644 --- a/examples/stm32h7rs/src/bin/mco.rs +++ b/examples/stm32h7rs/src/bin/mco.rs @@ -4,7 +4,7 @@ use defmt::*; use embassy_executor::Spawner; use embassy_stm32::gpio::{Level, Output, Speed}; -use embassy_stm32::rcc::{Mco, Mco1Source, McoPrescaler}; +use embassy_stm32::rcc::{Mco, Mco1Source, McoConfig, McoPrescaler}; use embassy_time::Timer; use {defmt_rtt as _, panic_probe as _}; @@ -15,7 +15,13 @@ async fn main(_spawner: Spawner) { let mut led = Output::new(p.PB14, Level::High, Speed::Low); - let _mco = Mco::new(p.MCO1, p.PA8, Mco1Source::HSI, McoPrescaler::DIV8); + let config = { + let mut config = McoConfig::default(); + config.prescaler = McoPrescaler::DIV8; + config + }; + + let _mco = Mco::new(p.MCO1, p.PA8, Mco1Source::HSI, config); loop { info!("high"); diff --git a/examples/stm32l4/src/bin/mco.rs b/examples/stm32l4/src/bin/mco.rs index 36c002952..4cdeaa440 100644 --- a/examples/stm32l4/src/bin/mco.rs +++ b/examples/stm32l4/src/bin/mco.rs @@ -4,7 +4,7 @@ use defmt::*; use embassy_executor::Spawner; use embassy_stm32::gpio::{Level, Output, Speed}; -use embassy_stm32::rcc::{Mco, McoPrescaler, McoSource}; +use embassy_stm32::rcc::{Mco, McoConfig, McoPrescaler, McoSource}; use embassy_time::Timer; use {defmt_rtt as _, panic_probe as _}; @@ -13,7 +13,13 @@ async fn main(_spawner: Spawner) { let p = embassy_stm32::init(Default::default()); info!("Hello World!"); - let _mco = Mco::new(p.MCO, p.PA8, McoSource::HSI, McoPrescaler::DIV1); + let config = { + let mut config = McoConfig::default(); + config.prescaler = McoPrescaler::DIV1; + config + }; + + let _mco = Mco::new(p.MCO, p.PA8, McoSource::HSI, config); let mut led = Output::new(p.PB14, Level::High, Speed::Low); -- cgit From 2e9f3a815d440f33126d47cdcbf3bf1c9eab0ee1 Mon Sep 17 00:00:00 2001 From: Adam Greig Date: Mon, 15 Sep 2025 03:32:23 +0100 Subject: STM32: USART: Add `eager_reads` config option --- embassy-hal-internal/src/atomic_ring_buffer.rs | 39 +++++++++- embassy-stm32/CHANGELOG.md | 1 + embassy-stm32/src/usart/buffered.rs | 18 ++++- embassy-stm32/src/usart/mod.rs | 20 ++++- embassy-stm32/src/usart/ringbuffered.rs | 104 ++++++++++++++----------- 5 files changed, 133 insertions(+), 49 deletions(-) diff --git a/embassy-hal-internal/src/atomic_ring_buffer.rs b/embassy-hal-internal/src/atomic_ring_buffer.rs index 00b7a1249..7de96e4e2 100644 --- a/embassy-hal-internal/src/atomic_ring_buffer.rs +++ b/embassy-hal-internal/src/atomic_ring_buffer.rs @@ -142,6 +142,19 @@ impl RingBuffer { self.wrap(start + len) == end } + /// Check if buffer is at least half full. + pub fn is_half_full(&self) -> bool { + let len = self.len.load(Ordering::Relaxed); + let start = self.start.load(Ordering::Relaxed); + let end = self.end.load(Ordering::Relaxed); + let n = if end >= start { + end - start + } else { + 2 * len - start + end + }; + n >= len / 2 + } + /// Check if buffer is empty. pub fn is_empty(&self) -> bool { let start = self.start.load(Ordering::Relaxed); @@ -394,6 +407,7 @@ mod tests { rb.init(b.as_mut_ptr(), 4); assert_eq!(rb.is_empty(), true); + assert_eq!(rb.is_half_full(), false); assert_eq!(rb.is_full(), false); rb.writer().push(|buf| { @@ -406,6 +420,7 @@ mod tests { }); assert_eq!(rb.is_empty(), false); + assert_eq!(rb.is_half_full(), true); assert_eq!(rb.is_full(), true); rb.writer().push(|buf| { @@ -415,6 +430,7 @@ mod tests { }); assert_eq!(rb.is_empty(), false); + assert_eq!(rb.is_half_full(), true); assert_eq!(rb.is_full(), true); rb.reader().pop(|buf| { @@ -424,6 +440,7 @@ mod tests { }); assert_eq!(rb.is_empty(), false); + assert_eq!(rb.is_half_full(), true); assert_eq!(rb.is_full(), false); rb.reader().pop(|buf| { @@ -432,6 +449,7 @@ mod tests { }); assert_eq!(rb.is_empty(), false); + assert_eq!(rb.is_half_full(), true); assert_eq!(rb.is_full(), false); rb.reader().pop(|buf| { @@ -447,6 +465,7 @@ mod tests { }); assert_eq!(rb.is_empty(), true); + assert_eq!(rb.is_half_full(), false); assert_eq!(rb.is_full(), false); rb.reader().pop(|buf| { @@ -460,14 +479,28 @@ mod tests { 1 }); + assert_eq!(rb.is_empty(), false); + assert_eq!(rb.is_half_full(), false); + assert_eq!(rb.is_full(), false); + rb.writer().push(|buf| { assert_eq!(3, buf.len()); buf[0] = 11; - buf[1] = 12; - 2 + 1 + }); + + assert_eq!(rb.is_empty(), false); + assert_eq!(rb.is_half_full(), true); + assert_eq!(rb.is_full(), false); + + rb.writer().push(|buf| { + assert_eq!(2, buf.len()); + buf[0] = 12; + 1 }); assert_eq!(rb.is_empty(), false); + assert_eq!(rb.is_half_full(), true); assert_eq!(rb.is_full(), false); rb.writer().push(|buf| { @@ -477,6 +510,7 @@ mod tests { }); assert_eq!(rb.is_empty(), false); + assert_eq!(rb.is_half_full(), true); assert_eq!(rb.is_full(), true); } } @@ -490,6 +524,7 @@ mod tests { rb.init(b.as_mut_ptr(), b.len()); assert_eq!(rb.is_empty(), true); + assert_eq!(rb.is_half_full(), true); assert_eq!(rb.is_full(), true); rb.writer().push(|buf| { diff --git a/embassy-stm32/CHANGELOG.md b/embassy-stm32/CHANGELOG.md index 1443472f5..f4cfc14cc 100644 --- a/embassy-stm32/CHANGELOG.md +++ b/embassy-stm32/CHANGELOG.md @@ -27,6 +27,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - fix: Cut down the capabilities of the STM32L412 and L422 RTC as those are missing binary timer mode and underflow interrupt. - fix: Allow configuration of the internal pull up/down resistors on the pins for the Qei peripheral, as well as the Qei decoder mode. - feat: stm32/rcc/mco: Added support for IO driver strength when using Master Clock Out IO. This changes signature on Mco::new taking a McoConfig struct ([#4679](https://github.com/embassy-rs/embassy/pull/4679)) +- feat: stm32/usart: add `eager_reads` option to control if buffered readers return as soon as possible or after more data is available ([#4668](https://github.com/embassy-rs/embassy/pull/4668)) ## 0.4.0 - 2025-08-26 diff --git a/embassy-stm32/src/usart/buffered.rs b/embassy-stm32/src/usart/buffered.rs index c734eed49..83aa4439b 100644 --- a/embassy-stm32/src/usart/buffered.rs +++ b/embassy-stm32/src/usart/buffered.rs @@ -68,8 +68,14 @@ unsafe fn on_interrupt(r: Regs, state: &'static State) { // FIXME: Should we disable any further RX interrupts when the buffer becomes full. } - if !state.rx_buf.is_empty() { - state.rx_waker.wake(); + if state.eager_reads.load(Ordering::Relaxed) { + if !state.rx_buf.is_empty() { + state.rx_waker.wake(); + } + } else { + if state.rx_buf.is_half_full() { + state.rx_waker.wake(); + } } } @@ -132,6 +138,7 @@ pub(super) struct State { tx_done: AtomicBool, tx_rx_refcount: AtomicU8, half_duplex_readback: AtomicBool, + eager_reads: AtomicBool, } impl State { @@ -144,6 +151,7 @@ impl State { tx_done: AtomicBool::new(true), tx_rx_refcount: AtomicU8::new(0), half_duplex_readback: AtomicBool::new(false), + eager_reads: AtomicBool::new(false), } } } @@ -419,6 +427,7 @@ impl<'d> BufferedUart<'d> { let state = T::buffered_state(); let kernel_clock = T::frequency(); + state.eager_reads.store(config.eager_reads, Ordering::Relaxed); state.half_duplex_readback.store( config.duplex == Duplex::Half(HalfDuplexReadback::Readback), Ordering::Relaxed, @@ -456,6 +465,7 @@ impl<'d> BufferedUart<'d> { let info = self.rx.info; let state = self.rx.state; state.tx_rx_refcount.store(2, Ordering::Relaxed); + state.eager_reads.store(config.eager_reads, Ordering::Relaxed); info.rcc.enable_and_reset(); @@ -527,6 +537,8 @@ impl<'d> BufferedUart<'d> { pub fn set_config(&mut self, config: &Config) -> Result<(), ConfigError> { reconfigure(self.rx.info, self.rx.kernel_clock, config)?; + self.rx.state.eager_reads.store(config.eager_reads, Ordering::Relaxed); + self.rx.info.regs.cr1().modify(|w| { w.set_rxneie(true); w.set_idleie(true); @@ -633,6 +645,8 @@ impl<'d> BufferedUartRx<'d> { pub fn set_config(&mut self, config: &Config) -> Result<(), ConfigError> { reconfigure(self.info, self.kernel_clock, config)?; + self.state.eager_reads.store(config.eager_reads, Ordering::Relaxed); + self.info.regs.cr1().modify(|w| { w.set_rxneie(true); w.set_idleie(true); diff --git a/embassy-stm32/src/usart/mod.rs b/embassy-stm32/src/usart/mod.rs index ff211e0c9..e439f2cee 100644 --- a/embassy-stm32/src/usart/mod.rs +++ b/embassy-stm32/src/usart/mod.rs @@ -4,7 +4,7 @@ use core::future::poll_fn; use core::marker::PhantomData; -use core::sync::atomic::{compiler_fence, AtomicU8, Ordering}; +use core::sync::atomic::{compiler_fence, AtomicBool, AtomicU8, Ordering}; use core::task::Poll; use embassy_embedded_hal::SetConfig; @@ -206,6 +206,18 @@ pub struct Config { /// If false: the error is ignored and cleared pub detect_previous_overrun: bool, + /// If true then read-like calls on `BufferedUartRx` and `RingBufferedUartRx` + /// are woken/return as soon as any data is available in the buffer. + /// + /// If false (the default) then reads started typically only wake/return after + /// line idle or after the buffer is at least half full (`BufferedUartRx`) or + /// the DMA buffer is written at the half or full positions (`RingBufferedUartRx`), + /// though it may also wake/return earlier in some circumstances. + /// + /// Has no effect on plain `Uart` or `UartRx` reads, which are specified to either + /// return a single word, a full buffer, or after line idle. + pub eager_reads: bool, + /// Set this to true if the line is considered noise free. /// This will increase the receiver’s tolerance to clock deviations, /// but will effectively disable noise detection. @@ -270,6 +282,7 @@ impl Default for Config { parity: Parity::ParityNone, // historical behavior detect_previous_overrun: false, + eager_reads: false, #[cfg(not(usart_v1))] assume_noise_free: false, #[cfg(any(usart_v3, usart_v4))] @@ -966,6 +979,7 @@ impl<'d, M: Mode> UartRx<'d, M> { let info = self.info; let state = self.state; state.tx_rx_refcount.store(1, Ordering::Relaxed); + state.eager_reads.store(config.eager_reads, Ordering::Relaxed); info.rcc.enable_and_reset(); @@ -982,6 +996,7 @@ impl<'d, M: Mode> UartRx<'d, M> { /// Reconfigure the driver pub fn set_config(&mut self, config: &Config) -> Result<(), ConfigError> { + self.state.eager_reads.store(config.eager_reads, Ordering::Relaxed); reconfigure(self.info, self.kernel_clock, config) } @@ -1462,6 +1477,7 @@ impl<'d, M: Mode> Uart<'d, M> { let info = self.rx.info; let state = self.rx.state; state.tx_rx_refcount.store(2, Ordering::Relaxed); + state.eager_reads.store(config.eager_reads, Ordering::Relaxed); info.rcc.enable_and_reset(); @@ -2022,6 +2038,7 @@ struct State { rx_waker: AtomicWaker, tx_waker: AtomicWaker, tx_rx_refcount: AtomicU8, + eager_reads: AtomicBool, } impl State { @@ -2030,6 +2047,7 @@ impl State { rx_waker: AtomicWaker::new(), tx_waker: AtomicWaker::new(), tx_rx_refcount: AtomicU8::new(0), + eager_reads: AtomicBool::new(false), } } } diff --git a/embassy-stm32/src/usart/ringbuffered.rs b/embassy-stm32/src/usart/ringbuffered.rs index 5f4e87834..d818e0bcc 100644 --- a/embassy-stm32/src/usart/ringbuffered.rs +++ b/embassy-stm32/src/usart/ringbuffered.rs @@ -26,9 +26,9 @@ use crate::Peri; /// contain enough bytes to fill the buffer passed by the caller of /// the function, or is empty. /// -/// Waiting for bytes operates in one of two modes, depending on -/// the behavior of the sender and the size of the buffer passed -/// to the function: +/// Waiting for bytes operates in one of three modes, depending on +/// the behavior of the sender, the size of the buffer passed +/// to the function, and the configuration: /// /// - If the sender sends intermittently, the 'idle line' /// condition will be detected when the sender stops, and any @@ -47,7 +47,11 @@ use crate::Peri; /// interrupt when those specific buffer addresses have been /// written. /// -/// In both cases this will result in variable latency due to the +/// - If `eager_reads` is enabled in `config`, the UART interrupt +/// is enabled on all data reception and the call will only wait +/// for at least one byte to be available before returning. +/// +/// In the first two cases this will result in variable latency due to the /// buffering effect. For example, if the baudrate is 2400 bps, and /// the configuration is 8 data bits, no parity bit, and one stop bit, /// then a byte will be received every ~4.16ms. If the ring buffer is @@ -68,15 +72,10 @@ use crate::Peri; /// sending, but would be falsely triggered in the worst-case /// buffer delay scenario. /// -/// Note: This latency is caused by the limited capabilities of the -/// STM32 DMA controller; since it cannot generate an interrupt when -/// it stores a byte into an empty ring buffer, or in any other -/// configurable conditions, it is not possible to take notice of the -/// contents of the ring buffer more quickly without introducing -/// polling. As a result the latency can be reduced by calling the -/// read functions repeatedly with smaller buffers to receive the -/// available bytes, as each call to a read function will explicitly -/// check the ring buffer for available bytes. +/// Note: Enabling `eager_reads` with `RingBufferedUartRx` will enable +/// an UART RXNE interrupt, which will cause an interrupt to occur on +/// every received data byte. The data is still copied using DMA, but +/// there is nevertheless additional processing overhead for each byte. pub struct RingBufferedUartRx<'d> { info: &'static Info, state: &'static State, @@ -133,6 +132,7 @@ impl<'d> UartRx<'d, Async> { impl<'d> RingBufferedUartRx<'d> { /// Reconfigure the driver pub fn set_config(&mut self, config: &Config) -> Result<(), ConfigError> { + self.state.eager_reads.store(config.eager_reads, Ordering::Relaxed); reconfigure(self.info, self.kernel_clock, config) } @@ -148,8 +148,8 @@ impl<'d> RingBufferedUartRx<'d> { let r = self.info.regs; // clear all interrupts and DMA Rx Request r.cr1().modify(|w| { - // disable RXNE interrupt - w.set_rxneie(false); + // use RXNE only when returning reads early + w.set_rxneie(self.state.eager_reads.load(Ordering::Relaxed)); // enable parity interrupt if not ParityNone w.set_peie(w.pce()); // enable idle line interrupt @@ -248,39 +248,55 @@ impl<'d> RingBufferedUartRx<'d> { async fn wait_for_data_or_idle(&mut self) -> Result<(), Error> { compiler_fence(Ordering::SeqCst); - // Future which completes when idle line is detected - let s = self.state; - let uart = poll_fn(|cx| { - s.rx_waker.register(cx.waker()); - - compiler_fence(Ordering::SeqCst); - - if check_idle_and_errors(self.info.regs)? { - // Idle line is detected - Poll::Ready(Ok(())) - } else { - Poll::Pending - } - }); + loop { + // Future which completes when idle line is detected + let s = self.state; + let mut uart_init = false; + let uart = poll_fn(|cx| { + s.rx_waker.register(cx.waker()); + + compiler_fence(Ordering::SeqCst); + + // We may have been woken by IDLE or, if eager_reads is set, by RXNE. + // However, DMA will clear RXNE, so we can't check directly, and because + // the other future borrows `ring_buf`, we can't check `len()` here either. + // Instead, return from this future and we'll check the length afterwards. + let eager = s.eager_reads.load(Ordering::Relaxed); + + if check_idle_and_errors(self.info.regs)? || (eager && uart_init) { + // Idle line is detected, or eager reads is set and some data is available. + Poll::Ready(Ok(())) + } else { + uart_init = true; + Poll::Pending + } + }); - let mut dma_init = false; - // Future which completes when the DMA controller indicates it - // has written to the ring buffer's middle byte, or last byte - let dma = poll_fn(|cx| { - self.ring_buf.set_waker(cx.waker()); + let mut dma_init = false; + // Future which completes when the DMA controller indicates it + // has written to the ring buffer's middle byte, or last byte + let dma = poll_fn(|cx| { + self.ring_buf.set_waker(cx.waker()); - let status = match dma_init { - false => Poll::Pending, - true => Poll::Ready(()), - }; + let status = match dma_init { + false => Poll::Pending, + true => Poll::Ready(()), + }; - dma_init = true; - status - }); + dma_init = true; + status + }); - match select(uart, dma).await { - Either::Left((result, _)) => result, - Either::Right(((), _)) => Ok(()), + match select(uart, dma).await { + Either::Left((result, _)) => { + if self.ring_buf.len().unwrap_or(0) > 0 || result.is_err() { + return result; + } else { + continue; + } + } + Either::Right(((), _)) => return Ok(()), + } } } -- cgit From c87051eecb50b80114c69cedc71ed9e3fcd7bb45 Mon Sep 17 00:00:00 2001 From: Adam Greig Date: Thu, 18 Sep 2025 01:50:48 +0100 Subject: STM32: USART: Add de_assertion_time and de_deassertion_time configs --- embassy-stm32/src/usart/mod.rs | 42 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 42 insertions(+) diff --git a/embassy-stm32/src/usart/mod.rs b/embassy-stm32/src/usart/mod.rs index e439f2cee..c8012a9b4 100644 --- a/embassy-stm32/src/usart/mod.rs +++ b/embassy-stm32/src/usart/mod.rs @@ -185,6 +185,12 @@ pub enum ConfigError { RxOrTxNotEnabled, /// Data bits and parity combination not supported DataParityNotSupported, + /// DE assertion time too high + #[cfg(not(any(usart_v1, usart_v2)))] + DeAssertionTimeTooHigh, + /// DE deassertion time too high + #[cfg(not(any(usart_v1, usart_v2)))] + DeDeassertionTimeTooHigh, } #[non_exhaustive] @@ -251,6 +257,14 @@ pub struct Config { /// Set the pin configuration for the DE pin. pub de_config: OutputConfig, + /// Set DE assertion time before the first start bit, 0-31 16ths of a bit period. + #[cfg(not(any(usart_v1, usart_v2)))] + pub de_assertion_time: u8, + + /// Set DE deassertion time after the last stop bit, 0-31 16ths of a bit period. + #[cfg(not(any(usart_v1, usart_v2)))] + pub de_deassertion_time: u8, + // private: set by new_half_duplex, not by the user. duplex: Duplex, } @@ -296,6 +310,10 @@ impl Default for Config { tx_config: OutputConfig::PushPull, rts_config: OutputConfig::PushPull, de_config: OutputConfig::PushPull, + #[cfg(not(any(usart_v1, usart_v2)))] + de_assertion_time: 0, + #[cfg(not(any(usart_v1, usart_v2)))] + de_deassertion_time: 0, duplex: Duplex::Full, } } @@ -1706,6 +1724,16 @@ fn configure( return Err(ConfigError::RxOrTxNotEnabled); } + #[cfg(not(any(usart_v1, usart_v2)))] + let dem = r.cr3().read().dem(); + + #[cfg(not(any(usart_v1, usart_v2)))] + if config.de_assertion_time > 31 { + return Err(ConfigError::DeAssertionTimeTooHigh); + } else if config.de_deassertion_time > 31 { + return Err(ConfigError::DeDeassertionTimeTooHigh); + } + // UART must be disabled during configuration. r.cr1().modify(|w| { w.set_ue(false); @@ -1754,6 +1782,20 @@ fn configure( w.set_re(enable_rx); } + #[cfg(not(any(usart_v1, usart_v2)))] + if dem { + w.set_deat(if over8 { + config.de_assertion_time / 2 + } else { + config.de_assertion_time + }); + w.set_dedt(if over8 { + config.de_assertion_time / 2 + } else { + config.de_assertion_time + }); + } + // configure word size and parity, since the parity bit is inserted into the MSB position, // it increases the effective word size match (config.parity, config.data_bits) { -- cgit From ef06ff43a14fd016d271c491bd830823ee96b740 Mon Sep 17 00:00:00 2001 From: Adam Greig Date: Thu, 18 Sep 2025 02:04:05 +0100 Subject: STM32: USART: Make BufferedUartRx return all available bytes when they wrap around the internal buffer end --- embassy-stm32/CHANGELOG.md | 3 +++ embassy-stm32/src/usart/buffered.rs | 37 +++++++++++++++++++++++-------------- 2 files changed, 26 insertions(+), 14 deletions(-) diff --git a/embassy-stm32/CHANGELOG.md b/embassy-stm32/CHANGELOG.md index f4cfc14cc..a6ee5c4b8 100644 --- a/embassy-stm32/CHANGELOG.md +++ b/embassy-stm32/CHANGELOG.md @@ -27,7 +27,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - fix: Cut down the capabilities of the STM32L412 and L422 RTC as those are missing binary timer mode and underflow interrupt. - fix: Allow configuration of the internal pull up/down resistors on the pins for the Qei peripheral, as well as the Qei decoder mode. - feat: stm32/rcc/mco: Added support for IO driver strength when using Master Clock Out IO. This changes signature on Mco::new taking a McoConfig struct ([#4679](https://github.com/embassy-rs/embassy/pull/4679)) +- feat: derive Clone, Copy and defmt::Format for all SPI-related configs - feat: stm32/usart: add `eager_reads` option to control if buffered readers return as soon as possible or after more data is available ([#4668](https://github.com/embassy-rs/embassy/pull/4668)) +- feat: stm32/usart: add `de_assertion_time` and `de_deassertion_time` config options +- change: stm32/uart: BufferedUartRx now returns all available bytes from the internal buffer ## 0.4.0 - 2025-08-26 diff --git a/embassy-stm32/src/usart/buffered.rs b/embassy-stm32/src/usart/buffered.rs index 83aa4439b..165f2e88e 100644 --- a/embassy-stm32/src/usart/buffered.rs +++ b/embassy-stm32/src/usart/buffered.rs @@ -565,24 +565,30 @@ impl<'d> BufferedUartRx<'d> { poll_fn(move |cx| { let state = self.state; let mut rx_reader = unsafe { state.rx_buf.reader() }; - let data = rx_reader.pop_slice(); + let mut buf_len = 0; + let mut data = rx_reader.pop_slice(); - if !data.is_empty() { - let len = data.len().min(buf.len()); - buf[..len].copy_from_slice(&data[..len]); + while !data.is_empty() && buf_len < buf.len() { + let data_len = data.len().min(buf.len() - buf_len); + buf[buf_len..buf_len + data_len].copy_from_slice(&data[..data_len]); + buf_len += data_len; let do_pend = state.rx_buf.is_full(); - rx_reader.pop_done(len); + rx_reader.pop_done(data_len); if do_pend { self.info.interrupt.pend(); } - return Poll::Ready(Ok(len)); + data = rx_reader.pop_slice(); } - state.rx_waker.register(cx.waker()); - Poll::Pending + if buf_len != 0 { + Poll::Ready(Ok(buf_len)) + } else { + state.rx_waker.register(cx.waker()); + Poll::Pending + } }) .await } @@ -591,21 +597,24 @@ impl<'d> BufferedUartRx<'d> { loop { let state = self.state; let mut rx_reader = unsafe { state.rx_buf.reader() }; - let data = rx_reader.pop_slice(); + let mut buf_len = 0; + let mut data = rx_reader.pop_slice(); - if !data.is_empty() { - let len = data.len().min(buf.len()); - buf[..len].copy_from_slice(&data[..len]); + while !data.is_empty() && buf_len < buf.len() { + let data_len = data.len().min(buf.len() - buf_len); + buf[buf_len..buf_len + data_len].copy_from_slice(&data[..data_len]); + buf_len += data_len; let do_pend = state.rx_buf.is_full(); - rx_reader.pop_done(len); + rx_reader.pop_done(data_len); if do_pend { self.info.interrupt.pend(); } - return Ok(len); + data = rx_reader.pop_slice(); } + return Ok(buf_len); } } -- cgit From 775123467b0ce6e5daede0795493df9577077a09 Mon Sep 17 00:00:00 2001 From: Adam Greig Date: Fri, 19 Sep 2025 02:10:56 +0100 Subject: STM32: USART: Change eager_reads from bool to Option --- embassy-hal-internal/src/atomic_ring_buffer.rs | 22 ++++++++------- embassy-stm32/src/usart/buffered.rs | 28 ++++++++++++------- embassy-stm32/src/usart/mod.rs | 37 ++++++++++++++++---------- embassy-stm32/src/usart/ringbuffered.rs | 30 +++++++++++++++------ 4 files changed, 77 insertions(+), 40 deletions(-) diff --git a/embassy-hal-internal/src/atomic_ring_buffer.rs b/embassy-hal-internal/src/atomic_ring_buffer.rs index 7de96e4e2..8c3889b85 100644 --- a/embassy-hal-internal/src/atomic_ring_buffer.rs +++ b/embassy-hal-internal/src/atomic_ring_buffer.rs @@ -133,6 +133,18 @@ impl RingBuffer { self.len.load(Ordering::Relaxed) } + /// Return number of items available to read. + pub fn available(&self) -> usize { + let end = self.end.load(Ordering::Relaxed); + let len = self.len.load(Ordering::Relaxed); + let start = self.start.load(Ordering::Relaxed); + if end >= start { + end - start + } else { + 2 * len - start + end + } + } + /// Check if buffer is full. pub fn is_full(&self) -> bool { let len = self.len.load(Ordering::Relaxed); @@ -144,15 +156,7 @@ impl RingBuffer { /// Check if buffer is at least half full. pub fn is_half_full(&self) -> bool { - let len = self.len.load(Ordering::Relaxed); - let start = self.start.load(Ordering::Relaxed); - let end = self.end.load(Ordering::Relaxed); - let n = if end >= start { - end - start - } else { - 2 * len - start + end - }; - n >= len / 2 + self.available() >= self.len.load(Ordering::Relaxed) / 2 } /// Check if buffer is empty. diff --git a/embassy-stm32/src/usart/buffered.rs b/embassy-stm32/src/usart/buffered.rs index 165f2e88e..10dc02334 100644 --- a/embassy-stm32/src/usart/buffered.rs +++ b/embassy-stm32/src/usart/buffered.rs @@ -1,7 +1,7 @@ use core::future::poll_fn; use core::marker::PhantomData; use core::slice; -use core::sync::atomic::{AtomicBool, AtomicU8, Ordering}; +use core::sync::atomic::{AtomicBool, AtomicU8, AtomicUsize, Ordering}; use core::task::Poll; use embassy_embedded_hal::SetConfig; @@ -68,8 +68,9 @@ unsafe fn on_interrupt(r: Regs, state: &'static State) { // FIXME: Should we disable any further RX interrupts when the buffer becomes full. } - if state.eager_reads.load(Ordering::Relaxed) { - if !state.rx_buf.is_empty() { + let eager = state.eager_reads.load(Ordering::Relaxed); + if eager > 0 { + if state.rx_buf.available() >= eager { state.rx_waker.wake(); } } else { @@ -138,7 +139,7 @@ pub(super) struct State { tx_done: AtomicBool, tx_rx_refcount: AtomicU8, half_duplex_readback: AtomicBool, - eager_reads: AtomicBool, + eager_reads: AtomicUsize, } impl State { @@ -151,7 +152,7 @@ impl State { tx_done: AtomicBool::new(true), tx_rx_refcount: AtomicU8::new(0), half_duplex_readback: AtomicBool::new(false), - eager_reads: AtomicBool::new(false), + eager_reads: AtomicUsize::new(0), } } } @@ -427,7 +428,9 @@ impl<'d> BufferedUart<'d> { let state = T::buffered_state(); let kernel_clock = T::frequency(); - state.eager_reads.store(config.eager_reads, Ordering::Relaxed); + state + .eager_reads + .store(config.eager_reads.unwrap_or(0), Ordering::Relaxed); state.half_duplex_readback.store( config.duplex == Duplex::Half(HalfDuplexReadback::Readback), Ordering::Relaxed, @@ -465,7 +468,9 @@ impl<'d> BufferedUart<'d> { let info = self.rx.info; let state = self.rx.state; state.tx_rx_refcount.store(2, Ordering::Relaxed); - state.eager_reads.store(config.eager_reads, Ordering::Relaxed); + state + .eager_reads + .store(config.eager_reads.unwrap_or(0), Ordering::Relaxed); info.rcc.enable_and_reset(); @@ -537,7 +542,10 @@ impl<'d> BufferedUart<'d> { pub fn set_config(&mut self, config: &Config) -> Result<(), ConfigError> { reconfigure(self.rx.info, self.rx.kernel_clock, config)?; - self.rx.state.eager_reads.store(config.eager_reads, Ordering::Relaxed); + self.rx + .state + .eager_reads + .store(config.eager_reads.unwrap_or(0), Ordering::Relaxed); self.rx.info.regs.cr1().modify(|w| { w.set_rxneie(true); @@ -654,7 +662,9 @@ impl<'d> BufferedUartRx<'d> { pub fn set_config(&mut self, config: &Config) -> Result<(), ConfigError> { reconfigure(self.info, self.kernel_clock, config)?; - self.state.eager_reads.store(config.eager_reads, Ordering::Relaxed); + self.state + .eager_reads + .store(config.eager_reads.unwrap_or(0), Ordering::Relaxed); self.info.regs.cr1().modify(|w| { w.set_rxneie(true); diff --git a/embassy-stm32/src/usart/mod.rs b/embassy-stm32/src/usart/mod.rs index c8012a9b4..0d2d86aca 100644 --- a/embassy-stm32/src/usart/mod.rs +++ b/embassy-stm32/src/usart/mod.rs @@ -4,7 +4,7 @@ use core::future::poll_fn; use core::marker::PhantomData; -use core::sync::atomic::{compiler_fence, AtomicBool, AtomicU8, Ordering}; +use core::sync::atomic::{compiler_fence, AtomicU8, AtomicUsize, Ordering}; use core::task::Poll; use embassy_embedded_hal::SetConfig; @@ -212,17 +212,20 @@ pub struct Config { /// If false: the error is ignored and cleared pub detect_previous_overrun: bool, - /// If true then read-like calls on `BufferedUartRx` and `RingBufferedUartRx` - /// are woken/return as soon as any data is available in the buffer. + /// If `None` (the default) then read-like calls on `BufferedUartRx` and `RingBufferedUartRx` + /// typically only wake/return after line idle or after the buffer is at least half full + /// (for `BufferedUartRx`) or the DMA buffer is written at the half or full positions + /// (for `RingBufferedUartRx`), though it may also wake/return earlier in some circumstances. /// - /// If false (the default) then reads started typically only wake/return after - /// line idle or after the buffer is at least half full (`BufferedUartRx`) or - /// the DMA buffer is written at the half or full positions (`RingBufferedUartRx`), - /// though it may also wake/return earlier in some circumstances. + /// If `Some(n)` then such reads are also woken/return as soon as at least `n` words are + /// available in the buffer, in addition to waking/returning when the conditions described + /// above are met. `Some(0)` is treated as `None`. Setting this for `RingBufferedUartRx` + /// will trigger an interrupt for every received word to check the buffer level, which may + /// impact performance at high data rates. /// /// Has no effect on plain `Uart` or `UartRx` reads, which are specified to either /// return a single word, a full buffer, or after line idle. - pub eager_reads: bool, + pub eager_reads: Option, /// Set this to true if the line is considered noise free. /// This will increase the receiver’s tolerance to clock deviations, @@ -296,7 +299,7 @@ impl Default for Config { parity: Parity::ParityNone, // historical behavior detect_previous_overrun: false, - eager_reads: false, + eager_reads: None, #[cfg(not(usart_v1))] assume_noise_free: false, #[cfg(any(usart_v3, usart_v4))] @@ -997,7 +1000,9 @@ impl<'d, M: Mode> UartRx<'d, M> { let info = self.info; let state = self.state; state.tx_rx_refcount.store(1, Ordering::Relaxed); - state.eager_reads.store(config.eager_reads, Ordering::Relaxed); + state + .eager_reads + .store(config.eager_reads.unwrap_or(0), Ordering::Relaxed); info.rcc.enable_and_reset(); @@ -1014,7 +1019,9 @@ impl<'d, M: Mode> UartRx<'d, M> { /// Reconfigure the driver pub fn set_config(&mut self, config: &Config) -> Result<(), ConfigError> { - self.state.eager_reads.store(config.eager_reads, Ordering::Relaxed); + self.state + .eager_reads + .store(config.eager_reads.unwrap_or(0), Ordering::Relaxed); reconfigure(self.info, self.kernel_clock, config) } @@ -1495,7 +1502,9 @@ impl<'d, M: Mode> Uart<'d, M> { let info = self.rx.info; let state = self.rx.state; state.tx_rx_refcount.store(2, Ordering::Relaxed); - state.eager_reads.store(config.eager_reads, Ordering::Relaxed); + state + .eager_reads + .store(config.eager_reads.unwrap_or(0), Ordering::Relaxed); info.rcc.enable_and_reset(); @@ -2080,7 +2089,7 @@ struct State { rx_waker: AtomicWaker, tx_waker: AtomicWaker, tx_rx_refcount: AtomicU8, - eager_reads: AtomicBool, + eager_reads: AtomicUsize, } impl State { @@ -2089,7 +2098,7 @@ impl State { rx_waker: AtomicWaker::new(), tx_waker: AtomicWaker::new(), tx_rx_refcount: AtomicU8::new(0), - eager_reads: AtomicBool::new(false), + eager_reads: AtomicUsize::new(0), } } } diff --git a/embassy-stm32/src/usart/ringbuffered.rs b/embassy-stm32/src/usart/ringbuffered.rs index d818e0bcc..27071fb31 100644 --- a/embassy-stm32/src/usart/ringbuffered.rs +++ b/embassy-stm32/src/usart/ringbuffered.rs @@ -132,7 +132,9 @@ impl<'d> UartRx<'d, Async> { impl<'d> RingBufferedUartRx<'d> { /// Reconfigure the driver pub fn set_config(&mut self, config: &Config) -> Result<(), ConfigError> { - self.state.eager_reads.store(config.eager_reads, Ordering::Relaxed); + self.state + .eager_reads + .store(config.eager_reads.unwrap_or(0), Ordering::Relaxed); reconfigure(self.info, self.kernel_clock, config) } @@ -149,7 +151,7 @@ impl<'d> RingBufferedUartRx<'d> { // clear all interrupts and DMA Rx Request r.cr1().modify(|w| { // use RXNE only when returning reads early - w.set_rxneie(self.state.eager_reads.load(Ordering::Relaxed)); + w.set_rxneie(self.state.eager_reads.load(Ordering::Relaxed) > 0); // enable parity interrupt if not ParityNone w.set_peie(w.pce()); // enable idle line interrupt @@ -261,11 +263,12 @@ impl<'d> RingBufferedUartRx<'d> { // However, DMA will clear RXNE, so we can't check directly, and because // the other future borrows `ring_buf`, we can't check `len()` here either. // Instead, return from this future and we'll check the length afterwards. - let eager = s.eager_reads.load(Ordering::Relaxed); + let eager = s.eager_reads.load(Ordering::Relaxed) > 0; - if check_idle_and_errors(self.info.regs)? || (eager && uart_init) { + let idle = check_idle_and_errors(self.info.regs)?; + if idle || (eager && uart_init) { // Idle line is detected, or eager reads is set and some data is available. - Poll::Ready(Ok(())) + Poll::Ready(Ok(idle)) } else { uart_init = true; Poll::Pending @@ -288,13 +291,24 @@ impl<'d> RingBufferedUartRx<'d> { }); match select(uart, dma).await { - Either::Left((result, _)) => { - if self.ring_buf.len().unwrap_or(0) > 0 || result.is_err() { - return result; + // UART woke with line idle + Either::Left((Ok(true), _)) => { + return Ok(()); + } + // UART woke without idle or error: word received + Either::Left((Ok(false), _)) => { + let eager = self.state.eager_reads.load(Ordering::Relaxed); + if eager > 0 && self.ring_buf.len().unwrap_or(0) >= eager { + return Ok(()); } else { continue; } } + // UART woke with error + Either::Left((Err(e), _)) => { + return Err(e); + } + // DMA woke Either::Right(((), _)) => return Ok(()), } } -- cgit From c0d3507728e424567a63cc8ba8989b981ee02be4 Mon Sep 17 00:00:00 2001 From: Robin Mueller Date: Thu, 2 Oct 2025 10:04:47 +0200 Subject: bump cortex-ar to v0.3 --- embassy-executor/CHANGELOG.md | 1 + embassy-executor/Cargo.toml | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/embassy-executor/CHANGELOG.md b/embassy-executor/CHANGELOG.md index 6f079a11a..47a8ae995 100644 --- a/embassy-executor/CHANGELOG.md +++ b/embassy-executor/CHANGELOG.md @@ -13,6 +13,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Upgraded rtos-trace - Added optional "highest priority" scheduling - Added optional "earliest deadline first" EDF scheduling +- Bump `cortex-ar` to v0.3 ## 0.9.1 - 2025-08-31 diff --git a/embassy-executor/Cargo.toml b/embassy-executor/Cargo.toml index 61d060630..6d11bc076 100644 --- a/embassy-executor/Cargo.toml +++ b/embassy-executor/Cargo.toml @@ -98,7 +98,7 @@ portable-atomic = { version = "1.5", optional = true } cortex-m = { version = "0.7.6", optional = true } # arch-cortex-ar dependencies -cortex-ar = { version = "0.2", optional = true } +cortex-ar = { version = "0.3", optional = true } # arch-wasm dependencies wasm-bindgen = { version = "0.2.82", optional = true } -- cgit From 99ec24162aab51feb661b709a869ce64a30cfef1 Mon Sep 17 00:00:00 2001 From: 1-rafael-1 Date: Sat, 4 Oct 2025 16:19:46 +0200 Subject: Add Air Quality Monitor project to Embassy in the Wild page --- docs/pages/embassy_in_the_wild.adoc | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/docs/pages/embassy_in_the_wild.adoc b/docs/pages/embassy_in_the_wild.adoc index cedbedada..3b58bb9b4 100644 --- a/docs/pages/embassy_in_the_wild.adoc +++ b/docs/pages/embassy_in_the_wild.adoc @@ -4,6 +4,8 @@ Here are known examples of real-world projects which make use of Embassy. Feel f _newer entries at the top_ +* link:https://github.com/1-rafael-1/air-quality-monitor[Air Quality Monitor] +** Air Quality Monitor based on rp2350 board, ens160 and aht21 sensors and ssd1306 display. Code and 3D printable enclosure included. * link:https://github.com/CarlKCarlK/clock[Embassy Clock: Layered, modular bare-metal clock with emulation] ** A `no_std` Raspberry Pi Pico clock demonstrating layered Embassy tasks (Display->Blinker->Clock) for clean separation of multiplexing, blinking, and UI logic. Features single-button HH:MM/MM:SS time-set UI, heapless data structures, and a Renode emulator for hardware-free testing. See link:https://medium.com/@carlmkadie/how-rust-embassy-shine-on-embedded-devices-part-2-aad1adfccf72[this article] for details. * link:https://github.com/1-rafael-1/simple-robot[A simple tracked robot based on Raspberry Pi Pico 2] @@ -11,7 +13,7 @@ _newer entries at the top_ * link:https://github.com/1-rafael-1/pi-pico-alarmclock-rust[A Raspberry Pi Pico W Alarmclock] ** A hobbyist project building an alarm clock around a Pi Pico W complete with code, components list and enclosure design files. * link:https://github.com/haobogu/rmk/[RMK: A feature-rich Rust keyboard firmware] -** RMK has built-in layer support, wireless(BLE) support, real-time key editing support using vial, and more! +** RMK has built-in layer support, wireless(BLE) support, real-time key editing support using vial, and more! ** Targets STM32, RP2040, nRF52 and ESP32 MCUs * link:https://github.com/cbruiz/printhor/[Printhor: The highly reliable but not necessarily functional 3D printer firmware] ** Targets some STM32 MCUs @@ -21,10 +23,9 @@ _newer entries at the top_ * link:https://github.com/matoushybl/air-force-one[Air force one: A simple air quality monitoring system] ** Targets nRF52 and uses nrf-softdevice -* link:https://github.com/schmettow/ylab-edge-go[YLab Edge Go] and link:https://github.com/schmettow/ylab-edge-pro[YLab Edge Pro] projects develop +* link:https://github.com/schmettow/ylab-edge-go[YLab Edge Go] and link:https://github.com/schmettow/ylab-edge-pro[YLab Edge Pro] projects develop firmware (RP2040, STM32) for capturing physiological data in behavioural science research. Included so far are: ** biopotentials (analog ports) ** motion capture (6-axis accelerometers) ** air quality (CO2, Temp, Humidity) ** comes with an app for capturing and visualizing data [link:https://github.com/schmettow/ystudio-zero[Ystudio]] - -- cgit From c0fd86d6c68ec5f66a4cd5a5ef36bcda7b9e1c0e Mon Sep 17 00:00:00 2001 From: Matthew Tran <0e4ef622@gmail.com> Date: Sun, 5 Oct 2025 03:16:18 -0500 Subject: nrf: apply FICR.TRIMCNF values --- embassy-nrf/CHANGELOG.md | 1 + embassy-nrf/src/chips/nrf54l15_app.rs | 1 + embassy-nrf/src/lib.rs | 64 +++++++++++++++++----- embassy-nrf/src/radio/ieee802154.rs | 17 ++++++ .../nrf5340/src/bin/nrf5340dk_internal_caps.rs | 30 ++++++++++ 5 files changed, 100 insertions(+), 13 deletions(-) create mode 100644 examples/nrf5340/src/bin/nrf5340dk_internal_caps.rs diff --git a/embassy-nrf/CHANGELOG.md b/embassy-nrf/CHANGELOG.md index b3d4045fa..0244dedab 100644 --- a/embassy-nrf/CHANGELOG.md +++ b/embassy-nrf/CHANGELOG.md @@ -7,6 +7,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## Unreleased - ReleaseDate +- changed: apply trimming values from FICR.TRIMCNF on nrf53/54l ## 0.8.0 - 2025-09-30 diff --git a/embassy-nrf/src/chips/nrf54l15_app.rs b/embassy-nrf/src/chips/nrf54l15_app.rs index ff05bbec0..82d30104f 100644 --- a/embassy-nrf/src/chips/nrf54l15_app.rs +++ b/embassy-nrf/src/chips/nrf54l15_app.rs @@ -94,6 +94,7 @@ pub mod pac { #[cfg(feature = "_s")] #[doc(no_inline)] pub use nrf_pac::{ + FICR_NS as FICR, SICR_S as SICR, ICACHEDATA_S as ICACHEDATA, ICACHEINFO_S as ICACHEINFO, diff --git a/embassy-nrf/src/lib.rs b/embassy-nrf/src/lib.rs index 7c26a6184..716eec961 100644 --- a/embassy-nrf/src/lib.rs +++ b/embassy-nrf/src/lib.rs @@ -406,9 +406,10 @@ pub mod config { /// Settings for the internal capacitors. #[cfg(feature = "nrf5340-app-s")] pub struct InternalCapacitors { - /// Config for the internal capacitors on pins XC1 and XC2. + /// Config for the internal capacitors on pins XC1 and XC2. Pass `None` to not touch it. pub hfxo: Option, - /// Config for the internal capacitors between pins XL1 and XL2. + /// Config for the internal capacitors between pins XL1 and XL2. Pass `None` to not touch + /// it. pub lfxo: Option, } @@ -416,6 +417,8 @@ pub mod config { #[cfg(feature = "nrf5340-app-s")] #[derive(Copy, Clone)] pub enum HfxoCapacitance { + /// Use external capacitors + External, /// 7.0 pF _7_0pF, /// 7.5 pF @@ -475,8 +478,9 @@ pub mod config { #[cfg(feature = "nrf5340-app-s")] impl HfxoCapacitance { /// The capacitance value times two. - pub(crate) const fn value2(self) -> i32 { + pub(crate) fn value2(self) -> i32 { match self { + HfxoCapacitance::External => unreachable!(), HfxoCapacitance::_7_0pF => 14, HfxoCapacitance::_7_5pF => 15, HfxoCapacitance::_8_0pF => 16, @@ -506,11 +510,17 @@ pub mod config { HfxoCapacitance::_20_0pF => 40, } } + + pub(crate) fn external(self) -> bool { + matches!(self, Self::External) + } } /// Internal capacitance value for the LFXO. #[cfg(feature = "nrf5340-app-s")] pub enum LfxoCapacitance { + /// Use external capacitors + External = 0, /// 6 pF _6pF = 1, /// 7 pF @@ -523,6 +533,7 @@ pub mod config { impl From for super::pac::oscillators::vals::Intcap { fn from(t: LfxoCapacitance) -> Self { match t { + LfxoCapacitance::External => Self::EXTERNAL, LfxoCapacitance::_6pF => Self::C6PF, LfxoCapacitance::_7pF => Self::C7PF, LfxoCapacitance::_9pF => Self::C9PF, @@ -720,6 +731,29 @@ pub fn init(config: config::Config) -> Peripherals { } } + // Apply trimming values from the FICR. + #[cfg(any( + all(feature = "_nrf5340-app", feature = "_s"), + all(feature = "_nrf54l", feature = "_s"), + feature = "_nrf5340-net", + ))] + { + #[cfg(feature = "_nrf5340")] + let n = 32; + #[cfg(feature = "_nrf54l")] + let n = 64; + for i in 0..n { + let info = pac::FICR.trimcnf(i); + let addr = info.addr().read(); + if addr == 0 || addr == 0xFFFF_FFFF { + break; + } + unsafe { + (addr as *mut u32).write_volatile(info.data().read()); + } + } + } + // GLITCHDET is only accessible for secure code #[cfg(all(feature = "_nrf54l", feature = "_s"))] { @@ -953,17 +987,21 @@ pub fn init(config: config::Config) -> Peripherals { #[cfg(feature = "nrf5340-app-s")] { if let Some(cap) = config.internal_capacitors.hfxo { - let mut slope = pac::FICR.xosc32mtrim().read().slope() as i32; - let offset = pac::FICR.xosc32mtrim().read().offset() as i32; - // slope is a signed 5-bit integer - if slope >= 16 { - slope -= 32; + if cap.external() { + pac::OSCILLATORS.xosc32mcaps().write(|w| w.set_enable(false)); + } else { + let mut slope = pac::FICR.xosc32mtrim().read().slope() as i32; + let offset = pac::FICR.xosc32mtrim().read().offset() as i32; + // slope is a signed 5-bit integer + if slope >= 16 { + slope -= 32; + } + let capvalue = (((slope + 56) * (cap.value2() - 14)) + ((offset - 8) << 4) + 32) >> 6; + pac::OSCILLATORS.xosc32mcaps().write(|w| { + w.set_capvalue(capvalue as u8); + w.set_enable(true); + }); } - let capvalue = (((slope + 56) * (cap.value2() - 14)) + ((offset - 8) << 4) + 32) >> 6; - pac::OSCILLATORS.xosc32mcaps().write(|w| { - w.set_capvalue(capvalue as u8); - w.set_enable(true); - }); } if let Some(cap) = config.internal_capacitors.lfxo { pac::OSCILLATORS.xosc32ki().intcap().write(|w| w.set_intcap(cap.into())); diff --git a/embassy-nrf/src/radio/ieee802154.rs b/embassy-nrf/src/radio/ieee802154.rs index 62af03a5a..844d3551e 100644 --- a/embassy-nrf/src/radio/ieee802154.rs +++ b/embassy-nrf/src/radio/ieee802154.rs @@ -52,6 +52,7 @@ impl<'d> Radio<'d> { // Disable and enable to reset peripheral r.power().write(|w| w.set_power(false)); r.power().write(|w| w.set_power(true)); + errata::post_power(); // Enable 802.15.4 mode r.mode().write(|w| w.set_mode(vals::Mode::IEEE802154_250KBIT)); @@ -541,3 +542,19 @@ fn dma_start_fence() { fn dma_end_fence() { compiler_fence(Ordering::Acquire); } + +mod errata { + pub fn post_power() { + // Workaround for anomaly 158 + #[cfg(feature = "_nrf5340-net")] + for i in 0..32 { + let info = crate::pac::FICR.trimcnf(i); + let addr = info.addr().read(); + if addr & 0xFFFF_F000 == crate::pac::RADIO.as_ptr() as u32 { + unsafe { + (addr as *mut u32).write_volatile(info.data().read()); + } + } + } + } +} diff --git a/examples/nrf5340/src/bin/nrf5340dk_internal_caps.rs b/examples/nrf5340/src/bin/nrf5340dk_internal_caps.rs new file mode 100644 index 000000000..0b1fb852e --- /dev/null +++ b/examples/nrf5340/src/bin/nrf5340dk_internal_caps.rs @@ -0,0 +1,30 @@ +#![no_std] +#![no_main] + +use defmt::info; +use embassy_executor::Spawner; +use embassy_nrf::config::{Config, HfclkSource, LfclkSource, LfxoCapacitance}; +use embassy_nrf::pac; +use {defmt_rtt as _, panic_probe as _}; + +fn print_xosc32mcaps() { + let value = pac::OSCILLATORS.xosc32mcaps().read(); + info!("XOSC32MCAPS.ENABLE = {}", value.enable()); + info!("XOSC32MCAPS.CAPVALUE = {}", value.capvalue()); +} + +#[embassy_executor::main] +async fn main(_spawner: Spawner) { + info!("Before init:"); + print_xosc32mcaps(); + + let mut config = Config::default(); + config.hfclk_source = HfclkSource::Internal; + config.lfclk_source = LfclkSource::ExternalXtal; + config.internal_capacitors.hfxo = None; // keep the value from the FICR + config.internal_capacitors.lfxo = Some(LfxoCapacitance::_7pF); + let _p = embassy_nrf::init(config); + + info!("After init:"); + print_xosc32mcaps(); +} -- cgit From 5046a8a4a117f68c2792fac8dbbdb50fb0b1e3d8 Mon Sep 17 00:00:00 2001 From: maor malka Date: Mon, 6 Oct 2025 07:50:48 -0400 Subject: stm32/adc/v3: * spelling mistakes fixed * added required changes to ringbufferedadc to support G0 --- embassy-stm32/CHANGELOG.md | 2 +- embassy-stm32/src/adc/ringbuffered_v3.rs | 18 +++++++++--------- embassy-stm32/src/adc/v3.rs | 11 ++++++++--- 3 files changed, 18 insertions(+), 13 deletions(-) diff --git a/embassy-stm32/CHANGELOG.md b/embassy-stm32/CHANGELOG.md index b661e0bae..6e069b22d 100644 --- a/embassy-stm32/CHANGELOG.md +++ b/embassy-stm32/CHANGELOG.md @@ -43,7 +43,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - chore: Updated stm32-metapac and stm32-data dependencies - feat: stm32/adc/v3: allow DMA reads to loop through enable channels - fix: Fix XSPI not disabling alternate bytes when they were previously enabled -- feat: stm32/adc/v3: added support for Continous DMA configuration +- feat: stm32/adc/v3: added support for Continuous DMA configuration - fix: Fix stm32h7rs init when using external flash via XSPI - feat: Add Adc::new_with_clock() to configure analog clock - feat: Add GPDMA linked-list + ringbuffer support ([#3923](https://github.com/embassy-rs/embassy/pull/3923)) diff --git a/embassy-stm32/src/adc/ringbuffered_v3.rs b/embassy-stm32/src/adc/ringbuffered_v3.rs index d7af2322d..a2c9f2bca 100644 --- a/embassy-stm32/src/adc/ringbuffered_v3.rs +++ b/embassy-stm32/src/adc/ringbuffered_v3.rs @@ -37,7 +37,7 @@ impl<'d, T: Instance> RingBufferedAdc<'d, T> { } #[inline] - fn start_continous_sampling(&mut self) { + fn start_continuous_sampling(&mut self) { // Start adc conversion T::regs().cr().modify(|reg| { reg.set_adstart(true); @@ -46,7 +46,7 @@ impl<'d, T: Instance> RingBufferedAdc<'d, T> { } #[inline] - pub fn stop_continous_sampling(&mut self) { + pub fn stop_continuous_sampling(&mut self) { // Stop adc conversion if T::regs().cr().read().adstart() && !T::regs().cr().read().addis() { T::regs().cr().modify(|reg| { @@ -56,7 +56,7 @@ impl<'d, T: Instance> RingBufferedAdc<'d, T> { } } pub fn disable_adc(&mut self) { - self.stop_continous_sampling(); + self.stop_continuous_sampling(); self.ring_buf.clear(); self.ring_buf.request_pause(); } @@ -123,7 +123,7 @@ impl<'d, T: Instance> RingBufferedAdc<'d, T> { /// /// /// [`teardown_adc`]: #method.teardown_adc - /// [`start_continous_sampling`]: #method.start_continous_sampling + /// [`start_continuous_sampling`]: #method.start_continuous_sampling pub async fn read(&mut self, measurements: &mut [u16]) -> Result { assert_eq!( self.ring_buf.capacity() / 2, @@ -135,7 +135,7 @@ impl<'d, T: Instance> RingBufferedAdc<'d, T> { // Start background receive if it was not already started if !r.cr().read().adstart() { - self.start_continous_sampling(); + self.start_continuous_sampling(); } self.ring_buf.read_exact(measurements).await.map_err(|_| OverrunError) @@ -145,16 +145,16 @@ impl<'d, T: Instance> RingBufferedAdc<'d, T> { /// If no bytes are currently available in the buffer the call waits until the some /// bytes are available (at least one byte and at most half the buffer size) /// - /// Background receive is started if `start_continous_sampling()` has not been previously called. + /// Background receive is started if `start_continuous_sampling()` has not been previously called. /// /// Receive in the background is terminated if an error is returned. - /// It must then manually be started again by calling `start_continous_sampling()` or by re-calling `blocking_read()`. + /// It must then manually be started again by calling `start_continuous_sampling()` or by re-calling `blocking_read()`. pub fn blocking_read(&mut self, buf: &mut [u16]) -> Result { let r = T::regs(); // Start background receive if it was not already started if !r.cr().read().adstart() { - self.start_continous_sampling(); + self.start_continuous_sampling(); } loop { @@ -164,7 +164,7 @@ impl<'d, T: Instance> RingBufferedAdc<'d, T> { return Ok(len); } Err(_) => { - self.stop_continous_sampling(); + self.stop_continuous_sampling(); return Err(OverrunError); } } diff --git a/embassy-stm32/src/adc/v3.rs b/embassy-stm32/src/adc/v3.rs index f714e030f..ef68fe223 100644 --- a/embassy-stm32/src/adc/v3.rs +++ b/embassy-stm32/src/adc/v3.rs @@ -13,10 +13,10 @@ use super::{ blocking_delay_us, Adc, AdcChannel, AnyAdcChannel, Instance, Resolution, RxDma, SampleTime, SealedAdcChannel, }; -#[cfg(adc_v3)] +#[cfg(adc_v3, adc_g0)] mod ringbuffered_v3; -#[cfg(adc_v3)] +#[cfg(adc_v3, adc_g0)] use ringbuffered_v3::RingBufferedAdc; use crate::dma::Transfer; @@ -576,7 +576,7 @@ impl<'d, T: Instance> Adc<'d, T> { /// It is critical to call `read` frequently to prevent DMA buffer overrun. /// /// [`read`]: #method.read - #[cfg(adc_v3)] + #[cfg(adc_v3, adc_g0)] pub fn into_ring_buffered<'a>( &mut self, dma: Peri<'a, impl RxDma>, @@ -633,6 +633,11 @@ impl<'d, T: Instance> Adc<'d, T> { } _ => unreachable!(), } + + #[cfg(any(adc_g0, adc_u0))] + { + channel_mask |= 1 << channel.channel(); + } } // On G0 and U0 enabled channels are sampled from 0 to last channel. -- cgit From 0a97a1d6536be20e8aea1da2d7a6dcd16ca679d4 Mon Sep 17 00:00:00 2001 From: maor malka Date: Mon, 6 Oct 2025 07:56:20 -0400 Subject: stm32/adc/v3: syntax errors :( --- embassy-stm32/src/adc/v3.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/embassy-stm32/src/adc/v3.rs b/embassy-stm32/src/adc/v3.rs index ef68fe223..39f9ee463 100644 --- a/embassy-stm32/src/adc/v3.rs +++ b/embassy-stm32/src/adc/v3.rs @@ -13,10 +13,10 @@ use super::{ blocking_delay_us, Adc, AdcChannel, AnyAdcChannel, Instance, Resolution, RxDma, SampleTime, SealedAdcChannel, }; -#[cfg(adc_v3, adc_g0)] +#[cfg(any(adc_v3, adc_g0))] mod ringbuffered_v3; -#[cfg(adc_v3, adc_g0)] +#[cfg(any(adc_v3, adc_g0))] use ringbuffered_v3::RingBufferedAdc; use crate::dma::Transfer; @@ -576,7 +576,7 @@ impl<'d, T: Instance> Adc<'d, T> { /// It is critical to call `read` frequently to prevent DMA buffer overrun. /// /// [`read`]: #method.read - #[cfg(adc_v3, adc_g0)] + #[cfg(any(adc_v3, adc_g0))] pub fn into_ring_buffered<'a>( &mut self, dma: Peri<'a, impl RxDma>, -- cgit From abc8e450f936567ad42cb34b5d2a7941b206aa5d Mon Sep 17 00:00:00 2001 From: Dario Nieuwenhuis Date: Mon, 6 Oct 2025 22:55:38 +0200 Subject: Edition 2024. --- .github/ci/build-nightly.sh | 2 +- .github/ci/build-xtensa.sh | 2 +- .github/ci/build.sh | 2 +- .github/ci/doc.sh | 2 +- .github/ci/janitor.sh | 2 +- .github/ci/rustfmt.sh | 2 +- cyw43-pio/Cargo.toml | 2 +- cyw43/Cargo.toml | 2 +- cyw43/src/lib.rs | 1 + .../layer-by-layer/blinky-async/Cargo.toml | 2 +- docs/examples/layer-by-layer/blinky-hal/Cargo.toml | 2 +- docs/examples/layer-by-layer/blinky-irq/Cargo.toml | 2 +- docs/examples/layer-by-layer/blinky-pac/Cargo.toml | 2 +- embassy-boot-nrf/Cargo.toml | 2 +- embassy-boot-nrf/src/lib.rs | 1 + embassy-boot-rp/Cargo.toml | 2 +- embassy-boot-rp/src/lib.rs | 1 + embassy-boot-stm32/Cargo.toml | 2 +- embassy-boot-stm32/src/lib.rs | 1 + embassy-boot/Cargo.toml | 2 +- embassy-boot/src/boot_loader.rs | 2 +- embassy-boot/src/firmware_updater/asynch.rs | 2 +- embassy-boot/src/firmware_updater/blocking.rs | 2 +- embassy-boot/src/lib.rs | 1 + embassy-embedded-hal/Cargo.toml | 2 +- embassy-executor-macros/Cargo.toml | 2 +- embassy-executor-macros/src/macros/main.rs | 2 +- embassy-executor-timer-queue/Cargo.toml | 2 +- embassy-executor/Cargo.toml | 4 +- embassy-executor/src/arch/avr.rs | 2 +- embassy-executor/src/arch/cortex_ar.rs | 2 +- embassy-executor/src/arch/cortex_m.rs | 2 +- embassy-executor/src/arch/riscv32.rs | 2 +- embassy-executor/src/arch/spin.rs | 2 +- embassy-executor/src/arch/std.rs | 2 +- embassy-executor/src/arch/wasm.rs | 2 +- embassy-executor/src/lib.rs | 1 + embassy-executor/src/raw/mod.rs | 6 +-- embassy-executor/src/raw/waker_turbo.rs | 2 +- embassy-executor/tests/test.rs | 2 +- embassy-executor/tests/ui/task_safety_attribute.rs | 2 +- embassy-futures/Cargo.toml | 2 +- embassy-hal-internal/Cargo.toml | 2 +- embassy-hal-internal/src/lib.rs | 1 + embassy-hal-internal/src/macros.rs | 2 +- embassy-imxrt/Cargo.toml | 2 +- embassy-imxrt/src/lib.rs | 3 +- embassy-mspm0/Cargo.toml | 2 +- embassy-mspm0/build.rs | 2 +- embassy-mspm0/src/gpio.rs | 6 +-- embassy-mspm0/src/lib.rs | 3 +- embassy-net-adin1110/Cargo.toml | 2 +- embassy-net-driver-channel/Cargo.toml | 2 +- embassy-net-driver/Cargo.toml | 2 +- embassy-net-driver/src/lib.rs | 1 + embassy-net-enc28j60/Cargo.toml | 2 +- embassy-net-esp-hosted/Cargo.toml | 2 +- embassy-net-nrf91/Cargo.toml | 2 +- embassy-net-nrf91/src/lib.rs | 1 + embassy-net-ppp/Cargo.toml | 2 +- embassy-net-tuntap/Cargo.toml | 2 +- embassy-net-wiznet/Cargo.toml | 2 +- embassy-net/Cargo.toml | 2 +- embassy-net/src/lib.rs | 1 + embassy-nrf/Cargo.toml | 2 +- embassy-nrf/src/lib.rs | 3 +- embassy-nxp/Cargo.toml | 2 +- embassy-nxp/src/lib.rs | 3 +- embassy-rp/Cargo.toml | 6 +-- embassy-rp/src/bootsel.rs | 2 +- embassy-rp/src/flash.rs | 6 +-- embassy-rp/src/intrinsics.rs | 6 +-- embassy-rp/src/lib.rs | 14 +++--- embassy-rp/src/multicore.rs | 5 +-- embassy-rp/src/psram.rs | 8 ++-- embassy-stm32-wpan/Cargo.toml | 2 +- embassy-stm32-wpan/src/lib.rs | 1 + embassy-stm32-wpan/src/tables.rs | 50 +++++++++++----------- embassy-stm32/Cargo.toml | 2 +- embassy-stm32/src/lib.rs | 5 ++- embassy-sync/Cargo.toml | 2 +- embassy-sync/src/lib.rs | 1 + embassy-time-driver/Cargo.toml | 2 +- embassy-time-driver/src/lib.rs | 8 ++-- embassy-time-queue-utils/Cargo.toml | 2 +- embassy-time/Cargo.toml | 2 +- embassy-time/src/lib.rs | 1 + embassy-usb-dfu/Cargo.toml | 2 +- embassy-usb-driver/Cargo.toml | 2 +- embassy-usb-driver/src/lib.rs | 1 + embassy-usb-logger/Cargo.toml | 2 +- embassy-usb-synopsys-otg/Cargo.toml | 2 +- embassy-usb-synopsys-otg/src/lib.rs | 1 + embassy-usb/Cargo.toml | 2 +- embassy-usb/src/lib.rs | 1 + examples/boot/application/nrf/Cargo.toml | 2 +- examples/boot/application/rp/Cargo.toml | 2 +- examples/boot/application/stm32f3/Cargo.toml | 2 +- examples/boot/application/stm32f7/Cargo.toml | 2 +- examples/boot/application/stm32h7/Cargo.toml | 2 +- examples/boot/application/stm32l0/Cargo.toml | 2 +- examples/boot/application/stm32l1/Cargo.toml | 2 +- examples/boot/application/stm32l4/Cargo.toml | 2 +- examples/boot/application/stm32wb-dfu/Cargo.toml | 2 +- examples/boot/application/stm32wba-dfu/Cargo.toml | 2 +- examples/boot/application/stm32wl/Cargo.toml | 2 +- examples/boot/bootloader/nrf/Cargo.toml | 2 +- examples/boot/bootloader/nrf/src/main.rs | 6 +-- examples/boot/bootloader/rp/Cargo.toml | 2 +- examples/boot/bootloader/rp/src/main.rs | 6 +-- .../boot/bootloader/stm32-dual-bank/Cargo.toml | 2 +- .../boot/bootloader/stm32-dual-bank/src/main.rs | 6 +-- examples/boot/bootloader/stm32/Cargo.toml | 2 +- examples/boot/bootloader/stm32/src/main.rs | 6 +-- examples/boot/bootloader/stm32wb-dfu/Cargo.toml | 2 +- examples/boot/bootloader/stm32wb-dfu/src/main.rs | 6 +-- examples/boot/bootloader/stm32wba-dfu/Cargo.toml | 2 +- examples/boot/bootloader/stm32wba-dfu/src/main.rs | 6 +-- examples/lpc55s69/Cargo.toml | 2 +- examples/mimxrt1011/Cargo.toml | 2 +- examples/mimxrt1011/src/lib.rs | 2 +- examples/mimxrt1062-evk/Cargo.toml | 2 +- examples/mimxrt1062-evk/src/lib.rs | 4 +- examples/mimxrt6/Cargo.toml | 2 +- examples/mspm0c1104/Cargo.toml | 2 +- examples/mspm0g3507/Cargo.toml | 2 +- examples/mspm0g3519/Cargo.toml | 2 +- examples/mspm0l1306/Cargo.toml | 2 +- examples/mspm0l2228/Cargo.toml | 2 +- examples/nrf-rtos-trace/Cargo.toml | 2 +- examples/nrf51/Cargo.toml | 2 +- examples/nrf52810/Cargo.toml | 2 +- examples/nrf52840-edf/Cargo.toml | 2 +- examples/nrf52840-rtic/Cargo.toml | 2 +- examples/nrf52840/Cargo.toml | 2 +- examples/nrf52840/src/bin/multiprio.rs | 4 +- examples/nrf52840/src/bin/raw_spawn.rs | 2 +- examples/nrf5340/Cargo.toml | 2 +- examples/nrf54l15/Cargo.toml | 2 +- examples/nrf9151/ns/Cargo.toml | 2 +- examples/nrf9151/s/Cargo.toml | 2 +- examples/nrf9160/Cargo.toml | 2 +- examples/nrf9160/src/bin/modem_tcp_client.rs | 2 +- examples/rp/Cargo.toml | 2 +- examples/rp/src/bin/multiprio.rs | 4 +- examples/rp/src/bin/sharing.rs | 2 +- examples/rp235x/Cargo.toml | 2 +- examples/rp235x/src/bin/multiprio.rs | 4 +- examples/rp235x/src/bin/sharing.rs | 2 +- examples/std/Cargo.toml | 2 +- examples/stm32c0/Cargo.toml | 2 +- examples/stm32f0/Cargo.toml | 2 +- examples/stm32f0/src/bin/multiprio.rs | 4 +- examples/stm32f1/Cargo.toml | 2 +- examples/stm32f2/Cargo.toml | 2 +- examples/stm32f3/Cargo.toml | 2 +- examples/stm32f3/src/bin/multiprio.rs | 4 +- examples/stm32f334/Cargo.toml | 2 +- examples/stm32f4/Cargo.toml | 2 +- examples/stm32f4/src/bin/multiprio.rs | 4 +- examples/stm32f469/Cargo.toml | 2 +- examples/stm32f7/Cargo.toml | 2 +- examples/stm32g0/Cargo.toml | 2 +- examples/stm32g4/Cargo.toml | 2 +- examples/stm32h5/Cargo.toml | 2 +- examples/stm32h7/Cargo.toml | 2 +- examples/stm32h7/src/bin/multiprio.rs | 4 +- examples/stm32h723/Cargo.toml | 2 +- examples/stm32h735/Cargo.toml | 2 +- examples/stm32h742/Cargo.toml | 2 +- examples/stm32h755cm4/Cargo.toml | 2 +- examples/stm32h755cm4/src/bin/intercore.rs | 4 +- examples/stm32h755cm7/Cargo.toml | 2 +- examples/stm32h755cm7/src/bin/intercore.rs | 4 +- examples/stm32h7b0/Cargo.toml | 2 +- examples/stm32h7rs/Cargo.toml | 2 +- examples/stm32h7rs/src/bin/multiprio.rs | 4 +- examples/stm32l0/Cargo.toml | 2 +- examples/stm32l0/src/bin/raw_spawn.rs | 2 +- examples/stm32l1/Cargo.toml | 2 +- examples/stm32l4/Cargo.toml | 2 +- examples/stm32l432/Cargo.toml | 2 +- examples/stm32l5/Cargo.toml | 2 +- examples/stm32u0/Cargo.toml | 2 +- examples/stm32u5/Cargo.toml | 2 +- examples/stm32wb/Cargo.toml | 2 +- examples/stm32wba/Cargo.toml | 2 +- examples/stm32wba6/Cargo.toml | 2 +- examples/stm32wl/Cargo.toml | 2 +- examples/wasm/Cargo.toml | 2 +- rustfmt.toml | 2 +- tests/mspm0/Cargo.toml | 2 +- tests/nrf/Cargo.toml | 2 +- tests/perf-client/Cargo.toml | 2 +- tests/perf-server/Cargo.toml | 2 +- tests/riscv32/Cargo.toml | 2 +- tests/rp/Cargo.toml | 2 +- tests/stm32/Cargo.toml | 2 +- tests/utils/Cargo.toml | 2 +- 199 files changed, 278 insertions(+), 254 deletions(-) diff --git a/.github/ci/build-nightly.sh b/.github/ci/build-nightly.sh index 8cca1b445..82e9436f3 100755 --- a/.github/ci/build-nightly.sh +++ b/.github/ci/build-nightly.sh @@ -23,7 +23,7 @@ fi hashtime restore /ci/cache/filetime.json || true hashtime save /ci/cache/filetime.json -cargo install --git https://github.com/embassy-rs/cargo-embassy-devtool --locked --rev 676e6d602bf016dc71f1e98f2c7f191d7bd20707 +cargo install --git https://github.com/embassy-rs/cargo-embassy-devtool --locked --rev d015fd5e972a3e550ebef0da6748099b88a93ba6 ./ci-nightly.sh diff --git a/.github/ci/build-xtensa.sh b/.github/ci/build-xtensa.sh index dbd2f7ffc..3f74b4a5a 100755 --- a/.github/ci/build-xtensa.sh +++ b/.github/ci/build-xtensa.sh @@ -25,7 +25,7 @@ fi hashtime restore /ci/cache/filetime.json || true hashtime save /ci/cache/filetime.json -cargo install --git https://github.com/embassy-rs/cargo-embassy-devtool --locked --rev 676e6d602bf016dc71f1e98f2c7f191d7bd20707 +cargo install --git https://github.com/embassy-rs/cargo-embassy-devtool --locked --rev d015fd5e972a3e550ebef0da6748099b88a93ba6 ./ci-xtensa.sh diff --git a/.github/ci/build.sh b/.github/ci/build.sh index d5e0e0bd2..3c196f72b 100755 --- a/.github/ci/build.sh +++ b/.github/ci/build.sh @@ -28,7 +28,7 @@ fi hashtime restore /ci/cache/filetime.json || true hashtime save /ci/cache/filetime.json -cargo install --git https://github.com/embassy-rs/cargo-embassy-devtool --locked --rev 676e6d602bf016dc71f1e98f2c7f191d7bd20707 +cargo install --git https://github.com/embassy-rs/cargo-embassy-devtool --locked --rev d015fd5e972a3e550ebef0da6748099b88a93ba6 ./ci.sh diff --git a/.github/ci/doc.sh b/.github/ci/doc.sh index dab47e86d..535fc5262 100755 --- a/.github/ci/doc.sh +++ b/.github/ci/doc.sh @@ -12,7 +12,7 @@ export CARGO_TARGET_DIR=/ci/cache/target export PATH=$CARGO_HOME/bin:$PATH mv rust-toolchain-nightly.toml rust-toolchain.toml -cargo install --git https://github.com/embassy-rs/cargo-embassy-devtool --locked --rev 676e6d602bf016dc71f1e98f2c7f191d7bd20707 +cargo install --git https://github.com/embassy-rs/cargo-embassy-devtool --locked --rev d015fd5e972a3e550ebef0da6748099b88a93ba6 cargo embassy-devtool doc -o webroot diff --git a/.github/ci/janitor.sh b/.github/ci/janitor.sh index 305c6b227..bc43075bd 100755 --- a/.github/ci/janitor.sh +++ b/.github/ci/janitor.sh @@ -9,7 +9,7 @@ export CARGO_HOME=/ci/cache/cargo export CARGO_TARGET_DIR=/ci/cache/target export PATH=$CARGO_HOME/bin:$PATH -cargo install --git https://github.com/embassy-rs/cargo-embassy-devtool --locked --rev 676e6d602bf016dc71f1e98f2c7f191d7bd20707 +cargo install --git https://github.com/embassy-rs/cargo-embassy-devtool --locked --rev d015fd5e972a3e550ebef0da6748099b88a93ba6 cargo embassy-devtool check-crlf cargo embassy-devtool check-manifest diff --git a/.github/ci/rustfmt.sh b/.github/ci/rustfmt.sh index 369239cfe..7aaf93234 100755 --- a/.github/ci/rustfmt.sh +++ b/.github/ci/rustfmt.sh @@ -9,4 +9,4 @@ export CARGO_HOME=/ci/cache/cargo export CARGO_TARGET_DIR=/ci/cache/target mv rust-toolchain-nightly.toml rust-toolchain.toml -find . -name '*.rs' -not -path '*target*' | xargs rustfmt --check --skip-children --unstable-features --edition 2021 +find . -name '*.rs' -not -path '*target*' | xargs rustfmt --check --skip-children --unstable-features --edition 2024 diff --git a/cyw43-pio/Cargo.toml b/cyw43-pio/Cargo.toml index 6ab5c453e..a10a091e9 100644 --- a/cyw43-pio/Cargo.toml +++ b/cyw43-pio/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "cyw43-pio" version = "0.8.0" -edition = "2021" +edition = "2024" description = "RP2040 PIO SPI implementation for cyw43" keywords = ["embedded", "cyw43", "embassy-net", "embedded-hal-async", "wifi"] categories = ["embedded", "hardware-support", "no-std", "network-programming", "asynchronous"] diff --git a/cyw43/Cargo.toml b/cyw43/Cargo.toml index c59c15a71..314427611 100644 --- a/cyw43/Cargo.toml +++ b/cyw43/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "cyw43" version = "0.5.0" -edition = "2021" +edition = "2024" description = "Rust driver for the CYW43439 WiFi chip, used in the Raspberry Pi Pico W." keywords = ["embedded", "cyw43", "embassy-net", "embedded-hal-async", "wifi"] categories = ["embedded", "hardware-support", "no-std", "network-programming", "asynchronous"] diff --git a/cyw43/src/lib.rs b/cyw43/src/lib.rs index 16b436e66..82c636346 100644 --- a/cyw43/src/lib.rs +++ b/cyw43/src/lib.rs @@ -1,6 +1,7 @@ #![no_std] #![no_main] #![allow(async_fn_in_trait)] +#![allow(unsafe_op_in_unsafe_fn)] #![deny(unused_must_use)] #![doc = include_str!("../README.md")] #![warn(missing_docs)] diff --git a/docs/examples/layer-by-layer/blinky-async/Cargo.toml b/docs/examples/layer-by-layer/blinky-async/Cargo.toml index ec718022c..797ae3097 100644 --- a/docs/examples/layer-by-layer/blinky-async/Cargo.toml +++ b/docs/examples/layer-by-layer/blinky-async/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "blinky-async" version = "0.1.0" -edition = "2021" +edition = "2024" license = "MIT OR Apache-2.0" publish = false diff --git a/docs/examples/layer-by-layer/blinky-hal/Cargo.toml b/docs/examples/layer-by-layer/blinky-hal/Cargo.toml index 4a0b03a83..802b8b32e 100644 --- a/docs/examples/layer-by-layer/blinky-hal/Cargo.toml +++ b/docs/examples/layer-by-layer/blinky-hal/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "blinky-hal" version = "0.1.0" -edition = "2021" +edition = "2024" license = "MIT OR Apache-2.0" publish = false diff --git a/docs/examples/layer-by-layer/blinky-irq/Cargo.toml b/docs/examples/layer-by-layer/blinky-irq/Cargo.toml index 3c4bf8446..d1b893a1e 100644 --- a/docs/examples/layer-by-layer/blinky-irq/Cargo.toml +++ b/docs/examples/layer-by-layer/blinky-irq/Cargo.toml @@ -3,7 +3,7 @@ [package] name = "blinky-irq" version = "0.1.0" -edition = "2021" +edition = "2024" license = "MIT OR Apache-2.0" publish = false diff --git a/docs/examples/layer-by-layer/blinky-pac/Cargo.toml b/docs/examples/layer-by-layer/blinky-pac/Cargo.toml index 0d4711da2..fa093a3af 100644 --- a/docs/examples/layer-by-layer/blinky-pac/Cargo.toml +++ b/docs/examples/layer-by-layer/blinky-pac/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "blinky-pac" version = "0.1.0" -edition = "2021" +edition = "2024" license = "MIT OR Apache-2.0" publish = false diff --git a/embassy-boot-nrf/Cargo.toml b/embassy-boot-nrf/Cargo.toml index 466f18631..787a28d70 100644 --- a/embassy-boot-nrf/Cargo.toml +++ b/embassy-boot-nrf/Cargo.toml @@ -1,5 +1,5 @@ [package] -edition = "2021" +edition = "2024" name = "embassy-boot-nrf" version = "0.9.0" description = "Bootloader lib for nRF chips" diff --git a/embassy-boot-nrf/src/lib.rs b/embassy-boot-nrf/src/lib.rs index f1c9da080..3b3434e2c 100644 --- a/embassy-boot-nrf/src/lib.rs +++ b/embassy-boot-nrf/src/lib.rs @@ -1,4 +1,5 @@ #![no_std] +#![allow(unsafe_op_in_unsafe_fn)] #![warn(missing_docs)] #![doc = include_str!("../README.md")] mod fmt; diff --git a/embassy-boot-rp/Cargo.toml b/embassy-boot-rp/Cargo.toml index 894b77595..e80c79374 100644 --- a/embassy-boot-rp/Cargo.toml +++ b/embassy-boot-rp/Cargo.toml @@ -1,5 +1,5 @@ [package] -edition = "2021" +edition = "2024" name = "embassy-boot-rp" version = "0.8.0" description = "Bootloader lib for RP2040 chips" diff --git a/embassy-boot-rp/src/lib.rs b/embassy-boot-rp/src/lib.rs index f704380ef..dd049851a 100644 --- a/embassy-boot-rp/src/lib.rs +++ b/embassy-boot-rp/src/lib.rs @@ -1,4 +1,5 @@ #![no_std] +#![allow(unsafe_op_in_unsafe_fn)] #![warn(missing_docs)] #![doc = include_str!("../README.md")] mod fmt; diff --git a/embassy-boot-stm32/Cargo.toml b/embassy-boot-stm32/Cargo.toml index 24eafcdbf..c8c7f4409 100644 --- a/embassy-boot-stm32/Cargo.toml +++ b/embassy-boot-stm32/Cargo.toml @@ -1,5 +1,5 @@ [package] -edition = "2021" +edition = "2024" name = "embassy-boot-stm32" version = "0.6.0" description = "Bootloader lib for STM32 chips" diff --git a/embassy-boot-stm32/src/lib.rs b/embassy-boot-stm32/src/lib.rs index 387cc0ce5..ee6ae41b7 100644 --- a/embassy-boot-stm32/src/lib.rs +++ b/embassy-boot-stm32/src/lib.rs @@ -1,4 +1,5 @@ #![no_std] +#![allow(unsafe_op_in_unsafe_fn)] #![warn(missing_docs)] #![doc = include_str!("../README.md")] mod fmt; diff --git a/embassy-boot/Cargo.toml b/embassy-boot/Cargo.toml index a18438c81..8c5c1f633 100644 --- a/embassy-boot/Cargo.toml +++ b/embassy-boot/Cargo.toml @@ -1,5 +1,5 @@ [package] -edition = "2021" +edition = "2024" name = "embassy-boot" version = "0.6.1" description = "A lightweight bootloader supporting firmware updates in a power-fail-safe way, with trial boots and rollbacks." diff --git a/embassy-boot/src/boot_loader.rs b/embassy-boot/src/boot_loader.rs index 5bffdc5ea..8d97882ea 100644 --- a/embassy-boot/src/boot_loader.rs +++ b/embassy-boot/src/boot_loader.rs @@ -94,7 +94,7 @@ impl<'a, ACTIVE: NorFlash, DFU: NorFlash, STATE: NorFlash> dfu_flash: &'a Mutex>, state_flash: &'a Mutex>, ) -> Self { - extern "C" { + unsafe extern "C" { static __bootloader_state_start: u32; static __bootloader_state_end: u32; static __bootloader_active_start: u32; diff --git a/embassy-boot/src/firmware_updater/asynch.rs b/embassy-boot/src/firmware_updater/asynch.rs index 66e311e38..fd02fa526 100644 --- a/embassy-boot/src/firmware_updater/asynch.rs +++ b/embassy-boot/src/firmware_updater/asynch.rs @@ -25,7 +25,7 @@ impl<'a, DFU: NorFlash, STATE: NorFlash> dfu_flash: &'a embassy_sync::mutex::Mutex, state_flash: &'a embassy_sync::mutex::Mutex, ) -> Self { - extern "C" { + unsafe extern "C" { static __bootloader_state_start: u32; static __bootloader_state_end: u32; static __bootloader_dfu_start: u32; diff --git a/embassy-boot/src/firmware_updater/blocking.rs b/embassy-boot/src/firmware_updater/blocking.rs index 0fedac1ea..44550e795 100644 --- a/embassy-boot/src/firmware_updater/blocking.rs +++ b/embassy-boot/src/firmware_updater/blocking.rs @@ -55,7 +55,7 @@ impl<'a, DFU: NorFlash, STATE: NorFlash> dfu_flash: &'a embassy_sync::blocking_mutex::Mutex>, state_flash: &'a embassy_sync::blocking_mutex::Mutex>, ) -> Self { - extern "C" { + unsafe extern "C" { static __bootloader_state_start: u32; static __bootloader_state_end: u32; static __bootloader_dfu_start: u32; diff --git a/embassy-boot/src/lib.rs b/embassy-boot/src/lib.rs index e2c4cf771..4d7ebfc4f 100644 --- a/embassy-boot/src/lib.rs +++ b/embassy-boot/src/lib.rs @@ -1,5 +1,6 @@ #![no_std] #![allow(async_fn_in_trait)] +#![allow(unsafe_op_in_unsafe_fn)] #![warn(missing_docs)] #![doc = include_str!("../README.md")] mod fmt; diff --git a/embassy-embedded-hal/Cargo.toml b/embassy-embedded-hal/Cargo.toml index 8b8122567..c9551257a 100644 --- a/embassy-embedded-hal/Cargo.toml +++ b/embassy-embedded-hal/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "embassy-embedded-hal" version = "0.5.0" -edition = "2021" +edition = "2024" license = "MIT OR Apache-2.0" description = "Collection of utilities to use `embedded-hal` and `embedded-storage` traits with Embassy." repository = "https://github.com/embassy-rs/embassy" diff --git a/embassy-executor-macros/Cargo.toml b/embassy-executor-macros/Cargo.toml index 9c2b40d03..3eeed5e4d 100644 --- a/embassy-executor-macros/Cargo.toml +++ b/embassy-executor-macros/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "embassy-executor-macros" version = "0.7.0" -edition = "2021" +edition = "2024" license = "MIT OR Apache-2.0" description = "macros for creating the entry point and tasks for embassy-executor" repository = "https://github.com/embassy-rs/embassy" diff --git a/embassy-executor-macros/src/macros/main.rs b/embassy-executor-macros/src/macros/main.rs index dc470e51c..3d52ebfe1 100644 --- a/embassy-executor-macros/src/macros/main.rs +++ b/embassy-executor-macros/src/macros/main.rs @@ -183,7 +183,7 @@ For example: `#[embassy_executor::main(entry = ..., executor = \"some_crate::Exe quote!(!), quote! { unsafe fn __make_static(t: &mut T) -> &'static mut T { - ::core::mem::transmute(t) + unsafe { ::core::mem::transmute(t) } } let mut executor = #executor::new(); diff --git a/embassy-executor-timer-queue/Cargo.toml b/embassy-executor-timer-queue/Cargo.toml index a0ac44420..6770ab26e 100644 --- a/embassy-executor-timer-queue/Cargo.toml +++ b/embassy-executor-timer-queue/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "embassy-executor-timer-queue" version = "0.1.0" -edition = "2021" +edition = "2024" description = "Timer queue item and interface between embassy-executor and timer queues" repository = "https://github.com/embassy-rs/embassy" documentation = "https://docs.embassy.dev/embassy-executor-timer-queue" diff --git a/embassy-executor/Cargo.toml b/embassy-executor/Cargo.toml index 6d11bc076..ecc4b6338 100644 --- a/embassy-executor/Cargo.toml +++ b/embassy-executor/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "embassy-executor" version = "0.9.1" -edition = "2021" +edition = "2024" license = "MIT OR Apache-2.0" description = "async/await executor designed for embedded usage" repository = "https://github.com/embassy-rs/embassy" @@ -30,6 +30,8 @@ build = [ {target = "thumbv7em-none-eabi", features = ["arch-cortex-m", "executor-interrupt", "executor-thread", "embassy-time-driver", "scheduler-deadline"]}, {target = "thumbv7em-none-eabi", features = ["arch-cortex-m", "executor-interrupt", "executor-thread", "scheduler-priority", "scheduler-deadline"]}, {target = "thumbv7em-none-eabi", features = ["arch-cortex-m", "executor-interrupt", "executor-thread", "scheduler-deadline"]}, + {target = "thumbv7em-none-eabi", features = ["arch-spin"]}, + {target = "thumbv7em-none-eabi", features = ["arch-spin", "scheduler-deadline"]}, {target = "armv7a-none-eabi", features = ["arch-cortex-ar", "executor-thread"]}, {target = "armv7r-none-eabi", features = ["arch-cortex-ar", "executor-thread"]}, {target = "armv7r-none-eabihf", features = ["arch-cortex-ar", "executor-thread"]}, diff --git a/embassy-executor/src/arch/avr.rs b/embassy-executor/src/arch/avr.rs index 70085d04d..4a19c523a 100644 --- a/embassy-executor/src/arch/avr.rs +++ b/embassy-executor/src/arch/avr.rs @@ -14,7 +14,7 @@ mod thread { static SIGNAL_WORK_THREAD_MODE: AtomicBool = AtomicBool::new(false); - #[export_name = "__pender"] + #[unsafe(export_name = "__pender")] fn __pender(_context: *mut ()) { SIGNAL_WORK_THREAD_MODE.store(true, Ordering::SeqCst); } diff --git a/embassy-executor/src/arch/cortex_ar.rs b/embassy-executor/src/arch/cortex_ar.rs index f9e2f3f7c..36d45944a 100644 --- a/embassy-executor/src/arch/cortex_ar.rs +++ b/embassy-executor/src/arch/cortex_ar.rs @@ -1,7 +1,7 @@ #[cfg(feature = "executor-interrupt")] compile_error!("`executor-interrupt` is not supported with `arch-cortex-ar`."); -#[export_name = "__pender"] +#[unsafe(export_name = "__pender")] #[cfg(any(feature = "executor-thread", feature = "executor-interrupt"))] fn __pender(context: *mut ()) { // `context` is always `usize::MAX` created by `Executor::run`. diff --git a/embassy-executor/src/arch/cortex_m.rs b/embassy-executor/src/arch/cortex_m.rs index 1c9ddd8a0..9f1081e93 100644 --- a/embassy-executor/src/arch/cortex_m.rs +++ b/embassy-executor/src/arch/cortex_m.rs @@ -1,4 +1,4 @@ -#[export_name = "__pender"] +#[unsafe(export_name = "__pender")] #[cfg(any(feature = "executor-thread", feature = "executor-interrupt"))] fn __pender(context: *mut ()) { unsafe { diff --git a/embassy-executor/src/arch/riscv32.rs b/embassy-executor/src/arch/riscv32.rs index 01e63a9fd..13b93cf02 100644 --- a/embassy-executor/src/arch/riscv32.rs +++ b/embassy-executor/src/arch/riscv32.rs @@ -15,7 +15,7 @@ mod thread { /// global atomic used to keep track of whether there is work to do since sev() is not available on RISCV static SIGNAL_WORK_THREAD_MODE: AtomicBool = AtomicBool::new(false); - #[export_name = "__pender"] + #[unsafe(export_name = "__pender")] fn __pender(_context: *mut ()) { SIGNAL_WORK_THREAD_MODE.store(true, Ordering::SeqCst); } diff --git a/embassy-executor/src/arch/spin.rs b/embassy-executor/src/arch/spin.rs index 340023620..40cb56a09 100644 --- a/embassy-executor/src/arch/spin.rs +++ b/embassy-executor/src/arch/spin.rs @@ -11,7 +11,7 @@ mod thread { use crate::{raw, Spawner}; - #[export_name = "__pender"] + #[unsafe(export_name = "__pender")] fn __pender(_context: *mut ()) {} /// Spin Executor diff --git a/embassy-executor/src/arch/std.rs b/embassy-executor/src/arch/std.rs index b02b15988..cdb9f7642 100644 --- a/embassy-executor/src/arch/std.rs +++ b/embassy-executor/src/arch/std.rs @@ -12,7 +12,7 @@ mod thread { use crate::{raw, Spawner}; - #[export_name = "__pender"] + #[unsafe(export_name = "__pender")] fn __pender(context: *mut ()) { let signaler: &'static Signaler = unsafe { std::mem::transmute(context) }; signaler.signal() diff --git a/embassy-executor/src/arch/wasm.rs b/embassy-executor/src/arch/wasm.rs index f9d0f935c..6b36f8a5b 100644 --- a/embassy-executor/src/arch/wasm.rs +++ b/embassy-executor/src/arch/wasm.rs @@ -15,7 +15,7 @@ mod thread { use crate::raw::util::UninitCell; use crate::{raw, Spawner}; - #[export_name = "__pender"] + #[unsafe(export_name = "__pender")] fn __pender(context: *mut ()) { let signaler: &'static WasmContext = unsafe { std::mem::transmute(context) }; let _ = signaler.promise.then(unsafe { signaler.closure.as_mut() }); diff --git a/embassy-executor/src/lib.rs b/embassy-executor/src/lib.rs index e47b8eb9f..cffc76699 100644 --- a/embassy-executor/src/lib.rs +++ b/embassy-executor/src/lib.rs @@ -1,5 +1,6 @@ #![cfg_attr(not(any(feature = "arch-std", feature = "arch-wasm")), no_std)] #![allow(clippy::new_without_default)] +#![allow(unsafe_op_in_unsafe_fn)] #![doc = include_str!("../README.md")] #![warn(missing_docs)] diff --git a/embassy-executor/src/raw/mod.rs b/embassy-executor/src/raw/mod.rs index dbd70cbf4..ab845ed3b 100644 --- a/embassy-executor/src/raw/mod.rs +++ b/embassy-executor/src/raw/mod.rs @@ -52,7 +52,7 @@ pub use self::waker::task_from_waker; use super::SpawnToken; use crate::{Metadata, SpawnError}; -#[no_mangle] +#[unsafe(no_mangle)] extern "Rust" fn __embassy_time_queue_item_from_waker(waker: &Waker) -> &'static mut TimerQueueItem { unsafe { task_from_waker(waker).timer_queue_item() } } @@ -407,7 +407,7 @@ unsafe impl Sync for Pender {} impl Pender { pub(crate) fn pend(self) { - extern "Rust" { + unsafe extern "Rust" { fn __pender(context: *mut ()); } unsafe { __pender(self.0) }; @@ -507,7 +507,7 @@ impl SyncExecutor { /// The pender function must be exported with the name `__pender` and have the following signature: /// /// ```rust -/// #[export_name = "__pender"] +/// #[unsafe(export_name = "__pender")] /// fn pender(context: *mut ()) { /// // schedule `poll()` to be called /// } diff --git a/embassy-executor/src/raw/waker_turbo.rs b/embassy-executor/src/raw/waker_turbo.rs index 435a0ff7e..9d0ad35ec 100644 --- a/embassy-executor/src/raw/waker_turbo.rs +++ b/embassy-executor/src/raw/waker_turbo.rs @@ -26,7 +26,7 @@ pub fn task_from_waker(waker: &Waker) -> TaskRef { } #[inline(never)] -#[no_mangle] +#[unsafe(no_mangle)] fn _turbo_wake(ptr: NonNull<()>) { // safety: our wakers are always created with `TaskRef::as_ptr` let task = unsafe { TaskRef::from_ptr(ptr.as_ptr() as *const TaskHeader) }; diff --git a/embassy-executor/tests/test.rs b/embassy-executor/tests/test.rs index 6baf3dc21..6c4783dc1 100644 --- a/embassy-executor/tests/test.rs +++ b/embassy-executor/tests/test.rs @@ -9,7 +9,7 @@ use std::task::Poll; use embassy_executor::raw::Executor; use embassy_executor::{task, Spawner}; -#[export_name = "__pender"] +#[unsafe(export_name = "__pender")] fn __pender(context: *mut ()) { unsafe { let trace = &*(context as *const Trace); diff --git a/embassy-executor/tests/ui/task_safety_attribute.rs b/embassy-executor/tests/ui/task_safety_attribute.rs index ab5a2f99f..46a5c665f 100644 --- a/embassy-executor/tests/ui/task_safety_attribute.rs +++ b/embassy-executor/tests/ui/task_safety_attribute.rs @@ -9,7 +9,7 @@ async fn safe() {} #[embassy_executor::task] async unsafe fn not_safe() {} -#[export_name = "__pender"] +#[unsafe(export_name = "__pender")] fn pender(_: *mut ()) { // The test doesn't link if we don't include this. // We never call this anyway. diff --git a/embassy-futures/Cargo.toml b/embassy-futures/Cargo.toml index 07d5219cf..d344e5c4b 100644 --- a/embassy-futures/Cargo.toml +++ b/embassy-futures/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "embassy-futures" version = "0.1.2" -edition = "2021" +edition = "2024" description = "no-std, no-alloc utilities for working with futures" repository = "https://github.com/embassy-rs/embassy" documentation = "https://docs.embassy.dev/embassy-futures" diff --git a/embassy-hal-internal/Cargo.toml b/embassy-hal-internal/Cargo.toml index 11dcc2466..c2e0bd30f 100644 --- a/embassy-hal-internal/Cargo.toml +++ b/embassy-hal-internal/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "embassy-hal-internal" version = "0.3.0" -edition = "2021" +edition = "2024" license = "MIT OR Apache-2.0" description = "Internal implementation details for Embassy HALs. DO NOT USE DIRECTLY." repository = "https://github.com/embassy-rs/embassy" diff --git a/embassy-hal-internal/src/lib.rs b/embassy-hal-internal/src/lib.rs index 7addb71e2..729f97f0c 100644 --- a/embassy-hal-internal/src/lib.rs +++ b/embassy-hal-internal/src/lib.rs @@ -1,5 +1,6 @@ #![no_std] #![allow(clippy::new_without_default)] +#![allow(unsafe_op_in_unsafe_fn)] #![doc = include_str!("../README.md")] #![warn(missing_docs)] diff --git a/embassy-hal-internal/src/macros.rs b/embassy-hal-internal/src/macros.rs index ce72ded5c..0fcca2baf 100644 --- a/embassy-hal-internal/src/macros.rs +++ b/embassy-hal-internal/src/macros.rs @@ -58,7 +58,7 @@ macro_rules! peripherals_struct { ///Returns all the peripherals *once* #[inline] pub(crate) fn take_with_cs(_cs: critical_section::CriticalSection) -> Self { - #[no_mangle] + #[unsafe(no_mangle)] static mut _EMBASSY_DEVICE_PERIPHERALS: bool = false; // safety: OK because we're inside a CS. diff --git a/embassy-imxrt/Cargo.toml b/embassy-imxrt/Cargo.toml index 7561640dd..c47756f10 100644 --- a/embassy-imxrt/Cargo.toml +++ b/embassy-imxrt/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "embassy-imxrt" version = "0.1.0" -edition = "2021" +edition = "2024" license = "MIT OR Apache-2.0" description = "Embassy Hardware Abstraction Layer (HAL) for the IMXRT microcontroller" keywords = ["embedded", "async", "imxrt", "rt600", "embedded-hal"] diff --git a/embassy-imxrt/src/lib.rs b/embassy-imxrt/src/lib.rs index a3437c655..00ac9af29 100644 --- a/embassy-imxrt/src/lib.rs +++ b/embassy-imxrt/src/lib.rs @@ -1,5 +1,6 @@ #![no_std] #![allow(async_fn_in_trait)] +#![allow(unsafe_op_in_unsafe_fn)] #![doc = include_str!("../README.md")] #![warn(missing_docs)] @@ -74,7 +75,7 @@ macro_rules! bind_interrupts { $( #[allow(non_snake_case)] - #[no_mangle] + #[unsafe(no_mangle)] unsafe extern "C" fn $irq() { unsafe { $( diff --git a/embassy-mspm0/Cargo.toml b/embassy-mspm0/Cargo.toml index 1b32c4d43..65019eb7c 100644 --- a/embassy-mspm0/Cargo.toml +++ b/embassy-mspm0/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "embassy-mspm0" version = "0.1.0" -edition = "2021" +edition = "2024" license = "MIT OR Apache-2.0" description = "Embassy Hardware Abstraction Layer (HAL) for Texas Instruments MSPM0 series microcontrollers" keywords = ["embedded", "async", "mspm0", "hal", "embedded-hal"] diff --git a/embassy-mspm0/build.rs b/embassy-mspm0/build.rs index d294bc422..93ea81ac3 100644 --- a/embassy-mspm0/build.rs +++ b/embassy-mspm0/build.rs @@ -208,7 +208,7 @@ fn generate_groups() -> TokenStream { #[cfg(feature = "rt")] mod group_vectors { - extern "Rust" { + unsafe extern "Rust" { #(#group_vectors)* } } diff --git a/embassy-mspm0/src/gpio.rs b/embassy-mspm0/src/gpio.rs index d5fd36dbf..4668262a9 100644 --- a/embassy-mspm0/src/gpio.rs +++ b/embassy-mspm0/src/gpio.rs @@ -1125,14 +1125,14 @@ fn GPIOB() { // Defining these as no_mangle is required so that the linker will pick these over the default handler. #[cfg(all(feature = "rt", not(any(mspm0c110x, mspm0c1105_c1106, mspm0l110x))))] -#[no_mangle] +#[unsafe(no_mangle)] #[allow(non_snake_case)] fn GPIOA() { irq_handler(pac::GPIOA, &PORTA_WAKERS); } #[cfg(all(feature = "rt", gpio_pb, not(mspm0c1105_c1106)))] -#[no_mangle] +#[unsafe(no_mangle)] #[allow(non_snake_case)] fn GPIOB() { irq_handler(pac::GPIOB, &PORTB_WAKERS); @@ -1140,7 +1140,7 @@ fn GPIOB() { #[cfg(all(feature = "rt", gpio_pc))] #[allow(non_snake_case)] -#[no_mangle] +#[unsafe(no_mangle)] fn GPIOC() { irq_handler(pac::GPIOC, &PORTC_WAKERS); } diff --git a/embassy-mspm0/src/lib.rs b/embassy-mspm0/src/lib.rs index 13f0ce662..06938c21d 100644 --- a/embassy-mspm0/src/lib.rs +++ b/embassy-mspm0/src/lib.rs @@ -1,4 +1,5 @@ #![no_std] +#![allow(unsafe_op_in_unsafe_fn)] // 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( @@ -111,7 +112,7 @@ macro_rules! bind_interrupts { $( #[allow(non_snake_case)] - #[no_mangle] + #[unsafe(no_mangle)] $(#[cfg($cond_irq)])? unsafe extern "C" fn $irq() { unsafe { diff --git a/embassy-net-adin1110/Cargo.toml b/embassy-net-adin1110/Cargo.toml index 587c69eb7..a5655870f 100644 --- a/embassy-net-adin1110/Cargo.toml +++ b/embassy-net-adin1110/Cargo.toml @@ -5,7 +5,7 @@ description = "embassy-net driver for the ADIN1110 ethernet chip" keywords = ["embedded", "ADIN1110", "embassy-net", "embedded-hal-async", "ethernet"] categories = ["embedded", "hardware-support", "no-std", "network-programming", "asynchronous"] license = "MIT OR Apache-2.0" -edition = "2021" +edition = "2024" repository = "https://github.com/embassy-rs/embassy" documentation = "https://docs.embassy.dev/embassy-net-adin1110" diff --git a/embassy-net-driver-channel/Cargo.toml b/embassy-net-driver-channel/Cargo.toml index 1e40c2d87..116057d6e 100644 --- a/embassy-net-driver-channel/Cargo.toml +++ b/embassy-net-driver-channel/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "embassy-net-driver-channel" version = "0.3.2" -edition = "2021" +edition = "2024" license = "MIT OR Apache-2.0" description = "High-level channel-based driver for the `embassy-net` async TCP/IP network stack." repository = "https://github.com/embassy-rs/embassy" diff --git a/embassy-net-driver/Cargo.toml b/embassy-net-driver/Cargo.toml index a36e412ad..948fb2667 100644 --- a/embassy-net-driver/Cargo.toml +++ b/embassy-net-driver/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "embassy-net-driver" version = "0.2.0" -edition = "2021" +edition = "2024" license = "MIT OR Apache-2.0" description = "Driver trait for the `embassy-net` async TCP/IP network stack." repository = "https://github.com/embassy-rs/embassy" diff --git a/embassy-net-driver/src/lib.rs b/embassy-net-driver/src/lib.rs index 4c847718d..47babe34a 100644 --- a/embassy-net-driver/src/lib.rs +++ b/embassy-net-driver/src/lib.rs @@ -1,4 +1,5 @@ #![no_std] +#![allow(unsafe_op_in_unsafe_fn)] #![warn(missing_docs)] #![doc = include_str!("../README.md")] diff --git a/embassy-net-enc28j60/Cargo.toml b/embassy-net-enc28j60/Cargo.toml index e7bad118b..7c3e05922 100644 --- a/embassy-net-enc28j60/Cargo.toml +++ b/embassy-net-enc28j60/Cargo.toml @@ -5,7 +5,7 @@ description = "embassy-net driver for the ENC28J60 ethernet chip" keywords = ["embedded", "enc28j60", "embassy-net", "embedded-hal-async", "ethernet"] categories = ["embedded", "hardware-support", "no-std", "network-programming", "asynchronous"] license = "MIT OR Apache-2.0" -edition = "2021" +edition = "2024" repository = "https://github.com/embassy-rs/embassy" documentation = "https://docs.embassy.dev/embassy-net-enc28j60" diff --git a/embassy-net-esp-hosted/Cargo.toml b/embassy-net-esp-hosted/Cargo.toml index 149ff2bb2..f148f4762 100644 --- a/embassy-net-esp-hosted/Cargo.toml +++ b/embassy-net-esp-hosted/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "embassy-net-esp-hosted" version = "0.2.1" -edition = "2021" +edition = "2024" description = "embassy-net driver for ESP-Hosted" keywords = ["embedded", "esp-hosted", "embassy-net", "embedded-hal-async", "wifi"] categories = ["embedded", "hardware-support", "no-std", "network-programming", "asynchronous"] diff --git a/embassy-net-nrf91/Cargo.toml b/embassy-net-nrf91/Cargo.toml index 35fbef3f6..ecb10246a 100644 --- a/embassy-net-nrf91/Cargo.toml +++ b/embassy-net-nrf91/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "embassy-net-nrf91" version = "0.1.1" -edition = "2021" +edition = "2024" description = "embassy-net driver for Nordic nRF91-series cellular modems" keywords = ["embedded", "nrf91", "embassy-net", "cellular"] categories = ["embedded", "hardware-support", "no-std", "network-programming", "asynchronous"] diff --git a/embassy-net-nrf91/src/lib.rs b/embassy-net-nrf91/src/lib.rs index 0bd9be0d9..8778b65ab 100644 --- a/embassy-net-nrf91/src/lib.rs +++ b/embassy-net-nrf91/src/lib.rs @@ -1,4 +1,5 @@ #![no_std] +#![allow(unsafe_op_in_unsafe_fn)] #![doc = include_str!("../README.md")] #![warn(missing_docs)] #![deny(unused_must_use)] diff --git a/embassy-net-ppp/Cargo.toml b/embassy-net-ppp/Cargo.toml index 644f5b827..45ee2f6b5 100644 --- a/embassy-net-ppp/Cargo.toml +++ b/embassy-net-ppp/Cargo.toml @@ -5,7 +5,7 @@ description = "embassy-net driver for PPP over Serial" keywords = ["embedded", "ppp", "embassy-net", "embedded-hal-async", "async"] categories = ["embedded", "hardware-support", "no-std", "network-programming", "asynchronous"] license = "MIT OR Apache-2.0" -edition = "2021" +edition = "2024" repository = "https://github.com/embassy-rs/embassy" documentation = "https://docs.embassy.dev/embassy-net-ppp" diff --git a/embassy-net-tuntap/Cargo.toml b/embassy-net-tuntap/Cargo.toml index 2cd0c0f7e..77668b445 100644 --- a/embassy-net-tuntap/Cargo.toml +++ b/embassy-net-tuntap/Cargo.toml @@ -5,7 +5,7 @@ description = "embassy-net driver for Linux TUN/TAP interfaces." keywords = ["embedded", "tuntap", "embassy-net", "ethernet", "async"] categories = ["embedded", "hardware-support", "network-programming", "asynchronous"] license = "MIT OR Apache-2.0" -edition = "2021" +edition = "2024" repository = "https://github.com/embassy-rs/embassy" documentation = "https://docs.embassy.dev/embassy-net-tuntap" diff --git a/embassy-net-wiznet/Cargo.toml b/embassy-net-wiznet/Cargo.toml index 6e6dccebd..069f46fc3 100644 --- a/embassy-net-wiznet/Cargo.toml +++ b/embassy-net-wiznet/Cargo.toml @@ -5,7 +5,7 @@ description = "embassy-net driver for WIZnet SPI Ethernet chips" keywords = ["embedded", "embassy-net", "embedded-hal-async", "ethernet", "async"] categories = ["embedded", "hardware-support", "no-std", "network-programming", "asynchronous"] license = "MIT OR Apache-2.0" -edition = "2021" +edition = "2024" repository = "https://github.com/embassy-rs/embassy" documentation = "https://docs.embassy.dev/embassy-net-wiznet" diff --git a/embassy-net/Cargo.toml b/embassy-net/Cargo.toml index 31ce7e9a6..4c8075c43 100644 --- a/embassy-net/Cargo.toml +++ b/embassy-net/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "embassy-net" version = "0.7.1" -edition = "2021" +edition = "2024" license = "MIT OR Apache-2.0" description = "Async TCP/IP network stack for embedded systems" repository = "https://github.com/embassy-rs/embassy" diff --git a/embassy-net/src/lib.rs b/embassy-net/src/lib.rs index 3f0634849..f701f8add 100644 --- a/embassy-net/src/lib.rs +++ b/embassy-net/src/lib.rs @@ -1,5 +1,6 @@ #![no_std] #![allow(async_fn_in_trait)] +#![allow(unsafe_op_in_unsafe_fn)] #![warn(missing_docs)] #![doc = include_str!("../README.md")] diff --git a/embassy-nrf/Cargo.toml b/embassy-nrf/Cargo.toml index 362fabcf7..17ffaf439 100644 --- a/embassy-nrf/Cargo.toml +++ b/embassy-nrf/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "embassy-nrf" version = "0.8.0" -edition = "2021" +edition = "2024" license = "MIT OR Apache-2.0" description = "Embassy Hardware Abstraction Layer (HAL) for nRF series microcontrollers" keywords = ["embedded", "async", "nordic", "nrf", "embedded-hal"] diff --git a/embassy-nrf/src/lib.rs b/embassy-nrf/src/lib.rs index 716eec961..7a0714cc0 100644 --- a/embassy-nrf/src/lib.rs +++ b/embassy-nrf/src/lib.rs @@ -1,5 +1,6 @@ #![no_std] #![allow(async_fn_in_trait)] +#![allow(unsafe_op_in_unsafe_fn)] #![cfg_attr( docsrs, doc = "

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

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

\n\n" @@ -252,7 +253,7 @@ macro_rules! bind_interrupts { $( #[allow(non_snake_case)] - #[no_mangle] + #[unsafe(no_mangle)] $(#[cfg($cond_irq)])? unsafe extern "C" fn $irq() { unsafe { diff --git a/embassy-nxp/Cargo.toml b/embassy-nxp/Cargo.toml index f3c828313..33f0f2dff 100644 --- a/embassy-nxp/Cargo.toml +++ b/embassy-nxp/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "embassy-nxp" version = "0.1.0" -edition = "2021" +edition = "2024" license = "MIT OR Apache-2.0" publish = false diff --git a/embassy-nxp/src/lib.rs b/embassy-nxp/src/lib.rs index f0f0afb6c..617045217 100644 --- a/embassy-nxp/src/lib.rs +++ b/embassy-nxp/src/lib.rs @@ -1,4 +1,5 @@ #![no_std] +#![allow(unsafe_op_in_unsafe_fn)] // This mod MUST go first, so that the others see its macros. pub(crate) mod fmt; @@ -67,7 +68,7 @@ macro_rules! bind_interrupts { $( #[allow(non_snake_case)] - #[no_mangle] + #[unsafe(no_mangle)] $(#[cfg($cond_irq)])? unsafe extern "C" fn $irq() { unsafe { diff --git a/embassy-rp/Cargo.toml b/embassy-rp/Cargo.toml index f6b0900f2..9ad4b47a3 100644 --- a/embassy-rp/Cargo.toml +++ b/embassy-rp/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "embassy-rp" version = "0.8.0" -edition = "2021" +edition = "2024" license = "MIT OR Apache-2.0" description = "Embassy Hardware Abstraction Layer (HAL) for the Raspberry Pi RP2040 or RP235x microcontroller" keywords = ["embedded", "async", "rp235x", "rp2040", "embedded-hal"] @@ -104,7 +104,7 @@ boot2-w25x10cl = [] ## Have embassy-rp not provide the boot2 so you can use your own. ## Place your own in the ".boot2" section like: ## ``` -## #[link_section = ".boot2"] +## #[unsafe(link_section = ".boot2")] ## #[used] ## static BOOT2: [u8; 256] = [0; 256]; // Provide your own with e.g. include_bytes! ## ``` @@ -127,7 +127,7 @@ imagedef-nonsecure-exe = [] ## ```ignore ## use embassy_rp::block::ImageDef; ## -## #[link_section = ".start_block"] +## #[unsafe(link_section = ".start_block")] ## #[used] ## static IMAGE_DEF: ImageDef = ImageDef::secure_exe(); // Update this with your own implementation. ## ``` diff --git a/embassy-rp/src/bootsel.rs b/embassy-rp/src/bootsel.rs index 14f9e46aa..5f0bac248 100644 --- a/embassy-rp/src/bootsel.rs +++ b/embassy-rp/src/bootsel.rs @@ -36,7 +36,7 @@ mod ram_helpers { /// This function must live in ram. It uses inline asm to avoid any /// potential calls to ABI functions that might be in flash. #[inline(never)] - #[link_section = ".data.ram_func"] + #[unsafe(link_section = ".data.ram_func")] #[cfg(target_arch = "arm")] pub unsafe fn read_cs_status() -> GpioStatus { let result: u32; diff --git a/embassy-rp/src/flash.rs b/embassy-rp/src/flash.rs index 8c809090e..6b5eda0a3 100644 --- a/embassy-rp/src/flash.rs +++ b/embassy-rp/src/flash.rs @@ -627,7 +627,7 @@ mod ram_helpers { /// Length of data must be a multiple of 4096 /// addr must be aligned to 4096 #[inline(never)] - #[link_section = ".data.ram_func"] + #[unsafe(link_section = ".data.ram_func")] #[cfg(feature = "rp2040")] unsafe fn write_flash_inner(addr: u32, len: u32, data: Option<&[u8]>, ptrs: *const FlashFunctionPointers) { #[cfg(target_arch = "arm")] @@ -692,7 +692,7 @@ mod ram_helpers { /// Length of data must be a multiple of 4096 /// addr must be aligned to 4096 #[inline(never)] - #[link_section = ".data.ram_func"] + #[unsafe(link_section = ".data.ram_func")] #[cfg(feature = "_rp235x")] unsafe fn write_flash_inner(addr: u32, len: u32, data: Option<&[u8]>, ptrs: *const FlashFunctionPointers) { let data = data.map(|d| d.as_ptr()).unwrap_or(core::ptr::null()); @@ -811,7 +811,7 @@ mod ram_helpers { /// /// Credit: taken from `rp2040-flash` (also licensed Apache+MIT) #[inline(never)] - #[link_section = ".data.ram_func"] + #[unsafe(link_section = ".data.ram_func")] #[cfg(feature = "rp2040")] unsafe fn read_flash_inner(cmd: FlashCommand, ptrs: *const FlashFunctionPointers) { #[cfg(target_arch = "arm")] diff --git a/embassy-rp/src/intrinsics.rs b/embassy-rp/src/intrinsics.rs index 69d5d92de..aed8a3227 100644 --- a/embassy-rp/src/intrinsics.rs +++ b/embassy-rp/src/intrinsics.rs @@ -223,7 +223,7 @@ macro_rules! intrinsics { #[cfg(all(target_arch = "arm", feature = "intrinsics"))] mod $name { - #[no_mangle] + #[unsafe(no_mangle)] $(#[$($attr)*])* pub extern $abi fn $name( $($argname: $ty),* ) -> $ret { super::$name($($argname),*) @@ -257,7 +257,7 @@ macro_rules! intrinsics { #[cfg(all(target_arch = "arm", feature = "intrinsics"))] mod $name { - #[no_mangle] + #[unsafe(no_mangle)] $(#[$($attr)*])* pub unsafe extern $abi fn $name( $($argname: $ty),* ) -> $ret { super::$name($($argname),*) @@ -392,7 +392,7 @@ macro_rules! division_function { ); #[cfg(target_arch = "arm")] - extern "aapcs" { + unsafe extern "aapcs" { // Connect a local name to global symbol above through FFI. #[link_name = concat!("_erphal_", stringify!($name)) ] fn $name(n: $argty, d: $argty) -> u64; diff --git a/embassy-rp/src/lib.rs b/embassy-rp/src/lib.rs index d03ba1fef..4cb1a0912 100644 --- a/embassy-rp/src/lib.rs +++ b/embassy-rp/src/lib.rs @@ -1,5 +1,7 @@ #![no_std] #![allow(async_fn_in_trait)] +#![allow(unsafe_op_in_unsafe_fn)] +#![allow(unused_unsafe)] #![doc = include_str!("../README.md")] #![warn(missing_docs)] @@ -190,7 +192,7 @@ macro_rules! bind_interrupts { $( #[allow(non_snake_case)] - #[no_mangle] + #[unsafe(no_mangle)] $(#[cfg($cond_irq)])? unsafe extern "C" fn $irq() { unsafe { @@ -446,13 +448,13 @@ macro_rules! select_bootloader { ( $( $feature:literal => $loader:ident, )+ default => $default:ident ) => { $( #[cfg(feature = $feature)] - #[link_section = ".boot2"] + #[unsafe(link_section = ".boot2")] #[used] static BOOT2: [u8; 256] = rp2040_boot2::$loader; )* #[cfg(not(any( $( feature = $feature),* )))] - #[link_section = ".boot2"] + #[unsafe(link_section = ".boot2")] #[used] static BOOT2: [u8; 256] = rp2040_boot2::$default; } @@ -475,13 +477,13 @@ macro_rules! select_imagedef { ( $( $feature:literal => $imagedef:ident, )+ default => $default:ident ) => { $( #[cfg(feature = $feature)] - #[link_section = ".start_block"] + #[unsafe(link_section = ".start_block")] #[used] static IMAGE_DEF: crate::block::ImageDef = crate::block::ImageDef::$imagedef(); )* #[cfg(not(any( $( feature = $feature),* )))] - #[link_section = ".start_block"] + #[unsafe(link_section = ".start_block")] #[used] static IMAGE_DEF: crate::block::ImageDef = crate::block::ImageDef::$default(); } @@ -528,7 +530,7 @@ select_imagedef! { /// } /// ``` pub fn install_core0_stack_guard() -> Result<(), ()> { - extern "C" { + unsafe extern "C" { static mut _stack_end: usize; } unsafe { install_stack_guard(core::ptr::addr_of_mut!(_stack_end)) } diff --git a/embassy-rp/src/multicore.rs b/embassy-rp/src/multicore.rs index adedc98ad..c305513ca 100644 --- a/embassy-rp/src/multicore.rs +++ b/embassy-rp/src/multicore.rs @@ -14,6 +14,7 @@ //! use embassy_rp::multicore::Stack; //! use static_cell::StaticCell; //! use embassy_executor::Executor; +//! use core::ptr::addr_of_mut; //! //! static mut CORE1_STACK: Stack<4096> = Stack::new(); //! static EXECUTOR0: StaticCell = StaticCell::new(); @@ -36,7 +37,7 @@ //! fn main() -> ! { //! let p = embassy_rp::init(Default::default()); //! -//! embassy_rp::multicore::spawn_core1(p.CORE1, unsafe { &mut CORE1_STACK }, move || { +//! embassy_rp::multicore::spawn_core1(p.CORE1, unsafe { &mut *addr_of_mut!(CORE1_STACK) }, move || { //! let executor1 = EXECUTOR1.init(Executor::new()); //! executor1.run(|spawner| spawner.spawn(core1_task().unwrap())); //! }); @@ -110,7 +111,6 @@ impl Stack { #[cfg(all(feature = "rt", feature = "rp2040"))] #[interrupt] -#[link_section = ".data.ram_func"] unsafe fn SIO_IRQ_PROC1() { let sio = pac::SIO; // Clear IRQ @@ -135,7 +135,6 @@ unsafe fn SIO_IRQ_PROC1() { #[cfg(all(feature = "rt", feature = "_rp235x"))] #[interrupt] -#[link_section = ".data.ram_func"] unsafe fn SIO_IRQ_FIFO() { let sio = pac::SIO; // Clear IRQ diff --git a/embassy-rp/src/psram.rs b/embassy-rp/src/psram.rs index ae43dd5aa..22eb1ed25 100644 --- a/embassy-rp/src/psram.rs +++ b/embassy-rp/src/psram.rs @@ -251,7 +251,7 @@ impl<'d> Psram<'d> { } /// Verify APS6404L PSRAM device matches expected configuration. - #[link_section = ".data.ram_func"] + #[unsafe(link_section = ".data.ram_func")] #[inline(never)] fn verify_aps6404l(qmi: &pac::qmi::Qmi, expected_size: usize) -> Result<(), Error> { // APS6404L-specific constants @@ -306,7 +306,7 @@ impl<'d> Psram<'d> { Ok(()) } - #[link_section = ".data.ram_func"] + #[unsafe(link_section = ".data.ram_func")] #[inline(never)] unsafe fn read_aps6404l_kgd_eid(qmi: &pac::qmi::Qmi) -> (u32, u32) { const RESET_ENABLE_CMD: u8 = 0xf5; @@ -435,7 +435,7 @@ impl<'d> Psram<'d> { } /// Initialize PSRAM with proper timing. - #[link_section = ".data.ram_func"] + #[unsafe(link_section = ".data.ram_func")] #[inline(never)] fn init_psram(qmi: &pac::qmi::Qmi, xip_ctrl: &pac::xip_ctrl::XipCtrl, config: &Config) -> Result<(), Error> { // Set PSRAM timing for APS6404 @@ -610,7 +610,7 @@ impl<'d> Psram<'d> { Ok(()) } - #[link_section = ".data.ram_func"] + #[unsafe(link_section = ".data.ram_func")] #[inline(never)] unsafe fn direct_csr_send_init_command(config: &Config, init_cmd: u8) { #[cfg(target_arch = "arm")] diff --git a/embassy-stm32-wpan/Cargo.toml b/embassy-stm32-wpan/Cargo.toml index d7c7a284c..0802b7328 100644 --- a/embassy-stm32-wpan/Cargo.toml +++ b/embassy-stm32-wpan/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "embassy-stm32-wpan" version = "0.1.0" -edition = "2021" +edition = "2024" license = "MIT OR Apache-2.0" description = "Async STM32 WPAN stack for embedded devices in Rust." keywords = ["embedded", "async", "stm32", "ble", "wpan"] diff --git a/embassy-stm32-wpan/src/lib.rs b/embassy-stm32-wpan/src/lib.rs index 40ff14795..f4eb0069f 100644 --- a/embassy-stm32-wpan/src/lib.rs +++ b/embassy-stm32-wpan/src/lib.rs @@ -13,6 +13,7 @@ #![no_std] #![allow(async_fn_in_trait)] +#![allow(unsafe_op_in_unsafe_fn)] #![doc = include_str!("../README.md")] // #![warn(missing_docs)] #![allow(static_mut_refs)] // TODO: Fix diff --git a/embassy-stm32-wpan/src/tables.rs b/embassy-stm32-wpan/src/tables.rs index fe6fc47a3..204790e6d 100644 --- a/embassy-stm32-wpan/src/tables.rs +++ b/embassy-stm32-wpan/src/tables.rs @@ -190,94 +190,94 @@ pub struct RefTable { } // --------------------- ref table --------------------- -#[link_section = "TL_REF_TABLE"] +#[unsafe(link_section = "TL_REF_TABLE")] pub static mut TL_REF_TABLE: MaybeUninit = MaybeUninit::uninit(); -#[link_section = "MB_MEM1"] +#[unsafe(link_section = "MB_MEM1")] pub static mut TL_DEVICE_INFO_TABLE: Aligned> = Aligned(MaybeUninit::uninit()); -#[link_section = "MB_MEM1"] +#[unsafe(link_section = "MB_MEM1")] pub static mut TL_BLE_TABLE: Aligned> = Aligned(MaybeUninit::uninit()); -#[link_section = "MB_MEM1"] +#[unsafe(link_section = "MB_MEM1")] pub static mut TL_THREAD_TABLE: Aligned> = Aligned(MaybeUninit::uninit()); -#[link_section = "MB_MEM1"] +#[unsafe(link_section = "MB_MEM1")] pub static mut TL_LLD_TESTS_TABLE: Aligned> = Aligned(MaybeUninit::uninit()); -#[link_section = "MB_MEM1"] +#[unsafe(link_section = "MB_MEM1")] pub static mut TL_BLE_LLD_TABLE: Aligned> = Aligned(MaybeUninit::uninit()); -#[link_section = "MB_MEM1"] +#[unsafe(link_section = "MB_MEM1")] pub static mut TL_SYS_TABLE: Aligned> = Aligned(MaybeUninit::uninit()); -#[link_section = "MB_MEM1"] +#[unsafe(link_section = "MB_MEM1")] pub static mut TL_MEM_MANAGER_TABLE: Aligned> = Aligned(MaybeUninit::uninit()); -#[link_section = "MB_MEM1"] +#[unsafe(link_section = "MB_MEM1")] pub static mut TL_TRACES_TABLE: Aligned> = Aligned(MaybeUninit::uninit()); -#[link_section = "MB_MEM1"] +#[unsafe(link_section = "MB_MEM1")] pub static mut TL_MAC_802_15_4_TABLE: Aligned> = Aligned(MaybeUninit::uninit()); -#[link_section = "MB_MEM1"] +#[unsafe(link_section = "MB_MEM1")] pub static mut TL_ZIGBEE_TABLE: Aligned> = Aligned(MaybeUninit::uninit()); // --------------------- tables --------------------- -#[link_section = "MB_MEM1"] +#[unsafe(link_section = "MB_MEM1")] pub static mut FREE_BUF_QUEUE: Aligned> = Aligned(MaybeUninit::uninit()); #[allow(dead_code)] -#[link_section = "MB_MEM1"] +#[unsafe(link_section = "MB_MEM1")] pub static mut TRACES_EVT_QUEUE: Aligned> = Aligned(MaybeUninit::uninit()); -#[link_section = "MB_MEM2"] +#[unsafe(link_section = "MB_MEM2")] pub static mut CS_BUFFER: Aligned> = Aligned(MaybeUninit::uninit()); -#[link_section = "MB_MEM2"] +#[unsafe(link_section = "MB_MEM2")] pub static mut EVT_QUEUE: Aligned> = Aligned(MaybeUninit::uninit()); -#[link_section = "MB_MEM2"] +#[unsafe(link_section = "MB_MEM2")] pub static mut SYSTEM_EVT_QUEUE: Aligned> = Aligned(MaybeUninit::uninit()); // --------------------- app tables --------------------- #[cfg(feature = "mac")] -#[link_section = "MB_MEM2"] +#[unsafe(link_section = "MB_MEM2")] pub static mut MAC_802_15_4_CMD_BUFFER: Aligned> = Aligned(MaybeUninit::uninit()); #[cfg(feature = "mac")] -#[link_section = "MB_MEM2"] +#[unsafe(link_section = "MB_MEM2")] pub static mut MAC_802_15_4_NOTIF_RSP_EVT_BUFFER: MaybeUninit< Aligned, > = MaybeUninit::uninit(); -#[link_section = "MB_MEM2"] +#[unsafe(link_section = "MB_MEM2")] pub static mut EVT_POOL: Aligned> = Aligned(MaybeUninit::uninit()); -#[link_section = "MB_MEM2"] +#[unsafe(link_section = "MB_MEM2")] pub static mut SYS_CMD_BUF: Aligned> = Aligned(MaybeUninit::uninit()); -#[link_section = "MB_MEM2"] +#[unsafe(link_section = "MB_MEM2")] pub static mut SYS_SPARE_EVT_BUF: Aligned> = Aligned(MaybeUninit::uninit()); #[cfg(feature = "mac")] -#[link_section = "MB_MEM2"] +#[unsafe(link_section = "MB_MEM2")] pub static mut MAC_802_15_4_CNFINDNOT: Aligned> = Aligned(MaybeUninit::uninit()); #[cfg(feature = "ble")] -#[link_section = "MB_MEM1"] +#[unsafe(link_section = "MB_MEM1")] pub static mut BLE_CMD_BUFFER: Aligned> = Aligned(MaybeUninit::uninit()); #[cfg(feature = "ble")] -#[link_section = "MB_MEM2"] +#[unsafe(link_section = "MB_MEM2")] pub static mut BLE_SPARE_EVT_BUF: Aligned> = Aligned(MaybeUninit::uninit()); #[cfg(feature = "ble")] -#[link_section = "MB_MEM2"] +#[unsafe(link_section = "MB_MEM2")] // fuck these "magic" numbers from ST ---v---v pub static mut HCI_ACL_DATA_BUFFER: Aligned> = Aligned(MaybeUninit::uninit()); diff --git a/embassy-stm32/Cargo.toml b/embassy-stm32/Cargo.toml index 82bc73708..7c243b350 100644 --- a/embassy-stm32/Cargo.toml +++ b/embassy-stm32/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "embassy-stm32" version = "0.4.0" -edition = "2021" +edition = "2024" license = "MIT OR Apache-2.0" description = "Embassy Hardware Abstraction Layer (HAL) for ST STM32 series microcontrollers" keywords = ["embedded", "async", "stm32", "hal", "embedded-hal"] diff --git a/embassy-stm32/src/lib.rs b/embassy-stm32/src/lib.rs index 7e0f7884e..dbf0fe620 100644 --- a/embassy-stm32/src/lib.rs +++ b/embassy-stm32/src/lib.rs @@ -1,5 +1,6 @@ #![cfg_attr(not(test), no_std)] #![allow(async_fn_in_trait)] +#![allow(unsafe_op_in_unsafe_fn)] #![cfg_attr( docsrs, doc = "

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

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

\n\n" @@ -194,7 +195,7 @@ macro_rules! bind_interrupts { $( #[allow(non_snake_case)] - #[no_mangle] + #[unsafe(no_mangle)] $(#[cfg($cond_irq)])? $(#[doc = $doc])* unsafe extern "C" fn $irq() { @@ -222,7 +223,7 @@ macro_rules! bind_interrupts { } // Reexports -pub use _generated::{peripherals, Peripherals}; +pub use _generated::{Peripherals, peripherals}; pub use embassy_hal_internal::{Peri, PeripheralType}; #[cfg(feature = "unstable-pac")] pub use stm32_metapac as pac; diff --git a/embassy-sync/Cargo.toml b/embassy-sync/Cargo.toml index 64d76baba..0c28cec7d 100644 --- a/embassy-sync/Cargo.toml +++ b/embassy-sync/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "embassy-sync" version = "0.7.2" -edition = "2021" +edition = "2024" description = "no-std, no-alloc synchronization primitives with async support" repository = "https://github.com/embassy-rs/embassy" documentation = "https://docs.embassy.dev/embassy-sync" diff --git a/embassy-sync/src/lib.rs b/embassy-sync/src/lib.rs index 5d91b4d9c..1cfde8b10 100644 --- a/embassy-sync/src/lib.rs +++ b/embassy-sync/src/lib.rs @@ -1,6 +1,7 @@ #![cfg_attr(not(feature = "std"), no_std)] #![allow(async_fn_in_trait)] #![allow(clippy::new_without_default)] +#![allow(unsafe_op_in_unsafe_fn)] #![doc = include_str!("../README.md")] #![warn(missing_docs)] diff --git a/embassy-time-driver/Cargo.toml b/embassy-time-driver/Cargo.toml index 56ef3d15f..a52e82433 100644 --- a/embassy-time-driver/Cargo.toml +++ b/embassy-time-driver/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "embassy-time-driver" version = "0.2.1" -edition = "2021" +edition = "2024" description = "Driver trait for embassy-time" repository = "https://github.com/embassy-rs/embassy" documentation = "https://docs.embassy.dev/embassy-time-driver" diff --git a/embassy-time-driver/src/lib.rs b/embassy-time-driver/src/lib.rs index 44d9a156a..f3e8e0153 100644 --- a/embassy-time-driver/src/lib.rs +++ b/embassy-time-driver/src/lib.rs @@ -89,7 +89,7 @@ //! Instead of the usual "trait + generic params" approach, calls from embassy to the driver are done via `extern` functions. //! //! `embassy` internally defines the driver function as `extern "Rust" { fn _embassy_time_now() -> u64; }` and calls it. -//! The driver crate defines the function as `#[no_mangle] fn _embassy_time_now() -> u64`. The linker will resolve the +//! The driver crate defines the function as `#[unsafe(no_mangle)] fn _embassy_time_now() -> u64`. The linker will resolve the //! calls from the `embassy` crate to call into the driver crate. //! //! If there is none or multiple drivers in the crate tree, linking will fail. @@ -133,7 +133,7 @@ pub trait Driver: Send + Sync + 'static { fn schedule_wake(&self, at: u64, waker: &Waker); } -extern "Rust" { +unsafe extern "Rust" { fn _embassy_time_now() -> u64; fn _embassy_time_schedule_wake(at: u64, waker: &Waker); } @@ -158,13 +158,13 @@ macro_rules! time_driver_impl { (static $name:ident: $t: ty = $val:expr) => { static $name: $t = $val; - #[no_mangle] + #[unsafe(no_mangle)] #[inline] fn _embassy_time_now() -> u64 { <$t as $crate::Driver>::now(&$name) } - #[no_mangle] + #[unsafe(no_mangle)] #[inline] fn _embassy_time_schedule_wake(at: u64, waker: &core::task::Waker) { <$t as $crate::Driver>::schedule_wake(&$name, at, waker); diff --git a/embassy-time-queue-utils/Cargo.toml b/embassy-time-queue-utils/Cargo.toml index 13da62874..8da30c544 100644 --- a/embassy-time-queue-utils/Cargo.toml +++ b/embassy-time-queue-utils/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "embassy-time-queue-utils" version = "0.3.0" -edition = "2021" +edition = "2024" description = "Timer queue driver trait for embassy-time" repository = "https://github.com/embassy-rs/embassy" documentation = "https://docs.embassy.dev/embassy-time-queue-utils" diff --git a/embassy-time/Cargo.toml b/embassy-time/Cargo.toml index bad6ecf97..05614dbf5 100644 --- a/embassy-time/Cargo.toml +++ b/embassy-time/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "embassy-time" version = "0.5.0" -edition = "2021" +edition = "2024" description = "Instant and Duration for embedded no-std systems, with async timer support" repository = "https://github.com/embassy-rs/embassy" documentation = "https://docs.embassy.dev/embassy-time" diff --git a/embassy-time/src/lib.rs b/embassy-time/src/lib.rs index 77f4b344d..5a511a0bd 100644 --- a/embassy-time/src/lib.rs +++ b/embassy-time/src/lib.rs @@ -1,5 +1,6 @@ #![cfg_attr(not(any(feature = "std", feature = "wasm", test)), no_std)] #![allow(async_fn_in_trait)] +#![allow(unsafe_op_in_unsafe_fn)] #![doc = include_str!("../README.md")] #![allow(clippy::new_without_default)] #![warn(missing_docs)] diff --git a/embassy-usb-dfu/Cargo.toml b/embassy-usb-dfu/Cargo.toml index e70ab970e..8b32582c0 100644 --- a/embassy-usb-dfu/Cargo.toml +++ b/embassy-usb-dfu/Cargo.toml @@ -1,5 +1,5 @@ [package] -edition = "2021" +edition = "2024" name = "embassy-usb-dfu" version = "0.2.0" description = "An implementation of the USB DFU 1.1 protocol, using embassy-boot" diff --git a/embassy-usb-driver/Cargo.toml b/embassy-usb-driver/Cargo.toml index 6e4c31273..3f43f60a3 100644 --- a/embassy-usb-driver/Cargo.toml +++ b/embassy-usb-driver/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "embassy-usb-driver" version = "0.2.0" -edition = "2021" +edition = "2024" license = "MIT OR Apache-2.0" description = "Driver trait for `embassy-usb`, an async USB device stack for embedded devices." keywords = ["embedded", "async", "usb", "hal", "embedded-hal"] diff --git a/embassy-usb-driver/src/lib.rs b/embassy-usb-driver/src/lib.rs index 59845a268..f19e0a401 100644 --- a/embassy-usb-driver/src/lib.rs +++ b/embassy-usb-driver/src/lib.rs @@ -1,5 +1,6 @@ #![no_std] #![allow(async_fn_in_trait)] +#![allow(unsafe_op_in_unsafe_fn)] #![doc = include_str!("../README.md")] #![warn(missing_docs)] diff --git a/embassy-usb-logger/Cargo.toml b/embassy-usb-logger/Cargo.toml index 6d13653bf..683821759 100644 --- a/embassy-usb-logger/Cargo.toml +++ b/embassy-usb-logger/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "embassy-usb-logger" version = "0.5.1" -edition = "2021" +edition = "2024" license = "MIT OR Apache-2.0" description = "`log` implementation for USB serial using `embassy-usb`." keywords = ["embedded", "log", "usb", "hal", "serial"] diff --git a/embassy-usb-synopsys-otg/Cargo.toml b/embassy-usb-synopsys-otg/Cargo.toml index 61b14a215..eca68095d 100644 --- a/embassy-usb-synopsys-otg/Cargo.toml +++ b/embassy-usb-synopsys-otg/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "embassy-usb-synopsys-otg" version = "0.3.1" -edition = "2021" +edition = "2024" license = "MIT OR Apache-2.0" description = "`embassy-usb-driver` implementation for Synopsys OTG USB controllers" keywords = ["embedded", "async", "usb", "hal", "embedded-hal"] diff --git a/embassy-usb-synopsys-otg/src/lib.rs b/embassy-usb-synopsys-otg/src/lib.rs index 6b4a87bdf..b8750491d 100644 --- a/embassy-usb-synopsys-otg/src/lib.rs +++ b/embassy-usb-synopsys-otg/src/lib.rs @@ -1,5 +1,6 @@ #![cfg_attr(not(test), no_std)] #![allow(async_fn_in_trait)] +#![allow(unsafe_op_in_unsafe_fn)] #![doc = include_str!("../README.md")] #![warn(missing_docs)] diff --git a/embassy-usb/Cargo.toml b/embassy-usb/Cargo.toml index bff48c4a6..aeb7392f1 100644 --- a/embassy-usb/Cargo.toml +++ b/embassy-usb/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "embassy-usb" version = "0.5.1" -edition = "2021" +edition = "2024" license = "MIT OR Apache-2.0" description = "Async USB device stack for embedded devices in Rust." keywords = ["embedded", "async", "usb", "hal", "embedded-hal"] diff --git a/embassy-usb/src/lib.rs b/embassy-usb/src/lib.rs index 0638fd0a2..7f78de29d 100644 --- a/embassy-usb/src/lib.rs +++ b/embassy-usb/src/lib.rs @@ -1,4 +1,5 @@ #![no_std] +#![allow(unsafe_op_in_unsafe_fn)] #![doc = include_str!("../README.md")] #![warn(missing_docs)] diff --git a/examples/boot/application/nrf/Cargo.toml b/examples/boot/application/nrf/Cargo.toml index f5f89ecb5..55053bc33 100644 --- a/examples/boot/application/nrf/Cargo.toml +++ b/examples/boot/application/nrf/Cargo.toml @@ -1,5 +1,5 @@ [package] -edition = "2021" +edition = "2024" name = "embassy-boot-nrf-examples" version = "0.1.0" license = "MIT OR Apache-2.0" diff --git a/examples/boot/application/rp/Cargo.toml b/examples/boot/application/rp/Cargo.toml index d86386b00..70a2c28c3 100644 --- a/examples/boot/application/rp/Cargo.toml +++ b/examples/boot/application/rp/Cargo.toml @@ -1,5 +1,5 @@ [package] -edition = "2021" +edition = "2024" name = "embassy-boot-rp-examples" version = "0.1.0" license = "MIT OR Apache-2.0" diff --git a/examples/boot/application/stm32f3/Cargo.toml b/examples/boot/application/stm32f3/Cargo.toml index cd5f422fc..2dc75d939 100644 --- a/examples/boot/application/stm32f3/Cargo.toml +++ b/examples/boot/application/stm32f3/Cargo.toml @@ -1,5 +1,5 @@ [package] -edition = "2021" +edition = "2024" name = "embassy-boot-stm32f3-examples" version = "0.1.0" license = "MIT OR Apache-2.0" diff --git a/examples/boot/application/stm32f7/Cargo.toml b/examples/boot/application/stm32f7/Cargo.toml index c3921a166..5c372fb19 100644 --- a/examples/boot/application/stm32f7/Cargo.toml +++ b/examples/boot/application/stm32f7/Cargo.toml @@ -1,5 +1,5 @@ [package] -edition = "2021" +edition = "2024" name = "embassy-boot-stm32f7-examples" version = "0.1.0" license = "MIT OR Apache-2.0" diff --git a/examples/boot/application/stm32h7/Cargo.toml b/examples/boot/application/stm32h7/Cargo.toml index ca186d4d9..641a2ba96 100644 --- a/examples/boot/application/stm32h7/Cargo.toml +++ b/examples/boot/application/stm32h7/Cargo.toml @@ -1,5 +1,5 @@ [package] -edition = "2021" +edition = "2024" name = "embassy-boot-stm32h7-examples" version = "0.1.0" license = "MIT OR Apache-2.0" diff --git a/examples/boot/application/stm32l0/Cargo.toml b/examples/boot/application/stm32l0/Cargo.toml index be08956f1..4a168be15 100644 --- a/examples/boot/application/stm32l0/Cargo.toml +++ b/examples/boot/application/stm32l0/Cargo.toml @@ -1,5 +1,5 @@ [package] -edition = "2021" +edition = "2024" name = "embassy-boot-stm32l0-examples" version = "0.1.0" license = "MIT OR Apache-2.0" diff --git a/examples/boot/application/stm32l1/Cargo.toml b/examples/boot/application/stm32l1/Cargo.toml index 207eed733..af2cb3881 100644 --- a/examples/boot/application/stm32l1/Cargo.toml +++ b/examples/boot/application/stm32l1/Cargo.toml @@ -1,5 +1,5 @@ [package] -edition = "2021" +edition = "2024" name = "embassy-boot-stm32l1-examples" version = "0.1.0" license = "MIT OR Apache-2.0" diff --git a/examples/boot/application/stm32l4/Cargo.toml b/examples/boot/application/stm32l4/Cargo.toml index 22b9642d8..032e934aa 100644 --- a/examples/boot/application/stm32l4/Cargo.toml +++ b/examples/boot/application/stm32l4/Cargo.toml @@ -1,5 +1,5 @@ [package] -edition = "2021" +edition = "2024" name = "embassy-boot-stm32l4-examples" version = "0.1.0" license = "MIT OR Apache-2.0" diff --git a/examples/boot/application/stm32wb-dfu/Cargo.toml b/examples/boot/application/stm32wb-dfu/Cargo.toml index e2be4f470..ea4c26681 100644 --- a/examples/boot/application/stm32wb-dfu/Cargo.toml +++ b/examples/boot/application/stm32wb-dfu/Cargo.toml @@ -1,5 +1,5 @@ [package] -edition = "2021" +edition = "2024" name = "embassy-boot-stm32wb-dfu-examples" version = "0.1.0" license = "MIT OR Apache-2.0" diff --git a/examples/boot/application/stm32wba-dfu/Cargo.toml b/examples/boot/application/stm32wba-dfu/Cargo.toml index 6f4213b2c..d6f7dc3b6 100644 --- a/examples/boot/application/stm32wba-dfu/Cargo.toml +++ b/examples/boot/application/stm32wba-dfu/Cargo.toml @@ -1,5 +1,5 @@ [package] -edition = "2021" +edition = "2024" name = "embassy-boot-stm32wba-dfu-examples" version = "0.1.0" license = "MIT OR Apache-2.0" diff --git a/examples/boot/application/stm32wl/Cargo.toml b/examples/boot/application/stm32wl/Cargo.toml index 8d1446ba9..c7fa811c9 100644 --- a/examples/boot/application/stm32wl/Cargo.toml +++ b/examples/boot/application/stm32wl/Cargo.toml @@ -1,5 +1,5 @@ [package] -edition = "2021" +edition = "2024" name = "embassy-boot-stm32wl-examples" version = "0.1.0" license = "MIT OR Apache-2.0" diff --git a/examples/boot/bootloader/nrf/Cargo.toml b/examples/boot/bootloader/nrf/Cargo.toml index 72b7114d4..1fea2b7d7 100644 --- a/examples/boot/bootloader/nrf/Cargo.toml +++ b/examples/boot/bootloader/nrf/Cargo.toml @@ -1,5 +1,5 @@ [package] -edition = "2021" +edition = "2024" name = "nrf-bootloader-example" version = "0.1.0" description = "Bootloader for nRF chips" diff --git a/examples/boot/bootloader/nrf/src/main.rs b/examples/boot/bootloader/nrf/src/main.rs index b849a0df3..76c4c1048 100644 --- a/examples/boot/bootloader/nrf/src/main.rs +++ b/examples/boot/bootloader/nrf/src/main.rs @@ -38,8 +38,8 @@ fn main() -> ! { unsafe { bl.load(active_offset) } } -#[no_mangle] -#[cfg_attr(target_os = "none", link_section = ".HardFault.user")] +#[unsafe(no_mangle)] +#[cfg_attr(target_os = "none", unsafe(link_section = ".HardFault.user"))] unsafe extern "C" fn HardFault() { cortex_m::peripheral::SCB::sys_reset(); } @@ -47,7 +47,7 @@ unsafe extern "C" fn HardFault() { #[exception] unsafe fn DefaultHandler(_: i16) -> ! { const SCB_ICSR: *const u32 = 0xE000_ED04 as *const u32; - let irqn = core::ptr::read_volatile(SCB_ICSR) as u8 as i16 - 16; + let irqn = unsafe { core::ptr::read_volatile(SCB_ICSR) } as u8 as i16 - 16; panic!("DefaultHandler #{:?}", irqn); } diff --git a/examples/boot/bootloader/rp/Cargo.toml b/examples/boot/bootloader/rp/Cargo.toml index 93a1c4edf..188bcab36 100644 --- a/examples/boot/bootloader/rp/Cargo.toml +++ b/examples/boot/bootloader/rp/Cargo.toml @@ -1,5 +1,5 @@ [package] -edition = "2021" +edition = "2024" name = "rp-bootloader-example" version = "0.1.0" description = "Example bootloader for RP2040 chips" diff --git a/examples/boot/bootloader/rp/src/main.rs b/examples/boot/bootloader/rp/src/main.rs index 25b1657b8..7ebefd374 100644 --- a/examples/boot/bootloader/rp/src/main.rs +++ b/examples/boot/bootloader/rp/src/main.rs @@ -34,8 +34,8 @@ fn main() -> ! { unsafe { bl.load(embassy_rp::flash::FLASH_BASE as u32 + active_offset) } } -#[no_mangle] -#[cfg_attr(target_os = "none", link_section = ".HardFault.user")] +#[unsafe(no_mangle)] +#[cfg_attr(target_os = "none", unsafe(link_section = ".HardFault.user"))] unsafe extern "C" fn HardFault() { cortex_m::peripheral::SCB::sys_reset(); } @@ -43,7 +43,7 @@ unsafe extern "C" fn HardFault() { #[exception] unsafe fn DefaultHandler(_: i16) -> ! { const SCB_ICSR: *const u32 = 0xE000_ED04 as *const u32; - let irqn = core::ptr::read_volatile(SCB_ICSR) as u8 as i16 - 16; + let irqn = unsafe { core::ptr::read_volatile(SCB_ICSR) } as u8 as i16 - 16; panic!("DefaultHandler #{:?}", irqn); } diff --git a/examples/boot/bootloader/stm32-dual-bank/Cargo.toml b/examples/boot/bootloader/stm32-dual-bank/Cargo.toml index 95ca20a59..cf68921dc 100644 --- a/examples/boot/bootloader/stm32-dual-bank/Cargo.toml +++ b/examples/boot/bootloader/stm32-dual-bank/Cargo.toml @@ -1,5 +1,5 @@ [package] -edition = "2021" +edition = "2024" name = "stm32-bootloader-dual-bank-flash-example" version = "0.1.0" description = "Example bootloader for dual-bank flash STM32 chips" diff --git a/examples/boot/bootloader/stm32-dual-bank/src/main.rs b/examples/boot/bootloader/stm32-dual-bank/src/main.rs index 4d2e82d26..ea81e1fe5 100644 --- a/examples/boot/bootloader/stm32-dual-bank/src/main.rs +++ b/examples/boot/bootloader/stm32-dual-bank/src/main.rs @@ -33,8 +33,8 @@ fn main() -> ! { unsafe { bl.load(BANK1_REGION.base + active_offset) } } -#[no_mangle] -#[cfg_attr(target_os = "none", link_section = ".HardFault.user")] +#[unsafe(no_mangle)] +#[cfg_attr(target_os = "none", unsafe(link_section = ".HardFault.user"))] unsafe extern "C" fn HardFault() { cortex_m::peripheral::SCB::sys_reset(); } @@ -42,7 +42,7 @@ unsafe extern "C" fn HardFault() { #[exception] unsafe fn DefaultHandler(_: i16) -> ! { const SCB_ICSR: *const u32 = 0xE000_ED04 as *const u32; - let irqn = core::ptr::read_volatile(SCB_ICSR) as u8 as i16 - 16; + let irqn = unsafe { core::ptr::read_volatile(SCB_ICSR) } as u8 as i16 - 16; panic!("DefaultHandler #{:?}", irqn); } diff --git a/examples/boot/bootloader/stm32/Cargo.toml b/examples/boot/bootloader/stm32/Cargo.toml index 526637f37..e457310b9 100644 --- a/examples/boot/bootloader/stm32/Cargo.toml +++ b/examples/boot/bootloader/stm32/Cargo.toml @@ -1,5 +1,5 @@ [package] -edition = "2021" +edition = "2024" name = "stm32-bootloader-example" version = "0.1.0" description = "Example bootloader for STM32 chips" diff --git a/examples/boot/bootloader/stm32/src/main.rs b/examples/boot/bootloader/stm32/src/main.rs index 99a7a6a6b..f74edd75f 100644 --- a/examples/boot/bootloader/stm32/src/main.rs +++ b/examples/boot/bootloader/stm32/src/main.rs @@ -32,8 +32,8 @@ fn main() -> ! { unsafe { bl.load(BANK1_REGION.base + active_offset) } } -#[no_mangle] -#[cfg_attr(target_os = "none", link_section = ".HardFault.user")] +#[unsafe(no_mangle)] +#[cfg_attr(target_os = "none", unsafe(link_section = ".HardFault.user"))] unsafe extern "C" fn HardFault() { cortex_m::peripheral::SCB::sys_reset(); } @@ -41,7 +41,7 @@ unsafe extern "C" fn HardFault() { #[exception] unsafe fn DefaultHandler(_: i16) -> ! { const SCB_ICSR: *const u32 = 0xE000_ED04 as *const u32; - let irqn = core::ptr::read_volatile(SCB_ICSR) as u8 as i16 - 16; + let irqn = unsafe { core::ptr::read_volatile(SCB_ICSR) } as u8 as i16 - 16; panic!("DefaultHandler #{:?}", irqn); } diff --git a/examples/boot/bootloader/stm32wb-dfu/Cargo.toml b/examples/boot/bootloader/stm32wb-dfu/Cargo.toml index ef10aeabf..75b7081df 100644 --- a/examples/boot/bootloader/stm32wb-dfu/Cargo.toml +++ b/examples/boot/bootloader/stm32wb-dfu/Cargo.toml @@ -1,5 +1,5 @@ [package] -edition = "2021" +edition = "2024" name = "stm32wb-dfu-bootloader-example" version = "0.1.0" description = "Example USB DFUbootloader for the STM32WB series of chips" diff --git a/examples/boot/bootloader/stm32wb-dfu/src/main.rs b/examples/boot/bootloader/stm32wb-dfu/src/main.rs index 107f243fd..475f1234d 100644 --- a/examples/boot/bootloader/stm32wb-dfu/src/main.rs +++ b/examples/boot/bootloader/stm32wb-dfu/src/main.rs @@ -109,8 +109,8 @@ fn main() -> ! { unsafe { bl.load(BANK1_REGION.base + active_offset) } } -#[no_mangle] -#[cfg_attr(target_os = "none", link_section = ".HardFault.user")] +#[unsafe(no_mangle)] +#[cfg_attr(target_os = "none", unsafe(link_section = ".HardFault.user"))] unsafe extern "C" fn HardFault() { cortex_m::peripheral::SCB::sys_reset(); } @@ -118,7 +118,7 @@ unsafe extern "C" fn HardFault() { #[exception] unsafe fn DefaultHandler(_: i16) -> ! { const SCB_ICSR: *const u32 = 0xE000_ED04 as *const u32; - let irqn = core::ptr::read_volatile(SCB_ICSR) as u8 as i16 - 16; + let irqn = unsafe { core::ptr::read_volatile(SCB_ICSR) } as u8 as i16 - 16; panic!("DefaultHandler #{:?}", irqn); } diff --git a/examples/boot/bootloader/stm32wba-dfu/Cargo.toml b/examples/boot/bootloader/stm32wba-dfu/Cargo.toml index 16de7684e..eee2b2f71 100644 --- a/examples/boot/bootloader/stm32wba-dfu/Cargo.toml +++ b/examples/boot/bootloader/stm32wba-dfu/Cargo.toml @@ -1,5 +1,5 @@ [package] -edition = "2021" +edition = "2024" name = "stm32wba6-dfu-bootloader-example" version = "0.1.0" description = "Example USB DFUbootloader for the STM32WBA series of chips" diff --git a/examples/boot/bootloader/stm32wba-dfu/src/main.rs b/examples/boot/bootloader/stm32wba-dfu/src/main.rs index 75d8d4199..e4aacbca9 100644 --- a/examples/boot/bootloader/stm32wba-dfu/src/main.rs +++ b/examples/boot/bootloader/stm32wba-dfu/src/main.rs @@ -138,8 +138,8 @@ fn main() -> ! { unsafe { bl.load(BANK1_REGION.base + active_offset) } } -#[no_mangle] -#[cfg_attr(target_os = "none", link_section = ".HardFault.user")] +#[unsafe(no_mangle)] +#[cfg_attr(target_os = "none", unsafe(link_section = ".HardFault.user"))] unsafe extern "C" fn HardFault() { cortex_m::peripheral::SCB::sys_reset(); } @@ -147,7 +147,7 @@ unsafe extern "C" fn HardFault() { #[exception] unsafe fn DefaultHandler(_: i16) -> ! { const SCB_ICSR: *const u32 = 0xE000_ED04 as *const u32; - let irqn = core::ptr::read_volatile(SCB_ICSR) as u8 as i16 - 16; + let irqn = unsafe { core::ptr::read_volatile(SCB_ICSR) } as u8 as i16 - 16; panic!("DefaultHandler #{:?}", irqn); } diff --git a/examples/lpc55s69/Cargo.toml b/examples/lpc55s69/Cargo.toml index 579748595..94903b3f8 100644 --- a/examples/lpc55s69/Cargo.toml +++ b/examples/lpc55s69/Cargo.toml @@ -1,5 +1,5 @@ [package] -edition = "2021" +edition = "2024" name = "embassy-nxp-lpc55s69-examples" version = "0.1.0" license = "MIT OR Apache-2.0" diff --git a/examples/mimxrt1011/Cargo.toml b/examples/mimxrt1011/Cargo.toml index 3038f5d4d..d784ce729 100644 --- a/examples/mimxrt1011/Cargo.toml +++ b/examples/mimxrt1011/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "embassy-imxrt1011-examples" version = "0.1.0" -edition = "2021" +edition = "2024" license = "MIT OR Apache-2.0" publish = false diff --git a/examples/mimxrt1011/src/lib.rs b/examples/mimxrt1011/src/lib.rs index f0391ef57..36d3e2fb3 100644 --- a/examples/mimxrt1011/src/lib.rs +++ b/examples/mimxrt1011/src/lib.rs @@ -71,5 +71,5 @@ pub const SERIAL_NOR_CONFIGURATION_BLOCK: nor::ConfigurationBlock = .ip_cmd_serial_clk_freq(nor::SerialClockFrequency::MHz30); #[unsafe(no_mangle)] -#[cfg_attr(all(target_arch = "arm", target_os = "none"), link_section = ".fcb")] +#[cfg_attr(all(target_arch = "arm", target_os = "none"), unsafe(link_section = ".fcb"))] pub static FLEXSPI_CONFIGURATION_BLOCK: nor::ConfigurationBlock = SERIAL_NOR_CONFIGURATION_BLOCK; diff --git a/examples/mimxrt1062-evk/Cargo.toml b/examples/mimxrt1062-evk/Cargo.toml index 82a24490d..29a80db12 100644 --- a/examples/mimxrt1062-evk/Cargo.toml +++ b/examples/mimxrt1062-evk/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "embassy-imxrt1062-evk-examples" version = "0.1.0" -edition = "2021" +edition = "2024" license = "MIT OR Apache-2.0" publish = false diff --git a/examples/mimxrt1062-evk/src/lib.rs b/examples/mimxrt1062-evk/src/lib.rs index 3f99f9db3..e952b91ec 100644 --- a/examples/mimxrt1062-evk/src/lib.rs +++ b/examples/mimxrt1062-evk/src/lib.rs @@ -55,6 +55,6 @@ pub const SERIAL_NOR_CONFIGURATION_BLOCK: nor::ConfigurationBlock = .sector_size(4096) .ip_cmd_serial_clk_freq(nor::SerialClockFrequency::MHz30); -#[no_mangle] -#[cfg_attr(all(target_arch = "arm", target_os = "none"), link_section = ".fcb")] +#[unsafe(no_mangle)] +#[cfg_attr(all(target_arch = "arm", target_os = "none"), unsafe(link_section = ".fcb"))] pub static FLEXSPI_CONFIGURATION_BLOCK: nor::ConfigurationBlock = SERIAL_NOR_CONFIGURATION_BLOCK; diff --git a/examples/mimxrt6/Cargo.toml b/examples/mimxrt6/Cargo.toml index 3f7ad8485..dc09e97e7 100644 --- a/examples/mimxrt6/Cargo.toml +++ b/examples/mimxrt6/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "embassy-imxrt-examples" version = "0.1.0" -edition = "2021" +edition = "2024" license = "MIT OR Apache-2.0" publish = false diff --git a/examples/mspm0c1104/Cargo.toml b/examples/mspm0c1104/Cargo.toml index 21434106a..74301bc9c 100644 --- a/examples/mspm0c1104/Cargo.toml +++ b/examples/mspm0c1104/Cargo.toml @@ -1,5 +1,5 @@ [package] -edition = "2021" +edition = "2024" name = "embassy-mspm0-c1104-examples" version = "0.1.0" license = "MIT OR Apache-2.0" diff --git a/examples/mspm0g3507/Cargo.toml b/examples/mspm0g3507/Cargo.toml index 616b82adb..8c230f038 100644 --- a/examples/mspm0g3507/Cargo.toml +++ b/examples/mspm0g3507/Cargo.toml @@ -1,5 +1,5 @@ [package] -edition = "2021" +edition = "2024" name = "embassy-mspm0-g3507-examples" version = "0.1.0" license = "MIT OR Apache-2.0" diff --git a/examples/mspm0g3519/Cargo.toml b/examples/mspm0g3519/Cargo.toml index ae699d6f4..0f5e58343 100644 --- a/examples/mspm0g3519/Cargo.toml +++ b/examples/mspm0g3519/Cargo.toml @@ -1,5 +1,5 @@ [package] -edition = "2021" +edition = "2024" name = "embassy-mspm0-g3519-examples" version = "0.1.0" license = "MIT OR Apache-2.0" diff --git a/examples/mspm0l1306/Cargo.toml b/examples/mspm0l1306/Cargo.toml index 8100e11da..d5b5e9d3e 100644 --- a/examples/mspm0l1306/Cargo.toml +++ b/examples/mspm0l1306/Cargo.toml @@ -1,5 +1,5 @@ [package] -edition = "2021" +edition = "2024" name = "embassy-mspm0-l1306-examples" version = "0.1.0" license = "MIT OR Apache-2.0" diff --git a/examples/mspm0l2228/Cargo.toml b/examples/mspm0l2228/Cargo.toml index 3add7b8e8..1d27ae64a 100644 --- a/examples/mspm0l2228/Cargo.toml +++ b/examples/mspm0l2228/Cargo.toml @@ -1,5 +1,5 @@ [package] -edition = "2021" +edition = "2024" name = "embassy-mspm0-l2228-examples" version = "0.1.0" license = "MIT OR Apache-2.0" diff --git a/examples/nrf-rtos-trace/Cargo.toml b/examples/nrf-rtos-trace/Cargo.toml index d2d0ae093..5caabf228 100644 --- a/examples/nrf-rtos-trace/Cargo.toml +++ b/examples/nrf-rtos-trace/Cargo.toml @@ -1,5 +1,5 @@ [package] -edition = "2021" +edition = "2024" name = "embassy-nrf-rtos-trace-examples" version = "0.1.0" license = "MIT OR Apache-2.0" diff --git a/examples/nrf51/Cargo.toml b/examples/nrf51/Cargo.toml index 082d85e5b..c7492f562 100644 --- a/examples/nrf51/Cargo.toml +++ b/examples/nrf51/Cargo.toml @@ -1,5 +1,5 @@ [package] -edition = "2021" +edition = "2024" name = "embassy-nrf51-examples" version = "0.1.0" license = "MIT OR Apache-2.0" diff --git a/examples/nrf52810/Cargo.toml b/examples/nrf52810/Cargo.toml index 7835320e5..1711a3d8d 100644 --- a/examples/nrf52810/Cargo.toml +++ b/examples/nrf52810/Cargo.toml @@ -1,5 +1,5 @@ [package] -edition = "2021" +edition = "2024" name = "embassy-nrf52810-examples" version = "0.1.0" license = "MIT OR Apache-2.0" diff --git a/examples/nrf52840-edf/Cargo.toml b/examples/nrf52840-edf/Cargo.toml index 67a624d6d..8b1db4652 100644 --- a/examples/nrf52840-edf/Cargo.toml +++ b/examples/nrf52840-edf/Cargo.toml @@ -1,5 +1,5 @@ [package] -edition = "2021" +edition = "2024" name = "embassy-nrf52840-edf-examples" version = "0.1.0" license = "MIT OR Apache-2.0" diff --git a/examples/nrf52840-rtic/Cargo.toml b/examples/nrf52840-rtic/Cargo.toml index d860626a1..26b21598f 100644 --- a/examples/nrf52840-rtic/Cargo.toml +++ b/examples/nrf52840-rtic/Cargo.toml @@ -1,5 +1,5 @@ [package] -edition = "2021" +edition = "2024" name = "embassy-nrf52840-rtic-examples" version = "0.1.0" license = "MIT OR Apache-2.0" diff --git a/examples/nrf52840/Cargo.toml b/examples/nrf52840/Cargo.toml index 5b3e176c0..a026d6352 100644 --- a/examples/nrf52840/Cargo.toml +++ b/examples/nrf52840/Cargo.toml @@ -1,5 +1,5 @@ [package] -edition = "2021" +edition = "2024" name = "embassy-nrf52840-examples" version = "0.1.0" license = "MIT OR Apache-2.0" diff --git a/examples/nrf52840/src/bin/multiprio.rs b/examples/nrf52840/src/bin/multiprio.rs index 4d9b986d4..dc566adee 100644 --- a/examples/nrf52840/src/bin/multiprio.rs +++ b/examples/nrf52840/src/bin/multiprio.rs @@ -113,12 +113,12 @@ static EXECUTOR_LOW: StaticCell = StaticCell::new(); #[interrupt] unsafe fn EGU1_SWI1() { - EXECUTOR_HIGH.on_interrupt() + unsafe { EXECUTOR_HIGH.on_interrupt() } } #[interrupt] unsafe fn EGU0_SWI0() { - EXECUTOR_MED.on_interrupt() + unsafe { EXECUTOR_MED.on_interrupt() } } #[entry] diff --git a/examples/nrf52840/src/bin/raw_spawn.rs b/examples/nrf52840/src/bin/raw_spawn.rs index b80954408..faa8517c8 100644 --- a/examples/nrf52840/src/bin/raw_spawn.rs +++ b/examples/nrf52840/src/bin/raw_spawn.rs @@ -48,5 +48,5 @@ fn main() -> ! { } unsafe fn make_static(t: &T) -> &'static T { - mem::transmute(t) + unsafe { mem::transmute(t) } } diff --git a/examples/nrf5340/Cargo.toml b/examples/nrf5340/Cargo.toml index 256fee08d..4dcbdd715 100644 --- a/examples/nrf5340/Cargo.toml +++ b/examples/nrf5340/Cargo.toml @@ -1,5 +1,5 @@ [package] -edition = "2021" +edition = "2024" name = "embassy-nrf5340-examples" version = "0.1.0" license = "MIT OR Apache-2.0" diff --git a/examples/nrf54l15/Cargo.toml b/examples/nrf54l15/Cargo.toml index 9c24cdab4..a053dd0ec 100644 --- a/examples/nrf54l15/Cargo.toml +++ b/examples/nrf54l15/Cargo.toml @@ -1,5 +1,5 @@ [package] -edition = "2021" +edition = "2024" name = "embassy-nrf54l15-examples" version = "0.1.0" license = "MIT OR Apache-2.0" diff --git a/examples/nrf9151/ns/Cargo.toml b/examples/nrf9151/ns/Cargo.toml index 89a6c7c94..7f1f5239a 100644 --- a/examples/nrf9151/ns/Cargo.toml +++ b/examples/nrf9151/ns/Cargo.toml @@ -1,5 +1,5 @@ [package] -edition = "2021" +edition = "2024" name = "embassy-nrf9151-non-secure-examples" version = "0.1.0" license = "MIT OR Apache-2.0" diff --git a/examples/nrf9151/s/Cargo.toml b/examples/nrf9151/s/Cargo.toml index 870311c5d..ce71cc456 100644 --- a/examples/nrf9151/s/Cargo.toml +++ b/examples/nrf9151/s/Cargo.toml @@ -1,5 +1,5 @@ [package] -edition = "2021" +edition = "2024" name = "embassy-nrf9151-secure-examples" version = "0.1.0" license = "MIT OR Apache-2.0" diff --git a/examples/nrf9160/Cargo.toml b/examples/nrf9160/Cargo.toml index 274e26dd6..ae3b2eeb1 100644 --- a/examples/nrf9160/Cargo.toml +++ b/examples/nrf9160/Cargo.toml @@ -1,5 +1,5 @@ [package] -edition = "2021" +edition = "2024" name = "embassy-nrf9160-examples" version = "0.1.0" license = "MIT OR Apache-2.0" diff --git a/examples/nrf9160/src/bin/modem_tcp_client.rs b/examples/nrf9160/src/bin/modem_tcp_client.rs index 460a4cfae..c9d879662 100644 --- a/examples/nrf9160/src/bin/modem_tcp_client.rs +++ b/examples/nrf9160/src/bin/modem_tcp_client.rs @@ -101,7 +101,7 @@ async fn blink_task(pin: Peri<'static, AnyPin>) { } } -extern "C" { +unsafe extern "C" { static __start_ipc: u8; static __end_ipc: u8; } diff --git a/examples/rp/Cargo.toml b/examples/rp/Cargo.toml index 97e019cdf..640addb28 100644 --- a/examples/rp/Cargo.toml +++ b/examples/rp/Cargo.toml @@ -1,5 +1,5 @@ [package] -edition = "2021" +edition = "2024" name = "embassy-rp-examples" version = "0.1.0" license = "MIT OR Apache-2.0" diff --git a/examples/rp/src/bin/multiprio.rs b/examples/rp/src/bin/multiprio.rs index 96cdf8fb1..0750d9bb7 100644 --- a/examples/rp/src/bin/multiprio.rs +++ b/examples/rp/src/bin/multiprio.rs @@ -113,12 +113,12 @@ static EXECUTOR_LOW: StaticCell = StaticCell::new(); #[interrupt] unsafe fn SWI_IRQ_1() { - EXECUTOR_HIGH.on_interrupt() + unsafe { EXECUTOR_HIGH.on_interrupt() } } #[interrupt] unsafe fn SWI_IRQ_0() { - EXECUTOR_MED.on_interrupt() + unsafe { EXECUTOR_MED.on_interrupt() } } #[entry] diff --git a/examples/rp/src/bin/sharing.rs b/examples/rp/src/bin/sharing.rs index d4c89946b..618ab9117 100644 --- a/examples/rp/src/bin/sharing.rs +++ b/examples/rp/src/bin/sharing.rs @@ -52,7 +52,7 @@ bind_interrupts!(struct Irqs { #[interrupt] unsafe fn SWI_IRQ_0() { - EXECUTOR_HI.on_interrupt() + unsafe { EXECUTOR_HI.on_interrupt() } } #[entry] diff --git a/examples/rp235x/Cargo.toml b/examples/rp235x/Cargo.toml index 40fbb5798..39a4f421a 100644 --- a/examples/rp235x/Cargo.toml +++ b/examples/rp235x/Cargo.toml @@ -1,5 +1,5 @@ [package] -edition = "2021" +edition = "2024" name = "embassy-rp2350-examples" version = "0.1.0" license = "MIT OR Apache-2.0" diff --git a/examples/rp235x/src/bin/multiprio.rs b/examples/rp235x/src/bin/multiprio.rs index 96cdf8fb1..0750d9bb7 100644 --- a/examples/rp235x/src/bin/multiprio.rs +++ b/examples/rp235x/src/bin/multiprio.rs @@ -113,12 +113,12 @@ static EXECUTOR_LOW: StaticCell = StaticCell::new(); #[interrupt] unsafe fn SWI_IRQ_1() { - EXECUTOR_HIGH.on_interrupt() + unsafe { EXECUTOR_HIGH.on_interrupt() } } #[interrupt] unsafe fn SWI_IRQ_0() { - EXECUTOR_MED.on_interrupt() + unsafe { EXECUTOR_MED.on_interrupt() } } #[entry] diff --git a/examples/rp235x/src/bin/sharing.rs b/examples/rp235x/src/bin/sharing.rs index d4c89946b..618ab9117 100644 --- a/examples/rp235x/src/bin/sharing.rs +++ b/examples/rp235x/src/bin/sharing.rs @@ -52,7 +52,7 @@ bind_interrupts!(struct Irqs { #[interrupt] unsafe fn SWI_IRQ_0() { - EXECUTOR_HI.on_interrupt() + unsafe { EXECUTOR_HI.on_interrupt() } } #[entry] diff --git a/examples/std/Cargo.toml b/examples/std/Cargo.toml index 449c5ddca..6dc6a353d 100644 --- a/examples/std/Cargo.toml +++ b/examples/std/Cargo.toml @@ -1,5 +1,5 @@ [package] -edition = "2021" +edition = "2024" name = "embassy-std-examples" version = "0.1.0" license = "MIT OR Apache-2.0" diff --git a/examples/stm32c0/Cargo.toml b/examples/stm32c0/Cargo.toml index bb7b57496..696a95854 100644 --- a/examples/stm32c0/Cargo.toml +++ b/examples/stm32c0/Cargo.toml @@ -1,5 +1,5 @@ [package] -edition = "2021" +edition = "2024" name = "embassy-stm32c0-examples" version = "0.1.0" license = "MIT OR Apache-2.0" diff --git a/examples/stm32f0/Cargo.toml b/examples/stm32f0/Cargo.toml index 11ecbe3c2..a78873d21 100644 --- a/examples/stm32f0/Cargo.toml +++ b/examples/stm32f0/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "embassy-stm32f0-examples" version = "0.1.0" -edition = "2021" +edition = "2024" license = "MIT OR Apache-2.0" publish = false diff --git a/examples/stm32f0/src/bin/multiprio.rs b/examples/stm32f0/src/bin/multiprio.rs index b5244afc8..9a8dc5685 100644 --- a/examples/stm32f0/src/bin/multiprio.rs +++ b/examples/stm32f0/src/bin/multiprio.rs @@ -113,12 +113,12 @@ static EXECUTOR_LOW: StaticCell = StaticCell::new(); #[interrupt] unsafe fn USART1() { - EXECUTOR_HIGH.on_interrupt() + unsafe { EXECUTOR_HIGH.on_interrupt() } } #[interrupt] unsafe fn USART2() { - EXECUTOR_MED.on_interrupt() + unsafe { EXECUTOR_MED.on_interrupt() } } #[entry] diff --git a/examples/stm32f1/Cargo.toml b/examples/stm32f1/Cargo.toml index dcb58796b..5714b149a 100644 --- a/examples/stm32f1/Cargo.toml +++ b/examples/stm32f1/Cargo.toml @@ -1,5 +1,5 @@ [package] -edition = "2021" +edition = "2024" name = "embassy-stm32f1-examples" version = "0.1.0" license = "MIT OR Apache-2.0" diff --git a/examples/stm32f2/Cargo.toml b/examples/stm32f2/Cargo.toml index 498c20d84..f726018c3 100644 --- a/examples/stm32f2/Cargo.toml +++ b/examples/stm32f2/Cargo.toml @@ -1,5 +1,5 @@ [package] -edition = "2021" +edition = "2024" name = "embassy-stm32f2-examples" version = "0.1.0" license = "MIT OR Apache-2.0" diff --git a/examples/stm32f3/Cargo.toml b/examples/stm32f3/Cargo.toml index 23025ef0b..4349e8055 100644 --- a/examples/stm32f3/Cargo.toml +++ b/examples/stm32f3/Cargo.toml @@ -1,5 +1,5 @@ [package] -edition = "2021" +edition = "2024" name = "embassy-stm32f3-examples" version = "0.1.0" license = "MIT OR Apache-2.0" diff --git a/examples/stm32f3/src/bin/multiprio.rs b/examples/stm32f3/src/bin/multiprio.rs index 2f2ffdea2..8375e0e8e 100644 --- a/examples/stm32f3/src/bin/multiprio.rs +++ b/examples/stm32f3/src/bin/multiprio.rs @@ -113,12 +113,12 @@ static EXECUTOR_LOW: StaticCell = StaticCell::new(); #[interrupt] unsafe fn UART4() { - EXECUTOR_HIGH.on_interrupt() + unsafe { EXECUTOR_HIGH.on_interrupt() } } #[interrupt] unsafe fn UART5() { - EXECUTOR_MED.on_interrupt() + unsafe { EXECUTOR_MED.on_interrupt() } } #[entry] diff --git a/examples/stm32f334/Cargo.toml b/examples/stm32f334/Cargo.toml index 3495b118c..cf22633dd 100644 --- a/examples/stm32f334/Cargo.toml +++ b/examples/stm32f334/Cargo.toml @@ -1,5 +1,5 @@ [package] -edition = "2021" +edition = "2024" name = "embassy-stm32f334-examples" version = "0.1.0" license = "MIT OR Apache-2.0" diff --git a/examples/stm32f4/Cargo.toml b/examples/stm32f4/Cargo.toml index fb5f86aac..d06b7505c 100644 --- a/examples/stm32f4/Cargo.toml +++ b/examples/stm32f4/Cargo.toml @@ -1,5 +1,5 @@ [package] -edition = "2021" +edition = "2024" name = "embassy-stm32f4-examples" version = "0.1.0" license = "MIT OR Apache-2.0" diff --git a/examples/stm32f4/src/bin/multiprio.rs b/examples/stm32f4/src/bin/multiprio.rs index 2f2ffdea2..8375e0e8e 100644 --- a/examples/stm32f4/src/bin/multiprio.rs +++ b/examples/stm32f4/src/bin/multiprio.rs @@ -113,12 +113,12 @@ static EXECUTOR_LOW: StaticCell = StaticCell::new(); #[interrupt] unsafe fn UART4() { - EXECUTOR_HIGH.on_interrupt() + unsafe { EXECUTOR_HIGH.on_interrupt() } } #[interrupt] unsafe fn UART5() { - EXECUTOR_MED.on_interrupt() + unsafe { EXECUTOR_MED.on_interrupt() } } #[entry] diff --git a/examples/stm32f469/Cargo.toml b/examples/stm32f469/Cargo.toml index f1d0e411a..5216e19b4 100644 --- a/examples/stm32f469/Cargo.toml +++ b/examples/stm32f469/Cargo.toml @@ -1,5 +1,5 @@ [package] -edition = "2021" +edition = "2024" name = "embassy-stm32f469-examples" version = "0.1.0" license = "MIT OR Apache-2.0" diff --git a/examples/stm32f7/Cargo.toml b/examples/stm32f7/Cargo.toml index 5d7763334..565277394 100644 --- a/examples/stm32f7/Cargo.toml +++ b/examples/stm32f7/Cargo.toml @@ -1,5 +1,5 @@ [package] -edition = "2021" +edition = "2024" name = "embassy-stm32f7-examples" version = "0.1.0" license = "MIT OR Apache-2.0" diff --git a/examples/stm32g0/Cargo.toml b/examples/stm32g0/Cargo.toml index 1c9451469..16f28500d 100644 --- a/examples/stm32g0/Cargo.toml +++ b/examples/stm32g0/Cargo.toml @@ -1,5 +1,5 @@ [package] -edition = "2021" +edition = "2024" name = "embassy-stm32g0-examples" version = "0.1.0" license = "MIT OR Apache-2.0" diff --git a/examples/stm32g4/Cargo.toml b/examples/stm32g4/Cargo.toml index 102960980..6fd282d6d 100644 --- a/examples/stm32g4/Cargo.toml +++ b/examples/stm32g4/Cargo.toml @@ -1,5 +1,5 @@ [package] -edition = "2021" +edition = "2024" name = "embassy-stm32g4-examples" version = "0.1.0" license = "MIT OR Apache-2.0" diff --git a/examples/stm32h5/Cargo.toml b/examples/stm32h5/Cargo.toml index 66680c027..475ba7e8a 100644 --- a/examples/stm32h5/Cargo.toml +++ b/examples/stm32h5/Cargo.toml @@ -1,5 +1,5 @@ [package] -edition = "2021" +edition = "2024" name = "embassy-stm32h5-examples" version = "0.1.0" license = "MIT OR Apache-2.0" diff --git a/examples/stm32h7/Cargo.toml b/examples/stm32h7/Cargo.toml index 9a2080013..5993110de 100644 --- a/examples/stm32h7/Cargo.toml +++ b/examples/stm32h7/Cargo.toml @@ -1,5 +1,5 @@ [package] -edition = "2021" +edition = "2024" name = "embassy-stm32h7-examples" version = "0.1.0" license = "MIT OR Apache-2.0" diff --git a/examples/stm32h7/src/bin/multiprio.rs b/examples/stm32h7/src/bin/multiprio.rs index 2f2ffdea2..8375e0e8e 100644 --- a/examples/stm32h7/src/bin/multiprio.rs +++ b/examples/stm32h7/src/bin/multiprio.rs @@ -113,12 +113,12 @@ static EXECUTOR_LOW: StaticCell = StaticCell::new(); #[interrupt] unsafe fn UART4() { - EXECUTOR_HIGH.on_interrupt() + unsafe { EXECUTOR_HIGH.on_interrupt() } } #[interrupt] unsafe fn UART5() { - EXECUTOR_MED.on_interrupt() + unsafe { EXECUTOR_MED.on_interrupt() } } #[entry] diff --git a/examples/stm32h723/Cargo.toml b/examples/stm32h723/Cargo.toml index 7e4ccc528..93a5109e2 100644 --- a/examples/stm32h723/Cargo.toml +++ b/examples/stm32h723/Cargo.toml @@ -1,5 +1,5 @@ [package] -edition = "2021" +edition = "2024" name = "embassy-stm32h723-examples" version = "0.1.0" license = "MIT OR Apache-2.0" diff --git a/examples/stm32h735/Cargo.toml b/examples/stm32h735/Cargo.toml index 22b7ad96a..1ad2eeb2e 100644 --- a/examples/stm32h735/Cargo.toml +++ b/examples/stm32h735/Cargo.toml @@ -1,5 +1,5 @@ [package] -edition = "2021" +edition = "2024" name = "embassy-stm32h735-examples" version = "0.1.0" license = "MIT OR Apache-2.0" diff --git a/examples/stm32h742/Cargo.toml b/examples/stm32h742/Cargo.toml index c76340b5f..9b5e5d93d 100644 --- a/examples/stm32h742/Cargo.toml +++ b/examples/stm32h742/Cargo.toml @@ -1,5 +1,5 @@ [package] -edition = "2021" +edition = "2024" name = "embassy-stm32h742-examples" version = "0.1.0" license = "MIT OR Apache-2.0" diff --git a/examples/stm32h755cm4/Cargo.toml b/examples/stm32h755cm4/Cargo.toml index c73f9df79..b5c313523 100644 --- a/examples/stm32h755cm4/Cargo.toml +++ b/examples/stm32h755cm4/Cargo.toml @@ -1,5 +1,5 @@ [package] -edition = "2021" +edition = "2024" name = "embassy-stm32h755cm4-examples" version = "0.1.0" license = "MIT OR Apache-2.0" diff --git a/examples/stm32h755cm4/src/bin/intercore.rs b/examples/stm32h755cm4/src/bin/intercore.rs index f584e31e9..d93d31786 100644 --- a/examples/stm32h755cm4/src/bin/intercore.rs +++ b/examples/stm32h755cm4/src/bin/intercore.rs @@ -85,7 +85,7 @@ mod shared { } } - #[link_section = ".ram_d3"] + #[unsafe(link_section = ".ram_d3")] pub static SHARED_LED_STATE: SharedLedState = SharedLedState::new(); } @@ -99,7 +99,7 @@ use embassy_time::Timer; use shared::SHARED_LED_STATE; use {defmt_rtt as _, panic_probe as _}; -#[link_section = ".ram_d3"] +#[unsafe(link_section = ".ram_d3")] static SHARED_DATA: MaybeUninit = MaybeUninit::uninit(); /// Task that continuously blinks the red LED as a heartbeat indicator diff --git a/examples/stm32h755cm7/Cargo.toml b/examples/stm32h755cm7/Cargo.toml index c34d4e45c..7a1519aae 100644 --- a/examples/stm32h755cm7/Cargo.toml +++ b/examples/stm32h755cm7/Cargo.toml @@ -1,5 +1,5 @@ [package] -edition = "2021" +edition = "2024" name = "embassy-stm32h755cm7-examples" version = "0.1.0" license = "MIT OR Apache-2.0" diff --git a/examples/stm32h755cm7/src/bin/intercore.rs b/examples/stm32h755cm7/src/bin/intercore.rs index a4e1b5ff4..3df0b26d7 100644 --- a/examples/stm32h755cm7/src/bin/intercore.rs +++ b/examples/stm32h755cm7/src/bin/intercore.rs @@ -97,7 +97,7 @@ mod shared { } } - #[link_section = ".ram_d3"] + #[unsafe(link_section = ".ram_d3")] pub static SHARED_LED_STATE: SharedLedState = SharedLedState::new(); // Memory region constants for MPU configuration @@ -106,7 +106,7 @@ mod shared { pub const SRAM4_REGION_NUMBER: u8 = 0; } -#[link_section = ".ram_d3"] +#[unsafe(link_section = ".ram_d3")] static SHARED_DATA: MaybeUninit = MaybeUninit::uninit(); /// Configure MPU to make SRAM4 region non-cacheable diff --git a/examples/stm32h7b0/Cargo.toml b/examples/stm32h7b0/Cargo.toml index 1917749c5..4cd7b84e5 100644 --- a/examples/stm32h7b0/Cargo.toml +++ b/examples/stm32h7b0/Cargo.toml @@ -1,5 +1,5 @@ [package] -edition = "2021" +edition = "2024" name = "embassy-stm32h7b0-examples" version = "0.1.0" license = "MIT OR Apache-2.0" diff --git a/examples/stm32h7rs/Cargo.toml b/examples/stm32h7rs/Cargo.toml index bfe59b68d..445916972 100644 --- a/examples/stm32h7rs/Cargo.toml +++ b/examples/stm32h7rs/Cargo.toml @@ -1,5 +1,5 @@ [package] -edition = "2021" +edition = "2024" name = "embassy-stm32h7rs-examples" version = "0.1.0" license = "MIT OR Apache-2.0" diff --git a/examples/stm32h7rs/src/bin/multiprio.rs b/examples/stm32h7rs/src/bin/multiprio.rs index 2f2ffdea2..8375e0e8e 100644 --- a/examples/stm32h7rs/src/bin/multiprio.rs +++ b/examples/stm32h7rs/src/bin/multiprio.rs @@ -113,12 +113,12 @@ static EXECUTOR_LOW: StaticCell = StaticCell::new(); #[interrupt] unsafe fn UART4() { - EXECUTOR_HIGH.on_interrupt() + unsafe { EXECUTOR_HIGH.on_interrupt() } } #[interrupt] unsafe fn UART5() { - EXECUTOR_MED.on_interrupt() + unsafe { EXECUTOR_MED.on_interrupt() } } #[entry] diff --git a/examples/stm32l0/Cargo.toml b/examples/stm32l0/Cargo.toml index d42cdac15..a9c71d655 100644 --- a/examples/stm32l0/Cargo.toml +++ b/examples/stm32l0/Cargo.toml @@ -1,5 +1,5 @@ [package] -edition = "2021" +edition = "2024" name = "embassy-stm32l0-examples" version = "0.1.0" license = "MIT OR Apache-2.0" diff --git a/examples/stm32l0/src/bin/raw_spawn.rs b/examples/stm32l0/src/bin/raw_spawn.rs index 6385e3c8f..7eea910ca 100644 --- a/examples/stm32l0/src/bin/raw_spawn.rs +++ b/examples/stm32l0/src/bin/raw_spawn.rs @@ -48,5 +48,5 @@ fn main() -> ! { } unsafe fn make_static(t: &T) -> &'static T { - mem::transmute(t) + unsafe { mem::transmute(t) } } diff --git a/examples/stm32l1/Cargo.toml b/examples/stm32l1/Cargo.toml index 76ceade9c..7f6b31ed5 100644 --- a/examples/stm32l1/Cargo.toml +++ b/examples/stm32l1/Cargo.toml @@ -1,5 +1,5 @@ [package] -edition = "2021" +edition = "2024" name = "embassy-stm32l1-examples" version = "0.1.0" license = "MIT OR Apache-2.0" diff --git a/examples/stm32l4/Cargo.toml b/examples/stm32l4/Cargo.toml index 1b7f15b1d..936472199 100644 --- a/examples/stm32l4/Cargo.toml +++ b/examples/stm32l4/Cargo.toml @@ -1,5 +1,5 @@ [package] -edition = "2021" +edition = "2024" name = "embassy-stm32l4-examples" version = "0.1.1" license = "MIT OR Apache-2.0" diff --git a/examples/stm32l432/Cargo.toml b/examples/stm32l432/Cargo.toml index f173c651e..14f41992d 100644 --- a/examples/stm32l432/Cargo.toml +++ b/examples/stm32l432/Cargo.toml @@ -1,5 +1,5 @@ [package] -edition = "2021" +edition = "2024" name = "embassy-stm32l432-examples" version = "0.1.1" license = "MIT OR Apache-2.0" diff --git a/examples/stm32l5/Cargo.toml b/examples/stm32l5/Cargo.toml index 9999300b8..b6158c854 100644 --- a/examples/stm32l5/Cargo.toml +++ b/examples/stm32l5/Cargo.toml @@ -1,5 +1,5 @@ [package] -edition = "2021" +edition = "2024" name = "embassy-stm32l5-examples" version = "0.1.0" license = "MIT OR Apache-2.0" diff --git a/examples/stm32u0/Cargo.toml b/examples/stm32u0/Cargo.toml index 9318414a5..9f5227e3f 100644 --- a/examples/stm32u0/Cargo.toml +++ b/examples/stm32u0/Cargo.toml @@ -1,5 +1,5 @@ [package] -edition = "2021" +edition = "2024" name = "embassy-stm32u0-examples" version = "0.1.0" license = "MIT OR Apache-2.0" diff --git a/examples/stm32u5/Cargo.toml b/examples/stm32u5/Cargo.toml index f2ffe52c5..7a1e62406 100644 --- a/examples/stm32u5/Cargo.toml +++ b/examples/stm32u5/Cargo.toml @@ -1,5 +1,5 @@ [package] -edition = "2021" +edition = "2024" name = "embassy-stm32u5-examples" version = "0.1.0" license = "MIT OR Apache-2.0" diff --git a/examples/stm32wb/Cargo.toml b/examples/stm32wb/Cargo.toml index 7ab13c290..783690c11 100644 --- a/examples/stm32wb/Cargo.toml +++ b/examples/stm32wb/Cargo.toml @@ -1,5 +1,5 @@ [package] -edition = "2021" +edition = "2024" name = "embassy-stm32wb-examples" version = "0.1.0" license = "MIT OR Apache-2.0" diff --git a/examples/stm32wba/Cargo.toml b/examples/stm32wba/Cargo.toml index e1196614a..3496b41b0 100644 --- a/examples/stm32wba/Cargo.toml +++ b/examples/stm32wba/Cargo.toml @@ -1,5 +1,5 @@ [package] -edition = "2021" +edition = "2024" name = "embassy-stm32wba-examples" version = "0.1.0" license = "MIT OR Apache-2.0" diff --git a/examples/stm32wba6/Cargo.toml b/examples/stm32wba6/Cargo.toml index f98317846..04bb27cb0 100644 --- a/examples/stm32wba6/Cargo.toml +++ b/examples/stm32wba6/Cargo.toml @@ -1,5 +1,5 @@ [package] -edition = "2021" +edition = "2024" name = "embassy-stm32wba6-examples" version = "0.1.0" license = "MIT OR Apache-2.0" diff --git a/examples/stm32wl/Cargo.toml b/examples/stm32wl/Cargo.toml index 825d25c0d..1754aa0b8 100644 --- a/examples/stm32wl/Cargo.toml +++ b/examples/stm32wl/Cargo.toml @@ -1,5 +1,5 @@ [package] -edition = "2021" +edition = "2024" name = "embassy-stm32wl-examples" version = "0.1.0" license = "MIT OR Apache-2.0" diff --git a/examples/wasm/Cargo.toml b/examples/wasm/Cargo.toml index e8897506c..79d50b584 100644 --- a/examples/wasm/Cargo.toml +++ b/examples/wasm/Cargo.toml @@ -1,5 +1,5 @@ [package] -edition = "2021" +edition = "2024" name = "embassy-wasm-example" version = "0.1.0" license = "MIT OR Apache-2.0" diff --git a/rustfmt.toml b/rustfmt.toml index 2561562fd..3d5eeed93 100644 --- a/rustfmt.toml +++ b/rustfmt.toml @@ -1,4 +1,4 @@ group_imports = "StdExternalCrate" imports_granularity = "Module" -edition = "2021" +edition = "2024" max_width = 120 diff --git a/tests/mspm0/Cargo.toml b/tests/mspm0/Cargo.toml index 227d898d5..df52b538d 100644 --- a/tests/mspm0/Cargo.toml +++ b/tests/mspm0/Cargo.toml @@ -1,5 +1,5 @@ [package] -edition = "2021" +edition = "2024" name = "embassy-mspm0-tests" version = "0.1.0" license = "MIT OR Apache-2.0" diff --git a/tests/nrf/Cargo.toml b/tests/nrf/Cargo.toml index 8acf27ce7..3a9b86cef 100644 --- a/tests/nrf/Cargo.toml +++ b/tests/nrf/Cargo.toml @@ -1,5 +1,5 @@ [package] -edition = "2021" +edition = "2024" name = "embassy-nrf-examples" version = "0.1.0" license = "MIT OR Apache-2.0" diff --git a/tests/perf-client/Cargo.toml b/tests/perf-client/Cargo.toml index c426fdd74..3756046fa 100644 --- a/tests/perf-client/Cargo.toml +++ b/tests/perf-client/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "perf-client" version = "0.1.0" -edition = "2021" +edition = "2024" license = "MIT OR Apache-2.0" publish = false diff --git a/tests/perf-server/Cargo.toml b/tests/perf-server/Cargo.toml index f048eade2..72f92ed8d 100644 --- a/tests/perf-server/Cargo.toml +++ b/tests/perf-server/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "perf-server" version = "0.1.0" -edition = "2021" +edition = "2024" license = "MIT OR Apache-2.0" publish = false diff --git a/tests/riscv32/Cargo.toml b/tests/riscv32/Cargo.toml index c441e8ed3..935c6a2ee 100644 --- a/tests/riscv32/Cargo.toml +++ b/tests/riscv32/Cargo.toml @@ -1,5 +1,5 @@ [package] -edition = "2021" +edition = "2024" name = "embassy-riscv-tests" version = "0.1.0" license = "MIT OR Apache-2.0" diff --git a/tests/rp/Cargo.toml b/tests/rp/Cargo.toml index 19461520a..640e58f11 100644 --- a/tests/rp/Cargo.toml +++ b/tests/rp/Cargo.toml @@ -1,5 +1,5 @@ [package] -edition = "2021" +edition = "2024" name = "embassy-rp-tests" version = "0.1.0" license = "MIT OR Apache-2.0" diff --git a/tests/stm32/Cargo.toml b/tests/stm32/Cargo.toml index 891ec93fd..1161e827b 100644 --- a/tests/stm32/Cargo.toml +++ b/tests/stm32/Cargo.toml @@ -1,5 +1,5 @@ [package] -edition = "2021" +edition = "2024" name = "embassy-stm32-tests" version = "0.1.0" license = "MIT OR Apache-2.0" diff --git a/tests/utils/Cargo.toml b/tests/utils/Cargo.toml index ddb990e0f..da04a1f5d 100644 --- a/tests/utils/Cargo.toml +++ b/tests/utils/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "test-utils" version = "0.1.0" -edition = "2021" +edition = "2024" license = "MIT OR Apache-2.0" publish = false -- cgit From 8730a013c395cf0bf4c2fa8eeb7f138288103039 Mon Sep 17 00:00:00 2001 From: Dario Nieuwenhuis Date: Mon, 6 Oct 2025 22:56:31 +0200 Subject: Rustfmt for edition 2024. --- cyw43-pio/src/lib.rs | 4 +-- cyw43/src/bluetooth.rs | 2 +- cyw43/src/bus.rs | 6 +--- cyw43/src/control.rs | 2 +- cyw43/src/ioctl.rs | 2 +- cyw43/src/runner.rs | 6 ++-- embassy-boot-nrf/src/lib.rs | 2 +- embassy-boot-rp/src/lib.rs | 4 +-- embassy-boot/src/boot_loader.rs | 4 +-- embassy-boot/src/firmware_updater/asynch.rs | 2 +- embassy-boot/src/firmware_updater/blocking.rs | 4 +-- embassy-boot/src/lib.rs | 14 ++++++---- embassy-boot/src/test_flash/blocking.rs | 2 +- .../src/flash/partition/blocking.rs | 2 +- embassy-embedded-hal/src/shared_bus/asynch/i2c.rs | 2 +- embassy-embedded-hal/src/shared_bus/asynch/spi.rs | 2 +- .../src/shared_bus/blocking/i2c.rs | 4 +-- .../src/shared_bus/blocking/spi.rs | 4 +-- embassy-executor-macros/src/macros/main.rs | 2 +- embassy-executor-macros/src/macros/task.rs | 8 ++++-- embassy-executor-macros/src/util.rs | 2 +- embassy-executor/src/arch/avr.rs | 2 +- embassy-executor/src/arch/cortex_ar.rs | 2 +- embassy-executor/src/arch/cortex_m.rs | 2 +- embassy-executor/src/arch/riscv32.rs | 2 +- embassy-executor/src/arch/spin.rs | 2 +- embassy-executor/src/arch/std.rs | 2 +- embassy-executor/src/arch/wasm.rs | 2 +- embassy-executor/src/metadata.rs | 2 +- embassy-executor/src/raw/run_queue.rs | 4 +-- embassy-executor/src/raw/state_atomics_arm.rs | 2 +- embassy-executor/src/raw/state_critical_section.rs | 2 +- embassy-executor/src/raw/trace.rs | 6 +--- embassy-executor/src/raw/waker.rs | 6 ++-- embassy-executor/src/raw/waker_turbo.rs | 2 +- embassy-executor/src/spawner.rs | 12 ++++++-- embassy-executor/tests/test.rs | 4 +-- embassy-hal-internal/src/interrupt.rs | 2 +- embassy-imxrt/src/clocks.rs | 2 +- embassy-imxrt/src/crc.rs | 4 +-- embassy-imxrt/src/dma.rs | 6 ++-- embassy-imxrt/src/flexcomm/mod.rs | 18 ++++++++---- embassy-imxrt/src/flexcomm/uart.rs | 4 +-- embassy-imxrt/src/gpio.rs | 2 +- embassy-imxrt/src/iopctl.rs | 2 +- embassy-imxrt/src/lib.rs | 2 +- embassy-imxrt/src/rng.rs | 4 +-- embassy-imxrt/src/time_driver.rs | 4 +-- embassy-mspm0/src/adc.rs | 6 ++-- embassy-mspm0/src/dma.rs | 8 +++--- embassy-mspm0/src/gpio.rs | 2 +- embassy-mspm0/src/i2c.rs | 4 +-- embassy-mspm0/src/lib.rs | 2 +- embassy-mspm0/src/time_driver.rs | 2 +- embassy-mspm0/src/uart/buffered.rs | 4 +-- embassy-mspm0/src/uart/mod.rs | 13 ++++----- embassy-mspm0/src/wwdt.rs | 4 +-- embassy-net-adin1110/src/crc8.rs | 2 +- embassy-net-adin1110/src/lib.rs | 4 +-- embassy-net-driver-channel/src/lib.rs | 2 +- embassy-net-esp-hosted/src/control.rs | 3 +- embassy-net-esp-hosted/src/ioctl.rs | 2 +- embassy-net-esp-hosted/src/lib.rs | 2 +- embassy-net-nrf91/src/lib.rs | 11 +++----- embassy-net-ppp/src/lib.rs | 2 +- embassy-net-wiznet/src/chip/mod.rs | 2 +- embassy-net-wiznet/src/lib.rs | 2 +- embassy-net/src/icmp.rs | 2 +- embassy-net/src/lib.rs | 2 +- embassy-net/src/raw.rs | 2 +- embassy-net/src/tcp.rs | 4 +-- embassy-net/src/udp.rs | 2 +- embassy-nrf/src/buffered_uarte.rs | 12 ++++---- embassy-nrf/src/egu.rs | 2 +- embassy-nrf/src/embassy_net_802154_driver.rs | 4 +-- embassy-nrf/src/gpio.rs | 4 +-- embassy-nrf/src/gpiote.rs | 4 +-- embassy-nrf/src/i2s.rs | 4 +-- embassy-nrf/src/lib.rs | 2 +- embassy-nrf/src/nfct.rs | 6 ++-- embassy-nrf/src/nvmc.rs | 2 +- embassy-nrf/src/pdm.rs | 4 +-- embassy-nrf/src/ppi/dppi.rs | 2 +- embassy-nrf/src/ppi/mod.rs | 4 +-- embassy-nrf/src/ppi/ppi.rs | 2 +- embassy-nrf/src/pwm.rs | 4 +-- embassy-nrf/src/qspi.rs | 2 +- embassy-nrf/src/radio/ieee802154.rs | 4 +-- embassy-nrf/src/rramc.rs | 2 +- embassy-nrf/src/saadc.rs | 4 +-- embassy-nrf/src/spim.rs | 6 ++-- embassy-nrf/src/spis.rs | 6 ++-- embassy-nrf/src/temp.rs | 2 +- embassy-nrf/src/time_driver.rs | 4 +-- embassy-nrf/src/twim.rs | 2 +- embassy-nrf/src/twis.rs | 4 +-- embassy-nrf/src/uarte.rs | 4 +-- embassy-nrf/src/usb/mod.rs | 10 ++----- embassy-nrf/src/usb/vbus_detect.rs | 2 +- embassy-nrf/src/util.rs | 6 +--- embassy-nrf/src/wdt.rs | 2 +- embassy-nxp/src/dma/lpc55.rs | 6 ++-- embassy-nxp/src/gpio/lpc55.rs | 4 +-- embassy-nxp/src/gpio/rt1xxx.rs | 4 +-- embassy-nxp/src/lib.rs | 2 +- embassy-nxp/src/pint.rs | 4 +-- embassy-nxp/src/time_driver/rtc.rs | 4 +-- embassy-nxp/src/usart/lpc55.rs | 6 ++-- embassy-rp/src/adc.rs | 8 +++--- embassy-rp/src/bootsel.rs | 2 +- embassy-rp/src/clocks.rs | 4 +-- embassy-rp/src/dma.rs | 4 +-- embassy-rp/src/flash.rs | 4 +-- embassy-rp/src/float/cmp.rs | 12 ++------ embassy-rp/src/float/functions.rs | 12 ++------ embassy-rp/src/gpio.rs | 6 ++-- embassy-rp/src/i2c_slave.rs | 4 +-- embassy-rp/src/multicore.rs | 4 +-- embassy-rp/src/pio/mod.rs | 14 ++++------ embassy-rp/src/pio_programs/hd44780.rs | 2 +- embassy-rp/src/pio_programs/i2s.rs | 2 +- embassy-rp/src/pio_programs/onewire.rs | 8 ++---- embassy-rp/src/pio_programs/pwm.rs | 2 +- embassy-rp/src/pio_programs/rotary_encoder.rs | 2 +- embassy-rp/src/pio_programs/stepper.rs | 2 +- embassy-rp/src/pio_programs/uart.rs | 2 +- embassy-rp/src/pio_programs/ws2812.rs | 2 +- embassy-rp/src/psram.rs | 2 +- embassy-rp/src/pwm.rs | 4 +-- embassy-rp/src/rtc/mod.rs | 2 +- embassy-rp/src/time_driver.rs | 2 +- embassy-rp/src/uart/mod.rs | 16 +++-------- embassy-rp/src/usb.rs | 16 +++-------- embassy-rp/src/watchdog.rs | 2 +- embassy-stm32-wpan/src/cmd.rs | 2 +- embassy-stm32-wpan/src/consts.rs | 2 +- embassy-stm32-wpan/src/lhci.rs | 4 +-- embassy-stm32-wpan/src/lib.rs | 4 +-- embassy-stm32-wpan/src/mac/driver.rs | 2 +- embassy-stm32-wpan/src/mac/runner.rs | 2 +- embassy-stm32-wpan/src/sub/ble.rs | 4 +-- embassy-stm32-wpan/src/sub/mm.rs | 4 +-- embassy-stm32-wpan/src/sub/sys.rs | 12 +++----- embassy-stm32-wpan/src/tables.rs | 2 +- embassy-stm32/build.rs | 8 ++++-- embassy-stm32/src/adc/adc4.rs | 9 ++++-- embassy-stm32/src/adc/c0.rs | 9 ++++-- embassy-stm32/src/adc/f1.rs | 2 +- embassy-stm32/src/adc/f3.rs | 2 +- embassy-stm32/src/adc/f3_v1_1.rs | 2 +- embassy-stm32/src/adc/g4.rs | 9 ++++-- embassy-stm32/src/adc/mod.rs | 2 +- embassy-stm32/src/adc/ringbuffered_v2.rs | 4 +-- embassy-stm32/src/adc/v1.rs | 8 ++---- embassy-stm32/src/adc/v2.rs | 2 +- embassy-stm32/src/adc/v3.rs | 4 +-- embassy-stm32/src/adc/v4.rs | 9 ++++-- embassy-stm32/src/can/bxcan/mod.rs | 12 ++++---- embassy-stm32/src/can/fd/config.rs | 2 +- embassy-stm32/src/can/fdcan.rs | 12 ++++---- embassy-stm32/src/can/util.rs | 2 +- embassy-stm32/src/crc/v1.rs | 2 +- embassy-stm32/src/crc/v2v3.rs | 4 +-- embassy-stm32/src/cryp/mod.rs | 10 +++++-- embassy-stm32/src/dac/mod.rs | 2 +- embassy-stm32/src/dcmi.rs | 2 +- embassy-stm32/src/dma/dma_bdma.rs | 4 +-- embassy-stm32/src/dma/gpdma/mod.rs | 2 +- embassy-stm32/src/dma/gpdma/ringbuffered.rs | 4 +-- embassy-stm32/src/dma/mod.rs | 2 +- .../src/dma/ringbuffer/tests/prop_test/mod.rs | 2 +- embassy-stm32/src/dsihost.rs | 2 +- embassy-stm32/src/dts/mod.rs | 2 +- embassy-stm32/src/eth/v1/mod.rs | 8 ++++-- embassy-stm32/src/eth/v1/rx_desc.rs | 2 +- embassy-stm32/src/eth/v1/tx_desc.rs | 2 +- embassy-stm32/src/eth/v2/descriptors.rs | 2 +- embassy-stm32/src/eth/v2/mod.rs | 6 ++-- embassy-stm32/src/exti.rs | 6 ++-- embassy-stm32/src/flash/asynch.rs | 8 +++--- embassy-stm32/src/flash/common.rs | 8 +++--- embassy-stm32/src/flash/eeprom.rs | 2 +- embassy-stm32/src/flash/f0.rs | 2 +- embassy-stm32/src/flash/f1f3.rs | 2 +- embassy-stm32/src/flash/f2.rs | 4 +-- embassy-stm32/src/flash/f4.rs | 24 ++++++++++------ embassy-stm32/src/flash/f7.rs | 12 +++++--- embassy-stm32/src/flash/g.rs | 18 ++++++++---- embassy-stm32/src/flash/h5.rs | 2 +- embassy-stm32/src/flash/h50.rs | 2 +- embassy-stm32/src/flash/h7.rs | 4 +-- embassy-stm32/src/flash/l.rs | 18 ++++++++---- embassy-stm32/src/flash/u0.rs | 2 +- embassy-stm32/src/flash/u5.rs | 2 +- embassy-stm32/src/fmc.rs | 2 +- embassy-stm32/src/gpio.rs | 2 +- embassy-stm32/src/hash/mod.rs | 8 ++---- embassy-stm32/src/hsem/mod.rs | 4 +-- embassy-stm32/src/hspi/mod.rs | 2 +- embassy-stm32/src/i2c/mod.rs | 4 +-- embassy-stm32/src/i2c/v1.rs | 8 ++---- embassy-stm32/src/i2c/v2.rs | 2 +- embassy-stm32/src/i2s.rs | 4 +-- embassy-stm32/src/ipcc.rs | 2 +- embassy-stm32/src/low_power.rs | 4 +-- embassy-stm32/src/lptim/pwm.rs | 6 ++-- embassy-stm32/src/ltdc.rs | 2 +- embassy-stm32/src/opamp.rs | 2 +- embassy-stm32/src/ospi/mod.rs | 6 ++-- embassy-stm32/src/qspi/mod.rs | 2 +- embassy-stm32/src/rcc/bd.rs | 4 +-- embassy-stm32/src/rcc/f247.rs | 4 +-- embassy-stm32/src/rcc/h.rs | 5 +++- embassy-stm32/src/rcc/l.rs | 8 +++--- embassy-stm32/src/rcc/mco.rs | 4 +-- embassy-stm32/src/rcc/mod.rs | 2 +- embassy-stm32/src/rcc/u5.rs | 9 ++++-- embassy-stm32/src/rcc/wba.rs | 9 ++++-- embassy-stm32/src/rng.rs | 2 +- embassy-stm32/src/rtc/low_power.rs | 2 +- embassy-stm32/src/rtc/mod.rs | 8 +++--- embassy-stm32/src/rtc/v3.rs | 2 +- embassy-stm32/src/sai/mod.rs | 6 ++-- embassy-stm32/src/sdmmc/mod.rs | 6 ++-- embassy-stm32/src/spdifrx/mod.rs | 2 +- embassy-stm32/src/spi/mod.rs | 8 +++--- embassy-stm32/src/time_driver.rs | 6 ++-- embassy-stm32/src/timer/complementary_pwm.rs | 6 ++-- embassy-stm32/src/timer/input_capture.rs | 2 +- embassy-stm32/src/timer/one_pulse.rs | 2 +- embassy-stm32/src/timer/pwm_input.rs | 2 +- embassy-stm32/src/timer/qei.rs | 2 +- embassy-stm32/src/timer/simple_pwm.rs | 2 +- embassy-stm32/src/tsc/acquisition_banks.rs | 4 +-- embassy-stm32/src/tsc/pin_groups.rs | 4 +-- embassy-stm32/src/ucpd.rs | 4 +-- embassy-stm32/src/usart/buffered.rs | 6 ++-- embassy-stm32/src/usart/mod.rs | 8 +++--- embassy-stm32/src/usart/ringbuffered.rs | 8 +++--- embassy-stm32/src/usb/otg.rs | 10 +++---- embassy-stm32/src/usb/usb.rs | 4 +-- embassy-stm32/src/vrefbuf/mod.rs | 3 +- embassy-stm32/src/wdg/mod.rs | 2 +- embassy-stm32/src/xspi/mod.rs | 6 ++-- embassy-sync/src/channel.rs | 30 +++++++++++--------- embassy-sync/src/mutex.rs | 4 +-- embassy-sync/src/once_lock.rs | 2 +- embassy-sync/src/pipe.rs | 2 +- embassy-sync/src/priority_channel.rs | 32 ++++++++++++---------- embassy-sync/src/pubsub/mod.rs | 2 +- embassy-sync/src/ring_buffer.rs | 6 +--- embassy-sync/src/rwlock.rs | 4 +-- embassy-sync/src/semaphore.rs | 4 +-- embassy-sync/src/signal.rs | 4 +-- embassy-sync/src/waitqueue/atomic_waker.rs | 2 +- embassy-sync/src/watch.rs | 4 +-- embassy-sync/src/zerocopy_channel.rs | 10 ++----- embassy-time-queue-utils/src/queue_generic.rs | 2 +- embassy-time/src/duration.rs | 8 +----- embassy-time/src/lib.rs | 10 ++----- embassy-time/src/timer.rs | 4 +-- embassy-usb-dfu/src/application.rs | 4 +-- embassy-usb-dfu/src/dfu.rs | 4 +-- embassy-usb-synopsys-otg/src/lib.rs | 16 +++-------- embassy-usb/src/builder.rs | 9 ++++-- embassy-usb/src/class/cdc_acm.rs | 2 +- embassy-usb/src/class/cdc_ncm/embassy_net.rs | 2 +- embassy-usb/src/class/cdc_ncm/mod.rs | 2 +- embassy-usb/src/class/cmsis_dap_v2.rs | 2 +- embassy-usb/src/class/midi.rs | 2 +- embassy-usb/src/class/uac1/speaker.rs | 4 +-- embassy-usb/src/descriptor.rs | 2 +- embassy-usb/src/lib.rs | 2 +- embassy-usb/src/msos.rs | 2 +- examples/boot/application/stm32wb-dfu/src/main.rs | 4 +-- examples/boot/application/stm32wba-dfu/src/main.rs | 4 +-- examples/boot/application/stm32wl/src/bin/a.rs | 2 +- examples/boot/application/stm32wl/src/bin/b.rs | 2 +- .../boot/bootloader/stm32-dual-bank/src/main.rs | 2 +- examples/boot/bootloader/stm32/src/main.rs | 2 +- examples/boot/bootloader/stm32wb-dfu/src/main.rs | 6 ++-- examples/boot/bootloader/stm32wba-dfu/src/main.rs | 8 +++--- examples/mimxrt6/src/bin/button.rs | 2 +- examples/mspm0c1104/src/bin/blinky.rs | 2 +- examples/mspm0c1104/src/bin/button.rs | 2 +- examples/mspm0g3507/src/bin/adc.rs | 2 +- examples/mspm0g3507/src/bin/blinky.rs | 2 +- examples/mspm0g3507/src/bin/button.rs | 2 +- examples/mspm0g3519/src/bin/blinky.rs | 2 +- examples/mspm0g3519/src/bin/button.rs | 2 +- examples/mspm0l1306/src/bin/adc.rs | 2 +- examples/mspm0l1306/src/bin/blinky.rs | 2 +- examples/mspm0l1306/src/bin/button.rs | 2 +- examples/mspm0l2228/src/bin/blinky.rs | 2 +- examples/mspm0l2228/src/bin/button.rs | 2 +- examples/nrf52840-edf/src/bin/basic.rs | 2 +- examples/nrf52840-rtic/src/bin/blinky.rs | 2 +- .../nrf52840/src/bin/channel_sender_receiver.rs | 2 +- examples/nrf52840/src/bin/ethernet_enc28j60.rs | 2 +- examples/nrf52840/src/bin/i2s_effect.rs | 8 ++---- examples/nrf52840/src/bin/i2s_monitor.rs | 2 +- examples/nrf52840/src/bin/i2s_waveform.rs | 8 ++---- examples/nrf52840/src/bin/raw_spawn.rs | 2 +- examples/nrf52840/src/bin/rtc.rs | 2 +- examples/nrf52840/src/bin/usb_ethernet.rs | 4 +-- examples/nrf52840/src/bin/usb_hid_keyboard.rs | 8 ++++-- examples/nrf52840/src/bin/usb_hid_mouse.rs | 2 +- examples/nrf52840/src/bin/usb_serial.rs | 2 +- examples/nrf52840/src/bin/usb_serial_multitask.rs | 2 +- examples/nrf52840/src/bin/usb_serial_winusb.rs | 2 +- examples/nrf52840/src/bin/wifi_esp_hosted.rs | 2 +- examples/nrf9160/src/bin/modem_tcp_client.rs | 4 +-- examples/rp/src/bin/assign_resources.rs | 2 +- examples/rp/src/bin/debounce.rs | 2 +- examples/rp/src/bin/ethernet_w5500_icmp_ping.rs | 4 +-- examples/rp/src/bin/ethernet_w55rp20_tcp_server.rs | 2 +- examples/rp/src/bin/interrupt.rs | 2 +- examples/rp/src/bin/multicore.rs | 2 +- examples/rp/src/bin/multiprio.rs | 2 +- examples/rp/src/bin/orchestrate_tasks.rs | 4 +-- examples/rp/src/bin/overclock.rs | 2 +- examples/rp/src/bin/overclock_manual.rs | 2 +- examples/rp/src/bin/pio_async.rs | 2 +- examples/rp/src/bin/pio_stepper.rs | 2 +- examples/rp/src/bin/pwm.rs | 4 +-- examples/rp/src/bin/rtc_alarm.rs | 2 +- examples/rp/src/bin/spi_display.rs | 12 +++----- examples/rp/src/bin/spi_gc9a01.rs | 4 +-- examples/rp/src/bin/uart_r503.rs | 2 +- examples/rp/src/bin/usb_ethernet.rs | 2 +- examples/rp/src/bin/usb_serial.rs | 2 +- examples/rp/src/bin/wifi_ap_tcp_server.rs | 2 +- examples/rp/src/bin/wifi_blinky.rs | 2 +- examples/rp/src/bin/wifi_scan.rs | 2 +- examples/rp/src/bin/wifi_tcp_server.rs | 2 +- examples/rp/src/bin/wifi_webrequest.rs | 2 +- examples/rp/src/bin/zerocopy.rs | 2 +- examples/rp235x/src/bin/assign_resources.rs | 2 +- examples/rp235x/src/bin/debounce.rs | 2 +- .../rp235x/src/bin/ethernet_w5500_icmp_ping.rs | 4 +-- examples/rp235x/src/bin/interrupt.rs | 2 +- examples/rp235x/src/bin/multicore.rs | 2 +- .../rp235x/src/bin/multicore_stack_overflow.rs | 2 +- examples/rp235x/src/bin/multiprio.rs | 2 +- examples/rp235x/src/bin/overclock.rs | 2 +- examples/rp235x/src/bin/pio_async.rs | 2 +- examples/rp235x/src/bin/pio_i2s_rx.rs | 2 +- examples/rp235x/src/bin/pio_rotary_encoder_rxf.rs | 2 +- examples/rp235x/src/bin/pio_stepper.rs | 2 +- examples/rp235x/src/bin/pwm.rs | 4 +-- .../rp235x/src/bin/pwm_tb6612fng_motor_driver.rs | 2 +- examples/rp235x/src/bin/spi_display.rs | 12 +++----- examples/rp235x/src/bin/uart_r503.rs | 2 +- examples/rp235x/src/bin/zerocopy.rs | 2 +- examples/stm32c0/src/bin/rtc.rs | 2 +- .../stm32f0/src/bin/button_controlled_blink.rs | 2 +- examples/stm32f1/src/bin/can.rs | 6 ++-- examples/stm32f1/src/bin/input_capture.rs | 2 +- examples/stm32f1/src/bin/pwm_input.rs | 2 +- examples/stm32f1/src/bin/usb_serial.rs | 4 +-- examples/stm32f2/src/bin/pll.rs | 2 +- examples/stm32f3/src/bin/button_events.rs | 2 +- examples/stm32f3/src/bin/usb_serial.rs | 4 +-- examples/stm32f334/src/bin/adc.rs | 2 +- examples/stm32f334/src/bin/opamp.rs | 2 +- examples/stm32f334/src/bin/pwm.rs | 2 +- examples/stm32f4/src/bin/adc_dma.rs | 2 +- examples/stm32f4/src/bin/eth.rs | 2 +- examples/stm32f4/src/bin/eth_compliance_test.rs | 2 +- examples/stm32f4/src/bin/eth_w5500.rs | 2 +- examples/stm32f4/src/bin/flash_async.rs | 2 +- examples/stm32f4/src/bin/input_capture.rs | 2 +- examples/stm32f4/src/bin/pwm_complementary.rs | 2 +- examples/stm32f4/src/bin/pwm_input.rs | 2 +- examples/stm32f4/src/bin/rtc.rs | 2 +- examples/stm32f4/src/bin/sdmmc.rs | 4 +-- examples/stm32f4/src/bin/usb_ethernet.rs | 4 +-- examples/stm32f4/src/bin/usb_hid_keyboard.rs | 2 +- examples/stm32f4/src/bin/usb_hid_mouse.rs | 4 +-- examples/stm32f4/src/bin/usb_raw.rs | 2 +- examples/stm32f4/src/bin/usb_serial.rs | 4 +-- examples/stm32f4/src/bin/usb_uac_speaker.rs | 4 +-- examples/stm32f4/src/bin/ws2812_pwm.rs | 2 +- examples/stm32f469/src/bin/dsi_bsp.rs | 6 ++-- examples/stm32f7/src/bin/can.rs | 2 +- examples/stm32f7/src/bin/cryp.rs | 4 +-- examples/stm32f7/src/bin/eth.rs | 2 +- examples/stm32f7/src/bin/hash.rs | 2 +- examples/stm32f7/src/bin/qspi.rs | 2 +- examples/stm32f7/src/bin/sdmmc.rs | 4 +-- examples/stm32f7/src/bin/usb_serial.rs | 4 +-- examples/stm32g0/src/bin/hf_timer.rs | 4 +-- examples/stm32g0/src/bin/input_capture.rs | 4 +-- examples/stm32g0/src/bin/pwm_complementary.rs | 2 +- examples/stm32g0/src/bin/pwm_input.rs | 2 +- examples/stm32g0/src/bin/rtc.rs | 2 +- examples/stm32g0/src/bin/usb_serial.rs | 4 +-- examples/stm32g4/src/bin/adc.rs | 2 +- examples/stm32g4/src/bin/adc_differential.rs | 2 +- examples/stm32g4/src/bin/adc_dma.rs | 2 +- examples/stm32g4/src/bin/adc_oversampling.rs | 2 +- examples/stm32g4/src/bin/can.rs | 2 +- examples/stm32g4/src/bin/usb_c_pd.rs | 6 ++-- examples/stm32g4/src/bin/usb_serial.rs | 4 +-- examples/stm32h5/src/bin/adc.rs | 2 +- examples/stm32h5/src/bin/can.rs | 2 +- examples/stm32h5/src/bin/dts.rs | 2 +- examples/stm32h5/src/bin/eth.rs | 2 +- examples/stm32h5/src/bin/sai.rs | 2 +- examples/stm32h5/src/bin/usb_c_pd.rs | 6 ++-- examples/stm32h5/src/bin/usb_serial.rs | 4 +-- examples/stm32h5/src/bin/usb_uac_speaker.rs | 4 +-- examples/stm32h7/src/bin/adc.rs | 2 +- examples/stm32h7/src/bin/adc_dma.rs | 2 +- examples/stm32h7/src/bin/camera.rs | 2 +- examples/stm32h7/src/bin/can.rs | 2 +- examples/stm32h7/src/bin/dac.rs | 2 +- examples/stm32h7/src/bin/dac_dma.rs | 2 +- examples/stm32h7/src/bin/eth.rs | 2 +- examples/stm32h7/src/bin/eth_client.rs | 4 +-- examples/stm32h7/src/bin/eth_client_mii.rs | 4 +-- examples/stm32h7/src/bin/fmc.rs | 2 +- examples/stm32h7/src/bin/i2c_shared.rs | 2 +- examples/stm32h7/src/bin/low_level_timer_api.rs | 2 +- examples/stm32h7/src/bin/pwm.rs | 2 +- examples/stm32h7/src/bin/rng.rs | 2 +- examples/stm32h7/src/bin/rtc.rs | 2 +- examples/stm32h7/src/bin/sdmmc.rs | 2 +- examples/stm32h7/src/bin/spi.rs | 2 +- examples/stm32h7/src/bin/spi_bdma.rs | 2 +- examples/stm32h7/src/bin/spi_dma.rs | 2 +- examples/stm32h7/src/bin/usb_serial.rs | 4 +-- examples/stm32h723/src/bin/spdifrx.rs | 4 +-- examples/stm32h735/src/bin/ltdc.rs | 4 +-- examples/stm32h742/src/bin/qspi.rs | 2 +- examples/stm32h755cm4/src/bin/blinky.rs | 2 +- examples/stm32h755cm4/src/bin/intercore.rs | 2 +- examples/stm32h755cm7/src/bin/blinky.rs | 2 +- examples/stm32h7b0/src/bin/ospi_memory_mapped.rs | 2 +- examples/stm32h7rs/src/bin/blinky.rs | 2 +- examples/stm32h7rs/src/bin/can.rs | 2 +- examples/stm32h7rs/src/bin/eth.rs | 2 +- examples/stm32h7rs/src/bin/rng.rs | 2 +- examples/stm32h7rs/src/bin/rtc.rs | 2 +- examples/stm32h7rs/src/bin/usb_serial.rs | 4 +-- examples/stm32h7rs/src/bin/xspi_memory_mapped.rs | 2 +- examples/stm32l0/src/bin/button_exti.rs | 2 +- examples/stm32l0/src/bin/dds.rs | 2 +- examples/stm32l0/src/bin/eeprom.rs | 2 +- examples/stm32l0/src/bin/raw_spawn.rs | 2 +- examples/stm32l0/src/bin/usb_serial.rs | 2 +- examples/stm32l1/src/bin/eeprom.rs | 2 +- examples/stm32l1/src/bin/usb_serial.rs | 2 +- examples/stm32l4/src/bin/adc.rs | 2 +- examples/stm32l4/src/bin/can.rs | 2 +- examples/stm32l4/src/bin/dac_dma.rs | 2 +- examples/stm32l4/src/bin/rng.rs | 2 +- examples/stm32l4/src/bin/rtc.rs | 2 +- .../stm32l4/src/bin/spe_adin1110_http_server.rs | 10 ++++--- examples/stm32l4/src/bin/usb_serial.rs | 4 +-- examples/stm32l5/src/bin/rng.rs | 2 +- examples/stm32l5/src/bin/usb_ethernet.rs | 4 +-- examples/stm32l5/src/bin/usb_hid_mouse.rs | 4 +-- examples/stm32l5/src/bin/usb_serial.rs | 4 +-- examples/stm32u0/src/bin/adc.rs | 2 +- examples/stm32u0/src/bin/rng.rs | 2 +- examples/stm32u0/src/bin/rtc.rs | 2 +- examples/stm32u0/src/bin/usb_serial.rs | 4 +-- examples/stm32u5/src/bin/adc.rs | 2 +- examples/stm32u5/src/bin/ltdc.rs | 6 ++-- examples/stm32u5/src/bin/usb_hs_serial.rs | 4 +-- examples/stm32u5/src/bin/usb_serial.rs | 4 +-- examples/stm32wb/src/bin/eddystone_beacon.rs | 4 +-- examples/stm32wb/src/bin/gatt_server.rs | 2 +- examples/stm32wb/src/bin/mac_ffd.rs | 2 +- examples/stm32wb/src/bin/mac_ffd_net.rs | 2 +- examples/stm32wb/src/bin/mac_rfd.rs | 2 +- examples/stm32wb/src/bin/tl_mbox_mac.rs | 2 +- examples/stm32wba/src/bin/adc.rs | 2 +- examples/stm32wba/src/bin/pwm.rs | 2 +- examples/stm32wba6/src/bin/adc.rs | 2 +- examples/stm32wba6/src/bin/pwm.rs | 2 +- examples/stm32wba6/src/bin/usb_hs_serial.rs | 4 +-- examples/stm32wl/src/bin/adc.rs | 2 +- examples/stm32wl/src/bin/blinky.rs | 2 +- examples/stm32wl/src/bin/button.rs | 2 +- examples/stm32wl/src/bin/button_exti.rs | 2 +- examples/stm32wl/src/bin/flash.rs | 2 +- examples/stm32wl/src/bin/random.rs | 2 +- examples/stm32wl/src/bin/uart_async.rs | 2 +- tests/mspm0/src/bin/dma.rs | 2 +- tests/perf-client/src/lib.rs | 2 +- tests/rp/src/bin/cyw43-perf.rs | 2 +- tests/rp/src/bin/gpio_multicore.rs | 4 +-- tests/rp/src/bin/multicore.rs | 2 +- tests/rp/src/bin/overclock.rs | 2 +- tests/rp/src/bin/pio_multi_load.rs | 4 ++- tests/rp/src/bin/rtc.rs | 2 +- tests/rp/src/bin/spinlock_mutex_multicore.rs | 2 +- tests/stm32/src/bin/afio.rs | 2 +- tests/stm32/src/bin/cryp.rs | 2 +- tests/stm32/src/bin/fdcan.rs | 2 +- tests/stm32/src/bin/stop.rs | 4 +-- tests/stm32/src/bin/ucpd.rs | 2 +- tests/stm32/src/bin/usart.rs | 2 +- tests/stm32/src/bin/wpan_ble.rs | 4 +-- tests/stm32/src/bin/wpan_mac.rs | 2 +- tests/stm32/src/common.rs | 2 +- tests/utils/src/bin/saturate_serial.rs | 2 +- 509 files changed, 943 insertions(+), 967 deletions(-) diff --git a/cyw43-pio/src/lib.rs b/cyw43-pio/src/lib.rs index b0be19358..41ac6816d 100644 --- a/cyw43-pio/src/lib.rs +++ b/cyw43-pio/src/lib.rs @@ -6,13 +6,13 @@ use core::slice; use cyw43::SpiBusCyw43; +use embassy_rp::Peri; use embassy_rp::dma::Channel; use embassy_rp::gpio::{Drive, Level, Output, Pull, SlewRate}; use embassy_rp::pio::program::pio_asm; use embassy_rp::pio::{Common, Config, Direction, Instance, Irq, PioPin, ShiftDirection, StateMachine}; -use embassy_rp::Peri; -use fixed::types::extra::U8; use fixed::FixedU32; +use fixed::types::extra::U8; /// SPI comms driven by PIO. pub struct PioSpi<'d, PIO: Instance, const SM: usize, DMA: Channel> { diff --git a/cyw43/src/bluetooth.rs b/cyw43/src/bluetooth.rs index d176c4b09..332b7048d 100644 --- a/cyw43/src/bluetooth.rs +++ b/cyw43/src/bluetooth.rs @@ -15,7 +15,7 @@ use crate::bus::Bus; pub use crate::bus::SpiBusCyw43; use crate::consts::*; use crate::util::round_up; -use crate::{util, CHIP}; +use crate::{CHIP, util}; pub(crate) struct BtState { rx: [BtPacketBuf; 4], diff --git a/cyw43/src/bus.rs b/cyw43/src/bus.rs index 8a53484d5..aa2b66a40 100644 --- a/cyw43/src/bus.rs +++ b/cyw43/src/bus.rs @@ -340,11 +340,7 @@ where self.status = self.spi.cmd_read(cmd, &mut buf[..len]).await; // if we read from the backplane, the result is in the second word, after the response delay - if func == FUNC_BACKPLANE { - buf[1] - } else { - buf[0] - } + if func == FUNC_BACKPLANE { buf[1] } else { buf[0] } } async fn writen(&mut self, func: u32, addr: u32, val: u32, len: u32) { diff --git a/cyw43/src/control.rs b/cyw43/src/control.rs index fd0d4d532..49e3faee4 100644 --- a/cyw43/src/control.rs +++ b/cyw43/src/control.rs @@ -10,7 +10,7 @@ use crate::events::{Event, EventSubscriber, Events}; use crate::fmt::Bytes; use crate::ioctl::{IoctlState, IoctlType}; use crate::structs::*; -use crate::{countries, events, PowerManagementMode}; +use crate::{PowerManagementMode, countries, events}; /// Control errors. #[derive(Debug)] diff --git a/cyw43/src/ioctl.rs b/cyw43/src/ioctl.rs index 35135e296..deccc945d 100644 --- a/cyw43/src/ioctl.rs +++ b/cyw43/src/ioctl.rs @@ -1,5 +1,5 @@ use core::cell::{Cell, RefCell}; -use core::future::{poll_fn, Future}; +use core::future::{Future, poll_fn}; use core::task::{Poll, Waker}; use embassy_sync::waitqueue::WakerRegistration; diff --git a/cyw43/src/runner.rs b/cyw43/src/runner.rs index 77910b281..7c38be24a 100644 --- a/cyw43/src/runner.rs +++ b/cyw43/src/runner.rs @@ -1,6 +1,6 @@ -use embassy_futures::select::{select4, Either4}; +use embassy_futures::select::{Either4, select4}; use embassy_net_driver_channel as ch; -use embassy_time::{block_for, Duration, Timer}; +use embassy_time::{Duration, Timer, block_for}; use embedded_hal_1::digital::OutputPin; use crate::bus::Bus; @@ -12,7 +12,7 @@ use crate::ioctl::{IoctlState, IoctlType, PendingIoctl}; use crate::nvram::NVRAM; use crate::structs::*; use crate::util::slice8_mut; -use crate::{events, Core, CHIP, MTU}; +use crate::{CHIP, Core, MTU, events}; #[cfg(feature = "firmware-logs")] struct LogState { diff --git a/embassy-boot-nrf/src/lib.rs b/embassy-boot-nrf/src/lib.rs index 3b3434e2c..b4c3c1151 100644 --- a/embassy-boot-nrf/src/lib.rs +++ b/embassy-boot-nrf/src/lib.rs @@ -9,7 +9,7 @@ pub use embassy_boot::{ FirmwareUpdater, FirmwareUpdaterConfig, }; use embassy_nrf::nvmc::PAGE_SIZE; -use embassy_nrf::{wdt, Peri}; +use embassy_nrf::{Peri, wdt}; use embedded_storage::nor_flash::{ErrorType, NorFlash, ReadNorFlash}; /// A bootloader for nRF devices. diff --git a/embassy-boot-rp/src/lib.rs b/embassy-boot-rp/src/lib.rs index dd049851a..d090aee49 100644 --- a/embassy-boot-rp/src/lib.rs +++ b/embassy-boot-rp/src/lib.rs @@ -8,10 +8,10 @@ pub use embassy_boot::{ AlignedBuffer, BlockingFirmwareState, BlockingFirmwareUpdater, BootError, BootLoaderConfig, FirmwareState, FirmwareUpdater, FirmwareUpdaterConfig, State, }; -use embassy_rp::flash::{Blocking, Flash, ERASE_SIZE}; +use embassy_rp::Peri; +use embassy_rp::flash::{Blocking, ERASE_SIZE, Flash}; use embassy_rp::peripherals::{FLASH, WATCHDOG}; use embassy_rp::watchdog::Watchdog; -use embassy_rp::Peri; use embassy_time::Duration; use embedded_storage::nor_flash::{ErrorType, NorFlash, ReadNorFlash}; diff --git a/embassy-boot/src/boot_loader.rs b/embassy-boot/src/boot_loader.rs index 8d97882ea..c38940d6e 100644 --- a/embassy-boot/src/boot_loader.rs +++ b/embassy-boot/src/boot_loader.rs @@ -1,11 +1,11 @@ use core::cell::RefCell; use embassy_embedded_hal::flash::partition::BlockingPartition; -use embassy_sync::blocking_mutex::raw::NoopRawMutex; use embassy_sync::blocking_mutex::Mutex; +use embassy_sync::blocking_mutex::raw::NoopRawMutex; use embedded_storage::nor_flash::{NorFlash, NorFlashError, NorFlashErrorKind}; -use crate::{State, DFU_DETACH_MAGIC, REVERT_MAGIC, STATE_ERASE_VALUE, SWAP_MAGIC}; +use crate::{DFU_DETACH_MAGIC, REVERT_MAGIC, STATE_ERASE_VALUE, SWAP_MAGIC, State}; /// Errors returned by bootloader #[derive(PartialEq, Eq, Debug)] diff --git a/embassy-boot/src/firmware_updater/asynch.rs b/embassy-boot/src/firmware_updater/asynch.rs index fd02fa526..26d4d39bd 100644 --- a/embassy-boot/src/firmware_updater/asynch.rs +++ b/embassy-boot/src/firmware_updater/asynch.rs @@ -6,7 +6,7 @@ use embassy_sync::blocking_mutex::raw::NoopRawMutex; use embedded_storage_async::nor_flash::NorFlash; use super::FirmwareUpdaterConfig; -use crate::{FirmwareUpdaterError, State, BOOT_MAGIC, DFU_DETACH_MAGIC, STATE_ERASE_VALUE, SWAP_MAGIC}; +use crate::{BOOT_MAGIC, DFU_DETACH_MAGIC, FirmwareUpdaterError, STATE_ERASE_VALUE, SWAP_MAGIC, State}; /// FirmwareUpdater is an application API for interacting with the BootLoader without the ability to /// 'mess up' the internal bootloader state diff --git a/embassy-boot/src/firmware_updater/blocking.rs b/embassy-boot/src/firmware_updater/blocking.rs index 44550e795..5554025fc 100644 --- a/embassy-boot/src/firmware_updater/blocking.rs +++ b/embassy-boot/src/firmware_updater/blocking.rs @@ -6,7 +6,7 @@ use embassy_sync::blocking_mutex::raw::NoopRawMutex; use embedded_storage::nor_flash::NorFlash; use super::FirmwareUpdaterConfig; -use crate::{FirmwareUpdaterError, State, BOOT_MAGIC, DFU_DETACH_MAGIC, STATE_ERASE_VALUE, SWAP_MAGIC}; +use crate::{BOOT_MAGIC, DFU_DETACH_MAGIC, FirmwareUpdaterError, STATE_ERASE_VALUE, SWAP_MAGIC, State}; /// Blocking FirmwareUpdater is an application API for interacting with the BootLoader without the ability to /// 'mess up' the internal bootloader state @@ -399,8 +399,8 @@ mod tests { use core::cell::RefCell; use embassy_embedded_hal::flash::partition::BlockingPartition; - use embassy_sync::blocking_mutex::raw::NoopRawMutex; use embassy_sync::blocking_mutex::Mutex; + use embassy_sync::blocking_mutex::raw::NoopRawMutex; use sha1::{Digest, Sha1}; use super::*; diff --git a/embassy-boot/src/lib.rs b/embassy-boot/src/lib.rs index 4d7ebfc4f..7dc811f66 100644 --- a/embassy-boot/src/lib.rs +++ b/embassy-boot/src/lib.rs @@ -342,11 +342,13 @@ mod tests { &mut aligned, ); - assert!(block_on(updater.verify_and_mark_updated( - &public_key.to_bytes(), - &signature.to_bytes(), - firmware_len as u32, - )) - .is_ok()); + assert!( + block_on(updater.verify_and_mark_updated( + &public_key.to_bytes(), + &signature.to_bytes(), + firmware_len as u32, + )) + .is_ok() + ); } } diff --git a/embassy-boot/src/test_flash/blocking.rs b/embassy-boot/src/test_flash/blocking.rs index 5ec476c65..7334346fd 100644 --- a/embassy-boot/src/test_flash/blocking.rs +++ b/embassy-boot/src/test_flash/blocking.rs @@ -1,8 +1,8 @@ use core::cell::RefCell; use embassy_embedded_hal::flash::partition::BlockingPartition; -use embassy_sync::blocking_mutex::raw::NoopRawMutex; use embassy_sync::blocking_mutex::Mutex; +use embassy_sync::blocking_mutex::raw::NoopRawMutex; use embedded_storage::nor_flash::NorFlash; use crate::BootLoaderConfig; diff --git a/embassy-embedded-hal/src/flash/partition/blocking.rs b/embassy-embedded-hal/src/flash/partition/blocking.rs index cb30290a8..bd9329e2d 100644 --- a/embassy-embedded-hal/src/flash/partition/blocking.rs +++ b/embassy-embedded-hal/src/flash/partition/blocking.rs @@ -1,7 +1,7 @@ use core::cell::RefCell; -use embassy_sync::blocking_mutex::raw::RawMutex; use embassy_sync::blocking_mutex::Mutex; +use embassy_sync::blocking_mutex::raw::RawMutex; use embedded_storage::nor_flash::{ErrorType, MultiwriteNorFlash, NorFlash, ReadNorFlash}; use super::Error; diff --git a/embassy-embedded-hal/src/shared_bus/asynch/i2c.rs b/embassy-embedded-hal/src/shared_bus/asynch/i2c.rs index 48246270e..9c7d3ee71 100644 --- a/embassy-embedded-hal/src/shared_bus/asynch/i2c.rs +++ b/embassy-embedded-hal/src/shared_bus/asynch/i2c.rs @@ -26,8 +26,8 @@ use embassy_sync::blocking_mutex::raw::RawMutex; use embassy_sync::mutex::Mutex; use embedded_hal_async::i2c; -use crate::shared_bus::I2cDeviceError; use crate::SetConfig; +use crate::shared_bus::I2cDeviceError; /// I2C device on a shared bus. pub struct I2cDevice<'a, M: RawMutex, BUS> { diff --git a/embassy-embedded-hal/src/shared_bus/asynch/spi.rs b/embassy-embedded-hal/src/shared_bus/asynch/spi.rs index 0faefbc1e..869a78164 100644 --- a/embassy-embedded-hal/src/shared_bus/asynch/spi.rs +++ b/embassy-embedded-hal/src/shared_bus/asynch/spi.rs @@ -32,8 +32,8 @@ use embedded_hal_1::digital::OutputPin; use embedded_hal_1::spi::Operation; use embedded_hal_async::spi; -use crate::shared_bus::SpiDeviceError; use crate::SetConfig; +use crate::shared_bus::SpiDeviceError; /// SPI device on a shared bus. pub struct SpiDevice<'a, M: RawMutex, BUS, CS> { diff --git a/embassy-embedded-hal/src/shared_bus/blocking/i2c.rs b/embassy-embedded-hal/src/shared_bus/blocking/i2c.rs index dc634a209..49b50f8c1 100644 --- a/embassy-embedded-hal/src/shared_bus/blocking/i2c.rs +++ b/embassy-embedded-hal/src/shared_bus/blocking/i2c.rs @@ -17,12 +17,12 @@ use core::cell::RefCell; -use embassy_sync::blocking_mutex::raw::RawMutex; use embassy_sync::blocking_mutex::Mutex; +use embassy_sync::blocking_mutex::raw::RawMutex; use embedded_hal_1::i2c::{ErrorType, I2c, Operation}; -use crate::shared_bus::I2cDeviceError; use crate::SetConfig; +use crate::shared_bus::I2cDeviceError; /// I2C device on a shared bus. pub struct I2cDevice<'a, M: RawMutex, BUS> { diff --git a/embassy-embedded-hal/src/shared_bus/blocking/spi.rs b/embassy-embedded-hal/src/shared_bus/blocking/spi.rs index ffe2aa1c6..48fe2f4c4 100644 --- a/embassy-embedded-hal/src/shared_bus/blocking/spi.rs +++ b/embassy-embedded-hal/src/shared_bus/blocking/spi.rs @@ -19,13 +19,13 @@ use core::cell::RefCell; -use embassy_sync::blocking_mutex::raw::RawMutex; use embassy_sync::blocking_mutex::Mutex; +use embassy_sync::blocking_mutex::raw::RawMutex; use embedded_hal_1::digital::OutputPin; use embedded_hal_1::spi::{self, Operation, SpiBus}; -use crate::shared_bus::SpiDeviceError; use crate::SetConfig; +use crate::shared_bus::SpiDeviceError; /// SPI device on a shared bus. pub struct SpiDevice<'a, M: RawMutex, BUS, CS> { diff --git a/embassy-executor-macros/src/macros/main.rs b/embassy-executor-macros/src/macros/main.rs index 3d52ebfe1..c259c003f 100644 --- a/embassy-executor-macros/src/macros/main.rs +++ b/embassy-executor-macros/src/macros/main.rs @@ -1,7 +1,7 @@ use std::str::FromStr; -use darling::export::NestedMeta; use darling::FromMeta; +use darling::export::NestedMeta; use proc_macro2::TokenStream; use quote::quote; use syn::{ReturnType, Type}; diff --git a/embassy-executor-macros/src/macros/task.rs b/embassy-executor-macros/src/macros/task.rs index 755948882..8ce8d6726 100644 --- a/embassy-executor-macros/src/macros/task.rs +++ b/embassy-executor-macros/src/macros/task.rs @@ -1,7 +1,7 @@ use std::str::FromStr; -use darling::export::NestedMeta; use darling::FromMeta; +use darling::export::NestedMeta; use proc_macro2::{Span, TokenStream}; use quote::{format_ident, quote}; use syn::visit::{self, Visit}; @@ -287,7 +287,11 @@ fn check_arg_ty(errors: &mut TokenStream, ty: &Type) { } fn visit_type_impl_trait(&mut self, i: &'ast syn::TypeImplTrait) { - error(self.errors, i, "`impl Trait` is not allowed in task arguments. It is syntax sugar for generics, and tasks can't be generic."); + error( + self.errors, + i, + "`impl Trait` is not allowed in task arguments. It is syntax sugar for generics, and tasks can't be generic.", + ); } } diff --git a/embassy-executor-macros/src/util.rs b/embassy-executor-macros/src/util.rs index ebd032a62..5a13f2121 100644 --- a/embassy-executor-macros/src/util.rs +++ b/embassy-executor-macros/src/util.rs @@ -3,7 +3,7 @@ use std::fmt::Display; use proc_macro2::{TokenStream, TokenTree}; use quote::{ToTokens, TokenStreamExt}; use syn::parse::{Parse, ParseStream}; -use syn::{braced, bracketed, token, AttrStyle, Attribute, Signature, Token, Visibility}; +use syn::{AttrStyle, Attribute, Signature, Token, Visibility, braced, bracketed, token}; pub fn token_stream_with_error(mut tokens: TokenStream, error: syn::Error) -> TokenStream { tokens.extend(error.into_compile_error()); diff --git a/embassy-executor/src/arch/avr.rs b/embassy-executor/src/arch/avr.rs index 4a19c523a..a841afe15 100644 --- a/embassy-executor/src/arch/avr.rs +++ b/embassy-executor/src/arch/avr.rs @@ -10,7 +10,7 @@ mod thread { pub use embassy_executor_macros::main_avr as main; use portable_atomic::{AtomicBool, Ordering}; - use crate::{raw, Spawner}; + use crate::{Spawner, raw}; static SIGNAL_WORK_THREAD_MODE: AtomicBool = AtomicBool::new(false); diff --git a/embassy-executor/src/arch/cortex_ar.rs b/embassy-executor/src/arch/cortex_ar.rs index 36d45944a..a9be3d323 100644 --- a/embassy-executor/src/arch/cortex_ar.rs +++ b/embassy-executor/src/arch/cortex_ar.rs @@ -26,7 +26,7 @@ mod thread { use cortex_ar::asm::wfe; pub use embassy_executor_macros::main_cortex_ar as main; - use crate::{raw, Spawner}; + use crate::{Spawner, raw}; /// Thread mode executor, using WFE/SEV. /// diff --git a/embassy-executor/src/arch/cortex_m.rs b/embassy-executor/src/arch/cortex_m.rs index 9f1081e93..1ce96d1d5 100644 --- a/embassy-executor/src/arch/cortex_m.rs +++ b/embassy-executor/src/arch/cortex_m.rs @@ -53,7 +53,7 @@ mod thread { pub use embassy_executor_macros::main_cortex_m as main; - use crate::{raw, Spawner}; + use crate::{Spawner, raw}; /// Thread mode executor, using WFE/SEV. /// diff --git a/embassy-executor/src/arch/riscv32.rs b/embassy-executor/src/arch/riscv32.rs index 13b93cf02..c70c1344a 100644 --- a/embassy-executor/src/arch/riscv32.rs +++ b/embassy-executor/src/arch/riscv32.rs @@ -10,7 +10,7 @@ mod thread { pub use embassy_executor_macros::main_riscv as main; - use crate::{raw, Spawner}; + use crate::{Spawner, raw}; /// global atomic used to keep track of whether there is work to do since sev() is not available on RISCV static SIGNAL_WORK_THREAD_MODE: AtomicBool = AtomicBool::new(false); diff --git a/embassy-executor/src/arch/spin.rs b/embassy-executor/src/arch/spin.rs index 40cb56a09..49f3356a6 100644 --- a/embassy-executor/src/arch/spin.rs +++ b/embassy-executor/src/arch/spin.rs @@ -9,7 +9,7 @@ mod thread { pub use embassy_executor_macros::main_spin as main; - use crate::{raw, Spawner}; + use crate::{Spawner, raw}; #[unsafe(export_name = "__pender")] fn __pender(_context: *mut ()) {} diff --git a/embassy-executor/src/arch/std.rs b/embassy-executor/src/arch/std.rs index cdb9f7642..c62ab723b 100644 --- a/embassy-executor/src/arch/std.rs +++ b/embassy-executor/src/arch/std.rs @@ -10,7 +10,7 @@ mod thread { pub use embassy_executor_macros::main_std as main; - use crate::{raw, Spawner}; + use crate::{Spawner, raw}; #[unsafe(export_name = "__pender")] fn __pender(context: *mut ()) { diff --git a/embassy-executor/src/arch/wasm.rs b/embassy-executor/src/arch/wasm.rs index 6b36f8a5b..d2ff2fe51 100644 --- a/embassy-executor/src/arch/wasm.rs +++ b/embassy-executor/src/arch/wasm.rs @@ -13,7 +13,7 @@ mod thread { use wasm_bindgen::prelude::*; use crate::raw::util::UninitCell; - use crate::{raw, Spawner}; + use crate::{Spawner, raw}; #[unsafe(export_name = "__pender")] fn __pender(context: *mut ()) { diff --git a/embassy-executor/src/metadata.rs b/embassy-executor/src/metadata.rs index bc0df0f83..76504ab0b 100644 --- a/embassy-executor/src/metadata.rs +++ b/embassy-executor/src/metadata.rs @@ -1,6 +1,6 @@ #[cfg(feature = "metadata-name")] use core::cell::Cell; -use core::future::{poll_fn, Future}; +use core::future::{Future, poll_fn}; #[cfg(feature = "scheduler-priority")] use core::sync::atomic::{AtomicU8, Ordering}; use core::task::Poll; diff --git a/embassy-executor/src/raw/run_queue.rs b/embassy-executor/src/raw/run_queue.rs index b8b052310..6f2abdbd0 100644 --- a/embassy-executor/src/raw/run_queue.rs +++ b/embassy-executor/src/raw/run_queue.rs @@ -1,9 +1,9 @@ -use core::ptr::{addr_of_mut, NonNull}; +use core::ptr::{NonNull, addr_of_mut}; -use cordyceps::sorted_list::Links; use cordyceps::Linked; #[cfg(any(feature = "scheduler-priority", feature = "scheduler-deadline"))] use cordyceps::SortedList; +use cordyceps::sorted_list::Links; #[cfg(target_has_atomic = "ptr")] type TransferStack = cordyceps::TransferStack; diff --git a/embassy-executor/src/raw/state_atomics_arm.rs b/embassy-executor/src/raw/state_atomics_arm.rs index b743dcc2c..f68de955f 100644 --- a/embassy-executor/src/raw/state_atomics_arm.rs +++ b/embassy-executor/src/raw/state_atomics_arm.rs @@ -1,4 +1,4 @@ -use core::sync::atomic::{compiler_fence, AtomicBool, AtomicU32, Ordering}; +use core::sync::atomic::{AtomicBool, AtomicU32, Ordering, compiler_fence}; #[derive(Clone, Copy)] pub(crate) struct Token(()); diff --git a/embassy-executor/src/raw/state_critical_section.rs b/embassy-executor/src/raw/state_critical_section.rs index b69a6ac66..8d7ef2892 100644 --- a/embassy-executor/src/raw/state_critical_section.rs +++ b/embassy-executor/src/raw/state_critical_section.rs @@ -1,7 +1,7 @@ use core::cell::Cell; -pub(crate) use critical_section::{with as locked, CriticalSection as Token}; use critical_section::{CriticalSection, Mutex}; +pub(crate) use critical_section::{CriticalSection as Token, with as locked}; #[cfg(target_arch = "avr")] type StateBits = u8; diff --git a/embassy-executor/src/raw/trace.rs b/embassy-executor/src/raw/trace.rs index b3086948c..74519b927 100644 --- a/embassy-executor/src/raw/trace.rs +++ b/embassy-executor/src/raw/trace.rs @@ -368,11 +368,7 @@ impl rtos_trace::RtosTraceOSCallbacks for crate::raw::SyncExecutor { } fn time() -> u64 { const fn gcd(a: u64, b: u64) -> u64 { - if b == 0 { - a - } else { - gcd(b, a % b) - } + if b == 0 { a } else { gcd(b, a % b) } } const GCD_1M: u64 = gcd(embassy_time_driver::TICK_HZ, 1_000_000); diff --git a/embassy-executor/src/raw/waker.rs b/embassy-executor/src/raw/waker.rs index d0d7b003d..2706f0fdf 100644 --- a/embassy-executor/src/raw/waker.rs +++ b/embassy-executor/src/raw/waker.rs @@ -1,6 +1,6 @@ use core::task::{RawWaker, RawWakerVTable, Waker}; -use super::{wake_task, TaskHeader, TaskRef}; +use super::{TaskHeader, TaskRef, wake_task}; static VTABLE: RawWakerVTable = RawWakerVTable::new(clone, wake, wake, drop); @@ -35,7 +35,9 @@ pub fn task_from_waker(waker: &Waker) -> TaskRef { // make sure to compare vtable addresses. Doing `==` on the references // will compare the contents, which is slower. if waker.vtable() as *const _ != &VTABLE as *const _ { - panic!("Found waker not created by the Embassy executor. `embassy_time::Timer` only works with the Embassy executor.") + panic!( + "Found waker not created by the Embassy executor. `embassy_time::Timer` only works with the Embassy executor." + ) } // safety: our wakers are always created with `TaskRef::as_ptr` unsafe { TaskRef::from_ptr(waker.data() as *const TaskHeader) } diff --git a/embassy-executor/src/raw/waker_turbo.rs b/embassy-executor/src/raw/waker_turbo.rs index 9d0ad35ec..919bcc61a 100644 --- a/embassy-executor/src/raw/waker_turbo.rs +++ b/embassy-executor/src/raw/waker_turbo.rs @@ -1,7 +1,7 @@ use core::ptr::NonNull; use core::task::Waker; -use super::{wake_task, TaskHeader, TaskRef}; +use super::{TaskHeader, TaskRef, wake_task}; pub(crate) unsafe fn from_task(p: TaskRef) -> Waker { Waker::from_turbo_ptr(NonNull::new_unchecked(p.as_ptr() as _)) diff --git a/embassy-executor/src/spawner.rs b/embassy-executor/src/spawner.rs index 83d896b76..b73a1e7c6 100644 --- a/embassy-executor/src/spawner.rs +++ b/embassy-executor/src/spawner.rs @@ -1,4 +1,4 @@ -use core::future::{poll_fn, Future}; +use core::future::{Future, poll_fn}; use core::marker::PhantomData; use core::mem; use core::sync::atomic::Ordering; @@ -75,7 +75,10 @@ impl core::fmt::Debug for SpawnError { impl core::fmt::Display for SpawnError { fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { match self { - SpawnError::Busy => write!(f, "Busy - Too many instances of this task are already running. Check the `pool_size` attribute of the task."), + SpawnError::Busy => write!( + f, + "Busy - Too many instances of this task are already running. Check the `pool_size` attribute of the task." + ), } } } @@ -84,7 +87,10 @@ impl core::fmt::Display for SpawnError { impl defmt::Format for SpawnError { fn format(&self, f: defmt::Formatter) { match self { - SpawnError::Busy => defmt::write!(f, "Busy - Too many instances of this task are already running. Check the `pool_size` attribute of the task."), + SpawnError::Busy => defmt::write!( + f, + "Busy - Too many instances of this task are already running. Check the `pool_size` attribute of the task." + ), } } } diff --git a/embassy-executor/tests/test.rs b/embassy-executor/tests/test.rs index 6c4783dc1..a99976168 100644 --- a/embassy-executor/tests/test.rs +++ b/embassy-executor/tests/test.rs @@ -2,12 +2,12 @@ #![cfg_attr(feature = "nightly", feature(never_type))] use std::boxed::Box; -use std::future::{poll_fn, Future}; +use std::future::{Future, poll_fn}; use std::sync::{Arc, Mutex}; use std::task::Poll; use embassy_executor::raw::Executor; -use embassy_executor::{task, Spawner}; +use embassy_executor::{Spawner, task}; #[unsafe(export_name = "__pender")] fn __pender(context: *mut ()) { diff --git a/embassy-hal-internal/src/interrupt.rs b/embassy-hal-internal/src/interrupt.rs index 5e64dce9d..ce6057e2d 100644 --- a/embassy-hal-internal/src/interrupt.rs +++ b/embassy-hal-internal/src/interrupt.rs @@ -1,6 +1,6 @@ //! Interrupt handling for cortex-m devices. use core::mem; -use core::sync::atomic::{compiler_fence, Ordering}; +use core::sync::atomic::{Ordering, compiler_fence}; use cortex_m::interrupt::InterruptNumber; use cortex_m::peripheral::NVIC; diff --git a/embassy-imxrt/src/clocks.rs b/embassy-imxrt/src/clocks.rs index 39c3e6238..22df2686f 100644 --- a/embassy-imxrt/src/clocks.rs +++ b/embassy-imxrt/src/clocks.rs @@ -1,5 +1,5 @@ //! Clock configuration for the `RT6xx` -use core::sync::atomic::{AtomicU32, AtomicU8, Ordering}; +use core::sync::atomic::{AtomicU8, AtomicU32, Ordering}; use paste::paste; diff --git a/embassy-imxrt/src/crc.rs b/embassy-imxrt/src/crc.rs index 24d6ba5bd..d6f0419d0 100644 --- a/embassy-imxrt/src/crc.rs +++ b/embassy-imxrt/src/crc.rs @@ -2,9 +2,9 @@ use core::marker::PhantomData; -use crate::clocks::{enable_and_reset, SysconPeripheral}; +use crate::clocks::{SysconPeripheral, enable_and_reset}; pub use crate::pac::crc_engine::mode::CrcPolynomial as Polynomial; -use crate::{peripherals, Peri, PeripheralType}; +use crate::{Peri, PeripheralType, peripherals}; /// CRC driver. pub struct Crc<'d> { diff --git a/embassy-imxrt/src/dma.rs b/embassy-imxrt/src/dma.rs index e141447f3..e71a27e0e 100644 --- a/embassy-imxrt/src/dma.rs +++ b/embassy-imxrt/src/dma.rs @@ -2,10 +2,10 @@ use core::future::Future; use core::pin::Pin; -use core::sync::atomic::{compiler_fence, Ordering}; +use core::sync::atomic::{Ordering, compiler_fence}; use core::task::{Context, Poll}; -use embassy_hal_internal::{impl_peripheral, Peri, PeripheralType}; +use embassy_hal_internal::{Peri, PeripheralType, impl_peripheral}; use embassy_sync::waitqueue::AtomicWaker; use pac::dma0::channel::cfg::Periphreqen; use pac::dma0::channel::xfercfg::{Dstinc, Srcinc, Width}; @@ -14,7 +14,7 @@ use crate::clocks::enable_and_reset; use crate::interrupt::InterruptExt; use crate::peripherals::DMA0; use crate::sealed::Sealed; -use crate::{interrupt, pac, peripherals, BitIter}; +use crate::{BitIter, interrupt, pac, peripherals}; #[cfg(feature = "rt")] #[interrupt] diff --git a/embassy-imxrt/src/flexcomm/mod.rs b/embassy-imxrt/src/flexcomm/mod.rs index 4473c9a77..27794042b 100644 --- a/embassy-imxrt/src/flexcomm/mod.rs +++ b/embassy-imxrt/src/flexcomm/mod.rs @@ -4,11 +4,11 @@ pub mod uart; use paste::paste; -use crate::clocks::{enable_and_reset, SysconPeripheral}; +use crate::clocks::{SysconPeripheral, enable_and_reset}; use crate::peripherals::{ - FLEXCOMM0, FLEXCOMM1, FLEXCOMM14, FLEXCOMM15, FLEXCOMM2, FLEXCOMM3, FLEXCOMM4, FLEXCOMM5, FLEXCOMM6, FLEXCOMM7, + FLEXCOMM0, FLEXCOMM1, FLEXCOMM2, FLEXCOMM3, FLEXCOMM4, FLEXCOMM5, FLEXCOMM6, FLEXCOMM7, FLEXCOMM14, FLEXCOMM15, }; -use crate::{pac, PeripheralType}; +use crate::{PeripheralType, pac}; /// clock selection option #[derive(Copy, Clone, Debug)] @@ -223,9 +223,15 @@ macro_rules! into_mode { } } -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!( + 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, diff --git a/embassy-imxrt/src/flexcomm/uart.rs b/embassy-imxrt/src/flexcomm/uart.rs index 230b30d43..2b759ba84 100644 --- a/embassy-imxrt/src/flexcomm/uart.rs +++ b/embassy-imxrt/src/flexcomm/uart.rs @@ -2,10 +2,10 @@ use core::future::poll_fn; use core::marker::PhantomData; -use core::sync::atomic::{compiler_fence, AtomicU8, Ordering}; +use core::sync::atomic::{AtomicU8, Ordering, compiler_fence}; use core::task::Poll; -use embassy_futures::select::{select, Either}; +use embassy_futures::select::{Either, select}; use embassy_hal_internal::drop::OnDrop; use embassy_hal_internal::{Peri, PeripheralType}; use embassy_sync::waitqueue::AtomicWaker; diff --git a/embassy-imxrt/src/gpio.rs b/embassy-imxrt/src/gpio.rs index e62fde8b1..4a0608e76 100644 --- a/embassy-imxrt/src/gpio.rs +++ b/embassy-imxrt/src/gpio.rs @@ -13,7 +13,7 @@ use crate::clocks::enable_and_reset; use crate::iopctl::IopctlPin; pub use crate::iopctl::{AnyPin, DriveMode, DriveStrength, Function, Inverter, Pull, SlewRate}; use crate::sealed::Sealed; -use crate::{interrupt, peripherals, BitIter, Peri, PeripheralType}; +use crate::{BitIter, Peri, PeripheralType, interrupt, peripherals}; // This should be unique per IMXRT package const PORT_COUNT: usize = 8; diff --git a/embassy-imxrt/src/iopctl.rs b/embassy-imxrt/src/iopctl.rs index a3b8b14d6..805bf2f1b 100644 --- a/embassy-imxrt/src/iopctl.rs +++ b/embassy-imxrt/src/iopctl.rs @@ -2,7 +2,7 @@ //! //! Also known as IO Pin Configuration (IOCON) -use crate::pac::{iopctl, Iopctl}; +use crate::pac::{Iopctl, iopctl}; // A generic pin of any type. // diff --git a/embassy-imxrt/src/lib.rs b/embassy-imxrt/src/lib.rs index 00ac9af29..643dd0c8a 100644 --- a/embassy-imxrt/src/lib.rs +++ b/embassy-imxrt/src/lib.rs @@ -40,7 +40,7 @@ pub use chip::interrupts::*; pub use chip::pac; #[cfg(not(feature = "unstable-pac"))] pub(crate) use chip::pac; -pub use chip::{peripherals, Peripherals}; +pub use chip::{Peripherals, peripherals}; pub use embassy_hal_internal::{Peri, PeripheralType}; #[cfg(feature = "rt")] diff --git a/embassy-imxrt/src/rng.rs b/embassy-imxrt/src/rng.rs index 75f243df9..094418e41 100644 --- a/embassy-imxrt/src/rng.rs +++ b/embassy-imxrt/src/rng.rs @@ -7,9 +7,9 @@ use core::task::Poll; use embassy_futures::block_on; use embassy_sync::waitqueue::AtomicWaker; -use crate::clocks::{enable_and_reset, SysconPeripheral}; +use crate::clocks::{SysconPeripheral, enable_and_reset}; use crate::interrupt::typelevel::Interrupt; -use crate::{interrupt, peripherals, Peri, PeripheralType}; +use crate::{Peri, PeripheralType, interrupt, peripherals}; static RNG_WAKER: AtomicWaker = AtomicWaker::new(); diff --git a/embassy-imxrt/src/time_driver.rs b/embassy-imxrt/src/time_driver.rs index f127609c8..fbd935b70 100644 --- a/embassy-imxrt/src/time_driver.rs +++ b/embassy-imxrt/src/time_driver.rs @@ -1,11 +1,11 @@ //! Time Driver. use core::cell::{Cell, RefCell}; #[cfg(feature = "time-driver-rtc")] -use core::sync::atomic::{compiler_fence, AtomicU32, Ordering}; +use core::sync::atomic::{AtomicU32, Ordering, compiler_fence}; use critical_section::CriticalSection; -use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex; use embassy_sync::blocking_mutex::Mutex; +use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex; use embassy_time_driver::Driver; use embassy_time_queue_utils::Queue; diff --git a/embassy-mspm0/src/adc.rs b/embassy-mspm0/src/adc.rs index 5b93e9a6e..948801679 100644 --- a/embassy-mspm0/src/adc.rs +++ b/embassy-mspm0/src/adc.rs @@ -4,13 +4,13 @@ use core::future::poll_fn; use core::marker::PhantomData; use core::task::Poll; -use embassy_hal_internal::{impl_peripheral, PeripheralType}; +use embassy_hal_internal::{PeripheralType, impl_peripheral}; use embassy_sync::waitqueue::AtomicWaker; use crate::interrupt::{Interrupt, InterruptExt}; use crate::mode::{Async, Blocking, Mode}; -use crate::pac::adc::{vals, Adc as Regs}; -use crate::{interrupt, Peri}; +use crate::pac::adc::{Adc as Regs, vals}; +use crate::{Peri, interrupt}; /// Interrupt handler. pub struct InterruptHandler { diff --git a/embassy-mspm0/src/dma.rs b/embassy-mspm0/src/dma.rs index 66b79709c..58b087761 100644 --- a/embassy-mspm0/src/dma.rs +++ b/embassy-mspm0/src/dma.rs @@ -5,18 +5,18 @@ use core::future::Future; use core::mem; use core::pin::Pin; -use core::sync::atomic::{compiler_fence, Ordering}; +use core::sync::atomic::{Ordering, compiler_fence}; use core::task::{Context, Poll}; use critical_section::CriticalSection; use embassy_hal_internal::interrupt::InterruptExt; -use embassy_hal_internal::{impl_peripheral, PeripheralType}; +use embassy_hal_internal::{PeripheralType, impl_peripheral}; use embassy_sync::waitqueue::AtomicWaker; -use mspm0_metapac::common::{Reg, RW}; +use mspm0_metapac::common::{RW, Reg}; use mspm0_metapac::dma::regs; use mspm0_metapac::dma::vals::{self, Autoen, Em, Incr, Preirq, Wdth}; -use crate::{interrupt, pac, Peri}; +use crate::{Peri, interrupt, pac}; /// The burst size of a DMA transfer. #[derive(Debug, Clone, Copy, PartialEq, Eq)] diff --git a/embassy-mspm0/src/gpio.rs b/embassy-mspm0/src/gpio.rs index 4668262a9..a4d41aa71 100644 --- a/embassy-mspm0/src/gpio.rs +++ b/embassy-mspm0/src/gpio.rs @@ -5,7 +5,7 @@ use core::future::Future; use core::pin::Pin as FuturePin; use core::task::{Context, Poll}; -use embassy_hal_internal::{impl_peripheral, Peri, PeripheralType}; +use embassy_hal_internal::{Peri, PeripheralType, impl_peripheral}; use embassy_sync::waitqueue::AtomicWaker; use crate::pac::gpio::vals::*; diff --git a/embassy-mspm0/src/i2c.rs b/embassy-mspm0/src/i2c.rs index 1906e37ba..a12b4b4a2 100644 --- a/embassy-mspm0/src/i2c.rs +++ b/embassy-mspm0/src/i2c.rs @@ -10,13 +10,13 @@ use embassy_hal_internal::PeripheralType; use embassy_sync::waitqueue::AtomicWaker; use mspm0_metapac::i2c; +use crate::Peri; use crate::gpio::{AnyPin, PfType, Pull, SealedPin}; use crate::interrupt::typelevel::Binding; use crate::interrupt::{Interrupt, InterruptExt}; use crate::mode::{Async, Blocking, Mode}; -use crate::pac::i2c::{vals, I2c as Regs}; +use crate::pac::i2c::{I2c as Regs, vals}; use crate::pac::{self}; -use crate::Peri; /// The clock source for the I2C. #[derive(Clone, Copy, PartialEq, Eq, Debug)] diff --git a/embassy-mspm0/src/lib.rs b/embassy-mspm0/src/lib.rs index 06938c21d..55f3f9381 100644 --- a/embassy-mspm0/src/lib.rs +++ b/embassy-mspm0/src/lib.rs @@ -55,7 +55,7 @@ pub(crate) mod _generated { // Reexports pub(crate) use _generated::gpio_pincm; -pub use _generated::{peripherals, Peripherals}; +pub use _generated::{Peripherals, peripherals}; pub use embassy_hal_internal::Peri; #[cfg(feature = "unstable-pac")] pub use mspm0_metapac as pac; diff --git a/embassy-mspm0/src/time_driver.rs b/embassy-mspm0/src/time_driver.rs index e80e89e55..0743c667b 100644 --- a/embassy-mspm0/src/time_driver.rs +++ b/embassy-mspm0/src/time_driver.rs @@ -1,5 +1,5 @@ use core::cell::{Cell, RefCell}; -use core::sync::atomic::{compiler_fence, AtomicU32, Ordering}; +use core::sync::atomic::{AtomicU32, Ordering, compiler_fence}; use core::task::Waker; use critical_section::{CriticalSection, Mutex}; diff --git a/embassy-mspm0/src/uart/buffered.rs b/embassy-mspm0/src/uart/buffered.rs index cbc0b6c80..89e6bcc7b 100644 --- a/embassy-mspm0/src/uart/buffered.rs +++ b/embassy-mspm0/src/uart/buffered.rs @@ -1,4 +1,4 @@ -use core::future::{poll_fn, Future}; +use core::future::{Future, poll_fn}; use core::marker::PhantomData; use core::slice; use core::sync::atomic::{AtomicU8, Ordering}; @@ -14,7 +14,7 @@ use crate::gpio::{AnyPin, SealedPin}; use crate::interrupt::typelevel::Binding; use crate::pac::uart::Uart as Regs; use crate::uart::{Config, ConfigError, CtsPin, Error, Info, Instance, RtsPin, RxPin, State, TxPin}; -use crate::{interrupt, Peri}; +use crate::{Peri, interrupt}; /// Interrupt handler. pub struct BufferedInterruptHandler { diff --git a/embassy-mspm0/src/uart/mod.rs b/embassy-mspm0/src/uart/mod.rs index 6599cea06..03e68d297 100644 --- a/embassy-mspm0/src/uart/mod.rs +++ b/embassy-mspm0/src/uart/mod.rs @@ -3,17 +3,17 @@ mod buffered; use core::marker::PhantomData; -use core::sync::atomic::{compiler_fence, AtomicU32, Ordering}; +use core::sync::atomic::{AtomicU32, Ordering, compiler_fence}; pub use buffered::*; use embassy_embedded_hal::SetConfig; use embassy_hal_internal::PeripheralType; +use crate::Peri; use crate::gpio::{AnyPin, PfType, Pull, SealedPin}; use crate::interrupt::{Interrupt, InterruptExt}; use crate::mode::{Blocking, Mode}; -use crate::pac::uart::{vals, Uart as Regs}; -use crate::Peri; +use crate::pac::uart::{Uart as Regs, vals}; /// The clock source for the UART. #[derive(Clone, Copy, PartialEq, Eq, Debug)] @@ -931,8 +931,7 @@ fn set_baudrate_inner(regs: Regs, clock: u32, baudrate: u32) -> Result<(), Confi let Some(min_clock) = baudrate.checked_mul(oversampling as u32) else { trace!( "{}x oversampling would cause overflow for clock: {} Hz", - oversampling, - clock + oversampling, clock ); continue; }; @@ -945,9 +944,7 @@ fn set_baudrate_inner(regs: Regs, clock: u32, baudrate: u32) -> Result<(), Confi for &(div, div_value) in &DIVS { trace!( "Trying div: {}, oversampling {} for {} baud", - div, - oversampling, - baudrate + div, oversampling, baudrate ); let Some((ibrd, fbrd)) = calculate_brd(clock, div, baudrate, oversampling) else { diff --git a/embassy-mspm0/src/wwdt.rs b/embassy-mspm0/src/wwdt.rs index e5c62c660..92aeb8b40 100644 --- a/embassy-mspm0/src/wwdt.rs +++ b/embassy-mspm0/src/wwdt.rs @@ -6,9 +6,9 @@ use embassy_hal_internal::PeripheralType; -use crate::pac::wwdt::{vals, Wwdt as Regs}; -use crate::pac::{self}; use crate::Peri; +use crate::pac::wwdt::{Wwdt as Regs, vals}; +use crate::pac::{self}; /// Possible watchdog timeout values. #[derive(Clone, Copy, PartialEq, Eq, Debug)] diff --git a/embassy-net-adin1110/src/crc8.rs b/embassy-net-adin1110/src/crc8.rs index 321983e64..a51353aab 100644 --- a/embassy-net-adin1110/src/crc8.rs +++ b/embassy-net-adin1110/src/crc8.rs @@ -23,7 +23,7 @@ pub fn crc8(data: &[u8]) -> u8 { #[cfg(test)] mod tests { - use ::crc::{Crc, CRC_8_SMBUS}; + use ::crc::{CRC_8_SMBUS, Crc}; use super::crc8; diff --git a/embassy-net-adin1110/src/lib.rs b/embassy-net-adin1110/src/lib.rs index 7f1c772e2..90ac242bd 100644 --- a/embassy-net-adin1110/src/lib.rs +++ b/embassy-net-adin1110/src/lib.rs @@ -17,9 +17,9 @@ mod phy; mod regs; use ch::driver::LinkState; -pub use crc32::ETH_FCS; use crc8::crc8; -use embassy_futures::select::{select, Either}; +pub use crc32::ETH_FCS; +use embassy_futures::select::{Either, select}; use embassy_net_driver_channel as ch; use embassy_time::Timer; use embedded_hal_1::digital::OutputPin; diff --git a/embassy-net-driver-channel/src/lib.rs b/embassy-net-driver-channel/src/lib.rs index 600efd9e5..d0a14aa52 100644 --- a/embassy-net-driver-channel/src/lib.rs +++ b/embassy-net-driver-channel/src/lib.rs @@ -11,8 +11,8 @@ use core::task::{Context, Poll}; pub use embassy_net_driver as driver; use embassy_net_driver::{Capabilities, LinkState}; -use embassy_sync::blocking_mutex::raw::NoopRawMutex; use embassy_sync::blocking_mutex::Mutex; +use embassy_sync::blocking_mutex::raw::NoopRawMutex; use embassy_sync::waitqueue::WakerRegistration; use embassy_sync::zerocopy_channel; diff --git a/embassy-net-esp-hosted/src/control.rs b/embassy-net-esp-hosted/src/control.rs index b1838a425..cbc194877 100644 --- a/embassy-net-esp-hosted/src/control.rs +++ b/embassy-net-esp-hosted/src/control.rs @@ -65,8 +65,7 @@ macro_rules! ioctl { }; $self.ioctl(&mut msg).await?; #[allow(unused_mut)] - let Some(proto::CtrlMsgPayload::$resp_variant(mut $resp)) = msg.payload - else { + let Some(proto::CtrlMsgPayload::$resp_variant(mut $resp)) = msg.payload else { warn!("unexpected response variant"); return Err(Error::Internal); }; diff --git a/embassy-net-esp-hosted/src/ioctl.rs b/embassy-net-esp-hosted/src/ioctl.rs index 512023206..a516f80c7 100644 --- a/embassy-net-esp-hosted/src/ioctl.rs +++ b/embassy-net-esp-hosted/src/ioctl.rs @@ -1,5 +1,5 @@ use core::cell::RefCell; -use core::future::{poll_fn, Future}; +use core::future::{Future, poll_fn}; use core::task::Poll; use embassy_sync::waitqueue::WakerRegistration; diff --git a/embassy-net-esp-hosted/src/lib.rs b/embassy-net-esp-hosted/src/lib.rs index f05e2a70a..4405d9f77 100644 --- a/embassy-net-esp-hosted/src/lib.rs +++ b/embassy-net-esp-hosted/src/lib.rs @@ -2,7 +2,7 @@ #![doc = include_str!("../README.md")] #![warn(missing_docs)] -use embassy_futures::select::{select4, Either4}; +use embassy_futures::select::{Either4, select4}; use embassy_net_driver_channel as ch; use embassy_net_driver_channel::driver::LinkState; use embassy_time::{Duration, Instant, Timer}; diff --git a/embassy-net-nrf91/src/lib.rs b/embassy-net-nrf91/src/lib.rs index 8778b65ab..dd4812aae 100644 --- a/embassy-net-nrf91/src/lib.rs +++ b/embassy-net-nrf91/src/lib.rs @@ -10,12 +10,12 @@ mod fmt; pub mod context; use core::cell::RefCell; -use core::future::{poll_fn, Future}; +use core::future::{Future, poll_fn}; use core::marker::PhantomData; use core::mem::{self, MaybeUninit}; use core::ptr::{self, addr_of, addr_of_mut, copy_nonoverlapping}; use core::slice; -use core::sync::atomic::{compiler_fence, fence, Ordering}; +use core::sync::atomic::{Ordering, compiler_fence, fence}; use core::task::{Poll, Waker}; use cortex_m::peripheral::NVIC; @@ -140,9 +140,7 @@ async fn new_internal<'a>( debug!("Setting IPC RAM as nonsecure..."); trace!( " SPU_REGION_SIZE={}, shmem_ptr=0x{:08X}, shmem_len={}", - SPU_REGION_SIZE, - shmem_ptr as usize, - shmem_len + SPU_REGION_SIZE, shmem_ptr as usize, shmem_len ); let region_start = (shmem_ptr as usize - 0x2000_0000) / SPU_REGION_SIZE; let region_end = region_start + shmem_len / SPU_REGION_SIZE; @@ -166,8 +164,7 @@ async fn new_internal<'a>( }; trace!( " Allocator: start=0x{:08X}, end=0x{:08X}", - alloc.start as usize, - alloc.end as usize + alloc.start as usize, alloc.end as usize ); let cb: &mut ControlBlock = alloc.alloc().write(unsafe { mem::zeroed() }); diff --git a/embassy-net-ppp/src/lib.rs b/embassy-net-ppp/src/lib.rs index 54a98c95f..ab42ecd26 100644 --- a/embassy-net-ppp/src/lib.rs +++ b/embassy-net-ppp/src/lib.rs @@ -8,7 +8,7 @@ mod fmt; use core::convert::Infallible; use core::mem::MaybeUninit; -use embassy_futures::select::{select, Either}; +use embassy_futures::select::{Either, select}; use embassy_net_driver_channel as ch; use embassy_net_driver_channel::driver::LinkState; use embedded_io_async::{BufRead, Write}; diff --git a/embassy-net-wiznet/src/chip/mod.rs b/embassy-net-wiznet/src/chip/mod.rs index 47d7c5dc3..04346bb21 100644 --- a/embassy-net-wiznet/src/chip/mod.rs +++ b/embassy-net-wiznet/src/chip/mod.rs @@ -43,7 +43,7 @@ pub(crate) trait SealedChip { fn tx_addr(addr: u16) -> Self::Address; async fn bus_read(spi: &mut SPI, address: Self::Address, data: &mut [u8]) - -> Result<(), SPI::Error>; + -> Result<(), SPI::Error>; async fn bus_write(spi: &mut SPI, address: Self::Address, data: &[u8]) -> Result<(), SPI::Error>; } diff --git a/embassy-net-wiznet/src/lib.rs b/embassy-net-wiznet/src/lib.rs index 3fbd4c741..30a5db9f6 100644 --- a/embassy-net-wiznet/src/lib.rs +++ b/embassy-net-wiznet/src/lib.rs @@ -6,7 +6,7 @@ pub mod chip; mod device; -use embassy_futures::select::{select3, Either3}; +use embassy_futures::select::{Either3, select3}; use embassy_net_driver_channel as ch; use embassy_net_driver_channel::driver::LinkState; use embassy_time::{Duration, Ticker, Timer}; diff --git a/embassy-net/src/icmp.rs b/embassy-net/src/icmp.rs index 22c31a589..09e91a1ae 100644 --- a/embassy-net/src/icmp.rs +++ b/embassy-net/src/icmp.rs @@ -1,6 +1,6 @@ //! ICMP sockets. -use core::future::{poll_fn, Future}; +use core::future::{Future, poll_fn}; use core::mem; use core::task::{Context, Poll}; diff --git a/embassy-net/src/lib.rs b/embassy-net/src/lib.rs index f701f8add..a49955c96 100644 --- a/embassy-net/src/lib.rs +++ b/embassy-net/src/lib.rs @@ -27,7 +27,7 @@ mod time; pub mod udp; use core::cell::RefCell; -use core::future::{poll_fn, Future}; +use core::future::{Future, poll_fn}; use core::mem::MaybeUninit; use core::pin::pin; use core::task::{Context, Poll}; diff --git a/embassy-net/src/raw.rs b/embassy-net/src/raw.rs index c9f753f13..89d2dd350 100644 --- a/embassy-net/src/raw.rs +++ b/embassy-net/src/raw.rs @@ -1,6 +1,6 @@ //! Raw sockets. -use core::future::{poll_fn, Future}; +use core::future::{Future, poll_fn}; use core::mem; use core::task::{Context, Poll}; diff --git a/embassy-net/src/tcp.rs b/embassy-net/src/tcp.rs index d0230b581..6792c5526 100644 --- a/embassy-net/src/tcp.rs +++ b/embassy-net/src/tcp.rs @@ -8,7 +8,7 @@ //! Incoming connections when no socket is listening are rejected. To accept many incoming //! connections, create many sockets and put them all into listening mode. -use core::future::{poll_fn, Future}; +use core::future::{Future, poll_fn}; use core::mem; use core::task::{Context, Poll}; @@ -18,8 +18,8 @@ use smoltcp::socket::tcp; pub use smoltcp::socket::tcp::State; use smoltcp::wire::{IpEndpoint, IpListenEndpoint}; -use crate::time::duration_to_smoltcp; use crate::Stack; +use crate::time::duration_to_smoltcp; /// Error returned by TcpSocket read/write functions. #[derive(PartialEq, Eq, Clone, Copy, Debug)] diff --git a/embassy-net/src/udp.rs b/embassy-net/src/udp.rs index 482eb0e56..448c25ecc 100644 --- a/embassy-net/src/udp.rs +++ b/embassy-net/src/udp.rs @@ -1,6 +1,6 @@ //! UDP sockets. -use core::future::{poll_fn, Future}; +use core::future::{Future, poll_fn}; use core::mem; use core::task::{Context, Poll}; diff --git a/embassy-nrf/src/buffered_uarte.rs b/embassy-nrf/src/buffered_uarte.rs index 40c679190..4c946497d 100644 --- a/embassy-nrf/src/buffered_uarte.rs +++ b/embassy-nrf/src/buffered_uarte.rs @@ -9,27 +9,27 @@ //! Please also see [crate::uarte] to understand when [BufferedUarte] should be used. use core::cmp::min; -use core::future::{poll_fn, Future}; +use core::future::{Future, poll_fn}; use core::marker::PhantomData; use core::slice; -use core::sync::atomic::{compiler_fence, AtomicBool, AtomicU8, AtomicUsize, Ordering}; +use core::sync::atomic::{AtomicBool, AtomicU8, AtomicUsize, Ordering, compiler_fence}; use core::task::Poll; -use embassy_hal_internal::atomic_ring_buffer::RingBuffer; use embassy_hal_internal::Peri; +use embassy_hal_internal::atomic_ring_buffer::RingBuffer; use pac::uarte::vals; // Re-export SVD variants to allow user to directly set values pub use pac::uarte::vals::{Baudrate, ConfigParity as Parity}; use crate::gpio::{AnyPin, Pin as GpioPin}; -use crate::interrupt::typelevel::Interrupt; use crate::interrupt::InterruptExt; +use crate::interrupt::typelevel::Interrupt; use crate::ppi::{ self, AnyConfigurableChannel, AnyGroup, Channel, ConfigurableChannel, Event, Group, Ppi, PpiGroup, Task, }; use crate::timer::{Instance as TimerInstance, Timer}; -use crate::uarte::{configure, configure_rx_pins, configure_tx_pins, drop_tx_rx, Config, Instance as UarteInstance}; -use crate::{interrupt, pac, EASY_DMA_SIZE}; +use crate::uarte::{Config, Instance as UarteInstance, configure, configure_rx_pins, configure_tx_pins, drop_tx_rx}; +use crate::{EASY_DMA_SIZE, interrupt, pac}; pub(crate) struct State { tx_buf: RingBuffer, diff --git a/embassy-nrf/src/egu.rs b/embassy-nrf/src/egu.rs index f7372fca1..666986115 100644 --- a/embassy-nrf/src/egu.rs +++ b/embassy-nrf/src/egu.rs @@ -10,7 +10,7 @@ use core::marker::PhantomData; use embassy_hal_internal::PeripheralType; use crate::ppi::{Event, Task}; -use crate::{interrupt, pac, Peri}; +use crate::{Peri, interrupt, pac}; /// An instance of the EGU. pub struct Egu<'d> { diff --git a/embassy-nrf/src/embassy_net_802154_driver.rs b/embassy-nrf/src/embassy_net_802154_driver.rs index b3fc5df2c..4c47b7cbd 100644 --- a/embassy-nrf/src/embassy_net_802154_driver.rs +++ b/embassy-nrf/src/embassy_net_802154_driver.rs @@ -1,12 +1,12 @@ //! embassy-net IEEE 802.15.4 driver -use embassy_futures::select::{select3, Either3}; +use embassy_futures::select::{Either3, select3}; use embassy_net_driver_channel::driver::LinkState; use embassy_net_driver_channel::{self as ch}; use embassy_time::{Duration, Ticker}; -use crate::radio::ieee802154::{Packet, Radio}; use crate::radio::InterruptHandler; +use crate::radio::ieee802154::{Packet, Radio}; use crate::{self as nrf, interrupt}; /// MTU for the nrf radio. diff --git a/embassy-nrf/src/gpio.rs b/embassy-nrf/src/gpio.rs index ab5e7ed4b..7ed3a7927 100644 --- a/embassy-nrf/src/gpio.rs +++ b/embassy-nrf/src/gpio.rs @@ -5,10 +5,10 @@ use core::convert::Infallible; use core::hint::unreachable_unchecked; use cfg_if::cfg_if; -use embassy_hal_internal::{impl_peripheral, Peri, PeripheralType}; +use embassy_hal_internal::{Peri, PeripheralType, impl_peripheral}; use crate::pac; -use crate::pac::common::{Reg, RW}; +use crate::pac::common::{RW, Reg}; use crate::pac::gpio; use crate::pac::gpio::vals; #[cfg(not(feature = "_nrf51"))] diff --git a/embassy-nrf/src/gpiote.rs b/embassy-nrf/src/gpiote.rs index 43e43f0bf..a490d5b60 100644 --- a/embassy-nrf/src/gpiote.rs +++ b/embassy-nrf/src/gpiote.rs @@ -1,10 +1,10 @@ //! GPIO task/event (GPIOTE) driver. use core::convert::Infallible; -use core::future::{poll_fn, Future}; +use core::future::{Future, poll_fn}; use core::task::{Context, Poll}; -use embassy_hal_internal::{impl_peripheral, Peri, PeripheralType}; +use embassy_hal_internal::{Peri, PeripheralType, impl_peripheral}; use embassy_sync::waitqueue::AtomicWaker; use crate::gpio::{AnyPin, Flex, Input, Output, Pin as GpioPin, SealedPin as _}; diff --git a/embassy-nrf/src/i2s.rs b/embassy-nrf/src/i2s.rs index 1bfa18491..9cce9f1e8 100644 --- a/embassy-nrf/src/i2s.rs +++ b/embassy-nrf/src/i2s.rs @@ -6,7 +6,7 @@ use core::future::poll_fn; use core::marker::PhantomData; use core::mem::size_of; use core::ops::{Deref, DerefMut}; -use core::sync::atomic::{compiler_fence, AtomicBool, Ordering}; +use core::sync::atomic::{AtomicBool, Ordering, compiler_fence}; use core::task::Poll; use embassy_hal_internal::drop::OnDrop; @@ -17,7 +17,7 @@ use crate::gpio::{AnyPin, Pin as GpioPin, PselBits}; use crate::interrupt::typelevel::Interrupt; use crate::pac::i2s::vals; use crate::util::slice_in_ram_or; -use crate::{interrupt, pac, EASY_DMA_SIZE}; +use crate::{EASY_DMA_SIZE, interrupt, pac}; /// Type alias for `MultiBuffering` with 2 buffers. pub type DoubleBuffering = MultiBuffering; diff --git a/embassy-nrf/src/lib.rs b/embassy-nrf/src/lib.rs index 7a0714cc0..1b7fb7e7f 100644 --- a/embassy-nrf/src/lib.rs +++ b/embassy-nrf/src/lib.rs @@ -285,7 +285,7 @@ macro_rules! bind_interrupts { pub use chip::pac; #[cfg(not(feature = "unstable-pac"))] pub(crate) use chip::pac; -pub use chip::{peripherals, Peripherals, EASY_DMA_SIZE}; +pub use chip::{EASY_DMA_SIZE, Peripherals, peripherals}; pub use embassy_hal_internal::{Peri, PeripheralType}; pub use crate::chip::interrupt; diff --git a/embassy-nrf/src/nfct.rs b/embassy-nrf/src/nfct.rs index 8d70ec954..bfbdc2906 100644 --- a/embassy-nrf/src/nfct.rs +++ b/embassy-nrf/src/nfct.rs @@ -10,18 +10,18 @@ #![macro_use] use core::future::poll_fn; -use core::sync::atomic::{compiler_fence, Ordering}; +use core::sync::atomic::{Ordering, compiler_fence}; use core::task::Poll; use embassy_sync::waitqueue::AtomicWaker; pub use vals::{Bitframesdd as SddPat, Discardmode as DiscardMode}; use crate::interrupt::InterruptExt; -use crate::pac::nfct::vals; use crate::pac::NFCT; +use crate::pac::nfct::vals; use crate::peripherals::NFCT; use crate::util::slice_in_ram; -use crate::{interrupt, pac, Peri}; +use crate::{Peri, interrupt, pac}; /// NFCID1 (aka UID) of different sizes. #[derive(Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Debug)] diff --git a/embassy-nrf/src/nvmc.rs b/embassy-nrf/src/nvmc.rs index c46af0b34..3f38cd0f5 100644 --- a/embassy-nrf/src/nvmc.rs +++ b/embassy-nrf/src/nvmc.rs @@ -8,7 +8,7 @@ use embedded_storage::nor_flash::{ use crate::pac::nvmc::vals; use crate::peripherals::NVMC; -use crate::{pac, Peri}; +use crate::{Peri, pac}; #[cfg(not(feature = "_nrf5340-net"))] /// Erase size of NVMC flash in bytes. diff --git a/embassy-nrf/src/pdm.rs b/embassy-nrf/src/pdm.rs index b6ee52850..bc28f5c8a 100644 --- a/embassy-nrf/src/pdm.rs +++ b/embassy-nrf/src/pdm.rs @@ -4,7 +4,7 @@ use core::future::poll_fn; use core::marker::PhantomData; -use core::sync::atomic::{compiler_fence, Ordering}; +use core::sync::atomic::{Ordering, compiler_fence}; use core::task::Poll; use embassy_hal_internal::drop::OnDrop; @@ -13,7 +13,7 @@ use embassy_sync::waitqueue::AtomicWaker; use fixed::types::I7F1; use crate::chip::EASY_DMA_SIZE; -use crate::gpio::{AnyPin, Pin as GpioPin, SealedPin, DISCONNECTED}; +use crate::gpio::{AnyPin, DISCONNECTED, Pin as GpioPin, SealedPin}; use crate::interrupt::typelevel::Interrupt; use crate::pac::gpio::vals as gpiovals; use crate::pac::pdm::vals; diff --git a/embassy-nrf/src/ppi/dppi.rs b/embassy-nrf/src/ppi/dppi.rs index 078d2fd1c..168647be3 100644 --- a/embassy-nrf/src/ppi/dppi.rs +++ b/embassy-nrf/src/ppi/dppi.rs @@ -1,5 +1,5 @@ use super::{Channel, ConfigurableChannel, Event, Ppi, Task}; -use crate::{pac, Peri}; +use crate::{Peri, pac}; const DPPI_ENABLE_BIT: u32 = 0x8000_0000; const DPPI_CHANNEL_MASK: u32 = 0x0000_00FF; diff --git a/embassy-nrf/src/ppi/mod.rs b/embassy-nrf/src/ppi/mod.rs index 2bcf72e9c..f30c2218d 100644 --- a/embassy-nrf/src/ppi/mod.rs +++ b/embassy-nrf/src/ppi/mod.rs @@ -18,9 +18,9 @@ use core::marker::PhantomData; use core::ptr::NonNull; -use embassy_hal_internal::{impl_peripheral, Peri, PeripheralType}; +use embassy_hal_internal::{Peri, PeripheralType, impl_peripheral}; -use crate::pac::common::{Reg, RW, W}; +use crate::pac::common::{RW, Reg, W}; use crate::peripherals; #[cfg_attr(feature = "_dppi", path = "dppi.rs")] diff --git a/embassy-nrf/src/ppi/ppi.rs b/embassy-nrf/src/ppi/ppi.rs index 531c25444..18bc8b8db 100644 --- a/embassy-nrf/src/ppi/ppi.rs +++ b/embassy-nrf/src/ppi/ppi.rs @@ -1,5 +1,5 @@ use super::{Channel, ConfigurableChannel, Event, Ppi, Task}; -use crate::{pac, Peri}; +use crate::{Peri, pac}; impl<'d> Task<'d> { fn reg_val(&self) -> u32 { diff --git a/embassy-nrf/src/pwm.rs b/embassy-nrf/src/pwm.rs index d67cb546b..e038f44b8 100644 --- a/embassy-nrf/src/pwm.rs +++ b/embassy-nrf/src/pwm.rs @@ -2,11 +2,11 @@ #![macro_use] -use core::sync::atomic::{compiler_fence, Ordering}; +use core::sync::atomic::{Ordering, compiler_fence}; use embassy_hal_internal::{Peri, PeripheralType}; -use crate::gpio::{convert_drive, AnyPin, OutputDrive, Pin as GpioPin, PselBits, SealedPin as _, DISCONNECTED}; +use crate::gpio::{AnyPin, DISCONNECTED, OutputDrive, Pin as GpioPin, PselBits, SealedPin as _, convert_drive}; use crate::pac::gpio::vals as gpiovals; use crate::pac::pwm::vals; use crate::ppi::{Event, Task}; diff --git a/embassy-nrf/src/qspi.rs b/embassy-nrf/src/qspi.rs index 6f4524716..6bb7c033e 100755 --- a/embassy-nrf/src/qspi.rs +++ b/embassy-nrf/src/qspi.rs @@ -2,7 +2,7 @@ #![macro_use] -use core::future::{poll_fn, Future}; +use core::future::{Future, poll_fn}; use core::marker::PhantomData; use core::ptr; use core::task::Poll; diff --git a/embassy-nrf/src/radio/ieee802154.rs b/embassy-nrf/src/radio/ieee802154.rs index 844d3551e..54b463343 100644 --- a/embassy-nrf/src/radio/ieee802154.rs +++ b/embassy-nrf/src/radio/ieee802154.rs @@ -1,18 +1,18 @@ //! IEEE 802.15.4 radio driver use core::marker::PhantomData; -use core::sync::atomic::{compiler_fence, Ordering}; +use core::sync::atomic::{Ordering, compiler_fence}; use core::task::Poll; use embassy_hal_internal::drop::OnDrop; use super::{Error, InterruptHandler, TxPower}; +use crate::Peri; use crate::interrupt::typelevel::Interrupt; use crate::interrupt::{self}; use crate::pac::radio::vals; pub use crate::pac::radio::vals::State as RadioState; use crate::radio::Instance; -use crate::Peri; /// Default (IEEE compliant) Start of Frame Delimiter pub const DEFAULT_SFD: u8 = 0xA7; diff --git a/embassy-nrf/src/rramc.rs b/embassy-nrf/src/rramc.rs index 7cb5660cb..521ac4ee7 100644 --- a/embassy-nrf/src/rramc.rs +++ b/embassy-nrf/src/rramc.rs @@ -7,7 +7,7 @@ use embedded_storage::nor_flash::{ }; use crate::peripherals::RRAMC; -use crate::{pac, Peri}; +use crate::{Peri, pac}; // // Export Nvmc alias and page size for downstream compatibility diff --git a/embassy-nrf/src/saadc.rs b/embassy-nrf/src/saadc.rs index fd48faabb..a199c1c4d 100644 --- a/embassy-nrf/src/saadc.rs +++ b/embassy-nrf/src/saadc.rs @@ -4,11 +4,11 @@ use core::future::poll_fn; use core::marker::PhantomData; -use core::sync::atomic::{compiler_fence, Ordering}; +use core::sync::atomic::{Ordering, compiler_fence}; use core::task::Poll; use embassy_hal_internal::drop::OnDrop; -use embassy_hal_internal::{impl_peripheral, Peri}; +use embassy_hal_internal::{Peri, impl_peripheral}; use embassy_sync::waitqueue::AtomicWaker; pub(crate) use vals::Psel as InputChannel; diff --git a/embassy-nrf/src/spim.rs b/embassy-nrf/src/spim.rs index c410e49fd..ce994dbc9 100644 --- a/embassy-nrf/src/spim.rs +++ b/embassy-nrf/src/spim.rs @@ -6,17 +6,17 @@ use core::future::poll_fn; use core::marker::PhantomData; #[cfg(feature = "_nrf52832_anomaly_109")] use core::sync::atomic::AtomicU8; -use core::sync::atomic::{compiler_fence, Ordering}; +use core::sync::atomic::{Ordering, compiler_fence}; use core::task::Poll; use embassy_embedded_hal::SetConfig; use embassy_hal_internal::{Peri, PeripheralType}; use embassy_sync::waitqueue::AtomicWaker; -pub use embedded_hal_02::spi::{Mode, Phase, Polarity, MODE_0, MODE_1, MODE_2, MODE_3}; +pub use embedded_hal_02::spi::{MODE_0, MODE_1, MODE_2, MODE_3, Mode, Phase, Polarity}; pub use pac::spim::vals::{Frequency, Order as BitOrder}; use crate::chip::{EASY_DMA_SIZE, FORCE_COPY_BUFFER_SIZE}; -use crate::gpio::{self, convert_drive, AnyPin, OutputDrive, Pin as GpioPin, PselBits, SealedPin as _}; +use crate::gpio::{self, AnyPin, OutputDrive, Pin as GpioPin, PselBits, SealedPin as _, convert_drive}; use crate::interrupt::typelevel::Interrupt; use crate::pac::gpio::vals as gpiovals; use crate::pac::spim::vals; diff --git a/embassy-nrf/src/spis.rs b/embassy-nrf/src/spis.rs index 713163a55..885821146 100644 --- a/embassy-nrf/src/spis.rs +++ b/embassy-nrf/src/spis.rs @@ -3,17 +3,17 @@ #![macro_use] use core::future::poll_fn; use core::marker::PhantomData; -use core::sync::atomic::{compiler_fence, Ordering}; +use core::sync::atomic::{Ordering, compiler_fence}; use core::task::Poll; use embassy_embedded_hal::SetConfig; use embassy_hal_internal::{Peri, PeripheralType}; use embassy_sync::waitqueue::AtomicWaker; -pub use embedded_hal_02::spi::{Mode, Phase, Polarity, MODE_0, MODE_1, MODE_2, MODE_3}; +pub use embedded_hal_02::spi::{MODE_0, MODE_1, MODE_2, MODE_3, Mode, Phase, Polarity}; pub use pac::spis::vals::Order as BitOrder; use crate::chip::{EASY_DMA_SIZE, FORCE_COPY_BUFFER_SIZE}; -use crate::gpio::{self, convert_drive, AnyPin, OutputDrive, Pin as GpioPin, SealedPin as _}; +use crate::gpio::{self, AnyPin, OutputDrive, Pin as GpioPin, SealedPin as _, convert_drive}; use crate::interrupt::typelevel::Interrupt; use crate::pac::gpio::vals as gpiovals; use crate::pac::spis::vals; diff --git a/embassy-nrf/src/temp.rs b/embassy-nrf/src/temp.rs index 44be0f6d1..a20e300b7 100644 --- a/embassy-nrf/src/temp.rs +++ b/embassy-nrf/src/temp.rs @@ -9,7 +9,7 @@ use fixed::types::I30F2; use crate::interrupt::InterruptExt; use crate::peripherals::TEMP; -use crate::{interrupt, pac, Peri}; +use crate::{Peri, interrupt, pac}; /// Interrupt handler. pub struct InterruptHandler { diff --git a/embassy-nrf/src/time_driver.rs b/embassy-nrf/src/time_driver.rs index 03f4c2e2b..b723e2334 100644 --- a/embassy-nrf/src/time_driver.rs +++ b/embassy-nrf/src/time_driver.rs @@ -1,9 +1,9 @@ use core::cell::{Cell, RefCell}; -use core::sync::atomic::{compiler_fence, AtomicU32, Ordering}; +use core::sync::atomic::{AtomicU32, Ordering, compiler_fence}; use critical_section::CriticalSection; -use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex; use embassy_sync::blocking_mutex::CriticalSectionMutex as Mutex; +use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex; use embassy_time_driver::Driver; use embassy_time_queue_utils::Queue; diff --git a/embassy-nrf/src/twim.rs b/embassy-nrf/src/twim.rs index 943ea9d31..93255c832 100644 --- a/embassy-nrf/src/twim.rs +++ b/embassy-nrf/src/twim.rs @@ -4,8 +4,8 @@ use core::future::poll_fn; use core::marker::PhantomData; -use core::sync::atomic::compiler_fence; use core::sync::atomic::Ordering::SeqCst; +use core::sync::atomic::compiler_fence; use core::task::Poll; use embassy_embedded_hal::SetConfig; diff --git a/embassy-nrf/src/twis.rs b/embassy-nrf/src/twis.rs index dd4978b3e..2bc0a5c13 100644 --- a/embassy-nrf/src/twis.rs +++ b/embassy-nrf/src/twis.rs @@ -2,10 +2,10 @@ #![macro_use] -use core::future::{poll_fn, Future}; +use core::future::{Future, poll_fn}; use core::marker::PhantomData; -use core::sync::atomic::compiler_fence; use core::sync::atomic::Ordering::SeqCst; +use core::sync::atomic::compiler_fence; use core::task::Poll; use embassy_hal_internal::{Peri, PeripheralType}; diff --git a/embassy-nrf/src/uarte.rs b/embassy-nrf/src/uarte.rs index 66fb3b3f2..1ee452173 100644 --- a/embassy-nrf/src/uarte.rs +++ b/embassy-nrf/src/uarte.rs @@ -15,7 +15,7 @@ use core::future::poll_fn; use core::marker::PhantomData; -use core::sync::atomic::{compiler_fence, AtomicU8, Ordering}; +use core::sync::atomic::{AtomicU8, Ordering, compiler_fence}; use core::task::Poll; use embassy_hal_internal::drop::OnDrop; @@ -25,7 +25,7 @@ use embassy_sync::waitqueue::AtomicWaker; pub use pac::uarte::vals::{Baudrate, ConfigParity as Parity}; use crate::chip::{EASY_DMA_SIZE, FORCE_COPY_BUFFER_SIZE}; -use crate::gpio::{self, AnyPin, Pin as GpioPin, PselBits, SealedPin as _, DISCONNECTED}; +use crate::gpio::{self, AnyPin, DISCONNECTED, Pin as GpioPin, PselBits, SealedPin as _}; use crate::interrupt::typelevel::Interrupt; use crate::pac::gpio::vals as gpiovals; use crate::pac::uarte::vals; diff --git a/embassy-nrf/src/usb/mod.rs b/embassy-nrf/src/usb/mod.rs index 2a32fe922..07cf2578a 100644 --- a/embassy-nrf/src/usb/mod.rs +++ b/embassy-nrf/src/usb/mod.rs @@ -4,10 +4,10 @@ pub mod vbus_detect; -use core::future::{poll_fn, Future}; +use core::future::{Future, poll_fn}; use core::marker::PhantomData; use core::mem::MaybeUninit; -use core::sync::atomic::{compiler_fence, AtomicU32, Ordering}; +use core::sync::atomic::{AtomicU32, Ordering, compiler_fence}; use core::task::Poll; use cortex_m::peripheral::NVIC; @@ -330,11 +330,7 @@ impl<'d, V: VbusDetect> driver::Bus for Bus<'d, V> { let mut was_enabled = false; regs.epinen().modify(|w| { was_enabled = (w.0 & mask) != 0; - if enabled { - w.0 |= mask - } else { - w.0 &= !mask - } + if enabled { w.0 |= mask } else { w.0 &= !mask } }); let ready_mask = In::mask(i); diff --git a/embassy-nrf/src/usb/vbus_detect.rs b/embassy-nrf/src/usb/vbus_detect.rs index 33cf91ee2..f24a7bff5 100644 --- a/embassy-nrf/src/usb/vbus_detect.rs +++ b/embassy-nrf/src/usb/vbus_detect.rs @@ -1,6 +1,6 @@ //! Trait and implementations for performing VBUS detection. -use core::future::{poll_fn, Future}; +use core::future::{Future, poll_fn}; use core::sync::atomic::{AtomicBool, Ordering}; use core::task::Poll; diff --git a/embassy-nrf/src/util.rs b/embassy-nrf/src/util.rs index 78f71719f..87118d347 100644 --- a/embassy-nrf/src/util.rs +++ b/embassy-nrf/src/util.rs @@ -15,9 +15,5 @@ pub(crate) fn slice_in_ram(slice: *const [T]) -> bool { /// Return an error if slice is not in RAM. Skips check if slice is zero-length. pub(crate) fn slice_in_ram_or(slice: *const [T], err: E) -> Result<(), E> { - if slice_in_ram(slice) { - Ok(()) - } else { - Err(err) - } + if slice_in_ram(slice) { Ok(()) } else { Err(err) } } diff --git a/embassy-nrf/src/wdt.rs b/embassy-nrf/src/wdt.rs index dc99a16f5..6afd73431 100644 --- a/embassy-nrf/src/wdt.rs +++ b/embassy-nrf/src/wdt.rs @@ -11,7 +11,7 @@ use embassy_hal_internal::PeripheralType; use crate::pac::wdt::vals; pub use crate::pac::wdt::vals::{Halt as HaltConfig, Sleep as SleepConfig}; -use crate::{interrupt, pac, peripherals, Peri}; +use crate::{Peri, interrupt, pac, peripherals}; const MIN_TICKS: u32 = 15; diff --git a/embassy-nxp/src/dma/lpc55.rs b/embassy-nxp/src/dma/lpc55.rs index 578d1fd88..5bd763f03 100644 --- a/embassy-nxp/src/dma/lpc55.rs +++ b/embassy-nxp/src/dma/lpc55.rs @@ -1,16 +1,16 @@ use core::cell::RefCell; use core::future::Future; use core::pin::Pin; -use core::sync::atomic::{compiler_fence, Ordering}; +use core::sync::atomic::{Ordering, compiler_fence}; use core::task::{Context, Poll}; use critical_section::Mutex; use embassy_hal_internal::interrupt::InterruptExt; -use embassy_hal_internal::{impl_peripheral, PeripheralType}; +use embassy_hal_internal::{PeripheralType, impl_peripheral}; use embassy_sync::waitqueue::AtomicWaker; use crate::pac::{DMA0, SYSCON, *}; -use crate::{peripherals, Peri}; +use crate::{Peri, peripherals}; #[interrupt] fn DMA0() { diff --git a/embassy-nxp/src/gpio/lpc55.rs b/embassy-nxp/src/gpio/lpc55.rs index 36ea99d21..ac8a27d4f 100644 --- a/embassy-nxp/src/gpio/lpc55.rs +++ b/embassy-nxp/src/gpio/lpc55.rs @@ -1,8 +1,8 @@ -use embassy_hal_internal::{impl_peripheral, PeripheralType}; +use embassy_hal_internal::{PeripheralType, impl_peripheral}; use crate::pac::iocon::vals::{PioDigimode, PioMode}; use crate::pac::{GPIO, IOCON, SYSCON}; -use crate::{peripherals, Peri}; +use crate::{Peri, peripherals}; pub(crate) fn init() { // Enable clocks for GPIO, PINT, and IOCON diff --git a/embassy-nxp/src/gpio/rt1xxx.rs b/embassy-nxp/src/gpio/rt1xxx.rs index 1d60a0d51..c4dc110ff 100644 --- a/embassy-nxp/src/gpio/rt1xxx.rs +++ b/embassy-nxp/src/gpio/rt1xxx.rs @@ -5,13 +5,13 @@ use core::ops::Not; use core::pin::Pin as FuturePin; use core::task::{Context, Poll}; -use embassy_hal_internal::{impl_peripheral, Peri, PeripheralType}; +use embassy_hal_internal::{Peri, PeripheralType, impl_peripheral}; use embassy_sync::waitqueue::AtomicWaker; use nxp_pac::gpio::vals::Icr; use nxp_pac::iomuxc::vals::Pus; use crate::chip::{mux_address, pad_address}; -use crate::pac::common::{Reg, RW}; +use crate::pac::common::{RW, Reg}; use crate::pac::gpio::Gpio; #[cfg(feature = "rt")] use crate::pac::interrupt; diff --git a/embassy-nxp/src/lib.rs b/embassy-nxp/src/lib.rs index 617045217..9576f02b1 100644 --- a/embassy-nxp/src/lib.rs +++ b/embassy-nxp/src/lib.rs @@ -30,7 +30,7 @@ pub use chip::interrupt; pub use chip::pac; #[cfg(not(feature = "unstable-pac"))] pub(crate) use chip::pac; -pub use chip::{peripherals, Peripherals}; +pub use chip::{Peripherals, peripherals}; pub use embassy_hal_internal::{Peri, PeripheralType}; /// Macro to bind interrupts to handlers. diff --git a/embassy-nxp/src/pint.rs b/embassy-nxp/src/pint.rs index e594aaa6a..5b10b4540 100644 --- a/embassy-nxp/src/pint.rs +++ b/embassy-nxp/src/pint.rs @@ -8,9 +8,9 @@ use critical_section::Mutex; use embassy_hal_internal::interrupt::InterruptExt; use embassy_sync::waitqueue::AtomicWaker; -use crate::gpio::{self, AnyPin, Level, SealedPin}; -use crate::pac::{interrupt, INPUTMUX, PINT, SYSCON}; use crate::Peri; +use crate::gpio::{self, AnyPin, Level, SealedPin}; +use crate::pac::{INPUTMUX, PINT, SYSCON, interrupt}; struct PinInterrupt { assigned: bool, diff --git a/embassy-nxp/src/time_driver/rtc.rs b/embassy-nxp/src/time_driver/rtc.rs index fb6de6a5e..0883fa2e8 100644 --- a/embassy-nxp/src/time_driver/rtc.rs +++ b/embassy-nxp/src/time_driver/rtc.rs @@ -4,10 +4,10 @@ use core::task::Waker; use critical_section::CriticalSection; use embassy_hal_internal::interrupt::{InterruptExt, Priority}; use embassy_sync::blocking_mutex::CriticalSectionMutex as Mutex; -use embassy_time_driver::{time_driver_impl, Driver}; +use embassy_time_driver::{Driver, time_driver_impl}; use embassy_time_queue_utils::Queue; -use crate::pac::{interrupt, pmc, rtc, PMC, RTC, SYSCON}; +use crate::pac::{PMC, RTC, SYSCON, interrupt, pmc, rtc}; struct AlarmState { timestamp: Cell, diff --git a/embassy-nxp/src/usart/lpc55.rs b/embassy-nxp/src/usart/lpc55.rs index 9034ed429..0be5a8ce7 100644 --- a/embassy-nxp/src/usart/lpc55.rs +++ b/embassy-nxp/src/usart/lpc55.rs @@ -4,16 +4,16 @@ use core::marker::PhantomData; use core::sync::atomic::{AtomicBool, Ordering}; use core::task::Poll; -use embassy_futures::select::{select, Either}; +use embassy_futures::select::{Either, select}; use embassy_hal_internal::interrupt::InterruptExt; use embassy_hal_internal::{Peri, PeripheralType}; use embassy_sync::waitqueue::AtomicWaker; use embedded_io::{self, ErrorKind}; use crate::dma::{AnyChannel, Channel}; -use crate::gpio::{match_iocon, AnyPin, Bank, SealedPin}; -use crate::interrupt::typelevel::{Binding, Interrupt as _}; +use crate::gpio::{AnyPin, Bank, SealedPin, match_iocon}; use crate::interrupt::Interrupt; +use crate::interrupt::typelevel::{Binding, Interrupt as _}; use crate::pac::flexcomm::Flexcomm as FlexcommReg; use crate::pac::iocon::vals::PioFunc; use crate::pac::usart::Usart as UsartReg; diff --git a/embassy-rp/src/adc.rs b/embassy-rp/src/adc.rs index 2db8e63d7..d16779e01 100644 --- a/embassy-rp/src/adc.rs +++ b/embassy-rp/src/adc.rs @@ -1,18 +1,18 @@ //! ADC driver. -use core::future::{poll_fn, Future}; +use core::future::{Future, poll_fn}; use core::marker::PhantomData; use core::mem; -use core::sync::atomic::{compiler_fence, Ordering}; +use core::sync::atomic::{Ordering, compiler_fence}; use core::task::Poll; use embassy_sync::waitqueue::AtomicWaker; use crate::gpio::{self, AnyPin, Pull, SealedPin as GpioPin}; -use crate::interrupt::typelevel::Binding; use crate::interrupt::InterruptExt; +use crate::interrupt::typelevel::Binding; use crate::pac::dma::vals::TreqSel; use crate::peripherals::{ADC, ADC_TEMP_SENSOR}; -use crate::{dma, interrupt, pac, peripherals, Peri, RegExt}; +use crate::{Peri, RegExt, dma, interrupt, pac, peripherals}; static WAKER: AtomicWaker = AtomicWaker::new(); diff --git a/embassy-rp/src/bootsel.rs b/embassy-rp/src/bootsel.rs index 5f0bac248..b24b98cd5 100644 --- a/embassy-rp/src/bootsel.rs +++ b/embassy-rp/src/bootsel.rs @@ -7,8 +7,8 @@ //! //! This module provides functionality to poll BOOTSEL from an embassy application. -use crate::flash::in_ram; use crate::Peri; +use crate::flash::in_ram; /// Reads the BOOTSEL button. Returns true if the button is pressed. /// diff --git a/embassy-rp/src/clocks.rs b/embassy-rp/src/clocks.rs index 2eddc0bcc..56892d7a2 100644 --- a/embassy-rp/src/clocks.rs +++ b/embassy-rp/src/clocks.rs @@ -72,8 +72,8 @@ use core::sync::atomic::{AtomicU32, Ordering}; use pac::clocks::vals::*; use crate::gpio::{AnyPin, SealedPin}; -use crate::pac::common::{Reg, RW}; -use crate::{pac, reset, Peri}; +use crate::pac::common::{RW, Reg}; +use crate::{Peri, pac, reset}; // NOTE: all gpin handling is commented out for future reference. // gpin is not usually safe to use during the boot init() call, so it won't diff --git a/embassy-rp/src/dma.rs b/embassy-rp/src/dma.rs index d31d1e159..18aec60a5 100644 --- a/embassy-rp/src/dma.rs +++ b/embassy-rp/src/dma.rs @@ -1,10 +1,10 @@ //! Direct Memory Access (DMA) use core::future::Future; use core::pin::Pin; -use core::sync::atomic::{compiler_fence, Ordering}; +use core::sync::atomic::{Ordering, compiler_fence}; use core::task::{Context, Poll}; -use embassy_hal_internal::{impl_peripheral, Peri, PeripheralType}; +use embassy_hal_internal::{Peri, PeripheralType, impl_peripheral}; use embassy_sync::waitqueue::AtomicWaker; use pac::dma::vals::DataSize; diff --git a/embassy-rp/src/flash.rs b/embassy-rp/src/flash.rs index 6b5eda0a3..7cc8f0c1d 100644 --- a/embassy-rp/src/flash.rs +++ b/embassy-rp/src/flash.rs @@ -6,8 +6,8 @@ use core::task::{Context, Poll}; use embassy_hal_internal::{Peri, PeripheralType}; use embedded_storage::nor_flash::{ - check_erase, check_read, check_write, ErrorType, MultiwriteNorFlash, NorFlash, NorFlashError, NorFlashErrorKind, - ReadNorFlash, + ErrorType, MultiwriteNorFlash, NorFlash, NorFlashError, NorFlashErrorKind, ReadNorFlash, check_erase, check_read, + check_write, }; use crate::dma::{AnyChannel, Channel, Transfer}; diff --git a/embassy-rp/src/float/cmp.rs b/embassy-rp/src/float/cmp.rs index e540e3918..f917eb9b3 100644 --- a/embassy-rp/src/float/cmp.rs +++ b/embassy-rp/src/float/cmp.rs @@ -21,19 +21,11 @@ impl ROMCmp for f64 { } fn le_abi(a: F, b: F) -> i32 { - if a.is_nan() || b.is_nan() { - 1 - } else { - a.rom_cmp(b) - } + if a.is_nan() || b.is_nan() { 1 } else { a.rom_cmp(b) } } fn ge_abi(a: F, b: F) -> i32 { - if a.is_nan() || b.is_nan() { - -1 - } else { - a.rom_cmp(b) - } + if a.is_nan() || b.is_nan() { -1 } else { a.rom_cmp(b) } } intrinsics! { diff --git a/embassy-rp/src/float/functions.rs b/embassy-rp/src/float/functions.rs index de29ce336..170168237 100644 --- a/embassy-rp/src/float/functions.rs +++ b/embassy-rp/src/float/functions.rs @@ -114,19 +114,11 @@ fn sqrt(f: F) -> F { } fn ln(f: F) -> F { - if is_negative_nonzero_or_nan(f) { - F::NAN - } else { - f.ln() - } + if is_negative_nonzero_or_nan(f) { F::NAN } else { f.ln() } } fn exp(f: F) -> F { - if f.is_nan() { - F::NAN - } else { - f.exp() - } + if f.is_nan() { F::NAN } else { f.exp() } } fn sin(f: F) -> F { diff --git a/embassy-rp/src/gpio.rs b/embassy-rp/src/gpio.rs index f79bf8948..c15e0e41b 100644 --- a/embassy-rp/src/gpio.rs +++ b/embassy-rp/src/gpio.rs @@ -5,13 +5,13 @@ use core::future::Future; use core::pin::Pin as FuturePin; use core::task::{Context, Poll}; -use embassy_hal_internal::{impl_peripheral, Peri, PeripheralType}; +use embassy_hal_internal::{Peri, PeripheralType, impl_peripheral}; use embassy_sync::waitqueue::AtomicWaker; use crate::interrupt::InterruptExt; -use crate::pac::common::{Reg, RW}; use crate::pac::SIO; -use crate::{interrupt, pac, peripherals, RegExt}; +use crate::pac::common::{RW, Reg}; +use crate::{RegExt, interrupt, pac, peripherals}; #[cfg(any(feature = "rp2040", feature = "rp235xa"))] pub(crate) const BANK0_PIN_COUNT: usize = 30; diff --git a/embassy-rp/src/i2c_slave.rs b/embassy-rp/src/i2c_slave.rs index c263047ad..770087bc8 100644 --- a/embassy-rp/src/i2c_slave.rs +++ b/embassy-rp/src/i2c_slave.rs @@ -5,9 +5,9 @@ use core::task::Poll; use pac::i2c; -use crate::i2c::{set_up_i2c_pin, AbortReason, Instance, InterruptHandler, SclPin, SdaPin, FIFO_SIZE}; +use crate::i2c::{AbortReason, FIFO_SIZE, Instance, InterruptHandler, SclPin, SdaPin, set_up_i2c_pin}; use crate::interrupt::typelevel::{Binding, Interrupt}; -use crate::{pac, Peri}; +use crate::{Peri, pac}; /// I2C error #[derive(Debug, PartialEq, Eq, Clone, Copy)] diff --git a/embassy-rp/src/multicore.rs b/embassy-rp/src/multicore.rs index c305513ca..3b120e349 100644 --- a/embassy-rp/src/multicore.rs +++ b/embassy-rp/src/multicore.rs @@ -48,11 +48,11 @@ //! ``` use core::mem::ManuallyDrop; -use core::sync::atomic::{compiler_fence, AtomicBool, Ordering}; +use core::sync::atomic::{AtomicBool, Ordering, compiler_fence}; use crate::interrupt::InterruptExt; use crate::peripherals::CORE1; -use crate::{gpio, install_stack_guard, interrupt, pac, Peri}; +use crate::{Peri, gpio, install_stack_guard, interrupt, pac}; const PAUSE_TOKEN: u32 = 0xDEADBEEF; const RESUME_TOKEN: u32 = !0xDEADBEEF; diff --git a/embassy-rp/src/pio/mod.rs b/embassy-rp/src/pio/mod.rs index 5f554dfe3..38ee1f97c 100644 --- a/embassy-rp/src/pio/mod.rs +++ b/embassy-rp/src/pio/mod.rs @@ -2,21 +2,21 @@ use core::future::Future; use core::marker::PhantomData; use core::pin::Pin as FuturePin; -use core::sync::atomic::{compiler_fence, Ordering}; +use core::sync::atomic::{Ordering, compiler_fence}; use core::task::{Context, Poll}; -use atomic_polyfill::{AtomicU64, AtomicU8}; +use atomic_polyfill::{AtomicU8, AtomicU64}; use embassy_hal_internal::{Peri, PeripheralType}; use embassy_sync::waitqueue::AtomicWaker; -use fixed::types::extra::U8; use fixed::FixedU32; +use fixed::types::extra::U8; use pio::{Program, SideSet, Wrap}; use crate::dma::{self, Channel, Transfer, Word}; use crate::gpio::{self, AnyPin, Drive, Level, Pull, SealedPin, SlewRate}; use crate::interrupt::typelevel::{Binding, Handler, Interrupt}; use crate::relocate::RelocatedProgram; -use crate::{pac, peripherals, RegExt}; +use crate::{RegExt, pac, peripherals}; mod instr; @@ -984,11 +984,7 @@ impl<'d, PIO: Instance + 'd, const SM: usize> StateMachine<'d, PIO, SM> { #[cfg(feature = "_rp235x")] fn pin_base() -> u8 { - if PIO::PIO.gpiobase().read().gpiobase() { - 16 - } else { - 0 - } + if PIO::PIO.gpiobase().read().gpiobase() { 16 } else { 0 } } /// Sets pin directions. This pauses the current state machine to run `SET` commands diff --git a/embassy-rp/src/pio_programs/hd44780.rs b/embassy-rp/src/pio_programs/hd44780.rs index 546c85a89..78281ddd4 100644 --- a/embassy-rp/src/pio_programs/hd44780.rs +++ b/embassy-rp/src/pio_programs/hd44780.rs @@ -1,12 +1,12 @@ //! [HD44780 display driver](https://www.sparkfun.com/datasheets/LCD/HD44780.pdf) +use crate::Peri; use crate::dma::{AnyChannel, Channel}; use crate::pio::{ Common, Config, Direction, FifoJoin, Instance, Irq, LoadedProgram, PioPin, ShiftConfig, ShiftDirection, StateMachine, }; use crate::pio_programs::clock_divider::calculate_pio_clock_divider; -use crate::Peri; /// This struct represents a HD44780 program that takes command words ( <0:4>) pub struct PioHD44780CommandWordProgram<'a, PIO: Instance> { diff --git a/embassy-rp/src/pio_programs/i2s.rs b/embassy-rp/src/pio_programs/i2s.rs index 2382a3f9f..7e5f68ad6 100644 --- a/embassy-rp/src/pio_programs/i2s.rs +++ b/embassy-rp/src/pio_programs/i2s.rs @@ -2,12 +2,12 @@ use fixed::traits::ToFixed; +use crate::Peri; use crate::dma::{AnyChannel, Channel, Transfer}; use crate::gpio::Pull; use crate::pio::{ Common, Config, Direction, FifoJoin, Instance, LoadedProgram, PioPin, ShiftConfig, ShiftDirection, StateMachine, }; -use crate::Peri; /// This struct represents an i2s receiver & controller driver program pub struct PioI2sInProgram<'d, PIO: Instance> { diff --git a/embassy-rp/src/pio_programs/onewire.rs b/embassy-rp/src/pio_programs/onewire.rs index 980d0fe5f..09babc229 100644 --- a/embassy-rp/src/pio_programs/onewire.rs +++ b/embassy-rp/src/pio_programs/onewire.rs @@ -1,11 +1,11 @@ //! OneWire pio driver +use crate::Peri; use crate::clocks::clk_sys_freq; use crate::gpio::Level; use crate::pio::{ Common, Config, Direction, Instance, LoadedProgram, PioPin, ShiftConfig, ShiftDirection, StateMachine, }; -use crate::Peri; /// This struct represents a onewire driver program pub struct PioOneWireProgram<'a, PIO: Instance> { @@ -321,11 +321,7 @@ impl PioOneWireSearch { /// Search for the next address on the bus pub async fn next(&mut self, pio: &mut PioOneWire<'_, PIO, SM>) -> Option { - if self.finished { - None - } else { - pio.search(self).await - } + if self.finished { None } else { pio.search(self).await } } /// Is finished when all devices have been found diff --git a/embassy-rp/src/pio_programs/pwm.rs b/embassy-rp/src/pio_programs/pwm.rs index f0f837bc5..ba06bb3c1 100644 --- a/embassy-rp/src/pio_programs/pwm.rs +++ b/embassy-rp/src/pio_programs/pwm.rs @@ -6,7 +6,7 @@ use pio::InstructionOperands; use crate::gpio::Level; use crate::pio::{Common, Config, Direction, Instance, LoadedProgram, Pin, PioPin, StateMachine}; -use crate::{clocks, Peri}; +use crate::{Peri, clocks}; /// This converts the duration provided into the number of cycles the PIO needs to run to make it take the same time fn to_pio_cycles(duration: Duration) -> u32 { diff --git a/embassy-rp/src/pio_programs/rotary_encoder.rs b/embassy-rp/src/pio_programs/rotary_encoder.rs index 70b3795e9..6347527e6 100644 --- a/embassy-rp/src/pio_programs/rotary_encoder.rs +++ b/embassy-rp/src/pio_programs/rotary_encoder.rs @@ -1,11 +1,11 @@ //! PIO backed quadrature encoder +use crate::Peri; use crate::gpio::Pull; use crate::pio::{ Common, Config, Direction as PioDirection, FifoJoin, Instance, LoadedProgram, PioPin, ShiftDirection, StateMachine, }; use crate::pio_programs::clock_divider::calculate_pio_clock_divider; -use crate::Peri; /// This struct represents an Encoder program loaded into pio instruction memory. pub struct PioEncoderProgram<'a, PIO: Instance> { diff --git a/embassy-rp/src/pio_programs/stepper.rs b/embassy-rp/src/pio_programs/stepper.rs index 0e9a8daf9..5762ee189 100644 --- a/embassy-rp/src/pio_programs/stepper.rs +++ b/embassy-rp/src/pio_programs/stepper.rs @@ -2,9 +2,9 @@ use core::mem::{self, MaybeUninit}; +use crate::Peri; use crate::pio::{Common, Config, Direction, Instance, Irq, LoadedProgram, PioPin, StateMachine}; use crate::pio_programs::clock_divider::calculate_pio_clock_divider; -use crate::Peri; /// This struct represents a Stepper driver program loaded into pio instruction memory. pub struct PioStepperProgram<'a, PIO: Instance> { diff --git a/embassy-rp/src/pio_programs/uart.rs b/embassy-rp/src/pio_programs/uart.rs index 04e39a571..444efb5db 100644 --- a/embassy-rp/src/pio_programs/uart.rs +++ b/embassy-rp/src/pio_programs/uart.rs @@ -5,12 +5,12 @@ use core::convert::Infallible; use embedded_io_async::{ErrorType, Read, Write}; use fixed::traits::ToFixed; +use crate::Peri; use crate::clocks::clk_sys_freq; use crate::gpio::Level; use crate::pio::{ Common, Config, Direction as PioDirection, FifoJoin, Instance, LoadedProgram, PioPin, ShiftDirection, StateMachine, }; -use crate::Peri; /// This struct represents a uart tx program loaded into pio instruction memory. pub struct PioUartTxProgram<'d, PIO: Instance> { diff --git a/embassy-rp/src/pio_programs/ws2812.rs b/embassy-rp/src/pio_programs/ws2812.rs index 37dd1c4e0..e6851b1a6 100644 --- a/embassy-rp/src/pio_programs/ws2812.rs +++ b/embassy-rp/src/pio_programs/ws2812.rs @@ -4,12 +4,12 @@ use embassy_time::Timer; use fixed::types::U24F8; use smart_leds::{RGB8, RGBW}; +use crate::Peri; use crate::clocks::clk_sys_freq; use crate::dma::{AnyChannel, Channel}; use crate::pio::{ Common, Config, FifoJoin, Instance, LoadedProgram, PioPin, ShiftConfig, ShiftDirection, StateMachine, }; -use crate::Peri; const T1: u8 = 2; // start bit const T2: u8 = 5; // data bit diff --git a/embassy-rp/src/psram.rs b/embassy-rp/src/psram.rs index 22eb1ed25..25185ead2 100644 --- a/embassy-rp/src/psram.rs +++ b/embassy-rp/src/psram.rs @@ -10,7 +10,7 @@ #![cfg(feature = "_rp235x")] -use critical_section::{acquire, release, CriticalSection, RestoreState}; +use critical_section::{CriticalSection, RestoreState, acquire, release}; use crate::pac; use crate::qmi_cs1::QmiCs1; diff --git a/embassy-rp/src/pwm.rs b/embassy-rp/src/pwm.rs index 1e1ccc4c6..59a3fc9a2 100644 --- a/embassy-rp/src/pwm.rs +++ b/embassy-rp/src/pwm.rs @@ -3,13 +3,13 @@ use embassy_hal_internal::{Peri, PeripheralType}; pub use embedded_hal_1::pwm::SetDutyCycle; use embedded_hal_1::pwm::{Error, ErrorKind, ErrorType}; -use fixed::traits::ToFixed; use fixed::FixedU16; +use fixed::traits::ToFixed; use pac::pwm::regs::{ChDiv, Intr}; use pac::pwm::vals::Divmode; use crate::gpio::{AnyPin, Pin as GpioPin, Pull, SealedPin as _}; -use crate::{pac, peripherals, RegExt}; +use crate::{RegExt, pac, peripherals}; /// The configuration of a PWM slice. /// Note the period in clock cycles of a slice can be computed as: diff --git a/embassy-rp/src/rtc/mod.rs b/embassy-rp/src/rtc/mod.rs index 8b0deed21..68fb3b765 100644 --- a/embassy-rp/src/rtc/mod.rs +++ b/embassy-rp/src/rtc/mod.rs @@ -2,7 +2,7 @@ mod filter; use core::future::poll_fn; -use core::sync::atomic::{compiler_fence, AtomicBool, Ordering}; +use core::sync::atomic::{AtomicBool, Ordering, compiler_fence}; use core::task::Poll; use embassy_hal_internal::{Peri, PeripheralType}; diff --git a/embassy-rp/src/time_driver.rs b/embassy-rp/src/time_driver.rs index d598287a9..ec1c17ed5 100644 --- a/embassy-rp/src/time_driver.rs +++ b/embassy-rp/src/time_driver.rs @@ -2,8 +2,8 @@ use core::cell::{Cell, RefCell}; use critical_section::CriticalSection; -use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex; use embassy_sync::blocking_mutex::Mutex; +use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex; use embassy_time_driver::Driver; use embassy_time_queue_utils::Queue; #[cfg(feature = "rp2040")] diff --git a/embassy-rp/src/uart/mod.rs b/embassy-rp/src/uart/mod.rs index 6f4e2ee07..43187df2d 100644 --- a/embassy-rp/src/uart/mod.rs +++ b/embassy-rp/src/uart/mod.rs @@ -4,7 +4,7 @@ use core::marker::PhantomData; use core::task::Poll; use atomic_polyfill::{AtomicU16, Ordering}; -use embassy_futures::select::{select, Either}; +use embassy_futures::select::{Either, select}; use embassy_hal_internal::{Peri, PeripheralType}; use embassy_sync::waitqueue::AtomicWaker; use embassy_time::{Delay, Timer}; @@ -16,7 +16,7 @@ use crate::gpio::{AnyPin, SealedPin}; use crate::interrupt::typelevel::{Binding, Interrupt as _}; use crate::interrupt::{Interrupt, InterruptExt}; use crate::pac::io::vals::{Inover, Outover}; -use crate::{interrupt, pac, peripherals, RegExt}; +use crate::{RegExt, interrupt, pac, peripherals}; mod buffered; pub use buffered::{BufferedInterruptHandler, BufferedUart, BufferedUartRx, BufferedUartTx}; @@ -863,11 +863,7 @@ impl<'d, M: Mode> Uart<'d, M> { if let Some(pin) = &tx { let funcsel = { let pin_number = ((pin.gpio().as_ptr() as u32) & 0x1FF) / 8; - if (pin_number % 4) == 0 { - 2 - } else { - 11 - } + if (pin_number % 4) == 0 { 2 } else { 11 } }; pin.gpio().ctrl().write(|w| { w.set_funcsel(funcsel); @@ -886,11 +882,7 @@ impl<'d, M: Mode> Uart<'d, M> { if let Some(pin) = &rx { let funcsel = { let pin_number = ((pin.gpio().as_ptr() as u32) & 0x1FF) / 8; - if ((pin_number - 1) % 4) == 0 { - 2 - } else { - 11 - } + if ((pin_number - 1) % 4) == 0 { 2 } else { 11 } }; pin.gpio().ctrl().write(|w| { w.set_funcsel(funcsel); diff --git a/embassy-rp/src/usb.rs b/embassy-rp/src/usb.rs index 671ecbd32..e8273c3f2 100644 --- a/embassy-rp/src/usb.rs +++ b/embassy-rp/src/usb.rs @@ -2,7 +2,7 @@ use core::future::poll_fn; use core::marker::PhantomData; use core::slice; -use core::sync::atomic::{compiler_fence, Ordering}; +use core::sync::atomic::{Ordering, compiler_fence}; use core::task::Poll; use embassy_hal_internal::PeripheralType; @@ -13,7 +13,7 @@ use embassy_usb_driver::{ }; use crate::interrupt::typelevel::{Binding, Interrupt}; -use crate::{interrupt, pac, peripherals, Peri, RegExt}; +use crate::{Peri, RegExt, interrupt, pac, peripherals}; trait SealedInstance { fn regs() -> crate::pac::usb::Usb; @@ -545,11 +545,7 @@ impl<'d, T: Instance> driver::Endpoint for Endpoint<'d, T, In> { poll_fn(|cx| { EP_IN_WAKERS[index].register(cx.waker()); let val = T::dpram().ep_in_control(self.info.addr.index() - 1).read(); - if val.enable() { - Poll::Ready(()) - } else { - Poll::Pending - } + if val.enable() { Poll::Ready(()) } else { Poll::Pending } }) .await; trace!("wait_enabled IN OK"); @@ -567,11 +563,7 @@ impl<'d, T: Instance> driver::Endpoint for Endpoint<'d, T, Out> { poll_fn(|cx| { EP_OUT_WAKERS[index].register(cx.waker()); let val = T::dpram().ep_out_control(self.info.addr.index() - 1).read(); - if val.enable() { - Poll::Ready(()) - } else { - Poll::Pending - } + if val.enable() { Poll::Ready(()) } else { Poll::Pending } }) .await; trace!("wait_enabled OUT OK"); diff --git a/embassy-rp/src/watchdog.rs b/embassy-rp/src/watchdog.rs index 49cf03850..d42601745 100644 --- a/embassy-rp/src/watchdog.rs +++ b/embassy-rp/src/watchdog.rs @@ -11,7 +11,7 @@ use core::marker::PhantomData; use embassy_time::Duration; use crate::peripherals::WATCHDOG; -use crate::{pac, Peri}; +use crate::{Peri, pac}; /// The reason for a system reset from the watchdog. #[derive(Debug, Copy, Clone, PartialEq, Eq)] diff --git a/embassy-stm32-wpan/src/cmd.rs b/embassy-stm32-wpan/src/cmd.rs index 928357384..5c81a4aa7 100644 --- a/embassy-stm32-wpan/src/cmd.rs +++ b/embassy-stm32-wpan/src/cmd.rs @@ -1,7 +1,7 @@ use core::ptr; -use crate::consts::TlPacketType; use crate::PacketHeader; +use crate::consts::TlPacketType; #[derive(Copy, Clone)] #[repr(C, packed)] diff --git a/embassy-stm32-wpan/src/consts.rs b/embassy-stm32-wpan/src/consts.rs index e2ae6ca86..7ecb22974 100644 --- a/embassy-stm32-wpan/src/consts.rs +++ b/embassy-stm32-wpan/src/consts.rs @@ -1,5 +1,5 @@ -use crate::evt::CsEvt; use crate::PacketHeader; +use crate::evt::CsEvt; #[derive(Debug)] #[repr(C)] diff --git a/embassy-stm32-wpan/src/lhci.rs b/embassy-stm32-wpan/src/lhci.rs index 89f204f99..59c8bfb5d 100644 --- a/embassy-stm32-wpan/src/lhci.rs +++ b/embassy-stm32-wpan/src/lhci.rs @@ -1,9 +1,9 @@ use core::ptr; use crate::cmd::CmdPacket; -use crate::consts::{TlPacketType, TL_EVT_HEADER_SIZE}; +use crate::consts::{TL_EVT_HEADER_SIZE, TlPacketType}; use crate::evt::{CcEvt, EvtPacket, EvtSerial}; -use crate::tables::{DeviceInfoTable, RssInfoTable, SafeBootInfoTable, WirelessFwInfoTable, TL_DEVICE_INFO_TABLE}; +use crate::tables::{DeviceInfoTable, RssInfoTable, SafeBootInfoTable, TL_DEVICE_INFO_TABLE, WirelessFwInfoTable}; const TL_BLEEVT_CC_OPCODE: u8 = 0x0e; const LHCI_OPCODE_C1_DEVICE_INF: u16 = 0xfd62; diff --git a/embassy-stm32-wpan/src/lib.rs b/embassy-stm32-wpan/src/lib.rs index f4eb0069f..f6b1f6021 100644 --- a/embassy-stm32-wpan/src/lib.rs +++ b/embassy-stm32-wpan/src/lib.rs @@ -22,7 +22,7 @@ mod fmt; use core::mem::MaybeUninit; -use core::sync::atomic::{compiler_fence, Ordering}; +use core::sync::atomic::{Ordering, compiler_fence}; use embassy_hal_internal::Peri; use embassy_stm32::interrupt; @@ -95,7 +95,7 @@ impl<'d> TlMbox<'d> { pub fn init( ipcc: Peri<'d, IPCC>, _irqs: impl interrupt::typelevel::Binding - + interrupt::typelevel::Binding, + + interrupt::typelevel::Binding, config: Config, ) -> Self { // this is an inlined version of TL_Init from the STM32WB firmware as requested by AN5289. diff --git a/embassy-stm32-wpan/src/mac/driver.rs b/embassy-stm32-wpan/src/mac/driver.rs index 41cca09e3..480ac3790 100644 --- a/embassy-stm32-wpan/src/mac/driver.rs +++ b/embassy-stm32-wpan/src/mac/driver.rs @@ -6,9 +6,9 @@ use embassy_net_driver::{Capabilities, HardwareAddress, LinkState}; use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex; use embassy_sync::channel::Channel; +use crate::mac::MTU; use crate::mac::event::MacEvent; use crate::mac::runner::Runner; -use crate::mac::MTU; pub struct Driver<'d> { runner: &'d Runner<'d>, diff --git a/embassy-stm32-wpan/src/mac/runner.rs b/embassy-stm32-wpan/src/mac/runner.rs index d3099b6b7..2409f994d 100644 --- a/embassy-stm32-wpan/src/mac/runner.rs +++ b/embassy-stm32-wpan/src/mac/runner.rs @@ -7,10 +7,10 @@ use embassy_sync::channel::Channel; use embassy_sync::mutex::Mutex; use embassy_sync::signal::Signal; +use crate::mac::MTU; use crate::mac::commands::DataRequest; use crate::mac::event::MacEvent; use crate::mac::typedefs::{AddressMode, MacAddress, PanId, SecurityLevel}; -use crate::mac::MTU; use crate::sub::mac::Mac; type ZeroCopyPubSub = blocking_mutex::Mutex>>>; diff --git a/embassy-stm32-wpan/src/sub/ble.rs b/embassy-stm32-wpan/src/sub/ble.rs index 0f770d92c..cd69a0479 100644 --- a/embassy-stm32-wpan/src/sub/ble.rs +++ b/embassy-stm32-wpan/src/sub/ble.rs @@ -4,10 +4,10 @@ use embassy_stm32::ipcc::Ipcc; use hci::Opcode; use crate::cmd::CmdPacket; -use crate::consts::{TlPacketType, TL_BLEEVT_CC_OPCODE, TL_BLEEVT_CS_OPCODE}; +use crate::consts::{TL_BLEEVT_CC_OPCODE, TL_BLEEVT_CS_OPCODE, TlPacketType}; use crate::evt::{EvtBox, EvtPacket, EvtStub}; use crate::sub::mm; -use crate::tables::{BleTable, BLE_CMD_BUFFER, CS_BUFFER, EVT_QUEUE, HCI_ACL_DATA_BUFFER, TL_BLE_TABLE}; +use crate::tables::{BLE_CMD_BUFFER, BleTable, CS_BUFFER, EVT_QUEUE, HCI_ACL_DATA_BUFFER, TL_BLE_TABLE}; use crate::unsafe_linked_list::LinkedListNode; use crate::{channels, evt}; diff --git a/embassy-stm32-wpan/src/sub/mm.rs b/embassy-stm32-wpan/src/sub/mm.rs index 4e4d2f854..62d0de8bd 100644 --- a/embassy-stm32-wpan/src/sub/mm.rs +++ b/embassy-stm32-wpan/src/sub/mm.rs @@ -3,7 +3,7 @@ use core::future::poll_fn; use core::mem::MaybeUninit; use core::task::Poll; -use aligned::{Aligned, A4}; +use aligned::{A4, Aligned}; use cortex_m::interrupt; use embassy_stm32::ipcc::Ipcc; use embassy_sync::waitqueue::AtomicWaker; @@ -12,7 +12,7 @@ use crate::consts::POOL_SIZE; use crate::evt::EvtPacket; #[cfg(feature = "ble")] use crate::tables::BLE_SPARE_EVT_BUF; -use crate::tables::{MemManagerTable, EVT_POOL, FREE_BUF_QUEUE, SYS_SPARE_EVT_BUF, TL_MEM_MANAGER_TABLE}; +use crate::tables::{EVT_POOL, FREE_BUF_QUEUE, MemManagerTable, SYS_SPARE_EVT_BUF, TL_MEM_MANAGER_TABLE}; use crate::unsafe_linked_list::LinkedListNode; use crate::{channels, evt}; diff --git a/embassy-stm32-wpan/src/sub/sys.rs b/embassy-stm32-wpan/src/sub/sys.rs index cf6df58bf..8a3382f86 100644 --- a/embassy-stm32-wpan/src/sub/sys.rs +++ b/embassy-stm32-wpan/src/sub/sys.rs @@ -8,7 +8,7 @@ use crate::shci::{SchiCommandStatus, ShciBleInitCmdParam, ShciOpcode}; use crate::sub::mm; use crate::tables::{SysTable, WirelessFwInfoTable}; use crate::unsafe_linked_list::LinkedListNode; -use crate::{channels, Ipcc, SYSTEM_EVT_QUEUE, SYS_CMD_BUF, TL_DEVICE_INFO_TABLE, TL_SYS_TABLE}; +use crate::{Ipcc, SYS_CMD_BUF, SYSTEM_EVT_QUEUE, TL_DEVICE_INFO_TABLE, TL_SYS_TABLE, channels}; /// A guard that, once constructed, allows for sys commands to be sent to CPU2. pub struct Sys { @@ -35,11 +35,7 @@ impl Sys { let info = unsafe { TL_DEVICE_INFO_TABLE.as_mut_ptr().read_volatile().wireless_fw_info_table }; // Zero version indicates that CPU2 wasn't active and didn't fill the information table - if info.version != 0 { - Some(info) - } else { - None - } + if info.version != 0 { Some(info) } else { None } } pub async fn write(&self, opcode: ShciOpcode, payload: &[u8]) { @@ -66,8 +62,8 @@ impl Sys { #[cfg(feature = "mac")] pub async fn shci_c2_mac_802_15_4_init(&self) -> Result { use crate::tables::{ - Mac802_15_4Table, TracesTable, MAC_802_15_4_CMD_BUFFER, MAC_802_15_4_NOTIF_RSP_EVT_BUFFER, - TL_MAC_802_15_4_TABLE, TL_TRACES_TABLE, TRACES_EVT_QUEUE, + MAC_802_15_4_CMD_BUFFER, MAC_802_15_4_NOTIF_RSP_EVT_BUFFER, Mac802_15_4Table, TL_MAC_802_15_4_TABLE, + TL_TRACES_TABLE, TRACES_EVT_QUEUE, TracesTable, }; unsafe { diff --git a/embassy-stm32-wpan/src/tables.rs b/embassy-stm32-wpan/src/tables.rs index 204790e6d..1dafed159 100644 --- a/embassy-stm32-wpan/src/tables.rs +++ b/embassy-stm32-wpan/src/tables.rs @@ -1,6 +1,6 @@ use core::mem::MaybeUninit; -use aligned::{Aligned, A4}; +use aligned::{A4, Aligned}; use bit_field::BitField; use crate::cmd::{AclDataPacket, CmdPacket}; diff --git a/embassy-stm32/build.rs b/embassy-stm32/build.rs index b5f1261fe..eea1acf68 100644 --- a/embassy-stm32/build.rs +++ b/embassy-stm32/build.rs @@ -9,8 +9,8 @@ use proc_macro2::{Ident, TokenStream}; use quote::{format_ident, quote}; use stm32_metapac::metadata::ir::BitOffset; use stm32_metapac::metadata::{ - MemoryRegion, MemoryRegionKind, PeripheralRccKernelClock, PeripheralRccRegister, PeripheralRegisters, StopMode, - ALL_CHIPS, ALL_PERIPHERAL_VERSIONS, METADATA, + ALL_CHIPS, ALL_PERIPHERAL_VERSIONS, METADATA, MemoryRegion, MemoryRegionKind, PeripheralRccKernelClock, + PeripheralRccRegister, PeripheralRegisters, StopMode, }; #[path = "./build_common.rs"] @@ -105,7 +105,9 @@ fn main() { } (false, false) => { if METADATA.memory.len() != 1 { - panic!("Chip supports single and dual bank configuration. No Cargo feature to select one is enabled. Use the 'single-bank' or 'dual-bank' feature to make your selection") + panic!( + "Chip supports single and dual bank configuration. No Cargo feature to select one is enabled. Use the 'single-bank' or 'dual-bank' feature to make your selection" + ) } METADATA.memory[0] } diff --git a/embassy-stm32/src/adc/adc4.rs b/embassy-stm32/src/adc/adc4.rs index 255dc7956..2608160a3 100644 --- a/embassy-stm32/src/adc/adc4.rs +++ b/embassy-stm32/src/adc/adc4.rs @@ -4,7 +4,7 @@ use pac::adc::vals::{Adc4Dmacfg as Dmacfg, Adc4Exten as Exten, Adc4OversamplingR #[cfg(stm32wba)] use pac::adc::vals::{Chselrmod, Cont, Dmacfg, Exten, OversamplingRatio, Ovss, Smpsel}; -use super::{blocking_delay_us, AdcChannel, AnyAdcChannel, RxDma4, SealedAdcChannel}; +use super::{AdcChannel, AnyAdcChannel, RxDma4, SealedAdcChannel, blocking_delay_us}; use crate::dma::Transfer; #[cfg(stm32u5)] pub use crate::pac::adc::regs::Adc4Chselrmod0 as Chselr; @@ -15,7 +15,7 @@ pub use crate::pac::adc::vals::{Adc4Presc as Presc, Adc4Res as Resolution, Adc4S #[cfg(stm32wba)] pub use crate::pac::adc::vals::{Presc, Res as Resolution, SampleTime}; use crate::time::Hertz; -use crate::{pac, rcc, Peri}; +use crate::{Peri, pac, rcc}; const MAX_ADC_CLK_FREQ: Hertz = Hertz::mhz(55); @@ -208,7 +208,10 @@ impl<'d, T: Instance> Adc4<'d, T> { info!("ADC4 frequency set to {}", frequency); if frequency > MAX_ADC_CLK_FREQ { - panic!("Maximal allowed frequency for ADC4 is {} MHz and it varies with different packages, refer to ST docs for more information.", MAX_ADC_CLK_FREQ.0 / 1_000_000 ); + panic!( + "Maximal allowed frequency for ADC4 is {} MHz and it varies with different packages, refer to ST docs for more information.", + MAX_ADC_CLK_FREQ.0 / 1_000_000 + ); } let mut s = Self { adc }; diff --git a/embassy-stm32/src/adc/c0.rs b/embassy-stm32/src/adc/c0.rs index f2837a8f1..fc28df346 100644 --- a/embassy-stm32/src/adc/c0.rs +++ b/embassy-stm32/src/adc/c0.rs @@ -4,11 +4,11 @@ use pac::adc::vals::{Adstp, Align, Ckmode, Dmacfg, Exten, Ovrmod, Ovsr}; use pac::adccommon::vals::Presc; use super::{ - blocking_delay_us, Adc, AdcChannel, AnyAdcChannel, Instance, Resolution, RxDma, SampleTime, SealedAdcChannel, + Adc, AdcChannel, AnyAdcChannel, Instance, Resolution, RxDma, SampleTime, SealedAdcChannel, blocking_delay_us, }; use crate::dma::Transfer; use crate::time::Hertz; -use crate::{pac, rcc, Peri}; +use crate::{Peri, pac, rcc}; /// Default VREF voltage used for sample conversion to millivolts. pub const VREF_DEFAULT_MV: u32 = 3300; @@ -168,7 +168,10 @@ impl<'d, T: Instance> Adc<'d, T> { debug!("ADC frequency set to {}", frequency); if frequency > MAX_ADC_CLK_FREQ { - panic!("Maximal allowed frequency for the ADC is {} MHz and it varies with different packages, refer to ST docs for more information.", MAX_ADC_CLK_FREQ.0 / 1_000_000 ); + panic!( + "Maximal allowed frequency for the ADC is {} MHz and it varies with different packages, refer to ST docs for more information.", + MAX_ADC_CLK_FREQ.0 / 1_000_000 + ); } let mut s = Self { diff --git a/embassy-stm32/src/adc/f1.rs b/embassy-stm32/src/adc/f1.rs index 3cdc9d8fb..f9c23d72b 100644 --- a/embassy-stm32/src/adc/f1.rs +++ b/embassy-stm32/src/adc/f1.rs @@ -7,7 +7,7 @@ use crate::adc::{Adc, AdcChannel, Instance, SampleTime}; use crate::interrupt::typelevel::Interrupt; use crate::interrupt::{self}; use crate::time::Hertz; -use crate::{rcc, Peri}; +use crate::{Peri, rcc}; pub const VDDA_CALIB_MV: u32 = 3300; pub const ADC_MAX: u32 = (1 << 12) - 1; diff --git a/embassy-stm32/src/adc/f3.rs b/embassy-stm32/src/adc/f3.rs index 3aeb6f2c7..73ceb087a 100644 --- a/embassy-stm32/src/adc/f3.rs +++ b/embassy-stm32/src/adc/f3.rs @@ -6,7 +6,7 @@ use super::blocking_delay_us; use crate::adc::{Adc, AdcChannel, Instance, SampleTime}; use crate::interrupt::typelevel::Interrupt; use crate::time::Hertz; -use crate::{interrupt, rcc, Peri}; +use crate::{Peri, interrupt, rcc}; pub const VDDA_CALIB_MV: u32 = 3300; pub const ADC_MAX: u32 = (1 << 12) - 1; diff --git a/embassy-stm32/src/adc/f3_v1_1.rs b/embassy-stm32/src/adc/f3_v1_1.rs index 84613078c..cd5de54f5 100644 --- a/embassy-stm32/src/adc/f3_v1_1.rs +++ b/embassy-stm32/src/adc/f3_v1_1.rs @@ -9,7 +9,7 @@ use super::Resolution; use crate::adc::{Adc, AdcChannel, Instance, SampleTime}; use crate::interrupt::typelevel::Interrupt; use crate::time::Hertz; -use crate::{interrupt, rcc, Peri}; +use crate::{Peri, interrupt, rcc}; const ADC_FREQ: Hertz = crate::rcc::HSI_FREQ; diff --git a/embassy-stm32/src/adc/g4.rs b/embassy-stm32/src/adc/g4.rs index 43498966f..5098aadd8 100644 --- a/embassy-stm32/src/adc/g4.rs +++ b/embassy-stm32/src/adc/g4.rs @@ -7,11 +7,11 @@ use pac::adc::vals::{Adcaldif, Difsel, Exten, Rovsm, Trovs}; use pac::adccommon::vals::Presc; use stm32_metapac::adc::vals::{Adstp, Dmacfg, Dmaen}; -use super::{blocking_delay_us, Adc, AdcChannel, AnyAdcChannel, Instance, Resolution, RxDma, SampleTime}; +use super::{Adc, AdcChannel, AnyAdcChannel, Instance, Resolution, RxDma, SampleTime, blocking_delay_us}; use crate::adc::SealedAdcChannel; use crate::dma::Transfer; use crate::time::Hertz; -use crate::{pac, rcc, Peri}; +use crate::{Peri, pac, rcc}; /// Default VREF voltage used for sample conversion to millivolts. pub const VREF_DEFAULT_MV: u32 = 3300; @@ -133,7 +133,10 @@ impl<'d, T: Instance> Adc<'d, T> { trace!("ADC frequency set to {}", frequency); if frequency > MAX_ADC_CLK_FREQ { - panic!("Maximal allowed frequency for the ADC is {} MHz and it varies with different packages, refer to ST docs for more information.", MAX_ADC_CLK_FREQ.0 / 1_000_000 ); + panic!( + "Maximal allowed frequency for the ADC is {} MHz and it varies with different packages, refer to ST docs for more information.", + MAX_ADC_CLK_FREQ.0 / 1_000_000 + ); } let mut s = Self { diff --git a/embassy-stm32/src/adc/mod.rs b/embassy-stm32/src/adc/mod.rs index ea986f4cf..22ed8295f 100644 --- a/embassy-stm32/src/adc/mod.rs +++ b/embassy-stm32/src/adc/mod.rs @@ -22,7 +22,7 @@ use core::marker::PhantomData; #[allow(unused)] #[cfg(not(any(adc_f3v3, adc_wba)))] pub use _version::*; -use embassy_hal_internal::{impl_peripheral, PeripheralType}; +use embassy_hal_internal::{PeripheralType, impl_peripheral}; #[cfg(any(adc_f1, adc_f3v1, adc_v1, adc_l0, adc_f3v2))] use embassy_sync::waitqueue::AtomicWaker; diff --git a/embassy-stm32/src/adc/ringbuffered_v2.rs b/embassy-stm32/src/adc/ringbuffered_v2.rs index 6f69e8486..9b2e5b8fe 100644 --- a/embassy-stm32/src/adc/ringbuffered_v2.rs +++ b/embassy-stm32/src/adc/ringbuffered_v2.rs @@ -1,13 +1,13 @@ use core::marker::PhantomData; use core::mem; -use core::sync::atomic::{compiler_fence, Ordering}; +use core::sync::atomic::{Ordering, compiler_fence}; use stm32_metapac::adc::vals::SampleTime; use crate::adc::{Adc, AdcChannel, Instance, RxDma}; use crate::dma::{Priority, ReadableRingBuffer, TransferOptions}; use crate::pac::adc::vals; -use crate::{rcc, Peri}; +use crate::{Peri, rcc}; #[cfg_attr(feature = "defmt", derive(defmt::Format))] pub struct OverrunError; diff --git a/embassy-stm32/src/adc/v1.rs b/embassy-stm32/src/adc/v1.rs index d09374876..a5869d110 100644 --- a/embassy-stm32/src/adc/v1.rs +++ b/embassy-stm32/src/adc/v1.rs @@ -9,7 +9,7 @@ use super::blocking_delay_us; use crate::adc::{Adc, AdcChannel, Instance, Resolution, SampleTime}; use crate::interrupt::typelevel::Interrupt; use crate::peripherals::ADC1; -use crate::{interrupt, rcc, Peri}; +use crate::{Peri, interrupt, rcc}; mod watchdog_v1; pub use watchdog_v1::WatchdogChannels; @@ -66,11 +66,7 @@ pub struct Temperature; impl AdcChannel for Temperature {} impl super::SealedAdcChannel for Temperature { fn channel(&self) -> u8 { - if cfg!(adc_l0) { - 18 - } else { - 16 - } + if cfg!(adc_l0) { 18 } else { 16 } } } diff --git a/embassy-stm32/src/adc/v2.rs b/embassy-stm32/src/adc/v2.rs index e94a25b24..93ec78548 100644 --- a/embassy-stm32/src/adc/v2.rs +++ b/embassy-stm32/src/adc/v2.rs @@ -2,7 +2,7 @@ use super::blocking_delay_us; use crate::adc::{Adc, AdcChannel, Instance, Resolution, SampleTime}; use crate::peripherals::ADC1; use crate::time::Hertz; -use crate::{rcc, Peri}; +use crate::{Peri, rcc}; mod ringbuffered_v2; pub use ringbuffered_v2::{RingBufferedAdc, Sequence}; diff --git a/embassy-stm32/src/adc/v3.rs b/embassy-stm32/src/adc/v3.rs index 16063ce4d..47632263b 100644 --- a/embassy-stm32/src/adc/v3.rs +++ b/embassy-stm32/src/adc/v3.rs @@ -10,10 +10,10 @@ use pac::adc::vals::{OversamplingRatio, OversamplingShift, Rovsm, Trovs}; pub use pac::adc::vals::{Ovsr, Ovss, Presc}; use super::{ - blocking_delay_us, Adc, AdcChannel, AnyAdcChannel, Instance, Resolution, RxDma, SampleTime, SealedAdcChannel, + Adc, AdcChannel, AnyAdcChannel, Instance, Resolution, RxDma, SampleTime, SealedAdcChannel, blocking_delay_us, }; use crate::dma::Transfer; -use crate::{pac, rcc, Peri}; +use crate::{Peri, pac, rcc}; /// Default VREF voltage used for sample conversion to millivolts. pub const VREF_DEFAULT_MV: u32 = 3300; diff --git a/embassy-stm32/src/adc/v4.rs b/embassy-stm32/src/adc/v4.rs index b66437e6e..c7d0103a6 100644 --- a/embassy-stm32/src/adc/v4.rs +++ b/embassy-stm32/src/adc/v4.rs @@ -5,11 +5,11 @@ use pac::adc::vals::{Adstp, Difsel, Dmngt, Exten, Pcsel}; use pac::adccommon::vals::Presc; use super::{ - blocking_delay_us, Adc, AdcChannel, AnyAdcChannel, Instance, Resolution, RxDma, SampleTime, SealedAdcChannel, + Adc, AdcChannel, AnyAdcChannel, Instance, Resolution, RxDma, SampleTime, SealedAdcChannel, blocking_delay_us, }; use crate::dma::Transfer; use crate::time::Hertz; -use crate::{pac, rcc, Peri}; +use crate::{Peri, pac, rcc}; /// Default VREF voltage used for sample conversion to millivolts. pub const VREF_DEFAULT_MV: u32 = 3300; @@ -171,7 +171,10 @@ impl<'d, T: Instance> Adc<'d, T> { info!("ADC frequency set to {}", frequency); if frequency > MAX_ADC_CLK_FREQ { - panic!("Maximal allowed frequency for the ADC is {} MHz and it varies with different packages, refer to ST docs for more information.", MAX_ADC_CLK_FREQ.0 / 1_000_000 ); + panic!( + "Maximal allowed frequency for the ADC is {} MHz and it varies with different packages, refer to ST docs for more information.", + MAX_ADC_CLK_FREQ.0 / 1_000_000 + ); } #[cfg(stm32h7)] diff --git a/embassy-stm32/src/can/bxcan/mod.rs b/embassy-stm32/src/can/bxcan/mod.rs index 8eb188560..507350c42 100644 --- a/embassy-stm32/src/can/bxcan/mod.rs +++ b/embassy-stm32/src/can/bxcan/mod.rs @@ -5,8 +5,8 @@ use core::future::poll_fn; use core::marker::PhantomData; use core::task::Poll; -use embassy_hal_internal::interrupt::InterruptExt; use embassy_hal_internal::PeripheralType; +use embassy_hal_internal::interrupt::InterruptExt; use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex; use embassy_sync::channel::Channel; use embassy_sync::waitqueue::AtomicWaker; @@ -22,7 +22,7 @@ use crate::can::enums::{BusError, RefCountOp, TryReadError}; use crate::gpio::{AfType, OutputType, Pull, Speed}; use crate::interrupt::typelevel::Interrupt; use crate::rcc::{self, RccPeripheral}; -use crate::{interrupt, peripherals, Peri}; +use crate::{Peri, interrupt, peripherals}; /// Interrupt handler. pub struct TxInterruptHandler { @@ -186,10 +186,10 @@ impl<'d> Can<'d> { rx: Peri<'d, if_afio!(impl RxPin)>, tx: Peri<'d, if_afio!(impl TxPin)>, _irqs: impl interrupt::typelevel::Binding> - + interrupt::typelevel::Binding> - + interrupt::typelevel::Binding> - + interrupt::typelevel::Binding> - + 'd, + + interrupt::typelevel::Binding> + + interrupt::typelevel::Binding> + + interrupt::typelevel::Binding> + + 'd, ) -> Self { let info = T::info(); let regs = &T::info().regs; diff --git a/embassy-stm32/src/can/fd/config.rs b/embassy-stm32/src/can/fd/config.rs index c6a66b469..e08349f02 100644 --- a/embassy-stm32/src/can/fd/config.rs +++ b/embassy-stm32/src/can/fd/config.rs @@ -1,7 +1,7 @@ //! Configuration for FDCAN Module // Note: This file is copied and modified from fdcan crate by Richard Meadows -use core::num::{NonZeroU16, NonZeroU8}; +use core::num::{NonZeroU8, NonZeroU16}; /// Configures the bit timings. /// diff --git a/embassy-stm32/src/can/fdcan.rs b/embassy-stm32/src/can/fdcan.rs index d8f71e03e..a142a6d63 100644 --- a/embassy-stm32/src/can/fdcan.rs +++ b/embassy-stm32/src/can/fdcan.rs @@ -3,8 +3,8 @@ use core::future::poll_fn; use core::marker::PhantomData; use core::task::Poll; -use embassy_hal_internal::interrupt::InterruptExt; use embassy_hal_internal::PeripheralType; +use embassy_hal_internal::interrupt::InterruptExt; use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex; use embassy_sync::channel::Channel; use embassy_sync::waitqueue::AtomicWaker; @@ -13,7 +13,7 @@ use crate::can::fd::peripheral::Registers; use crate::gpio::{AfType, OutputType, Pull, SealedPin as _, Speed}; use crate::interrupt::typelevel::Interrupt; use crate::rcc::{self, RccPeripheral}; -use crate::{interrupt, peripherals, Peri}; +use crate::{Peri, interrupt, peripherals}; pub(crate) mod fd; @@ -182,8 +182,8 @@ impl<'d> CanConfigurator<'d> { rx: Peri<'d, impl RxPin>, tx: Peri<'d, impl TxPin>, _irqs: impl interrupt::typelevel::Binding> - + interrupt::typelevel::Binding> - + 'd, + + interrupt::typelevel::Binding> + + 'd, ) -> CanConfigurator<'d> { set_as_af!(rx, AfType::input(Pull::None)); set_as_af!(tx, AfType::output(OutputType::PushPull, Speed::VeryHigh)); @@ -459,7 +459,7 @@ impl<'c, 'd, const TX_BUF_SIZE: usize, const RX_BUF_SIZE: usize> BufferedCan<'d, pub async fn write(&mut self, frame: Frame) { self.tx_buf.send(frame).await; self.info.interrupt0.pend(); // Wake for Tx - //T::IT0Interrupt::pend(); // Wake for Tx + //T::IT0Interrupt::pend(); // Wake for Tx } /// Async read frame from RX buffer. @@ -548,7 +548,7 @@ impl<'c, 'd, const TX_BUF_SIZE: usize, const RX_BUF_SIZE: usize> BufferedCanFd<' pub async fn write(&mut self, frame: FdFrame) { self.tx_buf.send(frame).await; self.info.interrupt0.pend(); // Wake for Tx - //T::IT0Interrupt::pend(); // Wake for Tx + //T::IT0Interrupt::pend(); // Wake for Tx } /// Async read frame from RX buffer. diff --git a/embassy-stm32/src/can/util.rs b/embassy-stm32/src/can/util.rs index fcdbbad62..6d7f0c16a 100644 --- a/embassy-stm32/src/can/util.rs +++ b/embassy-stm32/src/can/util.rs @@ -1,6 +1,6 @@ //! Utility functions shared between CAN controller types. -use core::num::{NonZeroU16, NonZeroU8}; +use core::num::{NonZeroU8, NonZeroU16}; /// Shared struct to represent bit timings used by calc_can_timings. #[derive(Clone, Copy, Debug)] diff --git a/embassy-stm32/src/crc/v1.rs b/embassy-stm32/src/crc/v1.rs index 13e5263de..836228599 100644 --- a/embassy-stm32/src/crc/v1.rs +++ b/embassy-stm32/src/crc/v1.rs @@ -1,6 +1,6 @@ use crate::pac::CRC as PAC_CRC; use crate::peripherals::CRC; -use crate::{rcc, Peri}; +use crate::{Peri, rcc}; /// CRC driver. pub struct Crc<'d> { diff --git a/embassy-stm32/src/crc/v2v3.rs b/embassy-stm32/src/crc/v2v3.rs index d834d0971..a566a2e04 100644 --- a/embassy-stm32/src/crc/v2v3.rs +++ b/embassy-stm32/src/crc/v2v3.rs @@ -1,7 +1,7 @@ -use crate::pac::crc::vals; use crate::pac::CRC as PAC_CRC; +use crate::pac::crc::vals; use crate::peripherals::CRC; -use crate::{rcc, Peri}; +use crate::{Peri, rcc}; /// CRC driver. pub struct Crc<'d> { diff --git a/embassy-stm32/src/cryp/mod.rs b/embassy-stm32/src/cryp/mod.rs index 0173b2b5d..4f1115fb7 100644 --- a/embassy-stm32/src/cryp/mod.rs +++ b/embassy-stm32/src/cryp/mod.rs @@ -1236,7 +1236,10 @@ impl<'d, T: Instance, M: Mode> Cryp<'d, T, M> { } if C::REQUIRES_PADDING { if last_block_remainder != 0 { - panic!("Input must be a multiple of {} bytes in ECB and CBC modes. Consider padding or ciphertext stealing.", C::BLOCK_SIZE); + panic!( + "Input must be a multiple of {} bytes in ECB and CBC modes. Consider padding or ciphertext stealing.", + C::BLOCK_SIZE + ); } } if last_block { @@ -1703,7 +1706,10 @@ impl<'d, T: Instance> Cryp<'d, T, Async> { } if C::REQUIRES_PADDING { if last_block_remainder != 0 { - panic!("Input must be a multiple of {} bytes in ECB and CBC modes. Consider padding or ciphertext stealing.", C::BLOCK_SIZE); + panic!( + "Input must be a multiple of {} bytes in ECB and CBC modes. Consider padding or ciphertext stealing.", + C::BLOCK_SIZE + ); } } if last_block { diff --git a/embassy-stm32/src/dac/mod.rs b/embassy-stm32/src/dac/mod.rs index 08e001337..d74d4a4be 100644 --- a/embassy-stm32/src/dac/mod.rs +++ b/embassy-stm32/src/dac/mod.rs @@ -8,7 +8,7 @@ use crate::mode::{Async, Blocking, Mode as PeriMode}; #[cfg(any(dac_v3, dac_v4, dac_v5, dac_v6, dac_v7))] use crate::pac::dac; use crate::rcc::{self, RccPeripheral}; -use crate::{peripherals, Peri}; +use crate::{Peri, peripherals}; mod tsel; use embassy_hal_internal::PeripheralType; diff --git a/embassy-stm32/src/dcmi.rs b/embassy-stm32/src/dcmi.rs index bd03f1e00..dcae9f298 100644 --- a/embassy-stm32/src/dcmi.rs +++ b/embassy-stm32/src/dcmi.rs @@ -9,7 +9,7 @@ use embassy_sync::waitqueue::AtomicWaker; use crate::dma::Transfer; use crate::gpio::{AfType, Pull}; use crate::interrupt::typelevel::Interrupt; -use crate::{interrupt, rcc, Peri}; +use crate::{Peri, interrupt, rcc}; /// Interrupt handler. pub struct InterruptHandler { diff --git a/embassy-stm32/src/dma/dma_bdma.rs b/embassy-stm32/src/dma/dma_bdma.rs index 73ecab070..90dbf4f09 100644 --- a/embassy-stm32/src/dma/dma_bdma.rs +++ b/embassy-stm32/src/dma/dma_bdma.rs @@ -1,6 +1,6 @@ -use core::future::{poll_fn, Future}; +use core::future::{Future, poll_fn}; use core::pin::Pin; -use core::sync::atomic::{fence, AtomicUsize, Ordering}; +use core::sync::atomic::{AtomicUsize, Ordering, fence}; use core::task::{Context, Poll, Waker}; use embassy_hal_internal::Peri; diff --git a/embassy-stm32/src/dma/gpdma/mod.rs b/embassy-stm32/src/dma/gpdma/mod.rs index 4a14c2a8e..3e117c331 100644 --- a/embassy-stm32/src/dma/gpdma/mod.rs +++ b/embassy-stm32/src/dma/gpdma/mod.rs @@ -2,7 +2,7 @@ use core::future::Future; use core::pin::Pin; -use core::sync::atomic::{fence, AtomicUsize, Ordering}; +use core::sync::atomic::{AtomicUsize, Ordering, fence}; use core::task::{Context, Poll}; use embassy_hal_internal::Peri; diff --git a/embassy-stm32/src/dma/gpdma/ringbuffered.rs b/embassy-stm32/src/dma/gpdma/ringbuffered.rs index 9ee52193b..94c597e0d 100644 --- a/embassy-stm32/src/dma/gpdma/ringbuffered.rs +++ b/embassy-stm32/src/dma/gpdma/ringbuffered.rs @@ -3,12 +3,12 @@ //! FIXME: Add request_pause functionality? //! FIXME: Stop the DMA, if a user does not queue new transfers (chain of linked-list items ends automatically). use core::future::poll_fn; -use core::sync::atomic::{fence, Ordering}; +use core::sync::atomic::{Ordering, fence}; use core::task::Waker; use embassy_hal_internal::Peri; -use super::{AnyChannel, TransferOptions, STATE}; +use super::{AnyChannel, STATE, TransferOptions}; use crate::dma::gpdma::linked_list::{RunMode, Table}; use crate::dma::ringbuffer::{DmaCtrl, Error, ReadableDmaRingBuffer, WritableDmaRingBuffer}; use crate::dma::word::Word; diff --git a/embassy-stm32/src/dma/mod.rs b/embassy-stm32/src/dma/mod.rs index 5989bfd7c..297fa3674 100644 --- a/embassy-stm32/src/dma/mod.rs +++ b/embassy-stm32/src/dma/mod.rs @@ -24,7 +24,7 @@ pub(crate) use util::*; pub(crate) mod ringbuffer; pub mod word; -use embassy_hal_internal::{impl_peripheral, PeripheralType}; +use embassy_hal_internal::{PeripheralType, impl_peripheral}; use crate::interrupt; diff --git a/embassy-stm32/src/dma/ringbuffer/tests/prop_test/mod.rs b/embassy-stm32/src/dma/ringbuffer/tests/prop_test/mod.rs index 661fb1728..eff5b4058 100644 --- a/embassy-stm32/src/dma/ringbuffer/tests/prop_test/mod.rs +++ b/embassy-stm32/src/dma/ringbuffer/tests/prop_test/mod.rs @@ -2,7 +2,7 @@ use std::task::Waker; use proptest::prop_oneof; use proptest::strategy::{self, BoxedStrategy, Strategy as _}; -use proptest_state_machine::{prop_state_machine, ReferenceStateMachine, StateMachineTest}; +use proptest_state_machine::{ReferenceStateMachine, StateMachineTest, prop_state_machine}; use super::*; diff --git a/embassy-stm32/src/dsihost.rs b/embassy-stm32/src/dsihost.rs index deda956af..fd1682d2b 100644 --- a/embassy-stm32/src/dsihost.rs +++ b/embassy-stm32/src/dsihost.rs @@ -7,7 +7,7 @@ use embassy_hal_internal::PeripheralType; //use crate::gpio::{AnyPin, SealedPin}; use crate::gpio::{AfType, AnyPin, OutputType, Speed}; use crate::rcc::{self, RccPeripheral}; -use crate::{peripherals, Peri}; +use crate::{Peri, peripherals}; /// Performs a busy-wait delay for a specified number of microseconds. pub fn blocking_delay_ms(ms: u32) { diff --git a/embassy-stm32/src/dts/mod.rs b/embassy-stm32/src/dts/mod.rs index 1f39c8db5..a75ae0560 100644 --- a/embassy-stm32/src/dts/mod.rs +++ b/embassy-stm32/src/dts/mod.rs @@ -1,7 +1,7 @@ //! Digital Temperature Sensor (DTS) use core::future::poll_fn; -use core::sync::atomic::{compiler_fence, Ordering}; +use core::sync::atomic::{Ordering, compiler_fence}; use core::task::Poll; use embassy_hal_internal::Peri; diff --git a/embassy-stm32/src/eth/v1/mod.rs b/embassy-stm32/src/eth/v1/mod.rs index 5be1c9739..a77eb8719 100644 --- a/embassy-stm32/src/eth/v1/mod.rs +++ b/embassy-stm32/src/eth/v1/mod.rs @@ -4,7 +4,7 @@ mod rx_desc; mod tx_desc; use core::marker::PhantomData; -use core::sync::atomic::{fence, Ordering}; +use core::sync::atomic::{Ordering, fence}; use embassy_hal_internal::Peri; use stm32_metapac::eth::vals::{Apcs, Cr, Dm, DmaomrSr, Fes, Ftf, Ifg, MbProgress, Mw, Pbl, Rsf, St, Tsf}; @@ -190,7 +190,7 @@ impl<'d, T: Instance, P: Phy> Ethernet<'d, T, P> { w.set_apcs(Apcs::STRIP); // automatic padding and crc stripping w.set_fes(Fes::FES100); // fast ethernet speed w.set_dm(Dm::FULL_DUPLEX); // full duplex - // TODO: Carrier sense ? ECRSFD + // TODO: Carrier sense ? ECRSFD }); // Set the mac to pass all multicast packets @@ -350,7 +350,9 @@ impl<'d, T: Instance, P: Phy> Ethernet<'d, T, P> { } #[cfg(any(eth_v1b, eth_v1c))] - config_pins!(rx_clk, tx_clk, mdio, mdc, rxdv, rx_d0, rx_d1, rx_d2, rx_d3, tx_d0, tx_d1, tx_d2, tx_d3, tx_en); + config_pins!( + rx_clk, tx_clk, mdio, mdc, rxdv, rx_d0, rx_d1, rx_d2, rx_d3, tx_d0, tx_d1, tx_d2, tx_d3, tx_en + ); let pins = Pins::Mii([ rx_clk.into(), diff --git a/embassy-stm32/src/eth/v1/rx_desc.rs b/embassy-stm32/src/eth/v1/rx_desc.rs index 2a46c1895..6ade1f29c 100644 --- a/embassy-stm32/src/eth/v1/rx_desc.rs +++ b/embassy-stm32/src/eth/v1/rx_desc.rs @@ -1,4 +1,4 @@ -use core::sync::atomic::{compiler_fence, fence, Ordering}; +use core::sync::atomic::{Ordering, compiler_fence, fence}; use stm32_metapac::eth::vals::{Rpd, Rps}; use vcell::VolatileCell; diff --git a/embassy-stm32/src/eth/v1/tx_desc.rs b/embassy-stm32/src/eth/v1/tx_desc.rs index 1317d20f4..ba99b66cb 100644 --- a/embassy-stm32/src/eth/v1/tx_desc.rs +++ b/embassy-stm32/src/eth/v1/tx_desc.rs @@ -1,4 +1,4 @@ -use core::sync::atomic::{compiler_fence, fence, Ordering}; +use core::sync::atomic::{Ordering, compiler_fence, fence}; use vcell::VolatileCell; diff --git a/embassy-stm32/src/eth/v2/descriptors.rs b/embassy-stm32/src/eth/v2/descriptors.rs index 645bfdb14..e335ed8f3 100644 --- a/embassy-stm32/src/eth/v2/descriptors.rs +++ b/embassy-stm32/src/eth/v2/descriptors.rs @@ -1,4 +1,4 @@ -use core::sync::atomic::{fence, Ordering}; +use core::sync::atomic::{Ordering, fence}; use vcell::VolatileCell; diff --git a/embassy-stm32/src/eth/v2/mod.rs b/embassy-stm32/src/eth/v2/mod.rs index cf7a9901b..39a6e8b0f 100644 --- a/embassy-stm32/src/eth/v2/mod.rs +++ b/embassy-stm32/src/eth/v2/mod.rs @@ -1,7 +1,7 @@ mod descriptors; use core::marker::PhantomData; -use core::sync::atomic::{fence, Ordering}; +use core::sync::atomic::{Ordering, fence}; use embassy_hal_internal::Peri; use stm32_metapac::syscfg::vals::EthSelPhy; @@ -144,7 +144,9 @@ impl<'d, T: Instance, P: Phy> Ethernet<'d, T, P> { .modify(|w| w.set_eth_sel_phy(EthSelPhy::MII_GMII)); }); - config_pins!(rx_clk, tx_clk, mdio, mdc, rxdv, rx_d0, rx_d1, rx_d2, rx_d3, tx_d0, tx_d1, tx_d2, tx_d3, tx_en); + config_pins!( + rx_clk, tx_clk, mdio, mdc, rxdv, rx_d0, rx_d1, rx_d2, rx_d3, tx_d0, tx_d1, tx_d2, tx_d3, tx_en + ); let pins = Pins::Mii([ rx_clk.into(), diff --git a/embassy-stm32/src/exti.rs b/embassy-stm32/src/exti.rs index 9fce78f95..12600d4eb 100644 --- a/embassy-stm32/src/exti.rs +++ b/embassy-stm32/src/exti.rs @@ -5,13 +5,13 @@ use core::marker::PhantomData; use core::pin::Pin; use core::task::{Context, Poll}; -use embassy_hal_internal::{impl_peripheral, PeripheralType}; +use embassy_hal_internal::{PeripheralType, impl_peripheral}; use embassy_sync::waitqueue::AtomicWaker; use crate::gpio::{AnyPin, Input, Level, Pin as GpioPin, Pull}; -use crate::pac::exti::regs::Lines; use crate::pac::EXTI; -use crate::{interrupt, pac, peripherals, Peri}; +use crate::pac::exti::regs::Lines; +use crate::{Peri, interrupt, pac, peripherals}; const EXTI_COUNT: usize = 16; static EXTI_WAKERS: [AtomicWaker; EXTI_COUNT] = [const { AtomicWaker::new() }; EXTI_COUNT]; diff --git a/embassy-stm32/src/flash/asynch.rs b/embassy-stm32/src/flash/asynch.rs index 006dcddeb..a131217b7 100644 --- a/embassy-stm32/src/flash/asynch.rs +++ b/embassy-stm32/src/flash/asynch.rs @@ -1,17 +1,17 @@ use core::marker::PhantomData; -use core::sync::atomic::{fence, Ordering}; +use core::sync::atomic::{Ordering, fence}; use embassy_hal_internal::drop::OnDrop; use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex; use embassy_sync::mutex::Mutex; use super::{ - blocking_read, ensure_sector_aligned, family, get_flash_regions, get_sector, Async, Error, Flash, FlashLayout, - FLASH_BASE, FLASH_SIZE, WRITE_SIZE, + Async, Error, FLASH_BASE, FLASH_SIZE, Flash, FlashLayout, WRITE_SIZE, blocking_read, ensure_sector_aligned, family, + get_flash_regions, get_sector, }; use crate::interrupt::InterruptExt; use crate::peripherals::FLASH; -use crate::{interrupt, Peri}; +use crate::{Peri, interrupt}; pub(super) static REGION_ACCESS: Mutex = Mutex::new(()); diff --git a/embassy-stm32/src/flash/common.rs b/embassy-stm32/src/flash/common.rs index 10023e637..b595938a6 100644 --- a/embassy-stm32/src/flash/common.rs +++ b/embassy-stm32/src/flash/common.rs @@ -1,14 +1,14 @@ use core::marker::PhantomData; -use core::sync::atomic::{fence, Ordering}; +use core::sync::atomic::{Ordering, fence}; use embassy_hal_internal::drop::OnDrop; use super::{ - family, get_flash_regions, Async, Blocking, Error, FlashBank, FlashLayout, FlashRegion, FlashSector, FLASH_SIZE, - MAX_ERASE_SIZE, READ_SIZE, WRITE_SIZE, + Async, Blocking, Error, FLASH_SIZE, FlashBank, FlashLayout, FlashRegion, FlashSector, MAX_ERASE_SIZE, READ_SIZE, + WRITE_SIZE, family, get_flash_regions, }; -use crate::Peri; use crate::_generated::FLASH_BASE; +use crate::Peri; use crate::peripherals::FLASH; /// Internal flash memory driver. diff --git a/embassy-stm32/src/flash/eeprom.rs b/embassy-stm32/src/flash/eeprom.rs index cc3529eb9..39c497e3f 100644 --- a/embassy-stm32/src/flash/eeprom.rs +++ b/embassy-stm32/src/flash/eeprom.rs @@ -1,6 +1,6 @@ use embassy_hal_internal::drop::OnDrop; -use super::{family, Blocking, Error, Flash, EEPROM_BASE, EEPROM_SIZE}; +use super::{Blocking, EEPROM_BASE, EEPROM_SIZE, Error, Flash, family}; #[cfg(eeprom)] impl<'d> Flash<'d, Blocking> { diff --git a/embassy-stm32/src/flash/f0.rs b/embassy-stm32/src/flash/f0.rs index 3f9dbe945..5c01fce9c 100644 --- a/embassy-stm32/src/flash/f0.rs +++ b/embassy-stm32/src/flash/f0.rs @@ -1,5 +1,5 @@ use core::ptr::write_volatile; -use core::sync::atomic::{fence, Ordering}; +use core::sync::atomic::{Ordering, fence}; use super::{FlashSector, WRITE_SIZE}; use crate::flash::Error; diff --git a/embassy-stm32/src/flash/f1f3.rs b/embassy-stm32/src/flash/f1f3.rs index bf9ad2893..9e469ffbc 100644 --- a/embassy-stm32/src/flash/f1f3.rs +++ b/embassy-stm32/src/flash/f1f3.rs @@ -1,5 +1,5 @@ use core::ptr::write_volatile; -use core::sync::atomic::{fence, Ordering}; +use core::sync::atomic::{Ordering, fence}; use super::{FlashSector, WRITE_SIZE}; use crate::flash::Error; diff --git a/embassy-stm32/src/flash/f2.rs b/embassy-stm32/src/flash/f2.rs index 67e380619..b48ab3b76 100644 --- a/embassy-stm32/src/flash/f2.rs +++ b/embassy-stm32/src/flash/f2.rs @@ -1,9 +1,9 @@ use core::ptr::write_volatile; -use core::sync::atomic::{fence, AtomicBool, Ordering}; +use core::sync::atomic::{AtomicBool, Ordering, fence}; use pac::flash::regs::Sr; -use super::{get_flash_regions, FlashBank, FlashSector, WRITE_SIZE}; +use super::{FlashBank, FlashSector, WRITE_SIZE, get_flash_regions}; use crate::flash::Error; use crate::pac; diff --git a/embassy-stm32/src/flash/f4.rs b/embassy-stm32/src/flash/f4.rs index 62e0492b5..9c5051492 100644 --- a/embassy-stm32/src/flash/f4.rs +++ b/embassy-stm32/src/flash/f4.rs @@ -1,10 +1,10 @@ use core::ptr::write_volatile; -use core::sync::atomic::{fence, AtomicBool, Ordering}; +use core::sync::atomic::{AtomicBool, Ordering, fence}; use embassy_sync::waitqueue::AtomicWaker; use pac::flash::regs::Sr; -use super::{get_flash_regions, FlashBank, FlashSector, WRITE_SIZE}; +use super::{FlashBank, FlashSector, WRITE_SIZE, get_flash_regions}; use crate::_generated::FLASH_SIZE; use crate::flash::Error; use crate::pac; @@ -246,7 +246,9 @@ pub(crate) fn assert_not_corrupted_read(end_address: u32) { feature = "stm32f439zi", ))] if second_bank_read && pac::DBGMCU.idcode().read().rev_id() < REVISION_3 && !pa12_is_output_pull_low() { - panic!("Read corruption for stm32f42xxI and stm32f43xxI when PA12 is in use for chips below revision 3, see errata 2.2.11"); + panic!( + "Read corruption for stm32f42xxI and stm32f43xxI when PA12 is in use for chips below revision 3, see errata 2.2.11" + ); } #[cfg(any( @@ -270,14 +272,16 @@ pub(crate) fn assert_not_corrupted_read(end_address: u32) { feature = "stm32f439zg", ))] if second_bank_read && pac::DBGMCU.idcode().read().rev_id() < REVISION_3 && !pa12_is_output_pull_low() { - panic!("Read corruption for stm32f42xxG and stm32f43xxG in dual bank mode when PA12 is in use for chips below revision 3, see errata 2.2.11"); + panic!( + "Read corruption for stm32f42xxG and stm32f43xxG in dual bank mode when PA12 is in use for chips below revision 3, see errata 2.2.11" + ); } } #[allow(unused)] fn pa12_is_output_pull_low() -> bool { - use pac::gpio::vals; use pac::GPIOA; + use pac::gpio::vals; const PIN: usize = 12; GPIOA.moder().read().moder(PIN) == vals::Moder::OUTPUT && GPIOA.pupdr().read().pupdr(PIN) == vals::Pupdr::PULL_DOWN @@ -287,7 +291,7 @@ fn pa12_is_output_pull_low() -> bool { #[cfg(test)] mod tests { use super::*; - use crate::flash::{get_sector, FlashBank}; + use crate::flash::{FlashBank, get_sector}; #[test] #[cfg(stm32f429)] @@ -370,9 +374,13 @@ mod tests { #[cfg(all(bank_setup_configurable))] pub(crate) fn check_bank_setup() { if cfg!(feature = "single-bank") && pac::FLASH.optcr().read().db1m() { - panic!("Embassy is configured as single-bank, but the hardware is running in dual-bank mode. Change the hardware by changing the db1m value in the user option bytes or configure embassy to use dual-bank config"); + panic!( + "Embassy is configured as single-bank, but the hardware is running in dual-bank mode. Change the hardware by changing the db1m value in the user option bytes or configure embassy to use dual-bank config" + ); } if cfg!(feature = "dual-bank") && !pac::FLASH.optcr().read().db1m() { - panic!("Embassy is configured as dual-bank, but the hardware is running in single-bank mode. Change the hardware by changing the db1m value in the user option bytes or configure embassy to use single-bank config"); + panic!( + "Embassy is configured as dual-bank, but the hardware is running in single-bank mode. Change the hardware by changing the db1m value in the user option bytes or configure embassy to use single-bank config" + ); } } diff --git a/embassy-stm32/src/flash/f7.rs b/embassy-stm32/src/flash/f7.rs index 0547c747a..09389c417 100644 --- a/embassy-stm32/src/flash/f7.rs +++ b/embassy-stm32/src/flash/f7.rs @@ -1,5 +1,5 @@ use core::ptr::write_volatile; -use core::sync::atomic::{fence, Ordering}; +use core::sync::atomic::{Ordering, fence}; use super::{FlashSector, WRITE_SIZE}; use crate::flash::Error; @@ -99,7 +99,7 @@ unsafe fn blocking_wait_ready() -> Result<(), Error> { #[cfg(test)] mod tests { use super::*; - use crate::flash::{get_sector, FlashBank}; + use crate::flash::{FlashBank, get_sector}; #[test] #[cfg(stm32f732)] @@ -218,9 +218,13 @@ mod tests { #[cfg(all(bank_setup_configurable))] pub(crate) fn check_bank_setup() { if cfg!(feature = "single-bank") && !pac::FLASH.optcr().read().n_dbank() { - panic!("Embassy is configured as single-bank, but the hardware is running in dual-bank mode. Change the hardware by changing the ndbank value in the user option bytes or configure embassy to use dual-bank config"); + panic!( + "Embassy is configured as single-bank, but the hardware is running in dual-bank mode. Change the hardware by changing the ndbank value in the user option bytes or configure embassy to use dual-bank config" + ); } if cfg!(feature = "dual-bank") && pac::FLASH.optcr().read().n_dbank() { - panic!("Embassy is configured as dual-bank, but the hardware is running in single-bank mode. Change the hardware by changing the ndbank value in the user option bytes or configure embassy to use single-bank config"); + panic!( + "Embassy is configured as dual-bank, but the hardware is running in single-bank mode. Change the hardware by changing the ndbank value in the user option bytes or configure embassy to use single-bank config" + ); } } diff --git a/embassy-stm32/src/flash/g.rs b/embassy-stm32/src/flash/g.rs index bc1fd360c..d026541a4 100644 --- a/embassy-stm32/src/flash/g.rs +++ b/embassy-stm32/src/flash/g.rs @@ -1,5 +1,5 @@ use core::ptr::write_volatile; -use core::sync::atomic::{fence, Ordering}; +use core::sync::atomic::{Ordering, fence}; use cortex_m::interrupt; @@ -105,19 +105,27 @@ fn wait_busy() { #[cfg(all(bank_setup_configurable, any(flash_g4c2, flash_g4c3, flash_g4c4)))] pub(crate) fn check_bank_setup() { if cfg!(feature = "single-bank") && pac::FLASH.optr().read().dbank() { - panic!("Embassy is configured as single-bank, but the hardware is running in dual-bank mode. Change the hardware by changing the dbank value in the user option bytes or configure embassy to use dual-bank config"); + panic!( + "Embassy is configured as single-bank, but the hardware is running in dual-bank mode. Change the hardware by changing the dbank value in the user option bytes or configure embassy to use dual-bank config" + ); } if cfg!(feature = "dual-bank") && !pac::FLASH.optr().read().dbank() { - panic!("Embassy is configured as dual-bank, but the hardware is running in single-bank mode. Change the hardware by changing the dbank value in the user option bytes or configure embassy to use single-bank config"); + panic!( + "Embassy is configured as dual-bank, but the hardware is running in single-bank mode. Change the hardware by changing the dbank value in the user option bytes or configure embassy to use single-bank config" + ); } } #[cfg(all(bank_setup_configurable, flash_g0x1))] pub(crate) fn check_bank_setup() { if cfg!(feature = "single-bank") && pac::FLASH.optr().read().dual_bank() { - panic!("Embassy is configured as single-bank, but the hardware is running in dual-bank mode. Change the hardware by changing the dual_bank value in the user option bytes or configure embassy to use dual-bank config"); + panic!( + "Embassy is configured as single-bank, but the hardware is running in dual-bank mode. Change the hardware by changing the dual_bank value in the user option bytes or configure embassy to use dual-bank config" + ); } if cfg!(feature = "dual-bank") && !pac::FLASH.optr().read().dual_bank() { - panic!("Embassy is configured as dual-bank, but the hardware is running in single-bank mode. Change the hardware by changing the dual_bank value in the user option bytes or configure embassy to use single-bank config"); + panic!( + "Embassy is configured as dual-bank, but the hardware is running in single-bank mode. Change the hardware by changing the dual_bank value in the user option bytes or configure embassy to use single-bank config" + ); } } diff --git a/embassy-stm32/src/flash/h5.rs b/embassy-stm32/src/flash/h5.rs index fd9bfcc75..88f247879 100644 --- a/embassy-stm32/src/flash/h5.rs +++ b/embassy-stm32/src/flash/h5.rs @@ -1,5 +1,5 @@ use core::ptr::write_volatile; -use core::sync::atomic::{fence, Ordering}; +use core::sync::atomic::{Ordering, fence}; use super::{FlashSector, WRITE_SIZE}; use crate::flash::Error; diff --git a/embassy-stm32/src/flash/h50.rs b/embassy-stm32/src/flash/h50.rs index f8e210556..91d5da4d6 100644 --- a/embassy-stm32/src/flash/h50.rs +++ b/embassy-stm32/src/flash/h50.rs @@ -1,7 +1,7 @@ /// STM32H50 series flash impl. See RM0492 use core::{ ptr::write_volatile, - sync::atomic::{fence, Ordering}, + sync::atomic::{Ordering, fence}, }; use cortex_m::interrupt; diff --git a/embassy-stm32/src/flash/h7.rs b/embassy-stm32/src/flash/h7.rs index f1d84101c..8a43cce3f 100644 --- a/embassy-stm32/src/flash/h7.rs +++ b/embassy-stm32/src/flash/h7.rs @@ -1,7 +1,7 @@ use core::ptr::write_volatile; -use core::sync::atomic::{fence, Ordering}; +use core::sync::atomic::{Ordering, fence}; -use super::{FlashSector, BANK1_REGION, FLASH_REGIONS, WRITE_SIZE}; +use super::{BANK1_REGION, FLASH_REGIONS, FlashSector, WRITE_SIZE}; use crate::flash::Error; use crate::pac; diff --git a/embassy-stm32/src/flash/l.rs b/embassy-stm32/src/flash/l.rs index 1b82704ec..cd23cda5c 100644 --- a/embassy-stm32/src/flash/l.rs +++ b/embassy-stm32/src/flash/l.rs @@ -1,5 +1,5 @@ use core::ptr::write_volatile; -use core::sync::atomic::{fence, Ordering}; +use core::sync::atomic::{Ordering, fence}; use super::{FlashSector, WRITE_SIZE}; use crate::flash::Error; @@ -234,19 +234,27 @@ pub(crate) unsafe fn wait_ready_blocking() -> Result<(), Error> { #[cfg(all(bank_setup_configurable, flash_l5))] pub(crate) fn check_bank_setup() { if cfg!(feature = "single-bank") && pac::FLASH.optr().read().dbank() { - panic!("Embassy is configured as single-bank, but the hardware is running in dual-bank mode. Change the hardware by changing the dbank value in the user option bytes or configure embassy to use dual-bank config"); + panic!( + "Embassy is configured as single-bank, but the hardware is running in dual-bank mode. Change the hardware by changing the dbank value in the user option bytes or configure embassy to use dual-bank config" + ); } if cfg!(feature = "dual-bank") && !pac::FLASH.optr().read().dbank() { - panic!("Embassy is configured as dual-bank, but the hardware is running in single-bank mode. Change the hardware by changing the dbank value in the user option bytes or configure embassy to use single-bank config"); + panic!( + "Embassy is configured as dual-bank, but the hardware is running in single-bank mode. Change the hardware by changing the dbank value in the user option bytes or configure embassy to use single-bank config" + ); } } #[cfg(all(bank_setup_configurable, flash_l4))] pub(crate) fn check_bank_setup() { if cfg!(feature = "single-bank") && pac::FLASH.optr().read().dualbank() { - panic!("Embassy is configured as single-bank, but the hardware is running in dual-bank mode. Change the hardware by changing the dualbank value in the user option bytes or configure embassy to use dual-bank config"); + panic!( + "Embassy is configured as single-bank, but the hardware is running in dual-bank mode. Change the hardware by changing the dualbank value in the user option bytes or configure embassy to use dual-bank config" + ); } if cfg!(feature = "dual-bank") && !pac::FLASH.optr().read().dualbank() { - panic!("Embassy is configured as dual-bank, but the hardware is running in single-bank mode. Change the hardware by changing the dualbank value in the user option bytes or configure embassy to use single-bank config"); + panic!( + "Embassy is configured as dual-bank, but the hardware is running in single-bank mode. Change the hardware by changing the dualbank value in the user option bytes or configure embassy to use single-bank config" + ); } } diff --git a/embassy-stm32/src/flash/u0.rs b/embassy-stm32/src/flash/u0.rs index 68d847eca..a64f6c492 100644 --- a/embassy-stm32/src/flash/u0.rs +++ b/embassy-stm32/src/flash/u0.rs @@ -1,5 +1,5 @@ use core::ptr::write_volatile; -use core::sync::atomic::{fence, Ordering}; +use core::sync::atomic::{Ordering, fence}; use cortex_m::interrupt; diff --git a/embassy-stm32/src/flash/u5.rs b/embassy-stm32/src/flash/u5.rs index 6c3d4b422..5f1f562c0 100644 --- a/embassy-stm32/src/flash/u5.rs +++ b/embassy-stm32/src/flash/u5.rs @@ -1,5 +1,5 @@ use core::ptr::write_volatile; -use core::sync::atomic::{fence, Ordering}; +use core::sync::atomic::{Ordering, fence}; use super::{FlashBank, FlashSector, WRITE_SIZE}; use crate::flash::Error; diff --git a/embassy-stm32/src/fmc.rs b/embassy-stm32/src/fmc.rs index ff18a8bee..8ecfbc522 100644 --- a/embassy-stm32/src/fmc.rs +++ b/embassy-stm32/src/fmc.rs @@ -4,7 +4,7 @@ use core::marker::PhantomData; use embassy_hal_internal::PeripheralType; use crate::gpio::{AfType, OutputType, Pull, Speed}; -use crate::{rcc, Peri}; +use crate::{Peri, rcc}; /// FMC driver pub struct Fmc<'d, T: Instance> { diff --git a/embassy-stm32/src/gpio.rs b/embassy-stm32/src/gpio.rs index 5a8d23183..b55baffdc 100644 --- a/embassy-stm32/src/gpio.rs +++ b/embassy-stm32/src/gpio.rs @@ -4,7 +4,7 @@ use core::convert::Infallible; use critical_section::CriticalSection; -use embassy_hal_internal::{impl_peripheral, Peri, PeripheralType}; +use embassy_hal_internal::{Peri, PeripheralType, impl_peripheral}; use crate::pac::gpio::{self, vals}; use crate::peripherals; diff --git a/embassy-stm32/src/hash/mod.rs b/embassy-stm32/src/hash/mod.rs index 90c06c0d8..ba573267c 100644 --- a/embassy-stm32/src/hash/mod.rs +++ b/embassy-stm32/src/hash/mod.rs @@ -19,7 +19,7 @@ use crate::interrupt::typelevel::Interrupt; use crate::mode::Async; use crate::mode::{Blocking, Mode}; use crate::peripherals::HASH; -use crate::{interrupt, pac, peripherals, rcc, Peri}; +use crate::{Peri, interrupt, pac, peripherals, rcc}; #[cfg(hash_v1)] const NUM_CONTEXT_REGS: usize = 51; @@ -514,11 +514,7 @@ impl<'d, T: Instance> Hash<'d, T, Async> { T::regs().imr().modify(|reg| reg.set_dcie(true)); // Check for completion. let bits = T::regs().sr().read(); - if bits.dcis() { - Poll::Ready(()) - } else { - Poll::Pending - } + if bits.dcis() { Poll::Ready(()) } else { Poll::Pending } }) .await; diff --git a/embassy-stm32/src/hsem/mod.rs b/embassy-stm32/src/hsem/mod.rs index 573a1851d..4d3a5d68d 100644 --- a/embassy-stm32/src/hsem/mod.rs +++ b/embassy-stm32/src/hsem/mod.rs @@ -2,13 +2,13 @@ use embassy_hal_internal::PeripheralType; -use crate::pac; -use crate::rcc::{self, RccPeripheral}; // TODO: This code works for all HSEM implemenations except for the STM32WBA52/4/5xx MCUs. // Those MCUs have a different HSEM implementation (Secure semaphore lock support, // Privileged / unprivileged semaphore lock support, Semaphore lock protection via semaphore attribute), // which is not yet supported by this code. use crate::Peri; +use crate::pac; +use crate::rcc::{self, RccPeripheral}; /// HSEM error. #[derive(Debug)] diff --git a/embassy-stm32/src/hspi/mod.rs b/embassy-stm32/src/hspi/mod.rs index 95d9e5099..69baa708e 100644 --- a/embassy-stm32/src/hspi/mod.rs +++ b/embassy-stm32/src/hspi/mod.rs @@ -16,7 +16,7 @@ use embassy_embedded_hal::{GetConfig, SetConfig}; use embassy_hal_internal::{Peri, PeripheralType}; pub use enums::*; -use crate::dma::{word, ChannelAndRequest}; +use crate::dma::{ChannelAndRequest, word}; use crate::gpio::{AfType, AnyPin, OutputType, Pull, SealedPin as _, Speed}; use crate::mode::{Async, Blocking, Mode as PeriMode}; use crate::pac::hspi::Hspi as Regs; diff --git a/embassy-stm32/src/i2c/mod.rs b/embassy-stm32/src/i2c/mod.rs index 249bac41c..f4bf55d34 100644 --- a/embassy-stm32/src/i2c/mod.rs +++ b/embassy-stm32/src/i2c/mod.rs @@ -154,8 +154,8 @@ impl<'d> I2c<'d, Async, Master> { scl: Peri<'d, if_afio!(impl SclPin)>, sda: Peri<'d, if_afio!(impl SdaPin)>, _irq: impl interrupt::typelevel::Binding> - + interrupt::typelevel::Binding> - + 'd, + + interrupt::typelevel::Binding> + + 'd, tx_dma: Peri<'d, impl TxDma>, rx_dma: Peri<'d, impl RxDma>, config: Config, diff --git a/embassy-stm32/src/i2c/v1.rs b/embassy-stm32/src/i2c/v1.rs index 081eb1191..e6b6c7c42 100644 --- a/embassy-stm32/src/i2c/v1.rs +++ b/embassy-stm32/src/i2c/v1.rs @@ -8,7 +8,7 @@ use core::future::poll_fn; use core::task::Poll; use embassy_embedded_hal::SetConfig; -use embassy_futures::select::{select, Either}; +use embassy_futures::select::{Either, select}; use embassy_hal_internal::drop::OnDrop; use embedded_hal_1::i2c::Operation; use mode::Master; @@ -762,11 +762,7 @@ impl Timings { mode = Mode::Standard; ccr = { let ccr = clock / (frequency * 2); - if ccr < 4 { - 4 - } else { - ccr - } + if ccr < 4 { 4 } else { ccr } }; } else { const DUTYCYCLE: u8 = 0; diff --git a/embassy-stm32/src/i2c/v2.rs b/embassy-stm32/src/i2c/v2.rs index 0bfc795ac..01b6b8800 100644 --- a/embassy-stm32/src/i2c/v2.rs +++ b/embassy-stm32/src/i2c/v2.rs @@ -2,7 +2,7 @@ use core::cmp; use core::future::poll_fn; use core::task::Poll; -use config::{Address, OwnAddresses, OA2}; +use config::{Address, OA2, OwnAddresses}; use embassy_embedded_hal::SetConfig; use embassy_hal_internal::drop::OnDrop; use embedded_hal_1::i2c::Operation; diff --git a/embassy-stm32/src/i2s.rs b/embassy-stm32/src/i2s.rs index b6d3daf54..db22cfa11 100644 --- a/embassy-stm32/src/i2s.rs +++ b/embassy-stm32/src/i2s.rs @@ -3,12 +3,12 @@ use embassy_futures::join::join; use stm32_metapac::spi::vals; -use crate::dma::{ringbuffer, ChannelAndRequest, ReadableRingBuffer, TransferOptions, WritableRingBuffer}; +use crate::Peri; +use crate::dma::{ChannelAndRequest, ReadableRingBuffer, TransferOptions, WritableRingBuffer, ringbuffer}; use crate::gpio::{AfType, AnyPin, OutputType, SealedPin, Speed}; use crate::mode::Async; use crate::spi::{Config as SpiConfig, RegsExt as _, *}; use crate::time::Hertz; -use crate::Peri; /// I2S mode #[derive(Copy, Clone)] diff --git a/embassy-stm32/src/ipcc.rs b/embassy-stm32/src/ipcc.rs index 670d8332c..e1d8b1c2a 100644 --- a/embassy-stm32/src/ipcc.rs +++ b/embassy-stm32/src/ipcc.rs @@ -1,7 +1,7 @@ //! Inter-Process Communication Controller (IPCC) use core::future::poll_fn; -use core::sync::atomic::{compiler_fence, Ordering}; +use core::sync::atomic::{Ordering, compiler_fence}; use core::task::Poll; use embassy_sync::waitqueue::AtomicWaker; diff --git a/embassy-stm32/src/low_power.rs b/embassy-stm32/src/low_power.rs index 342f73bc8..1b66ca680 100644 --- a/embassy-stm32/src/low_power.rs +++ b/embassy-stm32/src/low_power.rs @@ -56,13 +56,13 @@ use core::arch::asm; use core::marker::PhantomData; -use core::sync::atomic::{compiler_fence, Ordering}; +use core::sync::atomic::{Ordering, compiler_fence}; use cortex_m::peripheral::SCB; use embassy_executor::*; use crate::interrupt; -use crate::time_driver::{get_driver, RtcDriver}; +use crate::time_driver::{RtcDriver, get_driver}; const THREAD_PENDER: usize = usize::MAX; diff --git a/embassy-stm32/src/lptim/pwm.rs b/embassy-stm32/src/lptim/pwm.rs index 96af9f4d9..a69db3caf 100644 --- a/embassy-stm32/src/lptim/pwm.rs +++ b/embassy-stm32/src/lptim/pwm.rs @@ -4,12 +4,12 @@ use core::marker::PhantomData; use embassy_hal_internal::Peri; -use super::timer::Timer; #[cfg(not(any(lptim_v2a, lptim_v2b)))] use super::OutputPin; -#[cfg(any(lptim_v2a, lptim_v2b))] -use super::{channel::Channel, timer::ChannelDirection, Channel1Pin, Channel2Pin}; +use super::timer::Timer; use super::{BasicInstance, Instance}; +#[cfg(any(lptim_v2a, lptim_v2b))] +use super::{Channel1Pin, Channel2Pin, channel::Channel, timer::ChannelDirection}; #[cfg(gpio_v2)] use crate::gpio::Pull; use crate::gpio::{AfType, AnyPin, OutputType, Speed}; diff --git a/embassy-stm32/src/ltdc.rs b/embassy-stm32/src/ltdc.rs index 0f6ef569c..de2db9872 100644 --- a/embassy-stm32/src/ltdc.rs +++ b/embassy-stm32/src/ltdc.rs @@ -14,7 +14,7 @@ use stm32_metapac::ltdc::vals::{Bf1, Bf2, Cfuif, Clif, Crrif, Cterrif, Pf, Vbr}; use crate::gpio::{AfType, OutputType, Speed}; use crate::interrupt::typelevel::Interrupt; use crate::interrupt::{self}; -use crate::{peripherals, rcc, Peri}; +use crate::{Peri, peripherals, rcc}; static LTDC_WAKER: AtomicWaker = AtomicWaker::new(); diff --git a/embassy-stm32/src/opamp.rs b/embassy-stm32/src/opamp.rs index e36719ef3..ac8d5de21 100644 --- a/embassy-stm32/src/opamp.rs +++ b/embassy-stm32/src/opamp.rs @@ -3,10 +3,10 @@ use embassy_hal_internal::PeripheralType; +use crate::Peri; use crate::pac::opamp::vals::*; #[cfg(not(any(stm32g4, stm32f3)))] use crate::rcc::RccInfo; -use crate::Peri; /// Performs a busy-wait delay for a specified number of microseconds. #[cfg(opamp_v5)] diff --git a/embassy-stm32/src/ospi/mod.rs b/embassy-stm32/src/ospi/mod.rs index d93cecb69..592a8594a 100644 --- a/embassy-stm32/src/ospi/mod.rs +++ b/embassy-stm32/src/ospi/mod.rs @@ -12,14 +12,14 @@ use embassy_hal_internal::PeripheralType; pub use enums::*; use stm32_metapac::octospi::vals::{PhaseMode, SizeInBits}; -use crate::dma::{word, ChannelAndRequest}; +use crate::dma::{ChannelAndRequest, word}; use crate::gpio::{AfType, AnyPin, OutputType, Pull, SealedPin as _, Speed}; use crate::mode::{Async, Blocking, Mode as PeriMode}; -use crate::pac::octospi::{vals, Octospi as Regs}; +use crate::pac::octospi::{Octospi as Regs, vals}; #[cfg(octospim_v1)] use crate::pac::octospim::Octospim; use crate::rcc::{self, RccPeripheral}; -use crate::{peripherals, Peri}; +use crate::{Peri, peripherals}; /// OPSI driver config. #[derive(Clone, Copy)] diff --git a/embassy-stm32/src/qspi/mod.rs b/embassy-stm32/src/qspi/mod.rs index b03cd9009..bb4f4f1d0 100644 --- a/embassy-stm32/src/qspi/mod.rs +++ b/embassy-stm32/src/qspi/mod.rs @@ -14,7 +14,7 @@ use crate::gpio::{AfType, AnyPin, OutputType, Pull, Speed}; use crate::mode::{Async, Blocking, Mode as PeriMode}; use crate::pac::quadspi::Quadspi as Regs; use crate::rcc::{self, RccPeripheral}; -use crate::{peripherals, Peri}; +use crate::{Peri, peripherals}; /// QSPI transfer configuration. #[derive(Clone, Copy)] diff --git a/embassy-stm32/src/rcc/bd.rs b/embassy-stm32/src/rcc/bd.rs index 63fc195dd..3b2a10581 100644 --- a/embassy-stm32/src/rcc/bd.rs +++ b/embassy-stm32/src/rcc/bd.rs @@ -1,6 +1,6 @@ -use core::sync::atomic::{compiler_fence, Ordering}; +use core::sync::atomic::{Ordering, compiler_fence}; -use crate::pac::common::{Reg, RW}; +use crate::pac::common::{RW, Reg}; pub use crate::pac::rcc::vals::Rtcsel as RtcClockSource; use crate::time::Hertz; diff --git a/embassy-stm32/src/rcc/f247.rs b/embassy-stm32/src/rcc/f247.rs index 8f2e8db5f..d941054cd 100644 --- a/embassy-stm32/src/rcc/f247.rs +++ b/embassy-stm32/src/rcc/f247.rs @@ -1,13 +1,13 @@ use stm32_metapac::flash::vals::Latency; +#[cfg(any(stm32f4, stm32f7))] +use crate::pac::PWR; #[cfg(any(stm32f413, stm32f423, stm32f412))] pub use crate::pac::rcc::vals::Plli2ssrc as Plli2sSource; pub use crate::pac::rcc::vals::{ Hpre as AHBPrescaler, Pllm as PllPreDiv, Plln as PllMul, Pllp as PllPDiv, Pllq as PllQDiv, Pllr as PllRDiv, Pllsrc as PllSource, Ppre as APBPrescaler, Sw as Sysclk, }; -#[cfg(any(stm32f4, stm32f7))] -use crate::pac::PWR; use crate::pac::{FLASH, RCC}; use crate::time::Hertz; diff --git a/embassy-stm32/src/rcc/h.rs b/embassy-stm32/src/rcc/h.rs index 331bab7a0..485edd390 100644 --- a/embassy-stm32/src/rcc/h.rs +++ b/embassy-stm32/src/rcc/h.rs @@ -597,7 +597,10 @@ pub(crate) unsafe fn init(config: Config) { Hertz(24_000_000) => Usbrefcksel::MHZ24, Hertz(26_000_000) => Usbrefcksel::MHZ26, Hertz(32_000_000) => Usbrefcksel::MHZ32, - _ => panic!("cannot select USBPHYC reference clock with source frequency of {}, must be one of 16, 19.2, 20, 24, 26, 32 MHz", clk_val), + _ => panic!( + "cannot select USBPHYC reference clock with source frequency of {}, must be one of 16, 19.2, 20, 24, 26, 32 MHz", + clk_val + ), }, None => Usbrefcksel::MHZ24, }; diff --git a/embassy-stm32/src/rcc/l.rs b/embassy-stm32/src/rcc/l.rs index 81b89046e..2e1cbd702 100644 --- a/embassy-stm32/src/rcc/l.rs +++ b/embassy-stm32/src/rcc/l.rs @@ -499,9 +499,9 @@ pub use pll::*; #[cfg(any(stm32l0, stm32l1))] mod pll { - use super::{pll_enable, PllInstance}; - pub use crate::pac::rcc::vals::{Plldiv as PllDiv, Pllmul as PllMul, Pllsrc as PllSource}; + use super::{PllInstance, pll_enable}; use crate::pac::RCC; + pub use crate::pac::rcc::vals::{Plldiv as PllDiv, Pllmul as PllMul, Pllsrc as PllSource}; use crate::time::Hertz; #[derive(Clone, Copy)] @@ -563,11 +563,11 @@ mod pll { #[cfg(any(stm32l4, stm32l5, stm32wb, stm32wl, stm32u0))] mod pll { - use super::{pll_enable, PllInstance}; + use super::{PllInstance, pll_enable}; + use crate::pac::RCC; pub use crate::pac::rcc::vals::{ Pllm as PllPreDiv, Plln as PllMul, Pllp as PllPDiv, Pllq as PllQDiv, Pllr as PllRDiv, Pllsrc as PllSource, }; - use crate::pac::RCC; use crate::time::Hertz; #[derive(Clone, Copy)] diff --git a/embassy-stm32/src/rcc/mco.rs b/embassy-stm32/src/rcc/mco.rs index fa4b45a20..3d961df03 100644 --- a/embassy-stm32/src/rcc/mco.rs +++ b/embassy-stm32/src/rcc/mco.rs @@ -3,6 +3,7 @@ use core::marker::PhantomData; use embassy_hal_internal::PeripheralType; use crate::gpio::{AfType, OutputType, Speed}; +use crate::pac::RCC; #[cfg(not(any(stm32f1, rcc_f0v1, rcc_f3v1, rcc_f37)))] pub use crate::pac::rcc::vals::Mcopre as McoPrescaler; #[cfg(not(any( @@ -31,8 +32,7 @@ pub use crate::pac::rcc::vals::Mcosel as McoSource; rcc_h7rs ))] pub use crate::pac::rcc::vals::{Mco1sel as Mco1Source, Mco2sel as Mco2Source}; -use crate::pac::RCC; -use crate::{peripherals, Peri}; +use crate::{Peri, peripherals}; #[cfg(any(stm32f1, rcc_f0v1, rcc_f3v1, rcc_f37))] #[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd)] diff --git a/embassy-stm32/src/rcc/mod.rs b/embassy-stm32/src/rcc/mod.rs index c41f81816..addfca3c3 100644 --- a/embassy-stm32/src/rcc/mod.rs +++ b/embassy-stm32/src/rcc/mod.rs @@ -33,7 +33,7 @@ mod _version; pub use _version::*; use stm32_metapac::RCC; -pub use crate::_generated::{mux, Clocks}; +pub use crate::_generated::{Clocks, mux}; use crate::time::Hertz; #[cfg(feature = "low-power")] diff --git a/embassy-stm32/src/rcc/u5.rs b/embassy-stm32/src/rcc/u5.rs index 06895a99a..7b0dcb63f 100644 --- a/embassy-stm32/src/rcc/u5.rs +++ b/embassy-stm32/src/rcc/u5.rs @@ -6,9 +6,9 @@ pub use crate::pac::rcc::vals::{ Pllsrc as PllSource, Ppre as APBPrescaler, Sw as Sysclk, }; use crate::pac::rcc::vals::{Hseext, Msipllfast, Msipllsel, Msirgsel, Pllmboost, Pllrge}; -#[cfg(all(peri_usb_otg_hs))] -pub use crate::pac::{syscfg::vals::Usbrefcksel, SYSCFG}; use crate::pac::{FLASH, PWR, RCC}; +#[cfg(all(peri_usb_otg_hs))] +pub use crate::pac::{SYSCFG, syscfg::vals::Usbrefcksel}; use crate::rcc::LSI_FREQ; use crate::time::Hertz; @@ -442,7 +442,10 @@ pub(crate) unsafe fn init(config: Config) { Hertz(24_000_000) => Usbrefcksel::MHZ24, Hertz(26_000_000) => Usbrefcksel::MHZ26, Hertz(32_000_000) => Usbrefcksel::MHZ32, - _ => panic!("cannot select OTG_HS reference clock with source frequency of {}, must be one of 16, 19.2, 20, 24, 26, 32 MHz", clk_val), + _ => panic!( + "cannot select OTG_HS reference clock with source frequency of {}, must be one of 16, 19.2, 20, 24, 26, 32 MHz", + clk_val + ), }, None => Usbrefcksel::MHZ24, }; diff --git a/embassy-stm32/src/rcc/wba.rs b/embassy-stm32/src/rcc/wba.rs index 481437939..2528996d5 100644 --- a/embassy-stm32/src/rcc/wba.rs +++ b/embassy-stm32/src/rcc/wba.rs @@ -7,9 +7,9 @@ pub use crate::pac::rcc::vals::{ Hdiv5, Hpre as AHBPrescaler, Hpre5 as AHB5Prescaler, Hsepre as HsePrescaler, Plldiv as PllDiv, Pllm as PllPreDiv, Plln as PllMul, Pllsrc as PllSource, Ppre as APBPrescaler, Sai1sel, Sw as Sysclk, }; -#[cfg(all(peri_usb_otg_hs))] -pub use crate::pac::{syscfg::vals::Usbrefcksel, SYSCFG}; use crate::pac::{FLASH, RCC}; +#[cfg(all(peri_usb_otg_hs))] +pub use crate::pac::{SYSCFG, syscfg::vals::Usbrefcksel}; use crate::rcc::LSI_FREQ; use crate::time::Hertz; @@ -245,7 +245,10 @@ pub(crate) unsafe fn init(config: Config) { Hertz(24_000_000) => Usbrefcksel::MHZ24, Hertz(26_000_000) => Usbrefcksel::MHZ26, Hertz(32_000_000) => Usbrefcksel::MHZ32, - _ => panic!("cannot select OTG_HS reference clock with source frequency of {}, must be one of 16, 19.2, 20, 24, 26, 32 MHz", clk_val), + _ => panic!( + "cannot select OTG_HS reference clock with source frequency of {}, must be one of 16, 19.2, 20, 24, 26, 32 MHz", + clk_val + ), }, None => Usbrefcksel::MHZ24, }; diff --git a/embassy-stm32/src/rng.rs b/embassy-stm32/src/rng.rs index 63654639e..dada9bda1 100644 --- a/embassy-stm32/src/rng.rs +++ b/embassy-stm32/src/rng.rs @@ -9,7 +9,7 @@ use embassy_hal_internal::PeripheralType; use embassy_sync::waitqueue::AtomicWaker; use crate::interrupt::typelevel::Interrupt; -use crate::{interrupt, pac, peripherals, rcc, Peri}; +use crate::{Peri, interrupt, pac, peripherals, rcc}; static RNG_WAKER: AtomicWaker = AtomicWaker::new(); diff --git a/embassy-stm32/src/rtc/low_power.rs b/embassy-stm32/src/rtc/low_power.rs index a81ac6746..999f24714 100644 --- a/embassy-stm32/src/rtc/low_power.rs +++ b/embassy-stm32/src/rtc/low_power.rs @@ -1,7 +1,7 @@ #[cfg(feature = "time")] use embassy_time::{Duration, TICK_HZ}; -use super::{bcd2_to_byte, DateTimeError, Rtc, RtcError}; +use super::{DateTimeError, Rtc, RtcError, bcd2_to_byte}; use crate::interrupt::typelevel::Interrupt; use crate::peripherals::RTC; use crate::rtc::SealedInstance; diff --git a/embassy-stm32/src/rtc/mod.rs b/embassy-stm32/src/rtc/mod.rs index 92dec0960..bc6df528b 100644 --- a/embassy-stm32/src/rtc/mod.rs +++ b/embassy-stm32/src/rtc/mod.rs @@ -7,13 +7,13 @@ mod low_power; #[cfg(feature = "low-power")] use core::cell::Cell; -#[cfg(feature = "low-power")] -use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex; #[cfg(feature = "low-power")] use embassy_sync::blocking_mutex::Mutex; +#[cfg(feature = "low-power")] +use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex; -use self::datetime::{day_of_week_from_u8, day_of_week_to_u8}; pub use self::datetime::{DateTime, DayOfWeek, Error as DateTimeError}; +use self::datetime::{day_of_week_from_u8, day_of_week_to_u8}; use crate::pac::rtc::regs::{Dr, Tr}; use crate::time::Hertz; @@ -25,8 +25,8 @@ mod _version; #[allow(unused_imports)] pub use _version::*; -use crate::peripherals::RTC; use crate::Peri; +use crate::peripherals::RTC; /// Errors that can occur on methods on [RtcClock] #[non_exhaustive] diff --git a/embassy-stm32/src/rtc/v3.rs b/embassy-stm32/src/rtc/v3.rs index d0b52049e..01da5d70a 100644 --- a/embassy-stm32/src/rtc/v3.rs +++ b/embassy-stm32/src/rtc/v3.rs @@ -1,4 +1,4 @@ -use stm32_metapac::rtc::vals::{Calp, Calw16, Calw8, Fmt, Key, Osel, Pol, TampalrmType}; +use stm32_metapac::rtc::vals::{Calp, Calw8, Calw16, Fmt, Key, Osel, Pol, TampalrmType}; use super::RtcCalibrationCyclePeriod; use crate::pac::rtc::Rtc; diff --git a/embassy-stm32/src/sai/mod.rs b/embassy-stm32/src/sai/mod.rs index fb8b23b79..726d1729a 100644 --- a/embassy-stm32/src/sai/mod.rs +++ b/embassy-stm32/src/sai/mod.rs @@ -6,12 +6,12 @@ use core::marker::PhantomData; use embassy_hal_internal::PeripheralType; pub use crate::dma::word; -use crate::dma::{ringbuffer, Channel, ReadableRingBuffer, Request, TransferOptions, WritableRingBuffer}; +use crate::dma::{Channel, ReadableRingBuffer, Request, TransferOptions, WritableRingBuffer, ringbuffer}; use crate::gpio::{AfType, AnyPin, OutputType, Pull, SealedPin as _, Speed}; pub use crate::pac::sai::vals::Mckdiv as MasterClockDivider; -use crate::pac::sai::{vals, Sai as Regs}; +use crate::pac::sai::{Sai as Regs, vals}; use crate::rcc::{self, RccPeripheral}; -use crate::{peripherals, Peri}; +use crate::{Peri, peripherals}; /// SAI error #[derive(Debug, PartialEq, Eq, Clone, Copy)] diff --git a/embassy-stm32/src/sdmmc/mod.rs b/embassy-stm32/src/sdmmc/mod.rs index ccbd16cbf..408d1b764 100644 --- a/embassy-stm32/src/sdmmc/mod.rs +++ b/embassy-stm32/src/sdmmc/mod.rs @@ -11,9 +11,9 @@ use embassy_hal_internal::drop::OnDrop; use embassy_hal_internal::{Peri, PeripheralType}; use embassy_sync::waitqueue::AtomicWaker; use sdio_host::common_cmd::{self, Resp, ResponseLen}; -use sdio_host::emmc::{ExtCSD, EMMC}; -use sdio_host::sd::{BusWidth, CardCapacity, CardStatus, CurrentState, SDStatus, CIC, CID, CSD, OCR, RCA, SCR, SD}; -use sdio_host::{emmc_cmd, sd_cmd, Cmd}; +use sdio_host::emmc::{EMMC, ExtCSD}; +use sdio_host::sd::{BusWidth, CIC, CID, CSD, CardCapacity, CardStatus, CurrentState, OCR, RCA, SCR, SD, SDStatus}; +use sdio_host::{Cmd, emmc_cmd, sd_cmd}; #[cfg(sdmmc_v1)] use crate::dma::ChannelAndRequest; diff --git a/embassy-stm32/src/spdifrx/mod.rs b/embassy-stm32/src/spdifrx/mod.rs index b0a32d5d1..6f2d24560 100644 --- a/embassy-stm32/src/spdifrx/mod.rs +++ b/embassy-stm32/src/spdifrx/mod.rs @@ -13,7 +13,7 @@ use crate::gpio::{AfType, AnyPin, Pull, SealedPin as _}; use crate::interrupt::typelevel::Interrupt; use crate::pac::spdifrx::Spdifrx as Regs; use crate::rcc::{RccInfo, SealedRccPeripheral}; -use crate::{interrupt, peripherals, Peri}; +use crate::{Peri, interrupt, peripherals}; /// Possible S/PDIF preamble types. #[allow(dead_code)] diff --git a/embassy-stm32/src/spi/mod.rs b/embassy-stm32/src/spi/mod.rs index c5373a54d..c27d09ea7 100644 --- a/embassy-stm32/src/spi/mod.rs +++ b/embassy-stm32/src/spi/mod.rs @@ -6,15 +6,15 @@ use core::ptr; use embassy_embedded_hal::SetConfig; use embassy_futures::join::join; -pub use embedded_hal_02::spi::{Mode, Phase, Polarity, MODE_0, MODE_1, MODE_2, MODE_3}; +pub use embedded_hal_02::spi::{MODE_0, MODE_1, MODE_2, MODE_3, Mode, Phase, Polarity}; -use crate::dma::{word, ChannelAndRequest}; +use crate::Peri; +use crate::dma::{ChannelAndRequest, word}; use crate::gpio::{AfType, AnyPin, OutputType, Pull, SealedPin as _, Speed}; use crate::mode::{Async, Blocking, Mode as PeriMode}; -use crate::pac::spi::{regs, vals, Spi as Regs}; +use crate::pac::spi::{Spi as Regs, regs, vals}; use crate::rcc::{RccInfo, SealedRccPeripheral}; use crate::time::Hertz; -use crate::Peri; /// SPI error. #[derive(Debug, PartialEq, Eq, Clone, Copy)] diff --git a/embassy-stm32/src/time_driver.rs b/embassy-stm32/src/time_driver.rs index 7db74bdf6..74b10a183 100644 --- a/embassy-stm32/src/time_driver.rs +++ b/embassy-stm32/src/time_driver.rs @@ -1,14 +1,14 @@ #![allow(non_snake_case)] use core::cell::{Cell, RefCell}; -use core::sync::atomic::{compiler_fence, AtomicU32, Ordering}; +use core::sync::atomic::{AtomicU32, Ordering, compiler_fence}; use critical_section::CriticalSection; -use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex; use embassy_sync::blocking_mutex::Mutex; +use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex; use embassy_time_driver::{Driver, TICK_HZ}; use embassy_time_queue_utils::Queue; -use stm32_metapac::timer::{regs, TimGp16}; +use stm32_metapac::timer::{TimGp16, regs}; use crate::interrupt::typelevel::Interrupt; use crate::pac::timer::vals; diff --git a/embassy-stm32/src/timer/complementary_pwm.rs b/embassy-stm32/src/timer/complementary_pwm.rs index 484aae1d0..75a83629c 100644 --- a/embassy-stm32/src/timer/complementary_pwm.rs +++ b/embassy-stm32/src/timer/complementary_pwm.rs @@ -7,11 +7,11 @@ pub use stm32_metapac::timer::vals::{Ckd, Ossi, Ossr}; use super::low_level::{CountingMode, OutputPolarity, Timer}; use super::simple_pwm::PwmPin; use super::{AdvancedInstance4Channel, Ch1, Ch2, Ch3, Ch4, Channel, TimerComplementaryPin}; +use crate::Peri; use crate::gpio::{AnyPin, OutputType}; use crate::time::Hertz; -use crate::timer::low_level::OutputCompareMode; use crate::timer::TimerChannel; -use crate::Peri; +use crate::timer::low_level::OutputCompareMode; /// Complementary PWM pin wrapper. /// @@ -388,7 +388,7 @@ fn compute_dead_time_value(value: u16) -> (Ckd, u8) { #[cfg(test)] mod tests { - use super::{compute_dead_time_value, Ckd}; + use super::{Ckd, compute_dead_time_value}; #[test] fn test_compute_dead_time_value() { diff --git a/embassy-stm32/src/timer/input_capture.rs b/embassy-stm32/src/timer/input_capture.rs index 7a25e6c21..2a4ec2db0 100644 --- a/embassy-stm32/src/timer/input_capture.rs +++ b/embassy-stm32/src/timer/input_capture.rs @@ -8,11 +8,11 @@ use core::task::{Context, Poll}; use super::low_level::{CountingMode, FilterValue, InputCaptureMode, InputTISelection, Timer}; use super::{CaptureCompareInterruptHandler, Channel, GeneralInstance4Channel, TimerPin}; pub use super::{Ch1, Ch2, Ch3, Ch4}; +use crate::Peri; use crate::gpio::{AfType, AnyPin, Pull}; use crate::interrupt::typelevel::{Binding, Interrupt}; use crate::time::Hertz; use crate::timer::TimerChannel; -use crate::Peri; /// Capture pin wrapper. /// diff --git a/embassy-stm32/src/timer/one_pulse.rs b/embassy-stm32/src/timer/one_pulse.rs index a75b41bd7..fe8681356 100644 --- a/embassy-stm32/src/timer/one_pulse.rs +++ b/embassy-stm32/src/timer/one_pulse.rs @@ -11,12 +11,12 @@ use super::low_level::{ }; use super::{CaptureCompareInterruptHandler, Channel, ExternalTriggerPin, GeneralInstance4Channel, TimerPin}; pub use super::{Ch1, Ch2}; +use crate::Peri; use crate::gpio::{AfType, AnyPin, Pull}; use crate::interrupt::typelevel::{Binding, Interrupt}; use crate::pac::timer::vals::Etp; use crate::time::Hertz; use crate::timer::TimerChannel; -use crate::Peri; /// External input marker type. pub enum Ext {} diff --git a/embassy-stm32/src/timer/pwm_input.rs b/embassy-stm32/src/timer/pwm_input.rs index 159b5a177..da8a79b09 100644 --- a/embassy-stm32/src/timer/pwm_input.rs +++ b/embassy-stm32/src/timer/pwm_input.rs @@ -2,9 +2,9 @@ use super::low_level::{CountingMode, InputCaptureMode, InputTISelection, SlaveMode, Timer, TriggerSource}; use super::{Ch1, Ch2, Channel, GeneralInstance4Channel, TimerPin}; +use crate::Peri; use crate::gpio::{AfType, Pull}; use crate::time::Hertz; -use crate::Peri; /// PWM Input driver. /// diff --git a/embassy-stm32/src/timer/qei.rs b/embassy-stm32/src/timer/qei.rs index bb152731c..a547a2a19 100644 --- a/embassy-stm32/src/timer/qei.rs +++ b/embassy-stm32/src/timer/qei.rs @@ -5,9 +5,9 @@ use stm32_metapac::timer::vals::{self, Sms}; use super::low_level::Timer; pub use super::{Ch1, Ch2}; use super::{GeneralInstance4Channel, TimerPin}; +use crate::Peri; use crate::gpio::{AfType, AnyPin, Pull}; use crate::timer::TimerChannel; -use crate::Peri; /// Qei driver config. #[cfg_attr(feature = "defmt", derive(defmt::Format))] diff --git a/embassy-stm32/src/timer/simple_pwm.rs b/embassy-stm32/src/timer/simple_pwm.rs index e6165e42b..06315d7f3 100644 --- a/embassy-stm32/src/timer/simple_pwm.rs +++ b/embassy-stm32/src/timer/simple_pwm.rs @@ -5,11 +5,11 @@ use core::mem::ManuallyDrop; use super::low_level::{CountingMode, OutputCompareMode, OutputPolarity, Timer}; use super::{Ch1, Ch2, Ch3, Ch4, Channel, GeneralInstance4Channel, TimerBits, TimerChannel, TimerPin}; +use crate::Peri; #[cfg(gpio_v2)] use crate::gpio::Pull; use crate::gpio::{AfType, AnyPin, OutputType, Speed}; use crate::time::Hertz; -use crate::Peri; /// PWM pin wrapper. /// diff --git a/embassy-stm32/src/tsc/acquisition_banks.rs b/embassy-stm32/src/tsc/acquisition_banks.rs index 7d6442b48..097cf7942 100644 --- a/embassy-stm32/src/tsc/acquisition_banks.rs +++ b/embassy-stm32/src/tsc/acquisition_banks.rs @@ -1,11 +1,11 @@ +use super::TSC_NUM_GROUPS; use super::io_pin::*; #[cfg(any(tsc_v2, tsc_v3))] use super::pin_groups::G7; #[cfg(tsc_v3)] use super::pin_groups::G8; -use super::pin_groups::{pin_roles, G1, G2, G3, G4, G5, G6}; +use super::pin_groups::{G1, G2, G3, G4, G5, G6, pin_roles}; use super::types::{Group, GroupStatus}; -use super::TSC_NUM_GROUPS; /// Represents a collection of TSC (Touch Sensing Controller) pins for an acquisition bank. /// diff --git a/embassy-stm32/src/tsc/pin_groups.rs b/embassy-stm32/src/tsc/pin_groups.rs index 84421f7ff..9347e6bc0 100644 --- a/embassy-stm32/src/tsc/pin_groups.rs +++ b/embassy-stm32/src/tsc/pin_groups.rs @@ -1,11 +1,11 @@ use core::marker::PhantomData; use core::ops::BitOr; +use super::Instance; use super::errors::GroupError; use super::io_pin::*; -use super::Instance; -use crate::gpio::{AfType, AnyPin, OutputType, Speed}; use crate::Peri; +use crate::gpio::{AfType, AnyPin, OutputType, Speed}; /// Pin type definition to control IO parameters #[derive(PartialEq, Clone, Copy)] diff --git a/embassy-stm32/src/ucpd.rs b/embassy-stm32/src/ucpd.rs index 18aff4fbd..8f259a917 100644 --- a/embassy-stm32/src/ucpd.rs +++ b/embassy-stm32/src/ucpd.rs @@ -19,8 +19,8 @@ use core::marker::PhantomData; use core::sync::atomic::{AtomicBool, Ordering}; use core::task::Poll; -use embassy_hal_internal::drop::OnDrop; use embassy_hal_internal::PeripheralType; +use embassy_hal_internal::drop::OnDrop; use embassy_sync::waitqueue::AtomicWaker; use crate::dma::{ChannelAndRequest, TransferOptions}; @@ -28,7 +28,7 @@ use crate::interrupt::typelevel::Interrupt; use crate::pac::ucpd::vals::{Anamode, Ccenable, PscUsbpdclk, Txmode}; pub use crate::pac::ucpd::vals::{Phyccsel as CcSel, Rxordset, TypecVstateCc as CcVState}; use crate::rcc::{self, RccPeripheral}; -use crate::{interrupt, Peri}; +use crate::{Peri, interrupt}; pub(crate) fn init( _cs: critical_section::CriticalSection, diff --git a/embassy-stm32/src/usart/buffered.rs b/embassy-stm32/src/usart/buffered.rs index 10dc02334..69c3a740f 100644 --- a/embassy-stm32/src/usart/buffered.rs +++ b/embassy-stm32/src/usart/buffered.rs @@ -5,16 +5,16 @@ use core::sync::atomic::{AtomicBool, AtomicU8, AtomicUsize, Ordering}; use core::task::Poll; use embassy_embedded_hal::SetConfig; -use embassy_hal_internal::atomic_ring_buffer::RingBuffer; use embassy_hal_internal::Peri; +use embassy_hal_internal::atomic_ring_buffer::RingBuffer; use embassy_sync::waitqueue::AtomicWaker; #[cfg(not(any(usart_v1, usart_v2)))] use super::DePin; use super::{ + Config, ConfigError, CtsPin, Duplex, Error, HalfDuplexReadback, Info, Instance, Regs, RtsPin, RxPin, TxPin, clear_interrupt_flags, configure, half_duplex_set_rx_tx_before_write, rdr, reconfigure, send_break, set_baudrate, - sr, tdr, Config, ConfigError, CtsPin, Duplex, Error, HalfDuplexReadback, Info, Instance, Regs, RtsPin, RxPin, - TxPin, + sr, tdr, }; use crate::gpio::{AfType, AnyPin, Pull, SealedPin as _}; use crate::interrupt::{self, InterruptExt}; diff --git a/embassy-stm32/src/usart/mod.rs b/embassy-stm32/src/usart/mod.rs index 0d2d86aca..0e7da634d 100644 --- a/embassy-stm32/src/usart/mod.rs +++ b/embassy-stm32/src/usart/mod.rs @@ -4,15 +4,16 @@ use core::future::poll_fn; use core::marker::PhantomData; -use core::sync::atomic::{compiler_fence, AtomicU8, AtomicUsize, Ordering}; +use core::sync::atomic::{AtomicU8, AtomicUsize, Ordering, compiler_fence}; use core::task::Poll; use embassy_embedded_hal::SetConfig; -use embassy_hal_internal::drop::OnDrop; use embassy_hal_internal::PeripheralType; +use embassy_hal_internal::drop::OnDrop; use embassy_sync::waitqueue::AtomicWaker; -use futures_util::future::{select, Either}; +use futures_util::future::{Either, select}; +use crate::Peri; use crate::dma::ChannelAndRequest; use crate::gpio::{AfType, AnyPin, OutputType, Pull, SealedPin as _, Speed}; use crate::interrupt::typelevel::Interrupt as _; @@ -25,7 +26,6 @@ use crate::pac::usart::Usart as Regs; use crate::pac::usart::{regs, vals}; use crate::rcc::{RccInfo, SealedRccPeripheral}; use crate::time::Hertz; -use crate::Peri; /// Interrupt handler. pub struct InterruptHandler { diff --git a/embassy-stm32/src/usart/ringbuffered.rs b/embassy-stm32/src/usart/ringbuffered.rs index 27071fb31..20bfefd9e 100644 --- a/embassy-stm32/src/usart/ringbuffered.rs +++ b/embassy-stm32/src/usart/ringbuffered.rs @@ -1,19 +1,19 @@ use core::future::poll_fn; use core::mem; -use core::sync::atomic::{compiler_fence, Ordering}; +use core::sync::atomic::{Ordering, compiler_fence}; use core::task::Poll; use embassy_embedded_hal::SetConfig; use embedded_io_async::ReadReady; -use futures_util::future::{select, Either}; +use futures_util::future::{Either, select}; -use super::{rdr, reconfigure, set_baudrate, sr, Config, ConfigError, Error, Info, State, UartRx}; +use super::{Config, ConfigError, Error, Info, State, UartRx, rdr, reconfigure, set_baudrate, sr}; +use crate::Peri; use crate::dma::ReadableRingBuffer; use crate::gpio::{AnyPin, SealedPin as _}; use crate::mode::Async; use crate::time::Hertz; use crate::usart::Regs; -use crate::Peri; /// Rx-only Ring-buffered UART Driver /// diff --git a/embassy-stm32/src/usb/otg.rs b/embassy-stm32/src/usb/otg.rs index 5ce81b131..f6b1a81db 100644 --- a/embassy-stm32/src/usb/otg.rs +++ b/embassy-stm32/src/usb/otg.rs @@ -2,18 +2,18 @@ use core::marker::PhantomData; use embassy_hal_internal::PeripheralType; use embassy_usb_driver::{EndpointAddress, EndpointAllocError, EndpointType, Event, Unsupported}; -use embassy_usb_synopsys_otg::otg_v1::vals::Dspd; -use embassy_usb_synopsys_otg::otg_v1::Otg; pub use embassy_usb_synopsys_otg::Config; +use embassy_usb_synopsys_otg::otg_v1::Otg; +use embassy_usb_synopsys_otg::otg_v1::vals::Dspd; use embassy_usb_synopsys_otg::{ - on_interrupt as on_interrupt_impl, Bus as OtgBus, ControlPipe, Driver as OtgDriver, Endpoint, In, OtgInstance, Out, - PhyType, State, + Bus as OtgBus, ControlPipe, Driver as OtgDriver, Endpoint, In, OtgInstance, Out, PhyType, State, + on_interrupt as on_interrupt_impl, }; use crate::gpio::{AfType, OutputType, Speed}; use crate::interrupt::typelevel::Interrupt; use crate::rcc::{self, RccPeripheral}; -use crate::{interrupt, Peri}; +use crate::{Peri, interrupt}; const MAX_EP_COUNT: usize = 9; diff --git a/embassy-stm32/src/usb/usb.rs b/embassy-stm32/src/usb/usb.rs index 9e08d99b3..d405e4802 100644 --- a/embassy-stm32/src/usb/usb.rs +++ b/embassy-stm32/src/usb/usb.rs @@ -12,11 +12,11 @@ use embassy_usb_driver::{ Direction, EndpointAddress, EndpointAllocError, EndpointError, EndpointInfo, EndpointType, Event, Unsupported, }; +use crate::pac::USBRAM; use crate::pac::usb::regs; use crate::pac::usb::vals::{EpType, Stat}; -use crate::pac::USBRAM; use crate::rcc::RccPeripheral; -use crate::{interrupt, Peri}; +use crate::{Peri, interrupt}; /// Interrupt handler. pub struct InterruptHandler { diff --git a/embassy-stm32/src/vrefbuf/mod.rs b/embassy-stm32/src/vrefbuf/mod.rs index ccbd748d5..b061306a0 100644 --- a/embassy-stm32/src/vrefbuf/mod.rs +++ b/embassy-stm32/src/vrefbuf/mod.rs @@ -62,8 +62,7 @@ impl<'d, T: Instance> VoltageReferenceBuffer<'d, T> { } trace!( "Vrefbuf configured with voltage scale {} and impedance mode {}", - voltage_scale as u8, - impedance_mode as u8, + voltage_scale as u8, impedance_mode as u8, ); VoltageReferenceBuffer { vrefbuf: PhantomData } } diff --git a/embassy-stm32/src/wdg/mod.rs b/embassy-stm32/src/wdg/mod.rs index fb5c3d930..1164739ff 100644 --- a/embassy-stm32/src/wdg/mod.rs +++ b/embassy-stm32/src/wdg/mod.rs @@ -4,8 +4,8 @@ use core::marker::PhantomData; use embassy_hal_internal::PeripheralType; use stm32_metapac::iwdg::vals::{Key, Pr}; -use crate::rcc::LSI_FREQ; use crate::Peri; +use crate::rcc::LSI_FREQ; /// Independent watchdog (IWDG) driver. pub struct IndependentWatchdog<'d, T: Instance> { diff --git a/embassy-stm32/src/xspi/mod.rs b/embassy-stm32/src/xspi/mod.rs index 901569f64..a80a2692b 100644 --- a/embassy-stm32/src/xspi/mod.rs +++ b/embassy-stm32/src/xspi/mod.rs @@ -11,15 +11,15 @@ use embassy_embedded_hal::{GetConfig, SetConfig}; use embassy_hal_internal::PeripheralType; pub use enums::*; -use crate::dma::{word, ChannelAndRequest}; +use crate::dma::{ChannelAndRequest, word}; use crate::gpio::{AfType, AnyPin, OutputType, Pull, SealedPin as _, Speed}; use crate::mode::{Async, Blocking, Mode as PeriMode}; -use crate::pac::xspi::vals::*; use crate::pac::xspi::Xspi as Regs; +use crate::pac::xspi::vals::*; #[cfg(xspim_v1)] use crate::pac::xspim::Xspim; use crate::rcc::{self, RccPeripheral}; -use crate::{peripherals, Peri}; +use crate::{Peri, peripherals}; /// XPSI driver config. #[derive(Clone, Copy)] diff --git a/embassy-sync/src/channel.rs b/embassy-sync/src/channel.rs index de437cc52..dbd24a6c7 100644 --- a/embassy-sync/src/channel.rs +++ b/embassy-sync/src/channel.rs @@ -50,8 +50,8 @@ use core::task::{Context, Poll}; use heapless::Deque; -use crate::blocking_mutex::raw::RawMutex; use crate::blocking_mutex::Mutex; +use crate::blocking_mutex::raw::RawMutex; use crate::waitqueue::WakerRegistration; /// Send-only access to a [`Channel`]. @@ -1112,11 +1112,13 @@ mod tests { static CHANNEL: StaticCell> = StaticCell::new(); let c = &*CHANNEL.init(Channel::new()); let c2 = c; - assert!(executor - .spawn(async move { - assert!(c2.try_send(1).is_ok()); - }) - .is_ok()); + assert!( + executor + .spawn(async move { + assert!(c2.try_send(1).is_ok()); + }) + .is_ok() + ); assert_eq!(c.receive().await, 1); } @@ -1143,13 +1145,15 @@ mod tests { // However, I've used the debugger to observe that the send does indeed wait. Delay::new(Duration::from_millis(500)).await; assert_eq!(c.receive().await, 1); - assert!(executor - .spawn(async move { - loop { - c.receive().await; - } - }) - .is_ok()); + assert!( + executor + .spawn(async move { + loop { + c.receive().await; + } + }) + .is_ok() + ); send_task_1.unwrap().await; send_task_2.unwrap().await; } diff --git a/embassy-sync/src/mutex.rs b/embassy-sync/src/mutex.rs index aea682899..96b834f02 100644 --- a/embassy-sync/src/mutex.rs +++ b/embassy-sync/src/mutex.rs @@ -2,13 +2,13 @@ //! //! This module provides a mutex that can be used to synchronize data between asynchronous tasks. use core::cell::{RefCell, UnsafeCell}; -use core::future::{poll_fn, Future}; +use core::future::{Future, poll_fn}; use core::ops::{Deref, DerefMut}; use core::task::Poll; use core::{fmt, mem}; -use crate::blocking_mutex::raw::RawMutex; use crate::blocking_mutex::Mutex as BlockingMutex; +use crate::blocking_mutex::raw::RawMutex; use crate::waitqueue::WakerRegistration; /// Error returned by [`Mutex::try_lock`] diff --git a/embassy-sync/src/once_lock.rs b/embassy-sync/src/once_lock.rs index 73edfea9a..2af19ca20 100644 --- a/embassy-sync/src/once_lock.rs +++ b/embassy-sync/src/once_lock.rs @@ -2,7 +2,7 @@ use core::cell::Cell; use core::fmt::{Debug, Formatter}; -use core::future::{poll_fn, Future}; +use core::future::{Future, poll_fn}; use core::mem::MaybeUninit; use core::sync::atomic::{AtomicBool, Ordering}; use core::task::Poll; diff --git a/embassy-sync/src/pipe.rs b/embassy-sync/src/pipe.rs index 6d624979a..215a556d9 100644 --- a/embassy-sync/src/pipe.rs +++ b/embassy-sync/src/pipe.rs @@ -7,8 +7,8 @@ use core::ops::Range; use core::pin::Pin; use core::task::{Context, Poll}; -use crate::blocking_mutex::raw::RawMutex; use crate::blocking_mutex::Mutex; +use crate::blocking_mutex::raw::RawMutex; use crate::ring_buffer::RingBuffer; use crate::waitqueue::WakerRegistration; diff --git a/embassy-sync/src/priority_channel.rs b/embassy-sync/src/priority_channel.rs index 715a20e86..1af7d9221 100644 --- a/embassy-sync/src/priority_channel.rs +++ b/embassy-sync/src/priority_channel.rs @@ -8,11 +8,11 @@ use core::future::Future; use core::pin::Pin; use core::task::{Context, Poll}; -pub use heapless::binary_heap::{Kind, Max, Min}; use heapless::BinaryHeap; +pub use heapless::binary_heap::{Kind, Max, Min}; -use crate::blocking_mutex::raw::RawMutex; use crate::blocking_mutex::Mutex; +use crate::blocking_mutex::raw::RawMutex; use crate::channel::{DynamicChannel, DynamicReceiver, DynamicSender, TryReceiveError, TrySendError}; use crate::waitqueue::WakerRegistration; @@ -799,11 +799,13 @@ mod tests { static CHANNEL: StaticCell> = StaticCell::new(); let c = &*CHANNEL.init(PriorityChannel::new()); let c2 = c; - assert!(executor - .spawn(async move { - assert!(c2.try_send(1).is_ok()); - }) - .is_ok()); + assert!( + executor + .spawn(async move { + assert!(c2.try_send(1).is_ok()); + }) + .is_ok() + ); assert_eq!(c.receive().await, 1); } @@ -830,13 +832,15 @@ mod tests { // However, I've used the debugger to observe that the send does indeed wait. Delay::new(Duration::from_millis(500)).await; assert_eq!(c.receive().await, 1); - assert!(executor - .spawn(async move { - loop { - c.receive().await; - } - }) - .is_ok()); + assert!( + executor + .spawn(async move { + loop { + c.receive().await; + } + }) + .is_ok() + ); send_task_1.unwrap().await; send_task_2.unwrap().await; } diff --git a/embassy-sync/src/pubsub/mod.rs b/embassy-sync/src/pubsub/mod.rs index ad9402f5a..127a208f1 100644 --- a/embassy-sync/src/pubsub/mod.rs +++ b/embassy-sync/src/pubsub/mod.rs @@ -10,8 +10,8 @@ use heapless::Deque; use self::publisher::{ImmediatePub, Pub}; use self::subscriber::Sub; -use crate::blocking_mutex::raw::RawMutex; use crate::blocking_mutex::Mutex; +use crate::blocking_mutex::raw::RawMutex; use crate::waitqueue::MultiWakerRegistration; pub mod publisher; diff --git a/embassy-sync/src/ring_buffer.rs b/embassy-sync/src/ring_buffer.rs index f03b7dd8f..608447cd6 100644 --- a/embassy-sync/src/ring_buffer.rs +++ b/embassy-sync/src/ring_buffer.rs @@ -95,11 +95,7 @@ impl RingBuffer { fn wrap(&self, n: usize) -> usize { assert!(n <= N); - if n == N { - 0 - } else { - n - } + if n == N { 0 } else { n } } } diff --git a/embassy-sync/src/rwlock.rs b/embassy-sync/src/rwlock.rs index e43388c4d..918a6aa41 100644 --- a/embassy-sync/src/rwlock.rs +++ b/embassy-sync/src/rwlock.rs @@ -3,12 +3,12 @@ //! This module provides a read-write lock that can be used to synchronize data between asynchronous tasks. use core::cell::{RefCell, UnsafeCell}; use core::fmt; -use core::future::{poll_fn, Future}; +use core::future::{Future, poll_fn}; use core::ops::{Deref, DerefMut}; use core::task::Poll; -use crate::blocking_mutex::raw::RawMutex; use crate::blocking_mutex::Mutex as BlockingMutex; +use crate::blocking_mutex::raw::RawMutex; use crate::waitqueue::WakerRegistration; /// Error returned by [`RwLock::try_read`] and [`RwLock::try_write`] when the lock is already held. diff --git a/embassy-sync/src/semaphore.rs b/embassy-sync/src/semaphore.rs index 4e82b0fcd..8d2413931 100644 --- a/embassy-sync/src/semaphore.rs +++ b/embassy-sync/src/semaphore.rs @@ -1,13 +1,13 @@ //! A synchronization primitive for controlling access to a pool of resources. use core::cell::{Cell, RefCell}; use core::convert::Infallible; -use core::future::{poll_fn, Future}; +use core::future::{Future, poll_fn}; use core::task::{Poll, Waker}; use heapless::Deque; -use crate::blocking_mutex::raw::RawMutex; use crate::blocking_mutex::Mutex; +use crate::blocking_mutex::raw::RawMutex; use crate::waitqueue::WakerRegistration; /// An asynchronous semaphore. diff --git a/embassy-sync/src/signal.rs b/embassy-sync/src/signal.rs index 229b1fa99..cc02228cf 100644 --- a/embassy-sync/src/signal.rs +++ b/embassy-sync/src/signal.rs @@ -1,10 +1,10 @@ //! A synchronization primitive for passing the latest value to a task. use core::cell::Cell; -use core::future::{poll_fn, Future}; +use core::future::{Future, poll_fn}; use core::task::{Context, Poll, Waker}; -use crate::blocking_mutex::raw::RawMutex; use crate::blocking_mutex::Mutex; +use crate::blocking_mutex::raw::RawMutex; /// Single-slot signaling primitive for a _single_ consumer. /// diff --git a/embassy-sync/src/waitqueue/atomic_waker.rs b/embassy-sync/src/waitqueue/atomic_waker.rs index 5a9910e7f..d2bf890e5 100644 --- a/embassy-sync/src/waitqueue/atomic_waker.rs +++ b/embassy-sync/src/waitqueue/atomic_waker.rs @@ -1,8 +1,8 @@ use core::cell::Cell; use core::task::Waker; -use crate::blocking_mutex::raw::{CriticalSectionRawMutex, RawMutex}; use crate::blocking_mutex::Mutex; +use crate::blocking_mutex::raw::{CriticalSectionRawMutex, RawMutex}; /// Utility struct to register and wake a waker. /// If a waker is registered, registering another waker will replace the previous one without waking it. diff --git a/embassy-sync/src/watch.rs b/embassy-sync/src/watch.rs index 332ab5405..0f8a8d679 100644 --- a/embassy-sync/src/watch.rs +++ b/embassy-sync/src/watch.rs @@ -1,13 +1,13 @@ //! A synchronization primitive for passing the latest value to **multiple** receivers. use core::cell::RefCell; -use core::future::{poll_fn, Future}; +use core::future::{Future, poll_fn}; use core::marker::PhantomData; use core::ops::{Deref, DerefMut}; use core::task::{Context, Poll}; -use crate::blocking_mutex::raw::RawMutex; use crate::blocking_mutex::Mutex; +use crate::blocking_mutex::raw::RawMutex; use crate::waitqueue::MultiWakerRegistration; /// The `Watch` is a single-slot signaling primitive that allows _multiple_ (`N`) receivers to concurrently await diff --git a/embassy-sync/src/zerocopy_channel.rs b/embassy-sync/src/zerocopy_channel.rs index b3f7dbe8c..c572592b8 100644 --- a/embassy-sync/src/zerocopy_channel.rs +++ b/embassy-sync/src/zerocopy_channel.rs @@ -15,12 +15,12 @@ //! another message will result in an error being returned. use core::cell::RefCell; -use core::future::{poll_fn, Future}; +use core::future::{Future, poll_fn}; use core::marker::PhantomData; use core::task::{Context, Poll}; -use crate::blocking_mutex::raw::RawMutex; use crate::blocking_mutex::Mutex; +use crate::blocking_mutex::raw::RawMutex; use crate::waitqueue::WakerRegistration; /// A bounded zero-copy channel for communicating between asynchronous tasks @@ -296,11 +296,7 @@ struct State { impl State { fn increment(&self, i: usize) -> usize { - if i + 1 == self.capacity { - 0 - } else { - i + 1 - } + if i + 1 == self.capacity { 0 } else { i + 1 } } fn clear(&mut self) { diff --git a/embassy-time-queue-utils/src/queue_generic.rs b/embassy-time-queue-utils/src/queue_generic.rs index bff7a4735..88986953d 100644 --- a/embassy-time-queue-utils/src/queue_generic.rs +++ b/embassy-time-queue-utils/src/queue_generic.rs @@ -2,7 +2,7 @@ //! //! Time queue drivers may use this to simplify their implementation. -use core::cmp::{min, Ordering}; +use core::cmp::{Ordering, min}; use core::task::Waker; use heapless::Vec; diff --git a/embassy-time/src/duration.rs b/embassy-time/src/duration.rs index b3ea0468d..b2bfd6de9 100644 --- a/embassy-time/src/duration.rs +++ b/embassy-time/src/duration.rs @@ -175,13 +175,7 @@ impl Duration { /// NOTE: Giving this function a hz >= the TICK_HZ of your platform will clamp the Duration to 1 /// tick. Doing so will not deadlock, but will certainly not produce the desired output. pub const fn from_hz(hz: u64) -> Duration { - let ticks = { - if hz >= TICK_HZ { - 1 - } else { - (TICK_HZ + hz / 2) / hz - } - }; + let ticks = { if hz >= TICK_HZ { 1 } else { (TICK_HZ + hz / 2) / hz } }; Duration { ticks } } diff --git a/embassy-time/src/lib.rs b/embassy-time/src/lib.rs index 5a511a0bd..e375fe93e 100644 --- a/embassy-time/src/lib.rs +++ b/embassy-time/src/lib.rs @@ -28,18 +28,14 @@ mod driver_std; #[cfg(feature = "wasm")] mod driver_wasm; -pub use delay::{block_for, Delay}; +pub use delay::{Delay, block_for}; pub use duration::Duration; pub use embassy_time_driver::TICK_HZ; pub use instant::Instant; -pub use timer::{with_deadline, with_timeout, Ticker, TimeoutError, Timer, WithTimeout}; +pub use timer::{Ticker, TimeoutError, Timer, WithTimeout, with_deadline, with_timeout}; const fn gcd(a: u64, b: u64) -> u64 { - if b == 0 { - a - } else { - gcd(b, a % b) - } + if b == 0 { a } else { gcd(b, a % b) } } pub(crate) const GCD_1K: u64 = gcd(TICK_HZ, 1_000); diff --git a/embassy-time/src/timer.rs b/embassy-time/src/timer.rs index fcf79f58e..2f5967c63 100644 --- a/embassy-time/src/timer.rs +++ b/embassy-time/src/timer.rs @@ -1,9 +1,9 @@ -use core::future::{poll_fn, Future}; +use core::future::{Future, poll_fn}; use core::pin::Pin; use core::task::{Context, Poll}; -use futures_core::stream::FusedStream; use futures_core::Stream; +use futures_core::stream::FusedStream; use crate::{Duration, Instant}; diff --git a/embassy-usb-dfu/src/application.rs b/embassy-usb-dfu/src/application.rs index 78eb2c083..1ea1a74fe 100644 --- a/embassy-usb-dfu/src/application.rs +++ b/embassy-usb-dfu/src/application.rs @@ -6,11 +6,11 @@ use embassy_usb::driver::Driver; use embassy_usb::{Builder, FunctionBuilder, Handler}; use embedded_storage::nor_flash::NorFlash; +use crate::Reset; use crate::consts::{ - DfuAttributes, Request, State, Status, APPN_SPEC_SUBCLASS_DFU, DESC_DFU_FUNCTIONAL, DFU_PROTOCOL_RT, + APPN_SPEC_SUBCLASS_DFU, DESC_DFU_FUNCTIONAL, DFU_PROTOCOL_RT, DfuAttributes, Request, State, Status, USB_CLASS_APPN_SPEC, }; -use crate::Reset; /// Generic interface for a system that can signal to the bootloader that USB DFU mode is needed on the next boot. /// diff --git a/embassy-usb-dfu/src/dfu.rs b/embassy-usb-dfu/src/dfu.rs index 7c28d04cf..2ed4511ce 100644 --- a/embassy-usb-dfu/src/dfu.rs +++ b/embassy-usb-dfu/src/dfu.rs @@ -5,11 +5,11 @@ use embassy_usb::driver::Driver; use embassy_usb::{Builder, FunctionBuilder, Handler}; use embedded_storage::nor_flash::{NorFlash, NorFlashErrorKind}; +use crate::Reset; use crate::consts::{ - DfuAttributes, Request, State, Status, APPN_SPEC_SUBCLASS_DFU, DESC_DFU_FUNCTIONAL, DFU_PROTOCOL_DFU, + APPN_SPEC_SUBCLASS_DFU, DESC_DFU_FUNCTIONAL, DFU_PROTOCOL_DFU, DfuAttributes, Request, State, Status, USB_CLASS_APPN_SPEC, }; -use crate::Reset; /// Internal state for USB DFU pub struct Control<'d, DFU: NorFlash, STATE: NorFlash, RST: Reset, const BLOCK_SIZE: usize> { diff --git a/embassy-usb-synopsys-otg/src/lib.rs b/embassy-usb-synopsys-otg/src/lib.rs index b8750491d..d94209f45 100644 --- a/embassy-usb-synopsys-otg/src/lib.rs +++ b/embassy-usb-synopsys-otg/src/lib.rs @@ -23,7 +23,7 @@ use crate::fmt::Bytes; pub mod otg_v1; -use otg_v1::{regs, vals, Otg}; +use otg_v1::{Otg, regs, vals}; /// Handle interrupts. pub unsafe fn on_interrupt(r: Otg, state: &State, ep_count: usize) { @@ -680,9 +680,7 @@ impl<'d, const MAX_EP_COUNT: usize> Bus<'d, MAX_EP_COUNT> { if let Some(ep) = self.ep_in[i] { trace!( "configuring tx fifo ep={}, offset={}, size={}", - i, - fifo_top, - ep.fifo_size_words + i, fifo_top, ep.fifo_size_words ); let dieptxf = if i == 0 { regs.dieptxf0() } else { regs.dieptxf(i - 1) }; @@ -1159,9 +1157,7 @@ impl<'d> embassy_usb_driver::EndpointIn for Endpoint<'d, In> { let dtxfsts = self.regs.dtxfsts(index).read(); trace!( "write ep={:?}: diepctl {:08x} ftxfsts {:08x}", - self.info.addr, - diepctl.0, - dtxfsts.0 + self.info.addr, diepctl.0, dtxfsts.0 ); if !diepctl.usbaep() { trace!("write ep={:?} wait for prev: error disabled", self.info.addr); @@ -1376,11 +1372,7 @@ fn ep_irq_mask(eps: &[Option]) -> u16 { eps.iter().enumerate().fold( 0, |mask, (index, ep)| { - if ep.is_some() { - mask | (1 << index) - } else { - mask - } + if ep.is_some() { mask | (1 << index) } else { mask } }, ) } diff --git a/embassy-usb/src/builder.rs b/embassy-usb/src/builder.rs index 8d7abe46c..6fc2a5a22 100644 --- a/embassy-usb/src/builder.rs +++ b/embassy-usb/src/builder.rs @@ -5,7 +5,7 @@ use crate::descriptor::{BosWriter, DescriptorWriter, SynchronizationType, UsageT use crate::driver::{Driver, Endpoint, EndpointAddress, EndpointInfo, EndpointType}; use crate::msos::{DeviceLevelDescriptor, FunctionLevelDescriptor, MsOsDescriptorWriter}; use crate::types::{InterfaceNumber, StringIndex}; -use crate::{Handler, Interface, UsbDevice, MAX_INTERFACE_COUNT, STRING_INDEX_CUSTOM_START}; +use crate::{Handler, Interface, MAX_INTERFACE_COUNT, STRING_INDEX_CUSTOM_START, UsbDevice}; #[derive(Debug, Copy, Clone)] #[cfg_attr(feature = "defmt", derive(defmt::Format))] @@ -176,7 +176,9 @@ impl<'d, D: Driver<'d>> Builder<'d, D> { if config.composite_with_iads && (config.device_class != 0xEF || config.device_sub_class != 0x02 || config.device_protocol != 0x01) { - panic!("if composite_with_iads is set, you must set device_class = 0xEF, device_sub_class = 0x02, device_protocol = 0x01"); + panic!( + "if composite_with_iads is set, you must set device_class = 0xEF, device_sub_class = 0x02, device_protocol = 0x01" + ); } assert!( @@ -337,7 +339,8 @@ impl<'a, 'd, D: Driver<'d>> FunctionBuilder<'a, 'd, D> { num_alt_settings: 0, }; - assert!(self.builder.interfaces.push(iface).is_ok(), + assert!( + self.builder.interfaces.push(iface).is_ok(), "embassy-usb: interface list full. Increase the `max_interface_count` compile-time setting. Current value: {}", MAX_INTERFACE_COUNT ); diff --git a/embassy-usb/src/class/cdc_acm.rs b/embassy-usb/src/class/cdc_acm.rs index 0a1a5e64f..388e21fbd 100644 --- a/embassy-usb/src/class/cdc_acm.rs +++ b/embassy-usb/src/class/cdc_acm.rs @@ -1,7 +1,7 @@ //! CDC-ACM class implementation, aka Serial over USB. use core::cell::{Cell, RefCell}; -use core::future::{poll_fn, Future}; +use core::future::{Future, poll_fn}; use core::mem::{self, MaybeUninit}; use core::sync::atomic::{AtomicBool, Ordering}; use core::task::Poll; diff --git a/embassy-usb/src/class/cdc_ncm/embassy_net.rs b/embassy-usb/src/class/cdc_ncm/embassy_net.rs index 57d322946..c83ff468a 100644 --- a/embassy-usb/src/class/cdc_ncm/embassy_net.rs +++ b/embassy-usb/src/class/cdc_ncm/embassy_net.rs @@ -1,6 +1,6 @@ //! [`embassy-net`](https://crates.io/crates/embassy-net) driver for the CDC-NCM class. -use embassy_futures::select::{select, Either}; +use embassy_futures::select::{Either, select}; use embassy_net_driver_channel as ch; use embassy_net_driver_channel::driver::LinkState; use embassy_usb_driver::Driver; diff --git a/embassy-usb/src/class/cdc_ncm/mod.rs b/embassy-usb/src/class/cdc_ncm/mod.rs index 3af853091..9b6dd9f21 100644 --- a/embassy-usb/src/class/cdc_ncm/mod.rs +++ b/embassy-usb/src/class/cdc_ncm/mod.rs @@ -14,7 +14,7 @@ //! This is due to regex spaghetti: //! and this nonsense in the linux kernel: -use core::mem::{size_of, MaybeUninit}; +use core::mem::{MaybeUninit, size_of}; use core::ptr::{addr_of, copy_nonoverlapping}; use crate::control::{self, InResponse, OutResponse, Recipient, Request, RequestType}; diff --git a/embassy-usb/src/class/cmsis_dap_v2.rs b/embassy-usb/src/class/cmsis_dap_v2.rs index a9fd9cdf0..0e2356f17 100644 --- a/embassy-usb/src/class/cmsis_dap_v2.rs +++ b/embassy-usb/src/class/cmsis_dap_v2.rs @@ -4,7 +4,7 @@ use core::mem::MaybeUninit; use crate::driver::{Driver, Endpoint, EndpointError, EndpointIn, EndpointOut}; use crate::types::StringIndex; -use crate::{msos, Builder, Handler}; +use crate::{Builder, Handler, msos}; /// State for the CMSIS-DAP v2 USB class. pub struct State { diff --git a/embassy-usb/src/class/midi.rs b/embassy-usb/src/class/midi.rs index 1d152ca44..d29172be1 100644 --- a/embassy-usb/src/class/midi.rs +++ b/embassy-usb/src/class/midi.rs @@ -1,7 +1,7 @@ //! MIDI class implementation. -use crate::driver::{Driver, Endpoint, EndpointError, EndpointIn, EndpointOut}; use crate::Builder; +use crate::driver::{Driver, Endpoint, EndpointError, EndpointIn, EndpointOut}; /// This should be used as `device_class` when building the `UsbDevice`. pub const USB_AUDIO_CLASS: u8 = 0x01; diff --git a/embassy-usb/src/class/uac1/speaker.rs b/embassy-usb/src/class/uac1/speaker.rs index 9565e2a25..46e0420d5 100644 --- a/embassy-usb/src/class/uac1/speaker.rs +++ b/embassy-usb/src/class/uac1/speaker.rs @@ -11,7 +11,7 @@ //! The class provides volume and mute controls for each channel. use core::cell::{Cell, RefCell}; -use core::future::{poll_fn, Future}; +use core::future::{Future, poll_fn}; use core::marker::PhantomData; use core::sync::atomic::{AtomicBool, AtomicU32, Ordering}; use core::task::Poll; @@ -22,7 +22,7 @@ use heapless::Vec; use super::class_codes::*; use super::terminal_type::TerminalType; -use super::{Channel, ChannelConfig, FeedbackRefresh, SampleWidth, MAX_AUDIO_CHANNEL_COUNT, MAX_AUDIO_CHANNEL_INDEX}; +use super::{Channel, ChannelConfig, FeedbackRefresh, MAX_AUDIO_CHANNEL_COUNT, MAX_AUDIO_CHANNEL_INDEX, SampleWidth}; use crate::control::{self, InResponse, OutResponse, Recipient, Request, RequestType}; use crate::descriptor::{SynchronizationType, UsageType}; use crate::driver::{Driver, Endpoint, EndpointError, EndpointIn, EndpointOut, EndpointType}; diff --git a/embassy-usb/src/descriptor.rs b/embassy-usb/src/descriptor.rs index e9a6fd79a..c79dd02eb 100644 --- a/embassy-usb/src/descriptor.rs +++ b/embassy-usb/src/descriptor.rs @@ -1,10 +1,10 @@ //! Utilities for writing USB descriptors. use embassy_usb_driver::EndpointType; +use crate::CONFIGURATION_VALUE; use crate::builder::Config; use crate::driver::EndpointInfo; use crate::types::{InterfaceNumber, StringIndex}; -use crate::CONFIGURATION_VALUE; /// Standard descriptor types #[allow(missing_docs)] diff --git a/embassy-usb/src/lib.rs b/embassy-usb/src/lib.rs index 7f78de29d..0c10c08df 100644 --- a/embassy-usb/src/lib.rs +++ b/embassy-usb/src/lib.rs @@ -21,7 +21,7 @@ mod config { include!(concat!(env!("OUT_DIR"), "/config.rs")); } -use embassy_futures::select::{select, Either}; +use embassy_futures::select::{Either, select}; use heapless::Vec; pub use crate::builder::{Builder, Config, FunctionBuilder, InterfaceAltBuilder, InterfaceBuilder, UsbVersion}; diff --git a/embassy-usb/src/msos.rs b/embassy-usb/src/msos.rs index 9f4e1a57b..66689871e 100644 --- a/embassy-usb/src/msos.rs +++ b/embassy-usb/src/msos.rs @@ -4,7 +4,7 @@ use core::mem::size_of; -use crate::descriptor::{capability_type, BosWriter}; +use crate::descriptor::{BosWriter, capability_type}; use crate::types::InterfaceNumber; /// A serialized Microsoft OS 2.0 Descriptor set. diff --git a/examples/boot/application/stm32wb-dfu/src/main.rs b/examples/boot/application/stm32wb-dfu/src/main.rs index 5e7b71f5a..1ae28bf3a 100644 --- a/examples/boot/application/stm32wb-dfu/src/main.rs +++ b/examples/boot/application/stm32wb-dfu/src/main.rs @@ -13,9 +13,9 @@ 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::{msos, Builder}; +use embassy_usb::{Builder, msos}; use embassy_usb_dfu::consts::DfuAttributes; -use embassy_usb_dfu::{usb_dfu, Control, ResetImmediate}; +use embassy_usb_dfu::{Control, ResetImmediate, usb_dfu}; use panic_reset as _; bind_interrupts!(struct Irqs { diff --git a/examples/boot/application/stm32wba-dfu/src/main.rs b/examples/boot/application/stm32wba-dfu/src/main.rs index bf17a7150..8adb2e7c0 100644 --- a/examples/boot/application/stm32wba-dfu/src/main.rs +++ b/examples/boot/application/stm32wba-dfu/src/main.rs @@ -12,9 +12,9 @@ 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::{msos, Builder}; +use embassy_usb::{Builder, msos}; use embassy_usb_dfu::consts::DfuAttributes; -use embassy_usb_dfu::{usb_dfu, Control, ResetImmediate}; +use embassy_usb_dfu::{Control, ResetImmediate, usb_dfu}; use panic_reset as _; bind_interrupts!(struct Irqs { diff --git a/examples/boot/application/stm32wl/src/bin/a.rs b/examples/boot/application/stm32wl/src/bin/a.rs index e4526927f..3f381fd80 100644 --- a/examples/boot/application/stm32wl/src/bin/a.rs +++ b/examples/boot/application/stm32wl/src/bin/a.rs @@ -8,10 +8,10 @@ use defmt_rtt::*; use embassy_boot_stm32::{AlignedBuffer, FirmwareUpdater, FirmwareUpdaterConfig}; use embassy_embedded_hal::adapter::BlockingAsync; use embassy_executor::Spawner; +use embassy_stm32::SharedData; use embassy_stm32::exti::ExtiInput; use embassy_stm32::flash::{Flash, WRITE_SIZE}; use embassy_stm32::gpio::{Level, Output, Pull, Speed}; -use embassy_stm32::SharedData; use embassy_sync::mutex::Mutex; use panic_reset as _; diff --git a/examples/boot/application/stm32wl/src/bin/b.rs b/examples/boot/application/stm32wl/src/bin/b.rs index 6016a9555..952e94a58 100644 --- a/examples/boot/application/stm32wl/src/bin/b.rs +++ b/examples/boot/application/stm32wl/src/bin/b.rs @@ -6,8 +6,8 @@ use core::mem::MaybeUninit; #[cfg(feature = "defmt")] use defmt_rtt::*; use embassy_executor::Spawner; -use embassy_stm32::gpio::{Level, Output, Speed}; use embassy_stm32::SharedData; +use embassy_stm32::gpio::{Level, Output, Speed}; use embassy_time::Timer; use panic_reset as _; diff --git a/examples/boot/bootloader/stm32-dual-bank/src/main.rs b/examples/boot/bootloader/stm32-dual-bank/src/main.rs index ea81e1fe5..f0063fb5c 100644 --- a/examples/boot/bootloader/stm32-dual-bank/src/main.rs +++ b/examples/boot/bootloader/stm32-dual-bank/src/main.rs @@ -7,7 +7,7 @@ use cortex_m_rt::{entry, exception}; #[cfg(feature = "defmt")] use defmt_rtt as _; use embassy_boot_stm32::*; -use embassy_stm32::flash::{Flash, BANK1_REGION}; +use embassy_stm32::flash::{BANK1_REGION, Flash}; use embassy_sync::blocking_mutex::Mutex; #[entry] diff --git a/examples/boot/bootloader/stm32/src/main.rs b/examples/boot/bootloader/stm32/src/main.rs index f74edd75f..383ad912d 100644 --- a/examples/boot/bootloader/stm32/src/main.rs +++ b/examples/boot/bootloader/stm32/src/main.rs @@ -7,7 +7,7 @@ use cortex_m_rt::{entry, exception}; #[cfg(feature = "defmt")] use defmt_rtt as _; use embassy_boot_stm32::*; -use embassy_stm32::flash::{Flash, BANK1_REGION}; +use embassy_stm32::flash::{BANK1_REGION, Flash}; use embassy_sync::blocking_mutex::Mutex; #[entry] diff --git a/examples/boot/bootloader/stm32wb-dfu/src/main.rs b/examples/boot/bootloader/stm32wb-dfu/src/main.rs index 475f1234d..9ee82846d 100644 --- a/examples/boot/bootloader/stm32wb-dfu/src/main.rs +++ b/examples/boot/bootloader/stm32wb-dfu/src/main.rs @@ -7,14 +7,14 @@ use cortex_m_rt::{entry, exception}; #[cfg(feature = "defmt")] use defmt_rtt as _; use embassy_boot_stm32::*; -use embassy_stm32::flash::{Flash, BANK1_REGION, WRITE_SIZE}; +use embassy_stm32::flash::{BANK1_REGION, Flash, WRITE_SIZE}; use embassy_stm32::rcc::WPAN_DEFAULT; use embassy_stm32::usb::Driver; use embassy_stm32::{bind_interrupts, peripherals, usb}; use embassy_sync::blocking_mutex::Mutex; -use embassy_usb::{msos, Builder}; +use embassy_usb::{Builder, msos}; use embassy_usb_dfu::consts::DfuAttributes; -use embassy_usb_dfu::{usb_dfu, Control, ResetImmediate}; +use embassy_usb_dfu::{Control, ResetImmediate, usb_dfu}; bind_interrupts!(struct Irqs { USB_LP => usb::InterruptHandler; diff --git a/examples/boot/bootloader/stm32wba-dfu/src/main.rs b/examples/boot/bootloader/stm32wba-dfu/src/main.rs index e4aacbca9..b33a75d95 100644 --- a/examples/boot/bootloader/stm32wba-dfu/src/main.rs +++ b/examples/boot/bootloader/stm32wba-dfu/src/main.rs @@ -7,13 +7,13 @@ use cortex_m_rt::{entry, exception}; #[cfg(feature = "defmt")] use defmt_rtt as _; use embassy_boot_stm32::*; -use embassy_stm32::flash::{Flash, BANK1_REGION, WRITE_SIZE}; +use embassy_stm32::flash::{BANK1_REGION, Flash, WRITE_SIZE}; use embassy_stm32::usb::Driver; -use embassy_stm32::{bind_interrupts, peripherals, usb, Config}; +use embassy_stm32::{Config, bind_interrupts, peripherals, usb}; use embassy_sync::blocking_mutex::Mutex; -use embassy_usb::{msos, Builder}; +use embassy_usb::{Builder, msos}; use embassy_usb_dfu::consts::DfuAttributes; -use embassy_usb_dfu::{usb_dfu, Control, ResetImmediate}; +use embassy_usb_dfu::{Control, ResetImmediate, usb_dfu}; bind_interrupts!(struct Irqs { USB_OTG_HS => usb::InterruptHandler; diff --git a/examples/mimxrt6/src/bin/button.rs b/examples/mimxrt6/src/bin/button.rs index efb7f14af..a9bdde98e 100644 --- a/examples/mimxrt6/src/bin/button.rs +++ b/examples/mimxrt6/src/bin/button.rs @@ -3,7 +3,7 @@ use defmt::info; use embassy_executor::Spawner; -use embassy_futures::select::{select, Either}; +use embassy_futures::select::{Either, select}; use embassy_imxrt::gpio; use {defmt_rtt as _, embassy_imxrt_examples as _, panic_probe as _}; diff --git a/examples/mspm0c1104/src/bin/blinky.rs b/examples/mspm0c1104/src/bin/blinky.rs index 0d974cc5e..345077b37 100644 --- a/examples/mspm0c1104/src/bin/blinky.rs +++ b/examples/mspm0c1104/src/bin/blinky.rs @@ -3,8 +3,8 @@ use defmt::*; use embassy_executor::Spawner; -use embassy_mspm0::gpio::{Level, Output}; use embassy_mspm0::Config; +use embassy_mspm0::gpio::{Level, Output}; use embassy_time::Timer; use {defmt_rtt as _, panic_halt as _}; diff --git a/examples/mspm0c1104/src/bin/button.rs b/examples/mspm0c1104/src/bin/button.rs index 7face1618..557d997cd 100644 --- a/examples/mspm0c1104/src/bin/button.rs +++ b/examples/mspm0c1104/src/bin/button.rs @@ -3,8 +3,8 @@ use defmt::*; use embassy_executor::Spawner; -use embassy_mspm0::gpio::{Input, Level, Output, Pull}; use embassy_mspm0::Config; +use embassy_mspm0::gpio::{Input, Level, Output, Pull}; use {defmt_rtt as _, panic_halt as _}; #[embassy_executor::main] diff --git a/examples/mspm0g3507/src/bin/adc.rs b/examples/mspm0g3507/src/bin/adc.rs index ceccc7c02..cf1abb471 100644 --- a/examples/mspm0g3507/src/bin/adc.rs +++ b/examples/mspm0g3507/src/bin/adc.rs @@ -4,7 +4,7 @@ use defmt::*; use embassy_executor::Spawner; use embassy_mspm0::adc::{self, Adc, Vrsel}; -use embassy_mspm0::{bind_interrupts, peripherals, Config}; +use embassy_mspm0::{Config, bind_interrupts, peripherals}; use embassy_time::Timer; use {defmt_rtt as _, panic_halt as _}; diff --git a/examples/mspm0g3507/src/bin/blinky.rs b/examples/mspm0g3507/src/bin/blinky.rs index 055a5cd81..47eaf1535 100644 --- a/examples/mspm0g3507/src/bin/blinky.rs +++ b/examples/mspm0g3507/src/bin/blinky.rs @@ -3,8 +3,8 @@ use defmt::*; use embassy_executor::Spawner; -use embassy_mspm0::gpio::{Level, Output}; use embassy_mspm0::Config; +use embassy_mspm0::gpio::{Level, Output}; use embassy_time::Timer; use {defmt_rtt as _, panic_halt as _}; diff --git a/examples/mspm0g3507/src/bin/button.rs b/examples/mspm0g3507/src/bin/button.rs index cde1f2892..76f3a1aba 100644 --- a/examples/mspm0g3507/src/bin/button.rs +++ b/examples/mspm0g3507/src/bin/button.rs @@ -3,8 +3,8 @@ use defmt::*; use embassy_executor::Spawner; -use embassy_mspm0::gpio::{Input, Level, Output, Pull}; use embassy_mspm0::Config; +use embassy_mspm0::gpio::{Input, Level, Output, Pull}; use {defmt_rtt as _, panic_halt as _}; #[embassy_executor::main] diff --git a/examples/mspm0g3519/src/bin/blinky.rs b/examples/mspm0g3519/src/bin/blinky.rs index 055a5cd81..47eaf1535 100644 --- a/examples/mspm0g3519/src/bin/blinky.rs +++ b/examples/mspm0g3519/src/bin/blinky.rs @@ -3,8 +3,8 @@ use defmt::*; use embassy_executor::Spawner; -use embassy_mspm0::gpio::{Level, Output}; use embassy_mspm0::Config; +use embassy_mspm0::gpio::{Level, Output}; use embassy_time::Timer; use {defmt_rtt as _, panic_halt as _}; diff --git a/examples/mspm0g3519/src/bin/button.rs b/examples/mspm0g3519/src/bin/button.rs index c81cc2918..21e7873d8 100644 --- a/examples/mspm0g3519/src/bin/button.rs +++ b/examples/mspm0g3519/src/bin/button.rs @@ -3,8 +3,8 @@ use defmt::*; use embassy_executor::Spawner; -use embassy_mspm0::gpio::{Input, Level, Output, Pull}; use embassy_mspm0::Config; +use embassy_mspm0::gpio::{Input, Level, Output, Pull}; use {defmt_rtt as _, panic_halt as _}; #[embassy_executor::main] diff --git a/examples/mspm0l1306/src/bin/adc.rs b/examples/mspm0l1306/src/bin/adc.rs index 2806b98cc..235396b8a 100644 --- a/examples/mspm0l1306/src/bin/adc.rs +++ b/examples/mspm0l1306/src/bin/adc.rs @@ -4,7 +4,7 @@ use defmt::*; use embassy_executor::Spawner; use embassy_mspm0::adc::{self, Adc, Vrsel}; -use embassy_mspm0::{bind_interrupts, peripherals, Config}; +use embassy_mspm0::{Config, bind_interrupts, peripherals}; use embassy_time::Timer; use {defmt_rtt as _, panic_halt as _}; diff --git a/examples/mspm0l1306/src/bin/blinky.rs b/examples/mspm0l1306/src/bin/blinky.rs index 055a5cd81..47eaf1535 100644 --- a/examples/mspm0l1306/src/bin/blinky.rs +++ b/examples/mspm0l1306/src/bin/blinky.rs @@ -3,8 +3,8 @@ use defmt::*; use embassy_executor::Spawner; -use embassy_mspm0::gpio::{Level, Output}; use embassy_mspm0::Config; +use embassy_mspm0::gpio::{Level, Output}; use embassy_time::Timer; use {defmt_rtt as _, panic_halt as _}; diff --git a/examples/mspm0l1306/src/bin/button.rs b/examples/mspm0l1306/src/bin/button.rs index d8c85947f..33e682272 100644 --- a/examples/mspm0l1306/src/bin/button.rs +++ b/examples/mspm0l1306/src/bin/button.rs @@ -3,8 +3,8 @@ use defmt::*; use embassy_executor::Spawner; -use embassy_mspm0::gpio::{Input, Level, Output, Pull}; use embassy_mspm0::Config; +use embassy_mspm0::gpio::{Input, Level, Output, Pull}; use {defmt_rtt as _, panic_halt as _}; #[embassy_executor::main] diff --git a/examples/mspm0l2228/src/bin/blinky.rs b/examples/mspm0l2228/src/bin/blinky.rs index 055a5cd81..47eaf1535 100644 --- a/examples/mspm0l2228/src/bin/blinky.rs +++ b/examples/mspm0l2228/src/bin/blinky.rs @@ -3,8 +3,8 @@ use defmt::*; use embassy_executor::Spawner; -use embassy_mspm0::gpio::{Level, Output}; use embassy_mspm0::Config; +use embassy_mspm0::gpio::{Level, Output}; use embassy_time::Timer; use {defmt_rtt as _, panic_halt as _}; diff --git a/examples/mspm0l2228/src/bin/button.rs b/examples/mspm0l2228/src/bin/button.rs index 47bfd274b..bad1cb138 100644 --- a/examples/mspm0l2228/src/bin/button.rs +++ b/examples/mspm0l2228/src/bin/button.rs @@ -3,8 +3,8 @@ use defmt::*; use embassy_executor::Spawner; -use embassy_mspm0::gpio::{Input, Level, Output, Pull}; use embassy_mspm0::Config; +use embassy_mspm0::gpio::{Input, Level, Output, Pull}; use {defmt_rtt as _, panic_halt as _}; #[embassy_executor::main] diff --git a/examples/nrf52840-edf/src/bin/basic.rs b/examples/nrf52840-edf/src/bin/basic.rs index d888e17d1..f7214790d 100644 --- a/examples/nrf52840-edf/src/bin/basic.rs +++ b/examples/nrf52840-edf/src/bin/basic.rs @@ -12,7 +12,7 @@ #![no_std] #![no_main] -use core::sync::atomic::{compiler_fence, Ordering}; +use core::sync::atomic::{Ordering, compiler_fence}; use defmt::unwrap; use embassy_executor::Spawner; diff --git a/examples/nrf52840-rtic/src/bin/blinky.rs b/examples/nrf52840-rtic/src/bin/blinky.rs index 2adac7e0a..671082117 100644 --- a/examples/nrf52840-rtic/src/bin/blinky.rs +++ b/examples/nrf52840-rtic/src/bin/blinky.rs @@ -7,7 +7,7 @@ use {defmt_rtt as _, panic_probe as _}; mod app { use defmt::info; use embassy_nrf::gpio::{Level, Output, OutputDrive}; - use embassy_nrf::{peripherals, Peri}; + use embassy_nrf::{Peri, peripherals}; use embassy_time::Timer; #[shared] diff --git a/examples/nrf52840/src/bin/channel_sender_receiver.rs b/examples/nrf52840/src/bin/channel_sender_receiver.rs index 09050db68..de694eaa0 100644 --- a/examples/nrf52840/src/bin/channel_sender_receiver.rs +++ b/examples/nrf52840/src/bin/channel_sender_receiver.rs @@ -3,8 +3,8 @@ use defmt::unwrap; use embassy_executor::Spawner; -use embassy_nrf::gpio::{AnyPin, Level, Output, OutputDrive}; use embassy_nrf::Peri; +use embassy_nrf::gpio::{AnyPin, Level, Output, OutputDrive}; use embassy_sync::blocking_mutex::raw::NoopRawMutex; use embassy_sync::channel::{Channel, Receiver, Sender}; use embassy_time::Timer; diff --git a/examples/nrf52840/src/bin/ethernet_enc28j60.rs b/examples/nrf52840/src/bin/ethernet_enc28j60.rs index e59afd37f..5a988d89b 100644 --- a/examples/nrf52840/src/bin/ethernet_enc28j60.rs +++ b/examples/nrf52840/src/bin/ethernet_enc28j60.rs @@ -3,8 +3,8 @@ use defmt::*; use embassy_executor::Spawner; -use embassy_net::tcp::TcpSocket; use embassy_net::StackResources; +use embassy_net::tcp::TcpSocket; use embassy_net_enc28j60::Enc28j60; use embassy_nrf::gpio::{Level, Output, OutputDrive}; use embassy_nrf::rng::Rng; diff --git a/examples/nrf52840/src/bin/i2s_effect.rs b/examples/nrf52840/src/bin/i2s_effect.rs index 9eadeb4e4..c31b78614 100644 --- a/examples/nrf52840/src/bin/i2s_effect.rs +++ b/examples/nrf52840/src/bin/i2s_effect.rs @@ -5,7 +5,7 @@ use core::f32::consts::PI; use defmt::{error, info}; use embassy_executor::Spawner; -use embassy_nrf::i2s::{self, Channels, Config, MasterClock, MultiBuffering, Sample as _, SampleWidth, I2S}; +use embassy_nrf::i2s::{self, Channels, Config, I2S, MasterClock, MultiBuffering, Sample as _, SampleWidth}; use embassy_nrf::{bind_interrupts, peripherals}; use {defmt_rtt as _, panic_probe as _}; @@ -102,11 +102,7 @@ impl SineOsc { #[inline] fn abs(value: f32) -> f32 { - if value < 0.0 { - -value - } else { - value - } + if value < 0.0 { -value } else { value } } #[inline] diff --git a/examples/nrf52840/src/bin/i2s_monitor.rs b/examples/nrf52840/src/bin/i2s_monitor.rs index 799be351f..66b429b09 100644 --- a/examples/nrf52840/src/bin/i2s_monitor.rs +++ b/examples/nrf52840/src/bin/i2s_monitor.rs @@ -3,7 +3,7 @@ use defmt::{debug, error, info}; use embassy_executor::Spawner; -use embassy_nrf::i2s::{self, Channels, Config, DoubleBuffering, MasterClock, Sample as _, SampleWidth, I2S}; +use embassy_nrf::i2s::{self, Channels, Config, DoubleBuffering, I2S, MasterClock, Sample as _, SampleWidth}; use embassy_nrf::pwm::{Prescaler, SimplePwm}; use embassy_nrf::{bind_interrupts, peripherals}; use {defmt_rtt as _, panic_probe as _}; diff --git a/examples/nrf52840/src/bin/i2s_waveform.rs b/examples/nrf52840/src/bin/i2s_waveform.rs index 137d82840..ce7a68d3a 100644 --- a/examples/nrf52840/src/bin/i2s_waveform.rs +++ b/examples/nrf52840/src/bin/i2s_waveform.rs @@ -5,7 +5,7 @@ use core::f32::consts::PI; use defmt::{error, info}; use embassy_executor::Spawner; -use embassy_nrf::i2s::{self, Channels, Config, DoubleBuffering, MasterClock, Sample as _, SampleWidth, I2S}; +use embassy_nrf::i2s::{self, Channels, Config, DoubleBuffering, I2S, MasterClock, Sample as _, SampleWidth}; use embassy_nrf::{bind_interrupts, peripherals}; use {defmt_rtt as _, panic_probe as _}; @@ -140,11 +140,7 @@ impl SineOsc { #[inline] fn abs(value: f32) -> f32 { - if value < 0.0 { - -value - } else { - value - } + if value < 0.0 { -value } else { value } } #[inline] diff --git a/examples/nrf52840/src/bin/raw_spawn.rs b/examples/nrf52840/src/bin/raw_spawn.rs index faa8517c8..783be763d 100644 --- a/examples/nrf52840/src/bin/raw_spawn.rs +++ b/examples/nrf52840/src/bin/raw_spawn.rs @@ -5,8 +5,8 @@ use core::mem; use cortex_m_rt::entry; use defmt::{info, unwrap}; -use embassy_executor::raw::TaskStorage; use embassy_executor::Executor; +use embassy_executor::raw::TaskStorage; use embassy_time::Timer; use static_cell::StaticCell; use {defmt_rtt as _, panic_probe as _}; diff --git a/examples/nrf52840/src/bin/rtc.rs b/examples/nrf52840/src/bin/rtc.rs index 9d475df7f..56a0c25f4 100644 --- a/examples/nrf52840/src/bin/rtc.rs +++ b/examples/nrf52840/src/bin/rtc.rs @@ -7,8 +7,8 @@ use embassy_executor::Spawner; use embassy_nrf::gpio::{Level, Output, OutputDrive}; use embassy_nrf::interrupt; use embassy_nrf::rtc::Rtc; -use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex; use embassy_sync::blocking_mutex::Mutex; +use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex; use portable_atomic::AtomicU64; use {defmt_rtt as _, panic_probe as _}; diff --git a/examples/nrf52840/src/bin/usb_ethernet.rs b/examples/nrf52840/src/bin/usb_ethernet.rs index a75b967b4..14a1004d7 100644 --- a/examples/nrf52840/src/bin/usb_ethernet.rs +++ b/examples/nrf52840/src/bin/usb_ethernet.rs @@ -3,11 +3,11 @@ use defmt::*; use embassy_executor::Spawner; -use embassy_net::tcp::TcpSocket; use embassy_net::StackResources; +use embassy_net::tcp::TcpSocket; use embassy_nrf::rng::Rng; -use embassy_nrf::usb::vbus_detect::HardwareVbusDetect; use embassy_nrf::usb::Driver; +use embassy_nrf::usb::vbus_detect::HardwareVbusDetect; use embassy_nrf::{bind_interrupts, pac, peripherals, rng, usb}; use embassy_usb::class::cdc_ncm::embassy_net::{Device, Runner, State as NetState}; use embassy_usb::class::cdc_ncm::{CdcNcmClass, State}; diff --git a/examples/nrf52840/src/bin/usb_hid_keyboard.rs b/examples/nrf52840/src/bin/usb_hid_keyboard.rs index 5a9dc90a2..1cd730503 100644 --- a/examples/nrf52840/src/bin/usb_hid_keyboard.rs +++ b/examples/nrf52840/src/bin/usb_hid_keyboard.rs @@ -6,10 +6,10 @@ use core::sync::atomic::{AtomicBool, Ordering}; use defmt::*; use embassy_executor::Spawner; use embassy_futures::join::join; -use embassy_futures::select::{select, Either}; +use embassy_futures::select::{Either, select}; use embassy_nrf::gpio::{Input, Pull}; -use embassy_nrf::usb::vbus_detect::HardwareVbusDetect; use embassy_nrf::usb::Driver; +use embassy_nrf::usb::vbus_detect::HardwareVbusDetect; use embassy_nrf::{bind_interrupts, pac, peripherals, usb}; use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex; use embassy_sync::signal::Signal; @@ -210,7 +210,9 @@ impl Handler for MyDeviceHandler { fn suspended(&mut self, suspended: bool) { if suspended { - info!("Device suspended, the Vbus current limit is 500µA (or 2.5mA for high-power devices with remote wakeup enabled)."); + info!( + "Device suspended, the Vbus current limit is 500µA (or 2.5mA for high-power devices with remote wakeup enabled)." + ); SUSPENDED.store(true, Ordering::Release); } else { SUSPENDED.store(false, Ordering::Release); diff --git a/examples/nrf52840/src/bin/usb_hid_mouse.rs b/examples/nrf52840/src/bin/usb_hid_mouse.rs index 80cda70e3..3c0fc04e8 100644 --- a/examples/nrf52840/src/bin/usb_hid_mouse.rs +++ b/examples/nrf52840/src/bin/usb_hid_mouse.rs @@ -4,8 +4,8 @@ use defmt::*; use embassy_executor::Spawner; use embassy_futures::join::join; -use embassy_nrf::usb::vbus_detect::HardwareVbusDetect; use embassy_nrf::usb::Driver; +use embassy_nrf::usb::vbus_detect::HardwareVbusDetect; use embassy_nrf::{bind_interrupts, pac, peripherals, usb}; use embassy_time::Timer; use embassy_usb::class::hid::{HidWriter, ReportId, RequestHandler, State}; diff --git a/examples/nrf52840/src/bin/usb_serial.rs b/examples/nrf52840/src/bin/usb_serial.rs index e7c2d0854..469002bc7 100644 --- a/examples/nrf52840/src/bin/usb_serial.rs +++ b/examples/nrf52840/src/bin/usb_serial.rs @@ -4,8 +4,8 @@ use defmt::{info, panic}; use embassy_executor::Spawner; use embassy_futures::join::join; -use embassy_nrf::usb::vbus_detect::{HardwareVbusDetect, VbusDetect}; use embassy_nrf::usb::Driver; +use embassy_nrf::usb::vbus_detect::{HardwareVbusDetect, VbusDetect}; use embassy_nrf::{bind_interrupts, pac, peripherals, usb}; use embassy_usb::class::cdc_acm::{CdcAcmClass, State}; use embassy_usb::driver::EndpointError; diff --git a/examples/nrf52840/src/bin/usb_serial_multitask.rs b/examples/nrf52840/src/bin/usb_serial_multitask.rs index b6a983854..67b2bccbb 100644 --- a/examples/nrf52840/src/bin/usb_serial_multitask.rs +++ b/examples/nrf52840/src/bin/usb_serial_multitask.rs @@ -3,8 +3,8 @@ use defmt::{info, panic, unwrap}; use embassy_executor::Spawner; -use embassy_nrf::usb::vbus_detect::HardwareVbusDetect; use embassy_nrf::usb::Driver; +use embassy_nrf::usb::vbus_detect::HardwareVbusDetect; use embassy_nrf::{bind_interrupts, pac, peripherals, usb}; use embassy_usb::class::cdc_acm::{CdcAcmClass, State}; use embassy_usb::driver::EndpointError; diff --git a/examples/nrf52840/src/bin/usb_serial_winusb.rs b/examples/nrf52840/src/bin/usb_serial_winusb.rs index e30e08a01..cd4d5bca1 100644 --- a/examples/nrf52840/src/bin/usb_serial_winusb.rs +++ b/examples/nrf52840/src/bin/usb_serial_winusb.rs @@ -4,8 +4,8 @@ use defmt::{info, panic}; use embassy_executor::Spawner; use embassy_futures::join::join; -use embassy_nrf::usb::vbus_detect::{HardwareVbusDetect, VbusDetect}; use embassy_nrf::usb::Driver; +use embassy_nrf::usb::vbus_detect::{HardwareVbusDetect, VbusDetect}; use embassy_nrf::{bind_interrupts, pac, peripherals, usb}; use embassy_usb::class::cdc_acm::{CdcAcmClass, State}; use embassy_usb::driver::EndpointError; diff --git a/examples/nrf52840/src/bin/wifi_esp_hosted.rs b/examples/nrf52840/src/bin/wifi_esp_hosted.rs index 1bc35746a..07752ffc4 100644 --- a/examples/nrf52840/src/bin/wifi_esp_hosted.rs +++ b/examples/nrf52840/src/bin/wifi_esp_hosted.rs @@ -3,8 +3,8 @@ use defmt::{info, unwrap, warn}; use embassy_executor::Spawner; -use embassy_net::tcp::TcpSocket; use embassy_net::StackResources; +use embassy_net::tcp::TcpSocket; use embassy_nrf::gpio::{Input, Level, Output, OutputDrive, Pull}; use embassy_nrf::rng::Rng; use embassy_nrf::spim::{self, Spim}; diff --git a/examples/nrf9160/src/bin/modem_tcp_client.rs b/examples/nrf9160/src/bin/modem_tcp_client.rs index c9d879662..07fa57e63 100644 --- a/examples/nrf9160/src/bin/modem_tcp_client.rs +++ b/examples/nrf9160/src/bin/modem_tcp_client.rs @@ -11,11 +11,11 @@ use defmt::{info, unwrap, warn}; use embassy_executor::Spawner; use embassy_net::{Ipv4Cidr, Stack, StackResources}; use embassy_net_nrf91::context::Status; -use embassy_net_nrf91::{context, Runner, State, TraceBuffer, TraceReader}; +use embassy_net_nrf91::{Runner, State, TraceBuffer, TraceReader, context}; use embassy_nrf::buffered_uarte::{self, BufferedUarteTx}; use embassy_nrf::gpio::{AnyPin, Level, Output, OutputDrive}; use embassy_nrf::uarte::Baudrate; -use embassy_nrf::{bind_interrupts, interrupt, peripherals, uarte, Peri}; +use embassy_nrf::{Peri, bind_interrupts, interrupt, peripherals, uarte}; use embassy_time::{Duration, Timer}; use embedded_io_async::Write; use heapless::Vec; diff --git a/examples/rp/src/bin/assign_resources.rs b/examples/rp/src/bin/assign_resources.rs index 4ee4278b5..aaa134768 100644 --- a/examples/rp/src/bin/assign_resources.rs +++ b/examples/rp/src/bin/assign_resources.rs @@ -14,9 +14,9 @@ use assign_resources::assign_resources; use defmt::*; use embassy_executor::Spawner; +use embassy_rp::Peri; use embassy_rp::gpio::{Level, Output}; use embassy_rp::peripherals::{self, PIN_20, PIN_21}; -use embassy_rp::Peri; use embassy_time::Timer; use {defmt_rtt as _, panic_probe as _}; diff --git a/examples/rp/src/bin/debounce.rs b/examples/rp/src/bin/debounce.rs index 0077f19fc..6eeb01d0a 100644 --- a/examples/rp/src/bin/debounce.rs +++ b/examples/rp/src/bin/debounce.rs @@ -7,7 +7,7 @@ use defmt::info; use embassy_executor::Spawner; use embassy_rp::gpio::{Input, Level, Pull}; -use embassy_time::{with_deadline, Duration, Instant, Timer}; +use embassy_time::{Duration, Instant, Timer, with_deadline}; use {defmt_rtt as _, panic_probe as _}; pub struct Debouncer<'a> { diff --git a/examples/rp/src/bin/ethernet_w5500_icmp_ping.rs b/examples/rp/src/bin/ethernet_w5500_icmp_ping.rs index 49d28071a..cb667f24f 100644 --- a/examples/rp/src/bin/ethernet_w5500_icmp_ping.rs +++ b/examples/rp/src/bin/ethernet_w5500_icmp_ping.rs @@ -12,8 +12,8 @@ use core::str::FromStr; use defmt::*; use embassy_executor::Spawner; use embassy_futures::yield_now; -use embassy_net::icmp::ping::{PingManager, PingParams}; use embassy_net::icmp::PacketMetadata; +use embassy_net::icmp::ping::{PingManager, PingParams}; use embassy_net::{Ipv4Cidr, Stack, StackResources}; use embassy_net_wiznet::chip::W5500; use embassy_net_wiznet::*; @@ -99,7 +99,7 @@ async fn main(spawner: Spawner) { // Create the ping manager instance let mut ping_manager = PingManager::new(stack, &mut rx_meta, &mut rx_buffer, &mut tx_meta, &mut tx_buffer); let addr = "192.168.8.1"; // Address to ping to - // Create the PingParams with the target address + // Create the PingParams with the target address let mut ping_params = PingParams::new(Ipv4Addr::from_str(addr).unwrap()); // (optional) Set custom properties of the ping ping_params.set_payload(b"Hello, Ping!"); // custom payload diff --git a/examples/rp/src/bin/ethernet_w55rp20_tcp_server.rs b/examples/rp/src/bin/ethernet_w55rp20_tcp_server.rs index f51df2df9..b402029b5 100644 --- a/examples/rp/src/bin/ethernet_w55rp20_tcp_server.rs +++ b/examples/rp/src/bin/ethernet_w55rp20_tcp_server.rs @@ -65,7 +65,7 @@ async fn main(spawner: Spawner) { // Construct an SPI driver backed by a PIO state machine let mut spi_cfg = SpiConfig::default(); spi_cfg.frequency = 12_500_000; // The PIO SPI program is much less stable than the actual SPI - // peripheral, use higher speeds at your peril + // peripheral, use higher speeds at your peril let spi = Spi::new(&mut common, sm0, clk, mosi, miso, p.DMA_CH0, p.DMA_CH1, spi_cfg); // Further control pins diff --git a/examples/rp/src/bin/interrupt.rs b/examples/rp/src/bin/interrupt.rs index 2748f778a..2605622ab 100644 --- a/examples/rp/src/bin/interrupt.rs +++ b/examples/rp/src/bin/interrupt.rs @@ -16,8 +16,8 @@ use embassy_rp::adc::{self, Adc, Blocking}; use embassy_rp::gpio::Pull; use embassy_rp::interrupt; use embassy_rp::pwm::{Config, Pwm}; -use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex; use embassy_sync::blocking_mutex::Mutex; +use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex; use embassy_sync::channel::Channel; use embassy_time::{Duration, Ticker}; use portable_atomic::{AtomicU32, Ordering}; diff --git a/examples/rp/src/bin/multicore.rs b/examples/rp/src/bin/multicore.rs index 3a6367420..d289f8020 100644 --- a/examples/rp/src/bin/multicore.rs +++ b/examples/rp/src/bin/multicore.rs @@ -8,7 +8,7 @@ use defmt::*; use embassy_executor::Executor; use embassy_rp::gpio::{Level, Output}; -use embassy_rp::multicore::{spawn_core1, Stack}; +use embassy_rp::multicore::{Stack, spawn_core1}; use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex; use embassy_sync::channel::Channel; use embassy_time::Timer; diff --git a/examples/rp/src/bin/multiprio.rs b/examples/rp/src/bin/multiprio.rs index 0750d9bb7..310047505 100644 --- a/examples/rp/src/bin/multiprio.rs +++ b/examples/rp/src/bin/multiprio.rs @@ -61,7 +61,7 @@ use defmt::{info, unwrap}; use embassy_executor::{Executor, InterruptExecutor}; use embassy_rp::interrupt; use embassy_rp::interrupt::{InterruptExt, Priority}; -use embassy_time::{Instant, Timer, TICK_HZ}; +use embassy_time::{Instant, TICK_HZ, Timer}; use static_cell::StaticCell; use {defmt_rtt as _, panic_probe as _}; diff --git a/examples/rp/src/bin/orchestrate_tasks.rs b/examples/rp/src/bin/orchestrate_tasks.rs index 9f25e1087..cd26a5371 100644 --- a/examples/rp/src/bin/orchestrate_tasks.rs +++ b/examples/rp/src/bin/orchestrate_tasks.rs @@ -20,11 +20,11 @@ use assign_resources::assign_resources; use defmt::*; use embassy_executor::Spawner; -use embassy_futures::select::{select, Either}; +use embassy_futures::select::{Either, select}; use embassy_rp::adc::{Adc, Channel, Config, InterruptHandler}; use embassy_rp::clocks::RoscRng; use embassy_rp::gpio::{Input, Pull}; -use embassy_rp::{bind_interrupts, peripherals, Peri}; +use embassy_rp::{Peri, bind_interrupts, peripherals}; use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex; use embassy_sync::mutex::Mutex; use embassy_sync::{channel, signal}; diff --git a/examples/rp/src/bin/overclock.rs b/examples/rp/src/bin/overclock.rs index 83b17308b..a98185a8e 100644 --- a/examples/rp/src/bin/overclock.rs +++ b/examples/rp/src/bin/overclock.rs @@ -7,7 +7,7 @@ use defmt::*; use embassy_executor::Spawner; -use embassy_rp::clocks::{clk_sys_freq, core_voltage, ClockConfig}; +use embassy_rp::clocks::{ClockConfig, clk_sys_freq, core_voltage}; use embassy_rp::config::Config; use embassy_rp::gpio::{Level, Output}; use embassy_time::{Duration, Instant, Timer}; diff --git a/examples/rp/src/bin/overclock_manual.rs b/examples/rp/src/bin/overclock_manual.rs index dea5cfb3c..18397f9a8 100644 --- a/examples/rp/src/bin/overclock_manual.rs +++ b/examples/rp/src/bin/overclock_manual.rs @@ -7,7 +7,7 @@ use defmt::*; use embassy_executor::Spawner; -use embassy_rp::clocks::{clk_sys_freq, core_voltage, ClockConfig, CoreVoltage, PllConfig}; +use embassy_rp::clocks::{ClockConfig, CoreVoltage, PllConfig, clk_sys_freq, core_voltage}; use embassy_rp::config::Config; use embassy_rp::gpio::{Level, Output}; use embassy_time::{Duration, Instant, Timer}; diff --git a/examples/rp/src/bin/pio_async.rs b/examples/rp/src/bin/pio_async.rs index 1743a417e..55e983c36 100644 --- a/examples/rp/src/bin/pio_async.rs +++ b/examples/rp/src/bin/pio_async.rs @@ -7,7 +7,7 @@ use embassy_executor::Spawner; use embassy_rp::peripherals::PIO0; use embassy_rp::pio::program::pio_asm; use embassy_rp::pio::{Common, Config, InterruptHandler, Irq, Pio, PioPin, ShiftDirection, StateMachine}; -use embassy_rp::{bind_interrupts, Peri}; +use embassy_rp::{Peri, bind_interrupts}; use fixed::traits::ToFixed; use fixed_macro::types::U56F8; use {defmt_rtt as _, panic_probe as _}; diff --git a/examples/rp/src/bin/pio_stepper.rs b/examples/rp/src/bin/pio_stepper.rs index 3862c248b..e8f203990 100644 --- a/examples/rp/src/bin/pio_stepper.rs +++ b/examples/rp/src/bin/pio_stepper.rs @@ -10,7 +10,7 @@ use embassy_rp::bind_interrupts; use embassy_rp::peripherals::PIO0; use embassy_rp::pio::{InterruptHandler, Pio}; use embassy_rp::pio_programs::stepper::{PioStepper, PioStepperProgram}; -use embassy_time::{with_timeout, Duration, Timer}; +use embassy_time::{Duration, Timer, with_timeout}; use {defmt_rtt as _, panic_probe as _}; bind_interrupts!(struct Irqs { diff --git a/examples/rp/src/bin/pwm.rs b/examples/rp/src/bin/pwm.rs index 9dd07ab6e..f985bf7cf 100644 --- a/examples/rp/src/bin/pwm.rs +++ b/examples/rp/src/bin/pwm.rs @@ -9,9 +9,9 @@ use defmt::*; use embassy_executor::Spawner; -use embassy_rp::peripherals::{PIN_25, PIN_4, PWM_SLICE2, PWM_SLICE4}; -use embassy_rp::pwm::{Config, Pwm, SetDutyCycle}; use embassy_rp::Peri; +use embassy_rp::peripherals::{PIN_4, PIN_25, PWM_SLICE2, PWM_SLICE4}; +use embassy_rp::pwm::{Config, Pwm, SetDutyCycle}; use embassy_time::Timer; use {defmt_rtt as _, panic_probe as _}; diff --git a/examples/rp/src/bin/rtc_alarm.rs b/examples/rp/src/bin/rtc_alarm.rs index 94b5fbd27..bde49ccd5 100644 --- a/examples/rp/src/bin/rtc_alarm.rs +++ b/examples/rp/src/bin/rtc_alarm.rs @@ -5,7 +5,7 @@ use defmt::*; use embassy_executor::Spawner; -use embassy_futures::select::{select, Either}; +use embassy_futures::select::{Either, select}; use embassy_rp::bind_interrupts; use embassy_rp::rtc::{DateTime, DateTimeFilter, DayOfWeek, Rtc}; use embassy_time::Timer; diff --git a/examples/rp/src/bin/spi_display.rs b/examples/rp/src/bin/spi_display.rs index dd114a4ae..4bf924e56 100644 --- a/examples/rp/src/bin/spi_display.rs +++ b/examples/rp/src/bin/spi_display.rs @@ -15,19 +15,19 @@ use embassy_executor::Spawner; use embassy_rp::gpio::{Level, Output}; use embassy_rp::spi; use embassy_rp::spi::Spi; -use embassy_sync::blocking_mutex::raw::NoopRawMutex; use embassy_sync::blocking_mutex::Mutex; +use embassy_sync::blocking_mutex::raw::NoopRawMutex; use embassy_time::Delay; use embedded_graphics::image::{Image, ImageRawLE}; -use embedded_graphics::mono_font::ascii::FONT_10X20; use embedded_graphics::mono_font::MonoTextStyle; +use embedded_graphics::mono_font::ascii::FONT_10X20; use embedded_graphics::pixelcolor::Rgb565; use embedded_graphics::prelude::*; use embedded_graphics::primitives::{PrimitiveStyleBuilder, Rectangle}; use embedded_graphics::text::Text; +use mipidsi::Builder; use mipidsi::models::ST7789; use mipidsi::options::{Orientation, Rotation}; -use mipidsi::Builder; use {defmt_rtt as _, panic_probe as _}; use crate::touch::Touch; @@ -167,11 +167,7 @@ mod touch { let x = ((x - cal.x1) * cal.sx / (cal.x2 - cal.x1)).clamp(0, cal.sx); let y = ((y - cal.y1) * cal.sy / (cal.y2 - cal.y1)).clamp(0, cal.sy); - if x == 0 && y == 0 { - None - } else { - Some((x, y)) - } + if x == 0 && y == 0 { None } else { Some((x, y)) } } } } diff --git a/examples/rp/src/bin/spi_gc9a01.rs b/examples/rp/src/bin/spi_gc9a01.rs index fdef09d4b..fd007b9bd 100644 --- a/examples/rp/src/bin/spi_gc9a01.rs +++ b/examples/rp/src/bin/spi_gc9a01.rs @@ -16,16 +16,16 @@ use embassy_rp::clocks::RoscRng; use embassy_rp::gpio::{Level, Output}; use embassy_rp::spi; use embassy_rp::spi::{Blocking, Spi}; -use embassy_sync::blocking_mutex::raw::NoopRawMutex; use embassy_sync::blocking_mutex::Mutex; +use embassy_sync::blocking_mutex::raw::NoopRawMutex; use embassy_time::{Delay, Duration, Timer}; use embedded_graphics::image::{Image, ImageRawLE}; use embedded_graphics::pixelcolor::Rgb565; use embedded_graphics::prelude::*; use embedded_graphics::primitives::{PrimitiveStyleBuilder, Rectangle}; +use mipidsi::Builder; use mipidsi::models::GC9A01; use mipidsi::options::{ColorInversion, ColorOrder}; -use mipidsi::Builder; use {defmt_rtt as _, panic_probe as _}; const DISPLAY_FREQ: u32 = 64_000_000; diff --git a/examples/rp/src/bin/uart_r503.rs b/examples/rp/src/bin/uart_r503.rs index 085be280b..a25d45b18 100644 --- a/examples/rp/src/bin/uart_r503.rs +++ b/examples/rp/src/bin/uart_r503.rs @@ -6,7 +6,7 @@ use embassy_executor::Spawner; use embassy_rp::bind_interrupts; use embassy_rp::peripherals::UART0; use embassy_rp::uart::{Config, DataBits, InterruptHandler as UARTInterruptHandler, Parity, StopBits, Uart}; -use embassy_time::{with_timeout, Duration, Timer}; +use embassy_time::{Duration, Timer, with_timeout}; use heapless::Vec; use {defmt_rtt as _, panic_probe as _}; diff --git a/examples/rp/src/bin/usb_ethernet.rs b/examples/rp/src/bin/usb_ethernet.rs index 912e52e96..b62a602b1 100644 --- a/examples/rp/src/bin/usb_ethernet.rs +++ b/examples/rp/src/bin/usb_ethernet.rs @@ -7,8 +7,8 @@ use defmt::*; use embassy_executor::Spawner; -use embassy_net::tcp::TcpSocket; use embassy_net::StackResources; +use embassy_net::tcp::TcpSocket; use embassy_rp::clocks::RoscRng; use embassy_rp::peripherals::USB; use embassy_rp::usb::{Driver, InterruptHandler}; diff --git a/examples/rp/src/bin/usb_serial.rs b/examples/rp/src/bin/usb_serial.rs index b79012acb..23d0c9e8b 100644 --- a/examples/rp/src/bin/usb_serial.rs +++ b/examples/rp/src/bin/usb_serial.rs @@ -10,9 +10,9 @@ use embassy_executor::Spawner; use embassy_rp::bind_interrupts; use embassy_rp::peripherals::USB; use embassy_rp::usb::{Driver, Instance, InterruptHandler}; +use embassy_usb::UsbDevice; use embassy_usb::class::cdc_acm::{CdcAcmClass, State}; use embassy_usb::driver::EndpointError; -use embassy_usb::UsbDevice; use static_cell::StaticCell; use {defmt_rtt as _, panic_probe as _}; diff --git a/examples/rp/src/bin/wifi_ap_tcp_server.rs b/examples/rp/src/bin/wifi_ap_tcp_server.rs index 128599e0d..0828dbbb9 100644 --- a/examples/rp/src/bin/wifi_ap_tcp_server.rs +++ b/examples/rp/src/bin/wifi_ap_tcp_server.rs @@ -7,7 +7,7 @@ use core::str::from_utf8; -use cyw43_pio::{PioSpi, DEFAULT_CLOCK_DIVIDER}; +use cyw43_pio::{DEFAULT_CLOCK_DIVIDER, PioSpi}; use defmt::*; use embassy_executor::Spawner; use embassy_net::tcp::TcpSocket; diff --git a/examples/rp/src/bin/wifi_blinky.rs b/examples/rp/src/bin/wifi_blinky.rs index b2e08c517..aa6ee4df0 100644 --- a/examples/rp/src/bin/wifi_blinky.rs +++ b/examples/rp/src/bin/wifi_blinky.rs @@ -5,7 +5,7 @@ #![no_std] #![no_main] -use cyw43_pio::{PioSpi, DEFAULT_CLOCK_DIVIDER}; +use cyw43_pio::{DEFAULT_CLOCK_DIVIDER, PioSpi}; use defmt::*; use embassy_executor::Spawner; use embassy_rp::bind_interrupts; diff --git a/examples/rp/src/bin/wifi_scan.rs b/examples/rp/src/bin/wifi_scan.rs index c884aa2ba..7e3de1db9 100644 --- a/examples/rp/src/bin/wifi_scan.rs +++ b/examples/rp/src/bin/wifi_scan.rs @@ -7,7 +7,7 @@ use core::str; -use cyw43_pio::{PioSpi, DEFAULT_CLOCK_DIVIDER}; +use cyw43_pio::{DEFAULT_CLOCK_DIVIDER, PioSpi}; use defmt::*; use embassy_executor::Spawner; use embassy_rp::bind_interrupts; diff --git a/examples/rp/src/bin/wifi_tcp_server.rs b/examples/rp/src/bin/wifi_tcp_server.rs index 126475779..e39de4902 100644 --- a/examples/rp/src/bin/wifi_tcp_server.rs +++ b/examples/rp/src/bin/wifi_tcp_server.rs @@ -8,7 +8,7 @@ use core::str::from_utf8; use cyw43::JoinOptions; -use cyw43_pio::{PioSpi, DEFAULT_CLOCK_DIVIDER}; +use cyw43_pio::{DEFAULT_CLOCK_DIVIDER, PioSpi}; use defmt::*; use embassy_executor::Spawner; use embassy_net::tcp::TcpSocket; diff --git a/examples/rp/src/bin/wifi_webrequest.rs b/examples/rp/src/bin/wifi_webrequest.rs index 079def370..b618d2b38 100644 --- a/examples/rp/src/bin/wifi_webrequest.rs +++ b/examples/rp/src/bin/wifi_webrequest.rs @@ -8,7 +8,7 @@ use core::str::from_utf8; use cyw43::JoinOptions; -use cyw43_pio::{PioSpi, DEFAULT_CLOCK_DIVIDER}; +use cyw43_pio::{DEFAULT_CLOCK_DIVIDER, PioSpi}; use defmt::*; use embassy_executor::Spawner; use embassy_net::dns::DnsSocket; diff --git a/examples/rp/src/bin/zerocopy.rs b/examples/rp/src/bin/zerocopy.rs index d603e1ed3..fc5f95e6e 100644 --- a/examples/rp/src/bin/zerocopy.rs +++ b/examples/rp/src/bin/zerocopy.rs @@ -11,7 +11,7 @@ use embassy_executor::Spawner; use embassy_rp::adc::{self, Adc, Async, Config, InterruptHandler}; use embassy_rp::gpio::Pull; use embassy_rp::peripherals::DMA_CH0; -use embassy_rp::{bind_interrupts, Peri}; +use embassy_rp::{Peri, bind_interrupts}; use embassy_sync::blocking_mutex::raw::NoopRawMutex; use embassy_sync::zerocopy_channel::{Channel, Receiver, Sender}; use embassy_time::{Duration, Ticker, Timer}; diff --git a/examples/rp235x/src/bin/assign_resources.rs b/examples/rp235x/src/bin/assign_resources.rs index 4ee4278b5..aaa134768 100644 --- a/examples/rp235x/src/bin/assign_resources.rs +++ b/examples/rp235x/src/bin/assign_resources.rs @@ -14,9 +14,9 @@ use assign_resources::assign_resources; use defmt::*; use embassy_executor::Spawner; +use embassy_rp::Peri; use embassy_rp::gpio::{Level, Output}; use embassy_rp::peripherals::{self, PIN_20, PIN_21}; -use embassy_rp::Peri; use embassy_time::Timer; use {defmt_rtt as _, panic_probe as _}; diff --git a/examples/rp235x/src/bin/debounce.rs b/examples/rp235x/src/bin/debounce.rs index 0077f19fc..6eeb01d0a 100644 --- a/examples/rp235x/src/bin/debounce.rs +++ b/examples/rp235x/src/bin/debounce.rs @@ -7,7 +7,7 @@ use defmt::info; use embassy_executor::Spawner; use embassy_rp::gpio::{Input, Level, Pull}; -use embassy_time::{with_deadline, Duration, Instant, Timer}; +use embassy_time::{Duration, Instant, Timer, with_deadline}; use {defmt_rtt as _, panic_probe as _}; pub struct Debouncer<'a> { diff --git a/examples/rp235x/src/bin/ethernet_w5500_icmp_ping.rs b/examples/rp235x/src/bin/ethernet_w5500_icmp_ping.rs index 309d3e4f7..227e68029 100644 --- a/examples/rp235x/src/bin/ethernet_w5500_icmp_ping.rs +++ b/examples/rp235x/src/bin/ethernet_w5500_icmp_ping.rs @@ -12,8 +12,8 @@ use core::str::FromStr; use defmt::*; use embassy_executor::Spawner; use embassy_futures::yield_now; -use embassy_net::icmp::ping::{PingManager, PingParams}; use embassy_net::icmp::PacketMetadata; +use embassy_net::icmp::ping::{PingManager, PingParams}; use embassy_net::{Ipv4Cidr, Stack, StackResources}; use embassy_net_wiznet::chip::W5500; use embassy_net_wiznet::*; @@ -99,7 +99,7 @@ async fn main(spawner: Spawner) { // Create the ping manager instance let mut ping_manager = PingManager::new(stack, &mut rx_meta, &mut rx_buffer, &mut tx_meta, &mut tx_buffer); let addr = "192.168.8.1"; // Address to ping to - // Create the PingParams with the target address + // Create the PingParams with the target address let mut ping_params = PingParams::new(Ipv4Addr::from_str(addr).unwrap()); // (optional) Set custom properties of the ping ping_params.set_payload(b"Hello, Ping!"); // custom payload diff --git a/examples/rp235x/src/bin/interrupt.rs b/examples/rp235x/src/bin/interrupt.rs index 88513180c..1b18f6931 100644 --- a/examples/rp235x/src/bin/interrupt.rs +++ b/examples/rp235x/src/bin/interrupt.rs @@ -16,8 +16,8 @@ use embassy_rp::adc::{self, Adc, Blocking}; use embassy_rp::gpio::Pull; use embassy_rp::interrupt; use embassy_rp::pwm::{Config, Pwm}; -use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex; use embassy_sync::blocking_mutex::Mutex; +use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex; use embassy_sync::channel::Channel; use embassy_time::{Duration, Ticker}; use portable_atomic::{AtomicU32, Ordering}; diff --git a/examples/rp235x/src/bin/multicore.rs b/examples/rp235x/src/bin/multicore.rs index 4f82801d6..9b61fdbca 100644 --- a/examples/rp235x/src/bin/multicore.rs +++ b/examples/rp235x/src/bin/multicore.rs @@ -8,7 +8,7 @@ use defmt::*; use embassy_executor::Executor; use embassy_rp::gpio::{Level, Output}; -use embassy_rp::multicore::{spawn_core1, Stack}; +use embassy_rp::multicore::{Stack, spawn_core1}; use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex; use embassy_sync::channel::Channel; use embassy_time::Timer; diff --git a/examples/rp235x/src/bin/multicore_stack_overflow.rs b/examples/rp235x/src/bin/multicore_stack_overflow.rs index dba44aa23..9efe89318 100644 --- a/examples/rp235x/src/bin/multicore_stack_overflow.rs +++ b/examples/rp235x/src/bin/multicore_stack_overflow.rs @@ -6,7 +6,7 @@ use defmt::*; use embassy_executor::Executor; use embassy_rp::gpio::{Level, Output}; -use embassy_rp::multicore::{spawn_core1, Stack}; +use embassy_rp::multicore::{Stack, spawn_core1}; use embassy_time::Timer; use static_cell::StaticCell; use {defmt_rtt as _, panic_probe as _}; diff --git a/examples/rp235x/src/bin/multiprio.rs b/examples/rp235x/src/bin/multiprio.rs index 0750d9bb7..310047505 100644 --- a/examples/rp235x/src/bin/multiprio.rs +++ b/examples/rp235x/src/bin/multiprio.rs @@ -61,7 +61,7 @@ use defmt::{info, unwrap}; use embassy_executor::{Executor, InterruptExecutor}; use embassy_rp::interrupt; use embassy_rp::interrupt::{InterruptExt, Priority}; -use embassy_time::{Instant, Timer, TICK_HZ}; +use embassy_time::{Instant, TICK_HZ, Timer}; use static_cell::StaticCell; use {defmt_rtt as _, panic_probe as _}; diff --git a/examples/rp235x/src/bin/overclock.rs b/examples/rp235x/src/bin/overclock.rs index 5fd97ef97..cba137f3a 100644 --- a/examples/rp235x/src/bin/overclock.rs +++ b/examples/rp235x/src/bin/overclock.rs @@ -12,7 +12,7 @@ use defmt::*; use embassy_executor::Spawner; -use embassy_rp::clocks::{clk_sys_freq, core_voltage, ClockConfig, CoreVoltage}; +use embassy_rp::clocks::{ClockConfig, CoreVoltage, clk_sys_freq, core_voltage}; use embassy_rp::config::Config; use embassy_rp::gpio::{Level, Output}; use embassy_time::{Duration, Instant, Timer}; diff --git a/examples/rp235x/src/bin/pio_async.rs b/examples/rp235x/src/bin/pio_async.rs index d76930f5c..a392fe37e 100644 --- a/examples/rp235x/src/bin/pio_async.rs +++ b/examples/rp235x/src/bin/pio_async.rs @@ -7,7 +7,7 @@ use embassy_executor::Spawner; use embassy_rp::peripherals::PIO0; use embassy_rp::pio::program::pio_asm; use embassy_rp::pio::{Common, Config, InterruptHandler, Irq, Pio, PioPin, ShiftDirection, StateMachine}; -use embassy_rp::{bind_interrupts, Peri}; +use embassy_rp::{Peri, bind_interrupts}; use fixed::traits::ToFixed; use fixed_macro::types::U56F8; use {defmt_rtt as _, panic_probe as _}; diff --git a/examples/rp235x/src/bin/pio_i2s_rx.rs b/examples/rp235x/src/bin/pio_i2s_rx.rs index c3f505b13..6735c402f 100644 --- a/examples/rp235x/src/bin/pio_i2s_rx.rs +++ b/examples/rp235x/src/bin/pio_i2s_rx.rs @@ -34,7 +34,7 @@ const SAMPLE_RATE: u32 = 48_000; const BIT_DEPTH: u32 = 16; const CHANNELS: u32 = 2; const USE_ONBOARD_PULLDOWN: bool = false; // whether or not to use the onboard pull-down resistor, - // which has documented issues on many RP235x boards +// which has documented issues on many RP235x boards #[embassy_executor::main] async fn main(_spawner: Spawner) { let p = embassy_rp::init(Default::default()); diff --git a/examples/rp235x/src/bin/pio_rotary_encoder_rxf.rs b/examples/rp235x/src/bin/pio_rotary_encoder_rxf.rs index 61af94560..948699e40 100644 --- a/examples/rp235x/src/bin/pio_rotary_encoder_rxf.rs +++ b/examples/rp235x/src/bin/pio_rotary_encoder_rxf.rs @@ -9,7 +9,7 @@ use embassy_executor::Spawner; use embassy_rp::gpio::Pull; use embassy_rp::peripherals::PIO0; use embassy_rp::pio::program::pio_asm; -use embassy_rp::{bind_interrupts, pio, Peri}; +use embassy_rp::{Peri, bind_interrupts, pio}; use embassy_time::Timer; use fixed::traits::ToFixed; use pio::{Common, Config, FifoJoin, Instance, InterruptHandler, Pio, PioPin, ShiftDirection, StateMachine}; diff --git a/examples/rp235x/src/bin/pio_stepper.rs b/examples/rp235x/src/bin/pio_stepper.rs index 931adbeda..9b33710ad 100644 --- a/examples/rp235x/src/bin/pio_stepper.rs +++ b/examples/rp235x/src/bin/pio_stepper.rs @@ -10,7 +10,7 @@ use embassy_rp::bind_interrupts; use embassy_rp::peripherals::PIO0; use embassy_rp::pio::{InterruptHandler, Pio}; use embassy_rp::pio_programs::stepper::{PioStepper, PioStepperProgram}; -use embassy_time::{with_timeout, Duration, Timer}; +use embassy_time::{Duration, Timer, with_timeout}; use {defmt_rtt as _, panic_probe as _}; bind_interrupts!(struct Irqs { diff --git a/examples/rp235x/src/bin/pwm.rs b/examples/rp235x/src/bin/pwm.rs index 289480c85..971e86aa7 100644 --- a/examples/rp235x/src/bin/pwm.rs +++ b/examples/rp235x/src/bin/pwm.rs @@ -9,9 +9,9 @@ use defmt::*; use embassy_executor::Spawner; -use embassy_rp::peripherals::{PIN_25, PIN_4, PWM_SLICE2, PWM_SLICE4}; -use embassy_rp::pwm::{Config, Pwm, SetDutyCycle}; use embassy_rp::Peri; +use embassy_rp::peripherals::{PIN_4, PIN_25, PWM_SLICE2, PWM_SLICE4}; +use embassy_rp::pwm::{Config, Pwm, SetDutyCycle}; use embassy_time::Timer; use {defmt_rtt as _, panic_probe as _}; diff --git a/examples/rp235x/src/bin/pwm_tb6612fng_motor_driver.rs b/examples/rp235x/src/bin/pwm_tb6612fng_motor_driver.rs index 2cfb2038d..670f302a4 100644 --- a/examples/rp235x/src/bin/pwm_tb6612fng_motor_driver.rs +++ b/examples/rp235x/src/bin/pwm_tb6612fng_motor_driver.rs @@ -10,7 +10,7 @@ use defmt::*; use embassy_executor::Spawner; use embassy_rp::config::Config; use embassy_rp::gpio::Output; -use embassy_rp::{gpio, peripherals, pwm, Peri}; +use embassy_rp::{Peri, gpio, peripherals, pwm}; use embassy_time::{Duration, Timer}; use tb6612fng::{DriveCommand, Motor, Tb6612fng}; use {defmt_rtt as _, panic_probe as _}; diff --git a/examples/rp235x/src/bin/spi_display.rs b/examples/rp235x/src/bin/spi_display.rs index 9967abefd..3cef93f62 100644 --- a/examples/rp235x/src/bin/spi_display.rs +++ b/examples/rp235x/src/bin/spi_display.rs @@ -15,19 +15,19 @@ use embassy_executor::Spawner; use embassy_rp::gpio::{Level, Output}; use embassy_rp::spi; use embassy_rp::spi::{Blocking, Spi}; -use embassy_sync::blocking_mutex::raw::NoopRawMutex; use embassy_sync::blocking_mutex::Mutex; +use embassy_sync::blocking_mutex::raw::NoopRawMutex; use embassy_time::Delay; use embedded_graphics::image::{Image, ImageRawLE}; -use embedded_graphics::mono_font::ascii::FONT_10X20; use embedded_graphics::mono_font::MonoTextStyle; +use embedded_graphics::mono_font::ascii::FONT_10X20; use embedded_graphics::pixelcolor::Rgb565; use embedded_graphics::prelude::*; use embedded_graphics::primitives::{PrimitiveStyleBuilder, Rectangle}; use embedded_graphics::text::Text; +use mipidsi::Builder; use mipidsi::models::ST7789; use mipidsi::options::{Orientation, Rotation}; -use mipidsi::Builder; use {defmt_rtt as _, panic_probe as _}; use crate::touch::Touch; @@ -167,11 +167,7 @@ mod touch { let x = ((x - cal.x1) * cal.sx / (cal.x2 - cal.x1)).clamp(0, cal.sx); let y = ((y - cal.y1) * cal.sy / (cal.y2 - cal.y1)).clamp(0, cal.sy); - if x == 0 && y == 0 { - None - } else { - Some((x, y)) - } + if x == 0 && y == 0 { None } else { Some((x, y)) } } } } diff --git a/examples/rp235x/src/bin/uart_r503.rs b/examples/rp235x/src/bin/uart_r503.rs index 085be280b..a25d45b18 100644 --- a/examples/rp235x/src/bin/uart_r503.rs +++ b/examples/rp235x/src/bin/uart_r503.rs @@ -6,7 +6,7 @@ use embassy_executor::Spawner; use embassy_rp::bind_interrupts; use embassy_rp::peripherals::UART0; use embassy_rp::uart::{Config, DataBits, InterruptHandler as UARTInterruptHandler, Parity, StopBits, Uart}; -use embassy_time::{with_timeout, Duration, Timer}; +use embassy_time::{Duration, Timer, with_timeout}; use heapless::Vec; use {defmt_rtt as _, panic_probe as _}; diff --git a/examples/rp235x/src/bin/zerocopy.rs b/examples/rp235x/src/bin/zerocopy.rs index 62ba4cfb8..55deffd5f 100644 --- a/examples/rp235x/src/bin/zerocopy.rs +++ b/examples/rp235x/src/bin/zerocopy.rs @@ -11,7 +11,7 @@ use embassy_executor::Spawner; use embassy_rp::adc::{self, Adc, Async, Config, InterruptHandler}; use embassy_rp::gpio::Pull; use embassy_rp::peripherals::DMA_CH0; -use embassy_rp::{bind_interrupts, Peri}; +use embassy_rp::{Peri, bind_interrupts}; use embassy_sync::blocking_mutex::raw::NoopRawMutex; use embassy_sync::zerocopy_channel::{Channel, Receiver, Sender}; use embassy_time::{Duration, Ticker, Timer}; diff --git a/examples/stm32c0/src/bin/rtc.rs b/examples/stm32c0/src/bin/rtc.rs index 82d8a37ba..feb27f6d9 100644 --- a/examples/stm32c0/src/bin/rtc.rs +++ b/examples/stm32c0/src/bin/rtc.rs @@ -4,8 +4,8 @@ use chrono::{NaiveDate, NaiveDateTime}; use defmt::*; use embassy_executor::Spawner; -use embassy_stm32::rtc::{Rtc, RtcConfig}; use embassy_stm32::Config; +use embassy_stm32::rtc::{Rtc, RtcConfig}; use embassy_time::Timer; use {defmt_rtt as _, panic_probe as _}; diff --git a/examples/stm32f0/src/bin/button_controlled_blink.rs b/examples/stm32f0/src/bin/button_controlled_blink.rs index f232e3290..0b678af01 100644 --- a/examples/stm32f0/src/bin/button_controlled_blink.rs +++ b/examples/stm32f0/src/bin/button_controlled_blink.rs @@ -7,9 +7,9 @@ use core::sync::atomic::{AtomicU32, Ordering}; use defmt::info; use embassy_executor::Spawner; +use embassy_stm32::Peri; use embassy_stm32::exti::ExtiInput; use embassy_stm32::gpio::{AnyPin, Level, Output, Pull, Speed}; -use embassy_stm32::Peri; use embassy_time::Timer; use {defmt_rtt as _, panic_probe as _}; diff --git a/examples/stm32f1/src/bin/can.rs b/examples/stm32f1/src/bin/can.rs index ad0c8a5a5..cbe13b206 100644 --- a/examples/stm32f1/src/bin/can.rs +++ b/examples/stm32f1/src/bin/can.rs @@ -5,11 +5,11 @@ use defmt::*; use embassy_executor::Spawner; use embassy_stm32::can::frame::Envelope; use embassy_stm32::can::{ - filter, Can, Fifo, Frame, Id, Rx0InterruptHandler, Rx1InterruptHandler, SceInterruptHandler, StandardId, - TxInterruptHandler, + Can, Fifo, Frame, Id, Rx0InterruptHandler, Rx1InterruptHandler, SceInterruptHandler, StandardId, + TxInterruptHandler, filter, }; use embassy_stm32::peripherals::CAN; -use embassy_stm32::{bind_interrupts, Config}; +use embassy_stm32::{Config, bind_interrupts}; use static_cell::StaticCell; use {defmt_rtt as _, panic_probe as _}; diff --git a/examples/stm32f1/src/bin/input_capture.rs b/examples/stm32f1/src/bin/input_capture.rs index b5b26938d..6232d8c17 100644 --- a/examples/stm32f1/src/bin/input_capture.rs +++ b/examples/stm32f1/src/bin/input_capture.rs @@ -7,7 +7,7 @@ use embassy_stm32::gpio::{AfioRemap, Level, Output, Pull, Speed}; use embassy_stm32::time::khz; use embassy_stm32::timer::input_capture::{CapturePin, InputCapture}; use embassy_stm32::timer::{self, Channel}; -use embassy_stm32::{bind_interrupts, peripherals, Peri}; +use embassy_stm32::{Peri, bind_interrupts, peripherals}; use embassy_time::Timer; use {defmt_rtt as _, panic_probe as _}; diff --git a/examples/stm32f1/src/bin/pwm_input.rs b/examples/stm32f1/src/bin/pwm_input.rs index 9ae747018..136c5c555 100644 --- a/examples/stm32f1/src/bin/pwm_input.rs +++ b/examples/stm32f1/src/bin/pwm_input.rs @@ -6,7 +6,7 @@ use embassy_executor::Spawner; use embassy_stm32::gpio::{AfioRemap, Level, Output, Pull, Speed}; use embassy_stm32::time::khz; use embassy_stm32::timer::pwm_input::PwmInput; -use embassy_stm32::{bind_interrupts, peripherals, timer, Peri}; +use embassy_stm32::{Peri, bind_interrupts, peripherals, timer}; use embassy_time::Timer; use {defmt_rtt as _, panic_probe as _}; diff --git a/examples/stm32f1/src/bin/usb_serial.rs b/examples/stm32f1/src/bin/usb_serial.rs index 77ec307b9..5ff54a521 100644 --- a/examples/stm32f1/src/bin/usb_serial.rs +++ b/examples/stm32f1/src/bin/usb_serial.rs @@ -7,11 +7,11 @@ use embassy_futures::join::join; use embassy_stm32::gpio::{Level, Output, Speed}; use embassy_stm32::time::Hertz; use embassy_stm32::usb::{Driver, Instance}; -use embassy_stm32::{bind_interrupts, peripherals, usb, Config}; +use embassy_stm32::{Config, bind_interrupts, peripherals, usb}; use embassy_time::Timer; +use embassy_usb::Builder; use embassy_usb::class::cdc_acm::{CdcAcmClass, State}; use embassy_usb::driver::EndpointError; -use embassy_usb::Builder; use {defmt_rtt as _, panic_probe as _}; bind_interrupts!(struct Irqs { diff --git a/examples/stm32f2/src/bin/pll.rs b/examples/stm32f2/src/bin/pll.rs index e39e2daec..4418bf502 100644 --- a/examples/stm32f2/src/bin/pll.rs +++ b/examples/stm32f2/src/bin/pll.rs @@ -3,8 +3,8 @@ use defmt::*; use embassy_executor::Spawner; -use embassy_stm32::time::Hertz; use embassy_stm32::Config; +use embassy_stm32::time::Hertz; use embassy_time::Timer; use {defmt_rtt as _, panic_probe as _}; diff --git a/examples/stm32f3/src/bin/button_events.rs b/examples/stm32f3/src/bin/button_events.rs index a54d03212..99957a641 100644 --- a/examples/stm32f3/src/bin/button_events.rs +++ b/examples/stm32f3/src/bin/button_events.rs @@ -15,7 +15,7 @@ use embassy_stm32::exti::ExtiInput; use embassy_stm32::gpio::{Level, Output, Pull, Speed}; use embassy_sync::blocking_mutex::raw::ThreadModeRawMutex; use embassy_sync::channel::Channel; -use embassy_time::{with_timeout, Duration, Timer}; +use embassy_time::{Duration, Timer, with_timeout}; use {defmt_rtt as _, panic_probe as _}; struct Leds<'a> { diff --git a/examples/stm32f3/src/bin/usb_serial.rs b/examples/stm32f3/src/bin/usb_serial.rs index 5760f2c1c..58b801c36 100644 --- a/examples/stm32f3/src/bin/usb_serial.rs +++ b/examples/stm32f3/src/bin/usb_serial.rs @@ -7,11 +7,11 @@ use embassy_futures::join::join; use embassy_stm32::gpio::{Level, Output, Speed}; use embassy_stm32::time::mhz; use embassy_stm32::usb::{Driver, Instance}; -use embassy_stm32::{bind_interrupts, peripherals, usb, Config}; +use embassy_stm32::{Config, bind_interrupts, peripherals, usb}; use embassy_time::Timer; +use embassy_usb::Builder; use embassy_usb::class::cdc_acm::{CdcAcmClass, State}; use embassy_usb::driver::EndpointError; -use embassy_usb::Builder; use {defmt_rtt as _, panic_probe as _}; bind_interrupts!(struct Irqs { diff --git a/examples/stm32f334/src/bin/adc.rs b/examples/stm32f334/src/bin/adc.rs index 0528a9637..a993b00ca 100644 --- a/examples/stm32f334/src/bin/adc.rs +++ b/examples/stm32f334/src/bin/adc.rs @@ -6,7 +6,7 @@ use embassy_executor::Spawner; use embassy_stm32::adc::{Adc, SampleTime}; use embassy_stm32::peripherals::ADC1; use embassy_stm32::time::mhz; -use embassy_stm32::{adc, bind_interrupts, Config}; +use embassy_stm32::{Config, adc, bind_interrupts}; use embassy_time::Timer; use {defmt_rtt as _, panic_probe as _}; diff --git a/examples/stm32f334/src/bin/opamp.rs b/examples/stm32f334/src/bin/opamp.rs index c344935d7..3e621f2a1 100644 --- a/examples/stm32f334/src/bin/opamp.rs +++ b/examples/stm32f334/src/bin/opamp.rs @@ -7,7 +7,7 @@ use embassy_stm32::adc::{Adc, SampleTime}; use embassy_stm32::opamp::OpAmp; use embassy_stm32::peripherals::ADC2; use embassy_stm32::time::mhz; -use embassy_stm32::{adc, bind_interrupts, Config}; +use embassy_stm32::{Config, adc, bind_interrupts}; use embassy_time::Timer; use {defmt_rtt as _, panic_probe as _}; diff --git a/examples/stm32f334/src/bin/pwm.rs b/examples/stm32f334/src/bin/pwm.rs index 2b0686121..68a61ae22 100644 --- a/examples/stm32f334/src/bin/pwm.rs +++ b/examples/stm32f334/src/bin/pwm.rs @@ -3,9 +3,9 @@ use defmt::*; use embassy_executor::Spawner; +use embassy_stm32::Config; use embassy_stm32::hrtim::*; use embassy_stm32::time::{khz, mhz}; -use embassy_stm32::Config; use embassy_time::Timer; use {defmt_rtt as _, panic_probe as _}; diff --git a/examples/stm32f4/src/bin/adc_dma.rs b/examples/stm32f4/src/bin/adc_dma.rs index 2ec48640e..c24f01753 100644 --- a/examples/stm32f4/src/bin/adc_dma.rs +++ b/examples/stm32f4/src/bin/adc_dma.rs @@ -3,8 +3,8 @@ use cortex_m::singleton; use defmt::*; use embassy_executor::Spawner; -use embassy_stm32::adc::{Adc, RingBufferedAdc, SampleTime, Sequence}; use embassy_stm32::Peripherals; +use embassy_stm32::adc::{Adc, RingBufferedAdc, SampleTime, Sequence}; use embassy_time::Instant; use {defmt_rtt as _, panic_probe as _}; diff --git a/examples/stm32f4/src/bin/eth.rs b/examples/stm32f4/src/bin/eth.rs index f41a60529..2d72b6b0b 100644 --- a/examples/stm32f4/src/bin/eth.rs +++ b/examples/stm32f4/src/bin/eth.rs @@ -9,7 +9,7 @@ use embassy_stm32::eth::{Ethernet, GenericPhy, PacketQueue}; use embassy_stm32::peripherals::ETH; use embassy_stm32::rng::Rng; use embassy_stm32::time::Hertz; -use embassy_stm32::{bind_interrupts, eth, peripherals, rng, Config}; +use embassy_stm32::{Config, bind_interrupts, eth, peripherals, rng}; use embassy_time::Timer; use embedded_io_async::Write; use static_cell::StaticCell; diff --git a/examples/stm32f4/src/bin/eth_compliance_test.rs b/examples/stm32f4/src/bin/eth_compliance_test.rs index 52f9d57f6..734a14c2c 100644 --- a/examples/stm32f4/src/bin/eth_compliance_test.rs +++ b/examples/stm32f4/src/bin/eth_compliance_test.rs @@ -5,7 +5,7 @@ use defmt::*; use embassy_executor::Spawner; use embassy_stm32::eth::{Ethernet, GenericPhy, PacketQueue, StationManagement}; use embassy_stm32::time::Hertz; -use embassy_stm32::{bind_interrupts, eth, peripherals, rng, Config}; +use embassy_stm32::{Config, bind_interrupts, eth, peripherals, rng}; use embassy_time::Timer; use static_cell::StaticCell; use {defmt_rtt as _, panic_probe as _}; diff --git a/examples/stm32f4/src/bin/eth_w5500.rs b/examples/stm32f4/src/bin/eth_w5500.rs index 7ce3bfe75..cccf20949 100644 --- a/examples/stm32f4/src/bin/eth_w5500.rs +++ b/examples/stm32f4/src/bin/eth_w5500.rs @@ -13,7 +13,7 @@ use embassy_stm32::mode::Async; use embassy_stm32::rng::Rng; use embassy_stm32::spi::Spi; use embassy_stm32::time::Hertz; -use embassy_stm32::{bind_interrupts, peripherals, rng, spi, Config}; +use embassy_stm32::{Config, bind_interrupts, peripherals, rng, spi}; use embassy_time::{Delay, Timer}; use embedded_hal_bus::spi::ExclusiveDevice; use embedded_io_async::Write; diff --git a/examples/stm32f4/src/bin/flash_async.rs b/examples/stm32f4/src/bin/flash_async.rs index 2feb9de09..14f029747 100644 --- a/examples/stm32f4/src/bin/flash_async.rs +++ b/examples/stm32f4/src/bin/flash_async.rs @@ -5,7 +5,7 @@ use defmt::{info, unwrap}; use embassy_executor::Spawner; use embassy_stm32::flash::{Flash, InterruptHandler}; use embassy_stm32::gpio::{AnyPin, Level, Output, Speed}; -use embassy_stm32::{bind_interrupts, Peri}; +use embassy_stm32::{Peri, bind_interrupts}; use embassy_time::Timer; use {defmt_rtt as _, panic_probe as _}; diff --git a/examples/stm32f4/src/bin/input_capture.rs b/examples/stm32f4/src/bin/input_capture.rs index 9998c4733..3ff96584d 100644 --- a/examples/stm32f4/src/bin/input_capture.rs +++ b/examples/stm32f4/src/bin/input_capture.rs @@ -7,7 +7,7 @@ use embassy_stm32::gpio::{Level, Output, Pull, Speed}; use embassy_stm32::time::khz; use embassy_stm32::timer::input_capture::{CapturePin, InputCapture}; use embassy_stm32::timer::{self, Channel}; -use embassy_stm32::{bind_interrupts, peripherals, Peri}; +use embassy_stm32::{Peri, bind_interrupts, peripherals}; use embassy_time::Timer; use {defmt_rtt as _, panic_probe as _}; diff --git a/examples/stm32f4/src/bin/pwm_complementary.rs b/examples/stm32f4/src/bin/pwm_complementary.rs index c981f1a76..50008a37b 100644 --- a/examples/stm32f4/src/bin/pwm_complementary.rs +++ b/examples/stm32f4/src/bin/pwm_complementary.rs @@ -5,9 +5,9 @@ use defmt::*; use embassy_executor::Spawner; use embassy_stm32::gpio::OutputType; use embassy_stm32::time::khz; +use embassy_stm32::timer::Channel; use embassy_stm32::timer::complementary_pwm::{ComplementaryPwm, ComplementaryPwmPin}; use embassy_stm32::timer::simple_pwm::PwmPin; -use embassy_stm32::timer::Channel; use embassy_time::Timer; use {defmt_rtt as _, panic_probe as _}; diff --git a/examples/stm32f4/src/bin/pwm_input.rs b/examples/stm32f4/src/bin/pwm_input.rs index e8bfa524f..d8ea56a34 100644 --- a/examples/stm32f4/src/bin/pwm_input.rs +++ b/examples/stm32f4/src/bin/pwm_input.rs @@ -6,7 +6,7 @@ use embassy_executor::Spawner; use embassy_stm32::gpio::{Level, Output, Pull, Speed}; use embassy_stm32::time::khz; use embassy_stm32::timer::pwm_input::PwmInput; -use embassy_stm32::{bind_interrupts, peripherals, timer, Peri}; +use embassy_stm32::{Peri, bind_interrupts, peripherals, timer}; use embassy_time::Timer; use {defmt_rtt as _, panic_probe as _}; diff --git a/examples/stm32f4/src/bin/rtc.rs b/examples/stm32f4/src/bin/rtc.rs index 82d8a37ba..feb27f6d9 100644 --- a/examples/stm32f4/src/bin/rtc.rs +++ b/examples/stm32f4/src/bin/rtc.rs @@ -4,8 +4,8 @@ use chrono::{NaiveDate, NaiveDateTime}; use defmt::*; use embassy_executor::Spawner; -use embassy_stm32::rtc::{Rtc, RtcConfig}; use embassy_stm32::Config; +use embassy_stm32::rtc::{Rtc, RtcConfig}; use embassy_time::Timer; use {defmt_rtt as _, panic_probe as _}; diff --git a/examples/stm32f4/src/bin/sdmmc.rs b/examples/stm32f4/src/bin/sdmmc.rs index e97b63925..fe0f887bf 100644 --- a/examples/stm32f4/src/bin/sdmmc.rs +++ b/examples/stm32f4/src/bin/sdmmc.rs @@ -4,8 +4,8 @@ use defmt::*; use embassy_executor::Spawner; use embassy_stm32::sdmmc::{DataBlock, Sdmmc}; -use embassy_stm32::time::{mhz, Hertz}; -use embassy_stm32::{bind_interrupts, peripherals, sdmmc, Config}; +use embassy_stm32::time::{Hertz, mhz}; +use embassy_stm32::{Config, bind_interrupts, peripherals, sdmmc}; use {defmt_rtt as _, panic_probe as _}; /// This is a safeguard to not overwrite any data on the SD card. diff --git a/examples/stm32f4/src/bin/usb_ethernet.rs b/examples/stm32f4/src/bin/usb_ethernet.rs index 7abbe8719..a5e625edd 100644 --- a/examples/stm32f4/src/bin/usb_ethernet.rs +++ b/examples/stm32f4/src/bin/usb_ethernet.rs @@ -3,12 +3,12 @@ use defmt::*; use embassy_executor::Spawner; -use embassy_net::tcp::TcpSocket; use embassy_net::StackResources; +use embassy_net::tcp::TcpSocket; use embassy_stm32::rng::{self, Rng}; use embassy_stm32::time::Hertz; use embassy_stm32::usb::Driver; -use embassy_stm32::{bind_interrupts, peripherals, usb, Config}; +use embassy_stm32::{Config, bind_interrupts, peripherals, usb}; use embassy_usb::class::cdc_ncm::embassy_net::{Device, Runner, State as NetState}; use embassy_usb::class::cdc_ncm::{CdcNcmClass, State}; use embassy_usb::{Builder, UsbDevice}; diff --git a/examples/stm32f4/src/bin/usb_hid_keyboard.rs b/examples/stm32f4/src/bin/usb_hid_keyboard.rs index d6b4a9bc9..a3afb887c 100644 --- a/examples/stm32f4/src/bin/usb_hid_keyboard.rs +++ b/examples/stm32f4/src/bin/usb_hid_keyboard.rs @@ -10,7 +10,7 @@ use embassy_stm32::exti::ExtiInput; use embassy_stm32::gpio::Pull; use embassy_stm32::time::Hertz; use embassy_stm32::usb::Driver; -use embassy_stm32::{bind_interrupts, peripherals, usb, Config}; +use embassy_stm32::{Config, bind_interrupts, peripherals, usb}; use embassy_usb::class::hid::{HidReaderWriter, ReportId, RequestHandler, State}; use embassy_usb::control::OutResponse; use embassy_usb::{Builder, Handler}; diff --git a/examples/stm32f4/src/bin/usb_hid_mouse.rs b/examples/stm32f4/src/bin/usb_hid_mouse.rs index badb65e98..162a035f2 100644 --- a/examples/stm32f4/src/bin/usb_hid_mouse.rs +++ b/examples/stm32f4/src/bin/usb_hid_mouse.rs @@ -6,11 +6,11 @@ use embassy_executor::Spawner; use embassy_futures::join::join; use embassy_stm32::time::Hertz; use embassy_stm32::usb::Driver; -use embassy_stm32::{bind_interrupts, peripherals, usb, Config}; +use embassy_stm32::{Config, bind_interrupts, peripherals, usb}; use embassy_time::Timer; +use embassy_usb::Builder; use embassy_usb::class::hid::{HidWriter, ReportId, RequestHandler, State}; use embassy_usb::control::OutResponse; -use embassy_usb::Builder; use usbd_hid::descriptor::{MouseReport, SerializedDescriptor}; use {defmt_rtt as _, panic_probe as _}; diff --git a/examples/stm32f4/src/bin/usb_raw.rs b/examples/stm32f4/src/bin/usb_raw.rs index bbbcc082b..511f0b281 100644 --- a/examples/stm32f4/src/bin/usb_raw.rs +++ b/examples/stm32f4/src/bin/usb_raw.rs @@ -53,7 +53,7 @@ use defmt::*; use embassy_executor::Spawner; use embassy_stm32::time::Hertz; use embassy_stm32::usb::Driver; -use embassy_stm32::{bind_interrupts, peripherals, usb, Config}; +use embassy_stm32::{Config, bind_interrupts, peripherals, usb}; use embassy_usb::control::{InResponse, OutResponse, Recipient, Request, RequestType}; use embassy_usb::msos::{self, windows_version}; use embassy_usb::types::InterfaceNumber; diff --git a/examples/stm32f4/src/bin/usb_serial.rs b/examples/stm32f4/src/bin/usb_serial.rs index e62b2d8d6..2e81e0a59 100644 --- a/examples/stm32f4/src/bin/usb_serial.rs +++ b/examples/stm32f4/src/bin/usb_serial.rs @@ -6,10 +6,10 @@ use embassy_executor::Spawner; use embassy_futures::join::join; use embassy_stm32::time::Hertz; use embassy_stm32::usb::{Driver, Instance}; -use embassy_stm32::{bind_interrupts, peripherals, usb, Config}; +use embassy_stm32::{Config, bind_interrupts, peripherals, usb}; +use embassy_usb::Builder; use embassy_usb::class::cdc_acm::{CdcAcmClass, State}; use embassy_usb::driver::EndpointError; -use embassy_usb::Builder; use {defmt_rtt as _, panic_probe as _}; bind_interrupts!(struct Irqs { diff --git a/examples/stm32f4/src/bin/usb_uac_speaker.rs b/examples/stm32f4/src/bin/usb_uac_speaker.rs index 79bd2d914..b92f4531e 100644 --- a/examples/stm32f4/src/bin/usb_uac_speaker.rs +++ b/examples/stm32f4/src/bin/usb_uac_speaker.rs @@ -6,9 +6,9 @@ use core::cell::{Cell, RefCell}; use defmt::{panic, *}; use embassy_executor::Spawner; use embassy_stm32::time::Hertz; -use embassy_stm32::{bind_interrupts, interrupt, peripherals, timer, usb, Config}; -use embassy_sync::blocking_mutex::raw::{CriticalSectionRawMutex, NoopRawMutex}; +use embassy_stm32::{Config, bind_interrupts, interrupt, peripherals, timer, usb}; use embassy_sync::blocking_mutex::Mutex; +use embassy_sync::blocking_mutex::raw::{CriticalSectionRawMutex, NoopRawMutex}; use embassy_sync::signal::Signal; use embassy_sync::zerocopy_channel; use embassy_usb::class::uac1; diff --git a/examples/stm32f4/src/bin/ws2812_pwm.rs b/examples/stm32f4/src/bin/ws2812_pwm.rs index 5153e1cfd..ccfd0661e 100644 --- a/examples/stm32f4/src/bin/ws2812_pwm.rs +++ b/examples/stm32f4/src/bin/ws2812_pwm.rs @@ -15,9 +15,9 @@ use embassy_executor::Spawner; use embassy_stm32::gpio::OutputType; use embassy_stm32::time::khz; +use embassy_stm32::timer::Channel; use embassy_stm32::timer::low_level::CountingMode; use embassy_stm32::timer::simple_pwm::{PwmPin, SimplePwm}; -use embassy_stm32::timer::Channel; use embassy_time::{Duration, Ticker, Timer}; use {defmt_rtt as _, panic_probe as _}; diff --git a/examples/stm32f469/src/bin/dsi_bsp.rs b/examples/stm32f469/src/bin/dsi_bsp.rs index 3a24d5dcf..d659291ff 100644 --- a/examples/stm32f469/src/bin/dsi_bsp.rs +++ b/examples/stm32f469/src/bin/dsi_bsp.rs @@ -3,7 +3,7 @@ use defmt::*; use embassy_executor::Spawner; -use embassy_stm32::dsihost::{blocking_delay_ms, DsiHost, PacketType}; +use embassy_stm32::dsihost::{DsiHost, PacketType, blocking_delay_ms}; use embassy_stm32::gpio::{Level, Output, Speed}; use embassy_stm32::ltdc::Ltdc; use embassy_stm32::pac::dsihost::regs::{Ier0, Ier1}; @@ -211,7 +211,7 @@ async fn main(_spawner: Spawner) { const HORIZONTAL_SYNC_ACTIVE: u16 = 4; // ((HSA as u32 * LANE_BYTE_CLK_K_HZ as u32 ) / LCD_CLOCK as u32 ) as u16; const HORIZONTAL_BACK_PORCH: u16 = 77; //((HBP as u32 * LANE_BYTE_CLK_K_HZ as u32 ) / LCD_CLOCK as u32) as u16; const HORIZONTAL_LINE: u16 = 1982; //(((HACT + HSA + HBP + HFP) as u32 * LANE_BYTE_CLK_K_HZ as u32 ) / LCD_CLOCK as u32 ) as u16; /* Value depending on display orientation choice portrait/landscape */ - // FIXME: Make depend on orientation + // FIXME: Make depend on orientation const VERTICAL_SYNC_ACTIVE: u16 = VSA; const VERTICAL_BACK_PORCH: u16 = VBP; const VERTICAL_FRONT_PORCH: u16 = VFP; @@ -658,7 +658,7 @@ const NT35510_RASET_LANDSCAPE: &[u8] = &[NT35510_CMD_RASET, 0x00, 0x00, 0x01, 0x const NT35510_WRITES_26: &[u8] = &[NT35510_CMD_TEEON, 0x00]; // Tear on const NT35510_WRITES_27: &[u8] = &[NT35510_CMD_SLPOUT, 0x00]; // Sleep out - // 28,29 missing +// 28,29 missing const NT35510_WRITES_30: &[u8] = &[NT35510_CMD_DISPON, 0x00]; // Display on const NT35510_WRITES_31: &[u8] = &[NT35510_CMD_WRDISBV, 0x7F]; diff --git a/examples/stm32f7/src/bin/can.rs b/examples/stm32f7/src/bin/can.rs index 9a91ac814..2f3f6db84 100644 --- a/examples/stm32f7/src/bin/can.rs +++ b/examples/stm32f7/src/bin/can.rs @@ -1,7 +1,7 @@ #![no_std] #![no_main] -use core::num::{NonZeroU16, NonZeroU8}; +use core::num::{NonZeroU8, NonZeroU16}; use defmt::*; use embassy_executor::Spawner; diff --git a/examples/stm32f7/src/bin/cryp.rs b/examples/stm32f7/src/bin/cryp.rs index a31e9b4f2..9ccef0b82 100644 --- a/examples/stm32f7/src/bin/cryp.rs +++ b/examples/stm32f7/src/bin/cryp.rs @@ -1,13 +1,13 @@ #![no_std] #![no_main] +use aes_gcm::Aes128Gcm; use aes_gcm::aead::heapless::Vec; use aes_gcm::aead::{AeadInPlace, KeyInit}; -use aes_gcm::Aes128Gcm; use defmt::info; use embassy_executor::Spawner; use embassy_stm32::cryp::{self, *}; -use embassy_stm32::{bind_interrupts, peripherals, Config}; +use embassy_stm32::{Config, bind_interrupts, peripherals}; use embassy_time::Instant; use {defmt_rtt as _, panic_probe as _}; diff --git a/examples/stm32f7/src/bin/eth.rs b/examples/stm32f7/src/bin/eth.rs index b13b7bdda..f8a129239 100644 --- a/examples/stm32f7/src/bin/eth.rs +++ b/examples/stm32f7/src/bin/eth.rs @@ -9,7 +9,7 @@ use embassy_stm32::eth::{Ethernet, GenericPhy, PacketQueue}; use embassy_stm32::peripherals::ETH; use embassy_stm32::rng::Rng; use embassy_stm32::time::Hertz; -use embassy_stm32::{bind_interrupts, eth, peripherals, rng, Config}; +use embassy_stm32::{Config, bind_interrupts, eth, peripherals, rng}; use embassy_time::Timer; use embedded_io_async::Write; use static_cell::StaticCell; diff --git a/examples/stm32f7/src/bin/hash.rs b/examples/stm32f7/src/bin/hash.rs index c2d1a7158..4fd465df6 100644 --- a/examples/stm32f7/src/bin/hash.rs +++ b/examples/stm32f7/src/bin/hash.rs @@ -4,7 +4,7 @@ use defmt::info; use embassy_executor::Spawner; use embassy_stm32::hash::*; -use embassy_stm32::{bind_interrupts, hash, peripherals, Config}; +use embassy_stm32::{Config, bind_interrupts, hash, peripherals}; use embassy_time::Instant; use hmac::{Hmac, Mac}; use sha2::{Digest, Sha256}; diff --git a/examples/stm32f7/src/bin/qspi.rs b/examples/stm32f7/src/bin/qspi.rs index 80652b865..e8ef3ad81 100644 --- a/examples/stm32f7/src/bin/qspi.rs +++ b/examples/stm32f7/src/bin/qspi.rs @@ -4,11 +4,11 @@ use defmt::info; use embassy_executor::Spawner; +use embassy_stm32::Config as StmCfg; use embassy_stm32::mode::Async; use embassy_stm32::qspi::enums::{AddressSize, ChipSelectHighTime, FIFOThresholdLevel, MemorySize, *}; use embassy_stm32::qspi::{Config as QspiCfg, Instance, Qspi, TransferConfig}; use embassy_stm32::time::mhz; -use embassy_stm32::Config as StmCfg; use {defmt_rtt as _, panic_probe as _}; const MEMORY_PAGE_SIZE: usize = 256; diff --git a/examples/stm32f7/src/bin/sdmmc.rs b/examples/stm32f7/src/bin/sdmmc.rs index 787bef25e..8809b5d0c 100644 --- a/examples/stm32f7/src/bin/sdmmc.rs +++ b/examples/stm32f7/src/bin/sdmmc.rs @@ -4,8 +4,8 @@ use defmt::*; use embassy_executor::Spawner; use embassy_stm32::sdmmc::Sdmmc; -use embassy_stm32::time::{mhz, Hertz}; -use embassy_stm32::{bind_interrupts, peripherals, sdmmc, Config}; +use embassy_stm32::time::{Hertz, mhz}; +use embassy_stm32::{Config, bind_interrupts, peripherals, sdmmc}; use {defmt_rtt as _, panic_probe as _}; bind_interrupts!(struct Irqs { diff --git a/examples/stm32f7/src/bin/usb_serial.rs b/examples/stm32f7/src/bin/usb_serial.rs index 349012888..9a30b2c20 100644 --- a/examples/stm32f7/src/bin/usb_serial.rs +++ b/examples/stm32f7/src/bin/usb_serial.rs @@ -6,10 +6,10 @@ use embassy_executor::Spawner; use embassy_futures::join::join; use embassy_stm32::time::Hertz; use embassy_stm32::usb::{Driver, Instance}; -use embassy_stm32::{bind_interrupts, peripherals, usb, Config}; +use embassy_stm32::{Config, bind_interrupts, peripherals, usb}; +use embassy_usb::Builder; use embassy_usb::class::cdc_acm::{CdcAcmClass, State}; use embassy_usb::driver::EndpointError; -use embassy_usb::Builder; use {defmt_rtt as _, panic_probe as _}; bind_interrupts!(struct Irqs { diff --git a/examples/stm32g0/src/bin/hf_timer.rs b/examples/stm32g0/src/bin/hf_timer.rs index 705905f01..88ee7ea86 100644 --- a/examples/stm32g0/src/bin/hf_timer.rs +++ b/examples/stm32g0/src/bin/hf_timer.rs @@ -3,12 +3,12 @@ use defmt::info; use embassy_executor::Spawner; +use embassy_stm32::Config as PeripheralConfig; use embassy_stm32::gpio::OutputType; use embassy_stm32::time::khz; +use embassy_stm32::timer::Channel; use embassy_stm32::timer::complementary_pwm::{ComplementaryPwm, ComplementaryPwmPin}; use embassy_stm32::timer::simple_pwm::PwmPin; -use embassy_stm32::timer::Channel; -use embassy_stm32::Config as PeripheralConfig; use {defmt_rtt as _, panic_probe as _}; #[embassy_executor::main] diff --git a/examples/stm32g0/src/bin/input_capture.rs b/examples/stm32g0/src/bin/input_capture.rs index 5501a6941..ca3e8eb41 100644 --- a/examples/stm32g0/src/bin/input_capture.rs +++ b/examples/stm32g0/src/bin/input_capture.rs @@ -13,10 +13,10 @@ use defmt::*; use embassy_executor::Spawner; use embassy_stm32::gpio::{Level, Output, OutputType, Pull, Speed}; use embassy_stm32::time::khz; +use embassy_stm32::timer::Channel; use embassy_stm32::timer::input_capture::{CapturePin, InputCapture}; use embassy_stm32::timer::simple_pwm::{PwmPin, SimplePwm}; -use embassy_stm32::timer::Channel; -use embassy_stm32::{bind_interrupts, peripherals, timer, Peri}; +use embassy_stm32::{Peri, bind_interrupts, peripherals, timer}; use embassy_time::Timer; use {defmt_rtt as _, panic_probe as _}; diff --git a/examples/stm32g0/src/bin/pwm_complementary.rs b/examples/stm32g0/src/bin/pwm_complementary.rs index dbd9194c9..9856dd953 100644 --- a/examples/stm32g0/src/bin/pwm_complementary.rs +++ b/examples/stm32g0/src/bin/pwm_complementary.rs @@ -17,9 +17,9 @@ use defmt::info; use embassy_executor::Spawner; use embassy_stm32::gpio::OutputType; use embassy_stm32::time::khz; +use embassy_stm32::timer::Channel; use embassy_stm32::timer::complementary_pwm::{ComplementaryPwm, ComplementaryPwmPin}; use embassy_stm32::timer::simple_pwm::PwmPin; -use embassy_stm32::timer::Channel; use {defmt_rtt as _, panic_probe as _}; #[embassy_executor::main] diff --git a/examples/stm32g0/src/bin/pwm_input.rs b/examples/stm32g0/src/bin/pwm_input.rs index 72aa07c03..5da19e077 100644 --- a/examples/stm32g0/src/bin/pwm_input.rs +++ b/examples/stm32g0/src/bin/pwm_input.rs @@ -14,7 +14,7 @@ use embassy_stm32::gpio::{Level, Output, OutputType, Pull, Speed}; use embassy_stm32::time::khz; use embassy_stm32::timer::pwm_input::PwmInput; use embassy_stm32::timer::simple_pwm::{PwmPin, SimplePwm}; -use embassy_stm32::{bind_interrupts, peripherals, timer, Peri}; +use embassy_stm32::{Peri, bind_interrupts, peripherals, timer}; use embassy_time::Timer; use {defmt_rtt as _, panic_probe as _}; diff --git a/examples/stm32g0/src/bin/rtc.rs b/examples/stm32g0/src/bin/rtc.rs index 50fb6398e..21da204cc 100644 --- a/examples/stm32g0/src/bin/rtc.rs +++ b/examples/stm32g0/src/bin/rtc.rs @@ -3,8 +3,8 @@ use defmt::*; use embassy_executor::Spawner; -use embassy_stm32::rtc::{DateTime, DayOfWeek, Rtc, RtcConfig}; use embassy_stm32::Config; +use embassy_stm32::rtc::{DateTime, DayOfWeek, Rtc, RtcConfig}; use embassy_time::Timer; use {defmt_rtt as _, panic_probe as _}; diff --git a/examples/stm32g0/src/bin/usb_serial.rs b/examples/stm32g0/src/bin/usb_serial.rs index 162dfd86b..7dab393ac 100644 --- a/examples/stm32g0/src/bin/usb_serial.rs +++ b/examples/stm32g0/src/bin/usb_serial.rs @@ -5,10 +5,10 @@ use defmt::{panic, *}; use embassy_executor::Spawner; use embassy_futures::join::join; use embassy_stm32::usb::{Driver, Instance}; -use embassy_stm32::{bind_interrupts, peripherals, usb, Config}; +use embassy_stm32::{Config, bind_interrupts, peripherals, usb}; +use embassy_usb::Builder; use embassy_usb::class::cdc_acm::{CdcAcmClass, State}; use embassy_usb::driver::EndpointError; -use embassy_usb::Builder; use {defmt_rtt as _, panic_probe as _}; bind_interrupts!(struct Irqs { diff --git a/examples/stm32g4/src/bin/adc.rs b/examples/stm32g4/src/bin/adc.rs index adca846d8..920142a18 100644 --- a/examples/stm32g4/src/bin/adc.rs +++ b/examples/stm32g4/src/bin/adc.rs @@ -3,8 +3,8 @@ use defmt::*; use embassy_executor::Spawner; -use embassy_stm32::adc::{Adc, SampleTime}; use embassy_stm32::Config; +use embassy_stm32::adc::{Adc, SampleTime}; use embassy_time::Timer; use {defmt_rtt as _, panic_probe as _}; diff --git a/examples/stm32g4/src/bin/adc_differential.rs b/examples/stm32g4/src/bin/adc_differential.rs index 78d071d45..301f0da84 100644 --- a/examples/stm32g4/src/bin/adc_differential.rs +++ b/examples/stm32g4/src/bin/adc_differential.rs @@ -8,8 +8,8 @@ use defmt::*; use embassy_executor::Spawner; -use embassy_stm32::adc::{Adc, SampleTime}; use embassy_stm32::Config; +use embassy_stm32::adc::{Adc, SampleTime}; use embassy_time::Timer; use {defmt_rtt as _, panic_probe as _}; diff --git a/examples/stm32g4/src/bin/adc_dma.rs b/examples/stm32g4/src/bin/adc_dma.rs index 202704085..a82067049 100644 --- a/examples/stm32g4/src/bin/adc_dma.rs +++ b/examples/stm32g4/src/bin/adc_dma.rs @@ -3,8 +3,8 @@ use defmt::*; use embassy_executor::Spawner; -use embassy_stm32::adc::{Adc, AdcChannel as _, SampleTime}; use embassy_stm32::Config; +use embassy_stm32::adc::{Adc, AdcChannel as _, SampleTime}; use embassy_time::Timer; use {defmt_rtt as _, panic_probe as _}; diff --git a/examples/stm32g4/src/bin/adc_oversampling.rs b/examples/stm32g4/src/bin/adc_oversampling.rs index d31eb20f8..1e464183a 100644 --- a/examples/stm32g4/src/bin/adc_oversampling.rs +++ b/examples/stm32g4/src/bin/adc_oversampling.rs @@ -7,9 +7,9 @@ use defmt::*; use embassy_executor::Spawner; +use embassy_stm32::Config; use embassy_stm32::adc::vals::{Rovsm, Trovs}; use embassy_stm32::adc::{Adc, SampleTime}; -use embassy_stm32::Config; use embassy_time::Timer; use {defmt_rtt as _, panic_probe as _}; diff --git a/examples/stm32g4/src/bin/can.rs b/examples/stm32g4/src/bin/can.rs index 90004f874..7ff7bd7b4 100644 --- a/examples/stm32g4/src/bin/can.rs +++ b/examples/stm32g4/src/bin/can.rs @@ -4,7 +4,7 @@ use defmt::*; use embassy_executor::Spawner; use embassy_stm32::peripherals::*; use embassy_stm32::time::Hertz; -use embassy_stm32::{bind_interrupts, can, Config}; +use embassy_stm32::{Config, bind_interrupts, can}; use embassy_time::Timer; use static_cell::StaticCell; use {defmt_rtt as _, panic_probe as _}; diff --git a/examples/stm32g4/src/bin/usb_c_pd.rs b/examples/stm32g4/src/bin/usb_c_pd.rs index 2e87d3931..b23984b3a 100644 --- a/examples/stm32g4/src/bin/usb_c_pd.rs +++ b/examples/stm32g4/src/bin/usb_c_pd.rs @@ -1,11 +1,11 @@ #![no_std] #![no_main] -use defmt::{error, info, Format}; +use defmt::{Format, error, info}; use embassy_executor::Spawner; use embassy_stm32::ucpd::{self, CcPhy, CcPull, CcSel, CcVState, Ucpd}; -use embassy_stm32::{bind_interrupts, peripherals, Config}; -use embassy_time::{with_timeout, Duration}; +use embassy_stm32::{Config, bind_interrupts, peripherals}; +use embassy_time::{Duration, with_timeout}; use {defmt_rtt as _, panic_probe as _}; bind_interrupts!(struct Irqs { diff --git a/examples/stm32g4/src/bin/usb_serial.rs b/examples/stm32g4/src/bin/usb_serial.rs index 9f66f0c53..a62da6d97 100644 --- a/examples/stm32g4/src/bin/usb_serial.rs +++ b/examples/stm32g4/src/bin/usb_serial.rs @@ -6,10 +6,10 @@ use embassy_executor::Spawner; use embassy_futures::join::join; use embassy_stm32::time::Hertz; use embassy_stm32::usb::{self, Driver, Instance}; -use embassy_stm32::{bind_interrupts, peripherals, Config}; +use embassy_stm32::{Config, bind_interrupts, peripherals}; +use embassy_usb::Builder; use embassy_usb::class::cdc_acm::{CdcAcmClass, State}; use embassy_usb::driver::EndpointError; -use embassy_usb::Builder; use {defmt_rtt as _, panic_probe as _}; bind_interrupts!(struct Irqs { diff --git a/examples/stm32h5/src/bin/adc.rs b/examples/stm32h5/src/bin/adc.rs index c5d508ece..0566320d4 100644 --- a/examples/stm32h5/src/bin/adc.rs +++ b/examples/stm32h5/src/bin/adc.rs @@ -3,8 +3,8 @@ use defmt::*; use embassy_executor::Spawner; -use embassy_stm32::adc::{Adc, SampleTime}; use embassy_stm32::Config; +use embassy_stm32::adc::{Adc, SampleTime}; use embassy_time::Timer; use {defmt_rtt as _, panic_probe as _}; diff --git a/examples/stm32h5/src/bin/can.rs b/examples/stm32h5/src/bin/can.rs index 194239d47..b1923547e 100644 --- a/examples/stm32h5/src/bin/can.rs +++ b/examples/stm32h5/src/bin/can.rs @@ -4,7 +4,7 @@ use defmt::*; use embassy_executor::Spawner; use embassy_stm32::peripherals::*; -use embassy_stm32::{bind_interrupts, can, rcc, Config}; +use embassy_stm32::{Config, bind_interrupts, can, rcc}; use embassy_time::Timer; use {defmt_rtt as _, panic_probe as _}; diff --git a/examples/stm32h5/src/bin/dts.rs b/examples/stm32h5/src/bin/dts.rs index 8c18fafea..7c856b5b3 100644 --- a/examples/stm32h5/src/bin/dts.rs +++ b/examples/stm32h5/src/bin/dts.rs @@ -6,7 +6,7 @@ use embassy_executor::Spawner; use embassy_stm32::dts::{Dts, InterruptHandler, SampleTime}; use embassy_stm32::peripherals::DTS; use embassy_stm32::rcc::frequency; -use embassy_stm32::{bind_interrupts, dts, Config}; +use embassy_stm32::{Config, bind_interrupts, dts}; use embassy_time::Timer; use {defmt_rtt as _, panic_probe as _}; diff --git a/examples/stm32h5/src/bin/eth.rs b/examples/stm32h5/src/bin/eth.rs index a84fe358b..a5c6cee26 100644 --- a/examples/stm32h5/src/bin/eth.rs +++ b/examples/stm32h5/src/bin/eth.rs @@ -12,7 +12,7 @@ use embassy_stm32::rcc::{ }; use embassy_stm32::rng::Rng; use embassy_stm32::time::Hertz; -use embassy_stm32::{bind_interrupts, eth, peripherals, rng, Config}; +use embassy_stm32::{Config, bind_interrupts, eth, peripherals, rng}; use embassy_time::Timer; use embedded_io_async::Write; use static_cell::StaticCell; diff --git a/examples/stm32h5/src/bin/sai.rs b/examples/stm32h5/src/bin/sai.rs index 0e182f9cf..6632a7f98 100644 --- a/examples/stm32h5/src/bin/sai.rs +++ b/examples/stm32h5/src/bin/sai.rs @@ -3,7 +3,7 @@ use defmt::info; use embassy_executor::Spawner; -use embassy_stm32::{sai, Config}; +use embassy_stm32::{Config, sai}; use {defmt_rtt as _, panic_probe as _}; #[embassy_executor::main] diff --git a/examples/stm32h5/src/bin/usb_c_pd.rs b/examples/stm32h5/src/bin/usb_c_pd.rs index acb03e498..ab6efff32 100644 --- a/examples/stm32h5/src/bin/usb_c_pd.rs +++ b/examples/stm32h5/src/bin/usb_c_pd.rs @@ -3,12 +3,12 @@ #![no_std] #![no_main] -use defmt::{error, info, Format}; +use defmt::{Format, error, info}; use embassy_executor::Spawner; use embassy_stm32::gpio::Output; use embassy_stm32::ucpd::{self, CcPhy, CcPull, CcSel, CcVState, Ucpd}; -use embassy_stm32::{bind_interrupts, peripherals, Config}; -use embassy_time::{with_timeout, Duration}; +use embassy_stm32::{Config, bind_interrupts, peripherals}; +use embassy_time::{Duration, with_timeout}; use {defmt_rtt as _, panic_probe as _}; bind_interrupts!(struct Irqs { diff --git a/examples/stm32h5/src/bin/usb_serial.rs b/examples/stm32h5/src/bin/usb_serial.rs index e8f536133..f72851ed7 100644 --- a/examples/stm32h5/src/bin/usb_serial.rs +++ b/examples/stm32h5/src/bin/usb_serial.rs @@ -6,10 +6,10 @@ use embassy_executor::Spawner; use embassy_futures::join::join; use embassy_stm32::time::Hertz; use embassy_stm32::usb::{Driver, Instance}; -use embassy_stm32::{bind_interrupts, peripherals, usb, Config}; +use embassy_stm32::{Config, bind_interrupts, peripherals, usb}; +use embassy_usb::Builder; use embassy_usb::class::cdc_acm::{CdcAcmClass, State}; use embassy_usb::driver::EndpointError; -use embassy_usb::Builder; use {defmt_rtt as _, panic_probe as _}; bind_interrupts!(struct Irqs { diff --git a/examples/stm32h5/src/bin/usb_uac_speaker.rs b/examples/stm32h5/src/bin/usb_uac_speaker.rs index 86873cabd..f75b1fd8a 100644 --- a/examples/stm32h5/src/bin/usb_uac_speaker.rs +++ b/examples/stm32h5/src/bin/usb_uac_speaker.rs @@ -6,9 +6,9 @@ use core::cell::{Cell, RefCell}; use defmt::{panic, *}; use embassy_executor::Spawner; use embassy_stm32::time::Hertz; -use embassy_stm32::{bind_interrupts, interrupt, peripherals, timer, usb, Config}; -use embassy_sync::blocking_mutex::raw::{CriticalSectionRawMutex, NoopRawMutex}; +use embassy_stm32::{Config, bind_interrupts, interrupt, peripherals, timer, usb}; use embassy_sync::blocking_mutex::Mutex; +use embassy_sync::blocking_mutex::raw::{CriticalSectionRawMutex, NoopRawMutex}; use embassy_sync::signal::Signal; use embassy_sync::zerocopy_channel; use embassy_usb::class::uac1; diff --git a/examples/stm32h7/src/bin/adc.rs b/examples/stm32h7/src/bin/adc.rs index 98504ddf6..a53c9d8d5 100644 --- a/examples/stm32h7/src/bin/adc.rs +++ b/examples/stm32h7/src/bin/adc.rs @@ -3,8 +3,8 @@ use defmt::*; use embassy_executor::Spawner; -use embassy_stm32::adc::{Adc, SampleTime}; use embassy_stm32::Config; +use embassy_stm32::adc::{Adc, SampleTime}; use embassy_time::Timer; use {defmt_rtt as _, panic_probe as _}; diff --git a/examples/stm32h7/src/bin/adc_dma.rs b/examples/stm32h7/src/bin/adc_dma.rs index f06b5d06e..cedb32e47 100644 --- a/examples/stm32h7/src/bin/adc_dma.rs +++ b/examples/stm32h7/src/bin/adc_dma.rs @@ -3,8 +3,8 @@ use defmt::*; use embassy_executor::Spawner; -use embassy_stm32::adc::{Adc, AdcChannel as _, SampleTime}; use embassy_stm32::Config; +use embassy_stm32::adc::{Adc, AdcChannel as _, SampleTime}; use embassy_time::Timer; use {defmt_rtt as _, panic_probe as _}; diff --git a/examples/stm32h7/src/bin/camera.rs b/examples/stm32h7/src/bin/camera.rs index 039008d17..c593d5e0b 100644 --- a/examples/stm32h7/src/bin/camera.rs +++ b/examples/stm32h7/src/bin/camera.rs @@ -6,7 +6,7 @@ use embassy_stm32::dcmi::{self, *}; use embassy_stm32::gpio::{Level, Output, Speed}; use embassy_stm32::i2c::I2c; use embassy_stm32::rcc::{Mco, Mco1Source, McoConfig, McoPrescaler}; -use embassy_stm32::{bind_interrupts, i2c, peripherals, Config}; +use embassy_stm32::{Config, bind_interrupts, i2c, peripherals}; use embassy_time::Timer; use ov7725::*; use {defmt_rtt as _, panic_probe as _}; diff --git a/examples/stm32h7/src/bin/can.rs b/examples/stm32h7/src/bin/can.rs index 0af11ef3e..49830f9b7 100644 --- a/examples/stm32h7/src/bin/can.rs +++ b/examples/stm32h7/src/bin/can.rs @@ -4,7 +4,7 @@ use defmt::*; use embassy_executor::Spawner; use embassy_stm32::peripherals::*; -use embassy_stm32::{bind_interrupts, can, rcc, Config}; +use embassy_stm32::{Config, bind_interrupts, can, rcc}; use embassy_time::Timer; use {defmt_rtt as _, panic_probe as _}; diff --git a/examples/stm32h7/src/bin/dac.rs b/examples/stm32h7/src/bin/dac.rs index 27df80336..fa22837c5 100644 --- a/examples/stm32h7/src/bin/dac.rs +++ b/examples/stm32h7/src/bin/dac.rs @@ -3,8 +3,8 @@ use cortex_m_rt::entry; use defmt::*; -use embassy_stm32::dac::{DacCh1, Value}; use embassy_stm32::Config; +use embassy_stm32::dac::{DacCh1, Value}; use {defmt_rtt as _, panic_probe as _}; #[entry] diff --git a/examples/stm32h7/src/bin/dac_dma.rs b/examples/stm32h7/src/bin/dac_dma.rs index df37e9d78..9ccefa761 100644 --- a/examples/stm32h7/src/bin/dac_dma.rs +++ b/examples/stm32h7/src/bin/dac_dma.rs @@ -3,6 +3,7 @@ use defmt::*; use embassy_executor::Spawner; +use embassy_stm32::Peri; use embassy_stm32::dac::{DacCh1, DacCh2, ValueArray}; use embassy_stm32::mode::Async; use embassy_stm32::pac::timer::vals::Mms; @@ -10,7 +11,6 @@ use embassy_stm32::peripherals::{DAC1, TIM6, TIM7}; use embassy_stm32::rcc::frequency; use embassy_stm32::time::Hertz; use embassy_stm32::timer::low_level::Timer; -use embassy_stm32::Peri; use micromath::F32Ext; use {defmt_rtt as _, panic_probe as _}; diff --git a/examples/stm32h7/src/bin/eth.rs b/examples/stm32h7/src/bin/eth.rs index 6c215362d..589f4426e 100644 --- a/examples/stm32h7/src/bin/eth.rs +++ b/examples/stm32h7/src/bin/eth.rs @@ -8,7 +8,7 @@ use embassy_net::{Ipv4Address, StackResources}; use embassy_stm32::eth::{Ethernet, GenericPhy, PacketQueue}; use embassy_stm32::peripherals::ETH; use embassy_stm32::rng::Rng; -use embassy_stm32::{bind_interrupts, eth, peripherals, rng, Config}; +use embassy_stm32::{Config, bind_interrupts, eth, peripherals, rng}; use embassy_time::Timer; use embedded_io_async::Write; use static_cell::StaticCell; diff --git a/examples/stm32h7/src/bin/eth_client.rs b/examples/stm32h7/src/bin/eth_client.rs index 10ac57fc9..fed8f1a9c 100644 --- a/examples/stm32h7/src/bin/eth_client.rs +++ b/examples/stm32h7/src/bin/eth_client.rs @@ -5,12 +5,12 @@ use core::net::{Ipv4Addr, SocketAddr, SocketAddrV4}; use defmt::*; use embassy_executor::Spawner; -use embassy_net::tcp::client::{TcpClient, TcpClientState}; use embassy_net::StackResources; +use embassy_net::tcp::client::{TcpClient, TcpClientState}; use embassy_stm32::eth::{Ethernet, GenericPhy, PacketQueue}; use embassy_stm32::peripherals::ETH; use embassy_stm32::rng::Rng; -use embassy_stm32::{bind_interrupts, eth, peripherals, rng, Config}; +use embassy_stm32::{Config, bind_interrupts, eth, peripherals, rng}; use embassy_time::Timer; use embedded_io_async::Write; use embedded_nal_async::TcpConnect; diff --git a/examples/stm32h7/src/bin/eth_client_mii.rs b/examples/stm32h7/src/bin/eth_client_mii.rs index c6a108471..c3c631f0f 100644 --- a/examples/stm32h7/src/bin/eth_client_mii.rs +++ b/examples/stm32h7/src/bin/eth_client_mii.rs @@ -5,12 +5,12 @@ use core::net::{Ipv4Addr, SocketAddr, SocketAddrV4}; use defmt::*; use embassy_executor::Spawner; -use embassy_net::tcp::client::{TcpClient, TcpClientState}; use embassy_net::StackResources; +use embassy_net::tcp::client::{TcpClient, TcpClientState}; use embassy_stm32::eth::{Ethernet, GenericPhy, PacketQueue}; use embassy_stm32::peripherals::ETH; use embassy_stm32::rng::Rng; -use embassy_stm32::{bind_interrupts, eth, peripherals, rng, Config}; +use embassy_stm32::{Config, bind_interrupts, eth, peripherals, rng}; use embassy_time::Timer; use embedded_io_async::Write; use embedded_nal_async::TcpConnect; diff --git a/examples/stm32h7/src/bin/fmc.rs b/examples/stm32h7/src/bin/fmc.rs index 5e5e6ccc8..b65d50443 100644 --- a/examples/stm32h7/src/bin/fmc.rs +++ b/examples/stm32h7/src/bin/fmc.rs @@ -3,8 +3,8 @@ use defmt::*; use embassy_executor::Spawner; -use embassy_stm32::fmc::Fmc; use embassy_stm32::Config; +use embassy_stm32::fmc::Fmc; use embassy_time::{Delay, Timer}; use {defmt_rtt as _, panic_probe as _}; diff --git a/examples/stm32h7/src/bin/i2c_shared.rs b/examples/stm32h7/src/bin/i2c_shared.rs index 9e45d845f..08ff812f2 100644 --- a/examples/stm32h7/src/bin/i2c_shared.rs +++ b/examples/stm32h7/src/bin/i2c_shared.rs @@ -9,8 +9,8 @@ use embassy_executor::Spawner; use embassy_stm32::i2c::{self, I2c}; use embassy_stm32::mode::Async; use embassy_stm32::{bind_interrupts, peripherals}; -use embassy_sync::blocking_mutex::raw::NoopRawMutex; use embassy_sync::blocking_mutex::NoopMutex; +use embassy_sync::blocking_mutex::raw::NoopRawMutex; use embassy_time::{Duration, Timer}; use embedded_hal_1::i2c::I2c as _; use static_cell::StaticCell; diff --git a/examples/stm32h7/src/bin/low_level_timer_api.rs b/examples/stm32h7/src/bin/low_level_timer_api.rs index 12abb8693..f17fb2aaa 100644 --- a/examples/stm32h7/src/bin/low_level_timer_api.rs +++ b/examples/stm32h7/src/bin/low_level_timer_api.rs @@ -4,7 +4,7 @@ use defmt::*; use embassy_executor::Spawner; use embassy_stm32::gpio::{AfType, Flex, OutputType, Speed}; -use embassy_stm32::time::{khz, Hertz}; +use embassy_stm32::time::{Hertz, khz}; use embassy_stm32::timer::low_level::{OutputCompareMode, Timer as LLTimer}; use embassy_stm32::timer::{Ch1, Ch2, Ch3, Ch4, Channel, GeneralInstance32bit4Channel, TimerPin}; use embassy_stm32::{Config, Peri}; diff --git a/examples/stm32h7/src/bin/pwm.rs b/examples/stm32h7/src/bin/pwm.rs index 73b43be69..ffd117580 100644 --- a/examples/stm32h7/src/bin/pwm.rs +++ b/examples/stm32h7/src/bin/pwm.rs @@ -3,10 +3,10 @@ use defmt::*; use embassy_executor::Spawner; +use embassy_stm32::Config; use embassy_stm32::gpio::OutputType; use embassy_stm32::time::khz; use embassy_stm32::timer::simple_pwm::{PwmPin, SimplePwm}; -use embassy_stm32::Config; use embassy_time::Timer; use {defmt_rtt as _, panic_probe as _}; diff --git a/examples/stm32h7/src/bin/rng.rs b/examples/stm32h7/src/bin/rng.rs index a9ef7200d..489747678 100644 --- a/examples/stm32h7/src/bin/rng.rs +++ b/examples/stm32h7/src/bin/rng.rs @@ -4,7 +4,7 @@ use defmt::*; use embassy_executor::Spawner; use embassy_stm32::rng::Rng; -use embassy_stm32::{bind_interrupts, peripherals, rng, Config}; +use embassy_stm32::{Config, bind_interrupts, peripherals, rng}; use {defmt_rtt as _, panic_probe as _}; bind_interrupts!(struct Irqs { diff --git a/examples/stm32h7/src/bin/rtc.rs b/examples/stm32h7/src/bin/rtc.rs index 0adb48877..1bd71637b 100644 --- a/examples/stm32h7/src/bin/rtc.rs +++ b/examples/stm32h7/src/bin/rtc.rs @@ -4,9 +4,9 @@ use chrono::{NaiveDate, NaiveDateTime}; use defmt::*; use embassy_executor::Spawner; +use embassy_stm32::Config; use embassy_stm32::rcc::LsConfig; use embassy_stm32::rtc::{Rtc, RtcConfig}; -use embassy_stm32::Config; use embassy_time::Timer; use {defmt_rtt as _, panic_probe as _}; diff --git a/examples/stm32h7/src/bin/sdmmc.rs b/examples/stm32h7/src/bin/sdmmc.rs index 96840d8ff..4977fec79 100644 --- a/examples/stm32h7/src/bin/sdmmc.rs +++ b/examples/stm32h7/src/bin/sdmmc.rs @@ -5,7 +5,7 @@ use defmt::*; use embassy_executor::Spawner; use embassy_stm32::sdmmc::Sdmmc; use embassy_stm32::time::mhz; -use embassy_stm32::{bind_interrupts, peripherals, sdmmc, Config}; +use embassy_stm32::{Config, bind_interrupts, peripherals, sdmmc}; use {defmt_rtt as _, panic_probe as _}; bind_interrupts!(struct Irqs { diff --git a/examples/stm32h7/src/bin/spi.rs b/examples/stm32h7/src/bin/spi.rs index dce30a4a7..61f31be24 100644 --- a/examples/stm32h7/src/bin/spi.rs +++ b/examples/stm32h7/src/bin/spi.rs @@ -9,7 +9,7 @@ use defmt::*; use embassy_executor::Executor; use embassy_stm32::mode::Blocking; use embassy_stm32::time::mhz; -use embassy_stm32::{spi, Config}; +use embassy_stm32::{Config, spi}; use heapless::String; use static_cell::StaticCell; use {defmt_rtt as _, panic_probe as _}; diff --git a/examples/stm32h7/src/bin/spi_bdma.rs b/examples/stm32h7/src/bin/spi_bdma.rs index 828f687b8..be6a26d82 100644 --- a/examples/stm32h7/src/bin/spi_bdma.rs +++ b/examples/stm32h7/src/bin/spi_bdma.rs @@ -9,7 +9,7 @@ use defmt::*; use embassy_executor::Executor; use embassy_stm32::mode::Async; use embassy_stm32::time::mhz; -use embassy_stm32::{spi, Config}; +use embassy_stm32::{Config, spi}; use grounded::uninit::GroundedArrayCell; use heapless::String; use static_cell::StaticCell; diff --git a/examples/stm32h7/src/bin/spi_dma.rs b/examples/stm32h7/src/bin/spi_dma.rs index 2197fabce..20cb67ba0 100644 --- a/examples/stm32h7/src/bin/spi_dma.rs +++ b/examples/stm32h7/src/bin/spi_dma.rs @@ -9,7 +9,7 @@ use defmt::*; use embassy_executor::Executor; use embassy_stm32::mode::Async; use embassy_stm32::time::mhz; -use embassy_stm32::{spi, Config}; +use embassy_stm32::{Config, spi}; use heapless::String; use static_cell::StaticCell; use {defmt_rtt as _, panic_probe as _}; diff --git a/examples/stm32h7/src/bin/usb_serial.rs b/examples/stm32h7/src/bin/usb_serial.rs index 50bb964da..d0470101b 100644 --- a/examples/stm32h7/src/bin/usb_serial.rs +++ b/examples/stm32h7/src/bin/usb_serial.rs @@ -5,10 +5,10 @@ use defmt::{panic, *}; use embassy_executor::Spawner; use embassy_futures::join::join; use embassy_stm32::usb::{Driver, Instance}; -use embassy_stm32::{bind_interrupts, peripherals, usb, Config}; +use embassy_stm32::{Config, bind_interrupts, peripherals, usb}; +use embassy_usb::Builder; use embassy_usb::class::cdc_acm::{CdcAcmClass, State}; use embassy_usb::driver::EndpointError; -use embassy_usb::Builder; use {defmt_rtt as _, panic_probe as _}; bind_interrupts!(struct Irqs { diff --git a/examples/stm32h723/src/bin/spdifrx.rs b/examples/stm32h723/src/bin/spdifrx.rs index b75a03ae8..cdbd69b89 100644 --- a/examples/stm32h723/src/bin/spdifrx.rs +++ b/examples/stm32h723/src/bin/spdifrx.rs @@ -7,9 +7,9 @@ use defmt::{info, trace}; use embassy_executor::Spawner; -use embassy_futures::select::{select, Either}; +use embassy_futures::select::{Either, select}; use embassy_stm32::spdifrx::{self, Spdifrx}; -use embassy_stm32::{bind_interrupts, peripherals, sai, Peri}; +use embassy_stm32::{Peri, bind_interrupts, peripherals, sai}; use grounded::uninit::GroundedArrayCell; use hal::sai::*; use {defmt_rtt as _, embassy_stm32 as hal, panic_probe as _}; diff --git a/examples/stm32h735/src/bin/ltdc.rs b/examples/stm32h735/src/bin/ltdc.rs index 8a99f745d..f042e04c2 100644 --- a/examples/stm32h735/src/bin/ltdc.rs +++ b/examples/stm32h735/src/bin/ltdc.rs @@ -15,14 +15,14 @@ use embassy_stm32::gpio::{Level, Output, Speed}; use embassy_stm32::ltdc::{self, Ltdc, LtdcConfiguration, LtdcLayer, LtdcLayerConfig, PolarityActive, PolarityEdge}; use embassy_stm32::{bind_interrupts, peripherals}; use embassy_time::{Duration, Timer}; +use embedded_graphics::Pixel; use embedded_graphics::draw_target::DrawTarget; use embedded_graphics::geometry::{OriginDimensions, Point, Size}; use embedded_graphics::image::Image; -use embedded_graphics::pixelcolor::raw::RawU24; use embedded_graphics::pixelcolor::Rgb888; +use embedded_graphics::pixelcolor::raw::RawU24; use embedded_graphics::prelude::*; use embedded_graphics::primitives::Rectangle; -use embedded_graphics::Pixel; use heapless::{Entry, FnvIndexMap}; use tinybmp::Bmp; use {defmt_rtt as _, panic_probe as _}; diff --git a/examples/stm32h742/src/bin/qspi.rs b/examples/stm32h742/src/bin/qspi.rs index 9e79d7089..a88c8f249 100644 --- a/examples/stm32h742/src/bin/qspi.rs +++ b/examples/stm32h742/src/bin/qspi.rs @@ -4,10 +4,10 @@ use defmt::info; use embassy_executor::Spawner; +use embassy_stm32::Config as StmCfg; use embassy_stm32::mode::Blocking; use embassy_stm32::qspi::enums::{AddressSize, ChipSelectHighTime, FIFOThresholdLevel, MemorySize, *}; use embassy_stm32::qspi::{Config as QspiCfg, Instance, Qspi, TransferConfig}; -use embassy_stm32::Config as StmCfg; use {defmt_rtt as _, panic_probe as _}; const MEMORY_PAGE_SIZE: usize = 256; diff --git a/examples/stm32h755cm4/src/bin/blinky.rs b/examples/stm32h755cm4/src/bin/blinky.rs index 39112c1f5..0ee3c68dc 100644 --- a/examples/stm32h755cm4/src/bin/blinky.rs +++ b/examples/stm32h755cm4/src/bin/blinky.rs @@ -5,8 +5,8 @@ use core::mem::MaybeUninit; use defmt::*; use embassy_executor::Spawner; -use embassy_stm32::gpio::{Level, Output, Speed}; use embassy_stm32::SharedData; +use embassy_stm32::gpio::{Level, Output, Speed}; use embassy_time::Timer; use {defmt_rtt as _, panic_probe as _}; diff --git a/examples/stm32h755cm4/src/bin/intercore.rs b/examples/stm32h755cm4/src/bin/intercore.rs index d93d31786..c0db8cdd3 100644 --- a/examples/stm32h755cm4/src/bin/intercore.rs +++ b/examples/stm32h755cm4/src/bin/intercore.rs @@ -93,8 +93,8 @@ use core::mem::MaybeUninit; use defmt::*; use embassy_executor::Spawner; -use embassy_stm32::gpio::{Level, Output, Speed}; use embassy_stm32::SharedData; +use embassy_stm32::gpio::{Level, Output, Speed}; use embassy_time::Timer; use shared::SHARED_LED_STATE; use {defmt_rtt as _, panic_probe as _}; diff --git a/examples/stm32h755cm7/src/bin/blinky.rs b/examples/stm32h755cm7/src/bin/blinky.rs index b30bf4de8..e8f5a1c43 100644 --- a/examples/stm32h755cm7/src/bin/blinky.rs +++ b/examples/stm32h755cm7/src/bin/blinky.rs @@ -5,8 +5,8 @@ use core::mem::MaybeUninit; use defmt::*; use embassy_executor::Spawner; -use embassy_stm32::gpio::{Level, Output, Speed}; use embassy_stm32::SharedData; +use embassy_stm32::gpio::{Level, Output, Speed}; use embassy_time::Timer; use {defmt_rtt as _, panic_probe as _}; diff --git a/examples/stm32h7b0/src/bin/ospi_memory_mapped.rs b/examples/stm32h7b0/src/bin/ospi_memory_mapped.rs index dffb740a9..865062f4b 100644 --- a/examples/stm32h7b0/src/bin/ospi_memory_mapped.rs +++ b/examples/stm32h7b0/src/bin/ospi_memory_mapped.rs @@ -5,6 +5,7 @@ use defmt::info; use embassy_executor::Spawner; +use embassy_stm32::Config; use embassy_stm32::gpio::{Level, Output, Speed}; use embassy_stm32::mode::Blocking; use embassy_stm32::ospi::{ @@ -12,7 +13,6 @@ use embassy_stm32::ospi::{ OspiWidth, TransferConfig, WrapSize, }; use embassy_stm32::time::Hertz; -use embassy_stm32::Config; use embassy_time::Timer; use {defmt_rtt as _, panic_probe as _}; diff --git a/examples/stm32h7rs/src/bin/blinky.rs b/examples/stm32h7rs/src/bin/blinky.rs index 5fd50fb15..4c0864ff6 100644 --- a/examples/stm32h7rs/src/bin/blinky.rs +++ b/examples/stm32h7rs/src/bin/blinky.rs @@ -3,9 +3,9 @@ use defmt::*; use embassy_executor::Spawner; +use embassy_stm32::Config; use embassy_stm32::gpio::{Level, Output, Speed}; use embassy_stm32::time::Hertz; -use embassy_stm32::Config; use embassy_time::Timer; use {defmt_rtt as _, panic_probe as _}; diff --git a/examples/stm32h7rs/src/bin/can.rs b/examples/stm32h7rs/src/bin/can.rs index 0af11ef3e..49830f9b7 100644 --- a/examples/stm32h7rs/src/bin/can.rs +++ b/examples/stm32h7rs/src/bin/can.rs @@ -4,7 +4,7 @@ use defmt::*; use embassy_executor::Spawner; use embassy_stm32::peripherals::*; -use embassy_stm32::{bind_interrupts, can, rcc, Config}; +use embassy_stm32::{Config, bind_interrupts, can, rcc}; use embassy_time::Timer; use {defmt_rtt as _, panic_probe as _}; diff --git a/examples/stm32h7rs/src/bin/eth.rs b/examples/stm32h7rs/src/bin/eth.rs index 67f541564..5ce1d4765 100644 --- a/examples/stm32h7rs/src/bin/eth.rs +++ b/examples/stm32h7rs/src/bin/eth.rs @@ -8,7 +8,7 @@ use embassy_net::{Ipv4Address, Ipv4Cidr, StackResources}; use embassy_stm32::eth::{Ethernet, GenericPhy, PacketQueue}; use embassy_stm32::peripherals::ETH; use embassy_stm32::rng::Rng; -use embassy_stm32::{bind_interrupts, eth, peripherals, rng, Config}; +use embassy_stm32::{Config, bind_interrupts, eth, peripherals, rng}; use embassy_time::Timer; use heapless::Vec; use static_cell::StaticCell; diff --git a/examples/stm32h7rs/src/bin/rng.rs b/examples/stm32h7rs/src/bin/rng.rs index a9ef7200d..489747678 100644 --- a/examples/stm32h7rs/src/bin/rng.rs +++ b/examples/stm32h7rs/src/bin/rng.rs @@ -4,7 +4,7 @@ use defmt::*; use embassy_executor::Spawner; use embassy_stm32::rng::Rng; -use embassy_stm32::{bind_interrupts, peripherals, rng, Config}; +use embassy_stm32::{Config, bind_interrupts, peripherals, rng}; use {defmt_rtt as _, panic_probe as _}; bind_interrupts!(struct Irqs { diff --git a/examples/stm32h7rs/src/bin/rtc.rs b/examples/stm32h7rs/src/bin/rtc.rs index 0adb48877..1bd71637b 100644 --- a/examples/stm32h7rs/src/bin/rtc.rs +++ b/examples/stm32h7rs/src/bin/rtc.rs @@ -4,9 +4,9 @@ use chrono::{NaiveDate, NaiveDateTime}; use defmt::*; use embassy_executor::Spawner; +use embassy_stm32::Config; use embassy_stm32::rcc::LsConfig; use embassy_stm32::rtc::{Rtc, RtcConfig}; -use embassy_stm32::Config; use embassy_time::Timer; use {defmt_rtt as _, panic_probe as _}; diff --git a/examples/stm32h7rs/src/bin/usb_serial.rs b/examples/stm32h7rs/src/bin/usb_serial.rs index 23abc3e2f..3e295dd51 100644 --- a/examples/stm32h7rs/src/bin/usb_serial.rs +++ b/examples/stm32h7rs/src/bin/usb_serial.rs @@ -6,10 +6,10 @@ use embassy_executor::Spawner; use embassy_futures::join::join; use embassy_stm32::time::Hertz; use embassy_stm32::usb::{Driver, Instance}; -use embassy_stm32::{bind_interrupts, peripherals, usb, Config}; +use embassy_stm32::{Config, bind_interrupts, peripherals, usb}; +use embassy_usb::Builder; use embassy_usb::class::cdc_acm::{CdcAcmClass, State}; use embassy_usb::driver::EndpointError; -use embassy_usb::Builder; use {defmt_rtt as _, panic_probe as _}; bind_interrupts!(struct Irqs { diff --git a/examples/stm32h7rs/src/bin/xspi_memory_mapped.rs b/examples/stm32h7rs/src/bin/xspi_memory_mapped.rs index 4c1b450b4..d91ae9de0 100644 --- a/examples/stm32h7rs/src/bin/xspi_memory_mapped.rs +++ b/examples/stm32h7rs/src/bin/xspi_memory_mapped.rs @@ -8,6 +8,7 @@ use core::cmp::min; use defmt::info; use embassy_executor::Spawner; +use embassy_stm32::Config; use embassy_stm32::gpio::{Level, Output, Speed}; use embassy_stm32::mode::Blocking; use embassy_stm32::time::Hertz; @@ -15,7 +16,6 @@ use embassy_stm32::xspi::{ AddressSize, ChipSelectHighTime, DummyCycles, FIFOThresholdLevel, Instance, MemorySize, MemoryType, TransferConfig, WrapSize, Xspi, XspiWidth, }; -use embassy_stm32::Config; use embassy_time::Timer; use {defmt_rtt as _, panic_probe as _}; diff --git a/examples/stm32l0/src/bin/button_exti.rs b/examples/stm32l0/src/bin/button_exti.rs index 4945da7ce..7ff4a7d52 100644 --- a/examples/stm32l0/src/bin/button_exti.rs +++ b/examples/stm32l0/src/bin/button_exti.rs @@ -3,9 +3,9 @@ use defmt::*; use embassy_executor::Spawner; +use embassy_stm32::Config; use embassy_stm32::exti::ExtiInput; use embassy_stm32::gpio::Pull; -use embassy_stm32::Config; use {defmt_rtt as _, panic_probe as _}; #[embassy_executor::main] diff --git a/examples/stm32l0/src/bin/dds.rs b/examples/stm32l0/src/bin/dds.rs index eaa7a61a8..d8f9020d4 100644 --- a/examples/stm32l0/src/bin/dds.rs +++ b/examples/stm32l0/src/bin/dds.rs @@ -12,7 +12,7 @@ use embassy_stm32::time::hz; use embassy_stm32::timer::low_level::{Timer as LLTimer, *}; use embassy_stm32::timer::simple_pwm::PwmPin; use embassy_stm32::timer::{Ch3, Channel}; -use embassy_stm32::{interrupt, pac, Config}; +use embassy_stm32::{Config, interrupt, pac}; use panic_probe as _; const DDS_SINE_DATA: [u8; 256] = [ diff --git a/examples/stm32l0/src/bin/eeprom.rs b/examples/stm32l0/src/bin/eeprom.rs index 370246644..a33088f36 100644 --- a/examples/stm32l0/src/bin/eeprom.rs +++ b/examples/stm32l0/src/bin/eeprom.rs @@ -3,7 +3,7 @@ use defmt::{info, unwrap}; use embassy_executor::Spawner; -use embassy_stm32::flash::{Flash, EEPROM_BASE, EEPROM_SIZE}; +use embassy_stm32::flash::{EEPROM_BASE, EEPROM_SIZE, Flash}; use {defmt_rtt as _, panic_probe as _}; #[embassy_executor::main] diff --git a/examples/stm32l0/src/bin/raw_spawn.rs b/examples/stm32l0/src/bin/raw_spawn.rs index 7eea910ca..8e8fe0240 100644 --- a/examples/stm32l0/src/bin/raw_spawn.rs +++ b/examples/stm32l0/src/bin/raw_spawn.rs @@ -5,8 +5,8 @@ use core::mem; use cortex_m_rt::entry; use defmt::*; -use embassy_executor::raw::TaskStorage; use embassy_executor::Executor; +use embassy_executor::raw::TaskStorage; use embassy_time::Timer; use static_cell::StaticCell; use {defmt_rtt as _, panic_probe as _}; diff --git a/examples/stm32l0/src/bin/usb_serial.rs b/examples/stm32l0/src/bin/usb_serial.rs index fdb1aeb59..612082f29 100644 --- a/examples/stm32l0/src/bin/usb_serial.rs +++ b/examples/stm32l0/src/bin/usb_serial.rs @@ -6,9 +6,9 @@ use embassy_executor::Spawner; use embassy_futures::join::join; use embassy_stm32::usb::{self, Driver, Instance}; use embassy_stm32::{bind_interrupts, peripherals}; +use embassy_usb::Builder; use embassy_usb::class::cdc_acm::{CdcAcmClass, State}; use embassy_usb::driver::EndpointError; -use embassy_usb::Builder; use {defmt_rtt as _, panic_probe as _}; bind_interrupts!(struct Irqs { diff --git a/examples/stm32l1/src/bin/eeprom.rs b/examples/stm32l1/src/bin/eeprom.rs index 370246644..a33088f36 100644 --- a/examples/stm32l1/src/bin/eeprom.rs +++ b/examples/stm32l1/src/bin/eeprom.rs @@ -3,7 +3,7 @@ use defmt::{info, unwrap}; use embassy_executor::Spawner; -use embassy_stm32::flash::{Flash, EEPROM_BASE, EEPROM_SIZE}; +use embassy_stm32::flash::{EEPROM_BASE, EEPROM_SIZE, Flash}; use {defmt_rtt as _, panic_probe as _}; #[embassy_executor::main] diff --git a/examples/stm32l1/src/bin/usb_serial.rs b/examples/stm32l1/src/bin/usb_serial.rs index a35f1d7a7..c54d37f9d 100644 --- a/examples/stm32l1/src/bin/usb_serial.rs +++ b/examples/stm32l1/src/bin/usb_serial.rs @@ -6,9 +6,9 @@ use embassy_executor::Spawner; use embassy_futures::join::join; use embassy_stm32::usb::{self, Driver, Instance}; use embassy_stm32::{bind_interrupts, peripherals}; +use embassy_usb::Builder; use embassy_usb::class::cdc_acm::{CdcAcmClass, State}; use embassy_usb::driver::EndpointError; -use embassy_usb::Builder; use {defmt_rtt as _, panic_probe as _}; bind_interrupts!(struct Irqs { diff --git a/examples/stm32l4/src/bin/adc.rs b/examples/stm32l4/src/bin/adc.rs index c557ac6d7..40e907940 100644 --- a/examples/stm32l4/src/bin/adc.rs +++ b/examples/stm32l4/src/bin/adc.rs @@ -2,8 +2,8 @@ #![no_main] use defmt::*; -use embassy_stm32::adc::{Adc, Resolution}; use embassy_stm32::Config; +use embassy_stm32::adc::{Adc, Resolution}; use {defmt_rtt as _, panic_probe as _}; #[cortex_m_rt::entry] diff --git a/examples/stm32l4/src/bin/can.rs b/examples/stm32l4/src/bin/can.rs index 3c4cdac24..bd361417e 100644 --- a/examples/stm32l4/src/bin/can.rs +++ b/examples/stm32l4/src/bin/can.rs @@ -8,7 +8,7 @@ use embassy_stm32::can::{ Can, Fifo, Frame, Rx0InterruptHandler, Rx1InterruptHandler, SceInterruptHandler, TxInterruptHandler, }; use embassy_stm32::peripherals::CAN1; -use embassy_stm32::{bind_interrupts, Config}; +use embassy_stm32::{Config, bind_interrupts}; use embassy_time::Timer; use {defmt_rtt as _, panic_probe as _}; diff --git a/examples/stm32l4/src/bin/dac_dma.rs b/examples/stm32l4/src/bin/dac_dma.rs index 44edec728..bfdf858c5 100644 --- a/examples/stm32l4/src/bin/dac_dma.rs +++ b/examples/stm32l4/src/bin/dac_dma.rs @@ -3,6 +3,7 @@ use defmt::*; use embassy_executor::Spawner; +use embassy_stm32::Peri; use embassy_stm32::dac::{DacCh1, DacCh2, ValueArray}; use embassy_stm32::mode::Async; use embassy_stm32::pac::timer::vals::Mms; @@ -10,7 +11,6 @@ use embassy_stm32::peripherals::{DAC1, TIM6, TIM7}; use embassy_stm32::rcc::frequency; use embassy_stm32::time::Hertz; use embassy_stm32::timer::low_level::Timer; -use embassy_stm32::Peri; use micromath::F32Ext; use {defmt_rtt as _, panic_probe as _}; diff --git a/examples/stm32l4/src/bin/rng.rs b/examples/stm32l4/src/bin/rng.rs index 14d0e3c1e..4d9f83ad8 100644 --- a/examples/stm32l4/src/bin/rng.rs +++ b/examples/stm32l4/src/bin/rng.rs @@ -5,7 +5,7 @@ use defmt::*; use embassy_executor::Spawner; use embassy_stm32::rcc::{Pll, PllMul, PllPreDiv, PllQDiv, PllRDiv, PllSource, Sysclk}; use embassy_stm32::rng::Rng; -use embassy_stm32::{bind_interrupts, peripherals, rng, Config}; +use embassy_stm32::{Config, bind_interrupts, peripherals, rng}; use {defmt_rtt as _, panic_probe as _}; bind_interrupts!(struct Irqs { diff --git a/examples/stm32l4/src/bin/rtc.rs b/examples/stm32l4/src/bin/rtc.rs index f554f0f78..1d26cd008 100644 --- a/examples/stm32l4/src/bin/rtc.rs +++ b/examples/stm32l4/src/bin/rtc.rs @@ -4,9 +4,9 @@ use chrono::{NaiveDate, NaiveDateTime}; use defmt::*; use embassy_executor::Spawner; +use embassy_stm32::Config; use embassy_stm32::rtc::{Rtc, RtcConfig}; use embassy_stm32::time::Hertz; -use embassy_stm32::Config; use embassy_time::Timer; use {defmt_rtt as _, panic_probe as _}; diff --git a/examples/stm32l4/src/bin/spe_adin1110_http_server.rs b/examples/stm32l4/src/bin/spe_adin1110_http_server.rs index 24efe526f..8e54938d1 100644 --- a/examples/stm32l4/src/bin/spe_adin1110_http_server.rs +++ b/examples/stm32l4/src/bin/spe_adin1110_http_server.rs @@ -16,14 +16,14 @@ use core::marker::PhantomData; use core::sync::atomic::{AtomicI32, Ordering}; -use defmt::{error, info, println, unwrap, Format}; +use defmt::{Format, error, info, println, unwrap}; use defmt_rtt as _; // global logger use embassy_executor::Spawner; -use embassy_futures::select::{select, Either}; +use embassy_futures::select::{Either, select}; use embassy_futures::yield_now; use embassy_net::tcp::TcpSocket; use embassy_net::{Ipv4Address, Ipv4Cidr, Stack, StackResources, StaticConfigV4}; -use embassy_net_adin1110::{Device, Runner, ADIN1110}; +use embassy_net_adin1110::{ADIN1110, Device, Runner}; use embassy_stm32::gpio::{Input, Level, Output, Pull, Speed}; use embassy_stm32::i2c::{self, Config as I2C_Config, I2c}; use embassy_stm32::mode::Async; @@ -159,7 +159,9 @@ async fn main(spawner: Spawner) { // Check the SPI mode selected with the "HW CFG" dip-switch if !cfg1_spi_mode { - error!("Driver doesn´t support SPI Protolcol \"OPEN Alliance\".\nplease use the \"Generic SPI\"! Turn On \"HW CFG\": \"SPI_CFG1\""); + error!( + "Driver doesn´t support SPI Protolcol \"OPEN Alliance\".\nplease use the \"Generic SPI\"! Turn On \"HW CFG\": \"SPI_CFG1\"" + ); loop { led_uc2_red.toggle(); Timer::after(Duration::from_hz(10)).await; diff --git a/examples/stm32l4/src/bin/usb_serial.rs b/examples/stm32l4/src/bin/usb_serial.rs index af90e297e..17cd107f6 100644 --- a/examples/stm32l4/src/bin/usb_serial.rs +++ b/examples/stm32l4/src/bin/usb_serial.rs @@ -6,10 +6,10 @@ use defmt_rtt as _; // global logger use embassy_executor::Spawner; use embassy_futures::join::join; use embassy_stm32::usb::{Driver, Instance}; -use embassy_stm32::{bind_interrupts, peripherals, usb, Config}; +use embassy_stm32::{Config, bind_interrupts, peripherals, usb}; +use embassy_usb::Builder; use embassy_usb::class::cdc_acm::{CdcAcmClass, State}; use embassy_usb::driver::EndpointError; -use embassy_usb::Builder; use panic_probe as _; bind_interrupts!(struct Irqs { diff --git a/examples/stm32l5/src/bin/rng.rs b/examples/stm32l5/src/bin/rng.rs index 0a644e73d..d6302e106 100644 --- a/examples/stm32l5/src/bin/rng.rs +++ b/examples/stm32l5/src/bin/rng.rs @@ -5,7 +5,7 @@ use defmt::*; use embassy_executor::Spawner; use embassy_stm32::rcc::{Pll, PllMul, PllPreDiv, PllRDiv, PllSource, Sysclk}; use embassy_stm32::rng::Rng; -use embassy_stm32::{bind_interrupts, peripherals, rng, Config}; +use embassy_stm32::{Config, bind_interrupts, peripherals, rng}; use {defmt_rtt as _, panic_probe as _}; bind_interrupts!(struct Irqs { diff --git a/examples/stm32l5/src/bin/usb_ethernet.rs b/examples/stm32l5/src/bin/usb_ethernet.rs index 25aa9ef69..d2cbeb550 100644 --- a/examples/stm32l5/src/bin/usb_ethernet.rs +++ b/examples/stm32l5/src/bin/usb_ethernet.rs @@ -3,11 +3,11 @@ use defmt::*; use embassy_executor::Spawner; -use embassy_net::tcp::TcpSocket; use embassy_net::StackResources; +use embassy_net::tcp::TcpSocket; use embassy_stm32::rng::Rng; use embassy_stm32::usb::Driver; -use embassy_stm32::{bind_interrupts, peripherals, rng, usb, Config}; +use embassy_stm32::{Config, bind_interrupts, peripherals, rng, usb}; use embassy_usb::class::cdc_ncm::embassy_net::{Device, Runner, State as NetState}; use embassy_usb::class::cdc_ncm::{CdcNcmClass, State}; use embassy_usb::{Builder, UsbDevice}; diff --git a/examples/stm32l5/src/bin/usb_hid_mouse.rs b/examples/stm32l5/src/bin/usb_hid_mouse.rs index 3f8c52b82..b721f5b2e 100644 --- a/examples/stm32l5/src/bin/usb_hid_mouse.rs +++ b/examples/stm32l5/src/bin/usb_hid_mouse.rs @@ -5,11 +5,11 @@ use defmt::*; use embassy_executor::Spawner; use embassy_futures::join::join; use embassy_stm32::usb::Driver; -use embassy_stm32::{bind_interrupts, peripherals, usb, Config}; +use embassy_stm32::{Config, bind_interrupts, peripherals, usb}; use embassy_time::Timer; +use embassy_usb::Builder; use embassy_usb::class::hid::{HidWriter, ReportId, RequestHandler, State}; use embassy_usb::control::OutResponse; -use embassy_usb::Builder; use usbd_hid::descriptor::{MouseReport, SerializedDescriptor}; use {defmt_rtt as _, panic_probe as _}; diff --git a/examples/stm32l5/src/bin/usb_serial.rs b/examples/stm32l5/src/bin/usb_serial.rs index a64bda31b..4f77fc1d7 100644 --- a/examples/stm32l5/src/bin/usb_serial.rs +++ b/examples/stm32l5/src/bin/usb_serial.rs @@ -5,10 +5,10 @@ use defmt::{panic, *}; use embassy_executor::Spawner; use embassy_futures::join::join; use embassy_stm32::usb::{Driver, Instance}; -use embassy_stm32::{bind_interrupts, peripherals, usb, Config}; +use embassy_stm32::{Config, bind_interrupts, peripherals, usb}; +use embassy_usb::Builder; use embassy_usb::class::cdc_acm::{CdcAcmClass, State}; use embassy_usb::driver::EndpointError; -use embassy_usb::Builder; use {defmt_rtt as _, panic_probe as _}; bind_interrupts!(struct Irqs { diff --git a/examples/stm32u0/src/bin/adc.rs b/examples/stm32u0/src/bin/adc.rs index c8252e4e1..32a54299d 100644 --- a/examples/stm32u0/src/bin/adc.rs +++ b/examples/stm32u0/src/bin/adc.rs @@ -2,8 +2,8 @@ #![no_main] use defmt::*; -use embassy_stm32::adc::{Adc, Resolution}; use embassy_stm32::Config; +use embassy_stm32::adc::{Adc, Resolution}; use embassy_time::Duration; use {defmt_rtt as _, panic_probe as _}; diff --git a/examples/stm32u0/src/bin/rng.rs b/examples/stm32u0/src/bin/rng.rs index 89445b042..07deda94c 100644 --- a/examples/stm32u0/src/bin/rng.rs +++ b/examples/stm32u0/src/bin/rng.rs @@ -5,7 +5,7 @@ use defmt::*; use embassy_executor::Spawner; use embassy_stm32::rcc::mux::Clk48sel; use embassy_stm32::rng::Rng; -use embassy_stm32::{bind_interrupts, peripherals, rng, Config}; +use embassy_stm32::{Config, bind_interrupts, peripherals, rng}; use {defmt_rtt as _, panic_probe as _}; bind_interrupts!(struct Irqs { diff --git a/examples/stm32u0/src/bin/rtc.rs b/examples/stm32u0/src/bin/rtc.rs index 72fa0fde4..d071cfbc7 100644 --- a/examples/stm32u0/src/bin/rtc.rs +++ b/examples/stm32u0/src/bin/rtc.rs @@ -4,8 +4,8 @@ use chrono::{NaiveDate, NaiveDateTime}; use defmt::*; use embassy_executor::Spawner; -use embassy_stm32::rtc::{Rtc, RtcConfig}; use embassy_stm32::Config; +use embassy_stm32::rtc::{Rtc, RtcConfig}; use embassy_time::Timer; use {defmt_rtt as _, panic_probe as _}; diff --git a/examples/stm32u0/src/bin/usb_serial.rs b/examples/stm32u0/src/bin/usb_serial.rs index 273f40643..77d0640f6 100644 --- a/examples/stm32u0/src/bin/usb_serial.rs +++ b/examples/stm32u0/src/bin/usb_serial.rs @@ -6,10 +6,10 @@ use defmt_rtt as _; // global logger use embassy_executor::Spawner; use embassy_futures::join::join; use embassy_stm32::usb::{Driver, Instance}; -use embassy_stm32::{bind_interrupts, peripherals, usb, Config}; +use embassy_stm32::{Config, bind_interrupts, peripherals, usb}; +use embassy_usb::Builder; use embassy_usb::class::cdc_acm::{CdcAcmClass, State}; use embassy_usb::driver::EndpointError; -use embassy_usb::Builder; use panic_probe as _; bind_interrupts!(struct Irqs { diff --git a/examples/stm32u5/src/bin/adc.rs b/examples/stm32u5/src/bin/adc.rs index d2aa28087..91e33053e 100644 --- a/examples/stm32u5/src/bin/adc.rs +++ b/examples/stm32u5/src/bin/adc.rs @@ -3,7 +3,7 @@ use defmt::*; use embassy_stm32::adc; -use embassy_stm32::adc::{adc4, AdcChannel}; +use embassy_stm32::adc::{AdcChannel, adc4}; use {defmt_rtt as _, panic_probe as _}; #[embassy_executor::main] diff --git a/examples/stm32u5/src/bin/ltdc.rs b/examples/stm32u5/src/bin/ltdc.rs index 46d1c120f..d1fddb679 100644 --- a/examples/stm32u5/src/bin/ltdc.rs +++ b/examples/stm32u5/src/bin/ltdc.rs @@ -13,14 +13,14 @@ use embassy_stm32::gpio::{Level, Output, Speed}; use embassy_stm32::ltdc::{self, Ltdc, LtdcConfiguration, LtdcLayer, LtdcLayerConfig, PolarityActive, PolarityEdge}; use embassy_stm32::{bind_interrupts, peripherals}; use embassy_time::{Duration, Timer}; +use embedded_graphics::Pixel; use embedded_graphics::draw_target::DrawTarget; use embedded_graphics::geometry::{OriginDimensions, Point, Size}; use embedded_graphics::image::Image; -use embedded_graphics::pixelcolor::raw::RawU24; use embedded_graphics::pixelcolor::Rgb888; +use embedded_graphics::pixelcolor::raw::RawU24; use embedded_graphics::prelude::*; use embedded_graphics::primitives::Rectangle; -use embedded_graphics::Pixel; use heapless::{Entry, FnvIndexMap}; use tinybmp::Bmp; use {defmt_rtt as _, panic_probe as _}; @@ -317,7 +317,7 @@ impl OriginDimensions for DoubleBuffer { mod rcc_setup { use embassy_stm32::time::Hertz; - use embassy_stm32::{rcc, Config, Peripherals}; + use embassy_stm32::{Config, Peripherals, rcc}; /// Sets up clocks for the stm32u5g9zj mcu /// change this if you plan to use a different microcontroller diff --git a/examples/stm32u5/src/bin/usb_hs_serial.rs b/examples/stm32u5/src/bin/usb_hs_serial.rs index d37e7777b..c444d3479 100644 --- a/examples/stm32u5/src/bin/usb_hs_serial.rs +++ b/examples/stm32u5/src/bin/usb_hs_serial.rs @@ -6,10 +6,10 @@ use defmt_rtt as _; // global logger use embassy_executor::Spawner; use embassy_futures::join::join; use embassy_stm32::usb::{Driver, Instance}; -use embassy_stm32::{bind_interrupts, peripherals, usb, Config}; +use embassy_stm32::{Config, bind_interrupts, peripherals, usb}; +use embassy_usb::Builder; use embassy_usb::class::cdc_acm::{CdcAcmClass, State}; use embassy_usb::driver::EndpointError; -use embassy_usb::Builder; use panic_probe as _; bind_interrupts!(struct Irqs { diff --git a/examples/stm32u5/src/bin/usb_serial.rs b/examples/stm32u5/src/bin/usb_serial.rs index ff7f4e5be..c0a768cbb 100644 --- a/examples/stm32u5/src/bin/usb_serial.rs +++ b/examples/stm32u5/src/bin/usb_serial.rs @@ -6,10 +6,10 @@ use defmt_rtt as _; // global logger use embassy_executor::Spawner; use embassy_futures::join::join; use embassy_stm32::usb::{Driver, Instance}; -use embassy_stm32::{bind_interrupts, peripherals, usb, Config}; +use embassy_stm32::{Config, bind_interrupts, peripherals, usb}; +use embassy_usb::Builder; use embassy_usb::class::cdc_acm::{CdcAcmClass, State}; use embassy_usb::driver::EndpointError; -use embassy_usb::Builder; use panic_probe as _; bind_interrupts!(struct Irqs { diff --git a/examples/stm32wb/src/bin/eddystone_beacon.rs b/examples/stm32wb/src/bin/eddystone_beacon.rs index 3bd8b4a63..f309ca3a2 100644 --- a/examples/stm32wb/src/bin/eddystone_beacon.rs +++ b/examples/stm32wb/src/bin/eddystone_beacon.rs @@ -8,15 +8,15 @@ use embassy_executor::Spawner; use embassy_stm32::bind_interrupts; use embassy_stm32::ipcc::{Config, ReceiveInterruptHandler, TransmitInterruptHandler}; use embassy_stm32::rcc::WPAN_DEFAULT; +use embassy_stm32_wpan::TlMbox; +use embassy_stm32_wpan::hci::BdAddr; use embassy_stm32_wpan::hci::host::uart::UartHci; use embassy_stm32_wpan::hci::host::{AdvertisingFilterPolicy, EncryptionKey, HostHci, OwnAddressType}; use embassy_stm32_wpan::hci::types::AdvertisingType; use embassy_stm32_wpan::hci::vendor::command::gap::{AdvertisingDataType, DiscoverableParameters, GapCommands, Role}; use embassy_stm32_wpan::hci::vendor::command::gatt::GattCommands; use embassy_stm32_wpan::hci::vendor::command::hal::{ConfigData, HalCommands, PowerLevel}; -use embassy_stm32_wpan::hci::BdAddr; use embassy_stm32_wpan::lhci::LhciC1DeviceInformationCcrp; -use embassy_stm32_wpan::TlMbox; use {defmt_rtt as _, panic_probe as _}; bind_interrupts!(struct Irqs{ diff --git a/examples/stm32wb/src/bin/gatt_server.rs b/examples/stm32wb/src/bin/gatt_server.rs index 5d927bc00..2ed257566 100644 --- a/examples/stm32wb/src/bin/gatt_server.rs +++ b/examples/stm32wb/src/bin/gatt_server.rs @@ -8,6 +8,7 @@ use embassy_executor::Spawner; use embassy_stm32::bind_interrupts; use embassy_stm32::ipcc::{Config, ReceiveInterruptHandler, TransmitInterruptHandler}; use embassy_stm32::rcc::WPAN_DEFAULT; +use embassy_stm32_wpan::TlMbox; use embassy_stm32_wpan::hci::event::command::{CommandComplete, ReturnParameters}; use embassy_stm32_wpan::hci::host::uart::{Packet, UartHci}; use embassy_stm32_wpan::hci::host::{AdvertisingFilterPolicy, EncryptionKey, HostHci, OwnAddressType}; @@ -28,7 +29,6 @@ use embassy_stm32_wpan::hci::{BdAddr, Event}; use embassy_stm32_wpan::lhci::LhciC1DeviceInformationCcrp; use embassy_stm32_wpan::sub::ble::Ble; use embassy_stm32_wpan::sub::mm; -use embassy_stm32_wpan::TlMbox; use {defmt_rtt as _, panic_probe as _}; bind_interrupts!(struct Irqs{ diff --git a/examples/stm32wb/src/bin/mac_ffd.rs b/examples/stm32wb/src/bin/mac_ffd.rs index ede6cf4b9..18a52e162 100644 --- a/examples/stm32wb/src/bin/mac_ffd.rs +++ b/examples/stm32wb/src/bin/mac_ffd.rs @@ -6,11 +6,11 @@ use embassy_executor::Spawner; use embassy_stm32::bind_interrupts; use embassy_stm32::ipcc::{Config, ReceiveInterruptHandler, TransmitInterruptHandler}; use embassy_stm32::rcc::WPAN_DEFAULT; +use embassy_stm32_wpan::TlMbox; use embassy_stm32_wpan::mac::commands::{AssociateResponse, ResetRequest, SetRequest, StartRequest}; use embassy_stm32_wpan::mac::event::MacEvent; use embassy_stm32_wpan::mac::typedefs::{MacChannel, MacStatus, PanId, PibId, SecurityLevel}; use embassy_stm32_wpan::sub::mm; -use embassy_stm32_wpan::TlMbox; use {defmt_rtt as _, panic_probe as _}; bind_interrupts!(struct Irqs{ diff --git a/examples/stm32wb/src/bin/mac_ffd_net.rs b/examples/stm32wb/src/bin/mac_ffd_net.rs index cc3b21e2e..5296943a1 100644 --- a/examples/stm32wb/src/bin/mac_ffd_net.rs +++ b/examples/stm32wb/src/bin/mac_ffd_net.rs @@ -6,11 +6,11 @@ use embassy_executor::Spawner; use embassy_stm32::bind_interrupts; use embassy_stm32::ipcc::{Config, ReceiveInterruptHandler, TransmitInterruptHandler}; use embassy_stm32::rcc::WPAN_DEFAULT; +use embassy_stm32_wpan::TlMbox; use embassy_stm32_wpan::mac::commands::{ResetRequest, SetRequest, StartRequest}; use embassy_stm32_wpan::mac::typedefs::{MacChannel, PanId, PibId}; use embassy_stm32_wpan::mac::{self, Runner}; use embassy_stm32_wpan::sub::mm; -use embassy_stm32_wpan::TlMbox; use static_cell::StaticCell; use {defmt_rtt as _, panic_probe as _}; diff --git a/examples/stm32wb/src/bin/mac_rfd.rs b/examples/stm32wb/src/bin/mac_rfd.rs index d872104a8..883179023 100644 --- a/examples/stm32wb/src/bin/mac_rfd.rs +++ b/examples/stm32wb/src/bin/mac_rfd.rs @@ -6,13 +6,13 @@ use embassy_executor::Spawner; use embassy_stm32::bind_interrupts; use embassy_stm32::ipcc::{Config, ReceiveInterruptHandler, TransmitInterruptHandler}; use embassy_stm32::rcc::WPAN_DEFAULT; +use embassy_stm32_wpan::TlMbox; use embassy_stm32_wpan::mac::commands::{AssociateRequest, DataRequest, GetRequest, ResetRequest, SetRequest}; use embassy_stm32_wpan::mac::event::MacEvent; use embassy_stm32_wpan::mac::typedefs::{ AddressMode, Capabilities, KeyIdMode, MacAddress, MacChannel, PanId, PibId, SecurityLevel, }; use embassy_stm32_wpan::sub::mm; -use embassy_stm32_wpan::TlMbox; use {defmt_rtt as _, panic_probe as _}; bind_interrupts!(struct Irqs{ diff --git a/examples/stm32wb/src/bin/tl_mbox_mac.rs b/examples/stm32wb/src/bin/tl_mbox_mac.rs index 95c73872b..16d0a1527 100644 --- a/examples/stm32wb/src/bin/tl_mbox_mac.rs +++ b/examples/stm32wb/src/bin/tl_mbox_mac.rs @@ -6,8 +6,8 @@ use embassy_executor::Spawner; use embassy_stm32::bind_interrupts; use embassy_stm32::ipcc::{Config, ReceiveInterruptHandler, TransmitInterruptHandler}; use embassy_stm32::rcc::WPAN_DEFAULT; -use embassy_stm32_wpan::sub::mm; use embassy_stm32_wpan::TlMbox; +use embassy_stm32_wpan::sub::mm; use {defmt_rtt as _, panic_probe as _}; bind_interrupts!(struct Irqs{ diff --git a/examples/stm32wba/src/bin/adc.rs b/examples/stm32wba/src/bin/adc.rs index a9651d57e..8c80470b8 100644 --- a/examples/stm32wba/src/bin/adc.rs +++ b/examples/stm32wba/src/bin/adc.rs @@ -2,7 +2,7 @@ #![no_main] use defmt::*; -use embassy_stm32::adc::{adc4, AdcChannel}; +use embassy_stm32::adc::{AdcChannel, adc4}; use {defmt_rtt as _, panic_probe as _}; #[embassy_executor::main] diff --git a/examples/stm32wba/src/bin/pwm.rs b/examples/stm32wba/src/bin/pwm.rs index de690fda0..f20c77a7c 100644 --- a/examples/stm32wba/src/bin/pwm.rs +++ b/examples/stm32wba/src/bin/pwm.rs @@ -4,13 +4,13 @@ use defmt::*; use defmt_rtt as _; // global logger use embassy_executor::Spawner; +use embassy_stm32::Config; use embassy_stm32::gpio::OutputType; use embassy_stm32::rcc::{ AHB5Prescaler, AHBPrescaler, APBPrescaler, PllDiv, PllMul, PllPreDiv, PllSource, Sysclk, VoltageScale, }; use embassy_stm32::time::khz; use embassy_stm32::timer::simple_pwm::{PwmPin, SimplePwm}; -use embassy_stm32::Config; use embassy_time::Timer; use panic_probe as _; diff --git a/examples/stm32wba6/src/bin/adc.rs b/examples/stm32wba6/src/bin/adc.rs index a9651d57e..8c80470b8 100644 --- a/examples/stm32wba6/src/bin/adc.rs +++ b/examples/stm32wba6/src/bin/adc.rs @@ -2,7 +2,7 @@ #![no_main] use defmt::*; -use embassy_stm32::adc::{adc4, AdcChannel}; +use embassy_stm32::adc::{AdcChannel, adc4}; use {defmt_rtt as _, panic_probe as _}; #[embassy_executor::main] diff --git a/examples/stm32wba6/src/bin/pwm.rs b/examples/stm32wba6/src/bin/pwm.rs index 2c696834a..64ae01945 100644 --- a/examples/stm32wba6/src/bin/pwm.rs +++ b/examples/stm32wba6/src/bin/pwm.rs @@ -4,13 +4,13 @@ use defmt::*; use defmt_rtt as _; // global logger use embassy_executor::Spawner; +use embassy_stm32::Config; use embassy_stm32::gpio::OutputType; use embassy_stm32::rcc::{ AHB5Prescaler, AHBPrescaler, APBPrescaler, PllDiv, PllMul, PllPreDiv, PllSource, Sysclk, VoltageScale, }; use embassy_stm32::time::khz; use embassy_stm32::timer::simple_pwm::{PwmPin, SimplePwm}; -use embassy_stm32::Config; use embassy_time::Timer; use panic_probe as _; diff --git a/examples/stm32wba6/src/bin/usb_hs_serial.rs b/examples/stm32wba6/src/bin/usb_hs_serial.rs index 20bdeaac3..a60eeb480 100644 --- a/examples/stm32wba6/src/bin/usb_hs_serial.rs +++ b/examples/stm32wba6/src/bin/usb_hs_serial.rs @@ -5,10 +5,10 @@ use defmt::{panic, *}; use embassy_executor::Spawner; use embassy_futures::join::join; use embassy_stm32::usb::{Driver, Instance}; -use embassy_stm32::{bind_interrupts, peripherals, usb, Config}; +use embassy_stm32::{Config, bind_interrupts, peripherals, usb}; +use embassy_usb::Builder; use embassy_usb::class::cdc_acm::{CdcAcmClass, State}; use embassy_usb::driver::EndpointError; -use embassy_usb::Builder; use {defmt_rtt as _, panic_probe as _}; bind_interrupts!(struct Irqs { diff --git a/examples/stm32wl/src/bin/adc.rs b/examples/stm32wl/src/bin/adc.rs index 118f02ae1..6b21b086b 100644 --- a/examples/stm32wl/src/bin/adc.rs +++ b/examples/stm32wl/src/bin/adc.rs @@ -5,8 +5,8 @@ use core::mem::MaybeUninit; use defmt::*; use embassy_executor::Spawner; -use embassy_stm32::adc::{Adc, CkModePclk, Clock, SampleTime}; use embassy_stm32::SharedData; +use embassy_stm32::adc::{Adc, CkModePclk, Clock, SampleTime}; use embassy_time::Timer; use {defmt_rtt as _, panic_probe as _}; diff --git a/examples/stm32wl/src/bin/blinky.rs b/examples/stm32wl/src/bin/blinky.rs index a2a90871d..f7f57e35c 100644 --- a/examples/stm32wl/src/bin/blinky.rs +++ b/examples/stm32wl/src/bin/blinky.rs @@ -5,8 +5,8 @@ use core::mem::MaybeUninit; use defmt::*; use embassy_executor::Spawner; -use embassy_stm32::gpio::{Level, Output, Speed}; use embassy_stm32::SharedData; +use embassy_stm32::gpio::{Level, Output, Speed}; use embassy_time::Timer; use {defmt_rtt as _, panic_probe as _}; diff --git a/examples/stm32wl/src/bin/button.rs b/examples/stm32wl/src/bin/button.rs index 21bcd2ac6..07bc95ad7 100644 --- a/examples/stm32wl/src/bin/button.rs +++ b/examples/stm32wl/src/bin/button.rs @@ -5,8 +5,8 @@ use core::mem::MaybeUninit; use cortex_m_rt::entry; use defmt::*; -use embassy_stm32::gpio::{Input, Level, Output, Pull, Speed}; use embassy_stm32::SharedData; +use embassy_stm32::gpio::{Input, Level, Output, Pull, Speed}; use {defmt_rtt as _, panic_probe as _}; #[unsafe(link_section = ".shared_data")] diff --git a/examples/stm32wl/src/bin/button_exti.rs b/examples/stm32wl/src/bin/button_exti.rs index 0a8aece34..953b13bac 100644 --- a/examples/stm32wl/src/bin/button_exti.rs +++ b/examples/stm32wl/src/bin/button_exti.rs @@ -5,9 +5,9 @@ use core::mem::MaybeUninit; use defmt::*; use embassy_executor::Spawner; +use embassy_stm32::SharedData; use embassy_stm32::exti::ExtiInput; use embassy_stm32::gpio::Pull; -use embassy_stm32::SharedData; use {defmt_rtt as _, panic_probe as _}; #[unsafe(link_section = ".shared_data")] diff --git a/examples/stm32wl/src/bin/flash.rs b/examples/stm32wl/src/bin/flash.rs index 320a9723a..bc707820d 100644 --- a/examples/stm32wl/src/bin/flash.rs +++ b/examples/stm32wl/src/bin/flash.rs @@ -5,8 +5,8 @@ use core::mem::MaybeUninit; use defmt::{info, unwrap}; use embassy_executor::Spawner; -use embassy_stm32::flash::Flash; use embassy_stm32::SharedData; +use embassy_stm32::flash::Flash; use {defmt_rtt as _, panic_probe as _}; #[unsafe(link_section = ".shared_data")] diff --git a/examples/stm32wl/src/bin/random.rs b/examples/stm32wl/src/bin/random.rs index 68b9d7d00..931f9819a 100644 --- a/examples/stm32wl/src/bin/random.rs +++ b/examples/stm32wl/src/bin/random.rs @@ -7,7 +7,7 @@ use defmt::*; use embassy_executor::Spawner; use embassy_stm32::rng::{self, Rng}; use embassy_stm32::time::Hertz; -use embassy_stm32::{bind_interrupts, peripherals, SharedData}; +use embassy_stm32::{SharedData, bind_interrupts, peripherals}; use {defmt_rtt as _, panic_probe as _}; bind_interrupts!(struct Irqs{ diff --git a/examples/stm32wl/src/bin/uart_async.rs b/examples/stm32wl/src/bin/uart_async.rs index 505a85f47..829ea2de7 100644 --- a/examples/stm32wl/src/bin/uart_async.rs +++ b/examples/stm32wl/src/bin/uart_async.rs @@ -6,7 +6,7 @@ use core::mem::MaybeUninit; use defmt::*; use embassy_executor::Spawner; use embassy_stm32::usart::{Config, InterruptHandler, Uart}; -use embassy_stm32::{bind_interrupts, peripherals, SharedData}; +use embassy_stm32::{SharedData, bind_interrupts, peripherals}; use {defmt_rtt as _, panic_probe as _}; bind_interrupts!(struct Irqs{ diff --git a/tests/mspm0/src/bin/dma.rs b/tests/mspm0/src/bin/dma.rs index 6fd973a18..9c56acadc 100644 --- a/tests/mspm0/src/bin/dma.rs +++ b/tests/mspm0/src/bin/dma.rs @@ -11,8 +11,8 @@ use core::slice; use defmt::{assert, assert_eq, *}; use embassy_executor::Spawner; -use embassy_mspm0::dma::{Channel, Transfer, TransferMode, TransferOptions, Word}; use embassy_mspm0::Peri; +use embassy_mspm0::dma::{Channel, Transfer, TransferMode, TransferOptions, Word}; use {defmt_rtt as _, panic_probe as _}; #[embassy_executor::main] diff --git a/tests/perf-client/src/lib.rs b/tests/perf-client/src/lib.rs index 4bd9e5674..1ba071e8d 100644 --- a/tests/perf-client/src/lib.rs +++ b/tests/perf-client/src/lib.rs @@ -4,7 +4,7 @@ use defmt::{assert, *}; use embassy_futures::join::join; use embassy_net::tcp::TcpSocket; use embassy_net::{Ipv4Address, Stack}; -use embassy_time::{with_timeout, Duration, Timer}; +use embassy_time::{Duration, Timer, with_timeout}; pub struct Expected { pub down_kbps: usize, diff --git a/tests/rp/src/bin/cyw43-perf.rs b/tests/rp/src/bin/cyw43-perf.rs index 555134ffd..9487f5e1a 100644 --- a/tests/rp/src/bin/cyw43-perf.rs +++ b/tests/rp/src/bin/cyw43-perf.rs @@ -3,7 +3,7 @@ teleprobe_meta::target!(b"rpi-pico"); use cyw43::JoinOptions; -use cyw43_pio::{PioSpi, DEFAULT_CLOCK_DIVIDER}; +use cyw43_pio::{DEFAULT_CLOCK_DIVIDER, PioSpi}; use defmt::{panic, *}; use embassy_executor::Spawner; use embassy_net::{Config, StackResources}; diff --git a/tests/rp/src/bin/gpio_multicore.rs b/tests/rp/src/bin/gpio_multicore.rs index f48dd207b..6abcba590 100644 --- a/tests/rp/src/bin/gpio_multicore.rs +++ b/tests/rp/src/bin/gpio_multicore.rs @@ -7,10 +7,10 @@ teleprobe_meta::target!(b"pimoroni-pico-plus-2"); use defmt::{info, unwrap}; use embassy_executor::Executor; +use embassy_rp::Peri; use embassy_rp::gpio::{Input, Level, Output, Pull}; -use embassy_rp::multicore::{spawn_core1, Stack}; +use embassy_rp::multicore::{Stack, spawn_core1}; use embassy_rp::peripherals::{PIN_0, PIN_1}; -use embassy_rp::Peri; use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex; use embassy_sync::channel::Channel; use static_cell::StaticCell; diff --git a/tests/rp/src/bin/multicore.rs b/tests/rp/src/bin/multicore.rs index 11b03cfea..7e34bc778 100644 --- a/tests/rp/src/bin/multicore.rs +++ b/tests/rp/src/bin/multicore.rs @@ -7,7 +7,7 @@ teleprobe_meta::target!(b"pimoroni-pico-plus-2"); use defmt::{info, unwrap}; use embassy_executor::Executor; -use embassy_rp::multicore::{spawn_core1, Stack}; +use embassy_rp::multicore::{Stack, spawn_core1}; use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex; use embassy_sync::channel::Channel; use static_cell::StaticCell; diff --git a/tests/rp/src/bin/overclock.rs b/tests/rp/src/bin/overclock.rs index 167a26eb2..87a03b5e2 100644 --- a/tests/rp/src/bin/overclock.rs +++ b/tests/rp/src/bin/overclock.rs @@ -8,7 +8,7 @@ teleprobe_meta::target!(b"pimoroni-pico-plus-2"); use defmt::info; use embassy_executor::Spawner; -use embassy_rp::clocks::{clk_sys_freq, core_voltage, ClockConfig, CoreVoltage}; +use embassy_rp::clocks::{ClockConfig, CoreVoltage, clk_sys_freq, core_voltage}; use embassy_rp::config::Config; use embassy_time::Instant; use {defmt_rtt as _, panic_probe as _}; diff --git a/tests/rp/src/bin/pio_multi_load.rs b/tests/rp/src/bin/pio_multi_load.rs index aca476d56..82bbab272 100644 --- a/tests/rp/src/bin/pio_multi_load.rs +++ b/tests/rp/src/bin/pio_multi_load.rs @@ -57,7 +57,9 @@ async fn main(_spawner: Spawner) { assert_eq!(loaded2.wrap.target, 14); // wrapping around the end of program space automatically works - let prg3 = pio_asm!("nop", "nop", "nop", "nop", "nop", "nop", "nop", "nop", "nop", "nop", "nop", "irq 2",); + let prg3 = pio_asm!( + "nop", "nop", "nop", "nop", "nop", "nop", "nop", "nop", "nop", "nop", "nop", "irq 2", + ); let loaded3 = common.load_program(&prg3.program); assert_eq!(loaded3.origin, 24); assert_eq!(loaded3.wrap.source, 3); diff --git a/tests/rp/src/bin/rtc.rs b/tests/rp/src/bin/rtc.rs index c66981d95..e1def7b5b 100644 --- a/tests/rp/src/bin/rtc.rs +++ b/tests/rp/src/bin/rtc.rs @@ -5,7 +5,7 @@ teleprobe_meta::target!(b"rpi-pico"); use defmt::{assert, *}; use embassy_executor::Spawner; -use embassy_futures::select::{select, Either}; +use embassy_futures::select::{Either, select}; use embassy_rp::bind_interrupts; use embassy_rp::rtc::{DateTime, DateTimeFilter, DayOfWeek, Rtc}; use embassy_time::{Duration, Instant, Timer}; diff --git a/tests/rp/src/bin/spinlock_mutex_multicore.rs b/tests/rp/src/bin/spinlock_mutex_multicore.rs index c56d43ade..25c4faf37 100644 --- a/tests/rp/src/bin/spinlock_mutex_multicore.rs +++ b/tests/rp/src/bin/spinlock_mutex_multicore.rs @@ -7,7 +7,7 @@ teleprobe_meta::target!(b"pimoroni-pico-plus-2"); use defmt::{info, unwrap}; use embassy_executor::Executor; -use embassy_rp::multicore::{spawn_core1, Stack}; +use embassy_rp::multicore::{Stack, spawn_core1}; use embassy_rp::spinlock_mutex::SpinlockRawMutex; use embassy_sync::channel::Channel; use static_cell::StaticCell; diff --git a/tests/stm32/src/bin/afio.rs b/tests/stm32/src/bin/afio.rs index 81d50874b..d88765717 100644 --- a/tests/stm32/src/bin/afio.rs +++ b/tests/stm32/src/bin/afio.rs @@ -16,7 +16,7 @@ use embassy_stm32::timer::qei::Qei; use embassy_stm32::timer::simple_pwm::{PwmPin, SimplePwm}; use embassy_stm32::timer::{Ch1, Ch2}; use embassy_stm32::usart::{Uart, UartRx, UartTx}; -use embassy_stm32::{bind_interrupts, Peripherals}; +use embassy_stm32::{Peripherals, bind_interrupts}; #[cfg(not(feature = "afio-connectivity-line"))] bind_interrupts!(struct Irqs { diff --git a/tests/stm32/src/bin/cryp.rs b/tests/stm32/src/bin/cryp.rs index f54c99cc3..640de50e3 100644 --- a/tests/stm32/src/bin/cryp.rs +++ b/tests/stm32/src/bin/cryp.rs @@ -5,9 +5,9 @@ #[path = "../common.rs"] mod common; +use aes_gcm::Aes128Gcm; use aes_gcm::aead::heapless::Vec; use aes_gcm::aead::{AeadInPlace, KeyInit}; -use aes_gcm::Aes128Gcm; use common::*; use embassy_executor::Spawner; use embassy_stm32::cryp::{self, *}; diff --git a/tests/stm32/src/bin/fdcan.rs b/tests/stm32/src/bin/fdcan.rs index c2a1a7bb8..d97f493df 100644 --- a/tests/stm32/src/bin/fdcan.rs +++ b/tests/stm32/src/bin/fdcan.rs @@ -8,7 +8,7 @@ mod common; use common::*; use embassy_executor::Spawner; use embassy_stm32::peripherals::*; -use embassy_stm32::{bind_interrupts, can, Config}; +use embassy_stm32::{Config, bind_interrupts, can}; use embassy_time::Duration; use {defmt_rtt as _, panic_probe as _}; diff --git a/tests/stm32/src/bin/stop.rs b/tests/stm32/src/bin/stop.rs index 8119c1f39..833ca05d0 100644 --- a/tests/stm32/src/bin/stop.rs +++ b/tests/stm32/src/bin/stop.rs @@ -9,10 +9,10 @@ use chrono::NaiveDate; use common::*; use cortex_m_rt::entry; use embassy_executor::Spawner; -use embassy_stm32::low_power::{stop_ready, stop_with_rtc, Executor, StopMode}; +use embassy_stm32::Config; +use embassy_stm32::low_power::{Executor, StopMode, stop_ready, stop_with_rtc}; use embassy_stm32::rcc::LsConfig; use embassy_stm32::rtc::{Rtc, RtcConfig}; -use embassy_stm32::Config; use embassy_time::Timer; use static_cell::StaticCell; diff --git a/tests/stm32/src/bin/ucpd.rs b/tests/stm32/src/bin/ucpd.rs index 97aefe1a0..c794afff8 100644 --- a/tests/stm32/src/bin/ucpd.rs +++ b/tests/stm32/src/bin/ucpd.rs @@ -9,7 +9,7 @@ use defmt::{assert, assert_eq}; use embassy_executor::Spawner; use embassy_futures::join::join; use embassy_stm32::ucpd::{self, CcPhy, CcPull, CcSel, CcVState, RxError, Ucpd}; -use embassy_stm32::{bind_interrupts, peripherals, Peri}; +use embassy_stm32::{Peri, bind_interrupts, peripherals}; use embassy_time::Timer; bind_interrupts!(struct Irqs { diff --git a/tests/stm32/src/bin/usart.rs b/tests/stm32/src/bin/usart.rs index 129c7b692..0b98d3eeb 100644 --- a/tests/stm32/src/bin/usart.rs +++ b/tests/stm32/src/bin/usart.rs @@ -7,7 +7,7 @@ use common::*; use defmt::{assert, assert_eq, unreachable}; use embassy_executor::Spawner; use embassy_stm32::usart::{Config, ConfigError, Error, Uart}; -use embassy_time::{block_for, Duration, Instant}; +use embassy_time::{Duration, Instant, block_for}; #[embassy_executor::main] async fn main(_spawner: Spawner) { diff --git a/tests/stm32/src/bin/wpan_ble.rs b/tests/stm32/src/bin/wpan_ble.rs index 8957bfc04..0f396b848 100644 --- a/tests/stm32/src/bin/wpan_ble.rs +++ b/tests/stm32/src/bin/wpan_ble.rs @@ -12,16 +12,16 @@ use embassy_executor::Spawner; use embassy_stm32::bind_interrupts; use embassy_stm32::ipcc::{Config, ReceiveInterruptHandler, TransmitInterruptHandler}; use embassy_stm32::rcc::WPAN_DEFAULT; +use embassy_stm32_wpan::TlMbox; +use embassy_stm32_wpan::hci::BdAddr; use embassy_stm32_wpan::hci::host::uart::UartHci; use embassy_stm32_wpan::hci::host::{AdvertisingFilterPolicy, EncryptionKey, HostHci, OwnAddressType}; use embassy_stm32_wpan::hci::types::AdvertisingType; use embassy_stm32_wpan::hci::vendor::command::gap::{AdvertisingDataType, DiscoverableParameters, GapCommands, Role}; use embassy_stm32_wpan::hci::vendor::command::gatt::GattCommands; use embassy_stm32_wpan::hci::vendor::command::hal::{ConfigData, HalCommands, PowerLevel}; -use embassy_stm32_wpan::hci::BdAddr; use embassy_stm32_wpan::lhci::LhciC1DeviceInformationCcrp; use embassy_stm32_wpan::sub::mm; -use embassy_stm32_wpan::TlMbox; use {defmt_rtt as _, panic_probe as _}; bind_interrupts!(struct Irqs{ diff --git a/tests/stm32/src/bin/wpan_mac.rs b/tests/stm32/src/bin/wpan_mac.rs index 79e13d524..f27146c44 100644 --- a/tests/stm32/src/bin/wpan_mac.rs +++ b/tests/stm32/src/bin/wpan_mac.rs @@ -10,13 +10,13 @@ use embassy_executor::Spawner; use embassy_stm32::bind_interrupts; use embassy_stm32::ipcc::{Config, ReceiveInterruptHandler, TransmitInterruptHandler}; use embassy_stm32::rcc::WPAN_DEFAULT; +use embassy_stm32_wpan::TlMbox; use embassy_stm32_wpan::mac::commands::{AssociateRequest, GetRequest, ResetRequest, SetRequest}; use embassy_stm32_wpan::mac::event::MacEvent; use embassy_stm32_wpan::mac::typedefs::{ AddressMode, Capabilities, KeyIdMode, MacAddress, MacChannel, PanId, PibId, SecurityLevel, }; use embassy_stm32_wpan::sub::mm; -use embassy_stm32_wpan::TlMbox; use {defmt_rtt as _, panic_probe as _}; bind_interrupts!(struct Irqs{ diff --git a/tests/stm32/src/common.rs b/tests/stm32/src/common.rs index f800769ab..2bd934d6f 100644 --- a/tests/stm32/src/common.rs +++ b/tests/stm32/src/common.rs @@ -1,11 +1,11 @@ #![macro_use] pub use defmt::*; +use embassy_stm32::Config; #[allow(unused)] use embassy_stm32::rcc::*; #[allow(unused)] use embassy_stm32::time::Hertz; -use embassy_stm32::Config; use {defmt_rtt as _, panic_probe as _}; #[cfg(feature = "stm32f103c8")] diff --git a/tests/utils/src/bin/saturate_serial.rs b/tests/utils/src/bin/saturate_serial.rs index 85676b106..1c8a8b322 100644 --- a/tests/utils/src/bin/saturate_serial.rs +++ b/tests/utils/src/bin/saturate_serial.rs @@ -2,7 +2,7 @@ use std::path::Path; use std::time::Duration; use std::{env, io, process, thread}; -use rand::{rng, Rng}; +use rand::{Rng, rng}; use serial::SerialPort; pub fn main() { -- cgit From dbf0416abd48190056a25828d8e5d8f889170f88 Mon Sep 17 00:00:00 2001 From: Dario Nieuwenhuis Date: Mon, 6 Oct 2025 23:09:42 +0200 Subject: executor: Fix compiletest for edition 2024. --- embassy-executor/tests/ui/nonstatic_struct_elided.stderr | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/embassy-executor/tests/ui/nonstatic_struct_elided.stderr b/embassy-executor/tests/ui/nonstatic_struct_elided.stderr index 0ee1bfe0c..e6829bf5d 100644 --- a/embassy-executor/tests/ui/nonstatic_struct_elided.stderr +++ b/embassy-executor/tests/ui/nonstatic_struct_elided.stderr @@ -9,16 +9,16 @@ help: indicate the anonymous lifetime 6 | async fn task(_x: Foo<'_>) {} | ++++ -error[E0700]: hidden type for `impl Sized` captures lifetime that does not appear in bounds +error: lifetime may not live long enough --> tests/ui/nonstatic_struct_elided.rs:5:1 | 5 | #[embassy_executor::task] - | ^^^^^^^^^^^^^^^^^^^^^^^^^ opaque type defined here + | ^^^^^^^^^^^^^^^^^^^^^^^^^ returning this value requires that `'1` must outlive `'static` 6 | async fn task(_x: Foo) {} - | --- hidden type `impl Sized` captures the anonymous lifetime defined here + | -- has type `Foo<'1>` | = note: this error originates in the attribute macro `embassy_executor::task` (in Nightly builds, run with -Z macro-backtrace for more info) -help: add a `use<...>` bound to explicitly capture `'_` +help: to declare that `impl Sized` captures data from argument `_x`, you can add an explicit `'_` lifetime bound | -5 | #[embassy_executor::task] + use<'_> - | +++++++++ +5 | #[embassy_executor::task] + '_ + | ++++ -- cgit From cd91fe3b30dbb3d5b3c9c7d9e7cb151d721fb8d5 Mon Sep 17 00:00:00 2001 From: maor malka Date: Tue, 7 Oct 2025 07:57:29 -0400 Subject: stm32/adc/v3: merged newer adc_g0 configuration method to intoRingBuffered --- embassy-stm32/src/adc/v3.rs | 109 +++++++++++++++++++++++++++----------------- 1 file changed, 67 insertions(+), 42 deletions(-) diff --git a/embassy-stm32/src/adc/v3.rs b/embassy-stm32/src/adc/v3.rs index 39f9ee463..0b9b80db2 100644 --- a/embassy-stm32/src/adc/v3.rs +++ b/embassy-stm32/src/adc/v3.rs @@ -13,10 +13,10 @@ use super::{ blocking_delay_us, Adc, AdcChannel, AnyAdcChannel, Instance, Resolution, RxDma, SampleTime, SealedAdcChannel, }; -#[cfg(any(adc_v3, adc_g0))] +#[cfg(any(adc_v3, adc_g0, adc_u0))] mod ringbuffered_v3; -#[cfg(any(adc_v3, adc_g0))] +#[cfg(any(adc_v3, adc_g0, adc_u0))] use ringbuffered_v3::RingBufferedAdc; use crate::dma::Transfer; @@ -601,53 +601,78 @@ impl<'d, T: Instance> Adc<'d, T> { w.set_l(sequence.len() as u8 - 1); }); - #[cfg(any(adc_g0, adc_u0))] - let mut channel_mask = 0; + #[cfg(adc_g0)] + { + let mut sample_times = Vec::::new(); + + T::regs().chselr().write(|chselr| { + T::regs().smpr().write(|smpr| { + for (channel, sample_time) in sequence { + chselr.set_chsel(channel.channel.into(), true); + if let Some(i) = sample_times.iter().position(|&t| t == sample_time) { + smpr.set_smpsel(channel.channel.into(), (i as u8).into()); + } else { + smpr.set_sample_time(sample_times.len(), sample_time); + if let Err(_) = sample_times.push(sample_time) { + panic!( + "Implementation is limited to {} unique sample times among all channels.", + SAMPLE_TIMES_CAPACITY + ); + } + } + } + }) + }); + } + #[cfg(not(adc_g0))] + { + #[cfg(adc_u0)] + let mut channel_mask = 0; - // Configure channels and ranks - for (_i, (channel, sample_time)) in sequence.enumerate() { - Self::configure_channel(channel, sample_time); + // Configure channels and ranks + for (_i, (channel, sample_time)) in sequence.enumerate() { + Self::configure_channel(channel, sample_time); - // Each channel is sampled according to sequence - #[cfg(not(any(adc_g0, adc_u0)))] - match _i { - 0..=3 => { - T::regs().sqr1().modify(|w| { - w.set_sq(_i, channel.channel()); - }); - } - 4..=8 => { - T::regs().sqr2().modify(|w| { - w.set_sq(_i - 4, channel.channel()); - }); - } - 9..=13 => { - T::regs().sqr3().modify(|w| { - w.set_sq(_i - 9, channel.channel()); - }); + // Each channel is sampled according to sequence + #[cfg(not(any(adc_g0, adc_u0)))] + match _i { + 0..=3 => { + T::regs().sqr1().modify(|w| { + w.set_sq(_i, channel.channel()); + }); + } + 4..=8 => { + T::regs().sqr2().modify(|w| { + w.set_sq(_i - 4, channel.channel()); + }); + } + 9..=13 => { + T::regs().sqr3().modify(|w| { + w.set_sq(_i - 9, channel.channel()); + }); + } + 14..=15 => { + T::regs().sqr4().modify(|w| { + w.set_sq(_i - 14, channel.channel()); + }); + } + _ => unreachable!(), } - 14..=15 => { - T::regs().sqr4().modify(|w| { - w.set_sq(_i - 14, channel.channel()); - }); + + #[cfg(adc_u0)] + { + channel_mask |= 1 << channel.channel(); } - _ => unreachable!(), } - #[cfg(any(adc_g0, adc_u0))] - { - channel_mask |= 1 << channel.channel(); - } + // On G0 and U0 enabled channels are sampled from 0 to last channel. + // It is possible to add up to 8 sequences if CHSELRMOD = 1. + // However for supporting more than 8 channels alternative CHSELRMOD = 0 approach is used. + #[cfg(adc_u0)] + T::regs().chselr().modify(|reg| { + reg.set_chsel(channel_mask); + }); } - - // On G0 and U0 enabled channels are sampled from 0 to last channel. - // It is possible to add up to 8 sequences if CHSELRMOD = 1. - // However for supporting more than 8 channels alternative CHSELRMOD = 0 approach is used. - #[cfg(any(adc_g0, adc_u0))] - T::regs().chselr().modify(|reg| { - reg.set_chsel(channel_mask); - }); - // Set continuous mode with Circular dma. // Clear overrun flag before starting transfer. T::regs().isr().modify(|reg| { -- cgit From 151b1067b09fcc64e291254c0563da04b19d12a7 Mon Sep 17 00:00:00 2001 From: Charles Guan <3221512+charlesincharge@users.noreply.github.com> Date: Thu, 2 Oct 2025 16:08:49 -0700 Subject: Enable input-buffer and enable output drive for I/O pin --- embassy-mspm0/CHANGELOG.md | 1 + embassy-mspm0/src/gpio.rs | 7 ++++++- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/embassy-mspm0/CHANGELOG.md b/embassy-mspm0/CHANGELOG.md index b846f21b1..aaa09892c 100644 --- a/embassy-mspm0/CHANGELOG.md +++ b/embassy-mspm0/CHANGELOG.md @@ -13,3 +13,4 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - feat: Add window watchdog implementation based on WWDT0, WWDT1 peripherals (#4574) - feat: Add MSPM0C1105/C1106 support - feat: Add adc implementation (#4646) +- fix: gpio OutputOpenDrain config (#4735) \ No newline at end of file diff --git a/embassy-mspm0/src/gpio.rs b/embassy-mspm0/src/gpio.rs index d5fd36dbf..f9a8d6b75 100644 --- a/embassy-mspm0/src/gpio.rs +++ b/embassy-mspm0/src/gpio.rs @@ -156,7 +156,12 @@ impl<'d> Flex<'d> { w.set_pf(GPIO_PF); w.set_hiz1(true); w.set_pc(true); - w.set_inena(false); + w.set_inena(true); + }); + + // Enable output driver (DOE) - required for open-drain to drive low + self.pin.block().doeset31_0().write(|w| { + w.set_dio(self.pin.bit_index(), true); }); self.set_pull(Pull::None); -- cgit From cb0175a89f072d38393368ef380d9db8e3994740 Mon Sep 17 00:00:00 2001 From: maor malka Date: Tue, 7 Oct 2025 15:03:31 -0400 Subject: stm32/adc/v3: missing cfg option for adc_u0 fro into_ring_buffered --- embassy-stm32/src/adc/ringbuffered_v3.rs | 2 +- embassy-stm32/src/adc/v3.rs | 2 +- examples/stm32l4/src/bin/adc_dma.rs | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/embassy-stm32/src/adc/ringbuffered_v3.rs b/embassy-stm32/src/adc/ringbuffered_v3.rs index a2c9f2bca..b58630585 100644 --- a/embassy-stm32/src/adc/ringbuffered_v3.rs +++ b/embassy-stm32/src/adc/ringbuffered_v3.rs @@ -1,5 +1,5 @@ use core::marker::PhantomData; -use core::sync::atomic::{compiler_fence, Ordering}; +use core::sync::atomic::{Ordering, compiler_fence}; use embassy_hal_internal::Peri; diff --git a/embassy-stm32/src/adc/v3.rs b/embassy-stm32/src/adc/v3.rs index 8dcb5d04e..d9a3ce21d 100644 --- a/embassy-stm32/src/adc/v3.rs +++ b/embassy-stm32/src/adc/v3.rs @@ -576,7 +576,7 @@ impl<'d, T: Instance> Adc<'d, T> { /// It is critical to call `read` frequently to prevent DMA buffer overrun. /// /// [`read`]: #method.read - #[cfg(any(adc_v3, adc_g0))] + #[cfg(any(adc_v3, adc_g0, adc_u0))] pub fn into_ring_buffered<'a>( &mut self, dma: Peri<'a, impl RxDma>, diff --git a/examples/stm32l4/src/bin/adc_dma.rs b/examples/stm32l4/src/bin/adc_dma.rs index a5b7b0c5e..7a9200edd 100644 --- a/examples/stm32l4/src/bin/adc_dma.rs +++ b/examples/stm32l4/src/bin/adc_dma.rs @@ -3,8 +3,8 @@ use defmt::*; use embassy_executor::Spawner; -use embassy_stm32::adc::{Adc, AdcChannel, SampleTime}; use embassy_stm32::Config; +use embassy_stm32::adc::{Adc, AdcChannel, SampleTime}; use {defmt_rtt as _, panic_probe as _}; const DMA_BUF_LEN: usize = 512; -- cgit From 3f9af34e5a2347076df1f860baabaaa47eeca13d Mon Sep 17 00:00:00 2001 From: i509VCB Date: Thu, 2 Oct 2025 17:13:32 -0500 Subject: mspm0: add mspm0c1106 to test matrix RGZ package chosen to match LP-MSPM0C1106 board --- embassy-mspm0/CHANGELOG.md | 3 ++- embassy-mspm0/Cargo.toml | 1 + 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/embassy-mspm0/CHANGELOG.md b/embassy-mspm0/CHANGELOG.md index aaa09892c..40abca38b 100644 --- a/embassy-mspm0/CHANGELOG.md +++ b/embassy-mspm0/CHANGELOG.md @@ -13,4 +13,5 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - feat: Add window watchdog implementation based on WWDT0, WWDT1 peripherals (#4574) - feat: Add MSPM0C1105/C1106 support - feat: Add adc implementation (#4646) -- fix: gpio OutputOpenDrain config (#4735) \ No newline at end of file +- fix: gpio OutputOpenDrain config (#4735) +- fix: add MSPM0C1106 to build test matrix \ No newline at end of file diff --git a/embassy-mspm0/Cargo.toml b/embassy-mspm0/Cargo.toml index 65019eb7c..7245cd100 100644 --- a/embassy-mspm0/Cargo.toml +++ b/embassy-mspm0/Cargo.toml @@ -15,6 +15,7 @@ publish = false [package.metadata.embassy] build = [ {target = "thumbv6m-none-eabi", features = ["defmt", "mspm0c1104dgs20", "time-driver-any"]}, + {target = "thumbv6m-none-eabi", features = ["defmt", "mspm0c1106rgz", "time-driver-any"]}, {target = "thumbv6m-none-eabi", features = ["defmt", "mspm0g3507pm", "time-driver-any"]}, {target = "thumbv6m-none-eabi", features = ["defmt", "mspm0g3519pz", "time-driver-any"]}, {target = "thumbv6m-none-eabi", features = ["defmt", "mspm0l1306rhb", "time-driver-any"]}, -- cgit From c6799c2921780254319d293d37f33161f5fd1832 Mon Sep 17 00:00:00 2001 From: i509VCB Date: Thu, 2 Oct 2025 17:02:20 -0500 Subject: mspm0: add mspm0h321x support This also changes selection of GPIO interrupt type to be calculated by the buildscript. H321x is yet another exception with GPIOB being a physical interrupt rather than part of an interrupt group. H3215/6 are true 5V parts. I wonder if that is a first for an embassy hal --- embassy-mspm0/CHANGELOG.md | 3 ++- embassy-mspm0/Cargo.toml | 17 +++++++++------- embassy-mspm0/build.rs | 50 ++++++++++++++++++++++++++++++++++++++-------- embassy-mspm0/src/gpio.rs | 17 ++++++++++------ embassy-mspm0/src/i2c.rs | 4 ++-- 5 files changed, 67 insertions(+), 24 deletions(-) diff --git a/embassy-mspm0/CHANGELOG.md b/embassy-mspm0/CHANGELOG.md index 40abca38b..948f0205d 100644 --- a/embassy-mspm0/CHANGELOG.md +++ b/embassy-mspm0/CHANGELOG.md @@ -14,4 +14,5 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - feat: Add MSPM0C1105/C1106 support - feat: Add adc implementation (#4646) - fix: gpio OutputOpenDrain config (#4735) -- fix: add MSPM0C1106 to build test matrix \ No newline at end of file +- fix: add MSPM0C1106 to build test matrix +- feat: add MSPM0H3216 support diff --git a/embassy-mspm0/Cargo.toml b/embassy-mspm0/Cargo.toml index 7245cd100..df6176ff6 100644 --- a/embassy-mspm0/Cargo.toml +++ b/embassy-mspm0/Cargo.toml @@ -16,17 +16,18 @@ publish = false build = [ {target = "thumbv6m-none-eabi", features = ["defmt", "mspm0c1104dgs20", "time-driver-any"]}, {target = "thumbv6m-none-eabi", features = ["defmt", "mspm0c1106rgz", "time-driver-any"]}, + {target = "thumbv6m-none-eabi", features = ["defmt", "mspm0g1107ycj", "time-driver-any"]}, + {target = "thumbv6m-none-eabi", features = ["defmt", "mspm0g1505pt", "time-driver-any"]}, + {target = "thumbv6m-none-eabi", features = ["defmt", "mspm0g1519rhb", "time-driver-any"]}, + {target = "thumbv6m-none-eabi", features = ["defmt", "mspm0g3105rhb", "time-driver-any"]}, {target = "thumbv6m-none-eabi", features = ["defmt", "mspm0g3507pm", "time-driver-any"]}, {target = "thumbv6m-none-eabi", features = ["defmt", "mspm0g3519pz", "time-driver-any"]}, + {target = "thumbv6m-none-eabi", features = ["defmt", "mspm0h3216pt", "time-driver-any"]}, {target = "thumbv6m-none-eabi", features = ["defmt", "mspm0l1306rhb", "time-driver-any"]}, {target = "thumbv6m-none-eabi", features = ["defmt", "mspm0l2228pn", "time-driver-any"]}, {target = "thumbv6m-none-eabi", features = ["defmt", "mspm0l1345dgs28", "time-driver-any"]}, {target = "thumbv6m-none-eabi", features = ["defmt", "mspm0l1106dgs28", "time-driver-any"]}, - {target = "thumbv6m-none-eabi", features = ["defmt", "mspm0l1228pm", "time-driver-any"]}, - {target = "thumbv6m-none-eabi", features = ["defmt", "mspm0g1107ycj", "time-driver-any"]}, - {target = "thumbv6m-none-eabi", features = ["defmt", "mspm0g3105rhb", "time-driver-any"]}, - {target = "thumbv6m-none-eabi", features = ["defmt", "mspm0g1505pt", "time-driver-any"]}, - {target = "thumbv6m-none-eabi", features = ["defmt", "mspm0g1519rhb", "time-driver-any"]}, + {target = "thumbv6m-none-eabi", features = ["defmt", "mspm0l1228pt", "time-driver-any"]}, ] [package.metadata.embassy_docs] @@ -38,6 +39,7 @@ flavors = [ { regex_feature = "mspm0c.*", target = "thumbv6m-none-eabi" }, { regex_feature = "mspm0l.*", target = "thumbv6m-none-eabi" }, { regex_feature = "mspm0g.*", target = "thumbv6m-none-eabi" }, + { regex_feature = "mspm0h.*", target = "thumbv6m-none-eabi" }, ] [package.metadata.docs.rs] @@ -70,7 +72,7 @@ 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-d7bf3d01ac0780e716a45b0474234d39443dc5cf" } +mspm0-metapac = { git = "https://github.com/mspm0-rs/mspm0-data-generated/", tag = "mspm0-data-e7de4103a0713772695ffcad52c3c2f07414dc29" } [build-dependencies] proc-macro2 = "1.0.94" @@ -78,7 +80,7 @@ quote = "1.0.40" cfg_aliases = "0.2.1" # mspm0-metapac = { version = "", default-features = false, features = ["metadata"] } -mspm0-metapac = { git = "https://github.com/mspm0-rs/mspm0-data-generated/", tag = "mspm0-data-d7bf3d01ac0780e716a45b0474234d39443dc5cf", default-features = false, features = ["metadata"] } +mspm0-metapac = { git = "https://github.com/mspm0-rs/mspm0-data-generated/", tag = "mspm0-data-e7de4103a0713772695ffcad52c3c2f07414dc29", default-features = false, features = ["metadata"] } [features] default = ["rt"] @@ -244,6 +246,7 @@ mspm0g3519pn = ["mspm0-metapac/mspm0g3519pn"] mspm0g3519pz = ["mspm0-metapac/mspm0g3519pz"] mspm0g3519rgz = ["mspm0-metapac/mspm0g3519rgz"] mspm0g3519rhb = ["mspm0-metapac/mspm0g3519rhb"] +mspm0h3216pt = ["mspm0-metapac/mspm0h3216pt"] mspm0l1105dgs20 = ["mspm0-metapac/mspm0l1105dgs20"] mspm0l1105dgs28 = ["mspm0-metapac/mspm0l1105dgs28"] mspm0l1105dyy = ["mspm0-metapac/mspm0l1105dyy"] diff --git a/embassy-mspm0/build.rs b/embassy-mspm0/build.rs index 93ea81ac3..1d118ad66 100644 --- a/embassy-mspm0/build.rs +++ b/embassy-mspm0/build.rs @@ -16,14 +16,15 @@ use quote::{format_ident, quote}; mod common; fn main() { - generate_code(); - interrupt_group_linker_magic(); -} - -fn generate_code() { let mut cfgs = common::CfgSet::new(); common::set_target_cfgs(&mut cfgs); + generate_code(&mut cfgs); + select_gpio_features(&mut cfgs); + interrupt_group_linker_magic(); +} + +fn generate_code(cfgs: &mut CfgSet) { #[cfg(any(feature = "rt"))] println!( "cargo:rustc-link-search={}", @@ -53,9 +54,9 @@ fn generate_code() { cfgs.declare_all(&get_chip_cfgs(&chip)); } - let mut singletons = get_singletons(&mut cfgs); + let mut singletons = get_singletons(cfgs); - time_driver(&mut singletons, &mut cfgs); + time_driver(&mut singletons, cfgs); let mut g = TokenStream::new(); @@ -68,7 +69,7 @@ fn generate_code() { g.extend(generate_pin_trait_impls()); g.extend(generate_groups()); g.extend(generate_dma_channel_count()); - g.extend(generate_adc_constants(&mut cfgs)); + g.extend(generate_adc_constants(cfgs)); let out_dir = &PathBuf::from(env::var_os("OUT_DIR").unwrap()); let out_file = out_dir.join("_generated.rs").to_string_lossy().to_string(); @@ -115,6 +116,10 @@ fn get_chip_cfgs(chip_name: &str) -> Vec { cfgs.push("mspm0g351x".to_string()); } + if chip_name.starts_with("mspm0h321") { + cfgs.push("mspm0h321x".to_string()); + } + if chip_name.starts_with("mspm0l110") { cfgs.push("mspm0l110x".to_string()); } @@ -646,6 +651,35 @@ fn generate_pin_trait_impls() -> TokenStream { } } +fn select_gpio_features(cfgs: &mut CfgSet) { + cfgs.declare_all(&[ + "gpioa_interrupt", + "gpioa_group", + "gpiob_interrupt", + "gpiob_group", + "gpioc_group", + ]); + + for interrupt in METADATA.interrupts.iter() { + match interrupt.name { + "GPIOA" => cfgs.enable("gpioa_interrupt"), + "GPIOB" => cfgs.enable("gpiob_interrupt"), + _ => (), + } + } + + for group in METADATA.interrupt_groups.iter() { + for interrupt in group.interrupts { + match interrupt.name { + "GPIOA" => cfgs.enable("gpioa_group"), + "GPIOB" => cfgs.enable("gpiob_group"), + "GPIOC" => cfgs.enable("gpioc_group"), + _ => (), + } + } + } +} + /// rustfmt a given path. /// Failures are logged to stderr and ignored. fn rustfmt(path: impl AsRef) { diff --git a/embassy-mspm0/src/gpio.rs b/embassy-mspm0/src/gpio.rs index 13da4f30b..d8eb42dc2 100644 --- a/embassy-mspm0/src/gpio.rs +++ b/embassy-mspm0/src/gpio.rs @@ -10,7 +10,7 @@ use embassy_sync::waitqueue::AtomicWaker; use crate::pac::gpio::vals::*; use crate::pac::gpio::{self}; -#[cfg(all(feature = "rt", any(mspm0c110x, mspm0c1105_c1106, mspm0l110x)))] +#[cfg(all(feature = "rt", any(gpioa_interrupt, gpiob_interrupt)))] use crate::pac::interrupt; use crate::pac::{self}; @@ -1110,16 +1110,21 @@ fn irq_handler(gpio: gpio::Gpio, wakers: &[AtomicWaker; 32]) { } } +#[cfg(all(gpioa_interrupt, gpioa_group))] +compile_error!("gpioa_interrupt and gpioa_group are mutually exclusive cfgs"); +#[cfg(all(gpiob_interrupt, gpiob_group))] +compile_error!("gpiob_interrupt and gpiob_group are mutually exclusive cfgs"); + // C110x and L110x have a dedicated interrupts just for GPIOA. // // These chips do not have a GROUP1 interrupt. -#[cfg(all(feature = "rt", any(mspm0c110x, mspm0c1105_c1106, mspm0l110x)))] +#[cfg(all(feature = "rt", gpioa_interrupt))] #[interrupt] fn GPIOA() { irq_handler(pac::GPIOA, &PORTA_WAKERS); } -#[cfg(all(feature = "rt", mspm0c1105_c1106))] +#[cfg(all(feature = "rt", gpiob_interrupt))] #[interrupt] fn GPIOB() { irq_handler(pac::GPIOB, &PORTB_WAKERS); @@ -1129,21 +1134,21 @@ fn GPIOB() { // // Defining these as no_mangle is required so that the linker will pick these over the default handler. -#[cfg(all(feature = "rt", not(any(mspm0c110x, mspm0c1105_c1106, mspm0l110x))))] +#[cfg(all(feature = "rt", gpioa_group))] #[unsafe(no_mangle)] #[allow(non_snake_case)] fn GPIOA() { irq_handler(pac::GPIOA, &PORTA_WAKERS); } -#[cfg(all(feature = "rt", gpio_pb, not(mspm0c1105_c1106)))] +#[cfg(all(feature = "rt", gpiob_group))] #[unsafe(no_mangle)] #[allow(non_snake_case)] fn GPIOB() { irq_handler(pac::GPIOB, &PORTB_WAKERS); } -#[cfg(all(feature = "rt", gpio_pc))] +#[cfg(all(feature = "rt", gpioc_group))] #[allow(non_snake_case)] #[unsafe(no_mangle)] fn GPIOC() { diff --git a/embassy-mspm0/src/i2c.rs b/embassy-mspm0/src/i2c.rs index a12b4b4a2..192527dd2 100644 --- a/embassy-mspm0/src/i2c.rs +++ b/embassy-mspm0/src/i2c.rs @@ -206,8 +206,8 @@ impl Config { } #[cfg(any( - mspm0g110x, mspm0g150x, mspm0g151x, mspm0g310x, mspm0g350x, mspm0g351x, mspm0l110x, mspm0l122x, mspm0l130x, - mspm0l134x, mspm0l222x + mspm0g110x, mspm0g150x, mspm0g151x, mspm0g310x, mspm0g350x, mspm0g351x, mspm0h321x, mspm0l110x, mspm0l122x, + mspm0l130x, mspm0l134x, mspm0l222x ))] fn calculate_clock_source(&self) -> u32 { // Assume that BusClk has default value. -- cgit From a83cf2480671cee67e8edaa27565203aaaf6d8bc Mon Sep 17 00:00:00 2001 From: Kezi Date: Thu, 9 Oct 2025 21:00:57 +0200 Subject: remove panic on uarte overrun --- embassy-nrf/CHANGELOG.md | 1 + embassy-nrf/src/buffered_uarte.rs | 3 ++- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/embassy-nrf/CHANGELOG.md b/embassy-nrf/CHANGELOG.md index 0244dedab..9e8d29f67 100644 --- a/embassy-nrf/CHANGELOG.md +++ b/embassy-nrf/CHANGELOG.md @@ -8,6 +8,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## Unreleased - ReleaseDate - changed: apply trimming values from FICR.TRIMCNF on nrf53/54l +- changed: do not panic on BufferedUarte overrun ## 0.8.0 - 2025-09-30 diff --git a/embassy-nrf/src/buffered_uarte.rs b/embassy-nrf/src/buffered_uarte.rs index 4c946497d..ec104788f 100644 --- a/embassy-nrf/src/buffered_uarte.rs +++ b/embassy-nrf/src/buffered_uarte.rs @@ -87,7 +87,8 @@ impl interrupt::typelevel::Handler for Interrupt r.errorsrc().write_value(errs); if errs.overrun() { - panic!("BufferedUarte overrun"); + #[cfg(feature = "defmt")] + defmt::warn!("BufferedUarte overrun"); } } -- cgit From 2f31d7da537c754f3b1ba7b9533d1c42269721c5 Mon Sep 17 00:00:00 2001 From: Angelina-2007 <24uam107angelina@kgkite.ac.in> Date: Thu, 9 Oct 2025 18:51:15 -0700 Subject: Fix #2696: Prevent 8-bit UID reads on STM32H5 by returning [u8; 12] value --- embassy-stm32/src/uid.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/embassy-stm32/src/uid.rs b/embassy-stm32/src/uid.rs index 5e38532bd..2d3e2b972 100644 --- a/embassy-stm32/src/uid.rs +++ b/embassy-stm32/src/uid.rs @@ -1,8 +1,8 @@ //! Unique ID (UID) /// Get this device's unique 96-bit ID. -pub fn uid() -> &'static [u8; 12] { - unsafe { &*crate::pac::UID.uid(0).as_ptr().cast::<[u8; 12]>() } +pub fn uid() -> [u8; 12] { + unsafe { *crate::pac::UID.uid(0).as_ptr().cast::<[u8; 12]>() } } /// Get this device's unique 96-bit ID, encoded into a string of 24 hexadecimal ASCII digits. -- cgit From 94c2cc9eba3b1840063ea11a62e2eb27442bbe16 Mon Sep 17 00:00:00 2001 From: Angelina-2007 <24uam107angelina@kgkite.ac.in> Date: Thu, 9 Oct 2025 20:21:41 -0700 Subject: ci: Add changelog entry for STM32H5 UID fix --- embassy-stm32/CHANGELOG.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/embassy-stm32/CHANGELOG.md b/embassy-stm32/CHANGELOG.md index a6ee5c4b8..7675567ff 100644 --- a/embassy-stm32/CHANGELOG.md +++ b/embassy-stm32/CHANGELOG.md @@ -6,6 +6,9 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +### [Unreleased] + +* **Fix(stm32h5):** Prevent a HardFault crash on STM32H5 devices by changing `uid()` to return `[u8; 12]` by value instead of a reference. (Fixes #2696) ## Unreleased - ReleaseDate - fix: Fixed STM32H5 builds requiring time feature -- cgit From c685d80578b0fea8f66f8f8c858c9d59857586b5 Mon Sep 17 00:00:00 2001 From: crispaudio Date: Fri, 29 Aug 2025 12:32:38 +0200 Subject: mspm0-i2c-target: add i2c target with example --- embassy-mspm0/src/i2c.rs | 45 ++-- embassy-mspm0/src/i2c_target.rs | 435 ++++++++++++++++++++++++++++++ embassy-mspm0/src/lib.rs | 1 + examples/mspm0g3507/src/bin/i2c_target.rs | 60 +++++ 4 files changed, 526 insertions(+), 15 deletions(-) create mode 100644 embassy-mspm0/src/i2c_target.rs create mode 100644 examples/mspm0g3507/src/bin/i2c_target.rs diff --git a/embassy-mspm0/src/i2c.rs b/embassy-mspm0/src/i2c.rs index 192527dd2..ce5215871 100644 --- a/embassy-mspm0/src/i2c.rs +++ b/embassy-mspm0/src/i2c.rs @@ -56,19 +56,6 @@ pub enum ClockDiv { } impl ClockDiv { - fn into(self) -> vals::Ratio { - match self { - Self::DivBy1 => vals::Ratio::DIV_BY_1, - Self::DivBy2 => vals::Ratio::DIV_BY_2, - Self::DivBy3 => vals::Ratio::DIV_BY_3, - Self::DivBy4 => vals::Ratio::DIV_BY_4, - Self::DivBy5 => vals::Ratio::DIV_BY_5, - Self::DivBy6 => vals::Ratio::DIV_BY_6, - Self::DivBy7 => vals::Ratio::DIV_BY_7, - Self::DivBy8 => vals::Ratio::DIV_BY_8, - } - } - fn divider(self) -> u32 { match self { Self::DivBy1 => 1, @@ -83,6 +70,21 @@ impl ClockDiv { } } +impl From for vals::Ratio { + fn from(value: ClockDiv) -> Self { + match value { + ClockDiv::DivBy1 => Self::DIV_BY_1, + ClockDiv::DivBy2 => Self::DIV_BY_2, + ClockDiv::DivBy3 => Self::DIV_BY_3, + ClockDiv::DivBy4 => Self::DIV_BY_4, + ClockDiv::DivBy5 => Self::DIV_BY_5, + ClockDiv::DivBy6 => Self::DIV_BY_6, + ClockDiv::DivBy7 => Self::DIV_BY_7, + ClockDiv::DivBy8 => Self::DIV_BY_8, + } + } +} + /// The I2C mode. #[derive(Clone, Copy, PartialEq, Eq, Debug)] #[cfg_attr(feature = "defmt", derive(defmt::Format))] @@ -133,6 +135,11 @@ pub enum ConfigError { /// /// The clock soure is not enabled is SYSCTL. ClockSourceNotEnabled, + + /// Invalid target address. + /// + /// The target address is not 7-bit. + InvalidTargetAddress, } #[non_exhaustive] @@ -140,7 +147,7 @@ pub enum ConfigError { /// Config pub struct Config { /// I2C clock source. - clock_source: ClockSel, + pub(crate) clock_source: ClockSel, /// I2C clock divider. pub clock_div: ClockDiv, @@ -159,6 +166,12 @@ pub struct Config { /// Set the pull configuration for the SCL pin. pub bus_speed: BusSpeed, + + /// 7-bit Target Address + pub target_addr: u8, + + /// Control if the target should ack to and report general calls. + pub general_call: bool, } impl Default for Config { @@ -171,6 +184,8 @@ impl Default for Config { sda_pull: Pull::None, scl_pull: Pull::None, bus_speed: BusSpeed::Standard, + target_addr: 0x48, + general_call: false, } } } @@ -209,7 +224,7 @@ impl Config { mspm0g110x, mspm0g150x, mspm0g151x, mspm0g310x, mspm0g350x, mspm0g351x, mspm0h321x, mspm0l110x, mspm0l122x, mspm0l130x, mspm0l134x, mspm0l222x ))] - fn calculate_clock_source(&self) -> u32 { + pub(crate) fn calculate_clock_source(&self) -> u32 { // Assume that BusClk has default value. // TODO: calculate BusClk more precisely. match self.clock_source { diff --git a/embassy-mspm0/src/i2c_target.rs b/embassy-mspm0/src/i2c_target.rs new file mode 100644 index 000000000..c6ef2f5d4 --- /dev/null +++ b/embassy-mspm0/src/i2c_target.rs @@ -0,0 +1,435 @@ +//! Inter-Integrated-Circuit (I2C) Target +// The following code is modified from embassy-stm32 and embassy-rp +// https://github.com/embassy-rs/embassy/tree/main/embassy-stm32 +// https://github.com/embassy-rs/embassy/tree/main/embassy-rp + +use core::future::poll_fn; +use core::marker::PhantomData; +use core::sync::atomic::Ordering; +use core::task::Poll; + +use mspm0_metapac::i2c::vals::CpuIntIidxStat; + +use crate::gpio::{AnyPin, SealedPin}; +use crate::interrupt; +use crate::interrupt::InterruptExt; +use crate::mode::{Async, Blocking, Mode}; +use crate::pac::{self, i2c::vals}; +use crate::Peri; +// Re-use I2c controller types +use crate::i2c::{ClockSel, Config, ConfigError, Info, Instance, InterruptHandler, SclPin, SdaPin, State}; + +/// I2C error +#[derive(Debug, PartialEq, Eq, Clone, Copy)] +#[cfg_attr(feature = "defmt", derive(defmt::Format))] +#[non_exhaustive] +pub enum Error { + /// User passed in a response buffer that was 0 length + InvalidResponseBufferLength, + /// The response buffer length was too short to contain the message + /// + /// The length parameter will always be the length of the buffer, and is + /// provided as a convenience for matching alongside `Command::Write`. + PartialWrite(usize), + /// The response buffer length was too short to contain the message + /// + /// The length parameter will always be the length of the buffer, and is + /// provided as a convenience for matching alongside `Command::GeneralCall`. + PartialGeneralCall(usize), +} + +/// Received command from the controller. +#[derive(Debug, Copy, Clone, Eq, PartialEq)] +#[cfg_attr(feature = "defmt", derive(defmt::Format))] +pub enum Command { + /// General Call Write: Controller sent the General Call address (0x00) followed by data. + /// Contains the number of bytes written by the controller. + GeneralCall(usize), + /// Read: Controller wants to read data from the target. + Read, + /// Write: Controller sent the target's address followed by data. + /// Contains the number of bytes written by the controller. + Write(usize), + /// Write followed by Read (Repeated Start): Controller wrote data, then issued a repeated + /// start and wants to read data. Contains the number of bytes written before the read. + WriteRead(usize), +} + +/// Status after responding to a controller read request. +#[derive(Debug, Copy, Clone, Eq, PartialEq)] +#[cfg_attr(feature = "defmt", derive(defmt::Format))] +pub enum ReadStatus { + /// Transaction completed successfully. The controller either NACKed the last byte + /// or sent a STOP condition. + Done, + /// Transaction Incomplete, controller trying to read more bytes than were provided + NeedMoreBytes, + /// Transaction Complere, but controller stopped reading bytes before we ran out + LeftoverBytes(u16), +} + +/// I2C Target driver. +// Use the same Instance, SclPin, SdaPin traits as the controller +pub struct I2cTarget<'d, M: Mode> { + info: &'static Info, + state: &'static State, + scl: Option>, + sda: Option>, + config: Config, + _phantom: PhantomData, +} + +impl<'d> I2cTarget<'d, Async> { + /// Create a new asynchronous I2C target driver using interrupts + pub fn new( + peri: Peri<'d, T>, + scl: Peri<'d, impl SclPin>, + sda: Peri<'d, impl SdaPin>, + _irq: impl interrupt::typelevel::Binding> + 'd, + config: Config, + ) -> Result { + let mut this = Self::new_inner( + peri, + new_pin!(scl, config.scl_pf()), + new_pin!(sda, config.sda_pf()), + config, + ); + this.reset()?; + Ok(this) + } + + /// Reset the i2c peripheral. If you cancel a respond_to_read, you may stall the bus. + /// You can recover the bus by calling this function, but doing so will almost certainly cause + /// an i/o error in the controller. + pub fn reset(&mut self) -> Result<(), ConfigError> { + self.init()?; + unsafe { self.info.interrupt.enable() }; + Ok(()) + } +} + +impl<'d> I2cTarget<'d, Blocking> { + /// Create a new blocking I2C target driver. + pub fn new_blocking( + peri: Peri<'d, T>, + scl: Peri<'d, impl SclPin>, + sda: Peri<'d, impl SdaPin>, + config: Config, + ) -> Result { + let mut this = Self::new_inner( + peri, + new_pin!(scl, config.scl_pf()), + new_pin!(sda, config.sda_pf()), + config, + ); + this.reset()?; + Ok(this) + } + + /// Reset the i2c peripheral. If you cancel a respond_to_read, you may stall the bus. + /// You can recover the bus by calling this function, but doing so will almost certainly cause + /// an i/o error in the controller. + pub fn reset(&mut self) -> Result<(), ConfigError> { + self.init()?; + Ok(()) + } +} + +impl<'d, M: Mode> I2cTarget<'d, M> { + fn new_inner( + _peri: Peri<'d, T>, + scl: Option>, + sda: Option>, + config: Config, + ) -> Self { + if let Some(ref scl) = scl { + let pincm = pac::IOMUX.pincm(scl._pin_cm() as usize); + pincm.modify(|w| { + w.set_hiz1(true); + }); + } + if let Some(ref sda) = sda { + let pincm = pac::IOMUX.pincm(sda._pin_cm() as usize); + pincm.modify(|w| { + w.set_hiz1(true); + }); + } + + Self { + info: T::info(), + state: T::state(), + scl, + sda, + config, + _phantom: PhantomData, + } + } + + fn init(&mut self) -> Result<(), ConfigError> { + let mut config = self.config; + let regs = self.info.regs; + + config.check_config()?; + // Target address must be 7-bit + if !(config.target_addr < 0x80) { + return Err(ConfigError::InvalidTargetAddress); + } + + regs.target(0).tctr().modify(|w| { + w.set_active(false); + }); + + // Init power for I2C + regs.gprcm(0).rstctl().write(|w| { + w.set_resetstkyclr(true); + w.set_resetassert(true); + w.set_key(vals::ResetKey::KEY); + }); + + regs.gprcm(0).pwren().write(|w| { + w.set_enable(true); + w.set_key(vals::PwrenKey::KEY); + }); + + self.info.interrupt.disable(); + + // Init delay from the M0 examples by TI in CCStudio (16 cycles) + cortex_m::asm::delay(16); + + // Select and configure the I2C clock using the CLKSEL and CLKDIV registers + regs.clksel().write(|w| match config.clock_source { + ClockSel::BusClk => { + w.set_mfclk_sel(false); + w.set_busclk_sel(true); + } + ClockSel::MfClk => { + w.set_mfclk_sel(true); + w.set_busclk_sel(false); + } + }); + regs.clkdiv().write(|w| w.set_ratio(config.clock_div.into())); + + // Configure at least one target address by writing the 7-bit address to I2Cx.SOAR register. The additional + // target address can be enabled and configured by using I2Cx.TOAR2 register. + regs.target(0).toar().modify(|w| { + w.set_oaren(true); + w.set_oar(config.target_addr as u16); + }); + + self.state + .clock + .store(config.calculate_clock_source(), Ordering::Relaxed); + + regs.target(0).tctr().modify(|w| { + w.set_gencall(config.general_call); + w.set_tclkstretch(true); + // Disable target wakeup, follow TI example. (TI note: Workaround for errata I2C_ERR_04.) + w.set_twuen(false); + w.set_txempty_on_treq(true); + }); + + // Enable the I2C target mode by setting the ACTIVE bit in I2Cx.TCTR register. + regs.target(0).tctr().modify(|w| { + w.set_active(true); + }); + + Ok(()) + } + + #[inline(always)] + fn drain_fifo(&mut self, buffer: &mut [u8], offset: &mut usize) { + let regs = self.info.regs; + + for b in &mut buffer[*offset..] { + if regs.target(0).tfifosr().read().rxfifocnt() == 0 { + break; + } + + *b = regs.target(0).trxdata().read().value(); + *offset += 1; + } + } + + /// Blocking function to empty the tx fifo + /// + /// This function can be used to empty the transmit FIFO if data remains after handling a 'read' command (LeftoverBytes). + pub fn flush_tx_fifo(&mut self) { + self.info.regs.target(0).tfifoctl().modify(|w| { + w.set_txflush(true); + }); + while self.info.regs.target(0).tfifosr().read().txfifocnt() as usize != self.info.fifo_size {} + self.info.regs.target(0).tfifoctl().modify(|w| { + w.set_txflush(false); + }); + } +} + +impl<'d> I2cTarget<'d, Async> { + /// Wait asynchronously for commands from an I2C controller. + /// `buffer` is provided in case controller does a 'write', 'write read', or 'general call' and is unused for 'read'. + pub async fn listen(&mut self, buffer: &mut [u8]) -> Result { + let regs = self.info.regs; + + let mut len = 0; + + // Set the rx fifo interrupt to avoid a fifo overflow + regs.target(0).tfifoctl().modify(|r| { + r.set_rxtrig(vals::TfifoctlRxtrig::LEVEL_6); + }); + + self.wait_on( + |me| { + // Check if address matches the General Call address (0x00) + let is_gencall = regs.target(0).tsr().read().addrmatch() == 0; + + if regs.target(0).tfifosr().read().rxfifocnt() > 0 { + me.drain_fifo(buffer, &mut len); + } + + if buffer.len() == len && regs.target(0).tfifosr().read().rxfifocnt() > 0 { + if is_gencall { + return Poll::Ready(Err(Error::PartialGeneralCall(buffer.len()))); + } else { + return Poll::Ready(Err(Error::PartialWrite(buffer.len()))); + } + } + + let iidx = regs.cpu_int(0).iidx().read().stat(); + trace!("ls:{} len:{}", iidx as u8, len); + let result = match iidx { + CpuIntIidxStat::TTXEMPTY => match len { + 0 => Poll::Ready(Ok(Command::Read)), + w => Poll::Ready(Ok(Command::WriteRead(w))), + }, + CpuIntIidxStat::TSTOPFG => match (is_gencall, len) { + (_, 0) => Poll::Pending, + (true, w) => Poll::Ready(Ok(Command::GeneralCall(w))), + (false, w) => Poll::Ready(Ok(Command::Write(w))), + }, + _ => Poll::Pending, + }; + if !result.is_pending() { + regs.cpu_int(0).imask().write(|_| {}); + } + result + }, + |_me| { + regs.cpu_int(0).imask().write(|_| {}); + regs.cpu_int(0).imask().modify(|w| { + w.set_tgencall(true); + w.set_trxfifotrg(true); + w.set_tstop(true); + w.set_ttxempty(true); + }); + }, + ) + .await + } + + /// Respond to an I2C controller 'read' command, asynchronously. + pub async fn respond_to_read(&mut self, buffer: &[u8]) -> Result { + if buffer.is_empty() { + return Err(Error::InvalidResponseBufferLength); + } + + let regs = self.info.regs; + let fifo_size = self.info.fifo_size; + let mut chunks = buffer.chunks(self.info.fifo_size); + + self.wait_on( + |_me| { + if let Some(chunk) = chunks.next() { + for byte in chunk { + regs.target(0).ttxdata().write(|w| w.set_value(*byte)); + } + + return Poll::Pending; + } + + let iidx = regs.cpu_int(0).iidx().read().stat(); + let fifo_bytes = fifo_size - regs.target(0).tfifosr().read().txfifocnt() as usize; + trace!("rs:{}, fifo:{}", iidx as u8, fifo_bytes); + + let result = match iidx { + CpuIntIidxStat::TTXEMPTY => Poll::Ready(Ok(ReadStatus::NeedMoreBytes)), + CpuIntIidxStat::TSTOPFG => match fifo_bytes { + 0 => Poll::Ready(Ok(ReadStatus::Done)), + w => Poll::Ready(Ok(ReadStatus::LeftoverBytes(w as u16))), + }, + _ => Poll::Pending, + }; + if !result.is_pending() { + regs.cpu_int(0).imask().write(|_| {}); + } + result + }, + |_me| { + regs.cpu_int(0).imask().write(|_| {}); + regs.cpu_int(0).imask().modify(|w| { + w.set_ttxempty(true); + w.set_tstop(true); + }); + }, + ) + .await + } + + /// Respond to reads with the fill byte until the controller stops asking + pub async fn respond_till_stop(&mut self, fill: u8) -> Result<(), Error> { + // The buffer size could be increased to reduce interrupt noise but has higher probability + // of LeftoverBytes + let buff = [fill]; + loop { + match self.respond_to_read(&buff).await { + Ok(ReadStatus::NeedMoreBytes) => (), + Ok(_) => break Ok(()), + Err(e) => break Err(e), + } + } + } + + /// Respond to a controller read, then fill any remaining read bytes with `fill` + pub async fn respond_and_fill(&mut self, buffer: &[u8], fill: u8) -> Result { + let resp_stat = self.respond_to_read(buffer).await?; + + if resp_stat == ReadStatus::NeedMoreBytes { + self.respond_till_stop(fill).await?; + Ok(ReadStatus::Done) + } else { + Ok(resp_stat) + } + } + + /// Calls `f` to check if we are ready or not. + /// If not, `g` is called once(to eg enable the required interrupts). + /// The waker will always be registered prior to calling `f`. + #[inline(always)] + async fn wait_on(&mut self, mut f: F, mut g: G) -> U + where + F: FnMut(&mut Self) -> Poll, + G: FnMut(&mut Self), + { + poll_fn(|cx| { + // Register prior to checking the condition + self.state.waker.register(cx.waker()); + let r = f(self); + + if r.is_pending() { + g(self); + } + + r + }) + .await + } +} + +impl<'d, M: Mode> Drop for I2cTarget<'d, M> { + fn drop(&mut self) { + // Ensure peripheral is disabled and pins are reset + self.info.regs.target(0).tctr().modify(|w| w.set_active(false)); + + self.scl.as_ref().map(|x| x.set_as_disconnected()); + self.sda.as_ref().map(|x| x.set_as_disconnected()); + } +} diff --git a/embassy-mspm0/src/lib.rs b/embassy-mspm0/src/lib.rs index 55f3f9381..7135dd9f0 100644 --- a/embassy-mspm0/src/lib.rs +++ b/embassy-mspm0/src/lib.rs @@ -18,6 +18,7 @@ pub mod adc; pub mod dma; pub mod gpio; pub mod i2c; +pub mod i2c_target; pub mod timer; pub mod uart; pub mod wwdt; diff --git a/examples/mspm0g3507/src/bin/i2c_target.rs b/examples/mspm0g3507/src/bin/i2c_target.rs new file mode 100644 index 000000000..b1336cdd2 --- /dev/null +++ b/examples/mspm0g3507/src/bin/i2c_target.rs @@ -0,0 +1,60 @@ +//! Example of using blocking I2C +//! +//! This uses the virtual COM port provided on the LP-MSPM0G3507 board. + +#![no_std] +#![no_main] + +use defmt::*; +use embassy_executor::Spawner; +use embassy_mspm0::i2c_target::{Command, I2cTarget, ReadStatus}; +use embassy_mspm0::peripherals::I2C1; +use embassy_mspm0::{bind_interrupts, i2c}; +use {defmt_rtt as _, panic_halt as _}; + +bind_interrupts!(struct Irqs { + I2C1 => i2c::InterruptHandler; +}); + +#[embassy_executor::main] +async fn main(_spawner: Spawner) -> ! { + let p = embassy_mspm0::init(Default::default()); + + let instance = p.I2C1; + let scl = p.PB2; + let sda = p.PB3; + + let mut config = i2c::Config::default(); + config.general_call = true; + let mut i2c = I2cTarget::new(instance, scl, sda, Irqs, config).unwrap(); + + let mut read = [0u8; 8]; + let data = [8u8; 2]; + let data_wr = [9u8; 2]; + + loop { + match i2c.listen(&mut read).await { + Ok(Command::GeneralCall(_)) => info!("General call received"), + Ok(Command::Read) => { + info!("Read command received"); + match i2c.respond_to_read(&data).await.unwrap() { + ReadStatus::Done => info!("Finished reading"), + ReadStatus::NeedMoreBytes => { + info!("Read needs more bytes - will reset"); + i2c.reset().unwrap(); + } + ReadStatus::LeftoverBytes(_) => { + info!("Leftover bytes received"); + i2c.flush_tx_fifo(); + } + } + } + Ok(Command::Write(_)) => info!("Write command received"), + Ok(Command::WriteRead(_)) => { + info!("Write-Read command received"); + i2c.respond_and_fill(&data_wr, 0xFE).await.unwrap(); + } + Err(e) => info!("Got error {}", e), + } + } +} -- cgit From a12299d35d4641a8dfee27c52ec274257815cb3f Mon Sep 17 00:00:00 2001 From: crispaudio Date: Fri, 29 Aug 2025 12:44:40 +0200 Subject: mspm0-i2c-target: fix comment in example --- examples/mspm0g3507/src/bin/i2c_target.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/mspm0g3507/src/bin/i2c_target.rs b/examples/mspm0g3507/src/bin/i2c_target.rs index b1336cdd2..cb1d315fe 100644 --- a/examples/mspm0g3507/src/bin/i2c_target.rs +++ b/examples/mspm0g3507/src/bin/i2c_target.rs @@ -1,4 +1,4 @@ -//! Example of using blocking I2C +//! Example of using async I2C target //! //! This uses the virtual COM port provided on the LP-MSPM0G3507 board. -- cgit From e62ec23a389801f7a7c22db0727ae43814138fe1 Mon Sep 17 00:00:00 2001 From: crispaudio Date: Fri, 29 Aug 2025 12:49:58 +0200 Subject: mspm0-i2c-target: added to changelog --- embassy-mspm0/CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/embassy-mspm0/CHANGELOG.md b/embassy-mspm0/CHANGELOG.md index 948f0205d..fcb0f9dbd 100644 --- a/embassy-mspm0/CHANGELOG.md +++ b/embassy-mspm0/CHANGELOG.md @@ -16,3 +16,4 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - fix: gpio OutputOpenDrain config (#4735) - fix: add MSPM0C1106 to build test matrix - feat: add MSPM0H3216 support +- feat: Add i2c target implementation (#4605) -- cgit From 7797cc0effa069b78be29ff19b81068b17f98ac2 Mon Sep 17 00:00:00 2001 From: Iooon Date: Wed, 1 Oct 2025 11:00:44 +0200 Subject: mspm0-i2c-target: add mspm0l1306 example and set target address explicitly in examples --- examples/mspm0g3507/src/bin/i2c_target.rs | 1 + examples/mspm0l1306/src/bin/i2c_target.rs | 61 +++++++++++++++++++++++++++++++ 2 files changed, 62 insertions(+) create mode 100644 examples/mspm0l1306/src/bin/i2c_target.rs diff --git a/examples/mspm0g3507/src/bin/i2c_target.rs b/examples/mspm0g3507/src/bin/i2c_target.rs index cb1d315fe..ac7083a20 100644 --- a/examples/mspm0g3507/src/bin/i2c_target.rs +++ b/examples/mspm0g3507/src/bin/i2c_target.rs @@ -25,6 +25,7 @@ async fn main(_spawner: Spawner) -> ! { let sda = p.PB3; let mut config = i2c::Config::default(); + config.target_addr = 0x48; config.general_call = true; let mut i2c = I2cTarget::new(instance, scl, sda, Irqs, config).unwrap(); diff --git a/examples/mspm0l1306/src/bin/i2c_target.rs b/examples/mspm0l1306/src/bin/i2c_target.rs new file mode 100644 index 000000000..38d309e6b --- /dev/null +++ b/examples/mspm0l1306/src/bin/i2c_target.rs @@ -0,0 +1,61 @@ +//! Example of using async I2C target +//! +//! This uses the virtual COM port provided on the LP-MSPM0L1306 board. + +#![no_std] +#![no_main] + +use defmt::*; +use embassy_executor::Spawner; +use embassy_mspm0::i2c_target::{Command, I2cTarget, ReadStatus}; +use embassy_mspm0::peripherals::I2C0; +use embassy_mspm0::{bind_interrupts, i2c}; +use {defmt_rtt as _, panic_halt as _}; + +bind_interrupts!(struct Irqs { + I2C0 => i2c::InterruptHandler; +}); + +#[embassy_executor::main] +async fn main(_spawner: Spawner) -> ! { + let p = embassy_mspm0::init(Default::default()); + + let instance = p.I2C0; + let scl = p.PA1; + let sda = p.PA0; + + let mut config = i2c::Config::default(); + config.target_addr = 0x48; + config.general_call = true; + let mut i2c = I2cTarget::new(instance, scl, sda, Irqs, config).unwrap(); + + let mut read = [0u8; 8]; + let data = [8u8; 2]; + let data_wr = [9u8; 2]; + + loop { + match i2c.listen(&mut read).await { + Ok(Command::GeneralCall(_)) => info!("General call received"), + Ok(Command::Read) => { + info!("Read command received"); + match i2c.respond_to_read(&data).await.unwrap() { + ReadStatus::Done => info!("Finished reading"), + ReadStatus::NeedMoreBytes => { + info!("Read needs more bytes - will reset"); + i2c.reset().unwrap(); + } + ReadStatus::LeftoverBytes(_) => { + info!("Leftover bytes received"); + i2c.flush_tx_fifo(); + } + } + } + Ok(Command::Write(_)) => info!("Write command received"), + Ok(Command::WriteRead(_)) => { + info!("Write-Read command received"); + i2c.respond_and_fill(&data_wr, 0xFE).await.unwrap(); + } + Err(e) => info!("Got error {}", e), + } + } +} -- cgit From 8d13271100595c31001e0dd1078067a96e42816d Mon Sep 17 00:00:00 2001 From: Iooon Date: Wed, 1 Oct 2025 11:23:57 +0200 Subject: mspm0-i2c-target: fix spelling mistakes and revert From implementation --- embassy-mspm0/src/i2c.rs | 28 +++++++++++++--------------- embassy-mspm0/src/i2c_target.rs | 4 ++-- 2 files changed, 15 insertions(+), 17 deletions(-) diff --git a/embassy-mspm0/src/i2c.rs b/embassy-mspm0/src/i2c.rs index ce5215871..0aefd19de 100644 --- a/embassy-mspm0/src/i2c.rs +++ b/embassy-mspm0/src/i2c.rs @@ -56,6 +56,19 @@ pub enum ClockDiv { } impl ClockDiv { + pub(crate) fn into(self) -> vals::Ratio { + match self { + Self::DivBy1 => vals::Ratio::DIV_BY_1, + Self::DivBy2 => vals::Ratio::DIV_BY_2, + Self::DivBy3 => vals::Ratio::DIV_BY_3, + Self::DivBy4 => vals::Ratio::DIV_BY_4, + Self::DivBy5 => vals::Ratio::DIV_BY_5, + Self::DivBy6 => vals::Ratio::DIV_BY_6, + Self::DivBy7 => vals::Ratio::DIV_BY_7, + Self::DivBy8 => vals::Ratio::DIV_BY_8, + } + } + fn divider(self) -> u32 { match self { Self::DivBy1 => 1, @@ -70,21 +83,6 @@ impl ClockDiv { } } -impl From for vals::Ratio { - fn from(value: ClockDiv) -> Self { - match value { - ClockDiv::DivBy1 => Self::DIV_BY_1, - ClockDiv::DivBy2 => Self::DIV_BY_2, - ClockDiv::DivBy3 => Self::DIV_BY_3, - ClockDiv::DivBy4 => Self::DIV_BY_4, - ClockDiv::DivBy5 => Self::DIV_BY_5, - ClockDiv::DivBy6 => Self::DIV_BY_6, - ClockDiv::DivBy7 => Self::DIV_BY_7, - ClockDiv::DivBy8 => Self::DIV_BY_8, - } - } -} - /// The I2C mode. #[derive(Clone, Copy, PartialEq, Eq, Debug)] #[cfg_attr(feature = "defmt", derive(defmt::Format))] diff --git a/embassy-mspm0/src/i2c_target.rs b/embassy-mspm0/src/i2c_target.rs index c6ef2f5d4..7183280bd 100644 --- a/embassy-mspm0/src/i2c_target.rs +++ b/embassy-mspm0/src/i2c_target.rs @@ -62,9 +62,9 @@ pub enum ReadStatus { /// Transaction completed successfully. The controller either NACKed the last byte /// or sent a STOP condition. Done, - /// Transaction Incomplete, controller trying to read more bytes than were provided + /// Transaction incomplete, controller trying to read more bytes than were provided NeedMoreBytes, - /// Transaction Complere, but controller stopped reading bytes before we ran out + /// Transaction complete, but controller stopped reading bytes before we ran out LeftoverBytes(u16), } -- cgit From e6988a3acd8abacb33d6cc2f57f1ad576b1d8687 Mon Sep 17 00:00:00 2001 From: Iooon Date: Sat, 4 Oct 2025 17:03:51 +0200 Subject: mspm0-i2c-target: split i2c controller and i2c target configs --- embassy-mspm0/src/i2c.rs | 8 ---- embassy-mspm0/src/i2c_target.rs | 94 ++++++++++++++++++++++++++++++++++++----- 2 files changed, 84 insertions(+), 18 deletions(-) diff --git a/embassy-mspm0/src/i2c.rs b/embassy-mspm0/src/i2c.rs index 0aefd19de..fb871f85d 100644 --- a/embassy-mspm0/src/i2c.rs +++ b/embassy-mspm0/src/i2c.rs @@ -164,12 +164,6 @@ pub struct Config { /// Set the pull configuration for the SCL pin. pub bus_speed: BusSpeed, - - /// 7-bit Target Address - pub target_addr: u8, - - /// Control if the target should ack to and report general calls. - pub general_call: bool, } impl Default for Config { @@ -182,8 +176,6 @@ impl Default for Config { sda_pull: Pull::None, scl_pull: Pull::None, bus_speed: BusSpeed::Standard, - target_addr: 0x48, - general_call: false, } } } diff --git a/embassy-mspm0/src/i2c_target.rs b/embassy-mspm0/src/i2c_target.rs index 7183280bd..86be91415 100644 --- a/embassy-mspm0/src/i2c_target.rs +++ b/embassy-mspm0/src/i2c_target.rs @@ -8,16 +8,36 @@ use core::marker::PhantomData; use core::sync::atomic::Ordering; use core::task::Poll; +use embassy_embedded_hal::SetConfig; use mspm0_metapac::i2c::vals::CpuIntIidxStat; use crate::gpio::{AnyPin, SealedPin}; -use crate::interrupt; use crate::interrupt::InterruptExt; use crate::mode::{Async, Blocking, Mode}; use crate::pac::{self, i2c::vals}; -use crate::Peri; +use crate::{i2c, i2c_target, interrupt, Peri}; // Re-use I2c controller types -use crate::i2c::{ClockSel, Config, ConfigError, Info, Instance, InterruptHandler, SclPin, SdaPin, State}; +use crate::i2c::{ClockSel, ConfigError, Info, Instance, InterruptHandler, SclPin, SdaPin, State}; + +#[non_exhaustive] +#[derive(Clone, Copy, PartialEq, Eq, Debug)] +/// Config +pub struct Config { + /// 7-bit Target Address + pub target_addr: u8, + + /// Control if the target should ack to and report general calls. + pub general_call: bool, +} + +impl Default for Config { + fn default() -> Self { + Self { + target_addr: 0x48, + general_call: false, + } + } +} /// I2C error #[derive(Debug, PartialEq, Eq, Clone, Copy)] @@ -75,24 +95,71 @@ pub struct I2cTarget<'d, M: Mode> { state: &'static State, scl: Option>, sda: Option>, - config: Config, + config: i2c::Config, + target_config: i2c_target::Config, _phantom: PhantomData, } +impl<'d> SetConfig for I2cTarget<'d, Async> { + type Config = (i2c::Config, i2c_target::Config); + type ConfigError = ConfigError; + + fn set_config(&mut self, config: &Self::Config) -> Result<(), Self::ConfigError> { + self.info.interrupt.disable(); + + if let Some(ref sda) = self.sda { + sda.update_pf(config.0.sda_pf()); + } + + if let Some(ref scl) = self.scl { + scl.update_pf(config.0.scl_pf()); + } + + self.config = config.0.clone(); + self.target_config = config.1.clone(); + + self.reset() + } +} + +impl<'d> SetConfig for I2cTarget<'d, Blocking> { + type Config = (i2c::Config, i2c_target::Config); + type ConfigError = ConfigError; + + fn set_config(&mut self, config: &Self::Config) -> Result<(), Self::ConfigError> { + if let Some(ref sda) = self.sda { + sda.update_pf(config.0.sda_pf()); + } + + if let Some(ref scl) = self.scl { + scl.update_pf(config.0.scl_pf()); + } + + self.config = config.0.clone(); + self.target_config = config.1.clone(); + + self.reset() + } +} + impl<'d> I2cTarget<'d, Async> { /// Create a new asynchronous I2C target driver using interrupts + /// The `config` reuses the i2c controller config to setup the clock while `target_config` + /// configures i2c target specific parameters. pub fn new( peri: Peri<'d, T>, scl: Peri<'d, impl SclPin>, sda: Peri<'d, impl SdaPin>, _irq: impl interrupt::typelevel::Binding> + 'd, - config: Config, + config: i2c::Config, + target_config: i2c_target::Config, ) -> Result { let mut this = Self::new_inner( peri, new_pin!(scl, config.scl_pf()), new_pin!(sda, config.sda_pf()), config, + target_config, ); this.reset()?; Ok(this) @@ -110,17 +177,21 @@ impl<'d> I2cTarget<'d, Async> { impl<'d> I2cTarget<'d, Blocking> { /// Create a new blocking I2C target driver. + /// The `config` reuses the i2c controller config to setup the clock while `target_config` + /// configures i2c target specific parameters. pub fn new_blocking( peri: Peri<'d, T>, scl: Peri<'d, impl SclPin>, sda: Peri<'d, impl SdaPin>, - config: Config, + config: i2c::Config, + target_config: i2c_target::Config, ) -> Result { let mut this = Self::new_inner( peri, new_pin!(scl, config.scl_pf()), new_pin!(sda, config.sda_pf()), config, + target_config, ); this.reset()?; Ok(this) @@ -140,7 +211,8 @@ impl<'d, M: Mode> I2cTarget<'d, M> { _peri: Peri<'d, T>, scl: Option>, sda: Option>, - config: Config, + config: i2c::Config, + target_config: i2c_target::Config, ) -> Self { if let Some(ref scl) = scl { let pincm = pac::IOMUX.pincm(scl._pin_cm() as usize); @@ -161,17 +233,19 @@ impl<'d, M: Mode> I2cTarget<'d, M> { scl, sda, config, + target_config, _phantom: PhantomData, } } fn init(&mut self) -> Result<(), ConfigError> { let mut config = self.config; + let target_config = self.target_config; let regs = self.info.regs; config.check_config()?; // Target address must be 7-bit - if !(config.target_addr < 0x80) { + if !(target_config.target_addr < 0x80) { return Err(ConfigError::InvalidTargetAddress); } @@ -213,7 +287,7 @@ impl<'d, M: Mode> I2cTarget<'d, M> { // target address can be enabled and configured by using I2Cx.TOAR2 register. regs.target(0).toar().modify(|w| { w.set_oaren(true); - w.set_oar(config.target_addr as u16); + w.set_oar(target_config.target_addr as u16); }); self.state @@ -221,7 +295,7 @@ impl<'d, M: Mode> I2cTarget<'d, M> { .store(config.calculate_clock_source(), Ordering::Relaxed); regs.target(0).tctr().modify(|w| { - w.set_gencall(config.general_call); + w.set_gencall(target_config.general_call); w.set_tclkstretch(true); // Disable target wakeup, follow TI example. (TI note: Workaround for errata I2C_ERR_04.) w.set_twuen(false); -- cgit From 4217a264dba3a77da38897537f90e1fdfe5b9ddb Mon Sep 17 00:00:00 2001 From: crispaudio Date: Mon, 6 Oct 2025 10:06:28 +0200 Subject: mspm0-i2c-target: update examples with split config --- examples/mspm0g3507/src/bin/i2c_target.rs | 12 +++++++----- examples/mspm0l1306/src/bin/i2c_target.rs | 12 +++++++----- 2 files changed, 14 insertions(+), 10 deletions(-) diff --git a/examples/mspm0g3507/src/bin/i2c_target.rs b/examples/mspm0g3507/src/bin/i2c_target.rs index ac7083a20..5dd718eaf 100644 --- a/examples/mspm0g3507/src/bin/i2c_target.rs +++ b/examples/mspm0g3507/src/bin/i2c_target.rs @@ -7,7 +7,8 @@ use defmt::*; use embassy_executor::Spawner; -use embassy_mspm0::i2c_target::{Command, I2cTarget, ReadStatus}; +use embassy_mspm0::i2c::Config; +use embassy_mspm0::i2c_target::{Command, Config as TargetConfig, I2cTarget, ReadStatus}; use embassy_mspm0::peripherals::I2C1; use embassy_mspm0::{bind_interrupts, i2c}; use {defmt_rtt as _, panic_halt as _}; @@ -24,10 +25,11 @@ async fn main(_spawner: Spawner) -> ! { let scl = p.PB2; let sda = p.PB3; - let mut config = i2c::Config::default(); - config.target_addr = 0x48; - config.general_call = true; - let mut i2c = I2cTarget::new(instance, scl, sda, Irqs, config).unwrap(); + let config = Config::default(); + let mut target_config = TargetConfig::default(); + target_config.target_addr = 0x48; + target_config.general_call = true; + let mut i2c = I2cTarget::new(instance, scl, sda, Irqs, config, target_config).unwrap(); let mut read = [0u8; 8]; let data = [8u8; 2]; diff --git a/examples/mspm0l1306/src/bin/i2c_target.rs b/examples/mspm0l1306/src/bin/i2c_target.rs index 38d309e6b..4d147d08b 100644 --- a/examples/mspm0l1306/src/bin/i2c_target.rs +++ b/examples/mspm0l1306/src/bin/i2c_target.rs @@ -7,7 +7,8 @@ use defmt::*; use embassy_executor::Spawner; -use embassy_mspm0::i2c_target::{Command, I2cTarget, ReadStatus}; +use embassy_mspm0::i2c::Config; +use embassy_mspm0::i2c_target::{Command, Config as TargetConfig, I2cTarget, ReadStatus}; use embassy_mspm0::peripherals::I2C0; use embassy_mspm0::{bind_interrupts, i2c}; use {defmt_rtt as _, panic_halt as _}; @@ -24,10 +25,11 @@ async fn main(_spawner: Spawner) -> ! { let scl = p.PA1; let sda = p.PA0; - let mut config = i2c::Config::default(); - config.target_addr = 0x48; - config.general_call = true; - let mut i2c = I2cTarget::new(instance, scl, sda, Irqs, config).unwrap(); + let config = Config::default(); + let mut target_config = TargetConfig::default(); + target_config.target_addr = 0x48; + target_config.general_call = true; + let mut i2c = I2cTarget::new(instance, scl, sda, Irqs, config, target_config).unwrap(); let mut read = [0u8; 8]; let data = [8u8; 2]; -- cgit From fd35ddf305fcace9faa7266529d959dc8c425a90 Mon Sep 17 00:00:00 2001 From: crispaudio Date: Fri, 10 Oct 2025 07:04:41 +0200 Subject: mspm0-i2c-target: make calculate_clock_source pub(crate) for mspm0c --- embassy-mspm0/src/i2c.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/embassy-mspm0/src/i2c.rs b/embassy-mspm0/src/i2c.rs index fb871f85d..3067f4833 100644 --- a/embassy-mspm0/src/i2c.rs +++ b/embassy-mspm0/src/i2c.rs @@ -201,7 +201,7 @@ impl Config { } #[cfg(any(mspm0c110x, mspm0c1105_c1106))] - fn calculate_clock_source(&self) -> u32 { + pub(crate) fn calculate_clock_source(&self) -> u32 { // Assume that BusClk has default value. // TODO: calculate BusClk more precisely. match self.clock_source { -- cgit From f43eb6c204b5fe8a975bd0d325b268cbbcb00f99 Mon Sep 17 00:00:00 2001 From: i509VCB Date: Mon, 13 Oct 2025 16:17:42 -0500 Subject: nxp/lpc55: eliminate match_iocon It is easier to have SealedPin provide a way to get to the Pio icon registers --- embassy-nxp/CHANGELOG.md | 1 + embassy-nxp/src/gpio/lpc55.rs | 66 ++++++++++++++---------------------------- embassy-nxp/src/usart/lpc55.rs | 38 +++++++++++------------- 3 files changed, 40 insertions(+), 65 deletions(-) diff --git a/embassy-nxp/CHANGELOG.md b/embassy-nxp/CHANGELOG.md index 0fb677cd8..295d45c2d 100644 --- a/embassy-nxp/CHANGELOG.md +++ b/embassy-nxp/CHANGELOG.md @@ -7,6 +7,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## Unreleased - ReleaseDate +- LPC55: Remove internal match_iocon macro - LPC55: DMA Controller and asynchronous version of USART - Moved NXP LPC55S69 from `lpc55-pac` to `nxp-pac` - First release with changelog. diff --git a/embassy-nxp/src/gpio/lpc55.rs b/embassy-nxp/src/gpio/lpc55.rs index ac8a27d4f..6039d8ca8 100644 --- a/embassy-nxp/src/gpio/lpc55.rs +++ b/embassy-nxp/src/gpio/lpc55.rs @@ -1,7 +1,8 @@ use embassy_hal_internal::{PeripheralType, impl_peripheral}; +use crate::pac::common::{RW, Reg}; use crate::pac::iocon::vals::{PioDigimode, PioMode}; -use crate::pac::{GPIO, IOCON, SYSCON}; +use crate::pac::{GPIO, IOCON, SYSCON, iocon}; use crate::{Peri, peripherals}; pub(crate) fn init() { @@ -109,13 +110,7 @@ impl<'d> Input<'d> { /// Set the pull configuration for the pin. To disable the pull, use [Pull::None]. pub fn set_pull(&mut self, pull: Pull) { - match_iocon!(register, self.pin.pin_bank(), self.pin.pin_number(), { - register.modify(|w| match pull { - Pull::None => w.set_mode(PioMode::INACTIVE), - Pull::Up => w.set_mode(PioMode::PULL_UP), - Pull::Down => w.set_mode(PioMode::PULL_DOWN), - }); - }); + self.pin.set_pull(pull); } /// Get the current input level of the pin. @@ -193,11 +188,20 @@ impl<'d> Flex<'d> { 1 << self.pin.pin_number() } + /// Set the pull configuration for the pin. To disable the pull, use [Pull::None]. + pub fn set_pull(&mut self, pull: Pull) { + self.pin.pio().modify(|w| match pull { + Pull::None => w.set_mode(PioMode::INACTIVE), + Pull::Up => w.set_mode(PioMode::PULL_UP), + Pull::Down => w.set_mode(PioMode::PULL_DOWN), + }); + } + /// Set the pin to digital mode. This is required for using a pin as a GPIO pin. The default /// setting for pins is (usually) non-digital. fn set_as_digital(&mut self) { - match_iocon!(register, self.pin_bank(), self.pin_number(), { - register.modify(|w| w.set_digimode(PioDigimode::DIGITAL)); + self.pin.pio().modify(|w| { + w.set_digimode(PioDigimode::DIGITAL); }); } @@ -220,6 +224,14 @@ impl<'d> Flex<'d> { pub(crate) trait SealedPin: Sized { fn pin_bank(&self) -> Bank; fn pin_number(&self) -> u8; + + #[inline] + fn pio(&self) -> Reg { + match self.pin_bank() { + Bank::Bank0 => IOCON.pio0(self.pin_number() as usize), + Bank::Bank1 => IOCON.pio1(self.pin_number() as usize), + } + } } /// Interface for a Pin that can be configured by an [Input] or [Output] driver, or converted to an @@ -272,40 +284,6 @@ impl SealedPin for AnyPin { } } -/// Match the pin bank and number of a pin to the corresponding IOCON register. -/// -/// # Example -/// ``` -/// use embassy_nxp::gpio::Bank; -/// use embassy_nxp::pac_utils::{iocon_reg, match_iocon}; -/// -/// // Make pin PIO1_6 digital and set it to pull-down mode. -/// match_iocon!(register, Bank::Bank1, 6, { -/// register.modify(|w|{ -/// w.set_mode(PioMode::PULL_DOWN); -/// w.set_digimode(PioDigimode::DIGITAL); -/// -/// } -/// }); -/// ``` -macro_rules! match_iocon { - ($register:ident, $pin_bank:expr, $pin_number:expr, $action:expr) => { - match $pin_bank { - Bank::Bank0 => { - let $register = IOCON.pio0($pin_number as usize); - $action; - } - - Bank::Bank1 => { - let $register = IOCON.pio1($pin_number as usize); - $action; - } - } - }; -} - -pub(crate) use match_iocon; - macro_rules! impl_pin { ($name:ident, $bank:expr, $pin_num:expr) => { impl Pin for peripherals::$name {} diff --git a/embassy-nxp/src/usart/lpc55.rs b/embassy-nxp/src/usart/lpc55.rs index 0be5a8ce7..6cbde82a3 100644 --- a/embassy-nxp/src/usart/lpc55.rs +++ b/embassy-nxp/src/usart/lpc55.rs @@ -11,7 +11,7 @@ use embassy_sync::waitqueue::AtomicWaker; use embedded_io::{self, ErrorKind}; use crate::dma::{AnyChannel, Channel}; -use crate::gpio::{AnyPin, Bank, SealedPin, match_iocon}; +use crate::gpio::{AnyPin, SealedPin}; use crate::interrupt::Interrupt; use crate::interrupt::typelevel::{Binding, Interrupt as _}; use crate::pac::flexcomm::Flexcomm as FlexcommReg; @@ -555,29 +555,25 @@ impl<'d, M: Mode> Usart<'d, M> { fn pin_config(tx: Option>, rx: Option>) { if let Some(tx_pin) = tx { - match_iocon!(register, tx_pin.pin_bank(), tx_pin.pin_number(), { - register.modify(|w| { - w.set_func(T::tx_pin_func()); - w.set_mode(iocon::vals::PioMode::INACTIVE); - w.set_slew(iocon::vals::PioSlew::STANDARD); - w.set_invert(false); - w.set_digimode(iocon::vals::PioDigimode::DIGITAL); - w.set_od(iocon::vals::PioOd::NORMAL); - }); - }) + tx_pin.pio().modify(|w| { + w.set_func(T::tx_pin_func()); + w.set_mode(iocon::vals::PioMode::INACTIVE); + w.set_slew(iocon::vals::PioSlew::STANDARD); + w.set_invert(false); + w.set_digimode(iocon::vals::PioDigimode::DIGITAL); + w.set_od(iocon::vals::PioOd::NORMAL); + }); } if let Some(rx_pin) = rx { - match_iocon!(register, rx_pin.pin_bank(), rx_pin.pin_number(), { - register.modify(|w| { - w.set_func(T::rx_pin_func()); - w.set_mode(iocon::vals::PioMode::INACTIVE); - w.set_slew(iocon::vals::PioSlew::STANDARD); - w.set_invert(false); - w.set_digimode(iocon::vals::PioDigimode::DIGITAL); - w.set_od(iocon::vals::PioOd::NORMAL); - }); - }) + rx_pin.pio().modify(|w| { + w.set_func(T::rx_pin_func()); + w.set_mode(iocon::vals::PioMode::INACTIVE); + w.set_slew(iocon::vals::PioSlew::STANDARD); + w.set_invert(false); + w.set_digimode(iocon::vals::PioDigimode::DIGITAL); + w.set_od(iocon::vals::PioOd::NORMAL); + }); }; } -- cgit From 6fef28da94d133ce0cd36b5fb6ef2ef302c8eea0 Mon Sep 17 00:00:00 2001 From: Haobo Gu Date: Tue, 14 Oct 2025 23:39:52 +0800 Subject: feat(nrf): add rtc support for nRF54L Signed-off-by: Haobo Gu --- embassy-nrf/Cargo.toml | 2 ++ embassy-nrf/src/chips/nrf54l15_app.rs | 42 ++++++++++++++++++++++++++ embassy-nrf/src/lib.rs | 1 - examples/nrf54l15/Cargo.toml | 2 ++ examples/nrf54l15/src/bin/rtc.rs | 56 +++++++++++++++++++++++++++++++++++ 5 files changed, 102 insertions(+), 1 deletion(-) create mode 100644 examples/nrf54l15/src/bin/rtc.rs diff --git a/embassy-nrf/Cargo.toml b/embassy-nrf/Cargo.toml index 17ffaf439..28f137d5c 100644 --- a/embassy-nrf/Cargo.toml +++ b/embassy-nrf/Cargo.toml @@ -80,6 +80,8 @@ unstable-pac = [] gpiote = [] ## Use RTC1 as the time driver for `embassy-time`, with a tick rate of 32.768khz +## +## Note: For nRF54L, it's actually RTC30 time-driver-rtc1 = ["_time-driver"] ## Enable embassy-net 802.15.4 driver diff --git a/embassy-nrf/src/chips/nrf54l15_app.rs b/embassy-nrf/src/chips/nrf54l15_app.rs index 82d30104f..901c5e7fc 100644 --- a/embassy-nrf/src/chips/nrf54l15_app.rs +++ b/embassy-nrf/src/chips/nrf54l15_app.rs @@ -249,6 +249,45 @@ embassy_hal_internal::peripherals! { P2_09, P2_10, + // RTC + RTC10, + RTC30, + + // SERIAL + SERIAL00, + SERIAL20, + SERIAL21, + SERIAL22, + SERIAL30, + + // SAADC + SAADC, + + // RADIO + RADIO, + + // TIMER + TIMER00, + TIMER10, + TIMER20, + + // PPI BRIDGE + PPIB00, + PPIB01, + PPIB10, + PPIB11, + PPIB20, + PPIB21, + PPIB22, + PPIB30, + + // GPIOTE + GPIOTE20, + GPIOTE30, + + // CRACEN + CRACEN, + #[cfg(feature = "_s")] // RRAMC RRAMC, @@ -303,6 +342,9 @@ impl_pin!(P2_08, 2, 8); impl_pin!(P2_09, 2, 9); impl_pin!(P2_10, 2, 10); +impl_rtc!(RTC10, RTC10, RTC10); +impl_rtc!(RTC30, RTC30, RTC30); + #[cfg(feature = "_ns")] impl_wdt!(WDT, WDT31, WDT31, 0); #[cfg(feature = "_s")] diff --git a/embassy-nrf/src/lib.rs b/embassy-nrf/src/lib.rs index 1b7fb7e7f..705c77453 100644 --- a/embassy-nrf/src/lib.rs +++ b/embassy-nrf/src/lib.rs @@ -155,7 +155,6 @@ pub mod reset; #[cfg(not(feature = "_nrf54l"))] // TODO #[cfg(not(any(feature = "_nrf5340-app", feature = "_nrf91")))] pub mod rng; -#[cfg(not(feature = "_nrf54l"))] // TODO pub mod rtc; #[cfg(not(feature = "_nrf54l"))] // TODO #[cfg(not(any(feature = "_nrf51", feature = "nrf52820", feature = "_nrf5340-net")))] diff --git a/examples/nrf54l15/Cargo.toml b/examples/nrf54l15/Cargo.toml index a053dd0ec..541e79fcb 100644 --- a/examples/nrf54l15/Cargo.toml +++ b/examples/nrf54l15/Cargo.toml @@ -8,6 +8,7 @@ publish = false [dependencies] embassy-executor = { version = "0.9.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "executor-interrupt", "defmt"] } embassy-time = { version = "0.5.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime"] } +embassy-sync = { version = "0.7.2", path = "../../embassy-sync", features = ["defmt"] } embassy-nrf = { version = "0.8.0", path = "../../embassy-nrf", features = ["defmt", "nrf54l15-app-s", "time-driver-rtc1", "gpiote", "unstable-pac", "time"] } defmt = "1.0.1" @@ -18,6 +19,7 @@ cortex-m = { version = "0.7.6", features = ["inline-asm", "critical-section-sing cortex-m-rt = "0.7.0" embedded-storage = "0.3.1" +portable-atomic = "1" [profile.release] debug = 2 diff --git a/examples/nrf54l15/src/bin/rtc.rs b/examples/nrf54l15/src/bin/rtc.rs new file mode 100644 index 000000000..a45aaca52 --- /dev/null +++ b/examples/nrf54l15/src/bin/rtc.rs @@ -0,0 +1,56 @@ +#![no_std] +#![no_main] + +use core::cell::RefCell; + +use embassy_executor::Spawner; +use embassy_nrf::gpio::{Level, Output, OutputDrive}; +use embassy_nrf::interrupt; +use embassy_nrf::rtc::Rtc; +use embassy_sync::blocking_mutex::Mutex; +use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex; +use portable_atomic::AtomicU64; +use {defmt_rtt as _, panic_probe as _}; + +// 64 bit counter which will never overflow. +static TICK_COUNTER: AtomicU64 = AtomicU64::new(0); +static RTC: Mutex>>> = Mutex::new(RefCell::new(None)); + +#[embassy_executor::main] +async fn main(_spawner: Spawner) { + defmt::println!("nRF54L15 RTC example"); + let p = embassy_nrf::init(Default::default()); + let mut led = Output::new(p.P2_09, Level::High, OutputDrive::Standard); + // Counter resolution is 125 ms. + let mut rtc = Rtc::new(p.RTC10, (1 << 12) - 1).unwrap(); + rtc.enable_interrupt(embassy_nrf::rtc::Interrupt::Tick, true); + rtc.enable_event(embassy_nrf::rtc::Interrupt::Tick); + rtc.enable(); + RTC.lock(|r| { + let mut rtc_borrow = r.borrow_mut(); + *rtc_borrow = Some(rtc); + }); + + let mut last_counter_val = 0; + loop { + let current = TICK_COUNTER.load(core::sync::atomic::Ordering::Relaxed); + if current != last_counter_val { + led.toggle(); + last_counter_val = current; + } + } +} + +#[interrupt] +fn RTC10() { + // For 64-bit, we do not need to worry about overflowing, at least not for realistic program + // lifetimes. + TICK_COUNTER.fetch_add(1, core::sync::atomic::Ordering::Relaxed); + RTC.lock(|r| { + let mut rtc_borrow = r.borrow_mut(); + rtc_borrow + .as_mut() + .unwrap() + .reset_event(embassy_nrf::rtc::Interrupt::Tick); + }); +} -- cgit From 00aaf840352adaa31136e87efd929da20eb7afec Mon Sep 17 00:00:00 2001 From: Haobo Gu Date: Tue, 14 Oct 2025 23:41:46 +0800 Subject: doc: update changelog Signed-off-by: Haobo Gu --- embassy-nrf/CHANGELOG.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/embassy-nrf/CHANGELOG.md b/embassy-nrf/CHANGELOG.md index 0244dedab..4f17a40ed 100644 --- a/embassy-nrf/CHANGELOG.md +++ b/embassy-nrf/CHANGELOG.md @@ -7,6 +7,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## Unreleased - ReleaseDate + +- added: Add basic RTC support for nRF54L - changed: apply trimming values from FICR.TRIMCNF on nrf53/54l ## 0.8.0 - 2025-09-30 -- cgit From dad58cf915c753602f6c6bcdc4db7123c31b2877 Mon Sep 17 00:00:00 2001 From: Kezi Date: Fri, 10 Oct 2025 01:36:09 +0200 Subject: return error on read when uarte buffer overrun --- embassy-nrf/src/buffered_uarte.rs | 21 +++++++++++++++++---- 1 file changed, 17 insertions(+), 4 deletions(-) diff --git a/embassy-nrf/src/buffered_uarte.rs b/embassy-nrf/src/buffered_uarte.rs index ec104788f..b1eb5c81a 100644 --- a/embassy-nrf/src/buffered_uarte.rs +++ b/embassy-nrf/src/buffered_uarte.rs @@ -40,6 +40,7 @@ pub(crate) struct State { rx_started_count: AtomicU8, rx_ended_count: AtomicU8, rx_ppi_ch: AtomicU8, + rx_overrun: AtomicBool, } /// UART error. @@ -47,7 +48,8 @@ pub(crate) struct State { #[cfg_attr(feature = "defmt", derive(defmt::Format))] #[non_exhaustive] pub enum Error { - // No errors for now + /// Buffer Overrun + Overrun, } impl State { @@ -61,6 +63,7 @@ impl State { rx_started_count: AtomicU8::new(0), rx_ended_count: AtomicU8::new(0), rx_ppi_ch: AtomicU8::new(0), + rx_overrun: AtomicBool::new(false), } } } @@ -87,8 +90,8 @@ impl interrupt::typelevel::Handler for Interrupt r.errorsrc().write_value(errs); if errs.overrun() { - #[cfg(feature = "defmt")] - defmt::warn!("BufferedUarte overrun"); + s.rx_overrun.store(true, Ordering::Release); + ss.rx_waker.wake(); } } @@ -690,6 +693,7 @@ impl<'d> BufferedUarteRx<'d> { buffered_state.rx_started_count.store(0, Ordering::Relaxed); buffered_state.rx_ended_count.store(0, Ordering::Relaxed); buffered_state.rx_started.store(false, Ordering::Relaxed); + buffered_state.rx_overrun.store(false, Ordering::Relaxed); let rx_len = rx_buffer.len().min(EASY_DMA_SIZE * 2); unsafe { buffered_state.rx_buf.init(rx_buffer.as_mut_ptr(), rx_len) }; @@ -763,6 +767,10 @@ impl<'d> BufferedUarteRx<'d> { compiler_fence(Ordering::SeqCst); //trace!("poll_read"); + if s.rx_overrun.swap(false, Ordering::Acquire) { + return Poll::Ready(Err(Error::Overrun)); + } + // Read the RXDRDY counter. timer.cc(0).capture(); let mut end = timer.cc(0).read() as usize; @@ -821,6 +829,9 @@ impl<'d> BufferedUarteRx<'d> { /// we are ready to read if there is data in the buffer fn read_ready(&self) -> Result { let state = self.buffered_state; + if state.rx_overrun.swap(false, Ordering::Acquire) { + return Err(Error::Overrun); + } Ok(!state.rx_buf.is_empty()) } } @@ -855,7 +866,9 @@ mod _embedded_io { impl embedded_io_async::Error for Error { fn kind(&self) -> embedded_io_async::ErrorKind { - match *self {} + match *self { + Error::Overrun => embedded_io_async::ErrorKind::OutOfMemory, + } } } -- cgit From ec97698085e79239b51429f59249a7f42bf04368 Mon Sep 17 00:00:00 2001 From: Maarten de Vries Date: Wed, 15 Oct 2025 11:55:40 +0200 Subject: embassy_nrf::pwm: derive more traits for public structs --- embassy-nrf/src/pwm.rs | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/embassy-nrf/src/pwm.rs b/embassy-nrf/src/pwm.rs index e038f44b8..1fa8f183b 100644 --- a/embassy-nrf/src/pwm.rs +++ b/embassy-nrf/src/pwm.rs @@ -289,6 +289,8 @@ impl<'a> Drop for SequencePwm<'a> { } /// Configuration for the PWM as a whole. +#[derive(Debug, Clone)] +#[cfg_attr(feature = "defmt", derive(defmt::Format))] #[non_exhaustive] pub struct Config { /// Selects up mode or up-and-down mode for the counter @@ -326,7 +328,8 @@ impl Default for Config { /// Configuration per sequence #[non_exhaustive] -#[derive(Clone)] +#[derive(Debug, Clone)] +#[cfg_attr(feature = "defmt", derive(defmt::Format))] pub struct SequenceConfig { /// Number of PWM periods to delay between each sequence sample pub refresh: u32, @@ -345,6 +348,8 @@ impl Default for SequenceConfig { /// A composition of a sequence buffer and its configuration. #[non_exhaustive] +#[derive(Debug, Clone)] +#[cfg_attr(feature = "defmt", derive(defmt::Format))] pub struct Sequence<'s> { /// The words comprising the sequence. Must not exceed 32767 words. pub words: &'s [u16], @@ -496,6 +501,7 @@ impl<'d, 's> Drop for Sequencer<'d, 's> { /// How many times to run a single sequence #[derive(Debug, Eq, PartialEq, Clone, Copy)] +#[cfg_attr(feature = "defmt", derive(defmt::Format))] pub enum SingleSequenceMode { /// Run a single sequence n Times total. Times(u16), @@ -505,6 +511,7 @@ pub enum SingleSequenceMode { /// Which sequence to start a loop with #[derive(Debug, Eq, PartialEq, Clone, Copy)] +#[cfg_attr(feature = "defmt", derive(defmt::Format))] pub enum StartSequence { /// Start with Sequence 0 Zero, @@ -514,6 +521,7 @@ pub enum StartSequence { /// How many loops to run two sequences #[derive(Debug, Eq, PartialEq, Clone, Copy)] +#[cfg_attr(feature = "defmt", derive(defmt::Format))] pub enum SequenceMode { /// Run two sequences n loops i.e. (n * (seq0 + seq1.unwrap_or(seq0))) Loop(u16), @@ -523,6 +531,7 @@ pub enum SequenceMode { /// PWM Base clock is system clock (16MHz) divided by prescaler #[derive(Debug, Eq, PartialEq, Clone, Copy)] +#[cfg_attr(feature = "defmt", derive(defmt::Format))] pub enum Prescaler { /// Divide by 1 Div1, @@ -544,6 +553,7 @@ pub enum Prescaler { /// How the sequence values are distributed across the channels #[derive(Debug, Eq, PartialEq, Clone, Copy)] +#[cfg_attr(feature = "defmt", derive(defmt::Format))] pub enum SequenceLoad { /// Provided sequence will be used across all channels Common, @@ -560,6 +570,7 @@ pub enum SequenceLoad { /// Selects up mode or up-and-down mode for the counter #[derive(Debug, Eq, PartialEq, Clone, Copy)] +#[cfg_attr(feature = "defmt", derive(defmt::Format))] pub enum CounterMode { /// Up counter (edge-aligned PWM duty cycle) Up, -- cgit From 5be0e0e7f9d453fc695c1a3c5b8b8148d7a4852a Mon Sep 17 00:00:00 2001 From: Maarten de Vries Date: Wed, 15 Oct 2025 11:58:46 +0200 Subject: embassy_nrf::pwm: expose duty cycle polarity for SimplePwm --- embassy-nrf/src/pwm.rs | 92 ++++++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 85 insertions(+), 7 deletions(-) diff --git a/embassy-nrf/src/pwm.rs b/embassy-nrf/src/pwm.rs index 1fa8f183b..e47922e5a 100644 --- a/embassy-nrf/src/pwm.rs +++ b/embassy-nrf/src/pwm.rs @@ -17,7 +17,7 @@ use crate::{interrupt, pac}; /// to simply set a duty cycle across up to four channels. pub struct SimplePwm<'d> { r: pac::pwm::Pwm, - duty: [u16; 4], + duty: [DutyCycle; 4], ch0: Option>, ch1: Option>, ch2: Option>, @@ -578,6 +578,84 @@ pub enum CounterMode { UpAndDown, } +/// Duty value and polarity for a single channel. +/// +/// If the channel has inverted polarity, the output is set high as long as the counter is below the duty value. +#[repr(transparent)] +#[derive(Eq, PartialEq, Clone, Copy)] +pub struct DutyCycle { + /// The raw duty cycle valuea. + /// + /// This has the duty cycle in the lower 15 bits. + /// The highest bit indicates that the duty cycle has inverted polarity. + raw: u16, +} + +impl DutyCycle { + /// Make a new duty value with normal polarity. + /// + /// The value is truncated to 15 bits. + /// + /// The output is set high if the counter is at or above the duty value. + pub const fn normal(value: u16) -> Self { + let raw = value & 0x7FFF; + Self { raw } + } + + /// Make a new duty cycle with inverted polarity. + /// + /// The value is truncated to 15 bits. + /// + /// The output is set high if the counter is below the duty value. + pub const fn inverted(value: u16) -> Self { + let raw = value | 0x8000; + Self { raw } + } + + /// Adjust the polarity of the duty cycle (returns a new object). + #[must_use = "this function return a new object, it does not modify self"] + pub const fn with_inverted(self, inverted_polarity: bool) -> Self { + if inverted_polarity { + Self::inverted(self.value()) + } else { + Self::normal(self.value()) + } + } + + /// Gets the 15-bit value of the duty cycle. + pub const fn value(&self) -> u16 { + self.raw & 0x7FFF + } + + /// Checks if the duty period has inverted polarity. + /// + /// If the channel has inverted polarity, the output is set high as long as the counter is below the duty value. + pub const fn is_inverted(&self) -> bool { + self.raw & 0x8000 != 0 + } +} + +impl core::fmt::Debug for DutyCycle { + fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result { + f.debug_struct("DutyCycle") + .field("value", &self.value()) + .field("inverted", &self.is_inverted()) + .finish() + } +} + +#[cfg(feature = "defmt")] +impl defmt::Format for DutyCycle { + fn format(&self, f: defmt::Formatter) { + defmt::write!( + f, + "DutyCycle {{ value: {=u16}, inverted: {=bool} }}", + self.value(), + self.is_inverted(), + ); + } +} + impl<'d> SimplePwm<'d> { /// Create a new 1-channel PWM #[allow(unused_unsafe)] @@ -650,7 +728,7 @@ impl<'d> SimplePwm<'d> { ch1, ch2, ch3, - duty: [0; 4], + duty: [const { DutyCycle::normal(0) }; 4], }; // Disable all interrupts @@ -695,14 +773,14 @@ impl<'d> SimplePwm<'d> { self.r.enable().write(|w| w.set_enable(false)); } - /// Returns the current duty of the channel - pub fn duty(&self, channel: usize) -> u16 { + /// Returns the current duty of the channel. + pub fn duty(&self, channel: usize) -> DutyCycle { self.duty[channel] } - /// Sets duty cycle (15 bit) for a PWM channel. - pub fn set_duty(&mut self, channel: usize, duty: u16) { - self.duty[channel] = duty & 0x7FFF; + /// Sets duty cycle (15 bit) and polarity for a PWM channel. + pub fn set_duty(&mut self, channel: usize, duty: DutyCycle) { + self.duty[channel] = duty; // reload ptr in case self was moved self.r.seq(0).ptr().write_value((self.duty).as_ptr() as u32); -- cgit From b2dce7a67e0dc18c568da5758190e23778d025ef Mon Sep 17 00:00:00 2001 From: Maarten de Vries Date: Wed, 15 Oct 2025 11:59:42 +0200 Subject: embassy_nrf::pwm: allow setting all duty cycles of SimplePwm at once --- embassy-nrf/src/pwm.rs | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/embassy-nrf/src/pwm.rs b/embassy-nrf/src/pwm.rs index e47922e5a..7fbe9be9d 100644 --- a/embassy-nrf/src/pwm.rs +++ b/embassy-nrf/src/pwm.rs @@ -781,7 +781,23 @@ impl<'d> SimplePwm<'d> { /// Sets duty cycle (15 bit) and polarity for a PWM channel. pub fn set_duty(&mut self, channel: usize, duty: DutyCycle) { self.duty[channel] = duty; + self.sync_duty_cyles_to_peripheral(); + } + + /// Sets the duty cycle (15 bit) and polarity for all PWM channels. + /// + /// You can safely set the duty cycle of disabled PWM channels. + /// + /// When using this function, a single DMA transfer sets all the duty cycles. + /// If you call [`Self::set_duty()`] multiple times, + /// each duty cycle will be set by a separate DMA transfer. + pub fn set_all_duties(&mut self, duty: [DutyCycle; 4]) { + self.duty = duty; + self.sync_duty_cyles_to_peripheral(); + } + /// Transfer the duty cycles from `self` to the peripheral. + fn sync_duty_cyles_to_peripheral(&self) { // reload ptr in case self was moved self.r.seq(0).ptr().write_value((self.duty).as_ptr() as u32); -- cgit From 9c66ec1589ae2e55817e03d9e2bb8666050d054c Mon Sep 17 00:00:00 2001 From: Maarten de Vries Date: Wed, 15 Oct 2025 12:01:18 +0200 Subject: embassy_nrf::pwm: add channel idle level to config --- embassy-nrf/src/pwm.rs | 85 +++++++++++++++++++++----------------------------- 1 file changed, 35 insertions(+), 50 deletions(-) diff --git a/embassy-nrf/src/pwm.rs b/embassy-nrf/src/pwm.rs index 7fbe9be9d..6743674e8 100644 --- a/embassy-nrf/src/pwm.rs +++ b/embassy-nrf/src/pwm.rs @@ -6,7 +6,7 @@ use core::sync::atomic::{Ordering, compiler_fence}; use embassy_hal_internal::{Peri, PeripheralType}; -use crate::gpio::{AnyPin, DISCONNECTED, OutputDrive, Pin as GpioPin, PselBits, SealedPin as _, convert_drive}; +use crate::gpio::{AnyPin, DISCONNECTED, Level, OutputDrive, Pin as GpioPin, PselBits, SealedPin as _, convert_drive}; use crate::pac::gpio::vals as gpiovals; use crate::pac::pwm::vals; use crate::ppi::{Event, Task}; @@ -53,13 +53,11 @@ pub const PWM_CLK_HZ: u32 = 16_000_000; impl<'d> SequencePwm<'d> { /// Create a new 1-channel PWM - #[allow(unused_unsafe)] pub fn new_1ch(pwm: Peri<'d, T>, ch0: Peri<'d, impl GpioPin>, config: Config) -> Result { Self::new_inner(pwm, Some(ch0.into()), None, None, None, config) } /// Create a new 2-channel PWM - #[allow(unused_unsafe)] pub fn new_2ch( pwm: Peri<'d, T>, ch0: Peri<'d, impl GpioPin>, @@ -70,7 +68,6 @@ impl<'d> SequencePwm<'d> { } /// Create a new 3-channel PWM - #[allow(unused_unsafe)] pub fn new_3ch( pwm: Peri<'d, T>, ch0: Peri<'d, impl GpioPin>, @@ -82,7 +79,6 @@ impl<'d> SequencePwm<'d> { } /// Create a new 4-channel PWM - #[allow(unused_unsafe)] pub fn new_4ch( pwm: Peri<'d, T>, ch0: Peri<'d, impl GpioPin>, @@ -111,44 +107,27 @@ impl<'d> SequencePwm<'d> { ) -> Result { let r = T::regs(); - if let Some(pin) = &ch0 { - pin.set_low(); - pin.conf().write(|w| { - w.set_dir(gpiovals::Dir::OUTPUT); - w.set_input(gpiovals::Input::DISCONNECT); - convert_drive(w, config.ch0_drive); - }); - } - if let Some(pin) = &ch1 { - pin.set_low(); - pin.conf().write(|w| { - w.set_dir(gpiovals::Dir::OUTPUT); - w.set_input(gpiovals::Input::DISCONNECT); - convert_drive(w, config.ch1_drive); - }); - } - if let Some(pin) = &ch2 { - pin.set_low(); - pin.conf().write(|w| { - w.set_dir(gpiovals::Dir::OUTPUT); - w.set_input(gpiovals::Input::DISCONNECT); - convert_drive(w, config.ch2_drive); - }); - } - if let Some(pin) = &ch3 { - pin.set_low(); - pin.conf().write(|w| { - w.set_dir(gpiovals::Dir::OUTPUT); - w.set_input(gpiovals::Input::DISCONNECT); - convert_drive(w, config.ch3_drive); - }); + let channels = [ + (&ch0, config.ch0_drive, config.ch0_idle_level), + (&ch1, config.ch1_drive, config.ch1_idle_level), + (&ch2, config.ch2_drive, config.ch2_idle_level), + (&ch3, config.ch3_drive, config.ch3_idle_level), + ]; + for (i, (pin, drive, idle_level)) in channels.into_iter().enumerate() { + if let Some(pin) = pin { + match idle_level { + Level::Low => pin.set_low(), + Level::High => pin.set_high(), + } + pin.conf().write(|w| { + w.set_dir(gpiovals::Dir::OUTPUT); + w.set_input(gpiovals::Input::DISCONNECT); + convert_drive(w, drive); + }); + } + r.psel().out(i).write_value(pin.psel_bits()); } - r.psel().out(0).write_value(ch0.psel_bits()); - r.psel().out(1).write_value(ch1.psel_bits()); - r.psel().out(2).write_value(ch2.psel_bits()); - r.psel().out(3).write_value(ch3.psel_bits()); - // Disable all interrupts r.intenclr().write(|w| w.0 = 0xFFFF_FFFF); r.shorts().write(|_| ()); @@ -173,13 +152,7 @@ impl<'d> SequencePwm<'d> { .write(|w| w.set_prescaler(vals::Prescaler::from_bits(config.prescaler as u8))); r.countertop().write(|w| w.set_countertop(config.max_duty)); - Ok(Self { - r: T::regs(), - ch0, - ch1, - ch2, - ch3, - }) + Ok(Self { r, ch0, ch1, ch2, ch3 }) } /// Returns reference to `Stopped` event endpoint for PPI. @@ -309,11 +282,19 @@ pub struct Config { pub ch2_drive: OutputDrive, /// Drive strength for the channel 3 line. pub ch3_drive: OutputDrive, + /// Output level for the channel 0 line when PWM if disabled. + pub ch0_idle_level: Level, + /// Output level for the channel 1 line when PWM if disabled. + pub ch1_idle_level: Level, + /// Output level for the channel 2 line when PWM if disabled. + pub ch2_idle_level: Level, + /// Output level for the channel 3 line when PWM if disabled. + pub ch3_idle_level: Level, } impl Default for Config { - fn default() -> Config { - Config { + fn default() -> Self { + Self { counter_mode: CounterMode::Up, max_duty: 1000, prescaler: Prescaler::Div16, @@ -322,6 +303,10 @@ impl Default for Config { ch1_drive: OutputDrive::Standard, ch2_drive: OutputDrive::Standard, ch3_drive: OutputDrive::Standard, + ch0_idle_level: Level::Low, + ch1_idle_level: Level::Low, + ch2_idle_level: Level::Low, + ch3_idle_level: Level::Low, } } } -- cgit From eba322b5108e16de2c57a55d96fcedee154b6303 Mon Sep 17 00:00:00 2001 From: Maarten de Vries Date: Wed, 15 Oct 2025 12:02:39 +0200 Subject: embassy_nrf::pwm: add config argument to SimplePwm constructors --- embassy-nrf/src/pwm.rs | 118 +++++++++++++++++++++++++++++++++++++------------ 1 file changed, 90 insertions(+), 28 deletions(-) diff --git a/embassy-nrf/src/pwm.rs b/embassy-nrf/src/pwm.rs index 6743674e8..00b3278c7 100644 --- a/embassy-nrf/src/pwm.rs +++ b/embassy-nrf/src/pwm.rs @@ -311,6 +311,53 @@ impl Default for Config { } } +/// Configuration for the simple PWM driver. +#[derive(Debug, Clone)] +#[cfg_attr(feature = "defmt", derive(defmt::Format))] +#[non_exhaustive] +pub struct SimpleConfig { + /// Selects up mode or up-and-down mode for the counter + pub counter_mode: CounterMode, + /// Top value to be compared against buffer values + pub max_duty: u16, + /// Configuration for PWM_CLK + pub prescaler: Prescaler, + /// Drive strength for the channel 0 line. + pub ch0_drive: OutputDrive, + /// Drive strength for the channel 1 line. + pub ch1_drive: OutputDrive, + /// Drive strength for the channel 2 line. + pub ch2_drive: OutputDrive, + /// Drive strength for the channel 3 line. + pub ch3_drive: OutputDrive, + /// Output level for the channel 0 line when PWM if disabled. + pub ch0_idle_level: Level, + /// Output level for the channel 1 line when PWM if disabled. + pub ch1_idle_level: Level, + /// Output level for the channel 2 line when PWM if disabled. + pub ch2_idle_level: Level, + /// Output level for the channel 3 line when PWM if disabled. + pub ch3_idle_level: Level, +} + +impl Default for SimpleConfig { + fn default() -> Self { + Self { + counter_mode: CounterMode::Up, + max_duty: 1000, + prescaler: Prescaler::Div16, + ch0_drive: OutputDrive::Standard, + ch1_drive: OutputDrive::Standard, + ch2_drive: OutputDrive::Standard, + ch3_drive: OutputDrive::Standard, + ch0_idle_level: Level::Low, + ch1_idle_level: Level::Low, + ch2_idle_level: Level::Low, + ch3_idle_level: Level::Low, + } + } +} + /// Configuration per sequence #[non_exhaustive] #[derive(Debug, Clone)] @@ -643,46 +690,48 @@ impl defmt::Format for DutyCycle { impl<'d> SimplePwm<'d> { /// Create a new 1-channel PWM - #[allow(unused_unsafe)] - pub fn new_1ch(pwm: Peri<'d, T>, ch0: Peri<'d, impl GpioPin>) -> Self { - unsafe { Self::new_inner(pwm, Some(ch0.into()), None, None, None) } + pub fn new_1ch(pwm: Peri<'d, T>, ch0: Peri<'d, impl GpioPin>, config: &SimpleConfig) -> Self { + Self::new_inner(pwm, Some(ch0.into()), None, None, None, config) } /// Create a new 2-channel PWM - #[allow(unused_unsafe)] - pub fn new_2ch(pwm: Peri<'d, T>, ch0: Peri<'d, impl GpioPin>, ch1: Peri<'d, impl GpioPin>) -> Self { - Self::new_inner(pwm, Some(ch0.into()), Some(ch1.into()), None, None) + pub fn new_2ch( + pwm: Peri<'d, T>, + ch0: Peri<'d, impl GpioPin>, + ch1: Peri<'d, impl GpioPin>, + config: &SimpleConfig, + ) -> Self { + Self::new_inner(pwm, Some(ch0.into()), Some(ch1.into()), None, None, config) } /// Create a new 3-channel PWM - #[allow(unused_unsafe)] pub fn new_3ch( pwm: Peri<'d, T>, ch0: Peri<'d, impl GpioPin>, ch1: Peri<'d, impl GpioPin>, ch2: Peri<'d, impl GpioPin>, + config: &SimpleConfig, ) -> Self { - unsafe { Self::new_inner(pwm, Some(ch0.into()), Some(ch1.into()), Some(ch2.into()), None) } + Self::new_inner(pwm, Some(ch0.into()), Some(ch1.into()), Some(ch2.into()), None, config) } /// Create a new 4-channel PWM - #[allow(unused_unsafe)] pub fn new_4ch( pwm: Peri<'d, T>, ch0: Peri<'d, impl GpioPin>, ch1: Peri<'d, impl GpioPin>, ch2: Peri<'d, impl GpioPin>, ch3: Peri<'d, impl GpioPin>, + config: &SimpleConfig, ) -> Self { - unsafe { - Self::new_inner( - pwm, - Some(ch0.into()), - Some(ch1.into()), - Some(ch2.into()), - Some(ch3.into()), - ) - } + Self::new_inner( + pwm, + Some(ch0.into()), + Some(ch1.into()), + Some(ch2.into()), + Some(ch3.into()), + config, + ) } fn new_inner( @@ -691,24 +740,33 @@ impl<'d> SimplePwm<'d> { ch1: Option>, ch2: Option>, ch3: Option>, + config: &SimpleConfig, ) -> Self { let r = T::regs(); - for (i, ch) in [&ch0, &ch1, &ch2, &ch3].into_iter().enumerate() { - if let Some(pin) = ch { - pin.set_low(); - + let channels = [ + (&ch0, config.ch0_drive, config.ch0_idle_level), + (&ch1, config.ch1_drive, config.ch1_idle_level), + (&ch2, config.ch2_drive, config.ch2_idle_level), + (&ch3, config.ch3_drive, config.ch3_idle_level), + ]; + for (i, (pin, drive, idle_level)) in channels.into_iter().enumerate() { + if let Some(pin) = pin { + match idle_level { + Level::Low => pin.set_low(), + Level::High => pin.set_high(), + } pin.conf().write(|w| { w.set_dir(gpiovals::Dir::OUTPUT); w.set_input(gpiovals::Input::DISCONNECT); - w.set_drive(gpiovals::Drive::S0S1); + convert_drive(w, drive); }); } - r.psel().out(i).write_value(ch.psel_bits()); + r.psel().out(i).write_value(pin.psel_bits()); } let pwm = Self { - r: T::regs(), + r, ch0, ch1, ch2, @@ -732,9 +790,13 @@ impl<'d> SimplePwm<'d> { w.set_load(vals::Load::INDIVIDUAL); w.set_mode(vals::Mode::REFRESH_COUNT); }); - r.mode().write(|w| w.set_updown(vals::Updown::UP)); - r.prescaler().write(|w| w.set_prescaler(vals::Prescaler::DIV_16)); - r.countertop().write(|w| w.set_countertop(1000)); + r.mode().write(|w| match config.counter_mode { + CounterMode::UpAndDown => w.set_updown(vals::Updown::UP_AND_DOWN), + CounterMode::Up => w.set_updown(vals::Updown::UP), + }); + r.prescaler() + .write(|w| w.set_prescaler(vals::Prescaler::from_bits(config.prescaler as u8))); + r.countertop().write(|w| w.set_countertop(config.max_duty)); r.loop_().write(|w| w.set_cnt(vals::LoopCnt::DISABLED)); pwm -- cgit From 3250345748cd25f209ff3426ae01bad55b2c8e9e Mon Sep 17 00:00:00 2001 From: Maarten de Vries Date: Wed, 15 Oct 2025 14:41:25 +0200 Subject: embassy_nrf: update CHANGELOG --- embassy-nrf/CHANGELOG.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/embassy-nrf/CHANGELOG.md b/embassy-nrf/CHANGELOG.md index 3df7bfd4c..8ce484646 100644 --- a/embassy-nrf/CHANGELOG.md +++ b/embassy-nrf/CHANGELOG.md @@ -11,6 +11,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - added: Add basic RTC support for nRF54L - changed: apply trimming values from FICR.TRIMCNF on nrf53/54l - changed: do not panic on BufferedUarte overrun +- added: allow configuring the idle state of GPIO pins connected to PWM channels +- changed: allow configuring the PWM peripheral in the constructor of `SimplePwm` +- changed: support setting duty cycles with inverted polarity in `SimplePwm` +- added: support setting the duty cycles of all channels at once in `SimplePwm` ## 0.8.0 - 2025-09-30 -- cgit From 369959e654d095d0e3d95597693bd64fcdb50ec5 Mon Sep 17 00:00:00 2001 From: Maarten de Vries Date: Wed, 15 Oct 2025 14:53:40 +0200 Subject: embassy_nrf: update examples --- examples/nrf52840/src/bin/i2s_monitor.rs | 9 ++++----- examples/nrf52840/src/bin/pwm.rs | 14 ++++++++------ examples/nrf52840/src/bin/pwm_servo.rs | 14 +++++++------- 3 files changed, 19 insertions(+), 18 deletions(-) diff --git a/examples/nrf52840/src/bin/i2s_monitor.rs b/examples/nrf52840/src/bin/i2s_monitor.rs index 66b429b09..a54659101 100644 --- a/examples/nrf52840/src/bin/i2s_monitor.rs +++ b/examples/nrf52840/src/bin/i2s_monitor.rs @@ -4,7 +4,7 @@ use defmt::{debug, error, info}; use embassy_executor::Spawner; use embassy_nrf::i2s::{self, Channels, Config, DoubleBuffering, I2S, MasterClock, Sample as _, SampleWidth}; -use embassy_nrf::pwm::{Prescaler, SimplePwm}; +use embassy_nrf::pwm::{DutyCycle, Prescaler, SimplePwm}; use embassy_nrf::{bind_interrupts, peripherals}; use {defmt_rtt as _, panic_probe as _}; @@ -34,7 +34,7 @@ async fn main(_spawner: Spawner) { I2S::new_master(p.I2S, Irqs, p.P0_25, p.P0_26, p.P0_27, master_clock, config).input(p.P0_29, buffers); // Configure the PWM to use the pins corresponding to the RGB leds - let mut pwm = SimplePwm::new_3ch(p.PWM0, p.P0_23, p.P0_22, p.P0_24); + let mut pwm = SimplePwm::new_3ch(p.PWM0, p.P0_23, p.P0_22, p.P0_24, &Default::default()); pwm.set_prescaler(Prescaler::Div1); pwm.set_max_duty(255); @@ -47,9 +47,8 @@ async fn main(_spawner: Spawner) { let rgb = rgb_from_rms(rms); debug!("RMS: {}, RGB: {:?}", rms, rgb); - for i in 0..3 { - pwm.set_duty(i, rgb[i].into()); - } + let duties = rgb.map(|byte| DutyCycle::normal(u16::from(byte))); + pwm.set_all_duties([duties[0], duties[1], duties[2], DutyCycle::normal(0)]); if let Err(err) = input_stream.receive().await { error!("{}", err); diff --git a/examples/nrf52840/src/bin/pwm.rs b/examples/nrf52840/src/bin/pwm.rs index a5bb1347a..02f9b4191 100644 --- a/examples/nrf52840/src/bin/pwm.rs +++ b/examples/nrf52840/src/bin/pwm.rs @@ -3,7 +3,7 @@ use defmt::*; use embassy_executor::Spawner; -use embassy_nrf::pwm::{Prescaler, SimplePwm}; +use embassy_nrf::pwm::{DutyCycle, Prescaler, SimplePwm}; use embassy_time::Timer; use {defmt_rtt as _, panic_probe as _}; @@ -71,7 +71,7 @@ static DUTY: [u16; 1024] = [ #[embassy_executor::main] async fn main(_spawner: Spawner) { let p = embassy_nrf::init(Default::default()); - let mut pwm = SimplePwm::new_4ch(p.PWM0, p.P0_13, p.P0_14, p.P0_16, p.P0_15); + let mut pwm = SimplePwm::new_4ch(p.PWM0, p.P0_13, p.P0_14, p.P0_16, p.P0_15, &Default::default()); pwm.set_prescaler(Prescaler::Div1); pwm.set_max_duty(32767); info!("pwm initialized!"); @@ -79,10 +79,12 @@ async fn main(_spawner: Spawner) { let mut i = 0; loop { i += 1; - pwm.set_duty(0, DUTY[i % 1024]); - pwm.set_duty(1, DUTY[(i + 256) % 1024]); - pwm.set_duty(2, DUTY[(i + 512) % 1024]); - pwm.set_duty(3, DUTY[(i + 768) % 1024]); + pwm.set_all_duties([ + DutyCycle::normal(DUTY[i % 1024]), + DutyCycle::normal(DUTY[(i + 256) % 1024]), + DutyCycle::normal(DUTY[(i + 512) % 1024]), + DutyCycle::normal(DUTY[(i + 768) % 1024]), + ]); Timer::after_millis(3).await; } } diff --git a/examples/nrf52840/src/bin/pwm_servo.rs b/examples/nrf52840/src/bin/pwm_servo.rs index d772d2f5d..93cb984e6 100644 --- a/examples/nrf52840/src/bin/pwm_servo.rs +++ b/examples/nrf52840/src/bin/pwm_servo.rs @@ -3,14 +3,14 @@ use defmt::*; use embassy_executor::Spawner; -use embassy_nrf::pwm::{Prescaler, SimplePwm}; +use embassy_nrf::pwm::{DutyCycle, Prescaler, SimplePwm}; use embassy_time::Timer; use {defmt_rtt as _, panic_probe as _}; #[embassy_executor::main] async fn main(_spawner: Spawner) { let p = embassy_nrf::init(Default::default()); - let mut pwm = SimplePwm::new_1ch(p.PWM0, p.P0_05); + let mut pwm = SimplePwm::new_1ch(p.PWM0, p.P0_05, &Default::default()); // sg90 microervo requires 50hz or 20ms period // set_period can only set down to 125khz so we cant use it directly // Div128 is 125khz or 0.000008s or 0.008ms, 20/0.008 is 2500 is top @@ -24,23 +24,23 @@ async fn main(_spawner: Spawner) { loop { info!("45 deg"); // poor mans inverting, subtract our value from max_duty - pwm.set_duty(0, 2500 - 156); + pwm.set_duty(0, DutyCycle::normal(2500 - 156)); Timer::after_millis(5000).await; info!("90 deg"); - pwm.set_duty(0, 2500 - 187); + pwm.set_duty(0, DutyCycle::normal(2500 - 187)); Timer::after_millis(5000).await; info!("135 deg"); - pwm.set_duty(0, 2500 - 218); + pwm.set_duty(0, DutyCycle::normal(2500 - 218)); Timer::after_millis(5000).await; info!("180 deg"); - pwm.set_duty(0, 2500 - 250); + pwm.set_duty(0, DutyCycle::normal(2500 - 250)); Timer::after_millis(5000).await; info!("0 deg"); - pwm.set_duty(0, 2500 - 125); + pwm.set_duty(0, DutyCycle::normal(2500 - 125)); Timer::after_millis(5000).await; } } -- cgit From 6ba2611430e824a5d19d4d116640c8ba86c6850d Mon Sep 17 00:00:00 2001 From: Dillon Min Date: Thu, 16 Oct 2025 14:17:36 +0800 Subject: stm32: flash: fix flash erase on stm32l4xx, stm32l5xx series stm32l4xx, stm32l5xx flash layout has different pages(64/128/256) depends on BANK1_REGION.size and BANK1_REGION.erase_size. replace hardcoded 256 pages to size/erase_size. Signed-off-by: Dillon Min --- embassy-stm32/CHANGELOG.md | 1 + embassy-stm32/src/flash/l.rs | 12 +++++++++--- 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/embassy-stm32/CHANGELOG.md b/embassy-stm32/CHANGELOG.md index 7675567ff..9848daf49 100644 --- a/embassy-stm32/CHANGELOG.md +++ b/embassy-stm32/CHANGELOG.md @@ -11,6 +11,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 * **Fix(stm32h5):** Prevent a HardFault crash on STM32H5 devices by changing `uid()` to return `[u8; 12]` by value instead of a reference. (Fixes #2696) ## Unreleased - ReleaseDate +- fix flash erase on L4 & L5 - fix: Fixed STM32H5 builds requiring time feature - feat: Derive Clone, Copy for QSPI Config - fix: stm32/i2c in master mode (blocking): subsequent transmissions failed after a NACK was received diff --git a/embassy-stm32/src/flash/l.rs b/embassy-stm32/src/flash/l.rs index cd23cda5c..b3281f2d5 100644 --- a/embassy-stm32/src/flash/l.rs +++ b/embassy-stm32/src/flash/l.rs @@ -96,14 +96,20 @@ pub(crate) unsafe fn blocking_erase_sector(sector: &FlashSector) -> Result<(), E #[cfg(any(flash_wl, flash_wb, flash_l4, flash_l5))] { let idx = (sector.start - super::FLASH_BASE as u32) / super::BANK1_REGION.erase_size as u32; + #[cfg(any(flash_l4, flash_l5))] + let pgn = super::BANK1_REGION.size as u32 / super::BANK1_REGION.erase_size as u32; #[cfg(flash_l4)] - let (idx, bank) = if idx > 255 { (idx - 256, true) } else { (idx, false) }; + let (idx, bank) = if idx > (pgn - 1) { + (idx - pgn, true) + } else { + (idx, false) + }; #[cfg(flash_l5)] let (idx, bank) = if pac::FLASH.optr().read().dbank() { - if idx > 255 { - (idx - 256, Some(true)) + if idx > (pgn - 1) { + (idx - pgn, Some(true)) } else { (idx, Some(false)) } -- cgit From da5a563489757b9803074d6bddf0bf1b2d7f13d0 Mon Sep 17 00:00:00 2001 From: i509VCB Date: Sat, 18 Oct 2025 20:58:09 -0500 Subject: nxp/lpc55: move usart ALT pin definitions to impl_xx_pin macros --- embassy-nxp/CHANGELOG.md | 1 + embassy-nxp/src/usart/lpc55.rs | 139 ++++++++++++++++++++++++++--------------- 2 files changed, 88 insertions(+), 52 deletions(-) diff --git a/embassy-nxp/CHANGELOG.md b/embassy-nxp/CHANGELOG.md index 295d45c2d..ad8670854 100644 --- a/embassy-nxp/CHANGELOG.md +++ b/embassy-nxp/CHANGELOG.md @@ -7,6 +7,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## Unreleased - ReleaseDate +- LPC55: Move ALT definitions for USART to TX/RX pin impls. - LPC55: Remove internal match_iocon macro - LPC55: DMA Controller and asynchronous version of USART - Moved NXP LPC55S69 from `lpc55-pac` to `nxp-pac` diff --git a/embassy-nxp/src/usart/lpc55.rs b/embassy-nxp/src/usart/lpc55.rs index 6cbde82a3..d54927b25 100644 --- a/embassy-nxp/src/usart/lpc55.rs +++ b/embassy-nxp/src/usart/lpc55.rs @@ -146,7 +146,8 @@ impl<'d, M: Mode> UsartTx<'d, M> { tx_dma: Peri<'d, impl Channel>, config: Config, ) -> Self { - Usart::::init::(Some(tx.into()), None, config); + let tx_func = tx.pin_func(); + Usart::::init::(Some((tx.into(), tx_func)), None, config); Self::new_inner(T::info(), Some(tx_dma.into())) } @@ -179,7 +180,8 @@ impl<'d, M: Mode> UsartTx<'d, M> { impl<'d> UsartTx<'d, Blocking> { pub fn new_blocking(_usart: Peri<'d, T>, tx: Peri<'d, impl TxPin>, config: Config) -> Self { - Usart::::init::(Some(tx.into()), None, config); + let tx_func = tx.pin_func(); + Usart::::init::(Some((tx.into(), tx_func)), None, config); Self::new_inner(T::info(), None) } } @@ -208,7 +210,8 @@ impl<'d, M: Mode> UsartRx<'d, M> { rx_dma: Peri<'d, impl Channel>, config: Config, ) -> Self { - Usart::::init::(None, Some(rx.into()), config); + let rx_func = rx.pin_func(); + Usart::::init::(None, Some((rx.into(), rx_func)), config); Self::new_inner(T::info(), T::dma_state(), has_irq, Some(rx_dma.into())) } @@ -280,7 +283,8 @@ impl<'d, M: Mode> UsartRx<'d, M> { impl<'d> UsartRx<'d, Blocking> { pub fn new_blocking(_usart: Peri<'d, T>, rx: Peri<'d, impl RxPin>, config: Config) -> Self { - Usart::::init::(None, Some(rx.into()), config); + let rx_func = rx.pin_func(); + Usart::::init::(None, Some((rx.into(), rx_func)), config); Self::new_inner(T::info(), T::dma_state(), false, None) } } @@ -405,7 +409,10 @@ impl<'d> Usart<'d, Blocking> { rx: Peri<'d, impl RxPin>, config: Config, ) -> Self { - Self::new_inner(usart, tx.into(), rx.into(), false, None, None, config) + let tx_func = tx.pin_func(); + let rx_func = rx.pin_func(); + + Self::new_inner(usart, tx.into(), tx_func, rx.into(), rx_func, false, None, None, config) } } @@ -419,10 +426,15 @@ impl<'d> Usart<'d, Async> { rx_dma: Peri<'d, impl RxChannel>, config: Config, ) -> Self { + let tx_func = tx.pin_func(); + let rx_func = rx.pin_func(); + Self::new_inner( uart, tx.into(), + tx_func, rx.into(), + rx_func, true, Some(tx_dma.into()), Some(rx_dma.into()), @@ -435,20 +447,26 @@ impl<'d, M: Mode> Usart<'d, M> { fn new_inner( _usart: Peri<'d, T>, mut tx: Peri<'d, AnyPin>, + tx_func: PioFunc, mut rx: Peri<'d, AnyPin>, + rx_func: PioFunc, has_irq: bool, tx_dma: Option>, rx_dma: Option>, config: Config, ) -> Self { - Self::init::(Some(tx.reborrow()), Some(rx.reborrow()), config); + Self::init::(Some((tx.reborrow(), tx_func)), Some((rx.reborrow(), rx_func)), config); Self { tx: UsartTx::new_inner(T::info(), tx_dma), rx: UsartRx::new_inner(T::info(), T::dma_state(), has_irq, rx_dma), } } - fn init(tx: Option>, rx: Option>, config: Config) { + fn init( + tx: Option<(Peri<'_, AnyPin>, PioFunc)>, + rx: Option<(Peri<'_, AnyPin>, PioFunc)>, + config: Config, + ) { Self::configure_flexcomm(T::info().fc_reg, T::instance_number()); Self::configure_clock::(&config); Self::pin_config::(tx, rx); @@ -553,10 +571,10 @@ impl<'d, M: Mode> Usart<'d, M> { .modify(|w| w.set_brgval((brg_value - 1) as u16)); } - fn pin_config(tx: Option>, rx: Option>) { - if let Some(tx_pin) = tx { + fn pin_config(tx: Option<(Peri<'_, AnyPin>, PioFunc)>, rx: Option<(Peri<'_, AnyPin>, PioFunc)>) { + if let Some((tx_pin, func)) = tx { tx_pin.pio().modify(|w| { - w.set_func(T::tx_pin_func()); + w.set_func(func); w.set_mode(iocon::vals::PioMode::INACTIVE); w.set_slew(iocon::vals::PioSlew::STANDARD); w.set_invert(false); @@ -565,9 +583,9 @@ impl<'d, M: Mode> Usart<'d, M> { }); } - if let Some(rx_pin) = rx { + if let Some((rx_pin, func)) = rx { rx_pin.pio().modify(|w| { - w.set_func(T::rx_pin_func()); + w.set_func(func); w.set_mode(iocon::vals::PioMode::INACTIVE); w.set_slew(iocon::vals::PioSlew::STANDARD); w.set_invert(false); @@ -810,8 +828,6 @@ trait SealedInstance { fn info() -> &'static Info; fn dma_state() -> &'static DmaState; fn instance_number() -> usize; - fn tx_pin_func() -> PioFunc; - fn rx_pin_func() -> PioFunc; } /// UART instance. @@ -822,7 +838,7 @@ pub trait Instance: SealedInstance + PeripheralType { } macro_rules! impl_instance { - ($inst:ident, $fc:ident, $tx_pin:ident, $rx_pin:ident, $fc_num:expr) => { + ($inst:ident, $fc:ident, $fc_num:expr) => { impl $crate::usart::inner::SealedInstance for $crate::peripherals::$inst { fn info() -> &'static Info { static INFO: Info = Info { @@ -844,14 +860,6 @@ macro_rules! impl_instance { fn instance_number() -> usize { $fc_num } - #[inline] - fn tx_pin_func() -> PioFunc { - PioFunc::$tx_pin - } - #[inline] - fn rx_pin_func() -> PioFunc { - PioFunc::$rx_pin - } } impl $crate::usart::Instance for $crate::peripherals::$inst { type Interrupt = crate::interrupt::typelevel::$fc; @@ -859,45 +867,72 @@ macro_rules! impl_instance { }; } -impl_instance!(USART0, FLEXCOMM0, ALT1, ALT1, 0); -impl_instance!(USART1, FLEXCOMM1, ALT2, ALT2, 1); -impl_instance!(USART2, FLEXCOMM2, ALT1, ALT1, 2); -impl_instance!(USART3, FLEXCOMM3, ALT1, ALT1, 3); -impl_instance!(USART4, FLEXCOMM4, ALT1, ALT2, 4); -impl_instance!(USART5, FLEXCOMM5, ALT3, ALT3, 5); -impl_instance!(USART6, FLEXCOMM6, ALT2, ALT2, 6); -impl_instance!(USART7, FLEXCOMM7, ALT7, ALT7, 7); +impl_instance!(USART0, FLEXCOMM0, 0); +impl_instance!(USART1, FLEXCOMM1, 1); +impl_instance!(USART2, FLEXCOMM2, 2); +impl_instance!(USART3, FLEXCOMM3, 3); +impl_instance!(USART4, FLEXCOMM4, 4); +impl_instance!(USART5, FLEXCOMM5, 5); +impl_instance!(USART6, FLEXCOMM6, 6); +impl_instance!(USART7, FLEXCOMM7, 7); + +pub(crate) trait SealedTxPin: crate::gpio::Pin { + fn pin_func(&self) -> PioFunc; +} + +pub(crate) trait SealedRxPin: crate::gpio::Pin { + fn pin_func(&self) -> PioFunc; +} /// Trait for TX pins. -pub trait TxPin: crate::gpio::Pin {} +#[allow(private_bounds)] +pub trait TxPin: SealedTxPin + crate::gpio::Pin {} + /// Trait for RX pins. -pub trait RxPin: crate::gpio::Pin {} +#[allow(private_bounds)] +pub trait RxPin: SealedRxPin + crate::gpio::Pin {} + +macro_rules! impl_tx_pin { + ($pin:ident, $instance:ident, $func: ident) => { + impl SealedTxPin for crate::peripherals::$pin { + fn pin_func(&self) -> PioFunc { + PioFunc::$func + } + } -macro_rules! impl_pin { - ($pin:ident, $instance:ident, Tx) => { impl TxPin for crate::peripherals::$pin {} }; - ($pin:ident, $instance:ident, Rx) => { +} + +macro_rules! impl_rx_pin { + ($pin:ident, $instance:ident, $func: ident) => { + impl SealedRxPin for crate::peripherals::$pin { + fn pin_func(&self) -> PioFunc { + PioFunc::$func + } + } + impl RxPin for crate::peripherals::$pin {} }; } -impl_pin!(PIO1_6, USART0, Tx); -impl_pin!(PIO1_5, USART0, Rx); -impl_pin!(PIO1_11, USART1, Tx); -impl_pin!(PIO1_10, USART1, Rx); -impl_pin!(PIO0_27, USART2, Tx); -impl_pin!(PIO1_24, USART2, Rx); -impl_pin!(PIO0_2, USART3, Tx); -impl_pin!(PIO0_3, USART3, Rx); -impl_pin!(PIO0_16, USART4, Tx); -impl_pin!(PIO0_5, USART4, Rx); -impl_pin!(PIO0_9, USART5, Tx); -impl_pin!(PIO0_8, USART5, Rx); -impl_pin!(PIO1_16, USART6, Tx); -impl_pin!(PIO1_13, USART6, Rx); -impl_pin!(PIO0_19, USART7, Tx); -impl_pin!(PIO0_20, USART7, Rx); +impl_tx_pin!(PIO1_6, USART0, ALT1); +impl_tx_pin!(PIO1_11, USART1, ALT2); +impl_tx_pin!(PIO0_27, USART2, ALT1); +impl_tx_pin!(PIO0_2, USART3, ALT1); +impl_tx_pin!(PIO0_16, USART4, ALT1); +impl_tx_pin!(PIO0_9, USART5, ALT3); +impl_tx_pin!(PIO1_16, USART6, ALT2); +impl_tx_pin!(PIO0_19, USART7, ALT7); + +impl_rx_pin!(PIO1_5, USART0, ALT1); +impl_rx_pin!(PIO1_10, USART1, ALT2); +impl_rx_pin!(PIO1_24, USART2, ALT1); +impl_rx_pin!(PIO0_3, USART3, ALT1); +impl_rx_pin!(PIO0_5, USART4, ALT2); +impl_rx_pin!(PIO0_8, USART5, ALT3); +impl_rx_pin!(PIO1_13, USART6, ALT2); +impl_rx_pin!(PIO0_20, USART7, ALT7); /// Trait for TX DMA channels. pub trait TxChannel: crate::dma::Channel {} -- cgit From 1f1e3cd0e3490f23bedb125514550b3a2e0177c1 Mon Sep 17 00:00:00 2001 From: Kat <187942808+northernpaws@users.noreply.github.com> Date: Tue, 21 Oct 2025 22:03:43 -0600 Subject: add 16 bit SDRAM configuration for Bank 1 in fmc.rs --- embassy-stm32/src/fmc.rs | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/embassy-stm32/src/fmc.rs b/embassy-stm32/src/fmc.rs index 8ecfbc522..4fd7dac60 100644 --- a/embassy-stm32/src/fmc.rs +++ b/embassy-stm32/src/fmc.rs @@ -236,6 +236,24 @@ impl<'d, T: Instance> Fmc<'d, T> { (sdcke: SDCKE1Pin), (sdclk: SDCLKPin), (sdncas: SDNCASPin), (sdne: SDNE1Pin), (sdnras: SDNRASPin), (sdnwe: SDNWEPin) ] )); + + fmc_sdram_constructor!(sdram_a13bits_d16bits_16banks_bank1: ( + bank: stm32_fmc::SdramTargetBank::Bank1, + addr: [ + (a0: A0Pin), (a1: A1Pin), (a2: A2Pin), (a3: A3Pin), (a4: A4Pin), (a5: A5Pin), (a6: A6Pin), (a7: A7Pin), (a8: A8Pin), (a9: A9Pin), (a10: A10Pin), (a11: A11Pin), (a12: A12Pin) + ], + ba: [(ba0: BA0Pin), (ba1: BA1Pin)], + d: [ + (d0: D0Pin), (d1: D1Pin), (d2: D2Pin), (d3: D3Pin), (d4: D4Pin), (d5: D5Pin), (d6: D6Pin), (d7: D7Pin), + (d8: D8Pin), (d9: D9Pin), (d10: D10Pin), (d11: D11Pin), (d12: D12Pin), (d13: D13Pin), (d14: D14Pin), (d15: D15Pin) + ], + nbl: [ + (nbl0: NBL0Pin), (nbl1: NBL1Pin) + ], + ctrl: [ + (sdcke: SDCKE0Pin), (sdclk: SDCLKPin), (sdncas: SDNCASPin), (sdne: SDNE0Pin), (sdnras: SDNRASPin), (sdnwe: SDNWEPin) + ] + )); } trait SealedInstance: crate::rcc::RccPeripheral { -- cgit From 51b72a3f5a187b4102ef89f225ff9101742eab40 Mon Sep 17 00:00:00 2001 From: Kat <187942808+northernpaws@users.noreply.github.com> Date: Tue, 21 Oct 2025 22:17:09 -0600 Subject: correct 16 bit SDRAM configuration label from 16 banks to 4 banks --- embassy-stm32/src/fmc.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/embassy-stm32/src/fmc.rs b/embassy-stm32/src/fmc.rs index 4fd7dac60..b21506c38 100644 --- a/embassy-stm32/src/fmc.rs +++ b/embassy-stm32/src/fmc.rs @@ -237,7 +237,7 @@ impl<'d, T: Instance> Fmc<'d, T> { ] )); - fmc_sdram_constructor!(sdram_a13bits_d16bits_16banks_bank1: ( + fmc_sdram_constructor!(sdram_a13bits_d16bits_4banks_bank1: ( bank: stm32_fmc::SdramTargetBank::Bank1, addr: [ (a0: A0Pin), (a1: A1Pin), (a2: A2Pin), (a3: A3Pin), (a4: A4Pin), (a5: A5Pin), (a6: A6Pin), (a7: A7Pin), (a8: A8Pin), (a9: A9Pin), (a10: A10Pin), (a11: A11Pin), (a12: A12Pin) -- cgit From 5ed604fc0453066f0d0cf0c161823df5f4b7900f Mon Sep 17 00:00:00 2001 From: Roi Bachynskyi Date: Thu, 25 Sep 2025 15:19:45 +0300 Subject: nxp/lpc55: pwm simple --- embassy-nxp/CHANGELOG.md | 1 + embassy-nxp/Cargo.toml | 4 +- embassy-nxp/src/chips/lpc55.rs | 12 ++ embassy-nxp/src/fmt.rs | 1 - embassy-nxp/src/lib.rs | 7 +- embassy-nxp/src/pwm.rs | 5 + embassy-nxp/src/pwm/lpc55.rs | 325 +++++++++++++++++++++++++++++++++++++++ examples/lpc55s69/src/bin/pwm.rs | 18 +++ 8 files changed, 369 insertions(+), 4 deletions(-) create mode 100644 embassy-nxp/src/pwm.rs create mode 100644 embassy-nxp/src/pwm/lpc55.rs create mode 100644 examples/lpc55s69/src/bin/pwm.rs diff --git a/embassy-nxp/CHANGELOG.md b/embassy-nxp/CHANGELOG.md index ad8670854..39f5c75bd 100644 --- a/embassy-nxp/CHANGELOG.md +++ b/embassy-nxp/CHANGELOG.md @@ -7,6 +7,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## Unreleased - ReleaseDate +- LPC55: PWM simple - LPC55: Move ALT definitions for USART to TX/RX pin impls. - LPC55: Remove internal match_iocon macro - LPC55: DMA Controller and asynchronous version of USART diff --git a/embassy-nxp/Cargo.toml b/embassy-nxp/Cargo.toml index 33f0f2dff..f8c63ba29 100644 --- a/embassy-nxp/Cargo.toml +++ b/embassy-nxp/Cargo.toml @@ -38,13 +38,13 @@ embassy-time-queue-utils = { version = "0.3.0", path = "../embassy-time-queue-ut embedded-io = "0.6.1" embedded-hal-02 = { package = "embedded-hal", version = "0.2.6", features = ["unproven"] } ## Chip dependencies -nxp-pac = { version = "0.1.0", optional = true, git = "https://github.com/i509VCB/nxp-pac", rev = "b736e3038254d593024aaa1a5a7b1f95a5728538"} +nxp-pac = { version = "0.1.0", optional = true, git = "https://github.com/i509VCB/nxp-pac", rev = "477dfdbfd5e6c75c0730c56494b601c1b2257263"} imxrt-rt = { version = "0.1.7", optional = true, features = ["device"] } [build-dependencies] cfg_aliases = "0.2.1" -nxp-pac = { version = "0.1.0", git = "https://github.com/i509VCB/nxp-pac", rev = "b736e3038254d593024aaa1a5a7b1f95a5728538", features = ["metadata"], optional = true } +nxp-pac = { version = "0.1.0", git = "https://github.com/i509VCB/nxp-pac", rev = "477dfdbfd5e6c75c0730c56494b601c1b2257263", features = ["metadata"], optional = true } proc-macro2 = "1.0.95" quote = "1.0.15" diff --git a/embassy-nxp/src/chips/lpc55.rs b/embassy-nxp/src/chips/lpc55.rs index 9f4e7269f..e9addddb6 100644 --- a/embassy-nxp/src/chips/lpc55.rs +++ b/embassy-nxp/src/chips/lpc55.rs @@ -97,6 +97,18 @@ embassy_hal_internal::peripherals! { DMA_CH21, DMA_CH22, + // Pulse-Width Modulation Outputs. + PWM_OUTPUT0, + PWM_OUTPUT1, + PWM_OUTPUT2, + PWM_OUTPUT3, + PWM_OUTPUT4, + PWM_OUTPUT5, + PWM_OUTPUT6, + PWM_OUTPUT7, + PWM_OUTPUT8, + PWM_OUTPUT9, + // Universal Synchronous/Asynchronous Receiver/Transmitter (USART) instances. USART0, USART1, diff --git a/embassy-nxp/src/fmt.rs b/embassy-nxp/src/fmt.rs index 27d41ace6..11275235e 100644 --- a/embassy-nxp/src/fmt.rs +++ b/embassy-nxp/src/fmt.rs @@ -1,5 +1,4 @@ //! Copied from embassy-rp - #![macro_use] #![allow(unused)] diff --git a/embassy-nxp/src/lib.rs b/embassy-nxp/src/lib.rs index 9576f02b1..4058881a5 100644 --- a/embassy-nxp/src/lib.rs +++ b/embassy-nxp/src/lib.rs @@ -10,6 +10,8 @@ pub mod gpio; #[cfg(feature = "lpc55-core0")] pub mod pint; #[cfg(feature = "lpc55-core0")] +pub mod pwm; +#[cfg(feature = "lpc55-core0")] pub mod usart; #[cfg(feature = "_time_driver")] @@ -154,7 +156,10 @@ pub fn init(_config: config::Config) -> Peripherals { gpio::init(); #[cfg(feature = "lpc55-core0")] - pint::init(); + { + pint::init(); + pwm::Pwm::reset(); + } #[cfg(feature = "_time_driver")] time_driver::init(); diff --git a/embassy-nxp/src/pwm.rs b/embassy-nxp/src/pwm.rs new file mode 100644 index 000000000..68980924a --- /dev/null +++ b/embassy-nxp/src/pwm.rs @@ -0,0 +1,5 @@ +//! Pulse-Width Modulation (PWM) driver. + +#[cfg_attr(feature = "lpc55-core0", path = "./pwm/lpc55.rs")] +mod inner; +pub use inner::*; diff --git a/embassy-nxp/src/pwm/lpc55.rs b/embassy-nxp/src/pwm/lpc55.rs new file mode 100644 index 000000000..197184ad6 --- /dev/null +++ b/embassy-nxp/src/pwm/lpc55.rs @@ -0,0 +1,325 @@ +use core::sync::atomic::{AtomicU8, AtomicU32, Ordering}; + +use embassy_hal_internal::{Peri, PeripheralType}; + +use crate::gpio::AnyPin; +use crate::pac::iocon::vals::{PioDigimode, PioFunc, PioMode, PioOd, PioSlew}; +use crate::pac::sct0::vals; +use crate::pac::syscon::vals::{SctRst, SctclkselSel}; +use crate::pac::{SCT0, SYSCON}; + +// Since for now the counter is shared, the TOP value has to be kept. +static TOP_VALUE: AtomicU32 = AtomicU32::new(0); +// To check if there are still active instances. +static REF_COUNT: AtomicU8 = AtomicU8::new(0); + +/// The configuration of a PWM output. +/// Note the period in clock cycles of an output can be computed as: +/// `(top + 1) * (phase_correct ? 1 : 2) * divider * prescale_factor` +/// By default, the clock used is 96 MHz. +#[non_exhaustive] +#[derive(Clone)] +pub struct Config { + /// Inverts the PWM output signal. + pub invert: bool, + /// Enables phase-correct mode for PWM operation. + /// In phase-correct mode, the PWM signal is generated in such a way that + /// the pulse is always centered regardless of the duty cycle. + /// The output frequency is halved when phase-correct mode is enabled. + pub phase_correct: bool, + /// Enables the PWM output, allowing it to generate an output. + pub enable: bool, + /// A SYSCON clock divider allows precise control over + /// the PWM output frequency by gating the PWM counter increment. + /// A higher value will result in a slower output frequency. + /// The clock is divided by `divider + 1`. + pub divider: u8, + /// Specifies the factor by which the SCT clock is prescaled to produce the unified + /// counter clock. The counter clock is clocked at the rate of the SCT clock divided by + /// `PRE + 1`. + pub prescale_factor: u8, + /// The output goes high when `compare` is higher than the + /// counter. A compare of 0 will produce an always low output, while a + /// compare of `top` will produce an always high output. + pub compare: u32, + /// The point at which the counter resets, representing the maximum possible + /// period. The counter will either wrap to 0 or reverse depending on the + /// setting of `phase_correct`. + pub top: u32, +} + +impl Config { + pub fn new(compare: u32, top: u32) -> Self { + Self { + invert: false, + phase_correct: false, + enable: true, + divider: 255, + prescale_factor: 255, + compare, + top, + } + } +} + +/// PWM driver. +pub struct Pwm<'d> { + _pin: Peri<'d, AnyPin>, + output: usize, +} + +impl<'d> Pwm<'d> { + pub(crate) fn reset() { + // Reset SCTimer => Reset counter and halt it. + // It should be done only once during the initialization of the board. + SYSCON.presetctrl1().modify(|w| w.set_sct_rst(SctRst::ASSERTED)); + SYSCON.presetctrl1().modify(|w| w.set_sct_rst(SctRst::RELEASED)); + } + fn new_inner(output: usize, channel: Peri<'d, impl OutputChannelPin>, config: Config) -> Self { + // Enable clocks (Syscon is enabled by default) + critical_section::with(|_cs| { + if !SYSCON.ahbclkctrl0().read().iocon() { + SYSCON.ahbclkctrl0().modify(|w| w.set_iocon(true)); + } + if !SYSCON.ahbclkctrl1().read().sct() { + SYSCON.ahbclkctrl1().modify(|w| w.set_sct(true)); + } + }); + + // Choose the clock for PWM. + SYSCON.sctclksel().modify(|w| w.set_sel(SctclkselSel::ENUM_0X3)); + // For now, 96 MHz. + + // IOCON Setup + channel.pio().modify(|w| { + w.set_func(channel.pin_func()); + w.set_digimode(PioDigimode::DIGITAL); + w.set_slew(PioSlew::STANDARD); + w.set_mode(PioMode::INACTIVE); + w.set_od(PioOd::NORMAL); + }); + + Self::configure(output, &config); + REF_COUNT.fetch_add(1, Ordering::Relaxed); + Self { + _pin: channel.into(), + output, + } + } + + /// Create PWM driver with a single 'a' pin as output. + #[inline] + pub fn new_output( + output: Peri<'d, T>, + channel: Peri<'d, impl OutputChannelPin>, + config: Config, + ) -> Self { + Self::new_inner(output.number(), channel, config) + } + + /// Set the PWM config. + pub fn set_config(&mut self, config: &Config) { + Self::configure(self.output, config); + } + + fn configure(output_number: usize, config: &Config) { + // Stop and reset the counter + SCT0.ctrl().modify(|w| { + if config.phase_correct { + w.set_bidir_l(vals::Bidir::UP_DOWN); + } else { + w.set_bidir_l(vals::Bidir::UP); + } + w.set_halt_l(true); // halt the counter to make new changes + w.set_clrctr_l(true); // clear the counter + }); + // Divides clock by 1-255 + SYSCON.sctclkdiv().modify(|w| w.set_div(config.divider)); + + SCT0.config().modify(|w| { + w.set_unify(vals::Unify::UNIFIED_COUNTER); + w.set_clkmode(vals::Clkmode::SYSTEM_CLOCK_MODE); + w.set_noreload_l(true); + w.set_autolimit_l(true); + }); + + // Before setting the match registers, we have to make sure that `compare` is lower or equal to `top`, + // otherwise the counter will not reach the match and, therefore, no events will happen. + assert!(config.compare <= config.top); + + if TOP_VALUE.load(Ordering::Relaxed) == 0 { + // Match 0 will reset the timer using TOP value + SCT0.match_(0).modify(|w| { + w.set_matchn_l((config.top & 0xFFFF) as u16); + w.set_matchn_h((config.top >> 16) as u16); + }); + } else { + panic!("The top value cannot be changed after the initialization."); + } + // The actual matches that are used for event logic + SCT0.match_(output_number + 1).modify(|w| { + w.set_matchn_l((config.compare & 0xFFFF) as u16); + w.set_matchn_h((config.compare >> 16) as u16); + }); + + SCT0.match_(15).modify(|w| { + w.set_matchn_l(0); + w.set_matchn_h(0); + }); + + // Event configuration + critical_section::with(|_cs| { + // If it is already set, don't change + if SCT0.ev(0).ev_ctrl().read().matchsel() != 15 { + SCT0.ev(0).ev_ctrl().modify(|w| { + w.set_matchsel(15); + w.set_combmode(vals::Combmode::MATCH); + // STATE + statev, where STATE is a on-board variable. + w.set_stateld(vals::Stateld::ADD); + w.set_statev(0); + }); + } + }); + SCT0.ev(output_number + 1).ev_ctrl().modify(|w| { + w.set_matchsel((output_number + 1) as u8); + w.set_combmode(vals::Combmode::MATCH); + w.set_stateld(vals::Stateld::ADD); + // STATE + statev, where STATE is a on-board variable. + w.set_statev(0); + }); + + // Assign events to states + SCT0.ev(0).ev_state().modify(|w| w.set_statemskn(1 << 0)); + SCT0.ev(output_number + 1) + .ev_state() + .modify(|w| w.set_statemskn(1 << 0)); + // TODO(frihetselsker): optimize nxp-pac so that `set_clr` and `set_set` are turned into a bit array. + if config.invert { + // Low when event 0 is active + SCT0.out(output_number).out_clr().modify(|w| w.set_clr(1 << 0)); + // High when event `output_number + 1` is active + SCT0.out(output_number) + .out_set() + .modify(|w| w.set_set(1 << (output_number + 1))); + } else { + // High when event 0 is active + SCT0.out(output_number).out_set().modify(|w| w.set_set(1 << 0)); + // Low when event `output_number + 1` is active + SCT0.out(output_number) + .out_clr() + .modify(|w| w.set_clr(1 << (output_number + 1))); + } + + if config.phase_correct { + // Take into account the set matches and reverse their actions while counting back. + SCT0.outputdirctrl() + .modify(|w| w.set_setclr(output_number, vals::Setclr::L_REVERSED)); + } + + // State 0 by default + SCT0.state().modify(|w| w.set_state_l(0)); + // Remove halt and start the actual counter + SCT0.ctrl().modify(|w| { + w.set_halt_l(!config.enable); + }); + } + + /// Read PWM counter. + #[inline] + pub fn counter(&self) -> u32 { + SCT0.count().read().0 + } +} + +impl<'d> Drop for Pwm<'d> { + fn drop(&mut self) { + REF_COUNT.fetch_sub(1, Ordering::AcqRel); + if REF_COUNT.load(Ordering::Acquire) == 0 { + TOP_VALUE.store(0, Ordering::Release); + } + } +} + +trait SealedOutput { + /// Output number. + fn number(&self) -> usize; +} + +/// PWM Output. +#[allow(private_bounds)] +pub trait Output: PeripheralType + SealedOutput {} + +macro_rules! output { + ($name:ident, $num:expr) => { + impl SealedOutput for crate::peripherals::$name { + fn number(&self) -> usize { + $num + } + } + impl Output for crate::peripherals::$name {} + }; +} + +output!(PWM_OUTPUT0, 0); +output!(PWM_OUTPUT1, 1); +output!(PWM_OUTPUT2, 2); +output!(PWM_OUTPUT3, 3); +output!(PWM_OUTPUT4, 4); +output!(PWM_OUTPUT5, 5); +output!(PWM_OUTPUT6, 6); +output!(PWM_OUTPUT7, 7); +output!(PWM_OUTPUT8, 8); +output!(PWM_OUTPUT9, 9); + +/// PWM Output Channel. +pub trait OutputChannelPin: crate::gpio::Pin { + fn pin_func(&self) -> PioFunc; +} + +macro_rules! impl_pin { + ($pin:ident, $output:ident, $func:ident) => { + impl crate::pwm::inner::OutputChannelPin for crate::peripherals::$pin { + fn pin_func(&self) -> PioFunc { + PioFunc::$func + } + } + }; +} + +impl_pin!(PIO0_2, PWM_OUTPUT0, ALT3); +impl_pin!(PIO0_17, PWM_OUTPUT0, ALT4); +impl_pin!(PIO1_4, PWM_OUTPUT0, ALT4); +impl_pin!(PIO1_23, PWM_OUTPUT0, ALT2); + +impl_pin!(PIO0_3, PWM_OUTPUT1, ALT3); +impl_pin!(PIO0_18, PWM_OUTPUT1, ALT4); +impl_pin!(PIO1_8, PWM_OUTPUT1, ALT4); +impl_pin!(PIO1_24, PWM_OUTPUT1, ALT2); + +impl_pin!(PIO0_10, PWM_OUTPUT2, ALT5); +impl_pin!(PIO0_15, PWM_OUTPUT2, ALT4); +impl_pin!(PIO0_19, PWM_OUTPUT2, ALT4); +impl_pin!(PIO1_9, PWM_OUTPUT2, ALT4); +impl_pin!(PIO1_25, PWM_OUTPUT2, ALT2); + +impl_pin!(PIO0_22, PWM_OUTPUT3, ALT4); +impl_pin!(PIO0_31, PWM_OUTPUT3, ALT4); +impl_pin!(PIO1_10, PWM_OUTPUT3, ALT4); +impl_pin!(PIO1_26, PWM_OUTPUT3, ALT2); + +impl_pin!(PIO0_23, PWM_OUTPUT4, ALT4); +impl_pin!(PIO1_3, PWM_OUTPUT4, ALT4); +impl_pin!(PIO1_17, PWM_OUTPUT4, ALT4); + +impl_pin!(PIO0_26, PWM_OUTPUT5, ALT4); +impl_pin!(PIO1_18, PWM_OUTPUT5, ALT4); + +impl_pin!(PIO0_27, PWM_OUTPUT6, ALT4); +impl_pin!(PIO1_31, PWM_OUTPUT6, ALT4); + +impl_pin!(PIO0_28, PWM_OUTPUT7, ALT4); +impl_pin!(PIO1_19, PWM_OUTPUT7, ALT2); + +impl_pin!(PIO0_29, PWM_OUTPUT8, ALT4); + +impl_pin!(PIO0_30, PWM_OUTPUT9, ALT4); diff --git a/examples/lpc55s69/src/bin/pwm.rs b/examples/lpc55s69/src/bin/pwm.rs new file mode 100644 index 000000000..93b898b9d --- /dev/null +++ b/examples/lpc55s69/src/bin/pwm.rs @@ -0,0 +1,18 @@ +#![no_std] +#![no_main] + +use defmt::*; +use embassy_executor::Spawner; +use embassy_nxp::pwm::{Config, Pwm}; +use embassy_time::Timer; +use {defmt_rtt as _, panic_halt as _}; + +#[embassy_executor::main] +async fn main(_spawner: Spawner) { + let p = embassy_nxp::init(Default::default()); + let pwm = Pwm::new_output(p.PWM_OUTPUT1, p.PIO0_18, Config::new(1_000_000_000, 2_000_000_000)); + loop { + info!("Counter: {}", pwm.counter()); + Timer::after_millis(50).await; + } +} -- cgit From 5dac73f15bac10b097f51d941847a28bec36e97f Mon Sep 17 00:00:00 2001 From: Kat <187942808+northernpaws@users.noreply.github.com> Date: Wed, 22 Oct 2025 19:26:12 -0600 Subject: update stm32-fmc dependency version to 0.4.0 Fixes incompatibility issues using other libraries that rely on stm32-fmc 0.4.0 --- embassy-stm32/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/embassy-stm32/Cargo.toml b/embassy-stm32/Cargo.toml index 7c243b350..23e8a49d9 100644 --- a/embassy-stm32/Cargo.toml +++ b/embassy-stm32/Cargo.toml @@ -182,7 +182,7 @@ stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", ta vcell = "0.1.3" nb = "1.0.0" -stm32-fmc = "0.3.0" +stm32-fmc = "0.4.0" cfg-if = "1.0.0" embedded-io = { version = "0.6.0" } embedded-io-async = { version = "0.6.1" } -- cgit From 836d491a37094439f8bf3da3ceae075c8dbc221c Mon Sep 17 00:00:00 2001 From: Maarten de Vries Date: Thu, 23 Oct 2025 16:43:55 +0200 Subject: embassy-nrf: allow direct access to the `gpiote::InputChannel` input pin --- embassy-nrf/CHANGELOG.md | 1 + embassy-nrf/src/gpiote.rs | 5 +++++ 2 files changed, 6 insertions(+) diff --git a/embassy-nrf/CHANGELOG.md b/embassy-nrf/CHANGELOG.md index 3df7bfd4c..94fc58ca2 100644 --- a/embassy-nrf/CHANGELOG.md +++ b/embassy-nrf/CHANGELOG.md @@ -11,6 +11,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - added: Add basic RTC support for nRF54L - changed: apply trimming values from FICR.TRIMCNF on nrf53/54l - changed: do not panic on BufferedUarte overrun +- added: allow direct access to the input pin of `gpiote::InputChannel` ## 0.8.0 - 2025-09-30 diff --git a/embassy-nrf/src/gpiote.rs b/embassy-nrf/src/gpiote.rs index a490d5b60..61162b87f 100644 --- a/embassy-nrf/src/gpiote.rs +++ b/embassy-nrf/src/gpiote.rs @@ -259,6 +259,11 @@ impl<'d> InputChannel<'d> { .await; } + /// Get the associated input pin. + pub fn pin(&self) -> &Input<'_> { + &self.pin + } + /// Returns the IN event, for use with PPI. pub fn event_in(&self) -> Event<'d> { let g = regs(); -- cgit From 75ad0684f28ccb6b2a5b4772894e8c6a4f327299 Mon Sep 17 00:00:00 2001 From: Matthew Tran <0e4ef622@gmail.com> Date: Wed, 22 Oct 2025 18:59:34 -0500 Subject: nrf: use DETECTMODE_SEC in GPIOTE in secure mode DETECTMODE only applies to pins assigned to non-secure. --- embassy-nrf/CHANGELOG.md | 1 + embassy-nrf/src/gpiote.rs | 3 +++ 2 files changed, 4 insertions(+) diff --git a/embassy-nrf/CHANGELOG.md b/embassy-nrf/CHANGELOG.md index 94fc58ca2..0280e2730 100644 --- a/embassy-nrf/CHANGELOG.md +++ b/embassy-nrf/CHANGELOG.md @@ -12,6 +12,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - changed: apply trimming values from FICR.TRIMCNF on nrf53/54l - changed: do not panic on BufferedUarte overrun - added: allow direct access to the input pin of `gpiote::InputChannel` +- bugfix: use DETECTMODE_SEC in GPIOTE in secure mode ## 0.8.0 - 2025-09-30 diff --git a/embassy-nrf/src/gpiote.rs b/embassy-nrf/src/gpiote.rs index 61162b87f..3658657c0 100644 --- a/embassy-nrf/src/gpiote.rs +++ b/embassy-nrf/src/gpiote.rs @@ -77,6 +77,9 @@ pub(crate) fn init(irq_prio: crate::interrupt::Priority) { for &p in ports { // Enable latched detection + #[cfg(feature = "_s")] + p.detectmode_sec().write(|w| w.set_detectmode(Detectmode::LDETECT)); + #[cfg(not(feature = "_s"))] p.detectmode().write(|w| w.set_detectmode(Detectmode::LDETECT)); // Clear latch p.latch().write(|w| w.0 = 0xFFFFFFFF) -- cgit From 724edcaf70494316507af2d3bc7cdbcb2b3be06d Mon Sep 17 00:00:00 2001 From: Nicolas Mattia Date: Sun, 26 Oct 2025 11:37:05 +0100 Subject: rp: fix typo in Input interrupt comment --- embassy-rp/CHANGELOG.md | 1 + embassy-rp/src/gpio.rs | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/embassy-rp/CHANGELOG.md b/embassy-rp/CHANGELOG.md index e932bcaa3..a99d04aa4 100644 --- a/embassy-rp/CHANGELOG.md +++ b/embassy-rp/CHANGELOG.md @@ -8,6 +8,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## Unreleased - ReleaseDate +- Fix typo in interrupt comment - Add PIO SPI - Add PIO I2S input - Add PIO onewire parasite power strong pullup diff --git a/embassy-rp/src/gpio.rs b/embassy-rp/src/gpio.rs index c15e0e41b..154fc1585 100644 --- a/embassy-rp/src/gpio.rs +++ b/embassy-rp/src/gpio.rs @@ -300,7 +300,7 @@ impl<'d> InputFuture<'d> { // Each INTR register is divided into 8 groups, one group for each // pin, and each group consists of LEVEL_LOW, LEVEL_HIGH, EDGE_LOW, - // and EGDE_HIGH. + // and EDGE_HIGH. pin.int_proc() .inte((pin.pin() / 8) as usize) .write_set(|w| match level { -- cgit From e349ebb72c706c99dde34ba7b624aa9d1c25af39 Mon Sep 17 00:00:00 2001 From: usedhondacivic Date: Sun, 26 Oct 2025 18:00:51 -0700 Subject: cyw43-pio: core clock speed based pio program selection --- cyw43-pio/src/lib.rs | 109 +++++++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 92 insertions(+), 17 deletions(-) diff --git a/cyw43-pio/src/lib.rs b/cyw43-pio/src/lib.rs index 41ac6816d..51d8ec3ae 100644 --- a/cyw43-pio/src/lib.rs +++ b/cyw43-pio/src/lib.rs @@ -7,11 +7,13 @@ use core::slice; use cyw43::SpiBusCyw43; use embassy_rp::Peri; +use embassy_rp::clocks::clk_sys_freq; use embassy_rp::dma::Channel; use embassy_rp::gpio::{Drive, Level, Output, Pull, SlewRate}; use embassy_rp::pio::program::pio_asm; use embassy_rp::pio::{Common, Config, Direction, Instance, Irq, PioPin, ShiftDirection, StateMachine}; use fixed::FixedU32; +use fixed::traits::LosslessTryInto; use fixed::types::extra::U8; /// SPI comms driven by PIO. @@ -23,23 +25,24 @@ pub struct PioSpi<'d, PIO: Instance, const SM: usize, DMA: Channel> { wrap_target: u8, } -/// The default clock divider that works for Pico 1 and 2 W. As well as the RM2 on rp2040 devices. -/// same speed as pico-sdk, 62.5Mhz -/// This is actually the fastest we can go without overclocking. -/// According to data sheet, the theoretical maximum is 100Mhz Pio => 50Mhz SPI Freq. -/// However, the PIO uses a fractional divider, which works by introducing jitter when -/// the divider is not an integer. It does some clocks at 125mhz and others at 62.5mhz -/// so that it averages out to the desired frequency of 100mhz. The 125mhz clock cycles -/// violate the maximum from the data sheet. +/// Clock divider used for most applications +/// With default core clock configuration: +/// RP2350: 150Mhz / 2 = 75Mhz pio clock -> 37.5Mhz GSPI clock +/// RP2040: 133Mhz / 2 = 66.5Mhz pio clock -> 33.25Mhz GSPI clock pub const DEFAULT_CLOCK_DIVIDER: FixedU32 = FixedU32::from_bits(0x0200); -/// The overclock clock divider for the Pico 1 W. Does not work on any known RM2 devices. -/// 125mhz Pio => 62.5Mhz SPI Freq. 25% higher than theoretical maximum according to -/// data sheet, but seems to work fine. +/// Clock divider used to overclock the cyw43 +/// With default core clock configuration: +/// RP2350: 150Mhz / 1 = 150Mhz pio clock -> 75Mhz GSPI clock (50% greater that manufacturer +/// recommended 50Mhz) +/// RP2040: 133Mhz / 1 = 133Mhz pio clock -> 66.5Mhz GSPI clock (33% greater that manufacturer +/// recommended 50Mhz) pub const OVERCLOCK_CLOCK_DIVIDER: FixedU32 = FixedU32::from_bits(0x0100); -/// The clock divider for the RM2 module. Found to be needed for the Pimoroni Pico Plus 2 W, -/// Pico Plus 2 Non w with the RM2 breakout module, and the Pico 2 with the RM2 breakout module. +/// Clock divider used with the RM2 +/// With default core clock configuration: +/// RP2350: 150Mhz / 3 = 50Mhz pio clock -> 25Mhz GSPI clock +/// RP2040: 133Mhz / 3 = 44.33Mhz pio clock -> 22.16Mhz GSPI clock pub const RM2_CLOCK_DIVIDER: FixedU32 = FixedU32::from_bits(0x0300); impl<'d, PIO, const SM: usize, DMA> PioSpi<'d, PIO, SM, DMA> @@ -58,7 +61,40 @@ where clk: Peri<'d, impl PioPin>, dma: Peri<'d, DMA>, ) -> Self { - let loaded_program = if clock_divider < DEFAULT_CLOCK_DIVIDER { + let effective_pio_frequency = (clk_sys_freq() as f32 / clock_divider.to_num::()) as u32; + + #[cfg(feature = "defmt")] + defmt::trace!("Effective pio frequency: {}", effective_pio_frequency); + + // Non-integer pio clock dividers are achieved by introducing clock jitter resulting in a + // combination of long and short cycles. The long and short cycles average to achieve the + // requested clock speed. + // This can be a problem for peripherals that expect a consistent clock / have a clock + // speed upper bound that is violated by the short cycles. The cyw43 seems to handle the + // jitter well, but we emit a warning to recommend an integer divider anyway. + if let None = clock_divider.lossless_try_into() { + #[cfg(feature = "defmt")] + defmt::trace!( + "Configured clock divider is not a whole number. Some clock cycles may violate the maximum recommended GSPI speed. Use at your own risk." + ); + } + + // Different pio programs must be used for different pio clock speeds. + // The programs used below are based on the pico SDK: https://github.com/raspberrypi/pico-sdk/blob/master/src/rp2_common/pico_cyw43_driver/cyw43_bus_pio_spi.pio + // The clock speed cutoff for each program has been determined experimentally: + // > 100Mhz -> Overclock program + // [75Mhz, 100Mhz] -> High speed program + // [0, 75Mhz) -> Low speed program + let loaded_program = if effective_pio_frequency > 100_000_000 { + // Any frequency > 100Mhz is overclocking the chip (manufacturer recommends max 50Mhz GSPI + // clock) + // Example: + // * RP2040 @ 133Mhz (stock) with OVERCLOCK_CLOCK_DIVIDER (133MHz) + #[cfg(feature = "defmt")] + defmt::trace!( + "Configured clock divider results in a GSPI frequency greater than the manufacturer recommendation (50Mhz). Use at your own risk." + ); + let overclock_program = pio_asm!( ".side_set 1" @@ -69,7 +105,7 @@ where "jmp x-- lp side 1" // switch directions "set pindirs, 0 side 0" - "nop side 1" // necessary for clkdiv=1. + "nop side 1" "nop side 0" // read in y-1 bits "lp2:" @@ -83,8 +119,47 @@ where ".wrap" ); common.load_program(&overclock_program.program) + } else if effective_pio_frequency >= 75_000_000 { + // Experimentally determined cutoff. + // Notably includes the stock RP2350 configured with clk_div of 2 (150Mhz base clock / 2 = 75Mhz) + // but does not include stock RP2040 configured with clk_div of 2 (133Mhz base clock / 2 = 66.5Mhz) + // Example: + // * RP2350 @ 150Mhz (stock) with DEFAULT_CLOCK_DIVIDER (75Mhz) + // * RP2XXX @ 200Mhz with DEFAULT_CLOCK_DIVIDER (100Mhz) + #[cfg(feature = "defmt")] + defmt::trace!("Using high speed pio program."); + let high_speed_program = pio_asm!( + ".side_set 1" + + ".wrap_target" + // write out x-1 bits + "lp:" + "out pins, 1 side 0" + "jmp x-- lp side 1" + // switch directions + "set pindirs, 0 side 0" + "nop side 1" + // read in y-1 bits + "lp2:" + "in pins, 1 side 0" + "jmp y-- lp2 side 1" + + // wait for event and irq host + "wait 1 pin 0 side 0" + "irq 0 side 0" + + ".wrap" + ); + common.load_program(&high_speed_program.program) } else { - let default_program = pio_asm!( + // Low speed + // Examples: + // * RP2040 @ 133Mhz (stock) with DEFAULT_CLOCK_DIVIDER (66.5Mhz) + // * RP2040 @ 133Mhz (stock) with RM2_CLOCK_DIVIDER (44.3Mhz) + // * RP2350 @ 150Mhz (stock) with RM2_CLOCK_DIVIDER (50Mhz) + #[cfg(feature = "defmt")] + defmt::trace!("Using low speed pio program."); + let low_speed_program = pio_asm!( ".side_set 1" ".wrap_target" @@ -106,7 +181,7 @@ where ".wrap" ); - common.load_program(&default_program.program) + common.load_program(&low_speed_program.program) }; let mut pin_io: embassy_rp::pio::Pin = common.make_pio_pin(dio); -- cgit From 4d869e69730b997ff6d7c162cf1f5f3ffa868caa Mon Sep 17 00:00:00 2001 From: usedhondacivic Date: Sun, 26 Oct 2025 19:59:35 -0700 Subject: Update CHANGELOG --- cyw43-pio/CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cyw43-pio/CHANGELOG.md b/cyw43-pio/CHANGELOG.md index ec38989e3..584df6689 100644 --- a/cyw43-pio/CHANGELOG.md +++ b/cyw43-pio/CHANGELOG.md @@ -7,7 +7,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## Unreleased - ReleaseDate - +- Select pio program based on core clock speed #4792 ## 0.8.0 - 2025-08-28 - Bump cyw43 version -- cgit From a863aadc643d84707815e5c0f4564f2195809fec Mon Sep 17 00:00:00 2001 From: usedhondacivic Date: Sun, 26 Oct 2025 20:03:57 -0700 Subject: Fix build --- cyw43-pio/CHANGELOG.md | 2 ++ cyw43-pio/src/lib.rs | 7 +++---- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/cyw43-pio/CHANGELOG.md b/cyw43-pio/CHANGELOG.md index 584df6689..c2d18919c 100644 --- a/cyw43-pio/CHANGELOG.md +++ b/cyw43-pio/CHANGELOG.md @@ -7,7 +7,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## Unreleased - ReleaseDate + - Select pio program based on core clock speed #4792 + ## 0.8.0 - 2025-08-28 - Bump cyw43 version diff --git a/cyw43-pio/src/lib.rs b/cyw43-pio/src/lib.rs index 51d8ec3ae..c8715e662 100644 --- a/cyw43-pio/src/lib.rs +++ b/cyw43-pio/src/lib.rs @@ -13,7 +13,6 @@ use embassy_rp::gpio::{Drive, Level, Output, Pull, SlewRate}; use embassy_rp::pio::program::pio_asm; use embassy_rp::pio::{Common, Config, Direction, Instance, Irq, PioPin, ShiftDirection, StateMachine}; use fixed::FixedU32; -use fixed::traits::LosslessTryInto; use fixed::types::extra::U8; /// SPI comms driven by PIO. @@ -64,7 +63,7 @@ where let effective_pio_frequency = (clk_sys_freq() as f32 / clock_divider.to_num::()) as u32; #[cfg(feature = "defmt")] - defmt::trace!("Effective pio frequency: {}", effective_pio_frequency); + defmt::trace!("Effective pio frequency: {}Hz", effective_pio_frequency); // Non-integer pio clock dividers are achieved by introducing clock jitter resulting in a // combination of long and short cycles. The long and short cycles average to achieve the @@ -72,14 +71,14 @@ where // This can be a problem for peripherals that expect a consistent clock / have a clock // speed upper bound that is violated by the short cycles. The cyw43 seems to handle the // jitter well, but we emit a warning to recommend an integer divider anyway. - if let None = clock_divider.lossless_try_into() { + if clock_divider.frac() != FixedU32::::ZERO { #[cfg(feature = "defmt")] defmt::trace!( "Configured clock divider is not a whole number. Some clock cycles may violate the maximum recommended GSPI speed. Use at your own risk." ); } - // Different pio programs must be used for different pio clock speeds. + // Different pio programs must be used for different pio clock speeds. // The programs used below are based on the pico SDK: https://github.com/raspberrypi/pico-sdk/blob/master/src/rp2_common/pico_cyw43_driver/cyw43_bus_pio_spi.pio // The clock speed cutoff for each program has been determined experimentally: // > 100Mhz -> Overclock program -- cgit From e86c2b3b1c41c710acd34f6c85243c8bd5b5150d Mon Sep 17 00:00:00 2001 From: Gordon Tyler Date: Mon, 27 Oct 2025 10:41:33 -0400 Subject: mspm0: group irq handlers must check for NO_INTR (#4785) In the case of spurious interrupts, the interrupt group's STAT register may be set to NO_INTR, which must be checked before attempting to calculate the interrupt index from the STAT value. --- embassy-mspm0/build.rs | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/embassy-mspm0/build.rs b/embassy-mspm0/build.rs index 1d118ad66..6264c9177 100644 --- a/embassy-mspm0/build.rs +++ b/embassy-mspm0/build.rs @@ -194,8 +194,15 @@ fn generate_groups() -> TokenStream { use crate::pac::#group_enum; let group = crate::pac::CPUSS.int_group(#group_number); - // MUST subtract by 1 since 0 is NO_INTR - let iidx = group.iidx().read().stat().to_bits() - 1; + let stat = group.iidx().read().stat(); + + // check for spurious interrupts + if stat == crate::pac::cpuss::vals::Iidx::NO_INTR { + return; + } + + // MUST subtract by 1 because Iidx::INT0=1 + let iidx = stat.to_bits() - 1; let Ok(group) = #group_enum::try_from(iidx as u8) else { return; -- cgit From 3923f881c63a483c1593cc345079581ffcce5ff1 Mon Sep 17 00:00:00 2001 From: Gordon Tyler Date: Mon, 27 Oct 2025 10:45:47 -0400 Subject: Update changelog --- embassy-mspm0/CHANGELOG.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/embassy-mspm0/CHANGELOG.md b/embassy-mspm0/CHANGELOG.md index fcb0f9dbd..d9910a7ab 100644 --- a/embassy-mspm0/CHANGELOG.md +++ b/embassy-mspm0/CHANGELOG.md @@ -7,7 +7,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## Unreleased - ReleaseDate - + - feat: Add I2C Controller (blocking & async) + examples for mspm0l1306, mspm0g3507 (tested MCUs) (#4435) - fix gpio interrupt not being set for mspm0l110x - feat: Add window watchdog implementation based on WWDT0, WWDT1 peripherals (#4574) @@ -17,3 +17,4 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - fix: add MSPM0C1106 to build test matrix - feat: add MSPM0H3216 support - feat: Add i2c target implementation (#4605) +- fix: group irq handlers must check for NO_INTR (#4785) -- cgit From 7ef9a6453a0a2a286741d47fcb99170d802f7d7d Mon Sep 17 00:00:00 2001 From: Rob Wells Date: Mon, 27 Oct 2025 15:23:54 +0000 Subject: embassy-rp: doc comment spelling pass All changes but one are to documentation comments, and one to an ordinary comment. --- embassy-rp/CHANGELOG.md | 2 +- embassy-rp/src/block.rs | 4 ++-- embassy-rp/src/clocks.rs | 2 +- embassy-rp/src/i2c_slave.rs | 4 ++-- embassy-rp/src/multicore.rs | 2 +- embassy-rp/src/pio/mod.rs | 2 +- embassy-rp/src/pio_programs/i2s.rs | 18 +++++++++--------- embassy-rp/src/pio_programs/pwm.rs | 2 +- embassy-rp/src/pio_programs/spi.rs | 4 ++-- embassy-rp/src/pio_programs/uart.rs | 2 +- embassy-rp/src/rom_data/rp2040.rs | 2 +- embassy-rp/src/rtc/mod.rs | 2 +- embassy-rp/src/spi.rs | 2 +- embassy-rp/src/uart/mod.rs | 2 +- 14 files changed, 25 insertions(+), 25 deletions(-) diff --git a/embassy-rp/CHANGELOG.md b/embassy-rp/CHANGELOG.md index a99d04aa4..57ec13658 100644 --- a/embassy-rp/CHANGELOG.md +++ b/embassy-rp/CHANGELOG.md @@ -8,7 +8,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## Unreleased - ReleaseDate -- Fix typo in interrupt comment +- Fix several minor typos in documentation - Add PIO SPI - Add PIO I2S input - Add PIO onewire parasite power strong pullup diff --git a/embassy-rp/src/block.rs b/embassy-rp/src/block.rs index a3e1ad925..745883b83 100644 --- a/embassy-rp/src/block.rs +++ b/embassy-rp/src/block.rs @@ -240,7 +240,7 @@ impl UnpartitionedSpace { } } - /// Create a new unpartition space from run-time values. + /// Create a new unpartitioned space from run-time values. /// /// Get these from the ROM function `get_partition_table_info` with an argument of `PT_INFO`. pub const fn from_raw(permissions_and_location: u32, permissions_and_flags: u32) -> Self { @@ -714,7 +714,7 @@ impl PartitionTableBlock { new_table } - /// Add a a SHA256 hash of the Block + /// Add a SHA256 hash of the Block /// /// Adds a `HASH_DEF` covering all the previous items in the Block, and a /// `HASH_VALUE` with a SHA-256 hash of them. diff --git a/embassy-rp/src/clocks.rs b/embassy-rp/src/clocks.rs index 56892d7a2..8bfb5129a 100644 --- a/embassy-rp/src/clocks.rs +++ b/embassy-rp/src/clocks.rs @@ -267,7 +267,7 @@ impl CoreVoltage { } } -/// CLock configuration. +/// Clock configuration. #[non_exhaustive] pub struct ClockConfig { /// Ring oscillator configuration. diff --git a/embassy-rp/src/i2c_slave.rs b/embassy-rp/src/i2c_slave.rs index 770087bc8..0853709df 100644 --- a/embassy-rp/src/i2c_slave.rs +++ b/embassy-rp/src/i2c_slave.rs @@ -52,7 +52,7 @@ pub enum ReadStatus { Done, /// Transaction Incomplete, controller trying to read more bytes than were provided NeedMoreBytes, - /// Transaction Complere, but controller stopped reading bytes before we ran out + /// Transaction Complete, but controller stopped reading bytes before we ran out LeftoverBytes(u16), } @@ -240,7 +240,7 @@ impl<'d, T: Instance> I2cSlave<'d, T> { if p.ic_rxflr().read().rxflr() > 0 || me.pending_byte.is_some() { me.drain_fifo(buffer, &mut len); - // we're recieving data, set rx fifo watermark to 12 bytes (3/4 full) to reduce interrupt noise + // we're receiving data, set rx fifo watermark to 12 bytes (3/4 full) to reduce interrupt noise p.ic_rx_tl().write(|w| w.set_rx_tl(11)); } diff --git a/embassy-rp/src/multicore.rs b/embassy-rp/src/multicore.rs index 3b120e349..572d8db91 100644 --- a/embassy-rp/src/multicore.rs +++ b/embassy-rp/src/multicore.rs @@ -58,7 +58,7 @@ const PAUSE_TOKEN: u32 = 0xDEADBEEF; const RESUME_TOKEN: u32 = !0xDEADBEEF; static IS_CORE1_INIT: AtomicBool = AtomicBool::new(false); -/// Represents a partiticular CPU core (SIO_CPUID) +/// Represents a particular CPU core (SIO_CPUID) #[derive(Debug, PartialEq, Eq, Clone, Copy, Hash)] #[cfg_attr(feature = "defmt", derive(defmt::Format))] #[repr(u8)] diff --git a/embassy-rp/src/pio/mod.rs b/embassy-rp/src/pio/mod.rs index 38ee1f97c..92b2c603e 100644 --- a/embassy-rp/src/pio/mod.rs +++ b/embassy-rp/src/pio/mod.rs @@ -62,7 +62,7 @@ pub enum FifoJoin { #[cfg(feature = "_rp235x")] RxAsControl, /// FJOIN_RX_PUT | FJOIN_RX_GET: RX can be used as a scratch register, - /// not accesible from the CPU + /// not accessible from the CPU #[cfg(feature = "_rp235x")] PioScratch, } diff --git a/embassy-rp/src/pio_programs/i2s.rs b/embassy-rp/src/pio_programs/i2s.rs index 7e5f68ad6..5c49beecb 100644 --- a/embassy-rp/src/pio_programs/i2s.rs +++ b/embassy-rp/src/pio_programs/i2s.rs @@ -1,4 +1,4 @@ -//! Pio backed I2s output and output drivers +//! Pio backed I2S output and output drivers use fixed::traits::ToFixed; @@ -9,7 +9,7 @@ use crate::pio::{ Common, Config, Direction, FifoJoin, Instance, LoadedProgram, PioPin, ShiftConfig, ShiftDirection, StateMachine, }; -/// This struct represents an i2s receiver & controller driver program +/// This struct represents an I2S receiver & controller driver program pub struct PioI2sInProgram<'d, PIO: Instance> { prg: LoadedProgram<'d, PIO>, } @@ -35,7 +35,7 @@ impl<'d, PIO: Instance> PioI2sInProgram<'d, PIO> { } } -/// Pio backed I2s input driver +/// Pio backed I2S input driver pub struct PioI2sIn<'d, P: Instance, const S: usize> { dma: Peri<'d, AnyChannel>, sm: StateMachine<'d, P, S>, @@ -50,7 +50,7 @@ impl<'d, P: Instance, const S: usize> PioI2sIn<'d, P, S> { // Whether or not to use the MCU's internal pull-down resistor, as the // Pico 2 is known to have problems with the inbuilt pulldowns, many // opt to just use an external pull down resistor to meet requirements of common - // i2s microphones such as the INMP441 + // I2S microphones such as the INMP441 data_pulldown: bool, data_pin: Peri<'d, impl PioPin>, bit_clock_pin: Peri<'d, impl PioPin>, @@ -90,13 +90,13 @@ impl<'d, P: Instance, const S: usize> PioI2sIn<'d, P, S> { Self { dma: dma.into(), sm } } - /// Return an in-prograss dma transfer future. Awaiting it will guarentee a complete transfer. + /// Return an in-progress dma transfer future. Awaiting it will guarantee a complete transfer. pub fn read<'b>(&'b mut self, buff: &'b mut [u32]) -> Transfer<'b, AnyChannel> { self.sm.rx().dma_pull(self.dma.reborrow(), buff, false) } } -/// This struct represents an i2s output driver program +/// 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. @@ -128,14 +128,14 @@ impl<'d, PIO: Instance> PioI2sOutProgram<'d, PIO> { } } -/// Pio backed I2s output driver +/// Pio backed I2S output driver pub struct PioI2sOut<'d, P: Instance, const S: usize> { dma: Peri<'d, AnyChannel>, sm: StateMachine<'d, P, S>, } impl<'d, P: Instance, const S: usize> PioI2sOut<'d, P, S> { - /// Configure a state machine to output I2s + /// Configure a state machine to output I2S pub fn new( common: &mut Common<'d, P>, mut sm: StateMachine<'d, P, S>, @@ -179,7 +179,7 @@ impl<'d, P: Instance, const S: usize> PioI2sOut<'d, P, S> { Self { dma: dma.into(), sm } } - /// Return an in-prograss dma transfer future. Awaiting it will guarentee a complete transfer. + /// Return an in-progress dma transfer future. Awaiting it will guarantee a complete transfer. pub fn write<'b>(&'b mut self, buff: &'b [u32]) -> Transfer<'b, AnyChannel> { self.sm.tx().dma_push(self.dma.reborrow(), buff, false) } diff --git a/embassy-rp/src/pio_programs/pwm.rs b/embassy-rp/src/pio_programs/pwm.rs index ba06bb3c1..e4ad4a6f0 100644 --- a/embassy-rp/src/pio_programs/pwm.rs +++ b/embassy-rp/src/pio_programs/pwm.rs @@ -67,7 +67,7 @@ impl<'d, T: Instance, const SM: usize> PioPwm<'d, T, SM> { Self { sm, pin } } - /// Enable's the PIO program, continuing the wave generation from the PIO program. + /// Enables the PIO program, continuing the wave generation from the PIO program. pub fn start(&mut self) { self.sm.set_enable(true); } diff --git a/embassy-rp/src/pio_programs/spi.rs b/embassy-rp/src/pio_programs/spi.rs index b10fc6628..765ffaa06 100644 --- a/embassy-rp/src/pio_programs/spi.rs +++ b/embassy-rp/src/pio_programs/spi.rs @@ -1,4 +1,4 @@ -//! PIO backed SPi drivers +//! PIO backed SPI drivers use core::marker::PhantomData; @@ -83,7 +83,7 @@ pub enum Error { // No errors for now } -/// PIO based Spi driver. +/// PIO based SPI driver. /// Unlike other PIO programs, the PIO SPI driver owns and holds a reference to /// the PIO memory it uses. This is so that it can be reconfigured at runtime if /// desired. diff --git a/embassy-rp/src/pio_programs/uart.rs b/embassy-rp/src/pio_programs/uart.rs index 444efb5db..d59596dd1 100644 --- a/embassy-rp/src/pio_programs/uart.rs +++ b/embassy-rp/src/pio_programs/uart.rs @@ -130,7 +130,7 @@ impl<'d, PIO: Instance> PioUartRxProgram<'d, PIO> { } } -/// PIO backed Uart reciever +/// PIO backed Uart receiver pub struct PioUartRx<'d, PIO: Instance, const SM: usize> { sm_rx: StateMachine<'d, PIO, SM>, } diff --git a/embassy-rp/src/rom_data/rp2040.rs b/embassy-rp/src/rom_data/rp2040.rs index 5a74eddd6..27a8d8981 100644 --- a/embassy-rp/src/rom_data/rp2040.rs +++ b/embassy-rp/src/rom_data/rp2040.rs @@ -30,7 +30,7 @@ const DATA_TABLE: *const u16 = 0x0000_0016 as _; /// Address of the version number of the ROM. const VERSION_NUMBER: *const u8 = 0x0000_0013 as _; -/// Retrive rom content from a table using a code. +/// Retrieve rom content from a table using a code. fn rom_table_lookup(table: *const u16, tag: RomFnTableCode) -> T { unsafe { let rom_table_lookup_ptr: *const u32 = rom_hword_as_ptr(ROM_TABLE_LOOKUP_PTR); diff --git a/embassy-rp/src/rtc/mod.rs b/embassy-rp/src/rtc/mod.rs index 68fb3b765..054572903 100644 --- a/embassy-rp/src/rtc/mod.rs +++ b/embassy-rp/src/rtc/mod.rs @@ -47,7 +47,7 @@ impl<'d, T: Instance> Rtc<'d, T> { Self { inner } } - /// Enable or disable the leap year check. The rp2040 chip will always add a Feb 29th on every year that is divisable by 4, but this may be incorrect (e.g. on century years). This function allows you to disable this check. + /// Enable or disable the leap year check. The rp2040 chip will always add a Feb 29th on every year that is divisible by 4, but this may be incorrect (e.g. on century years). This function allows you to disable this check. /// /// Leap year checking is enabled by default. pub fn set_leap_year_check(&mut self, leap_year_check_enabled: bool) { diff --git a/embassy-rp/src/spi.rs b/embassy-rp/src/spi.rs index 559b3b909..d9410e78d 100644 --- a/embassy-rp/src/spi.rs +++ b/embassy-rp/src/spi.rs @@ -157,7 +157,7 @@ impl<'d, T: Instance, M: Mode> Spi<'d, T, M> { /// Private function to apply SPI configuration (phase, polarity, frequency) settings. /// - /// Driver should be disabled before making changes and reenabled after the modifications + /// Driver should be disabled before making changes and re-enabled after the modifications /// are applied. fn apply_config(inner: &Peri<'d, T>, config: &Config) { let p = inner.regs(); diff --git a/embassy-rp/src/uart/mod.rs b/embassy-rp/src/uart/mod.rs index 43187df2d..8be87a5d2 100644 --- a/embassy-rp/src/uart/mod.rs +++ b/embassy-rp/src/uart/mod.rs @@ -315,7 +315,7 @@ impl<'d, M: Mode> UartRx<'d, M> { } /// Returns Ok(len) if no errors occurred. Returns Err((len, err)) if an error was - /// encountered. in both cases, `len` is the number of *good* bytes copied into + /// encountered. In both cases, `len` is the number of *good* bytes copied into /// `buffer`. fn drain_fifo(&mut self, buffer: &mut [u8]) -> Result { let r = self.info.regs; -- cgit From e282662f2408455d5f7e53c010c3bf0d8eeb99aa Mon Sep 17 00:00:00 2001 From: xoviat Date: Mon, 27 Oct 2025 21:10:19 -0500 Subject: timer: add output compare values --- embassy-stm32/CHANGELOG.md | 1 + embassy-stm32/src/timer/low_level.rs | 69 ++++++++++++++++++++++++++++++------ 2 files changed, 60 insertions(+), 10 deletions(-) diff --git a/embassy-stm32/CHANGELOG.md b/embassy-stm32/CHANGELOG.md index 9848daf49..000d215b7 100644 --- a/embassy-stm32/CHANGELOG.md +++ b/embassy-stm32/CHANGELOG.md @@ -35,6 +35,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - feat: stm32/usart: add `eager_reads` option to control if buffered readers return as soon as possible or after more data is available ([#4668](https://github.com/embassy-rs/embassy/pull/4668)) - feat: stm32/usart: add `de_assertion_time` and `de_deassertion_time` config options - change: stm32/uart: BufferedUartRx now returns all available bytes from the internal buffer +- change: timer: added output compare values ## 0.4.0 - 2025-08-26 diff --git a/embassy-stm32/src/timer/low_level.rs b/embassy-stm32/src/timer/low_level.rs index ac039bb0d..7c02e7e62 100644 --- a/embassy-stm32/src/timer/low_level.rs +++ b/embassy-stm32/src/timer/low_level.rs @@ -143,20 +143,69 @@ pub enum OutputCompareMode { /// TIMx_CNTTIMx_CCRx else inactive. PwmMode2, - // TODO: there's more modes here depending on the chip family. + + #[cfg(timer_v2)] + /// In up-counting mode, the channel is active until a trigger + /// event is detected (on tim_trgi signal). Then, a comparison is performed as in PWM + /// mode 1 and the channels becomes active again at the next update. In down-counting + /// mode, the channel is inactive until a trigger event is detected (on tim_trgi signal). + /// Then, a comparison is performed as in PWM mode 1 and the channels becomes + /// inactive again at the next update. + OnePulseMode1, + + #[cfg(timer_v2)] + /// In up-counting mode, the channel is inactive until a + /// trigger event is detected (on tim_trgi signal). Then, a comparison is performed as in + /// PWM mode 2 and the channels becomes inactive again at the next update. In down + /// counting mode, the channel is active until a trigger event is detected (on tim_trgi + /// signal). Then, a comparison is performed as in PWM mode 1 and the channels + /// becomes active again at the next update. + OnePulseMode2, + + #[cfg(timer_v2)] + /// Combined PWM mode 1 - tim_oc1ref has the same behavior as in PWM mode 1. + /// tim_oc1refc is the logical OR between tim_oc1ref and tim_oc2ref. + CombinedPwmMode1, + + #[cfg(timer_v2)] + /// Combined PWM mode 2 - tim_oc1ref has the same behavior as in PWM mode 2. + /// tim_oc1refc is the logical AND between tim_oc1ref and tim_oc2ref. + CombinedPwmMode2, + + #[cfg(timer_v2)] + /// tim_oc1ref has the same behavior as in PWM mode 1. tim_oc1refc outputs tim_oc1ref + /// when the counter is counting up, tim_oc2ref when it is counting down. + AsymmetricPwmMode1, + + #[cfg(timer_v2)] + /// tim_oc1ref has the same behavior as in PWM mode 2. tim_oc1refc outputs tim_oc1ref + /// when the counter is counting up, tim_oc2ref when it is counting down. + AsymmetricPwmMode2, } -impl From for stm32_metapac::timer::vals::Ocm { +impl From for crate::pac::timer::vals::Ocm { fn from(mode: OutputCompareMode) -> Self { match mode { - OutputCompareMode::Frozen => stm32_metapac::timer::vals::Ocm::FROZEN, - OutputCompareMode::ActiveOnMatch => stm32_metapac::timer::vals::Ocm::ACTIVE_ON_MATCH, - OutputCompareMode::InactiveOnMatch => stm32_metapac::timer::vals::Ocm::INACTIVE_ON_MATCH, - OutputCompareMode::Toggle => stm32_metapac::timer::vals::Ocm::TOGGLE, - OutputCompareMode::ForceInactive => stm32_metapac::timer::vals::Ocm::FORCE_INACTIVE, - OutputCompareMode::ForceActive => stm32_metapac::timer::vals::Ocm::FORCE_ACTIVE, - OutputCompareMode::PwmMode1 => stm32_metapac::timer::vals::Ocm::PWM_MODE1, - OutputCompareMode::PwmMode2 => stm32_metapac::timer::vals::Ocm::PWM_MODE2, + OutputCompareMode::Frozen => crate::pac::timer::vals::Ocm::FROZEN, + OutputCompareMode::ActiveOnMatch => crate::pac::timer::vals::Ocm::ACTIVE_ON_MATCH, + OutputCompareMode::InactiveOnMatch => crate::pac::timer::vals::Ocm::INACTIVE_ON_MATCH, + OutputCompareMode::Toggle => crate::pac::timer::vals::Ocm::TOGGLE, + OutputCompareMode::ForceInactive => crate::pac::timer::vals::Ocm::FORCE_INACTIVE, + OutputCompareMode::ForceActive => crate::pac::timer::vals::Ocm::FORCE_ACTIVE, + OutputCompareMode::PwmMode1 => crate::pac::timer::vals::Ocm::PWM_MODE1, + OutputCompareMode::PwmMode2 => crate::pac::timer::vals::Ocm::PWM_MODE2, + #[cfg(timer_v2)] + OutputCompareMode::OnePulseMode1 => crate::pac::timer::vals::Ocm::RETRIGERRABLE_OPM_MODE_1, + #[cfg(timer_v2)] + OutputCompareMode::OnePulseMode2 => crate::pac::timer::vals::Ocm::RETRIGERRABLE_OPM_MODE_2, + #[cfg(timer_v2)] + OutputCompareMode::CombinedPwmMode1 => crate::pac::timer::vals::Ocm::COMBINED_PWM_MODE_1, + #[cfg(timer_v2)] + OutputCompareMode::CombinedPwmMode2 => crate::pac::timer::vals::Ocm::COMBINED_PWM_MODE_2, + #[cfg(timer_v2)] + OutputCompareMode::AsymmetricPwmMode1 => crate::pac::timer::vals::Ocm::ASYMMETRIC_PWM_MODE_1, + #[cfg(timer_v2)] + OutputCompareMode::AsymmetricPwmMode2 => crate::pac::timer::vals::Ocm::ASYMMETRIC_PWM_MODE_2, } } } -- cgit From de5760cc81a00966c61d668c41f6e3e4709f0283 Mon Sep 17 00:00:00 2001 From: Ulf Lilleengen Date: Tue, 14 Oct 2025 13:23:50 +0200 Subject: feat: improve nrf54 support using new nrf-pac * Update nrf-pac to version that modifies nrf52 register layout to match nrf54 to reduce the amount of cfg needed for nrf54 support. * Make the following peripherals available on nrf54: twim, twis, spim, spis, uart, buffered uarte, dppi, gpiote, pwm, saadc * Add examples tested on the nrf54 dk Some code is based on or copied from other pull requests, modified to match the new nrf-pac layout. Co-authored-by: Dmitry Tarnyagin --- embassy-net-nrf91/CHANGELOG.md | 2 + embassy-net-nrf91/Cargo.toml | 2 +- embassy-nrf/CHANGELOG.md | 2 + embassy-nrf/Cargo.toml | 21 +- embassy-nrf/src/buffered_uarte.rs | 951 -------------------------- embassy-nrf/src/buffered_uarte/mod.rs | 14 + embassy-nrf/src/buffered_uarte/v1.rs | 951 ++++++++++++++++++++++++++ embassy-nrf/src/buffered_uarte/v2.rs | 687 +++++++++++++++++++ embassy-nrf/src/chips/nrf51.rs | 5 + embassy-nrf/src/chips/nrf52805.rs | 51 +- embassy-nrf/src/chips/nrf52810.rs | 71 +- embassy-nrf/src/chips/nrf52811.rs | 71 +- embassy-nrf/src/chips/nrf52820.rs | 71 +- embassy-nrf/src/chips/nrf52832.rs | 71 +- embassy-nrf/src/chips/nrf52833.rs | 71 +- embassy-nrf/src/chips/nrf52840.rs | 71 +- embassy-nrf/src/chips/nrf5340_app.rs | 71 +- embassy-nrf/src/chips/nrf5340_net.rs | 71 +- embassy-nrf/src/chips/nrf54l15_app.rs | 208 +++++- embassy-nrf/src/chips/nrf9120.rs | 39 +- embassy-nrf/src/chips/nrf9160.rs | 39 +- embassy-nrf/src/gpio.rs | 2 - embassy-nrf/src/gpiote.rs | 431 +++++++++--- embassy-nrf/src/lib.rs | 12 - embassy-nrf/src/ppi/dppi.rs | 11 +- embassy-nrf/src/ppi/mod.rs | 119 +++- embassy-nrf/src/pwm.rs | 59 +- embassy-nrf/src/saadc.rs | 247 ++++++- embassy-nrf/src/spim.rs | 163 ++++- embassy-nrf/src/spis.rs | 16 +- embassy-nrf/src/twim.rs | 44 +- embassy-nrf/src/twis.rs | 44 +- embassy-nrf/src/uarte.rs | 162 +++-- examples/nrf52840/src/bin/egu.rs | 15 +- examples/nrf52840/src/bin/gpiote_channel.rs | 26 +- examples/nrf52840/src/bin/ppi.rs | 34 +- examples/nrf52840/src/bin/pwm_sequence_ppi.rs | 14 +- examples/nrf5340/src/bin/gpiote_channel.rs | 26 +- examples/nrf54l15/Cargo.toml | 5 + examples/nrf54l15/src/bin/buffered_uart.rs | 49 ++ examples/nrf54l15/src/bin/gpiote_channel.rs | 49 ++ examples/nrf54l15/src/bin/gpiote_port.rs | 33 + examples/nrf54l15/src/bin/pwm.rs | 86 +++ examples/nrf54l15/src/bin/saadc.rs | 28 + examples/nrf54l15/src/bin/spim.rs | 72 ++ examples/nrf54l15/src/bin/twim.rs | 37 + examples/nrf54l15/src/bin/twis.rs | 47 ++ examples/nrf54l15/src/bin/uart.rs | 37 + tests/nrf/.cargo/config.toml | 4 +- tests/nrf/src/bin/buffered_uart_spam.rs | 10 +- 50 files changed, 3774 insertions(+), 1648 deletions(-) delete mode 100644 embassy-nrf/src/buffered_uarte.rs create mode 100644 embassy-nrf/src/buffered_uarte/mod.rs create mode 100644 embassy-nrf/src/buffered_uarte/v1.rs create mode 100644 embassy-nrf/src/buffered_uarte/v2.rs create mode 100644 examples/nrf54l15/src/bin/buffered_uart.rs create mode 100644 examples/nrf54l15/src/bin/gpiote_channel.rs create mode 100644 examples/nrf54l15/src/bin/gpiote_port.rs create mode 100644 examples/nrf54l15/src/bin/pwm.rs create mode 100644 examples/nrf54l15/src/bin/saadc.rs create mode 100644 examples/nrf54l15/src/bin/spim.rs create mode 100644 examples/nrf54l15/src/bin/twim.rs create mode 100644 examples/nrf54l15/src/bin/twis.rs create mode 100644 examples/nrf54l15/src/bin/uart.rs diff --git a/embassy-net-nrf91/CHANGELOG.md b/embassy-net-nrf91/CHANGELOG.md index 52cbf5ef3..11974ac04 100644 --- a/embassy-net-nrf91/CHANGELOG.md +++ b/embassy-net-nrf91/CHANGELOG.md @@ -8,6 +8,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## Unreleased - ReleaseDate +- changed: updated to nrf-pac with nrf52/nrf53/nrf91 register layout more similar to nrf54 + ## 0.1.1 - 2025-08-14 - First release with changelog. diff --git a/embassy-net-nrf91/Cargo.toml b/embassy-net-nrf91/Cargo.toml index ecb10246a..75b7aeeb2 100644 --- a/embassy-net-nrf91/Cargo.toml +++ b/embassy-net-nrf91/Cargo.toml @@ -18,7 +18,7 @@ log = ["dep:log"] defmt = { version = "1.0.1", optional = true } log = { version = "0.4.14", optional = true } -nrf-pac = "0.1.0" +nrf-pac = { version = "0.1.0", git = "https://github.com/embassy-rs/nrf-pac.git", rev = "58198c23bce72edc10b4e1656d1b54441fc74e7c" } cortex-m = "0.7.7" embassy-time = { version = "0.5.0", path = "../embassy-time" } diff --git a/embassy-nrf/CHANGELOG.md b/embassy-nrf/CHANGELOG.md index 89adaf2da..c23613f19 100644 --- a/embassy-nrf/CHANGELOG.md +++ b/embassy-nrf/CHANGELOG.md @@ -17,6 +17,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - changed: allow configuring the PWM peripheral in the constructor of `SimplePwm` - changed: support setting duty cycles with inverted polarity in `SimplePwm` - added: support setting the duty cycles of all channels at once in `SimplePwm` +- changed: updated to nrf-pac with nrf52/nrf53/nrf91 register layout more similar to nrf54 +- added: support for nrf54l peripherals: uart, gpiote, twim, twis, spim, spis, dppi, pwm, saadc ## 0.8.0 - 2025-09-30 diff --git a/embassy-nrf/Cargo.toml b/embassy-nrf/Cargo.toml index 28f137d5c..08f4b280b 100644 --- a/embassy-nrf/Cargo.toml +++ b/embassy-nrf/Cargo.toml @@ -104,17 +104,17 @@ qspi-multiwrite-flash = [] #! ### Chip selection features ## nRF51 -nrf51 = ["nrf-pac/nrf51", "_nrf51"] +nrf51 = ["nrf-pac/nrf51", "_nrf51", "_spi-v1"] ## nRF52805 -nrf52805 = ["nrf-pac/nrf52805", "_nrf52"] +nrf52805 = ["nrf-pac/nrf52805", "_nrf52", "_spi-v1"] ## nRF52810 -nrf52810 = ["nrf-pac/nrf52810", "_nrf52"] +nrf52810 = ["nrf-pac/nrf52810", "_nrf52", "_spi-v1"] ## nRF52811 -nrf52811 = ["nrf-pac/nrf52811", "_nrf52"] +nrf52811 = ["nrf-pac/nrf52811", "_nrf52", "_spi-v1"] ## nRF52820 -nrf52820 = ["nrf-pac/nrf52820", "_nrf52"] +nrf52820 = ["nrf-pac/nrf52820", "_nrf52", "_spi-v1"] ## nRF52832 -nrf52832 = ["nrf-pac/nrf52832", "_nrf52", "_nrf52832_anomaly_109"] +nrf52832 = ["nrf-pac/nrf52832", "_nrf52", "_nrf52832_anomaly_109", "_spi-v1"] ## nRF52833 nrf52833 = ["nrf-pac/nrf52833", "_nrf52", "_gpio-p1"] ## nRF52840 @@ -154,10 +154,10 @@ _nrf54l15-app = ["_nrf54l15", "nrf-pac/nrf54l15-app"] _nrf54l15 = ["_nrf54l", "_gpio-p1", "_gpio-p2"] _nrf54l = ["_dppi"] -_nrf9160 = ["nrf-pac/nrf9160", "_dppi"] -_nrf9120 = ["nrf-pac/nrf9120", "_dppi"] +_nrf9160 = ["nrf-pac/nrf9160", "_dppi", "_spi-v1"] +_nrf9120 = ["nrf-pac/nrf9120", "_dppi", "_spi-v1"] _nrf52 = ["_ppi"] -_nrf51 = ["_ppi"] +_nrf51 = ["_ppi", "_spi-v1"] _nrf91 = [] _time-driver = ["dep:embassy-time-driver", "embassy-time-driver?/tick-hz-32_768", "dep:embassy-time-queue-utils", "embassy-embedded-hal/time"] @@ -172,6 +172,7 @@ _ppi = [] _dppi = [] _gpio-p1 = [] _gpio-p2 = [] +_spi-v1 = [] # Errata workarounds _nrf52832_anomaly_109 = [] @@ -199,7 +200,7 @@ 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" +nrf-pac = { version = "0.1.0", git = "https://github.com/embassy-rs/nrf-pac.git", rev = "58198c23bce72edc10b4e1656d1b54441fc74e7c" } defmt = { version = "1.0.1", optional = true } bitflags = "2.4.2" diff --git a/embassy-nrf/src/buffered_uarte.rs b/embassy-nrf/src/buffered_uarte.rs deleted file mode 100644 index b1eb5c81a..000000000 --- a/embassy-nrf/src/buffered_uarte.rs +++ /dev/null @@ -1,951 +0,0 @@ -//! Async buffered UART driver. -//! -//! Note that discarding a future from a read or write operation may lead to losing -//! data. For example, when using `futures_util::future::select` and completion occurs -//! on the "other" future, you should capture the incomplete future and continue to use -//! it for the next read or write. This pattern is a consideration for all IO, and not -//! just serial communications. -//! -//! Please also see [crate::uarte] to understand when [BufferedUarte] should be used. - -use core::cmp::min; -use core::future::{Future, poll_fn}; -use core::marker::PhantomData; -use core::slice; -use core::sync::atomic::{AtomicBool, AtomicU8, AtomicUsize, Ordering, compiler_fence}; -use core::task::Poll; - -use embassy_hal_internal::Peri; -use embassy_hal_internal::atomic_ring_buffer::RingBuffer; -use pac::uarte::vals; -// Re-export SVD variants to allow user to directly set values -pub use pac::uarte::vals::{Baudrate, ConfigParity as Parity}; - -use crate::gpio::{AnyPin, Pin as GpioPin}; -use crate::interrupt::InterruptExt; -use crate::interrupt::typelevel::Interrupt; -use crate::ppi::{ - self, AnyConfigurableChannel, AnyGroup, Channel, ConfigurableChannel, Event, Group, Ppi, PpiGroup, Task, -}; -use crate::timer::{Instance as TimerInstance, Timer}; -use crate::uarte::{Config, Instance as UarteInstance, configure, configure_rx_pins, configure_tx_pins, drop_tx_rx}; -use crate::{EASY_DMA_SIZE, interrupt, pac}; - -pub(crate) struct State { - tx_buf: RingBuffer, - tx_count: AtomicUsize, - - rx_buf: RingBuffer, - rx_started: AtomicBool, - rx_started_count: AtomicU8, - rx_ended_count: AtomicU8, - rx_ppi_ch: AtomicU8, - rx_overrun: AtomicBool, -} - -/// UART error. -#[derive(Debug, Clone, Copy, PartialEq, Eq)] -#[cfg_attr(feature = "defmt", derive(defmt::Format))] -#[non_exhaustive] -pub enum Error { - /// Buffer Overrun - Overrun, -} - -impl State { - pub(crate) const fn new() -> Self { - Self { - tx_buf: RingBuffer::new(), - tx_count: AtomicUsize::new(0), - - rx_buf: RingBuffer::new(), - rx_started: AtomicBool::new(false), - rx_started_count: AtomicU8::new(0), - rx_ended_count: AtomicU8::new(0), - rx_ppi_ch: AtomicU8::new(0), - rx_overrun: AtomicBool::new(false), - } - } -} - -/// Interrupt handler. -pub struct InterruptHandler { - _phantom: PhantomData, -} - -impl interrupt::typelevel::Handler for InterruptHandler { - unsafe fn on_interrupt() { - //trace!("irq: start"); - let r = U::regs(); - let ss = U::state(); - let s = U::buffered_state(); - - if let Some(mut rx) = unsafe { s.rx_buf.try_writer() } { - let buf_len = s.rx_buf.len(); - let half_len = buf_len / 2; - - if r.events_error().read() != 0 { - r.events_error().write_value(0); - let errs = r.errorsrc().read(); - r.errorsrc().write_value(errs); - - if errs.overrun() { - s.rx_overrun.store(true, Ordering::Release); - ss.rx_waker.wake(); - } - } - - // Received some bytes, wake task. - if r.inten().read().rxdrdy() && r.events_rxdrdy().read() != 0 { - r.intenclr().write(|w| w.set_rxdrdy(true)); - r.events_rxdrdy().write_value(0); - ss.rx_waker.wake(); - } - - if r.events_endrx().read() != 0 { - //trace!(" irq_rx: endrx"); - r.events_endrx().write_value(0); - - let val = s.rx_ended_count.load(Ordering::Relaxed); - s.rx_ended_count.store(val.wrapping_add(1), Ordering::Relaxed); - } - - if r.events_rxstarted().read() != 0 || !s.rx_started.load(Ordering::Relaxed) { - //trace!(" irq_rx: rxstarted"); - let (ptr, len) = rx.push_buf(); - if len >= half_len { - r.events_rxstarted().write_value(0); - - //trace!(" irq_rx: starting second {:?}", half_len); - - // Set up the DMA read - r.rxd().ptr().write_value(ptr as u32); - r.rxd().maxcnt().write(|w| w.set_maxcnt(half_len as _)); - - let chn = s.rx_ppi_ch.load(Ordering::Relaxed); - - // Enable endrx -> startrx PPI channel. - // From this point on, if endrx happens, startrx is automatically fired. - ppi::regs().chenset().write(|w| w.0 = 1 << chn); - - // It is possible that endrx happened BEFORE enabling the PPI. In this case - // the PPI channel doesn't trigger, and we'd hang. We have to detect this - // and manually start. - - // check again in case endrx has happened between the last check and now. - if r.events_endrx().read() != 0 { - //trace!(" irq_rx: endrx"); - r.events_endrx().write_value(0); - - let val = s.rx_ended_count.load(Ordering::Relaxed); - s.rx_ended_count.store(val.wrapping_add(1), Ordering::Relaxed); - } - - let rx_ended = s.rx_ended_count.load(Ordering::Relaxed); - let rx_started = s.rx_started_count.load(Ordering::Relaxed); - - // If we started the same amount of transfers as ended, the last rxend has - // already occured. - let rxend_happened = rx_started == rx_ended; - - // Check if the PPI channel is still enabled. The PPI channel disables itself - // when it fires, so if it's still enabled it hasn't fired. - let ppi_ch_enabled = ppi::regs().chen().read().ch(chn as _); - - // if rxend happened, and the ppi channel hasn't fired yet, the rxend got missed. - // this condition also naturally matches if `!started`, needed to kickstart the DMA. - if rxend_happened && ppi_ch_enabled { - //trace!("manually starting."); - - // disable the ppi ch, it's of no use anymore. - ppi::regs().chenclr().write(|w| w.set_ch(chn as _, true)); - - // manually start - r.tasks_startrx().write_value(1); - } - - rx.push_done(half_len); - - s.rx_started_count.store(rx_started.wrapping_add(1), Ordering::Relaxed); - s.rx_started.store(true, Ordering::Relaxed); - } else { - //trace!(" irq_rx: rxstarted no buf"); - r.intenclr().write(|w| w.set_rxstarted(true)); - } - } - } - - // ============================= - - if let Some(mut tx) = unsafe { s.tx_buf.try_reader() } { - // TX end - if r.events_endtx().read() != 0 { - r.events_endtx().write_value(0); - - let n = s.tx_count.load(Ordering::Relaxed); - //trace!(" irq_tx: endtx {:?}", n); - tx.pop_done(n); - ss.tx_waker.wake(); - s.tx_count.store(0, Ordering::Relaxed); - } - - // If not TXing, start. - if s.tx_count.load(Ordering::Relaxed) == 0 { - let (ptr, len) = tx.pop_buf(); - let len = len.min(EASY_DMA_SIZE); - if len != 0 { - //trace!(" irq_tx: starting {:?}", len); - s.tx_count.store(len, Ordering::Relaxed); - - // Set up the DMA write - r.txd().ptr().write_value(ptr as u32); - r.txd().maxcnt().write(|w| w.set_maxcnt(len as _)); - - // Start UARTE Transmit transaction - r.tasks_starttx().write_value(1); - } - } - } - - //trace!("irq: end"); - } -} - -/// Buffered UARTE driver. -pub struct BufferedUarte<'d> { - tx: BufferedUarteTx<'d>, - rx: BufferedUarteRx<'d>, -} - -impl<'d> Unpin for BufferedUarte<'d> {} - -impl<'d> BufferedUarte<'d> { - /// Create a new BufferedUarte without hardware flow control. - /// - /// # Panics - /// - /// Panics if `rx_buffer.len()` is odd. - #[allow(clippy::too_many_arguments)] - pub fn new( - uarte: Peri<'d, U>, - timer: Peri<'d, T>, - ppi_ch1: Peri<'d, impl ConfigurableChannel>, - ppi_ch2: Peri<'d, impl ConfigurableChannel>, - ppi_group: Peri<'d, impl Group>, - rxd: Peri<'d, impl GpioPin>, - txd: Peri<'d, impl GpioPin>, - _irq: impl interrupt::typelevel::Binding> + 'd, - config: Config, - rx_buffer: &'d mut [u8], - tx_buffer: &'d mut [u8], - ) -> Self { - Self::new_inner( - uarte, - timer, - ppi_ch1.into(), - ppi_ch2.into(), - ppi_group.into(), - rxd.into(), - txd.into(), - None, - None, - config, - rx_buffer, - tx_buffer, - ) - } - - /// Create a new BufferedUarte with hardware flow control (RTS/CTS) - /// - /// # Panics - /// - /// Panics if `rx_buffer.len()` is odd. - #[allow(clippy::too_many_arguments)] - pub fn new_with_rtscts( - uarte: Peri<'d, U>, - timer: Peri<'d, T>, - ppi_ch1: Peri<'d, impl ConfigurableChannel>, - ppi_ch2: Peri<'d, impl ConfigurableChannel>, - ppi_group: Peri<'d, impl Group>, - rxd: Peri<'d, impl GpioPin>, - txd: Peri<'d, impl GpioPin>, - cts: Peri<'d, impl GpioPin>, - rts: Peri<'d, impl GpioPin>, - _irq: impl interrupt::typelevel::Binding> + 'd, - config: Config, - rx_buffer: &'d mut [u8], - tx_buffer: &'d mut [u8], - ) -> Self { - Self::new_inner( - uarte, - timer, - ppi_ch1.into(), - ppi_ch2.into(), - ppi_group.into(), - rxd.into(), - txd.into(), - Some(cts.into()), - Some(rts.into()), - config, - rx_buffer, - tx_buffer, - ) - } - - #[allow(clippy::too_many_arguments)] - fn new_inner( - peri: Peri<'d, U>, - timer: Peri<'d, T>, - ppi_ch1: Peri<'d, AnyConfigurableChannel>, - ppi_ch2: Peri<'d, AnyConfigurableChannel>, - ppi_group: Peri<'d, AnyGroup>, - rxd: Peri<'d, AnyPin>, - txd: Peri<'d, AnyPin>, - cts: Option>, - rts: Option>, - config: Config, - rx_buffer: &'d mut [u8], - tx_buffer: &'d mut [u8], - ) -> Self { - let r = U::regs(); - let irq = U::Interrupt::IRQ; - let state = U::state(); - - configure(r, config, cts.is_some()); - - let tx = BufferedUarteTx::new_innerer(unsafe { peri.clone_unchecked() }, txd, cts, tx_buffer); - let rx = BufferedUarteRx::new_innerer(peri, timer, ppi_ch1, ppi_ch2, ppi_group, rxd, rts, rx_buffer); - - r.enable().write(|w| w.set_enable(vals::Enable::ENABLED)); - irq.pend(); - unsafe { irq.enable() }; - - state.tx_rx_refcount.store(2, Ordering::Relaxed); - - Self { tx, rx } - } - - /// Adjust the baud rate to the provided value. - pub fn set_baudrate(&mut self, baudrate: Baudrate) { - self.tx.set_baudrate(baudrate); - } - - /// Split the UART in reader and writer parts. - /// - /// This allows reading and writing concurrently from independent tasks. - pub fn split(self) -> (BufferedUarteRx<'d>, BufferedUarteTx<'d>) { - (self.rx, self.tx) - } - - /// Split the UART in reader and writer parts, by reference. - /// - /// The returned halves borrow from `self`, so you can drop them and go back to using - /// the "un-split" `self`. This allows temporarily splitting the UART. - pub fn split_by_ref(&mut self) -> (&mut BufferedUarteRx<'d>, &mut BufferedUarteTx<'d>) { - (&mut self.rx, &mut self.tx) - } - - /// Pull some bytes from this source into the specified buffer, returning how many bytes were read. - pub async fn read(&mut self, buf: &mut [u8]) -> Result { - self.rx.read(buf).await - } - - /// Return the contents of the internal buffer, filling it with more data from the inner reader if it is empty. - pub async fn fill_buf(&mut self) -> Result<&[u8], Error> { - self.rx.fill_buf().await - } - - /// Tell this buffer that `amt` bytes have been consumed from the buffer, so they should no longer be returned in calls to `fill_buf`. - pub fn consume(&mut self, amt: usize) { - self.rx.consume(amt) - } - - /// Write a buffer into this writer, returning how many bytes were written. - pub async fn write(&mut self, buf: &[u8]) -> Result { - self.tx.write(buf).await - } - - /// Try writing a buffer without waiting, returning how many bytes were written. - pub fn try_write(&mut self, buf: &[u8]) -> Result { - self.tx.try_write(buf) - } - - /// Flush this output stream, ensuring that all intermediately buffered contents reach their destination. - pub async fn flush(&mut self) -> Result<(), Error> { - self.tx.flush().await - } -} - -/// Reader part of the buffered UARTE driver. -pub struct BufferedUarteTx<'d> { - r: pac::uarte::Uarte, - _irq: interrupt::Interrupt, - state: &'static crate::uarte::State, - buffered_state: &'static State, - _p: PhantomData<&'d ()>, -} - -impl<'d> BufferedUarteTx<'d> { - /// Create a new BufferedUarteTx without hardware flow control. - pub fn new( - uarte: Peri<'d, U>, - txd: Peri<'d, impl GpioPin>, - _irq: impl interrupt::typelevel::Binding> + 'd, - config: Config, - tx_buffer: &'d mut [u8], - ) -> Self { - Self::new_inner(uarte, txd.into(), None, config, tx_buffer) - } - - /// Create a new BufferedUarte with hardware flow control (RTS/CTS) - /// - /// # Panics - /// - /// Panics if `rx_buffer.len()` is odd. - pub fn new_with_cts( - uarte: Peri<'d, U>, - txd: Peri<'d, impl GpioPin>, - cts: Peri<'d, impl GpioPin>, - _irq: impl interrupt::typelevel::Binding> + 'd, - config: Config, - tx_buffer: &'d mut [u8], - ) -> Self { - Self::new_inner(uarte, txd.into(), Some(cts.into()), config, tx_buffer) - } - - fn new_inner( - peri: Peri<'d, U>, - txd: Peri<'d, AnyPin>, - cts: Option>, - config: Config, - tx_buffer: &'d mut [u8], - ) -> Self { - let r = U::regs(); - let irq = U::Interrupt::IRQ; - let state = U::state(); - let _buffered_state = U::buffered_state(); - - configure(r, config, cts.is_some()); - - let this = Self::new_innerer(peri, txd, cts, tx_buffer); - - r.enable().write(|w| w.set_enable(vals::Enable::ENABLED)); - irq.pend(); - unsafe { irq.enable() }; - - state.tx_rx_refcount.store(1, Ordering::Relaxed); - - this - } - - fn new_innerer( - _peri: Peri<'d, U>, - txd: Peri<'d, AnyPin>, - cts: Option>, - tx_buffer: &'d mut [u8], - ) -> Self { - let r = U::regs(); - let irq = U::Interrupt::IRQ; - let state = U::state(); - let buffered_state = U::buffered_state(); - - configure_tx_pins(r, txd, cts); - - // Initialize state - buffered_state.tx_count.store(0, Ordering::Relaxed); - let len = tx_buffer.len(); - unsafe { buffered_state.tx_buf.init(tx_buffer.as_mut_ptr(), len) }; - - r.events_txstarted().write_value(0); - - // Enable interrupts - r.intenset().write(|w| { - w.set_endtx(true); - }); - - Self { - r, - _irq: irq, - state, - buffered_state, - _p: PhantomData, - } - } - - /// Write a buffer into this writer, returning how many bytes were written. - pub fn write<'a>(&'a mut self, buf: &'a [u8]) -> impl Future> + 'a + use<'a, 'd> { - poll_fn(move |cx| { - //trace!("poll_write: {:?}", buf.len()); - let ss = self.state; - let s = self.buffered_state; - let mut tx = unsafe { s.tx_buf.writer() }; - - let tx_buf = tx.push_slice(); - if tx_buf.is_empty() { - //trace!("poll_write: pending"); - ss.tx_waker.register(cx.waker()); - return Poll::Pending; - } - - let n = min(tx_buf.len(), buf.len()); - tx_buf[..n].copy_from_slice(&buf[..n]); - tx.push_done(n); - - //trace!("poll_write: queued {:?}", n); - - compiler_fence(Ordering::SeqCst); - self._irq.pend(); - - Poll::Ready(Ok(n)) - }) - } - - /// Try writing a buffer without waiting, returning how many bytes were written. - pub fn try_write(&mut self, buf: &[u8]) -> Result { - //trace!("poll_write: {:?}", buf.len()); - let s = self.buffered_state; - let mut tx = unsafe { s.tx_buf.writer() }; - - let tx_buf = tx.push_slice(); - if tx_buf.is_empty() { - return Ok(0); - } - - let n = min(tx_buf.len(), buf.len()); - tx_buf[..n].copy_from_slice(&buf[..n]); - tx.push_done(n); - - //trace!("poll_write: queued {:?}", n); - - compiler_fence(Ordering::SeqCst); - self._irq.pend(); - - Ok(n) - } - - /// Flush this output stream, ensuring that all intermediately buffered contents reach their destination. - pub fn flush(&mut self) -> impl Future> + '_ { - let ss = self.state; - let s = self.buffered_state; - poll_fn(move |cx| { - //trace!("poll_flush"); - if !s.tx_buf.is_empty() { - //trace!("poll_flush: pending"); - ss.tx_waker.register(cx.waker()); - return Poll::Pending; - } - - Poll::Ready(Ok(())) - }) - } - - /// Adjust the baud rate to the provided value. - pub fn set_baudrate(&mut self, baudrate: Baudrate) { - self.r.baudrate().write(|w| w.set_baudrate(baudrate)); - } -} - -impl<'a> Drop for BufferedUarteTx<'a> { - fn drop(&mut self) { - let r = self.r; - - r.intenclr().write(|w| { - w.set_txdrdy(true); - w.set_txstarted(true); - w.set_txstopped(true); - }); - r.events_txstopped().write_value(0); - r.tasks_stoptx().write_value(1); - while r.events_txstopped().read() == 0 {} - - let s = self.buffered_state; - unsafe { s.tx_buf.deinit() } - - let s = self.state; - drop_tx_rx(r, s); - } -} - -/// Reader part of the buffered UARTE driver. -pub struct BufferedUarteRx<'d> { - r: pac::uarte::Uarte, - state: &'static crate::uarte::State, - buffered_state: &'static State, - timer: Timer<'d>, - _ppi_ch1: Ppi<'d, AnyConfigurableChannel, 1, 1>, - _ppi_ch2: Ppi<'d, AnyConfigurableChannel, 1, 2>, - _ppi_group: PpiGroup<'d, AnyGroup>, - _p: PhantomData<&'d ()>, -} - -impl<'d> BufferedUarteRx<'d> { - /// Create a new BufferedUarte without hardware flow control. - /// - /// # Panics - /// - /// Panics if `rx_buffer.len()` is odd. - #[allow(clippy::too_many_arguments)] - pub fn new( - uarte: Peri<'d, U>, - timer: Peri<'d, T>, - ppi_ch1: Peri<'d, impl ConfigurableChannel>, - ppi_ch2: Peri<'d, impl ConfigurableChannel>, - ppi_group: Peri<'d, impl Group>, - _irq: impl interrupt::typelevel::Binding> + 'd, - rxd: Peri<'d, impl GpioPin>, - config: Config, - rx_buffer: &'d mut [u8], - ) -> Self { - Self::new_inner( - uarte, - timer, - ppi_ch1.into(), - ppi_ch2.into(), - ppi_group.into(), - rxd.into(), - None, - config, - rx_buffer, - ) - } - - /// Create a new BufferedUarte with hardware flow control (RTS/CTS) - /// - /// # Panics - /// - /// Panics if `rx_buffer.len()` is odd. - #[allow(clippy::too_many_arguments)] - pub fn new_with_rts( - uarte: Peri<'d, U>, - timer: Peri<'d, T>, - ppi_ch1: Peri<'d, impl ConfigurableChannel>, - ppi_ch2: Peri<'d, impl ConfigurableChannel>, - ppi_group: Peri<'d, impl Group>, - rxd: Peri<'d, impl GpioPin>, - rts: Peri<'d, impl GpioPin>, - _irq: impl interrupt::typelevel::Binding> + 'd, - config: Config, - rx_buffer: &'d mut [u8], - ) -> Self { - Self::new_inner( - uarte, - timer, - ppi_ch1.into(), - ppi_ch2.into(), - ppi_group.into(), - rxd.into(), - Some(rts.into()), - config, - rx_buffer, - ) - } - - #[allow(clippy::too_many_arguments)] - fn new_inner( - peri: Peri<'d, U>, - timer: Peri<'d, T>, - ppi_ch1: Peri<'d, AnyConfigurableChannel>, - ppi_ch2: Peri<'d, AnyConfigurableChannel>, - ppi_group: Peri<'d, AnyGroup>, - rxd: Peri<'d, AnyPin>, - rts: Option>, - config: Config, - rx_buffer: &'d mut [u8], - ) -> Self { - let r = U::regs(); - let irq = U::Interrupt::IRQ; - let state = U::state(); - let _buffered_state = U::buffered_state(); - - configure(r, config, rts.is_some()); - - let this = Self::new_innerer(peri, timer, ppi_ch1, ppi_ch2, ppi_group, rxd, rts, rx_buffer); - - r.enable().write(|w| w.set_enable(vals::Enable::ENABLED)); - irq.pend(); - unsafe { irq.enable() }; - - state.tx_rx_refcount.store(1, Ordering::Relaxed); - - this - } - - #[allow(clippy::too_many_arguments)] - fn new_innerer( - _peri: Peri<'d, U>, - timer: Peri<'d, T>, - ppi_ch1: Peri<'d, AnyConfigurableChannel>, - ppi_ch2: Peri<'d, AnyConfigurableChannel>, - ppi_group: Peri<'d, AnyGroup>, - rxd: Peri<'d, AnyPin>, - rts: Option>, - rx_buffer: &'d mut [u8], - ) -> Self { - assert!(rx_buffer.len() % 2 == 0); - - let r = U::regs(); - let state = U::state(); - let buffered_state = U::buffered_state(); - - configure_rx_pins(r, rxd, rts); - - // Initialize state - buffered_state.rx_started_count.store(0, Ordering::Relaxed); - buffered_state.rx_ended_count.store(0, Ordering::Relaxed); - buffered_state.rx_started.store(false, Ordering::Relaxed); - buffered_state.rx_overrun.store(false, Ordering::Relaxed); - let rx_len = rx_buffer.len().min(EASY_DMA_SIZE * 2); - unsafe { buffered_state.rx_buf.init(rx_buffer.as_mut_ptr(), rx_len) }; - - // clear errors - let errors = r.errorsrc().read(); - r.errorsrc().write_value(errors); - - r.events_rxstarted().write_value(0); - r.events_error().write_value(0); - r.events_endrx().write_value(0); - - // Enable interrupts - r.intenset().write(|w| { - w.set_endtx(true); - w.set_rxstarted(true); - w.set_error(true); - w.set_endrx(true); - }); - - // Configure byte counter. - let timer = Timer::new_counter(timer); - timer.cc(1).write(rx_len as u32 * 2); - timer.cc(1).short_compare_clear(); - timer.clear(); - timer.start(); - - let mut ppi_ch1 = Ppi::new_one_to_one(ppi_ch1, Event::from_reg(r.events_rxdrdy()), timer.task_count()); - ppi_ch1.enable(); - - buffered_state - .rx_ppi_ch - .store(ppi_ch2.number() as u8, Ordering::Relaxed); - let mut ppi_group = PpiGroup::new(ppi_group); - let mut ppi_ch2 = Ppi::new_one_to_two( - ppi_ch2, - Event::from_reg(r.events_endrx()), - Task::from_reg(r.tasks_startrx()), - ppi_group.task_disable_all(), - ); - ppi_ch2.disable(); - ppi_group.add_channel(&ppi_ch2); - - Self { - r, - state, - buffered_state, - timer, - _ppi_ch1: ppi_ch1, - _ppi_ch2: ppi_ch2, - _ppi_group: ppi_group, - _p: PhantomData, - } - } - - /// Pull some bytes from this source into the specified buffer, returning how many bytes were read. - pub async fn read(&mut self, buf: &mut [u8]) -> Result { - let data = self.fill_buf().await?; - let n = data.len().min(buf.len()); - buf[..n].copy_from_slice(&data[..n]); - self.consume(n); - Ok(n) - } - - /// Return the contents of the internal buffer, filling it with more data from the inner reader if it is empty. - pub fn fill_buf(&mut self) -> impl Future> { - let r = self.r; - let s = self.buffered_state; - let ss = self.state; - let timer = &self.timer; - poll_fn(move |cx| { - compiler_fence(Ordering::SeqCst); - //trace!("poll_read"); - - if s.rx_overrun.swap(false, Ordering::Acquire) { - return Poll::Ready(Err(Error::Overrun)); - } - - // Read the RXDRDY counter. - timer.cc(0).capture(); - let mut end = timer.cc(0).read() as usize; - //trace!(" rxdrdy count = {:?}", end); - - // We've set a compare channel that resets the counter to 0 when it reaches `len*2`. - // However, it's unclear if that's instant, or there's a small window where you can - // still read `len()*2`. - // This could happen if in one clock cycle the counter is updated, and in the next the - // clear takes effect. The docs are very sparse, they just say "Task delays: After TIMER - // is started, the CLEAR, COUNT, and STOP tasks are guaranteed to take effect within one - // clock cycle of the PCLK16M." :shrug: - // So, we wrap the counter ourselves, just in case. - if end > s.rx_buf.len() * 2 { - end = 0 - } - - // This logic mirrors `atomic_ring_buffer::Reader::pop_buf()` - let mut start = s.rx_buf.start.load(Ordering::Relaxed); - let len = s.rx_buf.len(); - if start == end { - //trace!(" empty"); - ss.rx_waker.register(cx.waker()); - r.intenset().write(|w| w.set_rxdrdy(true)); - return Poll::Pending; - } - - if start >= len { - start -= len - } - if end >= len { - end -= len - } - - let n = if end > start { end - start } else { len - start }; - assert!(n != 0); - //trace!(" uarte ringbuf: pop_buf {:?}..{:?}", start, start + n); - - let buf = s.rx_buf.buf.load(Ordering::Relaxed); - Poll::Ready(Ok(unsafe { slice::from_raw_parts(buf.add(start), n) })) - }) - } - - /// Tell this buffer that `amt` bytes have been consumed from the buffer, so they should no longer be returned in calls to `fill_buf`. - pub fn consume(&mut self, amt: usize) { - if amt == 0 { - return; - } - - let s = self.buffered_state; - let mut rx = unsafe { s.rx_buf.reader() }; - rx.pop_done(amt); - self.r.intenset().write(|w| w.set_rxstarted(true)); - } - - /// we are ready to read if there is data in the buffer - fn read_ready(&self) -> Result { - let state = self.buffered_state; - if state.rx_overrun.swap(false, Ordering::Acquire) { - return Err(Error::Overrun); - } - Ok(!state.rx_buf.is_empty()) - } -} - -impl<'a> Drop for BufferedUarteRx<'a> { - fn drop(&mut self) { - self._ppi_group.disable_all(); - - let r = self.r; - - self.timer.stop(); - - r.intenclr().write(|w| { - w.set_rxdrdy(true); - w.set_rxstarted(true); - w.set_rxto(true); - }); - r.events_rxto().write_value(0); - r.tasks_stoprx().write_value(1); - while r.events_rxto().read() == 0 {} - - let s = self.buffered_state; - unsafe { s.rx_buf.deinit() } - - let s = self.state; - drop_tx_rx(r, s); - } -} - -mod _embedded_io { - use super::*; - - impl embedded_io_async::Error for Error { - fn kind(&self) -> embedded_io_async::ErrorKind { - match *self { - Error::Overrun => embedded_io_async::ErrorKind::OutOfMemory, - } - } - } - - impl<'d> embedded_io_async::ErrorType for BufferedUarte<'d> { - type Error = Error; - } - - impl<'d> embedded_io_async::ErrorType for BufferedUarteRx<'d> { - type Error = Error; - } - - impl<'d> embedded_io_async::ErrorType for BufferedUarteTx<'d> { - type Error = Error; - } - - impl<'d> embedded_io_async::Read for BufferedUarte<'d> { - async fn read(&mut self, buf: &mut [u8]) -> Result { - self.read(buf).await - } - } - - impl<'d> embedded_io_async::Read for BufferedUarteRx<'d> { - async fn read(&mut self, buf: &mut [u8]) -> Result { - self.read(buf).await - } - } - - impl<'d> embedded_io_async::ReadReady for BufferedUarte<'d> { - fn read_ready(&mut self) -> Result { - self.rx.read_ready() - } - } - - impl<'d> embedded_io_async::ReadReady for BufferedUarteRx<'d> { - fn read_ready(&mut self) -> Result { - let state = self.buffered_state; - Ok(!state.rx_buf.is_empty()) - } - } - - impl<'d> embedded_io_async::BufRead for BufferedUarte<'d> { - async fn fill_buf(&mut self) -> Result<&[u8], Self::Error> { - self.fill_buf().await - } - - fn consume(&mut self, amt: usize) { - self.consume(amt) - } - } - - impl<'d> embedded_io_async::BufRead for BufferedUarteRx<'d> { - async fn fill_buf(&mut self) -> Result<&[u8], Self::Error> { - self.fill_buf().await - } - - fn consume(&mut self, amt: usize) { - self.consume(amt) - } - } - - impl<'d> embedded_io_async::Write for BufferedUarte<'d> { - async fn write(&mut self, buf: &[u8]) -> Result { - self.write(buf).await - } - - async fn flush(&mut self) -> Result<(), Self::Error> { - self.flush().await - } - } - - impl<'d> embedded_io_async::Write for BufferedUarteTx<'d> { - async fn write(&mut self, buf: &[u8]) -> Result { - self.write(buf).await - } - - async fn flush(&mut self) -> Result<(), Self::Error> { - self.flush().await - } - } -} diff --git a/embassy-nrf/src/buffered_uarte/mod.rs b/embassy-nrf/src/buffered_uarte/mod.rs new file mode 100644 index 000000000..75d84baac --- /dev/null +++ b/embassy-nrf/src/buffered_uarte/mod.rs @@ -0,0 +1,14 @@ +//! Async buffered UART driver. +//! +//! Note that discarding a future from a read or write operation may lead to losing +//! data. For example, when using `futures_util::future::select` and completion occurs +//! on the "other" future, you should capture the incomplete future and continue to use +//! it for the next read or write. This pattern is a consideration for all IO, and not +//! just serial communications. +//! +//! Please also see [crate::uarte] to understand when [BufferedUarte] should be used. +#[cfg_attr(not(feature = "_nrf54l"), path = "v1.rs")] +#[cfg_attr(feature = "_nrf54l", path = "v2.rs")] +mod _version; + +pub use _version::*; diff --git a/embassy-nrf/src/buffered_uarte/v1.rs b/embassy-nrf/src/buffered_uarte/v1.rs new file mode 100644 index 000000000..07de22717 --- /dev/null +++ b/embassy-nrf/src/buffered_uarte/v1.rs @@ -0,0 +1,951 @@ +//! Async buffered UART driver. +//! +//! Note that discarding a future from a read or write operation may lead to losing +//! data. For example, when using `futures_util::future::select` and completion occurs +//! on the "other" future, you should capture the incomplete future and continue to use +//! it for the next read or write. This pattern is a consideration for all IO, and not +//! just serial communications. +//! +//! Please also see [crate::uarte] to understand when [BufferedUarte] should be used. + +use core::cmp::min; +use core::future::{Future, poll_fn}; +use core::marker::PhantomData; +use core::slice; +use core::sync::atomic::{AtomicBool, AtomicU8, AtomicUsize, Ordering, compiler_fence}; +use core::task::Poll; + +use embassy_hal_internal::Peri; +use embassy_hal_internal::atomic_ring_buffer::RingBuffer; +use pac::uarte::vals; +// Re-export SVD variants to allow user to directly set values +pub use pac::uarte::vals::{Baudrate, ConfigParity as Parity}; + +use crate::gpio::{AnyPin, Pin as GpioPin}; +use crate::interrupt::InterruptExt; +use crate::interrupt::typelevel::Interrupt; +use crate::ppi::{ + self, AnyConfigurableChannel, AnyGroup, Channel, ConfigurableChannel, Event, Group, Ppi, PpiGroup, Task, +}; +use crate::timer::{Instance as TimerInstance, Timer}; +use crate::uarte::{Config, Instance as UarteInstance, configure, configure_rx_pins, configure_tx_pins, drop_tx_rx}; +use crate::{EASY_DMA_SIZE, interrupt, pac}; + +pub(crate) struct State { + tx_buf: RingBuffer, + tx_count: AtomicUsize, + + rx_buf: RingBuffer, + rx_started: AtomicBool, + rx_started_count: AtomicU8, + rx_ended_count: AtomicU8, + rx_ppi_ch: AtomicU8, + rx_overrun: AtomicBool, +} + +/// UART error. +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +#[cfg_attr(feature = "defmt", derive(defmt::Format))] +#[non_exhaustive] +pub enum Error { + /// Buffer Overrun + Overrun, +} + +impl State { + pub(crate) const fn new() -> Self { + Self { + tx_buf: RingBuffer::new(), + tx_count: AtomicUsize::new(0), + + rx_buf: RingBuffer::new(), + rx_started: AtomicBool::new(false), + rx_started_count: AtomicU8::new(0), + rx_ended_count: AtomicU8::new(0), + rx_ppi_ch: AtomicU8::new(0), + rx_overrun: AtomicBool::new(false), + } + } +} + +/// Interrupt handler. +pub struct InterruptHandler { + _phantom: PhantomData, +} + +impl interrupt::typelevel::Handler for InterruptHandler { + unsafe fn on_interrupt() { + //trace!("irq: start"); + let r = U::regs(); + let ss = U::state(); + let s = U::buffered_state(); + + if let Some(mut rx) = unsafe { s.rx_buf.try_writer() } { + let buf_len = s.rx_buf.len(); + let half_len = buf_len / 2; + + if r.events_error().read() != 0 { + r.events_error().write_value(0); + let errs = r.errorsrc().read(); + r.errorsrc().write_value(errs); + + if errs.overrun() { + s.rx_overrun.store(true, Ordering::Release); + ss.rx_waker.wake(); + } + } + + // Received some bytes, wake task. + if r.inten().read().rxdrdy() && r.events_rxdrdy().read() != 0 { + r.intenclr().write(|w| w.set_rxdrdy(true)); + r.events_rxdrdy().write_value(0); + ss.rx_waker.wake(); + } + + if r.events_dma().rx().end().read() != 0 { + //trace!(" irq_rx: endrx"); + r.events_dma().rx().end().write_value(0); + + let val = s.rx_ended_count.load(Ordering::Relaxed); + s.rx_ended_count.store(val.wrapping_add(1), Ordering::Relaxed); + } + + if r.events_dma().rx().ready().read() != 0 || !s.rx_started.load(Ordering::Relaxed) { + //trace!(" irq_rx: rxstarted"); + let (ptr, len) = rx.push_buf(); + if len >= half_len { + r.events_dma().rx().ready().write_value(0); + + //trace!(" irq_rx: starting second {:?}", half_len); + + // Set up the DMA read + r.dma().rx().ptr().write_value(ptr as u32); + r.dma().rx().maxcnt().write(|w| w.set_maxcnt(half_len as _)); + + let chn = s.rx_ppi_ch.load(Ordering::Relaxed); + + // Enable endrx -> startrx PPI channel. + // From this point on, if endrx happens, startrx is automatically fired. + ppi::regs().chenset().write(|w| w.0 = 1 << chn); + + // It is possible that endrx happened BEFORE enabling the PPI. In this case + // the PPI channel doesn't trigger, and we'd hang. We have to detect this + // and manually start. + + // check again in case endrx has happened between the last check and now. + if r.events_dma().rx().end().read() != 0 { + //trace!(" irq_rx: endrx"); + r.events_dma().rx().end().write_value(0); + + let val = s.rx_ended_count.load(Ordering::Relaxed); + s.rx_ended_count.store(val.wrapping_add(1), Ordering::Relaxed); + } + + let rx_ended = s.rx_ended_count.load(Ordering::Relaxed); + let rx_started = s.rx_started_count.load(Ordering::Relaxed); + + // If we started the same amount of transfers as ended, the last rxend has + // already occured. + let rxend_happened = rx_started == rx_ended; + + // Check if the PPI channel is still enabled. The PPI channel disables itself + // when it fires, so if it's still enabled it hasn't fired. + let ppi_ch_enabled = ppi::regs().chen().read().ch(chn as _); + + // if rxend happened, and the ppi channel hasn't fired yet, the rxend got missed. + // this condition also naturally matches if `!started`, needed to kickstart the DMA. + if rxend_happened && ppi_ch_enabled { + //trace!("manually starting."); + + // disable the ppi ch, it's of no use anymore. + ppi::regs().chenclr().write(|w| w.set_ch(chn as _, true)); + + // manually start + r.tasks_dma().rx().start().write_value(1); + } + + rx.push_done(half_len); + + s.rx_started_count.store(rx_started.wrapping_add(1), Ordering::Relaxed); + s.rx_started.store(true, Ordering::Relaxed); + } else { + //trace!(" irq_rx: rxstarted no buf"); + r.intenclr().write(|w| w.set_dmarxready(true)); + } + } + } + + // ============================= + + if let Some(mut tx) = unsafe { s.tx_buf.try_reader() } { + // TX end + if r.events_dma().tx().end().read() != 0 { + r.events_dma().tx().end().write_value(0); + + let n = s.tx_count.load(Ordering::Relaxed); + //trace!(" irq_tx: endtx {:?}", n); + tx.pop_done(n); + ss.tx_waker.wake(); + s.tx_count.store(0, Ordering::Relaxed); + } + + // If not TXing, start. + if s.tx_count.load(Ordering::Relaxed) == 0 { + let (ptr, len) = tx.pop_buf(); + let len = len.min(EASY_DMA_SIZE); + if len != 0 { + //trace!(" irq_tx: starting {:?}", len); + s.tx_count.store(len, Ordering::Relaxed); + + // Set up the DMA write + r.dma().tx().ptr().write_value(ptr as u32); + r.dma().tx().maxcnt().write(|w| w.set_maxcnt(len as _)); + + // Start UARTE Transmit transaction + r.tasks_dma().tx().start().write_value(1); + } + } + } + + //trace!("irq: end"); + } +} + +/// Buffered UARTE driver. +pub struct BufferedUarte<'d> { + tx: BufferedUarteTx<'d>, + rx: BufferedUarteRx<'d>, +} + +impl<'d> Unpin for BufferedUarte<'d> {} + +impl<'d> BufferedUarte<'d> { + /// Create a new BufferedUarte without hardware flow control. + /// + /// # Panics + /// + /// Panics if `rx_buffer.len()` is odd. + #[allow(clippy::too_many_arguments)] + pub fn new( + uarte: Peri<'d, U>, + timer: Peri<'d, T>, + ppi_ch1: Peri<'d, impl ConfigurableChannel>, + ppi_ch2: Peri<'d, impl ConfigurableChannel>, + ppi_group: Peri<'d, impl Group>, + rxd: Peri<'d, impl GpioPin>, + txd: Peri<'d, impl GpioPin>, + _irq: impl interrupt::typelevel::Binding> + 'd, + config: Config, + rx_buffer: &'d mut [u8], + tx_buffer: &'d mut [u8], + ) -> Self { + Self::new_inner( + uarte, + timer, + ppi_ch1.into(), + ppi_ch2.into(), + ppi_group.into(), + rxd.into(), + txd.into(), + None, + None, + config, + rx_buffer, + tx_buffer, + ) + } + + /// Create a new BufferedUarte with hardware flow control (RTS/CTS) + /// + /// # Panics + /// + /// Panics if `rx_buffer.len()` is odd. + #[allow(clippy::too_many_arguments)] + pub fn new_with_rtscts( + uarte: Peri<'d, U>, + timer: Peri<'d, T>, + ppi_ch1: Peri<'d, impl ConfigurableChannel>, + ppi_ch2: Peri<'d, impl ConfigurableChannel>, + ppi_group: Peri<'d, impl Group>, + rxd: Peri<'d, impl GpioPin>, + txd: Peri<'d, impl GpioPin>, + cts: Peri<'d, impl GpioPin>, + rts: Peri<'d, impl GpioPin>, + _irq: impl interrupt::typelevel::Binding> + 'd, + config: Config, + rx_buffer: &'d mut [u8], + tx_buffer: &'d mut [u8], + ) -> Self { + Self::new_inner( + uarte, + timer, + ppi_ch1.into(), + ppi_ch2.into(), + ppi_group.into(), + rxd.into(), + txd.into(), + Some(cts.into()), + Some(rts.into()), + config, + rx_buffer, + tx_buffer, + ) + } + + #[allow(clippy::too_many_arguments)] + fn new_inner( + peri: Peri<'d, U>, + timer: Peri<'d, T>, + ppi_ch1: Peri<'d, AnyConfigurableChannel>, + ppi_ch2: Peri<'d, AnyConfigurableChannel>, + ppi_group: Peri<'d, AnyGroup>, + rxd: Peri<'d, AnyPin>, + txd: Peri<'d, AnyPin>, + cts: Option>, + rts: Option>, + config: Config, + rx_buffer: &'d mut [u8], + tx_buffer: &'d mut [u8], + ) -> Self { + let r = U::regs(); + let irq = U::Interrupt::IRQ; + let state = U::state(); + + configure(r, config, cts.is_some()); + + let tx = BufferedUarteTx::new_innerer(unsafe { peri.clone_unchecked() }, txd, cts, tx_buffer); + let rx = BufferedUarteRx::new_innerer(peri, timer, ppi_ch1, ppi_ch2, ppi_group, rxd, rts, rx_buffer); + + r.enable().write(|w| w.set_enable(vals::Enable::ENABLED)); + irq.pend(); + unsafe { irq.enable() }; + + state.tx_rx_refcount.store(2, Ordering::Relaxed); + + Self { tx, rx } + } + + /// Adjust the baud rate to the provided value. + pub fn set_baudrate(&mut self, baudrate: Baudrate) { + self.tx.set_baudrate(baudrate); + } + + /// Split the UART in reader and writer parts. + /// + /// This allows reading and writing concurrently from independent tasks. + pub fn split(self) -> (BufferedUarteRx<'d>, BufferedUarteTx<'d>) { + (self.rx, self.tx) + } + + /// Split the UART in reader and writer parts, by reference. + /// + /// The returned halves borrow from `self`, so you can drop them and go back to using + /// the "un-split" `self`. This allows temporarily splitting the UART. + pub fn split_by_ref(&mut self) -> (&mut BufferedUarteRx<'d>, &mut BufferedUarteTx<'d>) { + (&mut self.rx, &mut self.tx) + } + + /// Pull some bytes from this source into the specified buffer, returning how many bytes were read. + pub async fn read(&mut self, buf: &mut [u8]) -> Result { + self.rx.read(buf).await + } + + /// Return the contents of the internal buffer, filling it with more data from the inner reader if it is empty. + pub async fn fill_buf(&mut self) -> Result<&[u8], Error> { + self.rx.fill_buf().await + } + + /// Tell this buffer that `amt` bytes have been consumed from the buffer, so they should no longer be returned in calls to `fill_buf`. + pub fn consume(&mut self, amt: usize) { + self.rx.consume(amt) + } + + /// Write a buffer into this writer, returning how many bytes were written. + pub async fn write(&mut self, buf: &[u8]) -> Result { + self.tx.write(buf).await + } + + /// Try writing a buffer without waiting, returning how many bytes were written. + pub fn try_write(&mut self, buf: &[u8]) -> Result { + self.tx.try_write(buf) + } + + /// Flush this output stream, ensuring that all intermediately buffered contents reach their destination. + pub async fn flush(&mut self) -> Result<(), Error> { + self.tx.flush().await + } +} + +/// Reader part of the buffered UARTE driver. +pub struct BufferedUarteTx<'d> { + r: pac::uarte::Uarte, + _irq: interrupt::Interrupt, + state: &'static crate::uarte::State, + buffered_state: &'static State, + _p: PhantomData<&'d ()>, +} + +impl<'d> BufferedUarteTx<'d> { + /// Create a new BufferedUarteTx without hardware flow control. + pub fn new( + uarte: Peri<'d, U>, + txd: Peri<'d, impl GpioPin>, + _irq: impl interrupt::typelevel::Binding> + 'd, + config: Config, + tx_buffer: &'d mut [u8], + ) -> Self { + Self::new_inner(uarte, txd.into(), None, config, tx_buffer) + } + + /// Create a new BufferedUarte with hardware flow control (RTS/CTS) + /// + /// # Panics + /// + /// Panics if `rx_buffer.len()` is odd. + pub fn new_with_cts( + uarte: Peri<'d, U>, + txd: Peri<'d, impl GpioPin>, + cts: Peri<'d, impl GpioPin>, + _irq: impl interrupt::typelevel::Binding> + 'd, + config: Config, + tx_buffer: &'d mut [u8], + ) -> Self { + Self::new_inner(uarte, txd.into(), Some(cts.into()), config, tx_buffer) + } + + fn new_inner( + peri: Peri<'d, U>, + txd: Peri<'d, AnyPin>, + cts: Option>, + config: Config, + tx_buffer: &'d mut [u8], + ) -> Self { + let r = U::regs(); + let irq = U::Interrupt::IRQ; + let state = U::state(); + let _buffered_state = U::buffered_state(); + + configure(r, config, cts.is_some()); + + let this = Self::new_innerer(peri, txd, cts, tx_buffer); + + r.enable().write(|w| w.set_enable(vals::Enable::ENABLED)); + irq.pend(); + unsafe { irq.enable() }; + + state.tx_rx_refcount.store(1, Ordering::Relaxed); + + this + } + + fn new_innerer( + _peri: Peri<'d, U>, + txd: Peri<'d, AnyPin>, + cts: Option>, + tx_buffer: &'d mut [u8], + ) -> Self { + let r = U::regs(); + let irq = U::Interrupt::IRQ; + let state = U::state(); + let buffered_state = U::buffered_state(); + + configure_tx_pins(r, txd, cts); + + // Initialize state + buffered_state.tx_count.store(0, Ordering::Relaxed); + let len = tx_buffer.len(); + unsafe { buffered_state.tx_buf.init(tx_buffer.as_mut_ptr(), len) }; + + r.events_dma().tx().ready().write_value(0); + + // Enable interrupts + r.intenset().write(|w| { + w.set_dmatxend(true); + }); + + Self { + r, + _irq: irq, + state, + buffered_state, + _p: PhantomData, + } + } + + /// Write a buffer into this writer, returning how many bytes were written. + pub fn write<'a>(&'a mut self, buf: &'a [u8]) -> impl Future> + 'a + use<'a, 'd> { + poll_fn(move |cx| { + //trace!("poll_write: {:?}", buf.len()); + let ss = self.state; + let s = self.buffered_state; + let mut tx = unsafe { s.tx_buf.writer() }; + + let tx_buf = tx.push_slice(); + if tx_buf.is_empty() { + //trace!("poll_write: pending"); + ss.tx_waker.register(cx.waker()); + return Poll::Pending; + } + + let n = min(tx_buf.len(), buf.len()); + tx_buf[..n].copy_from_slice(&buf[..n]); + tx.push_done(n); + + //trace!("poll_write: queued {:?}", n); + + compiler_fence(Ordering::SeqCst); + self._irq.pend(); + + Poll::Ready(Ok(n)) + }) + } + + /// Try writing a buffer without waiting, returning how many bytes were written. + pub fn try_write(&mut self, buf: &[u8]) -> Result { + //trace!("poll_write: {:?}", buf.len()); + let s = self.buffered_state; + let mut tx = unsafe { s.tx_buf.writer() }; + + let tx_buf = tx.push_slice(); + if tx_buf.is_empty() { + return Ok(0); + } + + let n = min(tx_buf.len(), buf.len()); + tx_buf[..n].copy_from_slice(&buf[..n]); + tx.push_done(n); + + //trace!("poll_write: queued {:?}", n); + + compiler_fence(Ordering::SeqCst); + self._irq.pend(); + + Ok(n) + } + + /// Flush this output stream, ensuring that all intermediately buffered contents reach their destination. + pub fn flush(&mut self) -> impl Future> + '_ { + let ss = self.state; + let s = self.buffered_state; + poll_fn(move |cx| { + //trace!("poll_flush"); + if !s.tx_buf.is_empty() { + //trace!("poll_flush: pending"); + ss.tx_waker.register(cx.waker()); + return Poll::Pending; + } + + Poll::Ready(Ok(())) + }) + } + + /// Adjust the baud rate to the provided value. + pub fn set_baudrate(&mut self, baudrate: Baudrate) { + self.r.baudrate().write(|w| w.set_baudrate(baudrate)); + } +} + +impl<'a> Drop for BufferedUarteTx<'a> { + fn drop(&mut self) { + let r = self.r; + + r.intenclr().write(|w| { + w.set_txdrdy(true); + w.set_dmatxready(true); + w.set_txstopped(true); + }); + r.events_txstopped().write_value(0); + r.tasks_dma().tx().stop().write_value(1); + while r.events_txstopped().read() == 0 {} + + let s = self.buffered_state; + unsafe { s.tx_buf.deinit() } + + let s = self.state; + drop_tx_rx(r, s); + } +} + +/// Reader part of the buffered UARTE driver. +pub struct BufferedUarteRx<'d> { + r: pac::uarte::Uarte, + state: &'static crate::uarte::State, + buffered_state: &'static State, + timer: Timer<'d>, + _ppi_ch1: Ppi<'d, AnyConfigurableChannel, 1, 1>, + _ppi_ch2: Ppi<'d, AnyConfigurableChannel, 1, 2>, + _ppi_group: PpiGroup<'d, AnyGroup>, + _p: PhantomData<&'d ()>, +} + +impl<'d> BufferedUarteRx<'d> { + /// Create a new BufferedUarte without hardware flow control. + /// + /// # Panics + /// + /// Panics if `rx_buffer.len()` is odd. + #[allow(clippy::too_many_arguments)] + pub fn new( + uarte: Peri<'d, U>, + timer: Peri<'d, T>, + ppi_ch1: Peri<'d, impl ConfigurableChannel>, + ppi_ch2: Peri<'d, impl ConfigurableChannel>, + ppi_group: Peri<'d, impl Group>, + _irq: impl interrupt::typelevel::Binding> + 'd, + rxd: Peri<'d, impl GpioPin>, + config: Config, + rx_buffer: &'d mut [u8], + ) -> Self { + Self::new_inner( + uarte, + timer, + ppi_ch1.into(), + ppi_ch2.into(), + ppi_group.into(), + rxd.into(), + None, + config, + rx_buffer, + ) + } + + /// Create a new BufferedUarte with hardware flow control (RTS/CTS) + /// + /// # Panics + /// + /// Panics if `rx_buffer.len()` is odd. + #[allow(clippy::too_many_arguments)] + pub fn new_with_rts( + uarte: Peri<'d, U>, + timer: Peri<'d, T>, + ppi_ch1: Peri<'d, impl ConfigurableChannel>, + ppi_ch2: Peri<'d, impl ConfigurableChannel>, + ppi_group: Peri<'d, impl Group>, + rxd: Peri<'d, impl GpioPin>, + rts: Peri<'d, impl GpioPin>, + _irq: impl interrupt::typelevel::Binding> + 'd, + config: Config, + rx_buffer: &'d mut [u8], + ) -> Self { + Self::new_inner( + uarte, + timer, + ppi_ch1.into(), + ppi_ch2.into(), + ppi_group.into(), + rxd.into(), + Some(rts.into()), + config, + rx_buffer, + ) + } + + #[allow(clippy::too_many_arguments)] + fn new_inner( + peri: Peri<'d, U>, + timer: Peri<'d, T>, + ppi_ch1: Peri<'d, AnyConfigurableChannel>, + ppi_ch2: Peri<'d, AnyConfigurableChannel>, + ppi_group: Peri<'d, AnyGroup>, + rxd: Peri<'d, AnyPin>, + rts: Option>, + config: Config, + rx_buffer: &'d mut [u8], + ) -> Self { + let r = U::regs(); + let irq = U::Interrupt::IRQ; + let state = U::state(); + let _buffered_state = U::buffered_state(); + + configure(r, config, rts.is_some()); + + let this = Self::new_innerer(peri, timer, ppi_ch1, ppi_ch2, ppi_group, rxd, rts, rx_buffer); + + r.enable().write(|w| w.set_enable(vals::Enable::ENABLED)); + irq.pend(); + unsafe { irq.enable() }; + + state.tx_rx_refcount.store(1, Ordering::Relaxed); + + this + } + + #[allow(clippy::too_many_arguments)] + fn new_innerer( + _peri: Peri<'d, U>, + timer: Peri<'d, T>, + ppi_ch1: Peri<'d, AnyConfigurableChannel>, + ppi_ch2: Peri<'d, AnyConfigurableChannel>, + ppi_group: Peri<'d, AnyGroup>, + rxd: Peri<'d, AnyPin>, + rts: Option>, + rx_buffer: &'d mut [u8], + ) -> Self { + assert!(rx_buffer.len() % 2 == 0); + + let r = U::regs(); + let state = U::state(); + let buffered_state = U::buffered_state(); + + configure_rx_pins(r, rxd, rts); + + // Initialize state + buffered_state.rx_started_count.store(0, Ordering::Relaxed); + buffered_state.rx_ended_count.store(0, Ordering::Relaxed); + buffered_state.rx_started.store(false, Ordering::Relaxed); + buffered_state.rx_overrun.store(false, Ordering::Relaxed); + let rx_len = rx_buffer.len().min(EASY_DMA_SIZE * 2); + unsafe { buffered_state.rx_buf.init(rx_buffer.as_mut_ptr(), rx_len) }; + + // clear errors + let errors = r.errorsrc().read(); + r.errorsrc().write_value(errors); + + r.events_dma().rx().ready().write_value(0); + r.events_error().write_value(0); + r.events_dma().rx().end().write_value(0); + + // Enable interrupts + r.intenset().write(|w| { + w.set_dmatxend(true); + w.set_dmarxready(true); + w.set_error(true); + w.set_dmarxend(true); + }); + + // Configure byte counter. + let timer = Timer::new_counter(timer); + timer.cc(1).write(rx_len as u32 * 2); + timer.cc(1).short_compare_clear(); + timer.clear(); + timer.start(); + + let mut ppi_ch1 = Ppi::new_one_to_one(ppi_ch1, Event::from_reg(r.events_rxdrdy()), timer.task_count()); + ppi_ch1.enable(); + + buffered_state + .rx_ppi_ch + .store(ppi_ch2.number() as u8, Ordering::Relaxed); + let mut ppi_group = PpiGroup::new(ppi_group); + let mut ppi_ch2 = Ppi::new_one_to_two( + ppi_ch2, + Event::from_reg(r.events_dma().rx().end()), + Task::from_reg(r.tasks_dma().rx().start()), + ppi_group.task_disable_all(), + ); + ppi_ch2.disable(); + ppi_group.add_channel(&ppi_ch2); + + Self { + r, + state, + buffered_state, + timer, + _ppi_ch1: ppi_ch1, + _ppi_ch2: ppi_ch2, + _ppi_group: ppi_group, + _p: PhantomData, + } + } + + /// Pull some bytes from this source into the specified buffer, returning how many bytes were read. + pub async fn read(&mut self, buf: &mut [u8]) -> Result { + let data = self.fill_buf().await?; + let n = data.len().min(buf.len()); + buf[..n].copy_from_slice(&data[..n]); + self.consume(n); + Ok(n) + } + + /// Return the contents of the internal buffer, filling it with more data from the inner reader if it is empty. + pub fn fill_buf(&mut self) -> impl Future> { + let r = self.r; + let s = self.buffered_state; + let ss = self.state; + let timer = &self.timer; + poll_fn(move |cx| { + compiler_fence(Ordering::SeqCst); + //trace!("poll_read"); + + if s.rx_overrun.swap(false, Ordering::Acquire) { + return Poll::Ready(Err(Error::Overrun)); + } + + // Read the RXDRDY counter. + timer.cc(0).capture(); + let mut end = timer.cc(0).read() as usize; + //trace!(" rxdrdy count = {:?}", end); + + // We've set a compare channel that resets the counter to 0 when it reaches `len*2`. + // However, it's unclear if that's instant, or there's a small window where you can + // still read `len()*2`. + // This could happen if in one clock cycle the counter is updated, and in the next the + // clear takes effect. The docs are very sparse, they just say "Task delays: After TIMER + // is started, the CLEAR, COUNT, and STOP tasks are guaranteed to take effect within one + // clock cycle of the PCLK16M." :shrug: + // So, we wrap the counter ourselves, just in case. + if end > s.rx_buf.len() * 2 { + end = 0 + } + + // This logic mirrors `atomic_ring_buffer::Reader::pop_buf()` + let mut start = s.rx_buf.start.load(Ordering::Relaxed); + let len = s.rx_buf.len(); + if start == end { + //trace!(" empty"); + ss.rx_waker.register(cx.waker()); + r.intenset().write(|w| w.set_rxdrdy(true)); + return Poll::Pending; + } + + if start >= len { + start -= len + } + if end >= len { + end -= len + } + + let n = if end > start { end - start } else { len - start }; + assert!(n != 0); + //trace!(" uarte ringbuf: pop_buf {:?}..{:?}", start, start + n); + + let buf = s.rx_buf.buf.load(Ordering::Relaxed); + Poll::Ready(Ok(unsafe { slice::from_raw_parts(buf.add(start), n) })) + }) + } + + /// Tell this buffer that `amt` bytes have been consumed from the buffer, so they should no longer be returned in calls to `fill_buf`. + pub fn consume(&mut self, amt: usize) { + if amt == 0 { + return; + } + + let s = self.buffered_state; + let mut rx = unsafe { s.rx_buf.reader() }; + rx.pop_done(amt); + self.r.intenset().write(|w| w.set_dmarxready(true)); + } + + /// we are ready to read if there is data in the buffer + fn read_ready(&self) -> Result { + let state = self.buffered_state; + if state.rx_overrun.swap(false, Ordering::Acquire) { + return Err(Error::Overrun); + } + Ok(!state.rx_buf.is_empty()) + } +} + +impl<'a> Drop for BufferedUarteRx<'a> { + fn drop(&mut self) { + self._ppi_group.disable_all(); + + let r = self.r; + + self.timer.stop(); + + r.intenclr().write(|w| { + w.set_rxdrdy(true); + w.set_dmarxready(true); + w.set_rxto(true); + }); + r.events_rxto().write_value(0); + r.tasks_dma().rx().stop().write_value(1); + while r.events_rxto().read() == 0 {} + + let s = self.buffered_state; + unsafe { s.rx_buf.deinit() } + + let s = self.state; + drop_tx_rx(r, s); + } +} + +mod _embedded_io { + use super::*; + + impl embedded_io_async::Error for Error { + fn kind(&self) -> embedded_io_async::ErrorKind { + match *self { + Error::Overrun => embedded_io_async::ErrorKind::OutOfMemory, + } + } + } + + impl<'d> embedded_io_async::ErrorType for BufferedUarte<'d> { + type Error = Error; + } + + impl<'d> embedded_io_async::ErrorType for BufferedUarteRx<'d> { + type Error = Error; + } + + impl<'d> embedded_io_async::ErrorType for BufferedUarteTx<'d> { + type Error = Error; + } + + impl<'d> embedded_io_async::Read for BufferedUarte<'d> { + async fn read(&mut self, buf: &mut [u8]) -> Result { + self.read(buf).await + } + } + + impl<'d> embedded_io_async::Read for BufferedUarteRx<'d> { + async fn read(&mut self, buf: &mut [u8]) -> Result { + self.read(buf).await + } + } + + impl<'d> embedded_io_async::ReadReady for BufferedUarte<'d> { + fn read_ready(&mut self) -> Result { + self.rx.read_ready() + } + } + + impl<'d> embedded_io_async::ReadReady for BufferedUarteRx<'d> { + fn read_ready(&mut self) -> Result { + let state = self.buffered_state; + Ok(!state.rx_buf.is_empty()) + } + } + + impl<'d> embedded_io_async::BufRead for BufferedUarte<'d> { + async fn fill_buf(&mut self) -> Result<&[u8], Self::Error> { + self.fill_buf().await + } + + fn consume(&mut self, amt: usize) { + self.consume(amt) + } + } + + impl<'d> embedded_io_async::BufRead for BufferedUarteRx<'d> { + async fn fill_buf(&mut self) -> Result<&[u8], Self::Error> { + self.fill_buf().await + } + + fn consume(&mut self, amt: usize) { + self.consume(amt) + } + } + + impl<'d> embedded_io_async::Write for BufferedUarte<'d> { + async fn write(&mut self, buf: &[u8]) -> Result { + self.write(buf).await + } + + async fn flush(&mut self) -> Result<(), Self::Error> { + self.flush().await + } + } + + impl<'d> embedded_io_async::Write for BufferedUarteTx<'d> { + async fn write(&mut self, buf: &[u8]) -> Result { + self.write(buf).await + } + + async fn flush(&mut self) -> Result<(), Self::Error> { + self.flush().await + } + } +} diff --git a/embassy-nrf/src/buffered_uarte/v2.rs b/embassy-nrf/src/buffered_uarte/v2.rs new file mode 100644 index 000000000..d0d2d97d1 --- /dev/null +++ b/embassy-nrf/src/buffered_uarte/v2.rs @@ -0,0 +1,687 @@ +//! Async buffered UART driver. +//! +//! Note that discarding a future from a read or write operation may lead to losing +//! data. For example, when using `futures_util::future::select` and completion occurs +//! on the "other" future, you should capture the incomplete future and continue to use +//! it for the next read or write. This pattern is a consideration for all IO, and not +//! just serial communications. +//! +//! Please also see [crate::uarte] to understand when [BufferedUarte] should be used. +//! +//! The code is based on the generic buffered_uarte implementation but uses the nrf54l +//! frame timeout event to correctly determine the size of transferred data. +//! Counting of rxrdy events, used in the generic implementation, cannot be applied +//! to nrf54l chips, as they buffer up to 4 bytes in a single DMA transaction. +//! The only reliable way to find the number of bytes received is to stop the transfer, +//! wait for the DMA stopped event, and read the value in the rx.dma.amount register. +//! This also flushes all in-flight data to RAM. + +use core::cmp::min; +use core::future::{Future, poll_fn}; +use core::marker::PhantomData; +use core::slice; +use core::sync::atomic::{AtomicBool, AtomicUsize, Ordering, compiler_fence}; +use core::task::Poll; + +use embassy_hal_internal::Peri; +use embassy_hal_internal::atomic_ring_buffer::RingBuffer; +use pac::uarte::vals; +// Re-export SVD variants to allow user to directly set values +pub use pac::uarte::vals::{Baudrate, ConfigParity as Parity}; + +use crate::gpio::{AnyPin, Pin as GpioPin}; +use crate::interrupt::typelevel::Interrupt; +use crate::uarte::{Config, Instance as UarteInstance, configure, configure_rx_pins, configure_tx_pins, drop_tx_rx}; +use crate::{EASY_DMA_SIZE, interrupt, pac}; + +pub(crate) struct State { + tx_buf: RingBuffer, + tx_count: AtomicUsize, + + rx_buf: RingBuffer, + rx_started: AtomicBool, +} + +/// UART error. +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +#[cfg_attr(feature = "defmt", derive(defmt::Format))] +#[non_exhaustive] +pub enum Error { + // No errors for now +} + +impl State { + pub(crate) const fn new() -> Self { + Self { + tx_buf: RingBuffer::new(), + tx_count: AtomicUsize::new(0), + + rx_buf: RingBuffer::new(), + rx_started: AtomicBool::new(false), + } + } +} + +/// Interrupt handler. +pub struct InterruptHandler { + _phantom: PhantomData, +} + +impl interrupt::typelevel::Handler for InterruptHandler { + unsafe fn on_interrupt() { + info!("irq: start"); + let r = U::regs(); + let ss = U::state(); + let s = U::buffered_state(); + + if let Some(mut rx) = unsafe { s.rx_buf.try_writer() } { + let buf_len = s.rx_buf.len(); + let half_len = buf_len / 2; + + if r.events_error().read() != 0 { + r.events_error().write_value(0); + let errs = r.errorsrc().read(); + r.errorsrc().write_value(errs); + + if errs.overrun() { + panic!("BufferedUarte UART overrun"); + } + } + + let first_run = !s.rx_started.swap(true, Ordering::Relaxed); + if r.events_dma().rx().end().read() != 0 || first_run { + //trace!(" irq_rx: endrx"); + r.events_dma().rx().end().write_value(0); + + if !first_run { + // Received some bytes, wake task. + let rxed = r.dma().rx().amount().read().amount() as usize; + rx.push_done(rxed); + ss.rx_waker.wake(); + } + + let (ptr, len) = rx.push_buf(); + if len == 0 { + panic!("BufferedUarte buffer overrun"); + } + + let len = if len > half_len { half_len } else { len }; + + // Set up the DMA read + r.dma().rx().ptr().write_value(ptr as u32); + r.dma().rx().maxcnt().write(|w| w.set_maxcnt(len as _)); + + // manually start + r.tasks_dma().rx().start().write_value(1); + } + } + + // ============================= + + if let Some(mut tx) = unsafe { s.tx_buf.try_reader() } { + // TX end + if r.events_dma().tx().end().read() != 0 { + r.events_dma().tx().end().write_value(0); + + let n = s.tx_count.load(Ordering::Relaxed); + //trace!(" irq_tx: endtx {:?}", n); + tx.pop_done(n); + ss.tx_waker.wake(); + s.tx_count.store(0, Ordering::Relaxed); + } + + // If not TXing, start. + if s.tx_count.load(Ordering::Relaxed) == 0 { + let (ptr, len) = tx.pop_buf(); + let len = len.min(EASY_DMA_SIZE); + if len != 0 { + //trace!(" irq_tx: starting {:?}", len); + s.tx_count.store(len, Ordering::Relaxed); + + // Set up the DMA write + r.dma().tx().ptr().write_value(ptr as u32); + r.dma().tx().maxcnt().write(|w| w.set_maxcnt(len as _)); + + // Start UARTE Transmit transaction + r.tasks_dma().tx().start().write_value(1); + } + } + } + + //trace!("irq: end"); + } +} + +/// Buffered UARTE driver. +pub struct BufferedUarte<'d, U: UarteInstance> { + tx: BufferedUarteTx<'d, U>, + rx: BufferedUarteRx<'d, U>, +} + +impl<'d, U: UarteInstance> Unpin for BufferedUarte<'d, U> {} + +impl<'d, U: UarteInstance> BufferedUarte<'d, U> { + /// Create a new BufferedUarte without hardware flow control. + #[allow(clippy::too_many_arguments)] + pub fn new( + uarte: Peri<'d, U>, + rxd: Peri<'d, impl GpioPin>, + txd: Peri<'d, impl GpioPin>, + _irq: impl interrupt::typelevel::Binding> + 'd, + config: Config, + rx_buffer: &'d mut [u8], + tx_buffer: &'d mut [u8], + ) -> Self { + Self::new_inner(uarte, rxd.into(), txd.into(), None, None, config, rx_buffer, tx_buffer) + } + + /// Create a new BufferedUarte with hardware flow control (RTS/CTS) + #[allow(clippy::too_many_arguments)] + pub fn new_with_rtscts( + uarte: Peri<'d, U>, + rxd: Peri<'d, impl GpioPin>, + txd: Peri<'d, impl GpioPin>, + cts: Peri<'d, impl GpioPin>, + rts: Peri<'d, impl GpioPin>, + _irq: impl interrupt::typelevel::Binding> + 'd, + config: Config, + rx_buffer: &'d mut [u8], + tx_buffer: &'d mut [u8], + ) -> Self { + Self::new_inner( + uarte, + rxd.into(), + txd.into(), + Some(cts.into()), + Some(rts.into()), + config, + rx_buffer, + tx_buffer, + ) + } + + #[allow(clippy::too_many_arguments)] + fn new_inner( + peri: Peri<'d, U>, + rxd: Peri<'d, AnyPin>, + txd: Peri<'d, AnyPin>, + cts: Option>, + rts: Option>, + config: Config, + rx_buffer: &'d mut [u8], + tx_buffer: &'d mut [u8], + ) -> Self { + configure(U::regs(), config, cts.is_some()); + + let tx = BufferedUarteTx::new_innerer(unsafe { peri.clone_unchecked() }, txd, cts, tx_buffer); + let rx = BufferedUarteRx::new_innerer(peri, rxd, rts, rx_buffer); + + U::regs().enable().write(|w| w.set_enable(vals::Enable::ENABLED)); + U::Interrupt::pend(); + unsafe { U::Interrupt::enable() }; + + U::state().tx_rx_refcount.store(2, Ordering::Relaxed); + + Self { tx, rx } + } + + /// Adjust the baud rate to the provided value. + pub fn set_baudrate(&mut self, baudrate: Baudrate) { + let r = U::regs(); + r.baudrate().write(|w| w.set_baudrate(baudrate)); + } + + /// Split the UART in reader and writer parts. + /// + /// This allows reading and writing concurrently from independent tasks. + pub fn split(self) -> (BufferedUarteRx<'d, U>, BufferedUarteTx<'d, U>) { + (self.rx, self.tx) + } + + /// Split the UART in reader and writer parts, by reference. + /// + /// The returned halves borrow from `self`, so you can drop them and go back to using + /// the "un-split" `self`. This allows temporarily splitting the UART. + pub fn split_by_ref(&mut self) -> (&mut BufferedUarteRx<'d, U>, &mut BufferedUarteTx<'d, U>) { + (&mut self.rx, &mut self.tx) + } + + /// Pull some bytes from this source into the specified buffer, returning how many bytes were read. + pub async fn read(&mut self, buf: &mut [u8]) -> Result { + self.rx.read(buf).await + } + + /// Return the contents of the internal buffer, filling it with more data from the inner reader if it is empty. + pub async fn fill_buf(&mut self) -> Result<&[u8], Error> { + self.rx.fill_buf().await + } + + /// Tell this buffer that `amt` bytes have been consumed from the buffer, so they should no longer be returned in calls to `fill_buf`. + pub fn consume(&mut self, amt: usize) { + self.rx.consume(amt) + } + + /// Write a buffer into this writer, returning how many bytes were written. + pub async fn write(&mut self, buf: &[u8]) -> Result { + self.tx.write(buf).await + } + + /// Try writing a buffer without waiting, returning how many bytes were written. + pub fn try_write(&mut self, buf: &[u8]) -> Result { + self.tx.try_write(buf) + } + + /// Flush this output stream, ensuring that all intermediately buffered contents reach their destination. + pub async fn flush(&mut self) -> Result<(), Error> { + self.tx.flush().await + } +} + +/// Reader part of the buffered UARTE driver. +pub struct BufferedUarteTx<'d, U: UarteInstance> { + _peri: Peri<'d, U>, +} + +impl<'d, U: UarteInstance> BufferedUarteTx<'d, U> { + /// Create a new BufferedUarteTx without hardware flow control. + pub fn new( + uarte: Peri<'d, U>, + txd: Peri<'d, impl GpioPin>, + _irq: impl interrupt::typelevel::Binding> + 'd, + config: Config, + tx_buffer: &'d mut [u8], + ) -> Self { + Self::new_inner(uarte, txd.into(), None, config, tx_buffer) + } + + /// Create a new BufferedUarte with hardware flow control (RTS/CTS) + pub fn new_with_cts( + uarte: Peri<'d, U>, + txd: Peri<'d, impl GpioPin>, + cts: Peri<'d, impl GpioPin>, + _irq: impl interrupt::typelevel::Binding> + 'd, + config: Config, + tx_buffer: &'d mut [u8], + ) -> Self { + Self::new_inner(uarte, txd.into(), Some(cts.into()), config, tx_buffer) + } + + fn new_inner( + peri: Peri<'d, U>, + txd: Peri<'d, AnyPin>, + cts: Option>, + config: Config, + tx_buffer: &'d mut [u8], + ) -> Self { + configure(U::regs(), config, cts.is_some()); + + let this = Self::new_innerer(peri, txd, cts, tx_buffer); + + U::regs().enable().write(|w| w.set_enable(vals::Enable::ENABLED)); + U::Interrupt::pend(); + unsafe { U::Interrupt::enable() }; + + U::state().tx_rx_refcount.store(1, Ordering::Relaxed); + + this + } + + fn new_innerer( + peri: Peri<'d, U>, + txd: Peri<'d, AnyPin>, + cts: Option>, + tx_buffer: &'d mut [u8], + ) -> Self { + let r = U::regs(); + + configure_tx_pins(r, txd, cts); + + // Initialize state + let s = U::buffered_state(); + s.tx_count.store(0, Ordering::Relaxed); + let len = tx_buffer.len(); + unsafe { s.tx_buf.init(tx_buffer.as_mut_ptr(), len) }; + + r.events_dma().tx().ready().write_value(0); + + // Enable interrupts + r.intenset().write(|w| { + w.set_dmatxend(true); + }); + + Self { _peri: peri } + } + + /// Write a buffer into this writer, returning how many bytes were written. + pub fn write<'a>(&'a mut self, buf: &'a [u8]) -> impl Future> + 'a { + poll_fn(move |cx| { + //trace!("poll_write: {:?}", buf.len()); + let ss = U::state(); + let s = U::buffered_state(); + let mut tx = unsafe { s.tx_buf.writer() }; + + let tx_buf = tx.push_slice(); + if tx_buf.is_empty() { + //trace!("poll_write: pending"); + ss.tx_waker.register(cx.waker()); + return Poll::Pending; + } + + let n = min(tx_buf.len(), buf.len()); + tx_buf[..n].copy_from_slice(&buf[..n]); + tx.push_done(n); + + //trace!("poll_write: queued {:?}", n); + + compiler_fence(Ordering::SeqCst); + U::Interrupt::pend(); + + Poll::Ready(Ok(n)) + }) + } + + /// Try writing a buffer without waiting, returning how many bytes were written. + pub fn try_write(&mut self, buf: &[u8]) -> Result { + //trace!("poll_write: {:?}", buf.len()); + let s = U::buffered_state(); + let mut tx = unsafe { s.tx_buf.writer() }; + + let tx_buf = tx.push_slice(); + if tx_buf.is_empty() { + return Ok(0); + } + + let n = min(tx_buf.len(), buf.len()); + tx_buf[..n].copy_from_slice(&buf[..n]); + tx.push_done(n); + + //trace!("poll_write: queued {:?}", n); + + compiler_fence(Ordering::SeqCst); + U::Interrupt::pend(); + + Ok(n) + } + + /// Flush this output stream, ensuring that all intermediately buffered contents reach their destination. + pub fn flush(&mut self) -> impl Future> + '_ { + poll_fn(move |cx| { + //trace!("poll_flush"); + let ss = U::state(); + let s = U::buffered_state(); + if !s.tx_buf.is_empty() { + //trace!("poll_flush: pending"); + ss.tx_waker.register(cx.waker()); + return Poll::Pending; + } + + Poll::Ready(Ok(())) + }) + } +} + +impl<'a, U: UarteInstance> Drop for BufferedUarteTx<'a, U> { + fn drop(&mut self) { + let r = U::regs(); + + r.intenclr().write(|w| { + w.set_txdrdy(true); + w.set_dmatxready(true); + w.set_txstopped(true); + }); + r.events_txstopped().write_value(0); + r.tasks_dma().tx().stop().write_value(1); + while r.events_txstopped().read() == 0 {} + + let s = U::buffered_state(); + unsafe { s.tx_buf.deinit() } + + let s = U::state(); + drop_tx_rx(r, s); + } +} + +/// Reader part of the buffered UARTE driver. +pub struct BufferedUarteRx<'d, U: UarteInstance> { + _peri: Peri<'d, U>, +} + +impl<'d, U: UarteInstance> BufferedUarteRx<'d, U> { + /// Create a new BufferedUarte without hardware flow control. + #[allow(clippy::too_many_arguments)] + pub fn new( + uarte: Peri<'d, U>, + _irq: impl interrupt::typelevel::Binding> + 'd, + rxd: Peri<'d, impl GpioPin>, + config: Config, + rx_buffer: &'d mut [u8], + ) -> Self { + Self::new_inner(uarte, rxd.into(), None, config, rx_buffer) + } + + /// Create a new BufferedUarte with hardware flow control (RTS/CTS) + #[allow(clippy::too_many_arguments)] + pub fn new_with_rts( + uarte: Peri<'d, U>, + rxd: Peri<'d, impl GpioPin>, + rts: Peri<'d, impl GpioPin>, + _irq: impl interrupt::typelevel::Binding> + 'd, + config: Config, + rx_buffer: &'d mut [u8], + ) -> Self { + Self::new_inner(uarte, rxd.into(), Some(rts.into()), config, rx_buffer) + } + + #[allow(clippy::too_many_arguments)] + fn new_inner( + peri: Peri<'d, U>, + rxd: Peri<'d, AnyPin>, + rts: Option>, + config: Config, + rx_buffer: &'d mut [u8], + ) -> Self { + configure(U::regs(), config, rts.is_some()); + + let this = Self::new_innerer(peri, rxd, rts, rx_buffer); + + U::regs().enable().write(|w| w.set_enable(vals::Enable::ENABLED)); + U::Interrupt::pend(); + unsafe { U::Interrupt::enable() }; + + U::state().tx_rx_refcount.store(1, Ordering::Relaxed); + + this + } + + #[allow(clippy::too_many_arguments)] + fn new_innerer( + peri: Peri<'d, U>, + rxd: Peri<'d, AnyPin>, + rts: Option>, + rx_buffer: &'d mut [u8], + ) -> Self { + let r = U::regs(); + + configure_rx_pins(r, rxd, rts); + + // Initialize state + let s = U::buffered_state(); + let rx_len = rx_buffer.len().min(EASY_DMA_SIZE * 2); + let rx_ptr = rx_buffer.as_mut_ptr(); + unsafe { s.rx_buf.init(rx_ptr, rx_len) }; + + // clear errors + let errors = r.errorsrc().read(); + r.errorsrc().write_value(errors); + + r.events_error().write_value(0); + r.events_dma().rx().end().write_value(0); + + // set timeout-to-stop short + r.shorts().write(|w| { + w.set_frametimeout_dma_rx_stop(true); + }); + + // set default timeout + r.frametimeout().write_value(pac::uarte::regs::Frametimeout(0x10)); + + // Enable interrupts + r.intenset().write(|w| { + w.set_dmatxend(true); + w.set_error(true); + w.set_dmarxend(true); + }); + + Self { _peri: peri } + } + + /// Pull some bytes from this source into the specified buffer, returning how many bytes were read. + pub async fn read(&mut self, buf: &mut [u8]) -> Result { + let data = self.fill_buf().await?; + let n = data.len().min(buf.len()); + buf[..n].copy_from_slice(&data[..n]); + self.consume(n); + Ok(n) + } + + /// Return the contents of the internal buffer, filling it with more data from the inner reader if it is empty. + pub fn fill_buf(&mut self) -> impl Future> { + poll_fn(move |cx| { + compiler_fence(Ordering::SeqCst); + //trace!("poll_read"); + + let s = U::buffered_state(); + let ss = U::state(); + let mut rx = unsafe { s.rx_buf.reader() }; + + let (ptr, n) = rx.pop_buf(); + if n == 0 { + //trace!(" empty"); + ss.rx_waker.register(cx.waker()); + Poll::Pending + } else { + Poll::Ready(Ok(unsafe { slice::from_raw_parts(ptr, n) })) + } + }) + } + + /// Tell this buffer that `amt` bytes have been consumed from the buffer, so they should no longer be returned in calls to `fill_buf`. + pub fn consume(&mut self, amt: usize) { + if amt == 0 { + return; + } + + let s = U::buffered_state(); + let mut rx = unsafe { s.rx_buf.reader() }; + rx.pop_done(amt); + } + + /// we are ready to read if there is data in the buffer + fn read_ready() -> Result { + let state = U::buffered_state(); + Ok(!state.rx_buf.is_empty()) + } +} + +impl<'a, U: UarteInstance> Drop for BufferedUarteRx<'a, U> { + fn drop(&mut self) { + let r = U::regs(); + + r.intenclr().write(|w| { + w.set_rxto(true); + }); + r.events_rxto().write_value(0); + + let s = U::buffered_state(); + unsafe { s.rx_buf.deinit() } + + let s = U::state(); + drop_tx_rx(r, s); + } +} + +mod _embedded_io { + use super::*; + + impl embedded_io_async::Error for Error { + fn kind(&self) -> embedded_io_async::ErrorKind { + match *self {} + } + } + + impl<'d, U: UarteInstance> embedded_io_async::ErrorType for BufferedUarte<'d, U> { + type Error = Error; + } + + impl<'d, U: UarteInstance> embedded_io_async::ErrorType for BufferedUarteRx<'d, U> { + type Error = Error; + } + + impl<'d, U: UarteInstance> embedded_io_async::ErrorType for BufferedUarteTx<'d, U> { + type Error = Error; + } + + impl<'d, U: UarteInstance> embedded_io_async::Read for BufferedUarte<'d, U> { + async fn read(&mut self, buf: &mut [u8]) -> Result { + self.read(buf).await + } + } + + impl<'d: 'd, U: UarteInstance> embedded_io_async::Read for BufferedUarteRx<'d, U> { + async fn read(&mut self, buf: &mut [u8]) -> Result { + self.read(buf).await + } + } + + impl<'d, U: UarteInstance> embedded_io_async::ReadReady for BufferedUarte<'d, U> { + fn read_ready(&mut self) -> Result { + BufferedUarteRx::<'d, U>::read_ready() + } + } + + impl<'d, U: UarteInstance> embedded_io_async::ReadReady for BufferedUarteRx<'d, U> { + fn read_ready(&mut self) -> Result { + Self::read_ready() + } + } + + impl<'d, U: UarteInstance> embedded_io_async::BufRead for BufferedUarte<'d, U> { + async fn fill_buf(&mut self) -> Result<&[u8], Self::Error> { + self.fill_buf().await + } + + fn consume(&mut self, amt: usize) { + self.consume(amt) + } + } + + impl<'d: 'd, U: UarteInstance> embedded_io_async::BufRead for BufferedUarteRx<'d, U> { + async fn fill_buf(&mut self) -> Result<&[u8], Self::Error> { + self.fill_buf().await + } + + fn consume(&mut self, amt: usize) { + self.consume(amt) + } + } + + impl<'d, U: UarteInstance> embedded_io_async::Write for BufferedUarte<'d, U> { + async fn write(&mut self, buf: &[u8]) -> Result { + self.write(buf).await + } + + async fn flush(&mut self) -> Result<(), Self::Error> { + self.flush().await + } + } + + impl<'d: 'd, U: UarteInstance> embedded_io_async::Write for BufferedUarteTx<'d, U> { + async fn write(&mut self, buf: &[u8]) -> Result { + self.write(buf).await + } + + async fn flush(&mut self) -> Result<(), Self::Error> { + self.flush().await + } + } +} diff --git a/embassy-nrf/src/chips/nrf51.rs b/embassy-nrf/src/chips/nrf51.rs index 3976e8ff0..1184c4409 100644 --- a/embassy-nrf/src/chips/nrf51.rs +++ b/embassy-nrf/src/chips/nrf51.rs @@ -115,6 +115,11 @@ impl_rtc!(RTC0, RTC0, RTC0); #[cfg(not(feature = "time-driver-rtc1"))] impl_rtc!(RTC1, RTC1, RTC1); +impl_ppi_group!(PPI_GROUP0, PPI, 0); +impl_ppi_group!(PPI_GROUP1, PPI, 1); +impl_ppi_group!(PPI_GROUP2, PPI, 2); +impl_ppi_group!(PPI_GROUP3, PPI, 3); + impl_pin!(P0_00, 0, 0); impl_pin!(P0_01, 0, 1); impl_pin!(P0_02, 0, 2); diff --git a/embassy-nrf/src/chips/nrf52805.rs b/embassy-nrf/src/chips/nrf52805.rs index 63ba6999a..dd2e66927 100644 --- a/embassy-nrf/src/chips/nrf52805.rs +++ b/embassy-nrf/src/chips/nrf52805.rs @@ -195,28 +195,35 @@ impl_pin!(P0_29, 0, 29); impl_pin!(P0_30, 0, 30); impl_pin!(P0_31, 0, 31); -impl_ppi_channel!(PPI_CH0, 0 => configurable); -impl_ppi_channel!(PPI_CH1, 1 => configurable); -impl_ppi_channel!(PPI_CH2, 2 => configurable); -impl_ppi_channel!(PPI_CH3, 3 => configurable); -impl_ppi_channel!(PPI_CH4, 4 => configurable); -impl_ppi_channel!(PPI_CH5, 5 => configurable); -impl_ppi_channel!(PPI_CH6, 6 => configurable); -impl_ppi_channel!(PPI_CH7, 7 => configurable); -impl_ppi_channel!(PPI_CH8, 8 => configurable); -impl_ppi_channel!(PPI_CH9, 9 => configurable); -impl_ppi_channel!(PPI_CH20, 20 => static); -impl_ppi_channel!(PPI_CH21, 21 => static); -impl_ppi_channel!(PPI_CH22, 22 => static); -impl_ppi_channel!(PPI_CH23, 23 => static); -impl_ppi_channel!(PPI_CH24, 24 => static); -impl_ppi_channel!(PPI_CH25, 25 => static); -impl_ppi_channel!(PPI_CH26, 26 => static); -impl_ppi_channel!(PPI_CH27, 27 => static); -impl_ppi_channel!(PPI_CH28, 28 => static); -impl_ppi_channel!(PPI_CH29, 29 => static); -impl_ppi_channel!(PPI_CH30, 30 => static); -impl_ppi_channel!(PPI_CH31, 31 => static); +impl_ppi_channel!(PPI_CH0, PPI, 0 => configurable); +impl_ppi_channel!(PPI_CH1, PPI, 1 => configurable); +impl_ppi_channel!(PPI_CH2, PPI, 2 => configurable); +impl_ppi_channel!(PPI_CH3, PPI, 3 => configurable); +impl_ppi_channel!(PPI_CH4, PPI, 4 => configurable); +impl_ppi_channel!(PPI_CH5, PPI, 5 => configurable); +impl_ppi_channel!(PPI_CH6, PPI, 6 => configurable); +impl_ppi_channel!(PPI_CH7, PPI, 7 => configurable); +impl_ppi_channel!(PPI_CH8, PPI, 8 => configurable); +impl_ppi_channel!(PPI_CH9, PPI, 9 => configurable); +impl_ppi_channel!(PPI_CH20, PPI, 20 => static); +impl_ppi_channel!(PPI_CH21, PPI, 21 => static); +impl_ppi_channel!(PPI_CH22, PPI, 22 => static); +impl_ppi_channel!(PPI_CH23, PPI, 23 => static); +impl_ppi_channel!(PPI_CH24, PPI, 24 => static); +impl_ppi_channel!(PPI_CH25, PPI, 25 => static); +impl_ppi_channel!(PPI_CH26, PPI, 26 => static); +impl_ppi_channel!(PPI_CH27, PPI, 27 => static); +impl_ppi_channel!(PPI_CH28, PPI, 28 => static); +impl_ppi_channel!(PPI_CH29, PPI, 29 => static); +impl_ppi_channel!(PPI_CH30, PPI, 30 => static); +impl_ppi_channel!(PPI_CH31, PPI, 31 => static); + +impl_ppi_group!(PPI_GROUP0, PPI, 0); +impl_ppi_group!(PPI_GROUP1, PPI, 1); +impl_ppi_group!(PPI_GROUP2, PPI, 2); +impl_ppi_group!(PPI_GROUP3, PPI, 3); +impl_ppi_group!(PPI_GROUP4, PPI, 4); +impl_ppi_group!(PPI_GROUP5, PPI, 5); impl_saadc_input!(P0_04, ANALOG_INPUT2); impl_saadc_input!(P0_05, ANALOG_INPUT3); diff --git a/embassy-nrf/src/chips/nrf52810.rs b/embassy-nrf/src/chips/nrf52810.rs index 7f744f9fb..7acb53a03 100644 --- a/embassy-nrf/src/chips/nrf52810.rs +++ b/embassy-nrf/src/chips/nrf52810.rs @@ -205,38 +205,45 @@ impl_pin!(P0_29, 0, 29); impl_pin!(P0_30, 0, 30); impl_pin!(P0_31, 0, 31); -impl_ppi_channel!(PPI_CH0, 0 => configurable); -impl_ppi_channel!(PPI_CH1, 1 => configurable); -impl_ppi_channel!(PPI_CH2, 2 => configurable); -impl_ppi_channel!(PPI_CH3, 3 => configurable); -impl_ppi_channel!(PPI_CH4, 4 => configurable); -impl_ppi_channel!(PPI_CH5, 5 => configurable); -impl_ppi_channel!(PPI_CH6, 6 => configurable); -impl_ppi_channel!(PPI_CH7, 7 => configurable); -impl_ppi_channel!(PPI_CH8, 8 => configurable); -impl_ppi_channel!(PPI_CH9, 9 => configurable); -impl_ppi_channel!(PPI_CH10, 10 => configurable); -impl_ppi_channel!(PPI_CH11, 11 => configurable); -impl_ppi_channel!(PPI_CH12, 12 => configurable); -impl_ppi_channel!(PPI_CH13, 13 => configurable); -impl_ppi_channel!(PPI_CH14, 14 => configurable); -impl_ppi_channel!(PPI_CH15, 15 => configurable); -impl_ppi_channel!(PPI_CH16, 16 => configurable); -impl_ppi_channel!(PPI_CH17, 17 => configurable); -impl_ppi_channel!(PPI_CH18, 18 => configurable); -impl_ppi_channel!(PPI_CH19, 19 => configurable); -impl_ppi_channel!(PPI_CH20, 20 => static); -impl_ppi_channel!(PPI_CH21, 21 => static); -impl_ppi_channel!(PPI_CH22, 22 => static); -impl_ppi_channel!(PPI_CH23, 23 => static); -impl_ppi_channel!(PPI_CH24, 24 => static); -impl_ppi_channel!(PPI_CH25, 25 => static); -impl_ppi_channel!(PPI_CH26, 26 => static); -impl_ppi_channel!(PPI_CH27, 27 => static); -impl_ppi_channel!(PPI_CH28, 28 => static); -impl_ppi_channel!(PPI_CH29, 29 => static); -impl_ppi_channel!(PPI_CH30, 30 => static); -impl_ppi_channel!(PPI_CH31, 31 => static); +impl_ppi_channel!(PPI_CH0, PPI, 0 => configurable); +impl_ppi_channel!(PPI_CH1, PPI, 1 => configurable); +impl_ppi_channel!(PPI_CH2, PPI, 2 => configurable); +impl_ppi_channel!(PPI_CH3, PPI, 3 => configurable); +impl_ppi_channel!(PPI_CH4, PPI, 4 => configurable); +impl_ppi_channel!(PPI_CH5, PPI, 5 => configurable); +impl_ppi_channel!(PPI_CH6, PPI, 6 => configurable); +impl_ppi_channel!(PPI_CH7, PPI, 7 => configurable); +impl_ppi_channel!(PPI_CH8, PPI, 8 => configurable); +impl_ppi_channel!(PPI_CH9, PPI, 9 => configurable); +impl_ppi_channel!(PPI_CH10, PPI, 10 => configurable); +impl_ppi_channel!(PPI_CH11, PPI, 11 => configurable); +impl_ppi_channel!(PPI_CH12, PPI, 12 => configurable); +impl_ppi_channel!(PPI_CH13, PPI, 13 => configurable); +impl_ppi_channel!(PPI_CH14, PPI, 14 => configurable); +impl_ppi_channel!(PPI_CH15, PPI, 15 => configurable); +impl_ppi_channel!(PPI_CH16, PPI, 16 => configurable); +impl_ppi_channel!(PPI_CH17, PPI, 17 => configurable); +impl_ppi_channel!(PPI_CH18, PPI, 18 => configurable); +impl_ppi_channel!(PPI_CH19, PPI, 19 => configurable); +impl_ppi_channel!(PPI_CH20, PPI, 20 => static); +impl_ppi_channel!(PPI_CH21, PPI, 21 => static); +impl_ppi_channel!(PPI_CH22, PPI, 22 => static); +impl_ppi_channel!(PPI_CH23, PPI, 23 => static); +impl_ppi_channel!(PPI_CH24, PPI, 24 => static); +impl_ppi_channel!(PPI_CH25, PPI, 25 => static); +impl_ppi_channel!(PPI_CH26, PPI, 26 => static); +impl_ppi_channel!(PPI_CH27, PPI, 27 => static); +impl_ppi_channel!(PPI_CH28, PPI, 28 => static); +impl_ppi_channel!(PPI_CH29, PPI, 29 => static); +impl_ppi_channel!(PPI_CH30, PPI, 30 => static); +impl_ppi_channel!(PPI_CH31, PPI, 31 => static); + +impl_ppi_group!(PPI_GROUP0, PPI, 0); +impl_ppi_group!(PPI_GROUP1, PPI, 1); +impl_ppi_group!(PPI_GROUP2, PPI, 2); +impl_ppi_group!(PPI_GROUP3, PPI, 3); +impl_ppi_group!(PPI_GROUP4, PPI, 4); +impl_ppi_group!(PPI_GROUP5, PPI, 5); impl_saadc_input!(P0_02, ANALOG_INPUT0); impl_saadc_input!(P0_03, ANALOG_INPUT1); diff --git a/embassy-nrf/src/chips/nrf52811.rs b/embassy-nrf/src/chips/nrf52811.rs index 908167e31..4178ef6cd 100644 --- a/embassy-nrf/src/chips/nrf52811.rs +++ b/embassy-nrf/src/chips/nrf52811.rs @@ -207,38 +207,45 @@ impl_pin!(P0_29, 0, 29); impl_pin!(P0_30, 0, 30); impl_pin!(P0_31, 0, 31); -impl_ppi_channel!(PPI_CH0, 0 => configurable); -impl_ppi_channel!(PPI_CH1, 1 => configurable); -impl_ppi_channel!(PPI_CH2, 2 => configurable); -impl_ppi_channel!(PPI_CH3, 3 => configurable); -impl_ppi_channel!(PPI_CH4, 4 => configurable); -impl_ppi_channel!(PPI_CH5, 5 => configurable); -impl_ppi_channel!(PPI_CH6, 6 => configurable); -impl_ppi_channel!(PPI_CH7, 7 => configurable); -impl_ppi_channel!(PPI_CH8, 8 => configurable); -impl_ppi_channel!(PPI_CH9, 9 => configurable); -impl_ppi_channel!(PPI_CH10, 10 => configurable); -impl_ppi_channel!(PPI_CH11, 11 => configurable); -impl_ppi_channel!(PPI_CH12, 12 => configurable); -impl_ppi_channel!(PPI_CH13, 13 => configurable); -impl_ppi_channel!(PPI_CH14, 14 => configurable); -impl_ppi_channel!(PPI_CH15, 15 => configurable); -impl_ppi_channel!(PPI_CH16, 16 => configurable); -impl_ppi_channel!(PPI_CH17, 17 => configurable); -impl_ppi_channel!(PPI_CH18, 18 => configurable); -impl_ppi_channel!(PPI_CH19, 19 => configurable); -impl_ppi_channel!(PPI_CH20, 20 => static); -impl_ppi_channel!(PPI_CH21, 21 => static); -impl_ppi_channel!(PPI_CH22, 22 => static); -impl_ppi_channel!(PPI_CH23, 23 => static); -impl_ppi_channel!(PPI_CH24, 24 => static); -impl_ppi_channel!(PPI_CH25, 25 => static); -impl_ppi_channel!(PPI_CH26, 26 => static); -impl_ppi_channel!(PPI_CH27, 27 => static); -impl_ppi_channel!(PPI_CH28, 28 => static); -impl_ppi_channel!(PPI_CH29, 29 => static); -impl_ppi_channel!(PPI_CH30, 30 => static); -impl_ppi_channel!(PPI_CH31, 31 => static); +impl_ppi_channel!(PPI_CH0, PPI, 0 => configurable); +impl_ppi_channel!(PPI_CH1, PPI, 1 => configurable); +impl_ppi_channel!(PPI_CH2, PPI, 2 => configurable); +impl_ppi_channel!(PPI_CH3, PPI, 3 => configurable); +impl_ppi_channel!(PPI_CH4, PPI, 4 => configurable); +impl_ppi_channel!(PPI_CH5, PPI, 5 => configurable); +impl_ppi_channel!(PPI_CH6, PPI, 6 => configurable); +impl_ppi_channel!(PPI_CH7, PPI, 7 => configurable); +impl_ppi_channel!(PPI_CH8, PPI, 8 => configurable); +impl_ppi_channel!(PPI_CH9, PPI, 9 => configurable); +impl_ppi_channel!(PPI_CH10, PPI, 10 => configurable); +impl_ppi_channel!(PPI_CH11, PPI, 11 => configurable); +impl_ppi_channel!(PPI_CH12, PPI, 12 => configurable); +impl_ppi_channel!(PPI_CH13, PPI, 13 => configurable); +impl_ppi_channel!(PPI_CH14, PPI, 14 => configurable); +impl_ppi_channel!(PPI_CH15, PPI, 15 => configurable); +impl_ppi_channel!(PPI_CH16, PPI, 16 => configurable); +impl_ppi_channel!(PPI_CH17, PPI, 17 => configurable); +impl_ppi_channel!(PPI_CH18, PPI, 18 => configurable); +impl_ppi_channel!(PPI_CH19, PPI, 19 => configurable); +impl_ppi_channel!(PPI_CH20, PPI, 20 => static); +impl_ppi_channel!(PPI_CH21, PPI, 21 => static); +impl_ppi_channel!(PPI_CH22, PPI, 22 => static); +impl_ppi_channel!(PPI_CH23, PPI, 23 => static); +impl_ppi_channel!(PPI_CH24, PPI, 24 => static); +impl_ppi_channel!(PPI_CH25, PPI, 25 => static); +impl_ppi_channel!(PPI_CH26, PPI, 26 => static); +impl_ppi_channel!(PPI_CH27, PPI, 27 => static); +impl_ppi_channel!(PPI_CH28, PPI, 28 => static); +impl_ppi_channel!(PPI_CH29, PPI, 29 => static); +impl_ppi_channel!(PPI_CH30, PPI, 30 => static); +impl_ppi_channel!(PPI_CH31, PPI, 31 => static); + +impl_ppi_group!(PPI_GROUP0, PPI, 0); +impl_ppi_group!(PPI_GROUP1, PPI, 1); +impl_ppi_group!(PPI_GROUP2, PPI, 2); +impl_ppi_group!(PPI_GROUP3, PPI, 3); +impl_ppi_group!(PPI_GROUP4, PPI, 4); +impl_ppi_group!(PPI_GROUP5, PPI, 5); impl_saadc_input!(P0_02, ANALOG_INPUT0); impl_saadc_input!(P0_03, ANALOG_INPUT1); diff --git a/embassy-nrf/src/chips/nrf52820.rs b/embassy-nrf/src/chips/nrf52820.rs index 22360575b..32304b3ea 100644 --- a/embassy-nrf/src/chips/nrf52820.rs +++ b/embassy-nrf/src/chips/nrf52820.rs @@ -207,38 +207,45 @@ impl_pin!(P0_29, 0, 29); impl_pin!(P0_30, 0, 30); impl_pin!(P0_31, 0, 31); -impl_ppi_channel!(PPI_CH0, 0 => configurable); -impl_ppi_channel!(PPI_CH1, 1 => configurable); -impl_ppi_channel!(PPI_CH2, 2 => configurable); -impl_ppi_channel!(PPI_CH3, 3 => configurable); -impl_ppi_channel!(PPI_CH4, 4 => configurable); -impl_ppi_channel!(PPI_CH5, 5 => configurable); -impl_ppi_channel!(PPI_CH6, 6 => configurable); -impl_ppi_channel!(PPI_CH7, 7 => configurable); -impl_ppi_channel!(PPI_CH8, 8 => configurable); -impl_ppi_channel!(PPI_CH9, 9 => configurable); -impl_ppi_channel!(PPI_CH10, 10 => configurable); -impl_ppi_channel!(PPI_CH11, 11 => configurable); -impl_ppi_channel!(PPI_CH12, 12 => configurable); -impl_ppi_channel!(PPI_CH13, 13 => configurable); -impl_ppi_channel!(PPI_CH14, 14 => configurable); -impl_ppi_channel!(PPI_CH15, 15 => configurable); -impl_ppi_channel!(PPI_CH16, 16 => configurable); -impl_ppi_channel!(PPI_CH17, 17 => configurable); -impl_ppi_channel!(PPI_CH18, 18 => configurable); -impl_ppi_channel!(PPI_CH19, 19 => configurable); -impl_ppi_channel!(PPI_CH20, 20 => static); -impl_ppi_channel!(PPI_CH21, 21 => static); -impl_ppi_channel!(PPI_CH22, 22 => static); -impl_ppi_channel!(PPI_CH23, 23 => static); -impl_ppi_channel!(PPI_CH24, 24 => static); -impl_ppi_channel!(PPI_CH25, 25 => static); -impl_ppi_channel!(PPI_CH26, 26 => static); -impl_ppi_channel!(PPI_CH27, 27 => static); -impl_ppi_channel!(PPI_CH28, 28 => static); -impl_ppi_channel!(PPI_CH29, 29 => static); -impl_ppi_channel!(PPI_CH30, 30 => static); -impl_ppi_channel!(PPI_CH31, 31 => static); +impl_ppi_channel!(PPI_CH0, PPI, 0 => configurable); +impl_ppi_channel!(PPI_CH1, PPI, 1 => configurable); +impl_ppi_channel!(PPI_CH2, PPI, 2 => configurable); +impl_ppi_channel!(PPI_CH3, PPI, 3 => configurable); +impl_ppi_channel!(PPI_CH4, PPI, 4 => configurable); +impl_ppi_channel!(PPI_CH5, PPI, 5 => configurable); +impl_ppi_channel!(PPI_CH6, PPI, 6 => configurable); +impl_ppi_channel!(PPI_CH7, PPI, 7 => configurable); +impl_ppi_channel!(PPI_CH8, PPI, 8 => configurable); +impl_ppi_channel!(PPI_CH9, PPI, 9 => configurable); +impl_ppi_channel!(PPI_CH10, PPI, 10 => configurable); +impl_ppi_channel!(PPI_CH11, PPI, 11 => configurable); +impl_ppi_channel!(PPI_CH12, PPI, 12 => configurable); +impl_ppi_channel!(PPI_CH13, PPI, 13 => configurable); +impl_ppi_channel!(PPI_CH14, PPI, 14 => configurable); +impl_ppi_channel!(PPI_CH15, PPI, 15 => configurable); +impl_ppi_channel!(PPI_CH16, PPI, 16 => configurable); +impl_ppi_channel!(PPI_CH17, PPI, 17 => configurable); +impl_ppi_channel!(PPI_CH18, PPI, 18 => configurable); +impl_ppi_channel!(PPI_CH19, PPI, 19 => configurable); +impl_ppi_channel!(PPI_CH20, PPI, 20 => static); +impl_ppi_channel!(PPI_CH21, PPI, 21 => static); +impl_ppi_channel!(PPI_CH22, PPI, 22 => static); +impl_ppi_channel!(PPI_CH23, PPI, 23 => static); +impl_ppi_channel!(PPI_CH24, PPI, 24 => static); +impl_ppi_channel!(PPI_CH25, PPI, 25 => static); +impl_ppi_channel!(PPI_CH26, PPI, 26 => static); +impl_ppi_channel!(PPI_CH27, PPI, 27 => static); +impl_ppi_channel!(PPI_CH28, PPI, 28 => static); +impl_ppi_channel!(PPI_CH29, PPI, 29 => static); +impl_ppi_channel!(PPI_CH30, PPI, 30 => static); +impl_ppi_channel!(PPI_CH31, PPI, 31 => static); + +impl_ppi_group!(PPI_GROUP0, PPI, 0); +impl_ppi_group!(PPI_GROUP1, PPI, 1); +impl_ppi_group!(PPI_GROUP2, PPI, 2); +impl_ppi_group!(PPI_GROUP3, PPI, 3); +impl_ppi_group!(PPI_GROUP4, PPI, 4); +impl_ppi_group!(PPI_GROUP5, PPI, 5); impl_radio!(RADIO, RADIO, RADIO); diff --git a/embassy-nrf/src/chips/nrf52832.rs b/embassy-nrf/src/chips/nrf52832.rs index 1598df3fe..06363a467 100644 --- a/embassy-nrf/src/chips/nrf52832.rs +++ b/embassy-nrf/src/chips/nrf52832.rs @@ -240,38 +240,45 @@ impl_pin!(P0_29, 0, 29); impl_pin!(P0_30, 0, 30); impl_pin!(P0_31, 0, 31); -impl_ppi_channel!(PPI_CH0, 0 => configurable); -impl_ppi_channel!(PPI_CH1, 1 => configurable); -impl_ppi_channel!(PPI_CH2, 2 => configurable); -impl_ppi_channel!(PPI_CH3, 3 => configurable); -impl_ppi_channel!(PPI_CH4, 4 => configurable); -impl_ppi_channel!(PPI_CH5, 5 => configurable); -impl_ppi_channel!(PPI_CH6, 6 => configurable); -impl_ppi_channel!(PPI_CH7, 7 => configurable); -impl_ppi_channel!(PPI_CH8, 8 => configurable); -impl_ppi_channel!(PPI_CH9, 9 => configurable); -impl_ppi_channel!(PPI_CH10, 10 => configurable); -impl_ppi_channel!(PPI_CH11, 11 => configurable); -impl_ppi_channel!(PPI_CH12, 12 => configurable); -impl_ppi_channel!(PPI_CH13, 13 => configurable); -impl_ppi_channel!(PPI_CH14, 14 => configurable); -impl_ppi_channel!(PPI_CH15, 15 => configurable); -impl_ppi_channel!(PPI_CH16, 16 => configurable); -impl_ppi_channel!(PPI_CH17, 17 => configurable); -impl_ppi_channel!(PPI_CH18, 18 => configurable); -impl_ppi_channel!(PPI_CH19, 19 => configurable); -impl_ppi_channel!(PPI_CH20, 20 => static); -impl_ppi_channel!(PPI_CH21, 21 => static); -impl_ppi_channel!(PPI_CH22, 22 => static); -impl_ppi_channel!(PPI_CH23, 23 => static); -impl_ppi_channel!(PPI_CH24, 24 => static); -impl_ppi_channel!(PPI_CH25, 25 => static); -impl_ppi_channel!(PPI_CH26, 26 => static); -impl_ppi_channel!(PPI_CH27, 27 => static); -impl_ppi_channel!(PPI_CH28, 28 => static); -impl_ppi_channel!(PPI_CH29, 29 => static); -impl_ppi_channel!(PPI_CH30, 30 => static); -impl_ppi_channel!(PPI_CH31, 31 => static); +impl_ppi_channel!(PPI_CH0, PPI, 0 => configurable); +impl_ppi_channel!(PPI_CH1, PPI, 1 => configurable); +impl_ppi_channel!(PPI_CH2, PPI, 2 => configurable); +impl_ppi_channel!(PPI_CH3, PPI, 3 => configurable); +impl_ppi_channel!(PPI_CH4, PPI, 4 => configurable); +impl_ppi_channel!(PPI_CH5, PPI, 5 => configurable); +impl_ppi_channel!(PPI_CH6, PPI, 6 => configurable); +impl_ppi_channel!(PPI_CH7, PPI, 7 => configurable); +impl_ppi_channel!(PPI_CH8, PPI, 8 => configurable); +impl_ppi_channel!(PPI_CH9, PPI, 9 => configurable); +impl_ppi_channel!(PPI_CH10, PPI, 10 => configurable); +impl_ppi_channel!(PPI_CH11, PPI, 11 => configurable); +impl_ppi_channel!(PPI_CH12, PPI, 12 => configurable); +impl_ppi_channel!(PPI_CH13, PPI, 13 => configurable); +impl_ppi_channel!(PPI_CH14, PPI, 14 => configurable); +impl_ppi_channel!(PPI_CH15, PPI, 15 => configurable); +impl_ppi_channel!(PPI_CH16, PPI, 16 => configurable); +impl_ppi_channel!(PPI_CH17, PPI, 17 => configurable); +impl_ppi_channel!(PPI_CH18, PPI, 18 => configurable); +impl_ppi_channel!(PPI_CH19, PPI, 19 => configurable); +impl_ppi_channel!(PPI_CH20, PPI, 20 => static); +impl_ppi_channel!(PPI_CH21, PPI, 21 => static); +impl_ppi_channel!(PPI_CH22, PPI, 22 => static); +impl_ppi_channel!(PPI_CH23, PPI, 23 => static); +impl_ppi_channel!(PPI_CH24, PPI, 24 => static); +impl_ppi_channel!(PPI_CH25, PPI, 25 => static); +impl_ppi_channel!(PPI_CH26, PPI, 26 => static); +impl_ppi_channel!(PPI_CH27, PPI, 27 => static); +impl_ppi_channel!(PPI_CH28, PPI, 28 => static); +impl_ppi_channel!(PPI_CH29, PPI, 29 => static); +impl_ppi_channel!(PPI_CH30, PPI, 30 => static); +impl_ppi_channel!(PPI_CH31, PPI, 31 => static); + +impl_ppi_group!(PPI_GROUP0, PPI, 0); +impl_ppi_group!(PPI_GROUP1, PPI, 1); +impl_ppi_group!(PPI_GROUP2, PPI, 2); +impl_ppi_group!(PPI_GROUP3, PPI, 3); +impl_ppi_group!(PPI_GROUP4, PPI, 4); +impl_ppi_group!(PPI_GROUP5, PPI, 5); impl_saadc_input!(P0_02, ANALOG_INPUT0); impl_saadc_input!(P0_03, ANALOG_INPUT1); diff --git a/embassy-nrf/src/chips/nrf52833.rs b/embassy-nrf/src/chips/nrf52833.rs index 6931fb064..754943d33 100644 --- a/embassy-nrf/src/chips/nrf52833.rs +++ b/embassy-nrf/src/chips/nrf52833.rs @@ -282,38 +282,45 @@ impl_pin!(P1_13, 1, 13); impl_pin!(P1_14, 1, 14); impl_pin!(P1_15, 1, 15); -impl_ppi_channel!(PPI_CH0, 0 => configurable); -impl_ppi_channel!(PPI_CH1, 1 => configurable); -impl_ppi_channel!(PPI_CH2, 2 => configurable); -impl_ppi_channel!(PPI_CH3, 3 => configurable); -impl_ppi_channel!(PPI_CH4, 4 => configurable); -impl_ppi_channel!(PPI_CH5, 5 => configurable); -impl_ppi_channel!(PPI_CH6, 6 => configurable); -impl_ppi_channel!(PPI_CH7, 7 => configurable); -impl_ppi_channel!(PPI_CH8, 8 => configurable); -impl_ppi_channel!(PPI_CH9, 9 => configurable); -impl_ppi_channel!(PPI_CH10, 10 => configurable); -impl_ppi_channel!(PPI_CH11, 11 => configurable); -impl_ppi_channel!(PPI_CH12, 12 => configurable); -impl_ppi_channel!(PPI_CH13, 13 => configurable); -impl_ppi_channel!(PPI_CH14, 14 => configurable); -impl_ppi_channel!(PPI_CH15, 15 => configurable); -impl_ppi_channel!(PPI_CH16, 16 => configurable); -impl_ppi_channel!(PPI_CH17, 17 => configurable); -impl_ppi_channel!(PPI_CH18, 18 => configurable); -impl_ppi_channel!(PPI_CH19, 19 => configurable); -impl_ppi_channel!(PPI_CH20, 20 => static); -impl_ppi_channel!(PPI_CH21, 21 => static); -impl_ppi_channel!(PPI_CH22, 22 => static); -impl_ppi_channel!(PPI_CH23, 23 => static); -impl_ppi_channel!(PPI_CH24, 24 => static); -impl_ppi_channel!(PPI_CH25, 25 => static); -impl_ppi_channel!(PPI_CH26, 26 => static); -impl_ppi_channel!(PPI_CH27, 27 => static); -impl_ppi_channel!(PPI_CH28, 28 => static); -impl_ppi_channel!(PPI_CH29, 29 => static); -impl_ppi_channel!(PPI_CH30, 30 => static); -impl_ppi_channel!(PPI_CH31, 31 => static); +impl_ppi_channel!(PPI_CH0, PPI, 0 => configurable); +impl_ppi_channel!(PPI_CH1, PPI, 1 => configurable); +impl_ppi_channel!(PPI_CH2, PPI, 2 => configurable); +impl_ppi_channel!(PPI_CH3, PPI, 3 => configurable); +impl_ppi_channel!(PPI_CH4, PPI, 4 => configurable); +impl_ppi_channel!(PPI_CH5, PPI, 5 => configurable); +impl_ppi_channel!(PPI_CH6, PPI, 6 => configurable); +impl_ppi_channel!(PPI_CH7, PPI, 7 => configurable); +impl_ppi_channel!(PPI_CH8, PPI, 8 => configurable); +impl_ppi_channel!(PPI_CH9, PPI, 9 => configurable); +impl_ppi_channel!(PPI_CH10, PPI, 10 => configurable); +impl_ppi_channel!(PPI_CH11, PPI, 11 => configurable); +impl_ppi_channel!(PPI_CH12, PPI, 12 => configurable); +impl_ppi_channel!(PPI_CH13, PPI, 13 => configurable); +impl_ppi_channel!(PPI_CH14, PPI, 14 => configurable); +impl_ppi_channel!(PPI_CH15, PPI, 15 => configurable); +impl_ppi_channel!(PPI_CH16, PPI, 16 => configurable); +impl_ppi_channel!(PPI_CH17, PPI, 17 => configurable); +impl_ppi_channel!(PPI_CH18, PPI, 18 => configurable); +impl_ppi_channel!(PPI_CH19, PPI, 19 => configurable); +impl_ppi_channel!(PPI_CH20, PPI, 20 => static); +impl_ppi_channel!(PPI_CH21, PPI, 21 => static); +impl_ppi_channel!(PPI_CH22, PPI, 22 => static); +impl_ppi_channel!(PPI_CH23, PPI, 23 => static); +impl_ppi_channel!(PPI_CH24, PPI, 24 => static); +impl_ppi_channel!(PPI_CH25, PPI, 25 => static); +impl_ppi_channel!(PPI_CH26, PPI, 26 => static); +impl_ppi_channel!(PPI_CH27, PPI, 27 => static); +impl_ppi_channel!(PPI_CH28, PPI, 28 => static); +impl_ppi_channel!(PPI_CH29, PPI, 29 => static); +impl_ppi_channel!(PPI_CH30, PPI, 30 => static); +impl_ppi_channel!(PPI_CH31, PPI, 31 => static); + +impl_ppi_group!(PPI_GROUP0, PPI, 0); +impl_ppi_group!(PPI_GROUP1, PPI, 1); +impl_ppi_group!(PPI_GROUP2, PPI, 2); +impl_ppi_group!(PPI_GROUP3, PPI, 3); +impl_ppi_group!(PPI_GROUP4, PPI, 4); +impl_ppi_group!(PPI_GROUP5, PPI, 5); impl_saadc_input!(P0_02, ANALOG_INPUT0); impl_saadc_input!(P0_03, ANALOG_INPUT1); diff --git a/embassy-nrf/src/chips/nrf52840.rs b/embassy-nrf/src/chips/nrf52840.rs index 5fa521aae..ac07cd820 100644 --- a/embassy-nrf/src/chips/nrf52840.rs +++ b/embassy-nrf/src/chips/nrf52840.rs @@ -287,38 +287,45 @@ impl_pin!(P1_13, 1, 13); impl_pin!(P1_14, 1, 14); impl_pin!(P1_15, 1, 15); -impl_ppi_channel!(PPI_CH0, 0 => configurable); -impl_ppi_channel!(PPI_CH1, 1 => configurable); -impl_ppi_channel!(PPI_CH2, 2 => configurable); -impl_ppi_channel!(PPI_CH3, 3 => configurable); -impl_ppi_channel!(PPI_CH4, 4 => configurable); -impl_ppi_channel!(PPI_CH5, 5 => configurable); -impl_ppi_channel!(PPI_CH6, 6 => configurable); -impl_ppi_channel!(PPI_CH7, 7 => configurable); -impl_ppi_channel!(PPI_CH8, 8 => configurable); -impl_ppi_channel!(PPI_CH9, 9 => configurable); -impl_ppi_channel!(PPI_CH10, 10 => configurable); -impl_ppi_channel!(PPI_CH11, 11 => configurable); -impl_ppi_channel!(PPI_CH12, 12 => configurable); -impl_ppi_channel!(PPI_CH13, 13 => configurable); -impl_ppi_channel!(PPI_CH14, 14 => configurable); -impl_ppi_channel!(PPI_CH15, 15 => configurable); -impl_ppi_channel!(PPI_CH16, 16 => configurable); -impl_ppi_channel!(PPI_CH17, 17 => configurable); -impl_ppi_channel!(PPI_CH18, 18 => configurable); -impl_ppi_channel!(PPI_CH19, 19 => configurable); -impl_ppi_channel!(PPI_CH20, 20 => static); -impl_ppi_channel!(PPI_CH21, 21 => static); -impl_ppi_channel!(PPI_CH22, 22 => static); -impl_ppi_channel!(PPI_CH23, 23 => static); -impl_ppi_channel!(PPI_CH24, 24 => static); -impl_ppi_channel!(PPI_CH25, 25 => static); -impl_ppi_channel!(PPI_CH26, 26 => static); -impl_ppi_channel!(PPI_CH27, 27 => static); -impl_ppi_channel!(PPI_CH28, 28 => static); -impl_ppi_channel!(PPI_CH29, 29 => static); -impl_ppi_channel!(PPI_CH30, 30 => static); -impl_ppi_channel!(PPI_CH31, 31 => static); +impl_ppi_channel!(PPI_CH0, PPI, 0 => configurable); +impl_ppi_channel!(PPI_CH1, PPI, 1 => configurable); +impl_ppi_channel!(PPI_CH2, PPI, 2 => configurable); +impl_ppi_channel!(PPI_CH3, PPI, 3 => configurable); +impl_ppi_channel!(PPI_CH4, PPI, 4 => configurable); +impl_ppi_channel!(PPI_CH5, PPI, 5 => configurable); +impl_ppi_channel!(PPI_CH6, PPI, 6 => configurable); +impl_ppi_channel!(PPI_CH7, PPI, 7 => configurable); +impl_ppi_channel!(PPI_CH8, PPI, 8 => configurable); +impl_ppi_channel!(PPI_CH9, PPI, 9 => configurable); +impl_ppi_channel!(PPI_CH10, PPI, 10 => configurable); +impl_ppi_channel!(PPI_CH11, PPI, 11 => configurable); +impl_ppi_channel!(PPI_CH12, PPI, 12 => configurable); +impl_ppi_channel!(PPI_CH13, PPI, 13 => configurable); +impl_ppi_channel!(PPI_CH14, PPI, 14 => configurable); +impl_ppi_channel!(PPI_CH15, PPI, 15 => configurable); +impl_ppi_channel!(PPI_CH16, PPI, 16 => configurable); +impl_ppi_channel!(PPI_CH17, PPI, 17 => configurable); +impl_ppi_channel!(PPI_CH18, PPI, 18 => configurable); +impl_ppi_channel!(PPI_CH19, PPI, 19 => configurable); +impl_ppi_channel!(PPI_CH20, PPI, 20 => static); +impl_ppi_channel!(PPI_CH21, PPI, 21 => static); +impl_ppi_channel!(PPI_CH22, PPI, 22 => static); +impl_ppi_channel!(PPI_CH23, PPI, 23 => static); +impl_ppi_channel!(PPI_CH24, PPI, 24 => static); +impl_ppi_channel!(PPI_CH25, PPI, 25 => static); +impl_ppi_channel!(PPI_CH26, PPI, 26 => static); +impl_ppi_channel!(PPI_CH27, PPI, 27 => static); +impl_ppi_channel!(PPI_CH28, PPI, 28 => static); +impl_ppi_channel!(PPI_CH29, PPI, 29 => static); +impl_ppi_channel!(PPI_CH30, PPI, 30 => static); +impl_ppi_channel!(PPI_CH31, PPI, 31 => static); + +impl_ppi_group!(PPI_GROUP0, PPI, 0); +impl_ppi_group!(PPI_GROUP1, PPI, 1); +impl_ppi_group!(PPI_GROUP2, PPI, 2); +impl_ppi_group!(PPI_GROUP3, PPI, 3); +impl_ppi_group!(PPI_GROUP4, PPI, 4); +impl_ppi_group!(PPI_GROUP5, PPI, 5); impl_saadc_input!(P0_02, ANALOG_INPUT0); impl_saadc_input!(P0_03, ANALOG_INPUT1); diff --git a/embassy-nrf/src/chips/nrf5340_app.rs b/embassy-nrf/src/chips/nrf5340_app.rs index 730c9842d..aa51527fb 100644 --- a/embassy-nrf/src/chips/nrf5340_app.rs +++ b/embassy-nrf/src/chips/nrf5340_app.rs @@ -435,38 +435,45 @@ impl_pin!(P1_13, 1, 13); impl_pin!(P1_14, 1, 14); impl_pin!(P1_15, 1, 15); -impl_ppi_channel!(PPI_CH0, 0 => configurable); -impl_ppi_channel!(PPI_CH1, 1 => configurable); -impl_ppi_channel!(PPI_CH2, 2 => configurable); -impl_ppi_channel!(PPI_CH3, 3 => configurable); -impl_ppi_channel!(PPI_CH4, 4 => configurable); -impl_ppi_channel!(PPI_CH5, 5 => configurable); -impl_ppi_channel!(PPI_CH6, 6 => configurable); -impl_ppi_channel!(PPI_CH7, 7 => configurable); -impl_ppi_channel!(PPI_CH8, 8 => configurable); -impl_ppi_channel!(PPI_CH9, 9 => configurable); -impl_ppi_channel!(PPI_CH10, 10 => configurable); -impl_ppi_channel!(PPI_CH11, 11 => configurable); -impl_ppi_channel!(PPI_CH12, 12 => configurable); -impl_ppi_channel!(PPI_CH13, 13 => configurable); -impl_ppi_channel!(PPI_CH14, 14 => configurable); -impl_ppi_channel!(PPI_CH15, 15 => configurable); -impl_ppi_channel!(PPI_CH16, 16 => configurable); -impl_ppi_channel!(PPI_CH17, 17 => configurable); -impl_ppi_channel!(PPI_CH18, 18 => configurable); -impl_ppi_channel!(PPI_CH19, 19 => configurable); -impl_ppi_channel!(PPI_CH20, 20 => configurable); -impl_ppi_channel!(PPI_CH21, 21 => configurable); -impl_ppi_channel!(PPI_CH22, 22 => configurable); -impl_ppi_channel!(PPI_CH23, 23 => configurable); -impl_ppi_channel!(PPI_CH24, 24 => configurable); -impl_ppi_channel!(PPI_CH25, 25 => configurable); -impl_ppi_channel!(PPI_CH26, 26 => configurable); -impl_ppi_channel!(PPI_CH27, 27 => configurable); -impl_ppi_channel!(PPI_CH28, 28 => configurable); -impl_ppi_channel!(PPI_CH29, 29 => configurable); -impl_ppi_channel!(PPI_CH30, 30 => configurable); -impl_ppi_channel!(PPI_CH31, 31 => configurable); +impl_ppi_channel!(PPI_CH0, DPPIC, 0 => configurable); +impl_ppi_channel!(PPI_CH1, DPPIC, 1 => configurable); +impl_ppi_channel!(PPI_CH2, DPPIC, 2 => configurable); +impl_ppi_channel!(PPI_CH3, DPPIC, 3 => configurable); +impl_ppi_channel!(PPI_CH4, DPPIC, 4 => configurable); +impl_ppi_channel!(PPI_CH5, DPPIC, 5 => configurable); +impl_ppi_channel!(PPI_CH6, DPPIC, 6 => configurable); +impl_ppi_channel!(PPI_CH7, DPPIC, 7 => configurable); +impl_ppi_channel!(PPI_CH8, DPPIC, 8 => configurable); +impl_ppi_channel!(PPI_CH9, DPPIC, 9 => configurable); +impl_ppi_channel!(PPI_CH10, DPPIC, 10 => configurable); +impl_ppi_channel!(PPI_CH11, DPPIC, 11 => configurable); +impl_ppi_channel!(PPI_CH12, DPPIC, 12 => configurable); +impl_ppi_channel!(PPI_CH13, DPPIC, 13 => configurable); +impl_ppi_channel!(PPI_CH14, DPPIC, 14 => configurable); +impl_ppi_channel!(PPI_CH15, DPPIC, 15 => configurable); +impl_ppi_channel!(PPI_CH16, DPPIC, 16 => configurable); +impl_ppi_channel!(PPI_CH17, DPPIC, 17 => configurable); +impl_ppi_channel!(PPI_CH18, DPPIC, 18 => configurable); +impl_ppi_channel!(PPI_CH19, DPPIC, 19 => configurable); +impl_ppi_channel!(PPI_CH20, DPPIC, 20 => configurable); +impl_ppi_channel!(PPI_CH21, DPPIC, 21 => configurable); +impl_ppi_channel!(PPI_CH22, DPPIC, 22 => configurable); +impl_ppi_channel!(PPI_CH23, DPPIC, 23 => configurable); +impl_ppi_channel!(PPI_CH24, DPPIC, 24 => configurable); +impl_ppi_channel!(PPI_CH25, DPPIC, 25 => configurable); +impl_ppi_channel!(PPI_CH26, DPPIC, 26 => configurable); +impl_ppi_channel!(PPI_CH27, DPPIC, 27 => configurable); +impl_ppi_channel!(PPI_CH28, DPPIC, 28 => configurable); +impl_ppi_channel!(PPI_CH29, DPPIC, 29 => configurable); +impl_ppi_channel!(PPI_CH30, DPPIC, 30 => configurable); +impl_ppi_channel!(PPI_CH31, DPPIC, 31 => configurable); + +impl_ppi_group!(PPI_GROUP0, DPPIC, 0); +impl_ppi_group!(PPI_GROUP1, DPPIC, 1); +impl_ppi_group!(PPI_GROUP2, DPPIC, 2); +impl_ppi_group!(PPI_GROUP3, DPPIC, 3); +impl_ppi_group!(PPI_GROUP4, DPPIC, 4); +impl_ppi_group!(PPI_GROUP5, DPPIC, 5); impl_saadc_input!(P0_04, ANALOG_INPUT0); impl_saadc_input!(P0_05, ANALOG_INPUT1); diff --git a/embassy-nrf/src/chips/nrf5340_net.rs b/embassy-nrf/src/chips/nrf5340_net.rs index 413afc5c5..2207e7bda 100644 --- a/embassy-nrf/src/chips/nrf5340_net.rs +++ b/embassy-nrf/src/chips/nrf5340_net.rs @@ -275,38 +275,45 @@ impl_pin!(P1_13, 1, 13); impl_pin!(P1_14, 1, 14); impl_pin!(P1_15, 1, 15); -impl_ppi_channel!(PPI_CH0, 0 => configurable); -impl_ppi_channel!(PPI_CH1, 1 => configurable); -impl_ppi_channel!(PPI_CH2, 2 => configurable); -impl_ppi_channel!(PPI_CH3, 3 => configurable); -impl_ppi_channel!(PPI_CH4, 4 => configurable); -impl_ppi_channel!(PPI_CH5, 5 => configurable); -impl_ppi_channel!(PPI_CH6, 6 => configurable); -impl_ppi_channel!(PPI_CH7, 7 => configurable); -impl_ppi_channel!(PPI_CH8, 8 => configurable); -impl_ppi_channel!(PPI_CH9, 9 => configurable); -impl_ppi_channel!(PPI_CH10, 10 => configurable); -impl_ppi_channel!(PPI_CH11, 11 => configurable); -impl_ppi_channel!(PPI_CH12, 12 => configurable); -impl_ppi_channel!(PPI_CH13, 13 => configurable); -impl_ppi_channel!(PPI_CH14, 14 => configurable); -impl_ppi_channel!(PPI_CH15, 15 => configurable); -impl_ppi_channel!(PPI_CH16, 16 => configurable); -impl_ppi_channel!(PPI_CH17, 17 => configurable); -impl_ppi_channel!(PPI_CH18, 18 => configurable); -impl_ppi_channel!(PPI_CH19, 19 => configurable); -impl_ppi_channel!(PPI_CH20, 20 => configurable); -impl_ppi_channel!(PPI_CH21, 21 => configurable); -impl_ppi_channel!(PPI_CH22, 22 => configurable); -impl_ppi_channel!(PPI_CH23, 23 => configurable); -impl_ppi_channel!(PPI_CH24, 24 => configurable); -impl_ppi_channel!(PPI_CH25, 25 => configurable); -impl_ppi_channel!(PPI_CH26, 26 => configurable); -impl_ppi_channel!(PPI_CH27, 27 => configurable); -impl_ppi_channel!(PPI_CH28, 28 => configurable); -impl_ppi_channel!(PPI_CH29, 29 => configurable); -impl_ppi_channel!(PPI_CH30, 30 => configurable); -impl_ppi_channel!(PPI_CH31, 31 => configurable); +impl_ppi_channel!(PPI_CH0, DPPIC, 0 => configurable); +impl_ppi_channel!(PPI_CH1, DPPIC, 1 => configurable); +impl_ppi_channel!(PPI_CH2, DPPIC, 2 => configurable); +impl_ppi_channel!(PPI_CH3, DPPIC, 3 => configurable); +impl_ppi_channel!(PPI_CH4, DPPIC, 4 => configurable); +impl_ppi_channel!(PPI_CH5, DPPIC, 5 => configurable); +impl_ppi_channel!(PPI_CH6, DPPIC, 6 => configurable); +impl_ppi_channel!(PPI_CH7, DPPIC, 7 => configurable); +impl_ppi_channel!(PPI_CH8, DPPIC, 8 => configurable); +impl_ppi_channel!(PPI_CH9, DPPIC, 9 => configurable); +impl_ppi_channel!(PPI_CH10, DPPIC, 10 => configurable); +impl_ppi_channel!(PPI_CH11, DPPIC, 11 => configurable); +impl_ppi_channel!(PPI_CH12, DPPIC, 12 => configurable); +impl_ppi_channel!(PPI_CH13, DPPIC, 13 => configurable); +impl_ppi_channel!(PPI_CH14, DPPIC, 14 => configurable); +impl_ppi_channel!(PPI_CH15, DPPIC, 15 => configurable); +impl_ppi_channel!(PPI_CH16, DPPIC, 16 => configurable); +impl_ppi_channel!(PPI_CH17, DPPIC, 17 => configurable); +impl_ppi_channel!(PPI_CH18, DPPIC, 18 => configurable); +impl_ppi_channel!(PPI_CH19, DPPIC, 19 => configurable); +impl_ppi_channel!(PPI_CH20, DPPIC, 20 => configurable); +impl_ppi_channel!(PPI_CH21, DPPIC, 21 => configurable); +impl_ppi_channel!(PPI_CH22, DPPIC, 22 => configurable); +impl_ppi_channel!(PPI_CH23, DPPIC, 23 => configurable); +impl_ppi_channel!(PPI_CH24, DPPIC, 24 => configurable); +impl_ppi_channel!(PPI_CH25, DPPIC, 25 => configurable); +impl_ppi_channel!(PPI_CH26, DPPIC, 26 => configurable); +impl_ppi_channel!(PPI_CH27, DPPIC, 27 => configurable); +impl_ppi_channel!(PPI_CH28, DPPIC, 28 => configurable); +impl_ppi_channel!(PPI_CH29, DPPIC, 29 => configurable); +impl_ppi_channel!(PPI_CH30, DPPIC, 30 => configurable); +impl_ppi_channel!(PPI_CH31, DPPIC, 31 => configurable); + +impl_ppi_group!(PPI_GROUP0, DPPIC, 0); +impl_ppi_group!(PPI_GROUP1, DPPIC, 1); +impl_ppi_group!(PPI_GROUP2, DPPIC, 2); +impl_ppi_group!(PPI_GROUP3, DPPIC, 3); +impl_ppi_group!(PPI_GROUP4, DPPIC, 4); +impl_ppi_group!(PPI_GROUP5, DPPIC, 5); impl_radio!(RADIO, RADIO, RADIO); diff --git a/embassy-nrf/src/chips/nrf54l15_app.rs b/embassy-nrf/src/chips/nrf54l15_app.rs index 901c5e7fc..2e1ac9be8 100644 --- a/embassy-nrf/src/chips/nrf54l15_app.rs +++ b/embassy-nrf/src/chips/nrf54l15_app.rs @@ -200,13 +200,67 @@ pub mod pac { /// The maximum buffer size that the EasyDMA can send/recv in one operation. pub const EASY_DMA_SIZE: usize = (1 << 16) - 1; -//pub const FORCE_COPY_BUFFER_SIZE: usize = 1024; +pub const FORCE_COPY_BUFFER_SIZE: usize = 1024; // 1.5 MB NVM #[allow(unused)] pub const FLASH_SIZE: usize = 1536 * 1024; embassy_hal_internal::peripherals! { + // PPI + PPI00_CH0, + PPI00_CH1, + PPI00_CH2, + PPI00_CH3, + PPI00_CH4, + PPI00_CH5, + PPI00_CH6, + PPI00_CH7, + + PPI20_CH0, + PPI20_CH1, + PPI20_CH2, + PPI20_CH3, + PPI20_CH4, + PPI20_CH5, + PPI20_CH6, + PPI20_CH7, + PPI20_CH8, + PPI20_CH9, + PPI20_CH10, + PPI20_CH11, + PPI20_CH12, + PPI20_CH13, + PPI20_CH14, + PPI20_CH15, + + PPI30_CH0, + PPI30_CH1, + PPI30_CH2, + PPI30_CH3, + + PPI00_GROUP0, + PPI00_GROUP1, + + PPI20_GROUP0, + PPI20_GROUP1, + PPI20_GROUP2, + PPI20_GROUP3, + PPI20_GROUP4, + PPI20_GROUP5, + + PPI30_GROUP0, + PPI30_GROUP1, + + // Timers + TIMER00, + TIMER10, + TIMER20, + TIMER21, + TIMER22, + TIMER23, + TIMER24, + // GPIO port 0 P0_00, P0_01, @@ -253,6 +307,11 @@ embassy_hal_internal::peripherals! { RTC10, RTC30, + // PWM + PWM20, + PWM21, + PWM22, + // SERIAL SERIAL00, SERIAL20, @@ -266,11 +325,6 @@ embassy_hal_internal::peripherals! { // RADIO RADIO, - // TIMER - TIMER00, - TIMER10, - TIMER20, - // PPI BRIDGE PPIB00, PPIB01, @@ -281,10 +335,24 @@ embassy_hal_internal::peripherals! { PPIB22, PPIB30, - // GPIOTE + // GPIOTE instances GPIOTE20, GPIOTE30, + // GPIOTE channels + GPIOTE_CH0, + GPIOTE_CH1, + GPIOTE_CH2, + GPIOTE_CH3, + GPIOTE_CH4, + GPIOTE_CH5, + GPIOTE_CH6, + GPIOTE_CH7, + GPIOTE_CH8, + GPIOTE_CH9, + GPIOTE_CH10, + GPIOTE_CH11, + // CRACEN CRACEN, @@ -311,6 +379,13 @@ impl_pin!(P0_03, 0, 3); impl_pin!(P0_04, 0, 4); impl_pin!(P0_05, 0, 5); impl_pin!(P0_06, 0, 6); +impl_gpiote_pin!(P0_00, GPIOTE30); +impl_gpiote_pin!(P0_01, GPIOTE30); +impl_gpiote_pin!(P0_02, GPIOTE30); +impl_gpiote_pin!(P0_03, GPIOTE30); +impl_gpiote_pin!(P0_04, GPIOTE30); +impl_gpiote_pin!(P0_05, GPIOTE30); +impl_gpiote_pin!(P0_06, GPIOTE30); impl_pin!(P1_00, 1, 0); impl_pin!(P1_01, 1, 1); @@ -330,6 +405,24 @@ impl_pin!(P1_14, 1, 14); impl_pin!(P1_15, 1, 15); impl_pin!(P1_16, 1, 16); +impl_gpiote_pin!(P1_00, GPIOTE20); +impl_gpiote_pin!(P1_01, GPIOTE20); +impl_gpiote_pin!(P1_02, GPIOTE20); +impl_gpiote_pin!(P1_03, GPIOTE20); +impl_gpiote_pin!(P1_04, GPIOTE20); +impl_gpiote_pin!(P1_05, GPIOTE20); +impl_gpiote_pin!(P1_06, GPIOTE20); +impl_gpiote_pin!(P1_07, GPIOTE20); +impl_gpiote_pin!(P1_08, GPIOTE20); +impl_gpiote_pin!(P1_09, GPIOTE20); +impl_gpiote_pin!(P1_10, GPIOTE20); +impl_gpiote_pin!(P1_11, GPIOTE20); +impl_gpiote_pin!(P1_12, GPIOTE20); +impl_gpiote_pin!(P1_13, GPIOTE20); +impl_gpiote_pin!(P1_14, GPIOTE20); +impl_gpiote_pin!(P1_15, GPIOTE20); +impl_gpiote_pin!(P1_16, GPIOTE20); + impl_pin!(P2_00, 2, 0); impl_pin!(P2_01, 2, 1); impl_pin!(P2_02, 2, 2); @@ -351,6 +444,107 @@ impl_wdt!(WDT, WDT31, WDT31, 0); impl_wdt!(WDT0, WDT31, WDT31, 0); #[cfg(feature = "_s")] impl_wdt!(WDT1, WDT30, WDT30, 1); +// DPPI00 channels +impl_ppi_channel!(PPI00_CH0, DPPIC00, 0 => configurable); +impl_ppi_channel!(PPI00_CH1, DPPIC00, 1 => configurable); +impl_ppi_channel!(PPI00_CH2, DPPIC00, 2 => configurable); +impl_ppi_channel!(PPI00_CH3, DPPIC00, 3 => configurable); +impl_ppi_channel!(PPI00_CH4, DPPIC00, 4 => configurable); +impl_ppi_channel!(PPI00_CH5, DPPIC00, 5 => configurable); +impl_ppi_channel!(PPI00_CH6, DPPIC00, 6 => configurable); +impl_ppi_channel!(PPI00_CH7, DPPIC00, 7 => configurable); + +// DPPI20 channels +impl_ppi_channel!(PPI20_CH0, DPPIC20, 0 => configurable); +impl_ppi_channel!(PPI20_CH1, DPPIC20, 1 => configurable); +impl_ppi_channel!(PPI20_CH2, DPPIC20, 2 => configurable); +impl_ppi_channel!(PPI20_CH3, DPPIC20, 3 => configurable); +impl_ppi_channel!(PPI20_CH4, DPPIC20, 4 => configurable); +impl_ppi_channel!(PPI20_CH5, DPPIC20, 5 => configurable); +impl_ppi_channel!(PPI20_CH6, DPPIC20, 6 => configurable); +impl_ppi_channel!(PPI20_CH7, DPPIC20, 7 => configurable); +impl_ppi_channel!(PPI20_CH8, DPPIC20, 8 => configurable); +impl_ppi_channel!(PPI20_CH9, DPPIC20, 9 => configurable); +impl_ppi_channel!(PPI20_CH10, DPPIC20, 10 => configurable); +impl_ppi_channel!(PPI20_CH11, DPPIC20, 11 => configurable); +impl_ppi_channel!(PPI20_CH12, DPPIC20, 12 => configurable); +impl_ppi_channel!(PPI20_CH13, DPPIC20, 13 => configurable); +impl_ppi_channel!(PPI20_CH14, DPPIC20, 14 => configurable); +impl_ppi_channel!(PPI20_CH15, DPPIC20, 15 => configurable); + +// DPPI30 channels +impl_ppi_channel!(PPI30_CH0, DPPIC30, 0 => configurable); +impl_ppi_channel!(PPI30_CH1, DPPIC30, 1 => configurable); +impl_ppi_channel!(PPI30_CH2, DPPIC30, 2 => configurable); +impl_ppi_channel!(PPI30_CH3, DPPIC30, 3 => configurable); + +// DPPI00 groups +impl_ppi_group!(PPI00_GROUP0, DPPIC00, 0); +impl_ppi_group!(PPI00_GROUP1, DPPIC00, 1); + +// DPPI20 groups +impl_ppi_group!(PPI20_GROUP0, DPPIC20, 0); +impl_ppi_group!(PPI20_GROUP1, DPPIC20, 1); +impl_ppi_group!(PPI20_GROUP2, DPPIC20, 2); +impl_ppi_group!(PPI20_GROUP3, DPPIC20, 3); +impl_ppi_group!(PPI20_GROUP4, DPPIC20, 4); +impl_ppi_group!(PPI20_GROUP5, DPPIC20, 5); + +// DPPI30 groups +impl_ppi_group!(PPI30_GROUP0, DPPIC30, 0); +impl_ppi_group!(PPI30_GROUP1, DPPIC30, 1); + +// impl_ppi_channel!(PPI10_CH0, pac::DPPIC10, 0 => static); +// impl_ppi_group!(PPI10_GROUP0, pac::DPPIC10, 0); + +impl_timer!(TIMER00, TIMER00, TIMER00); +impl_timer!(TIMER10, TIMER10, TIMER10); +impl_timer!(TIMER20, TIMER20, TIMER20); +impl_timer!(TIMER21, TIMER21, TIMER21); +impl_timer!(TIMER22, TIMER22, TIMER22); +impl_timer!(TIMER23, TIMER23, TIMER23); +impl_timer!(TIMER24, TIMER24, TIMER24); + +impl_twim!(SERIAL20, TWIM20, SERIAL20); +impl_twim!(SERIAL21, TWIM21, SERIAL21); +impl_twim!(SERIAL22, TWIM22, SERIAL22); +impl_twim!(SERIAL30, TWIM30, SERIAL30); + +impl_twis!(SERIAL20, TWIS20, SERIAL20); +impl_twis!(SERIAL21, TWIS21, SERIAL21); +impl_twis!(SERIAL22, TWIS22, SERIAL22); +impl_twis!(SERIAL30, TWIS30, SERIAL30); + +impl_pwm!(PWM20, PWM20, PWM20); +impl_pwm!(PWM21, PWM21, PWM21); +impl_pwm!(PWM22, PWM22, PWM22); + +impl_spim!(SERIAL00, SPIM00, SERIAL00, 128_000_000); +impl_spim!(SERIAL20, SPIM20, SERIAL20, 16_000_000); +impl_spim!(SERIAL21, SPIM21, SERIAL21, 16_000_000); +impl_spim!(SERIAL22, SPIM22, SERIAL22, 16_000_000); +impl_spim!(SERIAL30, SPIM30, SERIAL30, 16_000_000); + +impl_spis!(SERIAL20, SPIS20, SERIAL20); +impl_spis!(SERIAL21, SPIS21, SERIAL21); +impl_spis!(SERIAL22, SPIS22, SERIAL22); +impl_spis!(SERIAL30, SPIS30, SERIAL30); + +impl_uarte!(SERIAL00, UARTE00, SERIAL00); +impl_uarte!(SERIAL20, UARTE20, SERIAL20); +impl_uarte!(SERIAL21, UARTE21, SERIAL21); +impl_uarte!(SERIAL22, UARTE22, SERIAL22); +impl_uarte!(SERIAL30, UARTE30, SERIAL30); + +// NB: SAADC uses "pin" abstraction, not "AIN" +impl_saadc_input!(P1_04, 1, 4); +impl_saadc_input!(P1_05, 1, 5); +impl_saadc_input!(P1_06, 1, 6); +impl_saadc_input!(P1_07, 1, 7); +impl_saadc_input!(P1_11, 1, 11); +impl_saadc_input!(P1_12, 1, 12); +impl_saadc_input!(P1_13, 1, 13); +impl_saadc_input!(P1_14, 1, 14); embassy_hal_internal::interrupt_mod!( SWI00, diff --git a/embassy-nrf/src/chips/nrf9120.rs b/embassy-nrf/src/chips/nrf9120.rs index 5aee19d97..e9f313fef 100644 --- a/embassy-nrf/src/chips/nrf9120.rs +++ b/embassy-nrf/src/chips/nrf9120.rs @@ -314,22 +314,29 @@ impl_pin!(P0_29, 0, 29); impl_pin!(P0_30, 0, 30); impl_pin!(P0_31, 0, 31); -impl_ppi_channel!(PPI_CH0, 0 => configurable); -impl_ppi_channel!(PPI_CH1, 1 => configurable); -impl_ppi_channel!(PPI_CH2, 2 => configurable); -impl_ppi_channel!(PPI_CH3, 3 => configurable); -impl_ppi_channel!(PPI_CH4, 4 => configurable); -impl_ppi_channel!(PPI_CH5, 5 => configurable); -impl_ppi_channel!(PPI_CH6, 6 => configurable); -impl_ppi_channel!(PPI_CH7, 7 => configurable); -impl_ppi_channel!(PPI_CH8, 8 => configurable); -impl_ppi_channel!(PPI_CH9, 9 => configurable); -impl_ppi_channel!(PPI_CH10, 10 => configurable); -impl_ppi_channel!(PPI_CH11, 11 => configurable); -impl_ppi_channel!(PPI_CH12, 12 => configurable); -impl_ppi_channel!(PPI_CH13, 13 => configurable); -impl_ppi_channel!(PPI_CH14, 14 => configurable); -impl_ppi_channel!(PPI_CH15, 15 => configurable); +impl_ppi_channel!(PPI_CH0, DPPIC, 0 => configurable); +impl_ppi_channel!(PPI_CH1, DPPIC, 1 => configurable); +impl_ppi_channel!(PPI_CH2, DPPIC, 2 => configurable); +impl_ppi_channel!(PPI_CH3, DPPIC, 3 => configurable); +impl_ppi_channel!(PPI_CH4, DPPIC, 4 => configurable); +impl_ppi_channel!(PPI_CH5, DPPIC, 5 => configurable); +impl_ppi_channel!(PPI_CH6, DPPIC, 6 => configurable); +impl_ppi_channel!(PPI_CH7, DPPIC, 7 => configurable); +impl_ppi_channel!(PPI_CH8, DPPIC, 8 => configurable); +impl_ppi_channel!(PPI_CH9, DPPIC, 9 => configurable); +impl_ppi_channel!(PPI_CH10, DPPIC, 10 => configurable); +impl_ppi_channel!(PPI_CH11, DPPIC, 11 => configurable); +impl_ppi_channel!(PPI_CH12, DPPIC, 12 => configurable); +impl_ppi_channel!(PPI_CH13, DPPIC, 13 => configurable); +impl_ppi_channel!(PPI_CH14, DPPIC, 14 => configurable); +impl_ppi_channel!(PPI_CH15, DPPIC, 15 => configurable); + +impl_ppi_group!(PPI_GROUP0, DPPIC, 0); +impl_ppi_group!(PPI_GROUP1, DPPIC, 1); +impl_ppi_group!(PPI_GROUP2, DPPIC, 2); +impl_ppi_group!(PPI_GROUP3, DPPIC, 3); +impl_ppi_group!(PPI_GROUP4, DPPIC, 4); +impl_ppi_group!(PPI_GROUP5, DPPIC, 5); impl_saadc_input!(P0_13, ANALOG_INPUT0); impl_saadc_input!(P0_14, ANALOG_INPUT1); diff --git a/embassy-nrf/src/chips/nrf9160.rs b/embassy-nrf/src/chips/nrf9160.rs index 64aec217c..4c6f055dd 100644 --- a/embassy-nrf/src/chips/nrf9160.rs +++ b/embassy-nrf/src/chips/nrf9160.rs @@ -314,22 +314,29 @@ impl_pin!(P0_29, 0, 29); impl_pin!(P0_30, 0, 30); impl_pin!(P0_31, 0, 31); -impl_ppi_channel!(PPI_CH0, 0 => configurable); -impl_ppi_channel!(PPI_CH1, 1 => configurable); -impl_ppi_channel!(PPI_CH2, 2 => configurable); -impl_ppi_channel!(PPI_CH3, 3 => configurable); -impl_ppi_channel!(PPI_CH4, 4 => configurable); -impl_ppi_channel!(PPI_CH5, 5 => configurable); -impl_ppi_channel!(PPI_CH6, 6 => configurable); -impl_ppi_channel!(PPI_CH7, 7 => configurable); -impl_ppi_channel!(PPI_CH8, 8 => configurable); -impl_ppi_channel!(PPI_CH9, 9 => configurable); -impl_ppi_channel!(PPI_CH10, 10 => configurable); -impl_ppi_channel!(PPI_CH11, 11 => configurable); -impl_ppi_channel!(PPI_CH12, 12 => configurable); -impl_ppi_channel!(PPI_CH13, 13 => configurable); -impl_ppi_channel!(PPI_CH14, 14 => configurable); -impl_ppi_channel!(PPI_CH15, 15 => configurable); +impl_ppi_channel!(PPI_CH0, DPPIC, 0 => configurable); +impl_ppi_channel!(PPI_CH1, DPPIC, 1 => configurable); +impl_ppi_channel!(PPI_CH2, DPPIC, 2 => configurable); +impl_ppi_channel!(PPI_CH3, DPPIC, 3 => configurable); +impl_ppi_channel!(PPI_CH4, DPPIC, 4 => configurable); +impl_ppi_channel!(PPI_CH5, DPPIC, 5 => configurable); +impl_ppi_channel!(PPI_CH6, DPPIC, 6 => configurable); +impl_ppi_channel!(PPI_CH7, DPPIC, 7 => configurable); +impl_ppi_channel!(PPI_CH8, DPPIC, 8 => configurable); +impl_ppi_channel!(PPI_CH9, DPPIC, 9 => configurable); +impl_ppi_channel!(PPI_CH10, DPPIC, 10 => configurable); +impl_ppi_channel!(PPI_CH11, DPPIC, 11 => configurable); +impl_ppi_channel!(PPI_CH12, DPPIC, 12 => configurable); +impl_ppi_channel!(PPI_CH13, DPPIC, 13 => configurable); +impl_ppi_channel!(PPI_CH14, DPPIC, 14 => configurable); +impl_ppi_channel!(PPI_CH15, DPPIC, 15 => configurable); + +impl_ppi_group!(PPI_GROUP0, DPPIC, 0); +impl_ppi_group!(PPI_GROUP1, DPPIC, 1); +impl_ppi_group!(PPI_GROUP2, DPPIC, 2); +impl_ppi_group!(PPI_GROUP3, DPPIC, 3); +impl_ppi_group!(PPI_GROUP4, DPPIC, 4); +impl_ppi_group!(PPI_GROUP5, DPPIC, 5); impl_saadc_input!(P0_13, ANALOG_INPUT0); impl_saadc_input!(P0_14, ANALOG_INPUT1); diff --git a/embassy-nrf/src/gpio.rs b/embassy-nrf/src/gpio.rs index 7ed3a7927..43d1b9cb2 100644 --- a/embassy-nrf/src/gpio.rs +++ b/embassy-nrf/src/gpio.rs @@ -585,7 +585,6 @@ impl SealedPin for AnyPin { // ==================== #[cfg(not(feature = "_nrf51"))] -#[cfg_attr(feature = "_nrf54l", allow(unused))] // TODO pub(crate) trait PselBits { fn psel_bits(&self) -> pac::shared::regs::Psel; } @@ -602,7 +601,6 @@ impl<'a, P: Pin> PselBits for Option> { } #[cfg(not(feature = "_nrf51"))] -#[cfg_attr(feature = "_nrf54l", allow(unused))] // TODO pub(crate) const DISCONNECTED: Psel = Psel(1 << 31); #[cfg(not(feature = "_nrf51"))] diff --git a/embassy-nrf/src/gpiote.rs b/embassy-nrf/src/gpiote.rs index 3658657c0..ed95f5d83 100644 --- a/embassy-nrf/src/gpiote.rs +++ b/embassy-nrf/src/gpiote.rs @@ -1,4 +1,5 @@ //! GPIO task/event (GPIOTE) driver. +#![macro_use] use core::convert::Infallible; use core::future::{Future, poll_fn}; @@ -7,7 +8,7 @@ use core::task::{Context, Poll}; use embassy_hal_internal::{Peri, PeripheralType, impl_peripheral}; use embassy_sync::waitqueue::AtomicWaker; -use crate::gpio::{AnyPin, Flex, Input, Output, Pin as GpioPin, SealedPin as _}; +use crate::gpio::{AnyPin, Flex, Input, Level, Output, OutputDrive, Pin as GpioPin, Pull, SealedPin as _}; use crate::interrupt::InterruptExt; #[cfg(not(feature = "_nrf51"))] use crate::pac::gpio::vals::Detectmode; @@ -19,13 +20,28 @@ use crate::{interrupt, pac, peripherals}; #[cfg(feature = "_nrf51")] /// Amount of GPIOTE channels in the chip. const CHANNEL_COUNT: usize = 4; -#[cfg(not(feature = "_nrf51"))] +#[cfg(not(any(feature = "_nrf51", feature = "_nrf54l")))] /// Amount of GPIOTE channels in the chip. const CHANNEL_COUNT: usize = 8; - -#[cfg(any(feature = "nrf52833", feature = "nrf52840", feature = "_nrf5340"))] +#[cfg(any(feature = "_nrf54l"))] +/// Amount of GPIOTE channels in the chip. +const CHANNEL_COUNT: usize = 12; +/// Max channels per port +const CHANNELS_PER_PORT: usize = 8; + +#[cfg(any( + feature = "nrf52833", + feature = "nrf52840", + feature = "_nrf5340", + feature = "_nrf54l" +))] const PIN_COUNT: usize = 48; -#[cfg(not(any(feature = "nrf52833", feature = "nrf52840", feature = "_nrf5340")))] +#[cfg(not(any( + feature = "nrf52833", + feature = "nrf52840", + feature = "_nrf5340", + feature = "_nrf54l" +)))] const PIN_COUNT: usize = 32; #[allow(clippy::declare_interior_mutable_const)] @@ -54,18 +70,6 @@ pub enum OutputChannelPolarity { Toggle, } -fn regs() -> pac::gpiote::Gpiote { - cfg_if::cfg_if! { - if #[cfg(any(feature="nrf5340-app-s", feature="nrf9160-s", feature="nrf9120-s"))] { - pac::GPIOTE0 - } else if #[cfg(any(feature="nrf5340-app-ns", feature="nrf9160-ns", feature="nrf9120-ns"))] { - pac::GPIOTE1 - } else { - pac::GPIOTE - } - } -} - pub(crate) fn init(irq_prio: crate::interrupt::Priority) { // no latched GPIO detect in nrf51. #[cfg(not(feature = "_nrf51"))] @@ -77,9 +81,9 @@ pub(crate) fn init(irq_prio: crate::interrupt::Priority) { for &p in ports { // Enable latched detection - #[cfg(feature = "_s")] + #[cfg(all(feature = "_s", not(feature = "_nrf54l")))] p.detectmode_sec().write(|w| w.set_detectmode(Detectmode::LDETECT)); - #[cfg(not(feature = "_s"))] + #[cfg(any(not(feature = "_s"), feature = "_nrf54l"))] p.detectmode().write(|w| w.set_detectmode(Detectmode::LDETECT)); // Clear latch p.latch().write(|w| w.0 = 0xFFFFFFFF) @@ -88,57 +92,136 @@ pub(crate) fn init(irq_prio: crate::interrupt::Priority) { // Enable interrupts #[cfg(any(feature = "nrf5340-app-s", feature = "nrf9160-s", feature = "nrf9120-s"))] - let irq = interrupt::GPIOTE0; + let irqs = &[(pac::GPIOTE0, interrupt::GPIOTE0)]; #[cfg(any(feature = "nrf5340-app-ns", feature = "nrf9160-ns", feature = "nrf9120-ns"))] - let irq = interrupt::GPIOTE1; + let irqs = &[(pac::GPIOTE1, interrupt::GPIOTE1)]; #[cfg(any(feature = "_nrf51", feature = "_nrf52", feature = "nrf5340-net"))] - let irq = interrupt::GPIOTE; + let irqs = &[(pac::GPIOTE, interrupt::GPIOTE)]; + #[cfg(any(feature = "_nrf54l"))] + let irqs = &[ + #[cfg(feature = "_s")] + (pac::GPIOTE20, interrupt::GPIOTE20_0), + #[cfg(feature = "_s")] + (pac::GPIOTE30, interrupt::GPIOTE30_0), + #[cfg(feature = "_ns")] + (pac::GPIOTE20, interrupt::GPIOTE20_1), + #[cfg(feature = "_ns")] + (pac::GPIOTE30, interrupt::GPIOTE30_1), + ]; + + for (inst, irq) in irqs { + irq.unpend(); + irq.set_priority(irq_prio); + unsafe { irq.enable() }; - irq.unpend(); - irq.set_priority(irq_prio); - unsafe { irq.enable() }; + let g = inst; + #[cfg(not(feature = "_nrf54l"))] + g.intenset(INTNUM).write(|w| w.set_port(true)); - let g = regs(); - g.intenset().write(|w| w.set_port(true)); + #[cfg(all(feature = "_nrf54l", feature = "_ns"))] + g.intenset(INTNUM).write(|w| w.set_port0nonsecure(true)); + + #[cfg(all(feature = "_nrf54l", feature = "_s"))] + g.intenset(INTNUM).write(|w| w.set_port0secure(true)); + } } +#[cfg(all(feature = "_nrf54l", feature = "_ns"))] +const INTNUM: usize = 1; + +#[cfg(any(not(feature = "_nrf54l"), feature = "_s"))] +const INTNUM: usize = 0; + #[cfg(any(feature = "nrf5340-app-s", feature = "nrf9160-s", feature = "nrf9120-s"))] #[cfg(feature = "rt")] #[interrupt] fn GPIOTE0() { - unsafe { handle_gpiote_interrupt() }; + unsafe { handle_gpiote_interrupt(pac::GPIOTE0) }; } #[cfg(any(feature = "nrf5340-app-ns", feature = "nrf9160-ns", feature = "nrf9120-ns"))] #[cfg(feature = "rt")] #[interrupt] fn GPIOTE1() { - unsafe { handle_gpiote_interrupt() }; + unsafe { handle_gpiote_interrupt(pac::GPIOTE1) }; } #[cfg(any(feature = "_nrf51", feature = "_nrf52", feature = "nrf5340-net"))] #[cfg(feature = "rt")] #[interrupt] fn GPIOTE() { - unsafe { handle_gpiote_interrupt() }; + info!("GPIOTE!"); + unsafe { handle_gpiote_interrupt(pac::GPIOTE) }; } -unsafe fn handle_gpiote_interrupt() { - let g = regs(); +#[cfg(all(feature = "_nrf54l", feature = "_s"))] +#[cfg(feature = "rt")] +#[interrupt] +fn GPIOTE20_0() { + info!("GPIOTE20_0!"); + unsafe { handle_gpiote_interrupt(pac::GPIOTE20) }; +} - for i in 0..CHANNEL_COUNT { +#[cfg(all(feature = "_nrf54l", feature = "_s"))] +#[cfg(feature = "rt")] +#[interrupt] +fn GPIOTE30_0() { + info!("GPIOTE30_0!"); + unsafe { handle_gpiote_interrupt(pac::GPIOTE30) }; +} + +#[cfg(all(feature = "_nrf54l", feature = "_ns"))] +#[cfg(feature = "rt")] +#[interrupt] +fn GPIOTE20_1() { + info!("GPIOTE20_1!"); + unsafe { handle_gpiote_interrupt(pac::GPIOTE20) }; +} + +#[cfg(all(feature = "_nrf54l", feature = "_ns"))] +#[cfg(feature = "rt")] +#[interrupt] +fn GPIOTE30_1() { + info!("GPIOTE30_1!"); + unsafe { handle_gpiote_interrupt(pac::GPIOTE30) }; +} + +unsafe fn handle_gpiote_interrupt(g: pac::gpiote::Gpiote) { + for c in 0..CHANNEL_COUNT { + let i = c % CHANNELS_PER_PORT; if g.events_in(i).read() != 0 { - g.intenclr().write(|w| w.0 = 1 << i); - CHANNEL_WAKERS[i].wake(); + info!("Clear IRQ {} waker {}", INTNUM, c); + g.intenclr(INTNUM).write(|w| w.0 = 1 << i); + CHANNEL_WAKERS[c].wake(); } } - if g.events_port().read() != 0 { - g.events_port().write_value(0); + #[cfg(not(feature = "_nrf54l"))] + let eport = g.events_port(0); - #[cfg(any(feature = "nrf52833", feature = "nrf52840", feature = "_nrf5340"))] + #[cfg(all(feature = "_nrf54l", feature = "_ns"))] + let eport = g.events_port(0).nonsecure(); + + #[cfg(all(feature = "_nrf54l", feature = "_s"))] + let eport = g.events_port(0).secure(); + + if eport.read() != 0 { + eport.write_value(0); + + #[cfg(any( + feature = "nrf52833", + feature = "nrf52840", + feature = "_nrf5340", + feature = "_nrf54l" + ))] let ports = &[pac::P0, pac::P1]; - #[cfg(not(any(feature = "_nrf51", feature = "nrf52833", feature = "nrf52840", feature = "_nrf5340")))] + #[cfg(not(any( + feature = "_nrf51", + feature = "nrf52833", + feature = "nrf52840", + feature = "_nrf5340", + feature = "_nrf54l" + )))] let ports = &[pac::P0]; #[cfg(feature = "_nrf51")] let ports = &[pac::GPIO]; @@ -162,9 +245,14 @@ unsafe fn handle_gpiote_interrupt() { #[cfg(not(feature = "_nrf51"))] for (port, &p) in ports.iter().enumerate() { + info!("Interrupt port {}", port); let bits = p.latch().read().0; for pin in BitIter(bits) { p.pin_cnf(pin as usize).modify(|w| w.set_sense(Sense::DISABLED)); + + let w = port * 32 + pin as usize; + + info!("Interrupt pin {}, waker {}", pin as usize, w); PORT_WAKERS[port * 32 + pin as usize].wake(); } p.latch().write(|w| w.0 = bits); @@ -207,19 +295,43 @@ impl InputChannel<'static> { impl<'d> Drop for InputChannel<'d> { fn drop(&mut self) { - let g = regs(); + let g = self.ch.regs(); let num = self.ch.number(); g.config(num).write(|w| w.set_mode(Mode::DISABLED)); - g.intenclr().write(|w| w.0 = 1 << num); + g.intenclr(INTNUM).write(|w| w.0 = 1 << num); } } impl<'d> InputChannel<'d> { /// Create a new GPIOTE input channel driver. - pub fn new(ch: Peri<'d, impl Channel>, pin: Input<'d>, polarity: InputChannelPolarity) -> Self { - let g = regs(); - let num = ch.number(); + #[cfg(feature = "_nrf54l")] + pub fn new>( + ch: Peri<'d, C>, + pin: Peri<'d, T>, + pull: Pull, + polarity: InputChannelPolarity, + ) -> Self { + let pin = Input::new(pin, pull); + let ch = ch.into(); + Self::new_inner(ch, pin, polarity) + } + /// Create a new GPIOTE output channel driver. + #[cfg(not(feature = "_nrf54l"))] + pub fn new( + ch: Peri<'d, C>, + pin: Peri<'d, T>, + pull: Pull, + polarity: InputChannelPolarity, + ) -> Self { + let pin = Input::new(pin, pull); + let ch = ch.into(); + Self::new_inner(ch, pin, polarity) + } + + fn new_inner(ch: Peri<'d, AnyChannel>, pin: Input<'d>, polarity: InputChannelPolarity) -> Self { + let g = ch.regs(); + let num = ch.number(); g.config(num).write(|w| { w.set_mode(Mode::EVENT); match polarity { @@ -228,30 +340,38 @@ impl<'d> InputChannel<'d> { InputChannelPolarity::None => w.set_polarity(Polarity::NONE), InputChannelPolarity::Toggle => w.set_polarity(Polarity::TOGGLE), }; - #[cfg(any(feature = "nrf52833", feature = "nrf52840", feature = "_nrf5340"))] + #[cfg(any(feature = "nrf52833", feature = "nrf52840", feature = "_nrf5340",))] w.set_port(match pin.pin.pin.port() { crate::gpio::Port::Port0 => false, crate::gpio::Port::Port1 => true, }); + #[cfg(any(feature = "_nrf54l"))] + w.set_port(match pin.pin.pin.port() { + crate::gpio::Port::Port0 => 0, + crate::gpio::Port::Port1 => 1, + crate::gpio::Port::Port2 => 2, + }); w.set_psel(pin.pin.pin.pin()); }); g.events_in(num).write_value(0); - InputChannel { ch: ch.into(), pin } + InputChannel { ch, pin } } /// Asynchronously wait for an event in this channel. pub async fn wait(&self) { - let g = regs(); + let g = self.ch.regs(); let num = self.ch.number(); + let waker = self.ch.waker(); // Enable interrupt g.events_in(num).write_value(0); - g.intenset().write(|w| w.0 = 1 << num); + g.intenset(INTNUM).write(|w| w.0 = 1 << num); poll_fn(|cx| { - CHANNEL_WAKERS[num].register(cx.waker()); + info!("Waiting for channel waker {}", num); + CHANNEL_WAKERS[waker].register(cx.waker()); if g.events_in(num).read() != 0 { Poll::Ready(()) @@ -269,7 +389,7 @@ impl<'d> InputChannel<'d> { /// Returns the IN event, for use with PPI. pub fn event_in(&self) -> Event<'d> { - let g = regs(); + let g = self.ch.regs(); Event::from_reg(g.events_in(self.ch.number())) } } @@ -291,17 +411,44 @@ impl OutputChannel<'static> { impl<'d> Drop for OutputChannel<'d> { fn drop(&mut self) { - let g = regs(); + let g = self.ch.regs(); let num = self.ch.number(); g.config(num).write(|w| w.set_mode(Mode::DISABLED)); - g.intenclr().write(|w| w.0 = 1 << num); + g.intenclr(INTNUM).write(|w| w.0 = 1 << num); } } impl<'d> OutputChannel<'d> { /// Create a new GPIOTE output channel driver. - pub fn new(ch: Peri<'d, impl Channel>, pin: Output<'d>, polarity: OutputChannelPolarity) -> Self { - let g = regs(); + #[cfg(feature = "_nrf54l")] + pub fn new>( + ch: Peri<'d, C>, + pin: Peri<'d, T>, + initial_output: Level, + drive: OutputDrive, + polarity: OutputChannelPolarity, + ) -> Self { + let pin = Output::new(pin, initial_output, drive); + let ch = ch.into(); + Self::new_inner(ch, pin, polarity) + } + + /// Create a new GPIOTE output channel driver. + #[cfg(not(feature = "_nrf54l"))] + pub fn new( + ch: Peri<'d, C>, + pin: Peri<'d, T>, + initial_output: Level, + drive: OutputDrive, + polarity: OutputChannelPolarity, + ) -> Self { + let pin = Output::new(pin, initial_output, drive); + let ch = ch.into(); + Self::new_inner(ch, pin, polarity) + } + + fn new_inner(ch: Peri<'d, AnyChannel>, pin: Output<'d>, polarity: OutputChannelPolarity) -> Self { + let g = ch.regs(); let num = ch.number(); g.config(num).write(|w| { @@ -320,52 +467,55 @@ impl<'d> OutputChannel<'d> { crate::gpio::Port::Port0 => false, crate::gpio::Port::Port1 => true, }); + #[cfg(any(feature = "_nrf54l"))] + w.set_port(match pin.pin.pin.port() { + crate::gpio::Port::Port0 => 0, + crate::gpio::Port::Port1 => 1, + crate::gpio::Port::Port2 => 2, + }); w.set_psel(pin.pin.pin.pin()); }); - OutputChannel { - ch: ch.into(), - _pin: pin, - } + OutputChannel { ch, _pin: pin } } /// Triggers the OUT task (does the action as configured with task_out_polarity, defaults to Toggle). pub fn out(&self) { - let g = regs(); + let g = self.ch.regs(); g.tasks_out(self.ch.number()).write_value(1); } /// Triggers the SET task (set associated pin high). #[cfg(not(feature = "_nrf51"))] pub fn set(&self) { - let g = regs(); + let g = self.ch.regs(); g.tasks_set(self.ch.number()).write_value(1); } /// Triggers the CLEAR task (set associated pin low). #[cfg(not(feature = "_nrf51"))] pub fn clear(&self) { - let g = regs(); + let g = self.ch.regs(); g.tasks_clr(self.ch.number()).write_value(1); } /// Returns the OUT task, for use with PPI. pub fn task_out(&self) -> Task<'d> { - let g = regs(); + let g = self.ch.regs(); Task::from_reg(g.tasks_out(self.ch.number())) } /// Returns the CLR task, for use with PPI. #[cfg(not(feature = "_nrf51"))] pub fn task_clr(&self) -> Task<'d> { - let g = regs(); + let g = self.ch.regs(); Task::from_reg(g.tasks_clr(self.ch.number())) } /// Returns the SET task, for use with PPI. #[cfg(not(feature = "_nrf51"))] pub fn task_set(&self) -> Task<'d> { - let g = regs(); + let g = self.ch.regs(); Task::from_reg(g.tasks_set(self.ch.number())) } } @@ -395,6 +545,7 @@ impl<'a> Future for PortInputFuture<'a> { type Output = (); fn poll(self: core::pin::Pin<&mut Self>, cx: &mut Context<'_>) -> Poll { + info!("register waker on {}", self.pin.port() as usize); PORT_WAKERS[self.pin.pin_port() as usize].register(cx.waker()); if self.pin.conf().read().sense() == Sense::DISABLED { @@ -467,31 +618,52 @@ impl<'d> Flex<'d> { PortInputFuture::new(self.pin.reborrow()).await } } - // ======================= +// -trait SealedChannel {} +trait SealedChannel { + fn waker(&self) -> usize; + fn regs(&self) -> pac::gpiote::Gpiote; +} /// GPIOTE channel trait. /// /// Implemented by all GPIOTE channels. #[allow(private_bounds)] pub trait Channel: PeripheralType + SealedChannel + Into + Sized + 'static { + #[cfg(feature = "_nrf54l")] + /// GPIOTE instance this channel belongs to. + type Instance: GpioteInstance; /// Get the channel number. fn number(&self) -> usize; } -/// Type-erased channel. -/// -/// Obtained by calling `Channel::into()`. -/// -/// This allows using several channels in situations that might require -/// them to be the same type, like putting them in an array. -pub struct AnyChannel { +struct AnyChannel { number: u8, + regs: pac::gpiote::Gpiote, + waker: u8, } + impl_peripheral!(AnyChannel); -impl SealedChannel for AnyChannel {} + +impl SealedChannel for AnyChannel { + fn waker(&self) -> usize { + self.waker as usize + } + + fn regs(&self) -> pac::gpiote::Gpiote { + self.regs + } +} + +#[cfg(feature = "_nrf54l")] +impl AnyChannel { + fn number(&self) -> usize { + self.number as usize + } +} + +#[cfg(not(feature = "_nrf54l"))] impl Channel for AnyChannel { fn number(&self) -> usize { self.number as usize @@ -499,9 +671,19 @@ impl Channel for AnyChannel { } macro_rules! impl_channel { - ($type:ident, $number:expr) => { - impl SealedChannel for peripherals::$type {} + ($type:ident, $inst:ident, $number:expr, $waker:expr) => { + impl SealedChannel for peripherals::$type { + fn waker(&self) -> usize { + $waker as usize + } + + fn regs(&self) -> pac::gpiote::Gpiote { + pac::$inst + } + } impl Channel for peripherals::$type { + #[cfg(feature = "_nrf54l")] + type Instance = peripherals::$inst; fn number(&self) -> usize { $number as usize } @@ -511,24 +693,97 @@ macro_rules! impl_channel { fn from(val: peripherals::$type) -> Self { Self { number: val.number() as u8, + waker: val.waker() as u8, + regs: val.regs(), } } } }; } -impl_channel!(GPIOTE_CH0, 0); -impl_channel!(GPIOTE_CH1, 1); -impl_channel!(GPIOTE_CH2, 2); -impl_channel!(GPIOTE_CH3, 3); -#[cfg(not(feature = "_nrf51"))] -impl_channel!(GPIOTE_CH4, 4); -#[cfg(not(feature = "_nrf51"))] -impl_channel!(GPIOTE_CH5, 5); -#[cfg(not(feature = "_nrf51"))] -impl_channel!(GPIOTE_CH6, 6); -#[cfg(not(feature = "_nrf51"))] -impl_channel!(GPIOTE_CH7, 7); +cfg_if::cfg_if! { + if #[cfg(feature = "_nrf54l")] { + trait SealedGpioteInstance {} + /// Represents a GPIOTE instance. + #[allow(private_bounds)] + pub trait GpioteInstance: PeripheralType + SealedGpioteInstance + Sized + 'static {} + + macro_rules! impl_gpiote { + ($type:ident) => { + impl SealedGpioteInstance for peripherals::$type {} + impl GpioteInstance for peripherals::$type {} + }; + } + + pub(crate) trait SealedGpiotePin {} + + /// Represents a GPIO pin that can be used with GPIOTE. + #[allow(private_bounds)] + pub trait GpiotePin: GpioPin + SealedGpiotePin { + /// The GPIOTE instance this pin belongs to. + type Instance: GpioteInstance; + } + + macro_rules! impl_gpiote_pin { + ($type:ident, $inst:ident) => { + #[cfg(feature = "gpiote")] + impl crate::gpiote::SealedGpiotePin for peripherals::$type {} + #[cfg(feature = "gpiote")] + impl crate::gpiote::GpiotePin for peripherals::$type { + type Instance = peripherals::$inst; + } + }; + } + + impl_gpiote!(GPIOTE20); + impl_gpiote!(GPIOTE30); + impl_channel!(GPIOTE_CH0, GPIOTE20, 0, 0); + impl_channel!(GPIOTE_CH1, GPIOTE20, 1, 1); + impl_channel!(GPIOTE_CH2, GPIOTE20, 2, 2); + impl_channel!(GPIOTE_CH3, GPIOTE20, 3, 3); + impl_channel!(GPIOTE_CH4, GPIOTE20, 4, 4); + impl_channel!(GPIOTE_CH5, GPIOTE20, 5, 5); + impl_channel!(GPIOTE_CH6, GPIOTE20, 6, 6); + impl_channel!(GPIOTE_CH7, GPIOTE20, 7, 7); + + impl_channel!(GPIOTE_CH8, GPIOTE30, 0, 8); + impl_channel!(GPIOTE_CH9, GPIOTE30, 1, 9); + impl_channel!(GPIOTE_CH10, GPIOTE30, 2, 10); + impl_channel!(GPIOTE_CH11, GPIOTE30, 3, 11); + } else if #[cfg(feature = "_nrf51")] { + impl_channel!(GPIOTE_CH0, GPIOTE, 0, 0); + impl_channel!(GPIOTE_CH1, GPIOTE, 1, 1); + impl_channel!(GPIOTE_CH2, GPIOTE, 2, 2); + impl_channel!(GPIOTE_CH3, GPIOTE, 3, 3); + } else if #[cfg(all(feature = "_s", any(feature = "_nrf91", feature = "_nrf5340")))] { + impl_channel!(GPIOTE_CH0, GPIOTE0, 0, 0); + impl_channel!(GPIOTE_CH1, GPIOTE0, 1, 1); + impl_channel!(GPIOTE_CH2, GPIOTE0, 2, 2); + impl_channel!(GPIOTE_CH3, GPIOTE0, 3, 3); + impl_channel!(GPIOTE_CH4, GPIOTE0, 4, 4); + impl_channel!(GPIOTE_CH5, GPIOTE0, 5, 5); + impl_channel!(GPIOTE_CH6, GPIOTE0, 6, 6); + impl_channel!(GPIOTE_CH7, GPIOTE0, 7, 7); + } else if #[cfg(all(feature = "_ns", any(feature = "_nrf91", feature = "_nrf5340")))] { + impl_channel!(GPIOTE_CH0, GPIOTE1, 0, 0); + impl_channel!(GPIOTE_CH1, GPIOTE1, 1, 1); + impl_channel!(GPIOTE_CH2, GPIOTE1, 2, 2); + impl_channel!(GPIOTE_CH3, GPIOTE1, 3, 3); + impl_channel!(GPIOTE_CH4, GPIOTE1, 4, 4); + impl_channel!(GPIOTE_CH5, GPIOTE1, 5, 5); + impl_channel!(GPIOTE_CH6, GPIOTE1, 6, 6); + impl_channel!(GPIOTE_CH7, GPIOTE1, 7, 7); + } else { + impl_channel!(GPIOTE_CH0, GPIOTE, 0, 0); + impl_channel!(GPIOTE_CH1, GPIOTE, 1, 1); + impl_channel!(GPIOTE_CH2, GPIOTE, 2, 2); + impl_channel!(GPIOTE_CH3, GPIOTE, 3, 3); + impl_channel!(GPIOTE_CH4, GPIOTE, 4, 4); + impl_channel!(GPIOTE_CH5, GPIOTE, 5, 5); + impl_channel!(GPIOTE_CH6, GPIOTE, 6, 6); + impl_channel!(GPIOTE_CH7, GPIOTE, 7, 7); + } +} // ==================== diff --git a/embassy-nrf/src/lib.rs b/embassy-nrf/src/lib.rs index 705c77453..2f7505746 100644 --- a/embassy-nrf/src/lib.rs +++ b/embassy-nrf/src/lib.rs @@ -76,14 +76,12 @@ pub(crate) mod util; #[cfg(feature = "_time-driver")] mod time_driver; -#[cfg(not(feature = "_nrf54l"))] // TODO #[cfg(not(feature = "_nrf51"))] pub mod buffered_uarte; #[cfg(not(feature = "_nrf54l"))] // TODO #[cfg(not(feature = "_nrf51"))] pub mod egu; pub mod gpio; -#[cfg(not(feature = "_nrf54l"))] // TODO #[cfg(feature = "gpiote")] pub mod gpiote; #[cfg(not(feature = "_nrf54l"))] // TODO @@ -119,9 +117,7 @@ pub mod pdm; #[cfg(not(feature = "_nrf54l"))] // TODO #[cfg(any(feature = "nrf52840", feature = "nrf9160-s", feature = "nrf9160-ns"))] pub mod power; -#[cfg(not(feature = "_nrf54l"))] // TODO pub mod ppi; -#[cfg(not(feature = "_nrf54l"))] // TODO #[cfg(not(any( feature = "_nrf51", feature = "nrf52805", @@ -156,26 +152,19 @@ pub mod reset; #[cfg(not(any(feature = "_nrf5340-app", feature = "_nrf91")))] pub mod rng; pub mod rtc; -#[cfg(not(feature = "_nrf54l"))] // TODO #[cfg(not(any(feature = "_nrf51", feature = "nrf52820", feature = "_nrf5340-net")))] pub mod saadc; -#[cfg(not(feature = "_nrf54l"))] // TODO #[cfg(not(feature = "_nrf51"))] pub mod spim; -#[cfg(not(feature = "_nrf54l"))] // TODO #[cfg(not(feature = "_nrf51"))] pub mod spis; #[cfg(not(any(feature = "_nrf5340-app", feature = "_nrf91")))] pub mod temp; -#[cfg(not(feature = "_nrf54l"))] // TODO pub mod timer; -#[cfg(not(feature = "_nrf54l"))] // TODO #[cfg(not(feature = "_nrf51"))] pub mod twim; -#[cfg(not(feature = "_nrf54l"))] // TODO #[cfg(not(feature = "_nrf51"))] pub mod twis; -#[cfg(not(feature = "_nrf54l"))] // TODO #[cfg(not(feature = "_nrf51"))] pub mod uarte; #[cfg(not(feature = "_nrf54l"))] // TODO @@ -1153,7 +1142,6 @@ pub fn init(config: config::Config) -> Peripherals { } // Init GPIOTE - #[cfg(not(feature = "_nrf54l"))] // TODO #[cfg(feature = "gpiote")] gpiote::init(config.gpiote_interrupt_priority); diff --git a/embassy-nrf/src/ppi/dppi.rs b/embassy-nrf/src/ppi/dppi.rs index 168647be3..d43a25c4e 100644 --- a/embassy-nrf/src/ppi/dppi.rs +++ b/embassy-nrf/src/ppi/dppi.rs @@ -1,11 +1,12 @@ use super::{Channel, ConfigurableChannel, Event, Ppi, Task}; -use crate::{Peri, pac}; +use crate::Peri; const DPPI_ENABLE_BIT: u32 = 0x8000_0000; const DPPI_CHANNEL_MASK: u32 = 0x0000_00FF; -pub(crate) fn regs() -> pac::dppic::Dppic { - pac::DPPIC +#[cfg(not(feature = "_nrf54l"))] +pub(crate) fn regs() -> crate::pac::dppic::Dppic { + crate::pac::DPPIC } impl<'d, C: ConfigurableChannel> Ppi<'d, C, 1, 1> { @@ -49,13 +50,13 @@ impl<'d, C: Channel, const EVENT_COUNT: usize, const TASK_COUNT: usize> Ppi<'d, /// Enables the channel. pub fn enable(&mut self) { let n = self.ch.number(); - regs().chenset().write(|w| w.0 = 1 << n); + self.ch.regs().chenset().write(|w| w.0 = 1 << n); } /// Disables the channel. pub fn disable(&mut self) { let n = self.ch.number(); - regs().chenclr().write(|w| w.0 = 1 << n); + self.ch.regs().chenclr().write(|w| w.0 = 1 << n); } } diff --git a/embassy-nrf/src/ppi/mod.rs b/embassy-nrf/src/ppi/mod.rs index f30c2218d..a880d3188 100644 --- a/embassy-nrf/src/ppi/mod.rs +++ b/embassy-nrf/src/ppi/mod.rs @@ -21,11 +21,13 @@ use core::ptr::NonNull; use embassy_hal_internal::{Peri, PeripheralType, impl_peripheral}; use crate::pac::common::{RW, Reg, W}; -use crate::peripherals; +use crate::pac::{self}; #[cfg_attr(feature = "_dppi", path = "dppi.rs")] #[cfg_attr(feature = "_ppi", path = "ppi.rs")] mod _version; + +#[allow(unused_imports)] pub(crate) use _version::*; /// PPI channel driver. @@ -47,7 +49,7 @@ impl<'d, G: Group> PpiGroup<'d, G> { /// /// The group is initialized as containing no channels. pub fn new(g: Peri<'d, G>) -> Self { - let r = regs(); + let r = g.regs(); let n = g.number(); r.chg(n).write(|_| ()); @@ -61,7 +63,7 @@ impl<'d, G: Group> PpiGroup<'d, G> { &mut self, ch: &Ppi<'_, C, EVENT_COUNT, TASK_COUNT>, ) { - let r = regs(); + let r = self.g.regs(); let ng = self.g.number(); let nc = ch.ch.number(); r.chg(ng).modify(|w| w.set_ch(nc, true)); @@ -74,7 +76,7 @@ impl<'d, G: Group> PpiGroup<'d, G> { &mut self, ch: &Ppi<'_, C, EVENT_COUNT, TASK_COUNT>, ) { - let r = regs(); + let r = self.g.regs(); let ng = self.g.number(); let nc = ch.ch.number(); r.chg(ng).modify(|w| w.set_ch(nc, false)); @@ -83,13 +85,13 @@ impl<'d, G: Group> PpiGroup<'d, G> { /// Enable all the channels in this group. pub fn enable_all(&mut self) { let n = self.g.number(); - regs().tasks_chg(n).en().write_value(1); + self.g.regs().tasks_chg(n).en().write_value(1); } /// Disable all the channels in this group. pub fn disable_all(&mut self) { let n = self.g.number(); - regs().tasks_chg(n).dis().write_value(1); + self.g.regs().tasks_chg(n).dis().write_value(1); } /// Get a reference to the "enable all" task. @@ -97,7 +99,7 @@ impl<'d, G: Group> PpiGroup<'d, G> { /// When triggered, it will enable all the channels in this group. pub fn task_enable_all(&self) -> Task<'d> { let n = self.g.number(); - Task::from_reg(regs().tasks_chg(n).en()) + Task::from_reg(self.g.regs().tasks_chg(n).en()) } /// Get a reference to the "disable all" task. @@ -105,7 +107,7 @@ impl<'d, G: Group> PpiGroup<'d, G> { /// When triggered, it will disable all the channels in this group. pub fn task_disable_all(&self) -> Task<'d> { let n = self.g.number(); - Task::from_reg(regs().tasks_chg(n).dis()) + Task::from_reg(self.g.regs().tasks_chg(n).dis()) } } impl PpiGroup<'static, G> { @@ -119,7 +121,7 @@ impl PpiGroup<'static, G> { impl<'d, G: Group> Drop for PpiGroup<'d, G> { fn drop(&mut self) { - let r = regs(); + let r = self.g.regs(); let n = self.g.number(); r.chg(n).write(|_| ()); } @@ -211,8 +213,16 @@ unsafe impl Send for Event<'_> {} // ====================== // traits -pub(crate) trait SealedChannel {} -pub(crate) trait SealedGroup {} +pub(crate) trait SealedChannel { + #[cfg(feature = "_dppi")] + fn regs(&self) -> pac::dppic::Dppic; +} +pub(crate) trait SealedGroup { + #[cfg(feature = "_dppi")] + fn regs(&self) -> pac::dppic::Dppic; + #[cfg(not(feature = "_dppi"))] + fn regs(&self) -> pac::ppi::Ppi; +} /// Interface for PPI channels. #[allow(private_bounds)] @@ -241,9 +251,16 @@ pub trait Group: SealedGroup + PeripheralType + Into + Sized + 'static /// This can be used to have fewer generic parameters in some places. pub struct AnyStaticChannel { pub(crate) number: u8, + #[cfg(feature = "_dppi")] + pub(crate) regs: pac::dppic::Dppic, } impl_peripheral!(AnyStaticChannel); -impl SealedChannel for AnyStaticChannel {} +impl SealedChannel for AnyStaticChannel { + #[cfg(feature = "_dppi")] + fn regs(&self) -> pac::dppic::Dppic { + self.regs + } +} impl Channel for AnyStaticChannel { fn number(&self) -> usize { self.number as usize @@ -255,9 +272,16 @@ impl StaticChannel for AnyStaticChannel {} /// This can be used to have fewer generic parameters in some places. pub struct AnyConfigurableChannel { pub(crate) number: u8, + #[cfg(feature = "_dppi")] + pub(crate) regs: pac::dppic::Dppic, } impl_peripheral!(AnyConfigurableChannel); -impl SealedChannel for AnyConfigurableChannel {} +impl SealedChannel for AnyConfigurableChannel { + #[cfg(feature = "_dppi")] + fn regs(&self) -> pac::dppic::Dppic { + self.regs + } +} impl Channel for AnyConfigurableChannel { fn number(&self) -> usize { self.number as usize @@ -267,32 +291,41 @@ impl ConfigurableChannel for AnyConfigurableChannel {} #[cfg(not(feature = "_nrf51"))] macro_rules! impl_ppi_channel { - ($type:ident, $number:expr) => { - impl crate::ppi::SealedChannel for peripherals::$type {} + ($type:ident, $inst:ident, $number:expr) => { + impl crate::ppi::SealedChannel for peripherals::$type { + #[cfg(feature = "_dppi")] + fn regs(&self) -> pac::dppic::Dppic { + pac::$inst + } + } impl crate::ppi::Channel for peripherals::$type { fn number(&self) -> usize { $number } } }; - ($type:ident, $number:expr => static) => { - impl_ppi_channel!($type, $number); + ($type:ident, $inst:ident, $number:expr => static) => { + impl_ppi_channel!($type, $inst, $number); impl crate::ppi::StaticChannel for peripherals::$type {} impl From for crate::ppi::AnyStaticChannel { fn from(val: peripherals::$type) -> Self { Self { number: crate::ppi::Channel::number(&val) as u8, + #[cfg(feature = "_dppi")] + regs: pac::$inst, } } } }; - ($type:ident, $number:expr => configurable) => { - impl_ppi_channel!($type, $number); + ($type:ident, $inst:ident, $number:expr => configurable) => { + impl_ppi_channel!($type, $inst, $number); impl crate::ppi::ConfigurableChannel for peripherals::$type {} impl From for crate::ppi::AnyConfigurableChannel { fn from(val: peripherals::$type) -> Self { Self { number: crate::ppi::Channel::number(&val) as u8, + #[cfg(feature = "_dppi")] + regs: pac::$inst, } } } @@ -304,40 +337,54 @@ macro_rules! impl_ppi_channel { /// A type erased PPI group. pub struct AnyGroup { - number: u8, + pub(crate) number: u8, + #[cfg(feature = "_dppi")] + pub(crate) regs: pac::dppic::Dppic, + #[cfg(not(feature = "_dppi"))] + pub(crate) regs: pac::ppi::Ppi, } impl_peripheral!(AnyGroup); -impl SealedGroup for AnyGroup {} +impl SealedGroup for AnyGroup { + #[cfg(feature = "_dppi")] + fn regs(&self) -> pac::dppic::Dppic { + self.regs + } + #[cfg(not(feature = "_dppi"))] + fn regs(&self) -> pac::ppi::Ppi { + self.regs + } +} impl Group for AnyGroup { fn number(&self) -> usize { self.number as usize } } -macro_rules! impl_group { - ($type:ident, $number:expr) => { - impl SealedGroup for peripherals::$type {} - impl Group for peripherals::$type { +macro_rules! impl_ppi_group { + ($type:ident, $inst:ident, $number:expr) => { + impl crate::ppi::SealedGroup for crate::peripherals::$type { + #[cfg(feature = "_dppi")] + fn regs(&self) -> pac::dppic::Dppic { + pac::$inst + } + #[cfg(not(feature = "_dppi"))] + fn regs(&self) -> pac::ppi::Ppi { + pac::$inst + } + } + impl crate::ppi::Group for crate::peripherals::$type { fn number(&self) -> usize { $number } } - impl From for crate::ppi::AnyGroup { - fn from(val: peripherals::$type) -> Self { + impl From for crate::ppi::AnyGroup { + fn from(val: crate::peripherals::$type) -> Self { Self { number: crate::ppi::Group::number(&val) as u8, + regs: pac::$inst, } } } }; } - -impl_group!(PPI_GROUP0, 0); -impl_group!(PPI_GROUP1, 1); -impl_group!(PPI_GROUP2, 2); -impl_group!(PPI_GROUP3, 3); -#[cfg(not(feature = "_nrf51"))] -impl_group!(PPI_GROUP4, 4); -#[cfg(not(feature = "_nrf51"))] -impl_group!(PPI_GROUP5, 5); diff --git a/embassy-nrf/src/pwm.rs b/embassy-nrf/src/pwm.rs index 00b3278c7..04eb14a77 100644 --- a/embassy-nrf/src/pwm.rs +++ b/embassy-nrf/src/pwm.rs @@ -203,7 +203,7 @@ impl<'d> SequencePwm<'d> { /// Interacting with the sequence while it runs puts it in an unknown state #[inline(always)] pub unsafe fn task_start_seq0(&self) -> Task<'d> { - Task::from_reg(self.r.tasks_seqstart(0)) + Task::from_reg(self.r.tasks_dma().seq(0).start()) } /// Returns reference to `Seq1 Started` task endpoint for PPI. @@ -212,7 +212,7 @@ impl<'d> SequencePwm<'d> { /// Interacting with the sequence while it runs puts it in an unknown state #[inline(always)] pub unsafe fn task_start_seq1(&self) -> Task<'d> { - Task::from_reg(self.r.tasks_seqstart(1)) + Task::from_reg(self.r.tasks_dma().seq(1).start()) } /// Returns reference to `NextStep` task endpoint for PPI. @@ -444,6 +444,21 @@ pub struct Sequencer<'d, 's> { sequence1: Option>, } +#[cfg(feature = "_nrf54l")] +fn pwmseq(r: pac::pwm::Pwm, n: usize) -> pac::pwm::PwmSeq { + r.seq(n) +} + +#[cfg(not(feature = "_nrf54l"))] +fn pwmseq(r: pac::pwm::Pwm, n: usize) -> pac::pwm::DmaSeq { + r.dma().seq(n) +} + +#[cfg(feature = "_nrf54l")] +const CNT_UNIT: u32 = 2; +#[cfg(not(feature = "_nrf54l"))] +const CNT_UNIT: u32 = 1; + impl<'d, 's> Sequencer<'d, 's> { /// Create a new double sequence. In the absence of sequence 1, sequence 0 /// will be used twice in the one loop. @@ -476,15 +491,21 @@ impl<'d, 's> Sequencer<'d, 's> { let r = self._pwm.r; - r.seq(0).refresh().write(|w| w.0 = sequence0.config.refresh); - r.seq(0).enddelay().write(|w| w.0 = sequence0.config.end_delay); - r.seq(0).ptr().write_value(sequence0.words.as_ptr() as u32); - r.seq(0).cnt().write(|w| w.0 = sequence0.words.len() as u32); - - r.seq(1).refresh().write(|w| w.0 = alt_sequence.config.refresh); - r.seq(1).enddelay().write(|w| w.0 = alt_sequence.config.end_delay); - r.seq(1).ptr().write_value(alt_sequence.words.as_ptr() as u32); - r.seq(1).cnt().write(|w| w.0 = alt_sequence.words.len() as u32); + pwmseq(r, 0).refresh().write(|w| w.0 = sequence0.config.refresh); + pwmseq(r, 0).enddelay().write(|w| w.0 = sequence0.config.end_delay); + r.dma().seq(0).ptr().write_value(sequence0.words.as_ptr() as u32); + r.dma() + .seq(0) + .maxcnt() + .write(|w| w.0 = sequence0.words.len() as u32 * CNT_UNIT); + + pwmseq(r, 1).refresh().write(|w| w.0 = alt_sequence.config.refresh); + pwmseq(r, 1).enddelay().write(|w| w.0 = alt_sequence.config.end_delay); + r.dma().seq(1).ptr().write_value(alt_sequence.words.as_ptr() as u32); + r.dma() + .seq(1) + .maxcnt() + .write(|w| w.0 = alt_sequence.words.len() as u32 * CNT_UNIT); r.enable().write(|w| w.set_enable(true)); @@ -500,11 +521,11 @@ impl<'d, 's> Sequencer<'d, 's> { // to play infinitely, repeat the sequence one time, then have loops done self trigger seq0 again SequenceMode::Infinite => { r.loop_().write(|w| w.set_cnt(vals::LoopCnt::from_bits(1))); - r.shorts().write(|w| w.set_loopsdone_seqstart0(true)); + r.shorts().write(|w| w.set_loopsdone_dma_seq0_start(true)); } } - r.tasks_seqstart(seqstart_index).write_value(1); + r.tasks_dma().seq(seqstart_index).start().write_value(1); Ok(()) } @@ -781,10 +802,10 @@ impl<'d> SimplePwm<'d> { // Enable r.enable().write(|w| w.set_enable(true)); - r.seq(0).ptr().write_value((pwm.duty).as_ptr() as u32); - r.seq(0).cnt().write(|w| w.0 = 4); - r.seq(0).refresh().write(|w| w.0 = 0); - r.seq(0).enddelay().write(|w| w.0 = 0); + r.dma().seq(0).ptr().write_value((pwm.duty).as_ptr() as u32); + r.dma().seq(0).maxcnt().write(|w| w.0 = 4 * CNT_UNIT); + pwmseq(r, 0).refresh().write(|w| w.0 = 0); + pwmseq(r, 0).enddelay().write(|w| w.0 = 0); r.decoder().write(|w| { w.set_load(vals::Load::INDIVIDUAL); @@ -846,7 +867,7 @@ impl<'d> SimplePwm<'d> { /// Transfer the duty cycles from `self` to the peripheral. fn sync_duty_cyles_to_peripheral(&self) { // reload ptr in case self was moved - self.r.seq(0).ptr().write_value((self.duty).as_ptr() as u32); + self.r.dma().seq(0).ptr().write_value((self.duty).as_ptr() as u32); // defensive before seqstart compiler_fence(Ordering::SeqCst); @@ -854,7 +875,7 @@ impl<'d> SimplePwm<'d> { self.r.events_seqend(0).write_value(0); // tasks_seqstart() doesn't exist in all svds so write its bit instead - self.r.tasks_seqstart(0).write_value(1); + self.r.tasks_dma().seq(0).start().write_value(1); // defensive wait until waveform is loaded after seqstart so set_duty // can't be called again while dma is still reading diff --git a/embassy-nrf/src/saadc.rs b/embassy-nrf/src/saadc.rs index a199c1c4d..ca8cbd73e 100644 --- a/embassy-nrf/src/saadc.rs +++ b/embassy-nrf/src/saadc.rs @@ -10,6 +10,7 @@ use core::task::Poll; use embassy_hal_internal::drop::OnDrop; use embassy_hal_internal::{Peri, impl_peripheral}; use embassy_sync::waitqueue::AtomicWaker; +#[cfg(not(feature = "_nrf54l"))] pub(crate) use vals::Psel as InputChannel; use crate::interrupt::InterruptExt; @@ -84,6 +85,7 @@ pub struct ChannelConfig<'d> { /// Gain used to control the effective input range of the SAADC. pub gain: Gain, /// Positive channel resistor control. + #[cfg(not(feature = "_nrf54l"))] pub resistor: Resistor, /// Acquisition time in microseconds. pub time: Time, @@ -98,7 +100,11 @@ impl<'d> ChannelConfig<'d> { pub fn single_ended(input: impl Input + 'd) -> Self { Self { reference: Reference::INTERNAL, + #[cfg(not(feature = "_nrf54l"))] gain: Gain::GAIN1_6, + #[cfg(feature = "_nrf54l")] + gain: Gain::GAIN2_8, + #[cfg(not(feature = "_nrf54l"))] resistor: Resistor::BYPASS, time: Time::_10US, p_channel: input.degrade_saadc(), @@ -109,7 +115,11 @@ impl<'d> ChannelConfig<'d> { pub fn differential(p_input: impl Input + 'd, n_input: impl Input + 'd) -> Self { Self { reference: Reference::INTERNAL, + #[cfg(not(feature = "_nrf54l"))] gain: Gain::GAIN1_6, + #[cfg(feature = "_nrf54l")] + gain: Gain::GAIN2_8, + #[cfg(not(feature = "_nrf54l"))] resistor: Resistor::BYPASS, time: Time::_10US, p_channel: p_input.degrade_saadc(), @@ -118,6 +128,8 @@ impl<'d> ChannelConfig<'d> { } } +const CNT_UNIT: usize = if cfg!(feature = "_nrf54l") { 2 } else { 1 }; + /// Value returned by the SAADC callback, deciding what happens next. #[derive(PartialEq)] pub enum CallbackResult { @@ -150,19 +162,38 @@ impl<'d, const N: usize> Saadc<'d, N> { r.oversample().write(|w| w.set_oversample(oversample.into())); for (i, cc) in channel_configs.iter().enumerate() { + #[cfg(not(feature = "_nrf54l"))] r.ch(i).pselp().write(|w| w.set_pselp(cc.p_channel.channel())); + #[cfg(feature = "_nrf54l")] + r.ch(i).pselp().write(|w| { + w.set_port(cc.p_channel.port()); + w.set_pin(cc.p_channel.pin()); + w.set_internal(cc.p_channel.internal()); + w.set_connect(cc.p_channel.connect()); + }); if let Some(n_channel) = &cc.n_channel { + #[cfg(not(feature = "_nrf54l"))] r.ch(i).pseln().write(|w| w.set_pseln(n_channel.channel())); + #[cfg(feature = "_nrf54l")] + r.ch(i).pseln().write(|w| { + w.set_port(n_channel.port()); + w.set_pin(n_channel.pin()); + w.set_connect(n_channel.connect().to_bits().into()); + }); } r.ch(i).config().write(|w| { w.set_refsel(cc.reference.into()); w.set_gain(cc.gain.into()); w.set_tacq(cc.time.into()); + #[cfg(feature = "_nrf54l")] + w.set_tconv(7); // 7 is the default from the Nordic C driver w.set_mode(match cc.n_channel { None => vals::ConfigMode::SE, Some(_) => vals::ConfigMode::DIFF, }); + #[cfg(not(feature = "_nrf54l"))] w.set_resp(cc.resistor.into()); + #[cfg(not(feature = "_nrf54l"))] w.set_resn(vals::Resn::BYPASS); w.set_burst(!matches!(oversample, Oversample::BYPASS)); }); @@ -222,7 +253,7 @@ impl<'d, const N: usize> Saadc<'d, N> { // Set up the DMA r.result().ptr().write_value(buf.as_mut_ptr() as u32); - r.result().maxcnt().write(|w| w.set_maxcnt(N as _)); + r.result().maxcnt().write(|w| w.set_maxcnt((N * CNT_UNIT) as _)); // Reset and enable the end event r.events_end().write_value(0); @@ -354,7 +385,7 @@ impl<'d, const N: usize> Saadc<'d, N> { // Set up the initial DMA r.result().ptr().write_value(bufs[0].as_mut_ptr() as u32); - r.result().maxcnt().write(|w| w.set_maxcnt((N0 * N) as _)); + r.result().maxcnt().write(|w| w.set_maxcnt((N0 * N * CNT_UNIT) as _)); // Reset and enable the events r.events_end().write_value(0); @@ -473,12 +504,21 @@ impl<'d, const N: usize> Drop for Saadc<'d, N> { let r = Self::regs(); r.enable().write(|w| w.set_enable(false)); for i in 0..N { - r.ch(i).pselp().write(|w| w.set_pselp(InputChannel::NC)); - r.ch(i).pseln().write(|w| w.set_pseln(InputChannel::NC)); + #[cfg(not(feature = "_nrf54l"))] + { + r.ch(i).pselp().write(|w| w.set_pselp(InputChannel::NC)); + r.ch(i).pseln().write(|w| w.set_pseln(InputChannel::NC)); + } + #[cfg(feature = "_nrf54l")] + { + r.ch(i).pselp().write(|w| w.set_connect(vals::PselpConnect::NC)); + r.ch(i).pseln().write(|w| w.set_connect(vals::PselnConnect::NC)); + } } } } +#[cfg(not(feature = "_nrf54l"))] impl From for vals::Gain { fn from(gain: Gain) -> Self { match gain { @@ -494,7 +534,24 @@ impl From for vals::Gain { } } +#[cfg(feature = "_nrf54l")] +impl From for vals::Gain { + fn from(gain: Gain) -> Self { + match gain { + Gain::GAIN2_8 => vals::Gain::GAIN2_8, + Gain::GAIN2_7 => vals::Gain::GAIN2_7, + Gain::GAIN2_6 => vals::Gain::GAIN2_6, + Gain::GAIN2_5 => vals::Gain::GAIN2_5, + Gain::GAIN2_4 => vals::Gain::GAIN2_4, + Gain::GAIN2_3 => vals::Gain::GAIN2_3, + Gain::GAIN1 => vals::Gain::GAIN1, + Gain::GAIN2 => vals::Gain::GAIN2, + } + } +} + /// Gain control +#[cfg(not(feature = "_nrf54l"))] #[non_exhaustive] #[derive(Clone, Copy)] pub enum Gain { @@ -516,11 +573,37 @@ pub enum Gain { GAIN4 = 7, } +/// Gain control +#[cfg(feature = "_nrf54l")] +#[non_exhaustive] +#[derive(Clone, Copy)] +pub enum Gain { + /// 2/8 + GAIN2_8 = 0, + /// 2/7 + GAIN2_7 = 1, + /// 2/6 + GAIN2_6 = 2, + /// 2/5 + GAIN2_5 = 3, + /// 2/4 + GAIN2_4 = 4, + /// 2/3 + GAIN2_3 = 5, + /// 1 + GAIN1 = 6, + /// 2 + GAIN2 = 7, +} + impl From for vals::Refsel { fn from(reference: Reference) -> Self { match reference { Reference::INTERNAL => vals::Refsel::INTERNAL, + #[cfg(not(feature = "_nrf54l"))] Reference::VDD1_4 => vals::Refsel::VDD1_4, + #[cfg(feature = "_nrf54l")] + Reference::EXTERNAL => vals::Refsel::EXTERNAL, } } } @@ -531,10 +614,15 @@ impl From for vals::Refsel { pub enum Reference { /// Internal reference (0.6 V) INTERNAL = 0, + #[cfg(not(feature = "_nrf54l"))] /// VDD/4 as reference VDD1_4 = 1, + /// PADC_EXT_REF_1V2 as reference + #[cfg(feature = "_nrf54l")] + EXTERNAL = 1, } +#[cfg(not(feature = "_nrf54l"))] impl From for vals::Resp { fn from(resistor: Resistor) -> Self { match resistor { @@ -549,6 +637,7 @@ impl From for vals::Resp { /// Positive channel resistor control #[non_exhaustive] #[derive(Clone, Copy)] +#[cfg(not(feature = "_nrf54l"))] pub enum Resistor { /// Bypass resistor ladder BYPASS = 0, @@ -560,6 +649,7 @@ pub enum Resistor { VDD1_2 = 3, } +#[cfg(not(feature = "_nrf54l"))] impl From