esp_idf_hal/rmt.rs
1//! RMT (Remote Control) peripheral support.
2//!
3//! The RMT (Remote Control Transceiver) peripheral was designed to act as an infrared transceiver.
4//! However, due to the flexibility of its data format, RMT can be extended to a versatile and
5//! general-purpose transceiver, transmitting or receiving many other types of signals.
6//! From the perspective of network layering, the RMT hardware contains both physical and data
7//! link layers. The physical layer defines the communication media and bit signal representation.
8//! The data link layer defines the format of an RMT frame. The minimal data unit in the frame is
9//! called the RMT symbol, which is represented by [`Symbol`] in the driver.
10//!
11//! ESP32 contains multiple channels in the RMT peripheral. Each channel can be independently
12//! configured as either transmitter or receiver.
13//!
14//! Typically, the RMT peripheral can be used in the following scenarios:
15//! - Transmit or receive infrared signals, with any IR protocols, e.g., NEC
16//! - General-purpose sequence generator
17//! - Transmit signals in a hardware-controlled loop, with a finite or infinite number of times
18//! - Multi-channel simultaneous transmission
19//! - Modulate the carrier to the output signal or demodulate the carrier from the input signal
20//!
21//! # Driver redesign in ESP-IDF 5.0
22//!
23//! In ESP-IDF 5.0, the [RMT API was redesigned] to simplify and unify the usage of the
24//! RMT peripheral.
25//!
26//! It is recommended to use the new API, but for now the old API is available through
27//! the `rmt-legacy` feature. The ESP-IDF 6.0 release will remove support for the legacy API.
28//!
29//! [RMT API was redesigned]: https://docs.espressif.com/projects/esp-idf/en/stable/esp32/migration-guides/release-5.x/5.0/peripherals.html#rmt-driver
30pub mod config;
31pub mod encoder;
32
33mod tx_channel;
34pub use tx_channel::*;
35
36mod tx_queue;
37pub use tx_queue::*;
38
39mod rx_channel;
40pub use rx_channel::*;
41
42mod sync_manager;
43pub use sync_manager::*;
44mod pulse;
45pub use pulse::*;
46
47use core::time::Duration;
48use core::{fmt, ptr};
49
50use esp_idf_sys::*;
51
52use crate::rmt::config::CarrierConfig;
53use crate::units::Hertz;
54
55#[cfg(esp_idf_version_at_least_6_0_0)]
56#[allow(non_camel_case_types)]
57type rmt_carrier_config_t__bindgen_ty_1 = rmt_carrier_config_t_extra_rmt_carrier_config_flags;
58
59/// A [`Symbol`] constists of two [`Pulse`]s, where each pulse defines a level of the pin (high or low)
60/// and a duration ([`PulseTicks`]).
61///
62/// The `Pulse`s can be the same level (e.g., both high) and must not necessarily be different levels.
63///
64/// This is just a newtype over the IDF's `rmt_item32_t` or `rmt_symbol_word_t` type.
65#[derive(Clone, Copy)]
66#[repr(transparent)]
67pub struct Symbol(rmt_symbol_word_t);
68
69impl Symbol {
70 /// Create a symbol from a pair of half-cycles.
71 #[must_use]
72 pub fn new(level0: Pulse, level1: Pulse) -> Self {
73 let item = rmt_symbol_word_t { val: 0 };
74 let mut this = Self(item);
75 this.update(level0, level1);
76 this
77 }
78
79 /// Constructs a symbol from the given levels and durations.
80 ///
81 /// This is a convenience function that combines [`Pulse::new_with_duration`] and [`Symbol::new`].
82 pub fn new_with(
83 resolution: Hertz,
84 level0: PinState,
85 duration0: Duration,
86 level1: PinState,
87 duration1: Duration,
88 ) -> Result<Self, EspError> {
89 Ok(Self::new(
90 Pulse::new_with_duration(resolution, level0, duration0)?,
91 Pulse::new_with_duration(resolution, level1, duration1)?,
92 ))
93 }
94
95 /// Constructs a new symbol where the duration is split evenly between the two levels.
96 ///
97 /// It is guaranteed that the combined duration of the two levels adds up to the given duration.
98 /// If the duration is odd, the first level might be a bit shorter than the second level.
99 pub fn new_half_split(
100 resolution: Hertz,
101 level0: PinState,
102 level1: PinState,
103 duration: Duration,
104 ) -> Result<Self, EspError> {
105 let first_half_duration = duration / 2;
106 // This ensures that the two halves always add up to the original duration,
107 // even if the duration is odd.
108 let second_half_duration = duration - first_half_duration;
109
110 Ok(Self::new(
111 Pulse::new_with_duration(resolution, level0, first_half_duration)?,
112 Pulse::new_with_duration(resolution, level1, second_half_duration)?,
113 ))
114 }
115
116 /// Repeats the symbol to have the returned sequence of symbols last for
117 /// exactly the given duration.
118 ///
119 /// There is an upper limit for how long a single symbol can be ([`PulseTicks::max`]).
120 /// To create a symbol that lasts longer than that, it is split into multiple symbols.
121 /// The returned iterator yields as many symbols as necessary to reach the
122 /// desired duration.
123 ///
124 /// If the given duration is not a multiple of the symbol duration,
125 /// the last symbol will be adjusted to occupy the remaining time.
126 ///
127 /// # Panics
128 ///
129 /// If `self` has a duration of zero.
130 pub fn repeat_for(&self, resolution: Hertz, duration: Duration) -> impl Iterator<Item = Self> {
131 // Calculate the maximum allowed duration for a single symbol consisting of two pulses:
132 // let max_duration = PulseTicks::max().duration(resolution) * 2;
133
134 let symbol_duration = self.duration(resolution);
135
136 // Handle edge-case to prevent an infinite loop:
137 if symbol_duration.is_zero() {
138 panic!("Cannot repeat a symbol with zero duration for {duration:?}");
139 }
140
141 let count = duration.as_nanos() / symbol_duration.as_nanos();
142 let remainder =
143 Duration::from_nanos((duration.as_nanos() % symbol_duration.as_nanos()) as u64);
144
145 let last_symbol = {
146 if remainder.is_zero() {
147 None
148 } else {
149 let duration0 = self.level0().ticks.duration(resolution).min(remainder);
150 let duration1 = remainder.saturating_sub(duration0);
151
152 Some(
153 Self::new_with(
154 resolution,
155 self.level0().pin_state,
156 duration0,
157 self.level1().pin_state,
158 duration1,
159 )
160 .unwrap(),
161 )
162 }
163 };
164
165 core::iter::repeat_n(*self, count as usize).chain(core::iter::once(last_symbol).flatten())
166 }
167
168 #[must_use]
169 fn symbol_word_to_pulse(word: &rmt_symbol_word_t) -> (Pulse, Pulse) {
170 let inner = unsafe { &word.__bindgen_anon_1 };
171 (
172 Pulse::new(
173 (inner.level0() as u32).into(),
174 PulseTicks::new(inner.duration0()).unwrap(),
175 ),
176 Pulse::new(
177 (inner.level1() as u32).into(),
178 PulseTicks::new(inner.duration1()).unwrap(),
179 ),
180 )
181 }
182
183 /// Returns the first half-cycle (pulse) of this symbol.
184 #[must_use]
185 pub fn level0(&self) -> Pulse {
186 Self::symbol_word_to_pulse(&self.0).0
187 }
188
189 /// Returns the second half-cycle (pulse) of this symbol.
190 #[must_use]
191 pub fn level1(&self) -> Pulse {
192 Self::symbol_word_to_pulse(&self.0).1
193 }
194
195 /// Returns the combined duration of both half-cycles of this symbol.
196 pub fn duration(&self, resolution: Hertz) -> Duration {
197 self.level0().ticks.duration(resolution) + self.level1().ticks.duration(resolution)
198 }
199
200 /// Mutate this symbol to store a different pair of half-cycles.
201 pub fn update(&mut self, level0: Pulse, level1: Pulse) {
202 // SAFETY: We're overriding all 32 bits, so it doesn't matter what was here before.
203 let inner = unsafe { &mut self.0.__bindgen_anon_1 };
204 inner.set_level0(level0.pin_state as u16);
205 inner.set_duration0(level0.ticks.ticks());
206 inner.set_level1(level1.pin_state as u16);
207 inner.set_duration1(level1.ticks.ticks());
208 }
209}
210
211impl fmt::Debug for Symbol {
212 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
213 f.debug_struct("Symbol")
214 .field("level0", &self.level0())
215 .field("level1", &self.level1())
216 .finish()
217 }
218}
219
220impl Default for Symbol {
221 fn default() -> Self {
222 Self::new(Default::default(), Default::default())
223 }
224}
225
226impl PartialEq for Symbol {
227 fn eq(&self, other: &Self) -> bool {
228 (self.level0(), self.level1()) == (other.level0(), other.level1())
229 }
230}
231
232impl Eq for Symbol {}
233
234impl From<rmt_symbol_word_t> for Symbol {
235 fn from(value: rmt_symbol_word_t) -> Self {
236 Self(value)
237 }
238}
239
240impl From<Symbol> for rmt_symbol_word_t {
241 fn from(value: Symbol) -> Self {
242 value.0
243 }
244}
245
246/// A small helper function to assert that the current code is not running in an ISR.
247///
248/// This is useful for functions that must not be called from an ISR context.
249fn assert_not_in_isr() {
250 if crate::interrupt::active() {
251 panic!("This function cannot be called from an ISR");
252 }
253}
254
255/// Type of RMT TX done event data.
256#[derive(Debug, Clone, Copy)]
257#[non_exhaustive]
258pub struct TxDoneEventData {
259 /// The number of symbols ([`Symbol`]) that have been transmitted.
260 ///
261 /// This also reflects the size of the encoding artifacts. Please
262 /// note, this value accounts for the `EOF` symbol as well, which
263 /// is automatically appended by the driver to mark the end of one
264 /// transaction.
265 pub num_symbols: usize,
266}
267
268impl From<rmt_tx_done_event_data_t> for TxDoneEventData {
269 fn from(data: rmt_tx_done_event_data_t) -> Self {
270 Self {
271 num_symbols: data.num_symbols,
272 }
273 }
274}
275
276/// Type of RMT RX done event data.
277#[derive(Debug, Clone, Copy)]
278#[non_exhaustive]
279pub struct RxDoneEventData {
280 /// Pointer to the received RMT symbols.
281 ///
282 /// These symbols are saved in the internal `buffer` of the `RxChannelDriver`.
283 /// You are not allowed to free this buffer.
284 ///
285 /// If the partial receive feature is enabled, then the buffer will be
286 /// used as a "second level buffer", where its content can be overwritten by
287 /// data coming in afterwards. In this case, you should copy the received data to
288 /// another place if you want to keep it or process it later.
289 pub received_symbols: *mut Symbol,
290 /// The number of received RMT symbols.
291 ///
292 /// This value will never be larger than the buffer size of the buffer passed to the
293 /// receive function.
294 ///
295 /// If the buffer is not sufficient to accomodate all the received RMT symbols, the
296 /// driver only keeps the maximum number of symbols that the buffer can hold, and excess
297 /// symbols are discarded or ignored.
298 pub num_symbols: usize,
299 /// Indicates whether the current received data is the last part of the transaction.
300 ///
301 /// This is useful for when [`ReceiveConfig::enable_partial_rx`] is enabled,
302 /// and the data is received in parts.
303 ///
304 /// For receives where partial rx is not enabled, this field will always be `true`.
305 ///
306 /// [`ReceiveConfig::enable_partial_rx`]: crate::rmt::config::ReceiveConfig::enable_partial_rx
307 #[cfg(esp_idf_version_at_least_5_3_0)]
308 pub is_last: bool,
309}
310
311impl RxDoneEventData {
312 /// Returns the received symbols as a slice.
313 ///
314 /// # Safety
315 ///
316 /// Both the pointer and the length must be valid.
317 /// If these haven't been changed from the values provided by the driver,
318 /// this should be the case **in** the ISR callback.
319 pub unsafe fn as_slice(&self) -> &[Symbol] {
320 core::slice::from_raw_parts(self.received_symbols, self.num_symbols)
321 }
322}
323
324impl From<rmt_rx_done_event_data_t> for RxDoneEventData {
325 fn from(data: rmt_rx_done_event_data_t) -> Self {
326 Self {
327 received_symbols: data.received_symbols as *mut Symbol,
328 num_symbols: data.num_symbols,
329 #[cfg(esp_idf_version_at_least_5_3_0)]
330 is_last: data.flags.is_last() != 0,
331 }
332 }
333}
334
335/// A trait implemented by an RMT channel that provides common functionality.
336pub trait RmtChannel {
337 /// Returns the underlying `rmt_channel_handle_t`.
338 fn handle(&self) -> rmt_channel_handle_t;
339
340 /// Returns whether the channel is currently enabled.
341 #[must_use]
342 fn is_enabled(&self) -> bool;
343
344 /// Sets the internal `is_enabled` flag of the channel that is used to track the channel state.
345 ///
346 /// # Safety
347 ///
348 /// The channel assumes that the given `is_enabled` reflects the state of the channel.
349 /// There shouldn't be any reason for the user to call this function directly.
350 /// Use `enable`/`disable` instead.
351 #[doc(hidden)]
352 unsafe fn set_internal_enabled(&mut self, is_enabled: bool);
353
354 /// Must be called in advance before transmitting or receiving RMT symbols.
355 /// For TX channels, enabling a channel enables a specific interrupt and
356 /// prepares the hardware to dispatch transactions.
357 ///
358 /// For RX channels, enabling a channel enables an interrupt, but the receiver
359 /// is not started during this time, as the characteristics of the incoming
360 /// signal have yet to be specified.
361 ///
362 /// The receiver is started in [`RxChannel::receive`].
363 fn enable(&mut self) -> Result<(), EspError> {
364 esp!(unsafe { rmt_enable(self.handle()) })?;
365
366 // SAFETY: The channel has been enabled -> it is safe to mark it as enabled.
367 unsafe { self.set_internal_enabled(true) };
368 Ok(())
369 }
370
371 /// Disables the interrupt and clearing any pending interrupts. The transmitter
372 /// and receiver are disabled as well.
373 ///
374 /// # Note
375 ///
376 /// This function will release a power management (PM) lock that might be
377 /// installed during channel allocation
378 ///
379 /// # Errors
380 ///
381 /// - `ESP_ERR_INVALID_ARG`: Disable RMT channel failed because of invalid argument
382 /// - `ESP_ERR_INVALID_STATE`: Disable RMT channel failed because it's not enabled yet
383 /// - `ESP_FAIL`: Disable RMT channel failed because of other error
384 fn disable(&mut self) -> Result<(), EspError> {
385 esp!(unsafe { rmt_disable(self.handle()) })?;
386 // SAFETY: The channel has been disable -> it is safe to mark it as disabled.
387 unsafe { self.set_internal_enabled(false) };
388 Ok(())
389 }
390
391 /// Apply (de)modulation feature for the channel.
392 ///
393 /// If `carrier_config` is `None`, the carrier (de)modulation will be disabled.
394 ///
395 /// # Errors
396 ///
397 /// - `ESP_ERR_INVALID_ARG`: Apply carrier failed because of invalid argument
398 /// - `ESP_FAIL`: Apply carrier failed because of other error
399 fn apply_carrier(&mut self, carrier_config: Option<&CarrierConfig>) -> Result<(), EspError> {
400 let mut sys_carrier = None;
401 if let Some(CarrierConfig {
402 frequency,
403 duty_cycle,
404 polarity_active_low,
405 always_on,
406 // match __internal to get a compiler error if new fields are added in the future
407 __internal,
408 }) = carrier_config
409 {
410 sys_carrier = Some(rmt_carrier_config_t {
411 frequency_hz: (*frequency).into(),
412 duty_cycle: duty_cycle.to_f32(),
413 flags: rmt_carrier_config_t__bindgen_ty_1 {
414 _bitfield_1: rmt_carrier_config_t__bindgen_ty_1::new_bitfield_1(
415 *polarity_active_low as u32,
416 *always_on as u32,
417 ),
418 ..Default::default()
419 },
420 })
421 }
422
423 esp!(unsafe {
424 rmt_apply_carrier(
425 self.handle(),
426 sys_carrier.as_ref().map_or(ptr::null(), |c| c as *const _),
427 )
428 })
429 }
430}
431
432impl<R: RmtChannel> RmtChannel for &mut R {
433 fn handle(&self) -> rmt_channel_handle_t {
434 (**self).handle()
435 }
436
437 fn is_enabled(&self) -> bool {
438 (**self).is_enabled()
439 }
440
441 unsafe fn set_internal_enabled(&mut self, is_enabled: bool) {
442 (**self).set_internal_enabled(is_enabled)
443 }
444
445 fn enable(&mut self) -> Result<(), EspError> {
446 (**self).enable()
447 }
448
449 fn disable(&mut self) -> Result<(), EspError> {
450 (**self).disable()
451 }
452
453 fn apply_carrier(&mut self, carrier_config: Option<&CarrierConfig>) -> Result<(), EspError> {
454 (**self).apply_carrier(carrier_config)
455 }
456}
457
458/// Clock source for RMT channels.
459#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
460pub enum ClockSource {
461 #[default]
462 Default,
463 #[cfg(any(esp32, esp32c3, esp32s2, esp32s3))]
464 APB,
465 #[cfg(any(esp32c3, esp32c5, esp32c6, esp32h2, esp32h4, esp32p4, esp32s3))]
466 RcFast,
467 #[cfg(any(esp32, esp32s2))]
468 RefTick,
469 #[cfg(any(esp32c3, esp32c5, esp32c6, esp32h2, esp32h4, esp32p4, esp32s3))]
470 XTAL,
471 #[cfg(any(esp32c5, esp32c6, esp32p4))]
472 PLLF80M,
473}
474
475impl From<ClockSource> for rmt_clock_source_t {
476 fn from(clock: ClockSource) -> Self {
477 match clock {
478 ClockSource::Default => soc_periph_rmt_clk_src_t_RMT_CLK_SRC_DEFAULT,
479 #[cfg(any(esp32, esp32c3, esp32s2, esp32s3))]
480 ClockSource::APB => soc_periph_rmt_clk_src_t_RMT_CLK_SRC_APB,
481 #[cfg(any(esp32c3, esp32c5, esp32c6, esp32h2, esp32h4, esp32p4, esp32s3))]
482 ClockSource::RcFast => soc_periph_rmt_clk_src_t_RMT_CLK_SRC_RC_FAST,
483 #[cfg(any(esp32, esp32s2))]
484 ClockSource::RefTick => soc_periph_rmt_clk_src_t_RMT_CLK_SRC_REF_TICK,
485 #[cfg(any(esp32c3, esp32c5, esp32c6, esp32h2, esp32h4, esp32p4, esp32s3))]
486 ClockSource::XTAL => soc_periph_rmt_clk_src_t_RMT_CLK_SRC_XTAL,
487 #[cfg(any(esp32c5, esp32c6, esp32p4))]
488 ClockSource::PLLF80M => soc_periph_rmt_clk_src_t_RMT_CLK_SRC_PLL_F80M,
489 }
490 }
491}