Page 1 of 1

DMX Controller in Rust (ESP32C6) issues

Posted: Sun Feb 01, 2026 12:28 pm
by Drummer08
Hello,

I'm pretty new to the esp world and my rust knowledge is also limited but I wanted to create a dmx controller for this light (https://www.thomann.de/de/stairville_cl ... _bar_5.htm).

And because of the esp_hal 1.0.0 release I gave it a try in rust.

I have a ESP32-C6-DevKitC-1 connected to an max3485 (https://www.ebay.de/itm/406163825571?_s ... R-r9z4uDZw) module, which is then connected via a dmx cable to the light. My current code looks like this:

Code: Select all

 
#![no_std]
#![no_main]
#![deny(
    clippy::mem_forget,
    reason = "mem::forget is generally not safe to do with esp_hal types, especially those \
    holding buffers for the duration of a data transfer."
)]
#![deny(clippy::large_stack_frames)]

use esp_hal::clock::CpuClock;
use esp_hal::delay::Delay;
use esp_hal::gpio::{Level, Output, OutputConfig};
use esp_hal::main;
use esp_hal::uart::{Config, DataBits, Parity, StopBits, Uart};

use {esp_backtrace as _, esp_println as _};

// This creates a default app-descriptor required by the esp-idf bootloader.
// For more information see: <https://docs.espressif.com/projects/esp-idf/en/stable/esp32/api-reference/system/app_image_format.html#application-description>
esp_bootloader_esp_idf::esp_app_desc!();

#[allow(
    clippy::large_stack_frames,
    reason = "it's not unusual to allocate larger buffers etc. in main"
)]
#[main]
fn main() -> ! {
    let config = esp_hal::Config::default().with_cpu_clock(CpuClock::max());
    let mut peripherals = esp_hal::init(config);

    let delay = Delay::new();

    let uart_config = Config::default()
        .with_baudrate(250_000)
        .with_data_bits(DataBits::_8)
        .with_parity(Parity::None)
        .with_stop_bits(StopBits::_2);

    let mut frame = [0u8; 513];
    frame[0] = 0x00;
    frame[1] = 50;
    frame[2] = 200;
    frame[3] = 30;
    frame[4] = 125;

    let mut en_pin = Output::new(peripherals.GPIO5, Level::Low, OutputConfig::default());
    en_pin.set_high();

    loop {
        let mut tx_pin = Output::new(
            peripherals.GPIO4.reborrow(),
            Level::High,
            OutputConfig::default(),
        );

        tx_pin.set_low();
        delay.delay_micros(200);

        tx_pin.set_high();
        delay.delay_micros(20);

        core::mem::drop(tx_pin);

        let mut uart = Uart::new(peripherals.UART0.reborrow(), uart_config)
            .unwrap()
            .with_tx(peripherals.GPIO4.reborrow());

        uart.write(&frame).unwrap();
        uart.flush().unwrap();

        core::mem::drop(uart);

        delay.delay_millis(30);
    }
}
The problem is the light will light up in the correct color but then starts to flicker and at some point it just doesn't show any light and then it starts to flicker again.

What I know about dmx is, I need to do a break (low) for some period of time and a mark after break (MAB) for some period of time and then send the data via uart. This needs to be done every time. The problem is the eps rust uart implementation has no uart break. So my approach is to configure the tx as a simple output pin and then drop it and then create the uart transmission. The rust implementation of the esp_hal consumes the pins when they get configured. Because of this I have to drop and reinitialize the output and uart every time.

I could get the light to do what I want with an max485 module and an Arduino. They are not the same modules. The max3485 its specifically for 3.3v and the max485 for 5v. So I think this is not a connection issue.

I think there is an uart break bit which can be set to do a real break but its really low level and not exposed in the esp_hal as I know.

Is there something I could do to fix the flickering and drop outs of the light?

Re: DMX Controller in Rust (ESP32C6) issues

Posted: Mon Feb 02, 2026 9:46 am
by ESP_mabez
Hi there!

We did land a `send_break` function for uart after 1.0, but its not released yet, not stable: https://github.com/esp-rs/esp-hal/blob/ ... od.rs#L861.

If you can switch to using git (see https://docs.espressif.com/projects/rus ... s-from-git if you're not sure) you can try this out.

If you run into issues, its more likely to be seen one the esp-hal issue tracker, so feel free to continue this there.

Re: DMX Controller in Rust (ESP32C6) issues

Posted: Sun Feb 22, 2026 4:43 pm
by Drummer08
Thank you for your help.
With the send_break function I could get it to work.
I had to order the "raw" max3485 dip chip. Before that I used a basic module with the max3485 on it, which was the reason for the flickering.
With the "raw" chip and the send_break function the light lights up perfectly.
This is my code so far. I'm try to create and publish a library:

Code: Select all

#![no_std]
#![no_main]

use esp_backtrace as _;
use esp_hal::{
    clock::CpuClock,
    delay::Delay,
    gpio::{Level, Output, OutputConfig},
    main,
    uart::{Config, DataBits, Parity, StopBits, Uart},
};

#[main]
fn main() -> ! {
    let config = esp_hal::Config::default().with_cpu_clock(CpuClock::max());
    let peripherals = esp_hal::init(config);

    let delay = Delay::new();

    let mut uart = Uart::new(
        peripherals.UART0,
        Config::default()
            .with_baudrate(250_000)
            .with_data_bits(DataBits::_8)
            .with_parity(Parity::None)
            .with_stop_bits(StopBits::_2),
    )
    .unwrap()
    .with_tx(peripherals.GPIO4);

    // --- RS485 driver enable pin ---
    let mut en_pin = Output::new(peripherals.GPIO5, Level::Low, OutputConfig::default());
    en_pin.set_high();

    // --- DMX frame ---
    let mut frame = [0u8; 513];
    frame[0] = 0x00; // start code
    frame[1] = 125;
    frame[2] = 255;
    frame[3] = 0;
    frame[4] = 0;

    // let break_bits = 100 / (1_000_000 / 250_000);
    // let mab_bits = 12 / (1_000_000 / 250_000);

    loop {
        en_pin.set_high();

        // --- BREAK ---
        uart.send_break(22);

        // MAB: HIGH for 24 µs
        delay.delay_micros(24);

        // --- DMX data ---
        uart.write(&frame).unwrap();
        uart.flush().unwrap();

        en_pin.set_low();

        delay.delay_millis(30); // DMX refresh rate
    }
}
The send_break function is not yet released.
Do you know when the next version is supposed to release?