ESP32 Thing SparkFun RMT Pulse Generator 4 Channels Jitter 100ns
Posted: Sun Mar 21, 2021 2:21 pm
Hello
I'm programming with the Arduino IDE and hardware "ESP32 Thing with set to 80Mhz" from SparkFun.
My target application is a Pulse Generator for 4 Channels with low (no) Jitter.
See the following example code:
The code can be uploaded with the Arduino IDE (you have to download also the "driver/rmt.h" file and store it in a folder "driver" in the same project.
The example code configures 4 RMA channels each channel has a different GPIO PIN (16,17,18,19) used to output the synced pulses.
You can check the PINS with a 2 CH oscilloscope.
For repetitive testing I added a PWM which creates a 10 Hz repetition which triggers the RMA cycle.
The code works great!
But I get a Jitter from first RMT channel to the last channel of about 100ns. I would like to eliminate this too.
It would be intrestion to see this code working on a esp32-s3 with 240 Mhz compared tith the 80Mhz does in this case the jitter (delay) result in about 25ns?
I checked the architecture of the RMT but did only find enable signals per channel.
I start the 4 channels one after other with the following code lines. I believe I get some code execution delay from first line to the second or last line which creates this jitter of 100ns. (Maybe its the time to set the bit in the register)
At first I did use the command rmt_tx_start(RMT_CHANNEL_0, false); but with tis the jitter was even bigger and this makes also in my opinion sense.
Does somebody have a solution to hold the transmission of each RMT channel until a global bit /register or clock has been activated?
Is there a easy solution with a mentioned carrier CLK?
Thank for you Help!
I'm programming with the Arduino IDE and hardware "ESP32 Thing with set to 80Mhz" from SparkFun.
My target application is a Pulse Generator for 4 Channels with low (no) Jitter.
See the following example code:
The code can be uploaded with the Arduino IDE (you have to download also the "driver/rmt.h" file and store it in a folder "driver" in the same project.
The example code configures 4 RMA channels each channel has a different GPIO PIN (16,17,18,19) used to output the synced pulses.
You can check the PINS with a 2 CH oscilloscope.
For repetitive testing I added a PWM which creates a 10 Hz repetition which triggers the RMA cycle.
The code works great!
But I get a Jitter from first RMT channel to the last channel of about 100ns. I would like to eliminate this too.
It would be intrestion to see this code working on a esp32-s3 with 240 Mhz compared tith the 80Mhz does in this case the jitter (delay) result in about 25ns?
I checked the architecture of the RMT but did only find enable signals per channel.
I start the 4 channels one after other with the following code lines. I believe I get some code execution delay from first line to the second or last line which creates this jitter of 100ns. (Maybe its the time to set the bit in the register)
Code: Select all
REG_SET_BIT(RMT_CH0CONF1_REG, RMT_TX_START_CH0);
REG_SET_BIT(RMT_CH1CONF1_REG, RMT_TX_START_CH1);
REG_SET_BIT(RMT_CH2CONF1_REG, RMT_TX_START_CH2);
REG_SET_BIT(RMT_CH3CONF1_REG, RMT_TX_START_CH3);
Does somebody have a solution to hold the transmission of each RMT channel until a global bit /register or clock has been activated?
Is there a easy solution with a mentioned carrier CLK?
Thank for you Help!
Code: Select all
#include <driver/rmt.h>
// the number of the LED pin
const int ledPin = 16; // 16 corresponds to GPIO16
// use first channel of 16 channels (started from zero)
#define LEDC_CHANNEL_0 0
// use 13 bit precission for LEDC timer
#define LEDC_TIMER_13_BIT 13
// use 5000 Hz as a LEDC base frequency
#define LEDC_BASE_FREQ 10
// fade LED PIN (replace with LED_BUILTIN constant for built-in LED)
#define LED_PIN LED_BUILTIN
int brightness = 0; // how bright the LED is
int fadeAmount = 5; // how many points to fade the LED by
// Reference https://esp-idf.readthedocs.io/en/v1.0/api/rmt.html
// Arduino like analogWrite
// value has to be between 0 and valueMax
void ledcAnalogWrite(uint8_t channel, uint32_t value, uint32_t valueMax = 255) {
// calculate duty, 8191 from 2 ^ 13 - 1
uint32_t duty = (8191 / valueMax) * min(value, valueMax);
// write duty to LEDC
ledcWrite(channel, duty);
}
struct Button {
const uint8_t PIN;
uint32_t numberKeyPresses;
bool pressed;
};
Button button1 = {0, 0, false};
void IRAM_ATTR isr() {
button1.numberKeyPresses += 1;
button1.pressed = true;
}
rmt_config_t configA;
rmt_item32_t itemsA[3];
rmt_config_t configB;
rmt_item32_t itemsB[3];
rmt_config_t configC;
rmt_item32_t itemsC[3];
rmt_config_t configD;
rmt_item32_t itemsD[3];
void setup() {
Serial.begin(115200);
pinMode(button1.PIN, INPUT_PULLUP);
attachInterrupt(button1.PIN, isr, FALLING);
// Setup timer and attach timer to a led pin
ledcSetup(LEDC_CHANNEL_0, LEDC_BASE_FREQ, LEDC_TIMER_13_BIT);
ledcAttachPin(LED_PIN, LEDC_CHANNEL_0);
// put your setup code here, to run once:
configA.rmt_mode = RMT_MODE_TX;
configA.channel = RMT_CHANNEL_0;
configA.gpio_num = GPIO_NUM_16;
configA.mem_block_num = 1;
configA.tx_config.loop_en = 0;
configA.tx_config.carrier_en = 0;
configA.tx_config.idle_output_en = 1;
configA.tx_config.idle_level = RMT_IDLE_LEVEL_LOW;
configA.tx_config.carrier_level = RMT_CARRIER_LEVEL_HIGH;
configA.clk_div = 80; // 80MHx / 80 = 1MHz 0r 1uS per count
rmt_config(&configA);
rmt_driver_install(RMT_CHANNEL_0, 0, 0); // rmt_driver_install(rmt_channel_t channel, size_t rx_buf_size, int rmt_intr_num)
// put your setup code here, to run once:
configB.rmt_mode = RMT_MODE_TX;
configB.channel = RMT_CHANNEL_1;
configB.gpio_num = GPIO_NUM_17;
configB.mem_block_num = 1;
configB.tx_config.loop_en = 0;
configB.tx_config.carrier_en = 0;
configB.tx_config.idle_output_en = 1;
configB.tx_config.idle_level = RMT_IDLE_LEVEL_LOW;
configB.tx_config.carrier_level = RMT_CARRIER_LEVEL_HIGH;
configB.clk_div = 80; // 80MHx / 80 = 1MHz 0r 1uS per count
rmt_config(&configB);
rmt_driver_install(RMT_CHANNEL_1, 0, 0); // rmt_driver_install(rmt_channel_t channel, size_t rx_buf_size, int rmt_intr_num)
// put your setup code here, to run once:
configC.rmt_mode = RMT_MODE_TX;
configC.channel = RMT_CHANNEL_2;
configC.gpio_num = GPIO_NUM_18;
configC.mem_block_num = 1;
configC.tx_config.loop_en = 0;
configC.tx_config.carrier_en = 0;
configC.tx_config.idle_output_en = 1;
configC.tx_config.idle_level = RMT_IDLE_LEVEL_LOW;
configC.tx_config.carrier_level = RMT_CARRIER_LEVEL_HIGH;
configC.clk_div = 80; // 80MHx / 80 = 1MHz 0r 1uS per count
rmt_config(&configC);
rmt_driver_install(RMT_CHANNEL_2, 0, 0); // rmt_driver_install(rmt_channel_t channel, size_t rx_buf_size, int rmt_intr_num)
// put your setup code here, to run once:
configD.rmt_mode = RMT_MODE_TX;
configD.channel = RMT_CHANNEL_3;
configD.gpio_num = GPIO_NUM_19;
configD.mem_block_num = 1;
configD.tx_config.loop_en = 0;
configD.tx_config.carrier_en = 0;
configD.tx_config.idle_output_en = 1;
configD.tx_config.idle_level = RMT_IDLE_LEVEL_LOW;
configD.tx_config.carrier_level = RMT_CARRIER_LEVEL_HIGH;
configD.clk_div = 80; // 80MHx / 80 = 1MHz 0r 1uS per count
rmt_config(&configD);
rmt_driver_install(RMT_CHANNEL_3, 0, 0); // rmt_driver_install(rmt_channel_t channel, size_t rx_buf_size, int rmt_intr_num)
itemsA[0].duration0 = 100;
itemsA[0].level0 = 1;
itemsA[0].duration1 = 200;
itemsA[0].level1 = 0;
itemsA[1].duration0 = 100;
itemsA[1].level0 = 0;
itemsA[1].duration1 = 50;
itemsA[1].level1 = 0;
itemsA[2].duration0 = 10;
itemsA[2].level0 = 0;
itemsA[2].duration1 = 0;
itemsA[2].level1 = 0;
itemsB[0].duration0 = 100;
itemsB[0].level0 = 0;
itemsB[0].duration1 = 200;
itemsB[0].level1 = 0;
itemsB[1].duration0 = 100;
itemsB[1].level0 = 0;
itemsB[1].duration1 = 50;
itemsB[1].level1 = 0;
itemsB[2].duration0 = 10;
itemsB[2].level0 = 0;
itemsB[2].duration1 = 0;
itemsB[2].level1 = 0;
itemsC[0].duration0 = 100;
itemsC[0].level0 = 0;
itemsC[0].duration1 = 200;
itemsC[0].level1 = 0;
itemsC[1].duration0 = 100;
itemsC[1].level0 = 0;
itemsC[1].duration1 = 50;
itemsC[1].level1 = 0;
itemsC[2].duration0 = 10;
itemsC[2].level0 = 0;
itemsC[2].duration1 = 0;
itemsC[2].level1 = 0;
itemsD[0].duration0 = 100;
itemsD[0].level0 = 0;
itemsD[0].duration1 = 200;
itemsD[0].level1 = 0;
itemsD[1].duration0 = 100;
itemsD[1].level0 = 1;
itemsD[1].duration1 = 10;
itemsD[1].level1 = 0;
itemsD[2].duration0 = 0;
itemsD[2].level0 = 0;
itemsD[2].duration1 = 0;
itemsD[2].level1 = 0;
rmt_fill_tx_items(RMT_CHANNEL_0,itemsA,3,0);
rmt_fill_tx_items(RMT_CHANNEL_1,itemsB,3,0);
rmt_fill_tx_items(RMT_CHANNEL_2,itemsC,3,0);
rmt_fill_tx_items(RMT_CHANNEL_3,itemsD,3,0);
}
void loop() {
if (button1.pressed) {
Serial.printf("Button 1 has been pressed %u times\n", button1.numberKeyPresses);
button1.pressed = false;
// esp_err_t rmt_write_items(rmt_channel_t channel, rmt_item32_t *rmt_item, int item_num, bool wait_tx_done)
//rmt_tx_start(RMT_CHANNEL_0, false);
//rmt_tx_start(RMT_CHANNEL_1, false);
REG_SET_BIT(RMT_CH0CONF1_REG, RMT_TX_START_CH0);
REG_SET_BIT(RMT_CH1CONF1_REG, RMT_TX_START_CH1);
REG_SET_BIT(RMT_CH2CONF1_REG, RMT_TX_START_CH2);
REG_SET_BIT(RMT_CH3CONF1_REG, RMT_TX_START_CH3);
}
// set the brightness on LEDC channel 0
ledcAnalogWrite(LEDC_CHANNEL_0, 1);
// rmt_write_items(RMT_CHANNEL_0, items, 2, 0);
// rmt_write_items(RMT_CHANNEL_1, itemsA, 2, 0);
delay(10);
}