Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

RMT Onewire Peripheral #454

Merged
merged 26 commits into from
Aug 10, 2024
Merged
Show file tree
Hide file tree
Changes from 15 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions .cargo/config.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[build]
target = "riscv32imc-esp-espidf"
#target = "xtensa-esp32-espidf"
# target = "riscv32imc-esp-espidf"
ivmarkov marked this conversation as resolved.
Show resolved Hide resolved
target = "xtensa-esp32-espidf"
ivmarkov marked this conversation as resolved.
Show resolved Hide resolved

[target.xtensa-esp32-espidf]
linker = "ldproxy"
Expand Down
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -6,3 +6,5 @@
**/*.rs.bk
ulp/ulp_start.o
install-rust-toolchain.sh
/.devcontainer
ivmarkov marked this conversation as resolved.
Show resolved Hide resolved
components_esp32.lock
15 changes: 12 additions & 3 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -24,12 +24,17 @@ std = ["alloc", "esp-idf-sys/std"]
alloc = []
nightly = []
wake-from-isr = [] # Only enable if you plan to use the `edge-executor` crate
embassy-sync = [] # For now, the dependecy on the `embassy-sync` crate is non-optional, but this might change in future
embassy-sync = [
ivmarkov marked this conversation as resolved.
Show resolved Hide resolved
] # For now, the dependecy on the `embassy-sync` crate is non-optional, but this might change in future
# Temporary, until (https://github.com/espressif/esp-idf/issues/13938) is addressed
# - When enabled, the code for the legacy ADC oneshot driver will be compiled;
# - When not enabled (default) the code for the new ADC oneshot driver will be compiled;
# - Since we don't wrap the legacy _continuous_ ADC driver, the new _continuous_ ADC driver is always compiled.
adc-oneshot-legacy = []
# Similar to adc-oneshot-legacy
# - When enabled (default), the code for the legacy RMT TX/RX driver will be compiled.
# - When disabled the code for the new onewire RMT driver will be compiled.
rmt-legacy = []
# Propagated esp-idf-sys features
native = ["esp-idf-sys/native"]
pio = ["esp-idf-sys/pio"]
Expand All @@ -42,13 +47,17 @@ libstart = ["esp-idf-sys/libstart"]
nb = "1"
embedded-can = "0.4.1"
embedded-hal = "1"
embedded-hal-0-2 = { package = "embedded-hal", version = "0.2.7", features = ["unproven"] }
embedded-hal-0-2 = { package = "embedded-hal", version = "0.2.7", features = [
ivmarkov marked this conversation as resolved.
Show resolved Hide resolved
"unproven",
] }
embedded-hal-nb = "1"
embedded-hal-async = "1"
embedded-io = "0.6"
embedded-io-async = "0.6"
esp-idf-sys = { version = "0.35", default-features = false }
critical-section = { version = "1.1.1", optional = true, features = ["restore-state-none"] }
critical-section = { version = "1.1.1", optional = true, features = [
ivmarkov marked this conversation as resolved.
Show resolved Hide resolved
"restore-state-none",
] }
heapless = "0.8"
num_enum = { version = "0.7", default-features = false }
enumset = { version = "1.1", default-features = false }
Expand Down
17 changes: 17 additions & 0 deletions examples/rmt_morse_code.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,10 +18,13 @@ use esp_idf_hal::delay::Ets;
use esp_idf_hal::gpio::*;
use esp_idf_hal::peripheral::*;
use esp_idf_hal::peripherals::Peripherals;
#[cfg(any(feature = "rmt-legacy", esp_idf_version_major = "4"))]
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm relatively sure that in the case where rmt-legacy is not enabled, this example will compile with "unused import" warnings, as you import a lot of stuff you don't use. Not the end of the world, but ideally we should fix that too.

The easiest way to do it (and to avoid sprinkling #[cfg(any(feature = "rmt-legacy", esp_idf_version_major = "4"))] all over the example is to just put the whole example in a new module, as in:

#[cfg(not(any(feature = "rmt-legacy", esp_idf_version_major = "4")))]
fn main() -> anyhow::Result<()> {
    println!("This example requires feature `rmt-legacy` enabled or using ESP-IDF v4.4.X");

    loop {
        std::thread::sleep(std::time::Duration::from_millis(1000));
    }
}

#[cfg(any(feature = "rmt-legacy", esp_idf_version_major = "4"))]
fn main() -> anyhow::Result<()> {
    example::main()
}

#[cfg(any(feature = "rmt-legacy", esp_idf_version_major = "4"))]
mod example {
... /// Here you move the whole code of the example, with imports and whatnot.
}

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done. Will do the other examples soon.

use esp_idf_hal::rmt::config::{CarrierConfig, DutyPercent, Loop, TransmitConfig};
#[cfg(any(feature = "rmt-legacy", esp_idf_version_major = "4"))]
use esp_idf_hal::rmt::*;
use esp_idf_hal::units::FromValueType;

#[cfg(any(feature = "rmt-legacy", esp_idf_version_major = "4"))]
fn main() -> anyhow::Result<()> {
esp_idf_hal::sys::link_patches();

Expand Down Expand Up @@ -64,6 +67,16 @@ fn main() -> anyhow::Result<()> {
Ok(())
}

#[cfg(not(any(feature = "rmt-legacy", esp_idf_version_major = "4")))]
fn main() -> anyhow::Result<()> {
println!("This example requires feature `rmt-legacy` enabled or using ESP-IDF v4.4.X");

loop {
std::thread::sleep(std::time::Duration::from_millis(1000));
}
}

#[cfg(any(feature = "rmt-legacy", esp_idf_version_major = "4"))]
fn send_morse_code<'d>(
channel: impl Peripheral<P = impl RmtChannel> + 'd,
led: impl Peripheral<P = impl OutputPin> + 'd,
Expand All @@ -85,10 +98,12 @@ fn send_morse_code<'d>(
Ok(tx)
}

#[cfg(any(feature = "rmt-legacy", esp_idf_version_major = "4"))]
fn high() -> Pulse {
Pulse::new(PinState::High, PulseTicks::max())
}

#[cfg(any(feature = "rmt-legacy", esp_idf_version_major = "4"))]
fn low() -> Pulse {
Pulse::new(PinState::Low, PulseTicks::max())
}
Expand All @@ -99,6 +114,7 @@ enum Code {
WordGap,
}

#[cfg(any(feature = "rmt-legacy", esp_idf_version_major = "4"))]
impl Code {
pub fn push_pulse(&self, pulses: &mut Vec<Pulse>) {
match &self {
Expand All @@ -118,6 +134,7 @@ fn find_codes(c: &char) -> &'static [Code] {
&[]
}

#[cfg(any(feature = "rmt-legacy", esp_idf_version_major = "4"))]
fn str_pulses(s: &str) -> Vec<Pulse> {
let mut pulses = vec![];
for c in s.chars() {
Expand Down
16 changes: 16 additions & 0 deletions examples/rmt_musical_buzzer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,13 @@ use core::time::Duration;

use esp_idf_hal::delay::Ets;
use esp_idf_hal::peripherals::Peripherals;
#[cfg(any(feature = "rmt-legacy", esp_idf_version_major = "4"))]
DaneSlattery marked this conversation as resolved.
Show resolved Hide resolved
use esp_idf_hal::rmt::{self, config::TransmitConfig, TxRmtDriver};

use esp_idf_hal::units::Hertz;
use notes::*;

#[cfg(any(feature = "rmt-legacy", esp_idf_version_major = "4"))]
fn main() -> anyhow::Result<()> {
esp_idf_hal::sys::link_patches();

Expand All @@ -28,19 +30,31 @@ fn main() -> anyhow::Result<()> {
}
}

#[cfg(not(any(feature = "rmt-legacy", esp_idf_version_major = "4")))]
fn main() -> anyhow::Result<()> {
println!("This example requires feature `rmt-legacy` enabled or using ESP-IDF v4.4.X");

loop {
std::thread::sleep(Duration::from_millis(1000));
}
}

#[cfg(any(feature = "rmt-legacy", esp_idf_version_major = "4"))]
pub fn play_song(tx: &mut TxRmtDriver<'static>, song: &[NoteValue]) -> anyhow::Result<()> {
for note_value in song {
note_value.play(tx)?;
}
Ok(())
}

#[cfg(any(feature = "rmt-legacy", esp_idf_version_major = "4"))]
pub struct NoteValueIter {
ticks: rmt::PulseTicks,
tone_cycles: u32,
pause_cycles: u32,
}

#[cfg(any(feature = "rmt-legacy", esp_idf_version_major = "4"))]
impl NoteValueIter {
fn new(ticks_per_sec: Hertz, note: &NoteValue) -> Self {
// Calculate the frequency for a piezo buzzer.
Expand All @@ -63,6 +77,7 @@ impl NoteValueIter {
}
}

#[cfg(any(feature = "rmt-legacy", esp_idf_version_major = "4"))]
impl std::iter::Iterator for NoteValueIter {
type Item = rmt::Symbol;

Expand Down Expand Up @@ -113,6 +128,7 @@ pub struct NoteValue {
duration: Duration,
}

#[cfg(any(feature = "rmt-legacy", esp_idf_version_major = "4"))]
impl NoteValue {
pub fn play(&self, tx: &mut TxRmtDriver<'static>) -> anyhow::Result<()> {
let ticks_hz = tx.counter_clock()?;
Expand Down
13 changes: 13 additions & 0 deletions examples/rmt_neopixel.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,12 @@ use anyhow::{bail, Result};
use core::time::Duration;
use esp_idf_hal::delay::FreeRtos;
use esp_idf_hal::peripherals::Peripherals;
#[cfg(any(feature = "rmt-legacy", esp_idf_version_major = "4"))]
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ditto.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done

use esp_idf_hal::rmt::config::TransmitConfig;
#[cfg(any(feature = "rmt-legacy", esp_idf_version_major = "4"))]
use esp_idf_hal::rmt::*;

#[cfg(any(feature = "rmt-legacy", esp_idf_version_major = "4"))]
fn main() -> Result<()> {
esp_idf_hal::sys::link_patches();

Expand All @@ -39,6 +42,16 @@ fn main() -> Result<()> {
})
}

#[cfg(not(any(feature = "rmt-legacy", esp_idf_version_major = "4")))]
fn main() -> anyhow::Result<()> {
println!("This example requires feature `rmt-legacy` enabled or using ESP-IDF v4.4.X");

loop {
std::thread::sleep(Duration::from_millis(1000));
}
}

#[cfg(any(feature = "rmt-legacy", esp_idf_version_major = "4"))]
fn neopixel(rgb: Rgb, tx: &mut TxRmtDriver) -> Result<()> {
let color: u32 = rgb.into();
let ticks_hz = tx.counter_clock()?;
Expand Down
89 changes: 89 additions & 0 deletions examples/rmt_onewire.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
//! RMT Onewire Example
DaneSlattery marked this conversation as resolved.
Show resolved Hide resolved
//!
//! Example demonstrating the use of the onewire component.
//!
//! In order to use this example, an overidden `Cargo.toml` must be defined with the following definitions:
//! ```
//! [[package.metadata.esp-idf-sys.extra_components]]
//! remote_component = { name = "onewire_bus", version = "^1.0.2" }
//!
//!
//! [patch.crates-io]
//! esp-idf-sys = { git = "https://github.com/esp-rs/esp-idf-sys", rev = "2728b85" }
//!
//! ```
//!
//! The example can then be run with
//! `MCU=<target> cargo run --example rmt_onewire --manifest-path /path/to/other/Cargo.toml`
//!
//! Below is a connection sketch, the signal pin must be externally pulled-up
//! with a 4.7kOhm resistor.
//! This example uses gpio 16, but any pin capable of
//! input AND output is suitable.
//!
//! If the example is successful, it should print the address of each
//! onewire device attached to the bus.
//!
//! ┌──────────────────────────┐
//! │ 3.3V├───────┬─────────────┬──────────────────────┐
//! │ │ ┌┴┐ │VDD │VDD
//! │ ESP Board │ 4.7k│ │ ┌──────┴──────┐ ┌──────┴──────┐
//! │ │ └┬┘ DQ│ │ DQ│ │
//! │ ONEWIRE_GPIO_PIN├───────┴──┬───┤ DS18B20 │ ┌───┤ DS18B20 │ ......
//! │ │ └───│-------------│────┴───│-------------│──
//! │ │ └──────┬──────┘ └──────┬──────┘
//! │ │ │GND │GND
//! │ GND├─────────────────────┴──────────────────────┘
//! └──────────────────────────┘
//!
//!
//! This example demonstrates:
//! * A RMT device in both TX and RX mode.
//! * Usage of the onewire bus driver interface.
//! * How to iterate through a device search to discover devices on the bus.

use esp_idf_hal::delay::FreeRtos;
#[cfg(all(
esp_idf_soc_rmt_supported,
not(feature = "rmt-legacy"),
esp_idf_comp_espressif__onewire_bus_enabled,
))]
use esp_idf_hal::onewire::{DeviceSearch, OneWireBusDriver};
use esp_idf_hal::peripherals::Peripherals;

#[cfg(all(
esp_idf_soc_rmt_supported,
not(esp_idf_version_major = "4"),
esp_idf_comp_espressif__onewire_bus_enabled,
))]
fn main() -> anyhow::Result<()> {
println!("Starting APP!");

let peripherals = Peripherals::take()?;

let onewire_gpio_pin = peripherals.pins.gpio16;

let mut rmt_onewire: OneWireBusDriver = OneWireBusDriver::new(onewire_gpio_pin)?;
let search: DeviceSearch = rmt_onewire.search()?;

for device in search {
println!("Found Device: {}", device.address());
}
loop {
FreeRtos::delay_ms(3000);
}
}

#[cfg(any(
feature = "rmt-legacy",
esp_idf_version_major = "4",
not(esp_idf_comp_espressif__onewire_bus_enabled),
not(esp_idf_soc_rmt_supported),
))]
fn main() -> anyhow::Result<()> {
println!("This example requires feature `rmt-legacy` disabled, using ESP-IDF > v4.4.X, the component included in `Cargo.toml`, or is not supported on this MCU");

loop {
std::thread::sleep(std::time::Duration::from_millis(1000));
}
}
11 changes: 11 additions & 0 deletions examples/rmt_transceiver.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,11 +20,13 @@

use esp_idf_hal::delay::FreeRtos;
use esp_idf_hal::peripherals::Peripherals;
#[cfg(any(feature = "rmt-legacy", esp_idf_version_major = "4"))]
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ditto - mod example {}.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done

use esp_idf_hal::rmt::{
FixedLengthSignal, PinState, Pulse, PulseTicks, Receive, RmtReceiveConfig, RmtTransmitConfig,
RxRmtDriver, TxRmtDriver,
};

#[cfg(any(feature = "rmt-legacy", esp_idf_version_major = "4"))]
fn main() -> anyhow::Result<()> {
println!("Starting APP!");

Expand Down Expand Up @@ -105,3 +107,12 @@ fn main() -> anyhow::Result<()> {
FreeRtos::delay_ms(3000);
}
}

#[cfg(not(any(feature = "rmt-legacy", esp_idf_version_major = "4")))]
fn main() -> anyhow::Result<()> {
println!("This example requires feature `rmt-legacy` enabled or using ESP-IDF v4.4.X");

loop {
std::thread::sleep(std::time::Duration::from_millis(1000));
}
}
14 changes: 14 additions & 0 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,21 @@ pub mod peripheral;
pub mod peripherals;
pub mod prelude;
pub mod reset;

// mutually exclusive features assert
#[cfg(all(feature = "rmt-legacy", esp_idf_comp_espressif__onewire_bus_enabled))]
compile_error!("the onewire component cannot be used with the legacy rmt peripheral");

#[cfg(any(feature = "rmt-legacy", esp_idf_version_major = "4"))]
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This cannot be done so simply. As discussed during the previous iteration, you do need the RMT peripherals which are defined by the esp_idf_hal::rmt module. And you need to pass a RMT channel to OWDriver in addition to the pin. So you can't just #ifNdef the rmt module when the rmt-legacy feature is not defined. What you need to do instead is to leave the rmt module here unconditionally, and then - inside the rmt module - protect with an #ifdef all of the driver code, but leave the peripheral definitions always defined and valid - even when the legacy RMT driver is #ifNdef-ed.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done

pub mod rmt;

#[cfg(all(
esp_idf_soc_rmt_supported,
not(esp_idf_version_major = "4"),
esp_idf_comp_espressif__onewire_bus_enabled,
))]
pub mod onewire;
ivmarkov marked this conversation as resolved.
Show resolved Hide resolved

pub mod rom;
pub mod spi;
pub mod sys;
Expand Down
Loading
Loading