Skip to content

Async RMT Tx not working with >64 PulseCodes #1779

@akriese

Description

@akriese

I was switching my project from manual interrupt handling to using embassy. In the process I also switched from blocking to async RMT. Before, I was sending about 150*24=3000 PulseCodes on each transmission without issues to control an LED strip. With the async implementation, the strip wasnt getting any input apparently. I used parts of the embassy_rmt example to reproduce this and check for which array sizes the RMT would stop working completely. At 65 PulseCodes, my example stopped working, so 64 seems to be the sweet spot.

This makes some sense as the RAM blocks for each RMT channel hold up to 64 data points according to the ESP32 documentation. So, I guess, something which the Blocking implementation is doing right is going wrong on the Async side. I haven't had the time to look into the implementation further. Maybe someone has an insight on this?

Here are some snippets of the program:

#[main]
async fn main(spawner: Spawner) {
    let peripherals = Peripherals::take();
    let system = SystemControl::new(peripherals.SYSTEM);
    let clocks = ClockControl::max(system.clock_control).freeze();

    esp_println::logger::init_logger_from_env();

    let timg0 = TimerGroup::new_async(peripherals.TIMG0, &clocks);
    esp_hal_embassy::init(&clocks, timg0);

    let io = Io::new(peripherals.GPIO, peripherals.IO_MUX);

    let channel = transmit::init_rmt(peripherals.RMT, io.pins.gpio26, &clocks);

    spawner.spawn(test_rmt(channel)).ok();
}

pub fn init_rmt<'d, P: esp_hal::gpio::OutputPin>(
    rmt: impl Peripheral<P = RMT> + 'd,
    pin: impl Peripheral<P = P> + 'd,
    clocks: &Clocks,
) -> Channel<Async, 0> {
    let _rmt = Rmt::new_async(rmt, HertzU32::MHz(80), clocks).unwrap();
    _rmt.channel0
        .configure(
            pin,
            TxChannelConfig {
                clk_divider: 1,
                idle_output_level: false,
                idle_output: false,
                carrier_modulation: false,
                carrier_high: 1,
                carrier_low: 1,
                carrier_level: false,
            },
        )
        .unwrap()
}

#[embassy_executor::task]
async fn test_rmt(mut channel: Channel<Async, 0>) {
    loop {
        let on = 10000 / NS_PER_CLOCK_CYCLE;
        let off = 10000 / NS_PER_CLOCK_CYCLE;
        let mut sequence = [PulseCode {
            level1: true,
            length1: on,
            level2: false,
            length2: off,
        }; 65];

        sequence.last_mut().unwrap().length2 = 0;

        channel.transmit(&sequence).await.ok();

        Timer::after_secs(1).await;
    }
}

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    Status

    Todo

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions