rmt timing not precise on dmx512 packets

mhmart
Posts: 2
Joined: Mon Sep 08, 2025 1:34 pm

rmt timing not precise on dmx512 packets

Postby mhmart » Sun Oct 05, 2025 12:53 pm

I'm using an esp32 s3 (dual core) and I'd like to transmit DMX signals. The thing is that I have set the resolution as such that each tick is 4us (should be) but what I am getting is bits with way less time duration.

Image

I am using esp-idf v5.5. I know that for now the overhead in the task is too much but that should not have an influence of the timing on the signals, right?

Any clue what might be causing this effect on the signals? The expected bits are there actually but timing is not correct.

Image

Does anyone have a clue on why my timing might not be correct and what I could do to solve this?

My code (i know bit much but rather all than lack of information)

main.c

Code: Select all

#include <stdio.h>
#include "sdkconfig.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "esp_cpp.h"

void app_main(void)
{
    printf("Main, Starting\n");
    esp_cpp();
    printf("Restarting now.\n");
    fflush(stdout);
    esp_restart();
}
esp_cpp.cpp

Code: Select all

#include <stdio.h>
#include <freertos/FreeRTOS.h>
#include <freertos/task.h>
#include "driver/uart.h"
#include "esp_cpp.h"
#include "esp_dmx_transmitter.h"

extern "C" {  
    void esp_cpp() {
        uart_port_t dmx_uart_num = UART_NUM_1;
        ESP_Dmx_Transmitter *p_dmx_transmitter = new ESP_Dmx_Transmitter(dmx_uart_num);

        p_dmx_transmitter->init();

        while(true) {
            p_dmx_transmitter->transmit();
            vTaskDelay(1000 / portTICK_PERIOD_MS);
        }
    }
}
esp_cpp.h

Code: Select all

#ifndef _ESP_CPP_H_
#define _ESP_CPP_H_


#ifdef __cplusplus
    extern "C" {
#endif
    

void esp_cpp();

#ifdef __cplusplus
    } 
#endif


#endif //_ESP_CPP_H

esp_dmx_transmitter.h

Code: Select all

#ifndef _ESP_DMX_TRANSMITTER_H
#define _ESP_DMX_TRANSMITTER_H

#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "driver/uart.h"
#include <stdint.h>
#include "driver/rmt_tx.h"

class ESP_Dmx_Transmitter {
    public:
        ESP_Dmx_Transmitter(uart_port_t uart_num) : _dmx_uart_num(uart_num) {};
        ~ESP_Dmx_Transmitter() {};
        
        void init();
        void transmit();

    private:
        const uart_port_t _dmx_uart_num;
        friend void _esp_dmx_transmitter_task(void*);
        uint8_t _dmx_buffer[513];
        bool _flag_transmit = false;

        rmt_copy_encoder_config_t _copy_encoder_config = {};
        rmt_encoder_handle_t _copy_encoder = NULL;

        rmt_transmit_config_t _tx_config = {
            .loop_count = 0,
            .flags = {
                .eot_level = 1,
                .queue_nonblocking = 1,
            },
        };

        rmt_symbol_word_t _dmx_break_mab_symbol;
        rmt_channel_handle_t _tx_channel = NULL;
};

#endif

esp_dmx_transmitter.cpp

Code: Select all

#include "esp_dmx_transmitter.h"
#include "driver/gpio.h"
#include <rom/ets_sys.h>
#include <esp_log.h>
#include "soc/gpio_reg.h"

#define TAG "ESP_DMX_TRANSMITTER"

void _esp_dmx_transmitter_task(void *pvParameters) {
    ESP_Dmx_Transmitter* p_dmx_transmitter = static_cast<ESP_Dmx_Transmitter*>(pvParameters);

    while(true) {
        vTaskDelay(pdMS_TO_TICKS(25)); // 20ms delay between packets
        if(!p_dmx_transmitter->_flag_transmit) continue;
        p_dmx_transmitter->_flag_transmit = false;
        uart_port_t dmx_uart_num = p_dmx_transmitter->_dmx_uart_num;

        size_t num_symbols = 1 + 513 * 5;
        rmt_symbol_word_t *items = (rmt_symbol_word_t*)malloc(num_symbols * sizeof(rmt_symbol_word_t));

        //  first >=88us -> 0
        //  then >= 8us -> 1

        items[0].duration0 = 22;
        items[0].level0 = 0;
        items[0].duration1 = 2;
        items[0].level1 = 1;

        for(int i = 0; i < 513; i++) {
            uint16_t base_word = i * 5 + 1;
            //  each bit is 4us
            //  each message has 1 start bit (low)
            //  each message has 2 stop bits (high)
            //  each message (8 bits) goes from LSB to MSB

            //  first word has start bit and bit 7 - 0
            //  2nd word has bit 7 - 1 and bit 7 - 2
            //  3rd word has bit 7 - 3 and bit 7 - 4
            //  4th word has bit 7 - 5 and bit 7 - 6
            //  8th word has bit 7 - 7 and two stop bits
            //  5 words
            uint8_t byte = p_dmx_transmitter->_dmx_buffer[i];
            items[base_word].duration0 = 1;
            items[base_word].level0 = 0;
            items[base_word].duration1 = 1;
            items[base_word].level1 = (byte & 0x01) ? 1 : 0;

            for(int i = 1; i < 5; i++) {
                byte >>= 1;
                items[base_word + i].duration0 = 1;
                items[base_word + i].level0 = (byte & 0x01) ? 1 : 0;
                byte >>= 1;
                items[base_word + i].duration1 = 1;
                items[base_word + i].level1 = (byte & 0x01) ? 1 : 0;
            }

            byte >>= 1;
            items[base_word + 4].duration0 = 1;
            items[base_word + 4].level0 = (byte & 0x01) ? 1 : 0;
            items[base_word + 4].duration1 = 2;
            items[base_word + 4].level1 = 1;

        }

        ESP_ERROR_CHECK(
            rmt_transmit(
                p_dmx_transmitter->_tx_channel,
                p_dmx_transmitter->_copy_encoder,
                items,
                num_symbols,
                &p_dmx_transmitter->_tx_config
            )
        );
        rmt_tx_wait_all_done(p_dmx_transmitter->_tx_channel, portMAX_DELAY);
        free(items);
    }
}

void ESP_Dmx_Transmitter::init() {

    rmt_tx_channel_config_t tx_chan_config = {
        .gpio_num = GPIO_NUM_16,
        .clk_src = RMT_CLK_SRC_APB, // Use the default clock source (usually APB)
        .resolution_hz = 250000, // 1 MHz resolution, 1 tick = 1 microsecond
        .mem_block_symbols = 512, // Memory block size
        .trans_queue_depth = 4,          // set the number of transactions that can pend in the background
        .intr_priority = 0,
        .flags = {
            .invert_out = false,
            .with_dma = true,  
            .io_loop_back = false,
            .io_od_mode = true,
            .allow_pd = false
        }
    };

    ESP_ERROR_CHECK(rmt_new_tx_channel(&tx_chan_config, &_tx_channel));

    ESP_ERROR_CHECK(rmt_enable(_tx_channel));

    ESP_ERROR_CHECK(rmt_new_copy_encoder(&_copy_encoder_config, &_copy_encoder));

    for(int i = 0; i < 513; i++) {
        _dmx_buffer[i] = i; // or fill with channel values
    }

    xTaskCreate(
        _esp_dmx_transmitter_task, 
        "_esp_dmx_transmitter_task", 
        4096, 
        this,
        10,
        NULL
    );
    
}

void ESP_Dmx_Transmitter::transmit() {
    while(_flag_transmit == true) {
        vTaskDelay(pdMS_TO_TICKS(1));
    }
    _flag_transmit = true;
}

Who is online

Users browsing this forum: Barkrowler, meta-externalagent, Semrush [Bot] and 3 guests