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 22 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
2 changes: 1 addition & 1 deletion .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 = "xtensa-esp32-espidf"

[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
4 changes: 4 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,10 @@ embassy-sync = [] # For now, the dependecy on the `embassy-sync` crate is non-op
# - 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 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
172 changes: 172 additions & 0 deletions examples/rmt_onewire.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,172 @@
//! 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 std::time::Duration;

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::{OWAddress, OWCommand, OWDriver};
use esp_idf_hal::peripherals::Peripherals;
use esp_idf_sys::EspError;

#[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 onewire_bus: OWDriver = OWDriver::new(onewire_gpio_pin)?;
let device = {
let mut search = onewire_bus.search()?;
search.next()
};
// let mut search = onewire_bus.search()?;
// let device = search.next();
if device.is_none() {
println!("No device found");
return Ok(());
}

let device = device.unwrap();
if let Err(err) = device {
println!("An error occured searching for the device, err = {}", err);
return Err(err.into());
}
let device = device.unwrap();
println!(
"Found Device: {:?}, family code = {}",
device,
device.family_code()
);

loop {
ds18b20_trigger_temp_conversion(&device, &onewire_bus)?;
let temp = ds18b20_get_temperature(&device, &onewire_bus)?;
println!("Temperature: {}", temp);
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));
}
}

#[cfg(all(
esp_idf_soc_rmt_supported,
not(esp_idf_version_major = "4"),
esp_idf_comp_espressif__onewire_bus_enabled,
))]
fn ds18b20_send_command<'a>(addr: &OWAddress, bus: &OWDriver, cmd: u8) -> Result<(), EspError> {
let mut buf = [0; 10];
ivmarkov marked this conversation as resolved.
Show resolved Hide resolved
buf[0] = OWCommand::MatchRom as _;
let addr = addr.address().to_le_bytes();
buf[1..9].copy_from_slice(&addr);
buf[9] = cmd;

bus.write(&buf)
}

#[allow(dead_code)]
#[repr(u8)]
enum Ds18b20Command {
ConvertTemp = 0x44,
WriteScratch = 0x4E,
ReadScratch = 0xBE,
}
#[cfg(all(
esp_idf_soc_rmt_supported,
not(esp_idf_version_major = "4"),
esp_idf_comp_espressif__onewire_bus_enabled,
))]
fn ds18b20_trigger_temp_conversion<'a>(addr: &OWAddress, bus: &OWDriver) -> Result<(), EspError> {
// reset bus and check if the ds18b20 is present
bus.reset()?;

ds18b20_send_command(addr, bus, Ds18b20Command::ConvertTemp as u8)?;

// delay proper time for temp conversion,
// assume max resolution (12-bits)
std::thread::sleep(Duration::from_millis(800));

Ok(())
}
#[cfg(all(
esp_idf_soc_rmt_supported,
not(esp_idf_version_major = "4"),
esp_idf_comp_espressif__onewire_bus_enabled,
))]
fn ds18b20_get_temperature<'a>(addr: &OWAddress, bus: &OWDriver) -> Result<f32, EspError> {
bus.reset()?;

ds18b20_send_command(addr, bus, Ds18b20Command::ReadScratch as u8)?;

let mut buf = [0u8; 10];
bus.read(&mut buf)?;
let lsb = buf[0];
let msb = buf[1];

let temp_raw: u16 = (u16::from(msb) << 8) | u16::from(lsb);

Ok(f32::from(temp_raw) / 16.0)
}
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));
}
}
Loading
Loading