I've noticed that when the total cycle duration is too short, the system is unstable (perhaps due to a flood of interrupts), so for high-frequency generation I use a multiple number of items (all set identically except the last that needs to be one cycle shorter duration for a perfect loop). Let's say 16 items provides sufficient stability.
My understanding is that the following two configurations should produce the same result on the configured GPIO.
Configuration 1, using the APB clock at 80MHz divided by 40, wait 1 cycle per half-wave, to generate 1 MHz square wave:
Code: Select all
// pseudocode
Set .clk_div=40
For items 1-15:
.level0 = 1
.duration0 = 1
.level1 = 0
.duration1 = 1
For item 16:
.level0 = 1
.duration0 = 1
.level1 = 0
.duration1 = 0
Code: Select all
// pseudocode
Set .clk_div=1
For items 1-15:
.level0 = 1
.duration0 = 40
.level1 = 0
.duration1 = 40
For item 16:
.level0 = 1
.duration0 = 40
.level1 = 0
.duration1 = 39
However Configuration 2 does not produce the expected signal (after some toggling it stays idle), and it also does not loop.
What might account for this behaviour?
Code: Select all
void rmt_task(void * pvParameter)
{
// Configuration 1
uint8_t clock_divider = 40;
uint32_t high_count = 1;
uint32_t low_count = 1;
// Configuration 2
// uint8_t clock_divider = 1;
// uint32_t high_count = 40;
// uint32_t low_count = 40;
rmt_config_t rmt_tx = {
.rmt_mode = RMT_MODE_TX,
.channel = RMT_CHANNEL_0,
.gpio_num = GPIO_NUM_4,
.mem_block_num = 1,
.clk_div = clock_divider,
.tx_config.loop_en = true,
.tx_config.carrier_en = false,
.tx_config.idle_level = RMT_IDLE_LEVEL_LOW,
.tx_config.idle_output_en = true,
};
rmt_config(&rmt_tx);
rmt_driver_install(rmt_tx.channel, 0, 0);
size_t num_items = 16;
rmt_item32_t * items = calloc(num_items, sizeof(*items));
for (size_t i = 0; i < num_items; ++i)
{
items[i].level0 = 1;
items[i].duration0 = high_count;
items[i].level1 = 0;
items[i].duration1 = low_count;
}
// shorten final item to accommodate final idle period
--items[num_items - 1].duration1;
rmt_write_items(rmt_tx.channel, items, num_items, false);
while(1)
{
vTaskDelay(1);
}
}
EDIT: a divider of 13 with high/low counts of 40 does loop correctly. A divider of 12 does not.
div 13, high 1, low 1 produces 3.08 MHz.
div 12, high 1, low 1 does not loop.