mirror of
https://github.com/esp-rs/esp-idf-hal.git
synced 2025-10-02 06:40:55 +00:00

* WIP: Initial tx rmt implementation * Rename Bulder to Config to line up with other mods * WIP Potential traits for a "pulses" mod in embedded-hal * WIP: Initial tx rmt implementation * Rename Bulder to Config to line up with other mods * WIP Potential traits for a "pulses" mod in embedded-hal * Copied example code from ledc fork. Semi-working example. * Rename level to pulse. dev-dep versions. * WIP RMT, Examples * WIP RMT Fix neopixel example * WIP RMT morse code work * WIP RMT fixed morse example * WIP RMT more config, docs. * WIP RMT fix compilation * WIP RMT Fix doc comment in example. * WIP RMT: notes on examples * WIP RMT Group up same level config items. * WIP RMT Change half_inserted to an Option * WIP RMT Don't need to return Result in clear() * WIP RMT Config refactor. Into for enum. * Result instead of Option in PulseTick * Don't use floats for ticks calcs * WIP Duration for ticks * Cleanups. * Moved Duration logic into PulseDuration. * Remove unused tick_hz field. * Cleanups. * WIP playing around with generics * Refactored out Vec storage out of Writer * WIP Heap and Stack implementations for data * WIP about to nuke tricky const code * Cleanups * Own PinState. start/start_blocking. * Wrap duty percent with range safety. * Use units::Hertz * Use Hertz in ticks_hz * Stop transmitting implementation * Fix morse example * rmt peripheral for channels (4 for now) * Small tweaks * Morse example to demo more functionality * WIP Fixes and testing functionality * Cleanups and notes * Assign devices to number of channels. Cleanups. * Sprinkled TODO's around for docs/fixes * Longer messages don't repeat so remove it for now * Rename data to signal because data is a too generic term * More docs * Don't mention receiving in description. * More docs * Rename `add` to `push` like Vec. More docs. * Rename `Writer` to `Transmit` to line up with rmt docs. * Accidentally had idle_level in carrier config. * More docs and cleanups. std compatibility. * Remove chip::HwChannel import because of a * import later. * Separate duration to ticks calc. Music example. * Added comment on example. * clippy: ok_or_else, Default. * fixes: mut self, allows/features, alloc, &Pulse. * only need feature alloc for the use warning. * rename Signal implementations * Alloc, morse example fix. * Didn't need that map. iter does the ref. * Clippy repairs. println! instead of info!
162 lines
5.2 KiB
Rust
162 lines
5.2 KiB
Rust
//! RMT Transmit Example -- Morse Code
|
|
//!
|
|
//! To try this out, connect a piezo buzzer via a resistor into pin 17. It should repeat "HELLO"
|
|
//! in morse code.
|
|
//!
|
|
//! Set pin 16 to low to stop the signal and make the buzzer sound "GOODBYE" in morse code.
|
|
//!
|
|
//! Example loosely based off which has a circuit you can follow.
|
|
//! https://github.com/espressif/esp-idf/tree/master/examples/peripherals/rmt/morse_code
|
|
//!
|
|
//! This example demonstrates:
|
|
//! * A carrier signal.
|
|
//! * Looping.
|
|
//! * Background sending.
|
|
//! * Stopping/releasing a [`Pin`] and [`Channel`], to be used again.
|
|
//!
|
|
use embedded_hal::delay::blocking::DelayUs;
|
|
use embedded_hal::digital::blocking::InputPin;
|
|
use esp_idf_hal::delay::Ets;
|
|
use esp_idf_hal::gpio::{Gpio16, Gpio17, Input, Output, Pin};
|
|
use esp_idf_hal::peripherals::Peripherals;
|
|
use esp_idf_hal::rmt::config::{CarrierConfig, DutyPercent, Loop, TransmitConfig};
|
|
use esp_idf_hal::rmt::VariableLengthSignal; // This example requires `alloc` feature.
|
|
use esp_idf_hal::rmt::{PinState, Pulse, PulseTicks, Transmit, CHANNEL0};
|
|
use esp_idf_hal::units::FromValueType;
|
|
|
|
fn main() -> anyhow::Result<()> {
|
|
esp_idf_sys::link_patches();
|
|
|
|
let peripherals = Peripherals::take().unwrap();
|
|
let led: Gpio17<Output> = peripherals.pins.gpio17.into_output()?;
|
|
let stop: Gpio16<Input> = peripherals.pins.gpio16.into_input()?;
|
|
let channel = peripherals.rmt.channel0;
|
|
|
|
let carrier = CarrierConfig::new()
|
|
.duty_percent(DutyPercent::new(50)?)
|
|
.frequency(611.Hz());
|
|
let mut config = TransmitConfig::new()
|
|
.carrier(Some(carrier))
|
|
.looping(Loop::Count(100))
|
|
.clock_divider(255);
|
|
|
|
let tx = send_morse_code(&config, led, channel, "HELLO ")?;
|
|
|
|
println!("Keep sending until pin {} is set low.", stop.pin());
|
|
while stop.is_high()? {
|
|
Ets.delay_ms(100)?;
|
|
}
|
|
println!("Pin {} is set to low--stopping message.", stop.pin());
|
|
|
|
// Release pin and channel so we can use them again.
|
|
let (led, channel) = tx.release()?;
|
|
|
|
// Wait so the messages don't get garbled.
|
|
Ets.delay_ms(3000)?;
|
|
|
|
// Now send a single message and stop.
|
|
println!("Saying GOODBYE!");
|
|
config.looping = Loop::None;
|
|
send_morse_code(&config, led, channel, "GOODBYE")?;
|
|
|
|
Ok(())
|
|
}
|
|
|
|
fn send_morse_code(
|
|
config: &TransmitConfig,
|
|
led: Gpio17<Output>,
|
|
channel: CHANNEL0,
|
|
message: &str,
|
|
) -> anyhow::Result<Transmit<Gpio17<Output>, CHANNEL0>> {
|
|
println!("Sending morse message '{}' to pin {}.", message, led.pin());
|
|
|
|
let mut signal = VariableLengthSignal::new();
|
|
let pulses = str_pulses(message);
|
|
// We've been collecting `Pulse` but `VariableLengthSignal` needs `&Pulse`:
|
|
let pulses: Vec<&Pulse> = pulses.iter().collect();
|
|
signal.push(pulses)?;
|
|
|
|
let mut tx = Transmit::new(led, channel, config)?;
|
|
tx.start(signal)?;
|
|
|
|
// Return `tx` so we can release the pin and channel later.
|
|
Ok(tx)
|
|
}
|
|
|
|
fn high() -> Pulse {
|
|
Pulse::new(PinState::High, PulseTicks::max())
|
|
}
|
|
|
|
fn low() -> Pulse {
|
|
Pulse::new(PinState::Low, PulseTicks::max())
|
|
}
|
|
|
|
enum Code {
|
|
Dot,
|
|
Dash,
|
|
WordGap,
|
|
}
|
|
|
|
impl Code {
|
|
pub fn push_pulse(&self, pulses: &mut Vec<Pulse>) {
|
|
match &self {
|
|
Code::Dot => pulses.extend_from_slice(&[high(), low()]),
|
|
Code::Dash => pulses.extend_from_slice(&[high(), high(), high(), low()]),
|
|
Code::WordGap => pulses.extend_from_slice(&[low(), low(), low(), low(), low(), low()]),
|
|
}
|
|
}
|
|
}
|
|
|
|
fn find_codes(c: &char) -> &'static [Code] {
|
|
for (found, codes) in CODES.iter() {
|
|
if found == c {
|
|
return codes;
|
|
}
|
|
}
|
|
&[]
|
|
}
|
|
|
|
fn str_pulses(s: &str) -> Vec<Pulse> {
|
|
let mut pulses = vec![];
|
|
for c in s.chars() {
|
|
for code in find_codes(&c) {
|
|
code.push_pulse(&mut pulses);
|
|
}
|
|
|
|
// Create a gap after each symbol.
|
|
pulses.push(low());
|
|
pulses.push(low());
|
|
}
|
|
pulses
|
|
}
|
|
|
|
const CODES: &[(char, &[Code])] = &[
|
|
(' ', &[Code::WordGap]),
|
|
('A', &[Code::Dot, Code::Dash]),
|
|
('B', &[Code::Dash, Code::Dot, Code::Dot, Code::Dot]),
|
|
('C', &[Code::Dash, Code::Dot, Code::Dash, Code::Dot]),
|
|
('D', &[Code::Dash, Code::Dot, Code::Dot]),
|
|
('E', &[Code::Dot]),
|
|
('F', &[Code::Dot, Code::Dot, Code::Dash, Code::Dot]),
|
|
('G', &[Code::Dash, Code::Dash, Code::Dot]),
|
|
('H', &[Code::Dot, Code::Dot, Code::Dot, Code::Dot]),
|
|
('I', &[Code::Dot, Code::Dot]),
|
|
('J', &[Code::Dot, Code::Dash, Code::Dash, Code::Dash]),
|
|
('K', &[Code::Dash, Code::Dot, Code::Dash]),
|
|
('L', &[Code::Dot, Code::Dash, Code::Dot, Code::Dot]),
|
|
('M', &[Code::Dash, Code::Dash]),
|
|
('N', &[Code::Dash, Code::Dot]),
|
|
('O', &[Code::Dash, Code::Dash, Code::Dash]),
|
|
('P', &[Code::Dot, Code::Dash, Code::Dash, Code::Dot]),
|
|
('Q', &[Code::Dash, Code::Dash, Code::Dot, Code::Dash]),
|
|
('R', &[Code::Dot, Code::Dash, Code::Dot]),
|
|
('S', &[Code::Dot, Code::Dot, Code::Dot]),
|
|
('T', &[Code::Dash]),
|
|
('U', &[Code::Dot, Code::Dot, Code::Dash]),
|
|
('V', &[Code::Dot, Code::Dot, Code::Dot, Code::Dash]),
|
|
('W', &[Code::Dot, Code::Dash, Code::Dash]),
|
|
('X', &[Code::Dash, Code::Dot, Code::Dot, Code::Dash]),
|
|
('Y', &[Code::Dash, Code::Dot, Code::Dash, Code::Dash]),
|
|
('Z', &[Code::Dash, Code::Dash, Code::Dot, Code::Dot]),
|
|
];
|