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.
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.
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
#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
#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
#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
#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
#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;
}

