Description
Hardware:
Board: ESP32 Dev Module
Core Installation version: 1.0.2 (latest public release)
IDE name: Arduino IDE
Flash Frequency: 40Mhz (default)
PSRAM enabled: no (default)
Upload Speed: 921600 (default)
Computer OS: Windows 10
Description:
When using the rmt_write_sample
, with no wait (async) with all 8 channels, the last few channels have significant delay before the pulses are started.
Channel 5 has a 1.5ms stagger from the first, which is significant from the first four.
Channel 6 has a 14.5ms stagger from the first (as captured above as dx field), which seems way out of reasonability. This seems related to a channel buffer becoming available. The timing shows that while the last pulse of channel 0 is still presently being sent, it is just sending the extended low side of the last pulse; so it will not be calling translate again for that channel; seemingly making it available to start sending channel 6.
Sketch:
extern "C"
{
#include <driver/rmt.h>
}
const size_t dataSize = 1500;
uint8_t* data;
// selected to be in order on the board for easy connection of the
// logic analyser
const uint8_t ChannelPins[] = {19, 18, 5, 17, 16, 4, 2, 15};
static void IRAM_ATTR _translate(const void* src,
rmt_item32_t* dest,
size_t src_size,
size_t wanted_num,
size_t* translated_size,
size_t* item_num) {
if (src == NULL || dest == NULL) {
*translated_size = 0;
*item_num = 0;
return;
}
size_t size = 0;
size_t num = 0;
uint8_t *psrc = (uint8_t *)src;
rmt_item32_t* pdest = dest;
for (;;) {
uint8_t data = *psrc;
// convert a byte into rmt item timing
// zero bit pulse = 200ns 1000ns = 8 cycles 40 cycles = 0x0028 8008 as rmt item val
// one bit pulse = 1000ns 200ns = 40 cycles 8 cycles = 0x0008 8028 as rmt item val
for (uint8_t bit = 0; bit < 8; bit++) {
pdest->val = (data & 0x80) ? 0x00088028 : 0x00288008;
pdest++;
data <<= 1;
}
num += 8;
size++;
// if this is the last byte we need to adjust the length of the last pulse
if (size >= src_size) {
// extend the last bits LOW value to include the full reset signal length
pdest--;
pdest->duration1 = 20000; // 500us reset
// and stop updating data to send
break;
}
if (num >= wanted_num) {
// stop updating data to send
break;
}
psrc++;
}
*translated_size = size;
*item_num = num;
}
void initChannel(rmt_channel_t ch, gpio_num_t pin) {
rmt_config_t config;
config.rmt_mode = RMT_MODE_TX;
config.channel = ch;
config.gpio_num = pin;
config.mem_block_num = 1;
config.tx_config.loop_en = false;
config.tx_config.idle_output_en = true;
config.tx_config.idle_level = RMT_IDLE_LEVEL_LOW;
config.tx_config.carrier_en = false;
config.tx_config.carrier_level = RMT_CARRIER_LEVEL_LOW;
config.clk_div = 2;
rmt_config(&config);
rmt_driver_install(ch, 0, 0);
rmt_translator_init(ch, _translate);
}
void writeChannel(rmt_channel_t ch) {
// wait for the last send to complete
if (ESP_OK == rmt_wait_tx_done(ch, 10000 / portTICK_PERIOD_MS)) {
// then start a new async send
rmt_write_sample(ch, data, dataSize, false);
}
}
void waitForAllDone()
{
bool done = false;
while (!done) {
done = true;
for (uint8_t ch = 0; ch < RMT_CHANNEL_MAX; ch++) {
if (ESP_OK != rmt_wait_tx_done(static_cast<rmt_channel_t>(ch), 0)) {
done = false;
yield();
break;
}
}
}
}
void setup() {
data = (uint8_t*)malloc(dataSize);
memset(data, 0x00, dataSize);
for (uint8_t ch = 0; ch < RMT_CHANNEL_MAX; ch++) {
initChannel(static_cast<rmt_channel_t>(ch), static_cast<gpio_num_t>(ChannelPins[ch]));
}
}
void loop() {
// start all channels, then wait for them to be sent, then start all channels again
//
for (uint8_t ch = 0; ch < RMT_CHANNEL_MAX; ch++) {
writeChannel(static_cast<rmt_channel_t>(ch));
}
waitForAllDone();
for (uint8_t ch = 0; ch < RMT_CHANNEL_MAX; ch++) {
writeChannel(static_cast<rmt_channel_t>(ch));
}
// repeat with a long delay between so it can easily be captured in the logic analyser
//
delay(5000);
}