RMT Peripheral to send a variable number of pulses continuously
Posted: Wed Jan 10, 2024 1:16 pm
Hi guys,
I am tinkering around with the rmt peripheral and understand it is an amazing tool to generate complex and changing waveform overtime. I need to generate a certain amount of pulses over a GPIO that I would like to vary in terms of number of pulses, frequency and duty cycle. Here is my current code :
Basically what I do is configure the RMT to use a carrier . The carrier is where I define my frequency and duty cycle. I then write an item whose duration allows me to get the number of pulses I would like. Basically, I see it that the item I write is a mask that will ultimately get me the number of pulses I wish for. It works quite well and allows me to have a dynamic number of pulses. However I have two main issues :
1- Sometimes, I can get one more pulse and the one at the beginning and at the end of my wave of pulses are no longer of the width I look for . This tells me my item is not synchronized with the rising edge of my carrier and so my method of masking does not work.
2- When I run the code above, I expect to continuously send a wave of 5 pulses and expect each wave of 5 pulses to have a different duty cycle. The problem is that I have a huge delay between two successive waves that varies between 20 microseconds to 40 microseconds. How can I make it so that this delay is minimized. Ideally, I would like the waves to be sent successively almost indistinguishable from a non interrupted PWM. Is that possible ?
You can see below both problems (supposed to be 5 pulses at 50% duty cycle 120 kHz followed by 5 pulses at 10% duty cycle 120kHz) :
My biggest problem really is the point number 2 because I really cannot afford 20 microseconds of delay in between two consecutive waves of pulses.
Thanks in advance
I am tinkering around with the rmt peripheral and understand it is an amazing tool to generate complex and changing waveform overtime. I need to generate a certain amount of pulses over a GPIO that I would like to vary in terms of number of pulses, frequency and duty cycle. Here is my current code :
Code: Select all
#include <Arduino.h>
#include <driver/rmt.h>
// RMT configuration parameters
#define RMT_TX_CHANNEL RMT_CHANNEL_0 // RMT channel for transmitter
#define RMT_TX_GPIO_NUM 4 // GPIO number for transmitter signal
#define RMT_CLK_DIV 4 // Clock divider for RMT
#define RMT_BASE_CLK 80000000 // Base clock frequency in Hz (typically 80 MHz for ESP32)
#define CARRIER_FREQ_HZ 120000 // Carrier frequency in Hz
#define CARRIER_DUTY_PERCENT 30 // Carrier duty cycle in percent
// Calculated RMT ticks for a period of the carrier frequency
uint32_t rmt_tick_period =(RMT_BASE_CLK / RMT_CLK_DIV / CARRIER_FREQ_HZ);
rmt_config_t rmt_tx_config = {};
volatile bool tx_complete = true;
rmt_isr_handle_t my_rmt_isr_handle;
rmt_item32_t item;
uint8_t counter=0;
uint8_t desired_duty[3]={50,10,1};
void setup() {
Serial.begin(115200);
rmt_tx_config.channel = RMT_TX_CHANNEL;
rmt_tx_config.gpio_num = (gpio_num_t)RMT_TX_GPIO_NUM;
rmt_tx_config.mem_block_num = 4;
rmt_tx_config.clk_div = RMT_CLK_DIV;
rmt_tx_config.rmt_mode = RMT_MODE_TX;
rmt_tx_config.tx_config.loop_en = false;
rmt_tx_config.tx_config.carrier_en = true;
rmt_tx_config.tx_config.carrier_freq_hz = CARRIER_FREQ_HZ; // Carrier frequency
rmt_tx_config.tx_config.carrier_duty_percent = CARRIER_DUTY_PERCENT; // Duty cycle
rmt_tx_config.tx_config.carrier_level = RMT_CARRIER_LEVEL_HIGH;
rmt_tx_config.tx_config.idle_level = RMT_IDLE_LEVEL_LOW;
rmt_tx_config.tx_config.idle_output_en = true;
// Install RMT driver
rmt_config(&rmt_tx_config);
rmt_driver_install(rmt_tx_config.channel, 0, 0);
rmt_register_tx_end_callback(rmt_tx_end_callback, NULL);
}
void loop() {
if(tx_complete){
sendPulses(5,CARRIER_FREQ_HZ,desired_duty[counter]);
counter++;
if(counter==3)
counter=0;
}
}
static void rmt_tx_end_callback(rmt_channel_t channel, void *arg) {
tx_complete=true;
}
void sendPulses(uint32_t numPulses,uint32_t freq, uint8_t duty_percent) {
rmt_tx_config.tx_config.carrier_duty_percent = duty_percent; // Duty cycle
rmt_tx_config.tx_config.carrier_freq_hz = freq; // Carrier frequency
rmt_tick_period =(RMT_BASE_CLK / RMT_CLK_DIV / freq);
rmt_config(&rmt_tx_config);
tx_complete=false;
item.level0 = 1; // High: Enable carrier signal
item.duration0 = (rmt_tick_period) * (numPulses); // Duration of all pulses
item.level1 = 0; // Low: Disable carrier signal
item.duration1 = 0; // Duration for signal to be off
rmt_write_items(RMT_TX_CHANNEL, &item, 1, false);
}
1- Sometimes, I can get one more pulse and the one at the beginning and at the end of my wave of pulses are no longer of the width I look for . This tells me my item is not synchronized with the rising edge of my carrier and so my method of masking does not work.
2- When I run the code above, I expect to continuously send a wave of 5 pulses and expect each wave of 5 pulses to have a different duty cycle. The problem is that I have a huge delay between two successive waves that varies between 20 microseconds to 40 microseconds. How can I make it so that this delay is minimized. Ideally, I would like the waves to be sent successively almost indistinguishable from a non interrupted PWM. Is that possible ?
You can see below both problems (supposed to be 5 pulses at 50% duty cycle 120 kHz followed by 5 pulses at 10% duty cycle 120kHz) :
My biggest problem really is the point number 2 because I really cannot afford 20 microseconds of delay in between two consecutive waves of pulses.
Thanks in advance