Skip to content

Commit

Permalink
RMT: Use gpio::Level for carrier and pulse levels (#2989)
Browse files Browse the repository at this point in the history
* rmt: Use gpio::Level instead of bool to specify output levels

* rmt: Use gpio::Level for PulseCode::level{1|2}
  • Loading branch information
wisp3rwind authored Jan 17, 2025
1 parent da7dda3 commit 2105ba0
Show file tree
Hide file tree
Showing 6 changed files with 143 additions and 54 deletions.
2 changes: 2 additions & 0 deletions esp-hal/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

### Changed
- RMT: `TxChannelConfig` and `RxChannelConfig` now support the builder-lite pattern (#2978)
- RMT: Some fields of `TxChannelConfig` and `RxChannelConfig` are now `gpio::Level`-valued instead of `bool` (#2989)
- RMT: The `PulseCode` trait now uses `gpio::Level` to specify output levels instead of `bool` (#2989)

### Fixed

Expand Down
47 changes: 47 additions & 0 deletions esp-hal/MIGRATING-0.23.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@

## RMT changes

### Configurations structs now support the builder-lite pattern

The `TxChannelConfig` and `RxChannelConfig` structs now support the builder-lite pattern.
Thus, explicit initialization of all fields can be replaced by only the necessary setter methods:

Expand All @@ -23,3 +25,48 @@ Thus, explicit initialization of all fields can be replaced by only the necessar
)
.unwrap();
```

### Some configuration fields now take `gpio::Level` instead of `bool`

Fields related to the carrier level in the channel configuration structs now
take the more descriptive `gpio::Level` type instead of a plain `bool`.

```diff
let mut tx_channel = rmt
.channel0
.configure(
peripherals.GPIO1,
TxChannelConfig::default()
.with_clk_divider(1)
- .with_idle_output_level(false)
+ .with_idle_output_level(Level::Low)
- .with_carrier_level(true)
+ .with_carrier_level(Level::High)
)
.unwrap();

let mut rx_channel = rmt
.channel1
.configure(
peripherals.GPIO2,
RxChannelConfig::default()
.with_clk_divider(1)
.with_carrier_modulation(true)
.with_carrier_high(1)
.with_carrier_low(1)
- .with_carrier_level(false),
+ .with_carrier_level(Level::Low),
)
.unwrap();
```

### `PulseCode` now uses `gpio::Level` instead of `bool` to specify output levels

The more descriptive `gpio::Level` enum is now used to specify output levels of `PulseCode`:

```diff
+ use esp_hal::gpio::Level;
+
- let code = PulseCode::new(true, 200, false, 50);
+ let code = PulseCode::new(Level::High, 200, Level::Low, 50);
```
113 changes: 75 additions & 38 deletions esp-hal/src/rmt.rs
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@
//!
//! ```rust, no_run
#![doc = crate::before_snippet!()]
//! # use esp_hal::gpio::Level;
//! # use esp_hal::peripherals::Peripherals;
//! # use esp_hal::rmt::TxChannelConfig;
//! # use esp_hal::rmt::Rmt;
Expand All @@ -64,12 +65,12 @@
//! peripherals.GPIO1,
//! TxChannelConfig::default()
//! .with_clk_divider(1)
//! .with_idle_output_level(false)
//! .with_idle_output_level(Level::Low)
//! .with_idle_output(false)
//! .with_carrier_modulation(false)
//! .with_carrier_high(1)
//! .with_carrier_low(1)
//! .with_carrier_level(false),
//! .with_carrier_level(Level::Low),
//! )
//! .unwrap();
//! # }
Expand All @@ -78,8 +79,9 @@
//! ### TX operation
//! ```rust, no_run
#![doc = crate::before_snippet!()]
//! # use esp_hal::rmt::{PulseCode, Rmt, TxChannel, TxChannelConfig, TxChannelCreator};
//! # use esp_hal::delay::Delay;
//! # use esp_hal::gpio::Level;
//! # use esp_hal::rmt::{PulseCode, Rmt, TxChannel, TxChannelConfig, TxChannelCreator};
//!
//! // Configure frequency based on chip type
#![cfg_attr(esp32h2, doc = "let freq = 32.MHz();")]
Expand All @@ -95,8 +97,8 @@
//!
//! let delay = Delay::new();
//!
//! let mut data = [PulseCode::new(true, 200, false, 50); 20];
//! data[data.len() - 2] = PulseCode::new(true, 3000, false, 500);
//! let mut data = [PulseCode::new(Level::High, 200, Level::Low, 50); 20];
//! data[data.len() - 2] = PulseCode::new(Level::High, 3000, Level::Low, 500);
//! data[data.len() - 1] = PulseCode::empty();
//!
//! loop {
Expand Down Expand Up @@ -178,7 +180,10 @@
//! }
//!
//! let count = WIDTH / (total / entry.length1() as usize);
//! let c = if entry.level1() { '-' } else { '_' };
//! let c = match entry.level1() {
//! Level::High => '-',
//! Level::Low => '_',
//! };
//! for _ in 0..count + 1 {
//! print!("{}", c);
//! }
Expand All @@ -188,7 +193,10 @@
//! }
//!
//! let count = WIDTH / (total / entry.length2() as usize);
//! let c = if entry.level2() { '-' } else { '_' };
//! let c = match entry.level2() {
//! Level::High => '-',
//! Level::Low => '_',
//! };
//! for _ in 0..count + 1 {
//! print!("{}", c);
//! }
Expand All @@ -209,6 +217,7 @@
//! > Note: on ESP32 and ESP32-S2 you cannot specify a base frequency other than 80 MHz
use core::{
default::Default,
marker::PhantomData,
pin::Pin,
task::{Context, Poll},
Expand All @@ -219,7 +228,7 @@ use fugit::HertzU32;

use crate::{
asynch::AtomicWaker,
gpio::interconnect::{PeripheralInput, PeripheralOutput},
gpio::{interconnect::{PeripheralInput, PeripheralOutput}, Level},
handler,
interrupt::InterruptConfigurable,
peripheral::Peripheral,
Expand Down Expand Up @@ -250,7 +259,7 @@ pub enum Error {
/// Convenience trait to work with pulse codes.
pub trait PulseCode: crate::private::Sealed {
/// Create a new instance
fn new(level1: bool, length1: u16, level2: bool, length2: u16) -> Self;
fn new(level1: Level, length1: u16, level2: Level, length2: u16) -> Self;

/// Create a new empty instance
fn empty() -> Self;
Expand All @@ -259,22 +268,22 @@ pub trait PulseCode: crate::private::Sealed {
fn reset(&mut self);

/// Logical output level in the first pulse code interval
fn level1(&self) -> bool;
fn level1(&self) -> Level;

/// Length of the first pulse code interval (in clock cycles)
fn length1(&self) -> u16;

/// Logical output level in the second pulse code interval
fn level2(&self) -> bool;
fn level2(&self) -> Level;

/// Length of the second pulse code interval (in clock cycles)
fn length2(&self) -> u16;
}

impl PulseCode for u32 {
fn new(level1: bool, length1: u16, level2: bool, length2: u16) -> Self {
let level1 = ((level1 as u32) << 15) | (length1 as u32 & 0b111_1111_1111_1111);
let level2 = ((level2 as u32) << 15) | (length2 as u32 & 0b111_1111_1111_1111);
fn new(level1: Level, length1: u16, level2: Level, length2: u16) -> Self {
let level1 = ((bool::from(level1) as u32) << 15) | (length1 as u32 & 0b111_1111_1111_1111);
let level2 = ((bool::from(level2) as u32) << 15) | (length2 as u32 & 0b111_1111_1111_1111);
level1 | (level2 << 16)
}

Expand All @@ -286,16 +295,16 @@ impl PulseCode for u32 {
*self = 0
}

fn level1(&self) -> bool {
self & (1 << 15) != 0
fn level1(&self) -> Level {
(self & (1 << 15) != 0).into()
}

fn length1(&self) -> u16 {
(self & 0b111_1111_1111_1111) as u16
}

fn level2(&self) -> bool {
self & (1 << 31) != 0
fn level2(&self) -> Level {
(self & (1 << 31) != 0).into()
}

fn length2(&self) -> u16 {
Expand All @@ -304,13 +313,13 @@ impl PulseCode for u32 {
}

/// Channel configuration for TX channels
#[derive(Debug, Copy, Clone, Default, procmacros::BuilderLite)]
#[derive(Debug, Copy, Clone, procmacros::BuilderLite)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub struct TxChannelConfig {
/// Channel's clock divider
pub clk_divider: u8,
/// Set the idle output level to low/high
pub idle_output_level: bool,
pub idle_output_level: Level,
/// Enable idle output
pub idle_output: bool,
/// Enable carrier modulation
Expand All @@ -320,11 +329,25 @@ pub struct TxChannelConfig {
/// Carrier low phase in ticks
pub carrier_low: u16,
/// Level of the carrier
pub carrier_level: bool,
pub carrier_level: Level,
}

impl Default for TxChannelConfig {
fn default() -> Self {
Self {
clk_divider: Default::default(),
idle_output_level: Level::Low,
idle_output: Default::default(),
carrier_modulation: Default::default(),
carrier_high: Default::default(),
carrier_low: Default::default(),
carrier_level: Level::Low,
}
}
}

/// Channel configuration for RX channels
#[derive(Debug, Copy, Clone, Default, procmacros::BuilderLite)]
#[derive(Debug, Copy, Clone, procmacros::BuilderLite)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub struct RxChannelConfig {
/// Channel's clock divider
Expand All @@ -336,13 +359,27 @@ pub struct RxChannelConfig {
/// Carrier low phase in ticks
pub carrier_low: u16,
/// Level of the carrier
pub carrier_level: bool,
pub carrier_level: Level,
/// Filter threshold in ticks
pub filter_threshold: u8,
/// Idle threshold in ticks
pub idle_threshold: u16,
}

impl Default for RxChannelConfig {
fn default() -> Self {
Self {
clk_divider: Default::default(),
carrier_modulation: Default::default(),
carrier_high: Default::default(),
carrier_low: Default::default(),
carrier_level: Level::Low,
filter_threshold: Default::default(),
idle_threshold: Default::default(),
}
}
}

pub use impl_for_chip::{ChannelCreator, Rmt};

impl<'d, Dm> Rmt<'d, Dm>
Expand Down Expand Up @@ -1549,9 +1586,9 @@ where

fn set_wrap_mode(wrap: bool);

fn set_carrier(carrier: bool, high: u16, low: u16, level: bool);
fn set_carrier(carrier: bool, high: u16, low: u16, level: Level);

fn set_idle_output(enable: bool, level: bool);
fn set_idle_output(enable: bool, level: Level);

fn set_memsize(memsize: u8);

Expand Down Expand Up @@ -1641,7 +1678,7 @@ where

fn set_wrap_mode(wrap: bool);

fn set_carrier(carrier: bool, high: u16, low: u16, level: bool);
fn set_carrier(carrier: bool, high: u16, low: u16, level: Level);

fn set_memsize(memsize: u8);

Expand Down Expand Up @@ -1828,7 +1865,7 @@ mod chip_specific {
rmt.ch_tx_conf0($ch_num).modify(|_, w| w.mem_tx_wrap_en().bit(wrap));
}

fn set_carrier(carrier: bool, high: u16, low: u16, level: bool) {
fn set_carrier(carrier: bool, high: u16, low: u16, level: $crate::gpio::Level) {
let rmt = unsafe { &*crate::peripherals::RMT::PTR };

rmt.chcarrier_duty($ch_num)
Expand All @@ -1837,13 +1874,13 @@ mod chip_specific {
rmt.ch_tx_conf0($ch_num).modify(|_, w| {
w.carrier_en().bit(carrier);
w.carrier_eff_en().set_bit();
w.carrier_out_lv().bit(level)
w.carrier_out_lv().bit(level.into())
});
}

fn set_idle_output(enable: bool, level: bool) {
fn set_idle_output(enable: bool, level: $crate::gpio::Level) {
let rmt = unsafe { &*crate::peripherals::RMT::PTR };
rmt.ch_tx_conf0($ch_num).modify(|_, w| w.idle_out_en().bit(enable).idle_out_lv().bit(level));
rmt.ch_tx_conf0($ch_num).modify(|_, w| w.idle_out_en().bit(enable).idle_out_lv().bit(level.into()));
}

fn set_memsize(memsize: u8) {
Expand Down Expand Up @@ -1964,7 +2001,7 @@ mod chip_specific {
rmt.ch_rx_conf1($ch_index).modify(|_, w| w.mem_rx_wrap_en().bit(wrap));
}

fn set_carrier(carrier: bool, high: u16, low: u16, level: bool) {
fn set_carrier(carrier: bool, high: u16, low: u16, level: $crate::gpio::Level) {
let rmt = unsafe { &*crate::peripherals::RMT::PTR };

rmt.ch_rx_carrier_rm($ch_index).write(|w| unsafe {
Expand All @@ -1973,7 +2010,7 @@ mod chip_specific {
});

rmt.ch_rx_conf0($ch_index)
.modify(|_, w| w.carrier_en().bit(carrier).carrier_out_lv().bit(level));
.modify(|_, w| w.carrier_en().bit(carrier).carrier_out_lv().bit(level.into()));
}

fn set_memsize(memsize: u8) {
Expand Down Expand Up @@ -2176,20 +2213,20 @@ mod chip_specific {
rmt.apb_conf().modify(|_, w| w.mem_tx_wrap_en().bit(wrap));
}

fn set_carrier(carrier: bool, high: u16, low: u16, level: bool) {
fn set_carrier(carrier: bool, high: u16, low: u16, level: $crate::gpio::Level) {
let rmt = unsafe { &*crate::peripherals::RMT::PTR };

rmt.chcarrier_duty($ch_num)
.write(|w| unsafe { w.carrier_high().bits(high).carrier_low().bits(low) });

rmt.chconf0($ch_num)
.modify(|_, w| w.carrier_en().bit(carrier).carrier_out_lv().bit(level));
.modify(|_, w| w.carrier_en().bit(carrier).carrier_out_lv().bit(level.into()));
}

fn set_idle_output(enable: bool, level: bool) {
fn set_idle_output(enable: bool, level: $crate::gpio::Level) {
let rmt = unsafe { &*crate::peripherals::RMT::PTR };
rmt.chconf1($ch_num)
.modify(|_, w| w.idle_out_en().bit(enable).idle_out_lv().bit(level));
.modify(|_, w| w.idle_out_en().bit(enable).idle_out_lv().bit(level.into()));
}

fn set_memsize(memsize: u8) {
Expand Down Expand Up @@ -2314,14 +2351,14 @@ mod chip_specific {
// no-op
}

fn set_carrier(carrier: bool, high: u16, low: u16, level: bool) {
fn set_carrier(carrier: bool, high: u16, low: u16, level: $crate::gpio::Level) {
let rmt = unsafe { &*crate::peripherals::RMT::PTR };

rmt.chcarrier_duty($ch_num)
.write(|w| unsafe { w.carrier_high().bits(high).carrier_low().bits(low) });

rmt.chconf0($ch_num)
.modify(|_, w| w.carrier_en().bit(carrier).carrier_out_lv().bit(level));
.modify(|_, w| w.carrier_en().bit(carrier).carrier_out_lv().bit(level.into()));
}

fn set_memsize(memsize: u8) {
Expand Down
Loading

0 comments on commit 2105ba0

Please sign in to comment.