From 05bfb7d0f1105236dd0d7ab0bdc54c97b17c53bb Mon Sep 17 00:00:00 2001 From: wisp3rwind <17089248+wisp3rwind@users.noreply.github.com> Date: Fri, 26 Sep 2025 13:03:24 +0200 Subject: [PATCH 1/2] RMT: Remove Into / From support which was probably of little value, anyway, and also in preparation for adding more sophisticated Encoder data types --- esp-hal/src/rmt.rs | 92 ++++++++++++--------------------------- esp-hal/src/rmt/reader.rs | 12 ++--- esp-hal/src/rmt/writer.rs | 12 ++--- 3 files changed, 42 insertions(+), 74 deletions(-) diff --git a/esp-hal/src/rmt.rs b/esp-hal/src/rmt.rs index 2f253856f17..8863d45d60f 100644 --- a/esp-hal/src/rmt.rs +++ b/esp-hal/src/rmt.rs @@ -1431,10 +1431,7 @@ impl Drop for RxGuard { #[must_use = "transactions need to be `poll()`ed / `wait()`ed for to ensure progress"] #[derive(Debug)] #[cfg_attr(feature = "defmt", derive(defmt::Format))] -pub struct TxTransaction<'ch, 'data, T> -where - T: Into + Copy, -{ +pub struct TxTransaction<'ch, 'data> { // This must go first such that it is dropped before the channel (which might disable the // peripheral on drop)! _guard: TxGuard, @@ -1444,13 +1441,10 @@ where writer: RmtWriter, // Remaining data that has not yet been written to channel RAM. May be empty. - remaining_data: &'data [T], + remaining_data: &'data [PulseCode], } -impl<'ch, T> TxTransaction<'ch, '_, T> -where - T: Into + Copy, -{ +impl<'ch> TxTransaction<'ch, '_> { #[cfg_attr(place_rmt_driver_in_ram, ram)] fn poll_internal(&mut self) -> Option { let raw = self.channel.raw; @@ -1709,19 +1703,16 @@ impl<'ch> Channel<'ch, Blocking, Tx> { /// the transaction to complete and get back the channel for further /// use. #[cfg_attr(place_rmt_driver_in_ram, ram)] - pub fn transmit<'data, T>( + pub fn transmit<'data>( self, - mut data: &'data [T], - ) -> Result, (Error, Self)> - where - T: Into + Copy, - { + mut data: &'data [PulseCode], + ) -> Result, (Error, Self)> { let raw = self.raw; let memsize = raw.memsize(); match data.last() { None => return Err((Error::InvalidArgument, self)), - Some(&code) if code.into().is_end_marker() => (), + Some(&code) if code.is_end_marker() => (), Some(_) => return Err((Error::EndMarkerMissing, self)), } @@ -1752,14 +1743,11 @@ impl<'ch> Channel<'ch, Blocking, Tx> { )] /// The length of `data` cannot exceed the size of the allocated RMT RAM. #[cfg_attr(place_rmt_driver_in_ram, ram)] - pub fn transmit_continuously( + pub fn transmit_continuously( self, - mut data: &[T], + mut data: &[PulseCode], mode: LoopMode, - ) -> Result, (Error, Self)> - where - T: Into + Copy, - { + ) -> Result, (Error, Self)> { let raw = self.raw; let memsize = raw.memsize(); @@ -1799,10 +1787,7 @@ impl<'ch> Channel<'ch, Blocking, Tx> { #[must_use = "transactions need to be `poll()`ed / `wait()`ed for to ensure progress"] #[derive(Debug)] #[cfg_attr(feature = "defmt", derive(defmt::Format))] -pub struct RxTransaction<'ch, 'data, T> -where - T: From, -{ +pub struct RxTransaction<'ch, 'data> { // This must go first such that it is dropped before the channel (which might disable the // peripheral on drop)! _guard: RxGuard, @@ -1811,13 +1796,10 @@ where reader: RmtReader, - data: &'data mut [T], + data: &'data mut [PulseCode], } -impl<'ch, T> RxTransaction<'ch, '_, T> -where - T: From, -{ +impl<'ch> RxTransaction<'ch, '_> { #[cfg_attr(place_rmt_driver_in_ram, ram)] fn poll_internal(&mut self) -> Option { let raw = self.channel.raw; @@ -1893,13 +1875,10 @@ impl<'ch> Channel<'ch, Blocking, Rx> { /// /// # {rx_size_limit} #[cfg_attr(place_rmt_driver_in_ram, ram)] - pub fn receive<'data, T>( + pub fn receive<'data>( self, - data: &'data mut [T], - ) -> Result, (Error, Self)> - where - T: From, - { + data: &'data mut [PulseCode], + ) -> Result, (Error, Self)> { let raw = self.raw; let memsize = raw.memsize(); @@ -1927,24 +1906,18 @@ static WAKER: [AtomicWaker; NUM_CHANNELS] = [const { AtomicWaker::new() }; NUM_C static RMT_LOCK: RawMutex = RawMutex::new(); #[must_use = "futures do nothing unless you `.await` or poll them"] -struct TxFuture<'a, T> -where - T: Into + Copy, -{ +struct TxFuture<'a> { raw: DynChannelAccess, _phantom: PhantomData>, writer: RmtWriter, // Remaining data that has not yet been written to channel RAM. May be empty. - data: &'a [T], + data: &'a [PulseCode], _guard: TxGuard, } -impl core::future::Future for TxFuture<'_, T> -where - T: Into + Copy, -{ +impl core::future::Future for TxFuture<'_> { type Output = Result<(), Error>; #[cfg_attr(place_rmt_driver_in_ram, ram)] @@ -1992,10 +1965,7 @@ where impl Channel<'_, Async, Tx> { /// Start transmitting the given pulse code sequence. #[cfg_attr(place_rmt_driver_in_ram, ram)] - pub fn transmit(&mut self, mut data: &[T]) -> impl Future> - where - T: Into + Copy, - { + pub fn transmit(&mut self, mut data: &[PulseCode]) -> impl Future> { let raw = self.raw; let memsize = raw.memsize(); @@ -2005,7 +1975,7 @@ impl Channel<'_, Async, Tx> { None => { writer.state = WriterState::Error(Error::InvalidArgument); } - Some(&code) if code.into().is_end_marker() => (), + Some(&code) if code.is_end_marker() => (), Some(_) => { writer.state = WriterState::Error(Error::EndMarkerMissing); } @@ -2044,21 +2014,15 @@ impl Channel<'_, Async, Tx> { } #[must_use = "futures do nothing unless you `.await` or poll them"] -struct RxFuture<'a, T> -where - T: From + Unpin, -{ +struct RxFuture<'a> { raw: DynChannelAccess, _phantom: PhantomData>, reader: RmtReader, - data: &'a mut [T], + data: &'a mut [PulseCode], _guard: RxGuard, } -impl core::future::Future for RxFuture<'_, T> -where - T: From + Unpin, -{ +impl core::future::Future for RxFuture<'_> { type Output = Result; #[cfg_attr(place_rmt_driver_in_ram, ram)] @@ -2114,10 +2078,10 @@ impl Channel<'_, Async, Rx> { /// /// # {rx_size_limit} #[cfg_attr(place_rmt_driver_in_ram, ram)] - pub fn receive(&mut self, data: &mut [T]) -> impl Future> - where - T: From + Unpin, - { + pub fn receive( + &mut self, + data: &mut [PulseCode], + ) -> impl Future> { let raw = self.raw; let memsize = raw.memsize(); diff --git a/esp-hal/src/rmt/reader.rs b/esp-hal/src/rmt/reader.rs index 9682231ab20..674be47cdca 100644 --- a/esp-hal/src/rmt/reader.rs +++ b/esp-hal/src/rmt/reader.rs @@ -40,10 +40,12 @@ impl RmtReader { // If `final_` is set, read a full buffer length, potentially wrapping around. Otherwise, fetch // half the buffer's length. #[cfg_attr(place_rmt_driver_in_ram, ram)] - pub(super) fn read(&mut self, data: &mut &mut [T], raw: DynChannelAccess, final_: bool) - where - T: From, - { + pub(super) fn read( + &mut self, + data: &mut &mut [PulseCode], + raw: DynChannelAccess, + final_: bool, + ) { if self.state != ReaderState::Active { return; } @@ -97,7 +99,7 @@ impl RmtReader { // `data.len()` such that incrementing both pointers cannot advance them beyond // their allocation's end. unsafe { - data_ptr.write(ram_ptr.read_volatile().into()); + data_ptr.write(ram_ptr.read_volatile()); ram_ptr = ram_ptr.add(1); data_ptr = data_ptr.add(1); } diff --git a/esp-hal/src/rmt/writer.rs b/esp-hal/src/rmt/writer.rs index 3b50558bca6..9630b0d8fee 100644 --- a/esp-hal/src/rmt/writer.rs +++ b/esp-hal/src/rmt/writer.rs @@ -37,10 +37,12 @@ impl RmtWriter { // If `initial` is set, fill the entire buffer. Otherwise, append half the buffer's length from // `data`. #[cfg_attr(place_rmt_driver_in_ram, ram)] - pub(super) fn write(&mut self, data: &mut &[T], raw: DynChannelAccess, initial: bool) - where - T: Into + Copy, - { + pub(super) fn write( + &mut self, + data: &mut &[PulseCode], + raw: DynChannelAccess, + initial: bool, + ) { if self.state != WriterState::Active { return; } @@ -62,7 +64,7 @@ impl RmtWriter { // SAFETY: The iteration `count` is smaller than both `max_count` and `data.len()` such // that incrementing both pointers cannot advance them beyond their allocation's end. unsafe { - ram_ptr.write_volatile(data_ptr.read().into()); + ram_ptr.write_volatile(data_ptr.read()); ram_ptr = ram_ptr.add(1); data_ptr = data_ptr.add(1); } From 3711df13eab282dde33b9a1be6468f8203cfb67e Mon Sep 17 00:00:00 2001 From: wisp3rwind <17089248+wisp3rwind@users.noreply.github.com> Date: Thu, 4 Dec 2025 20:30:48 +0100 Subject: [PATCH 2/2] update changelog + migration guide --- esp-hal/CHANGELOG.md | 4 ++-- esp-hal/MIGRATING-1.0.0.md | 17 +++++++++++++++++ 2 files changed, 19 insertions(+), 2 deletions(-) diff --git a/esp-hal/CHANGELOG.md b/esp-hal/CHANGELOG.md index b6f77ccad54..0343121069d 100644 --- a/esp-hal/CHANGELOG.md +++ b/esp-hal/CHANGELOG.md @@ -8,9 +8,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] ### Added + - RMT: All public types now derive `Debug` and `defmt::Format`. (#4302) - RMT: `Channel::apply_config` has been added. (#4302) - - Added blocking `send_break`, `wait_for_break` and `wait_for_break_with_timeout` for sending and detecting software breaks with the UART driver (#4284) - Added support for `RxBreakDetected` interrupt and `wait_for_break_async` for detecting software breaks asynchronously to the UART driver (#4284) - Unsafely expose GPIO pins that are only available on certain chip/module variants (#4520) @@ -23,8 +23,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - RMT: `ChannelCreator::configure_tx` and `ChannelCreator::configure_rx` don't take a pin anymore, instead `Channel::with_pin` has been added. (#4302) - RMT: Configuration errors have been split out of `rmt::Error` into the new `rmt::ConfigError` enum. (#4494) - RMT: `Rmt::new()` now returns `Error::UnreachableTargetFrequency` instead of panicking when requesting 0 Hz. (#4509) - - Internal clock configuration rework (#4501) +- RMT: Support for `Into` and `From` has been removed from Tx and Rx methods, respectively, in favor of requiring `PulseCode` directly. (#4616) ### Fixed diff --git a/esp-hal/MIGRATING-1.0.0.md b/esp-hal/MIGRATING-1.0.0.md index cc6d0fe35dc..2437c552ab9 100644 --- a/esp-hal/MIGRATING-1.0.0.md +++ b/esp-hal/MIGRATING-1.0.0.md @@ -69,3 +69,20 @@ Configuration methods now return `ConfigError` instead of `Error`. Corresponding enum variants have been removed from `Error`, and some variants that are now part of `ConfigError` have been renamed. + +### RMT data type changes + +Support for `Into` and `From` has been removed from Tx and Rx methods, respectively. +Instead, buffers must now contain `PulseCode` directly. +The corresponding generic argument has also been removed from `TxTransaction` and `RxTransaction`: + +```diff +-let tx_data: [u32; 8] = todo!(); +-let mut rx_data: [u32; 8] = [0u32; 8]; +-let tx_transaction: TxTransaction<'_, '_, u32> = tx_channel.transmit(&tx_data)?; +-let rx_transaction: RxTransaction<'_, '_, u32> = rx_channel.receive(&mut rx_data)?; ++let tx_data: [PulseCode; 8] = todo!(); ++let mut rx_data: [PulseCode; 8] = [PulseCode::default(); 8]; ++let tx_transaction: TxTransaction<'_, '_> = tx_channel.transmit(&tx_data)?; ++let rx_transaction: RxTransaction<'_, '_> = rx_channel.receive(&mut rx_data)?; +```