mirror of
https://github.com/esp-rs/esp-idf-hal.git
synced 2025-12-29 03:18:10 +00:00
* push first draft * fix source clock * fix clippy lints * rename `source_clock` to `clock_source` * implement sync manager * implement `RxChannel` * finish implementing TxChannel * make code compile with and without `alloc` * implement encoder and remove non_exhaustive * push new changes * push now hopefully safe impl * fix ci * use correct esp_idf_version in simple_encoder example * cleanup example * ... * fix ub * minor code improvements * implement async support * fix use-after-free bug and add a helper function * redesign `TxChannelDriver` (again) * fix minor mistakes and add `TxQueue` * rewrite `RxChannelDriver` and do some minor adjustments * adress the review (partially) * implement more things * make the async code mostly safe wrappers * return token in when pushing on queue * push initial new impl * update code * update code * remove todo * update changelog * adjust duty cycle to store an `f32` * fix clippy * fix clippy * fix clippy
135 lines
3.8 KiB
Rust
135 lines
3.8 KiB
Rust
//! This example demonstrates how to create a custom RMT encoder that loops for a
|
|
//! specified number of times or indefinitely.
|
|
//!
|
|
//! The `Loop` option provided by the driver is not available on every ESP32 and
|
|
//! how often it can loop (given a count) is limited to `u32::MAX` (maybe less).
|
|
//!
|
|
//! This example creates a custom encoder that will not have these limitations.
|
|
//!
|
|
//! SPDX-License-Identifier: Unlicense OR CC0-1.0
|
|
|
|
#![allow(unknown_lints)]
|
|
#![allow(unexpected_cfgs)]
|
|
|
|
#[cfg(any(
|
|
feature = "rmt-legacy",
|
|
not(esp_idf_version_at_least_5_3_0),
|
|
not(esp_idf_soc_rmt_supported),
|
|
))]
|
|
fn main() -> anyhow::Result<()> {
|
|
println!("This example requires feature `rmt-legacy` disabled, using ESP-IDF >= v5.1.2, or is not supported on this MCU");
|
|
|
|
loop {
|
|
std::thread::sleep(std::time::Duration::from_millis(1000));
|
|
}
|
|
}
|
|
|
|
#[cfg(all(
|
|
esp_idf_soc_rmt_supported,
|
|
esp_idf_version_at_least_5_3_0,
|
|
not(feature = "rmt-legacy")
|
|
))]
|
|
mod example {
|
|
use esp_idf_hal::peripherals::Peripherals;
|
|
use esp_idf_hal::rmt::config::TxChannelConfig;
|
|
use esp_idf_hal::rmt::encoder::{
|
|
CopyEncoder, Encoder, EncoderState, EncoderWrapper, RmtChannelHandle,
|
|
};
|
|
use esp_idf_hal::rmt::Symbol;
|
|
use esp_idf_hal::rmt::TxChannelDriver;
|
|
use esp_idf_hal::units::Hertz;
|
|
|
|
use esp_idf_sys::*;
|
|
|
|
const RMT_RESOLUTION: Hertz = Hertz(10_000_000); // 10MHz resolution, 1 tick = 0.1us
|
|
|
|
pub struct LoopEncoder<E> {
|
|
count: u128,
|
|
target: Option<u128>,
|
|
encoder: E,
|
|
}
|
|
|
|
impl<E: Encoder> LoopEncoder<E> {
|
|
pub fn new(target: Option<u128>, encoder: E) -> Self {
|
|
Self {
|
|
count: 0,
|
|
target,
|
|
encoder,
|
|
}
|
|
}
|
|
}
|
|
|
|
impl<E: Encoder> Encoder for LoopEncoder<E> {
|
|
type Item = E::Item;
|
|
|
|
fn encode(
|
|
&mut self,
|
|
handle: &mut RmtChannelHandle,
|
|
primary_data: &[Self::Item],
|
|
) -> (usize, EncoderState) {
|
|
let mut written = 0;
|
|
let mut state;
|
|
|
|
loop {
|
|
let (current_written, current_state) = self.encoder.encode(handle, primary_data);
|
|
written += current_written;
|
|
state = current_state;
|
|
|
|
// If the inner encoder completed, one count has been completed.
|
|
if let EncoderState::EncodingComplete = state {
|
|
// only increment the count if there is a target, otherwise it might crash in debug mode because of overflow
|
|
if self.target.is_some() {
|
|
self.count += 1;
|
|
}
|
|
|
|
// If the target count has been reached, stop encoding.
|
|
if self.target.is_some_and(|target| self.count >= target) {
|
|
break;
|
|
}
|
|
} else {
|
|
break;
|
|
}
|
|
}
|
|
|
|
(written, state)
|
|
}
|
|
|
|
fn reset(&mut self) -> Result<(), EspError> {
|
|
self.encoder.reset()?;
|
|
self.count = 0;
|
|
Ok(())
|
|
}
|
|
}
|
|
|
|
pub fn run() -> anyhow::Result<()> {
|
|
println!("Create RMT TX channel");
|
|
|
|
let peripherals = Peripherals::take()?;
|
|
|
|
let mut channel = TxChannelDriver::new(
|
|
peripherals.pins.gpio21,
|
|
&TxChannelConfig {
|
|
resolution: RMT_RESOLUTION,
|
|
..Default::default()
|
|
},
|
|
)?;
|
|
|
|
println!("Start Encoding and sending symbols");
|
|
|
|
let encoder = EncoderWrapper::new(LoopEncoder::new(Some(50), CopyEncoder::new()?))?;
|
|
|
|
channel.send_and_wait(encoder, &[Symbol::default()], &Default::default())?;
|
|
|
|
Ok(())
|
|
}
|
|
}
|
|
|
|
#[cfg(all(
|
|
esp_idf_soc_rmt_supported,
|
|
esp_idf_version_at_least_5_3_0,
|
|
not(feature = "rmt-legacy")
|
|
))]
|
|
fn main() -> anyhow::Result<()> {
|
|
example::run()
|
|
}
|