Page 1 of 1

RMT inconsistency when looping - no loop for low clock divider values

Posted: Sat Sep 30, 2017 11:09 pm
by meowsqueak
I am using the RMT to generate a fixed frequency square wave. I set the driver to "loop" mode by setting .tx_config.loop_en to true.

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
Configuration 2, using the APB clock at 80MHz, no divider, wait 40 cycles per half-wave, to generate 1 MHz square wave:

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
Viewing on an oscilloscope, Configuration 1 seems to work as expected.
DS1104Z_20171001-120548.png
DS1104Z_20171001-120548.png (35.66 KiB) Viewed 3727 times
However Configuration 2 does not produce the expected signal (after some toggling it stays idle), and it also does not loop.
DS1104Z_20171001-120320.png
DS1104Z_20171001-120320.png (35.35 KiB) Viewed 3727 times
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);
    }
}
Note: a divider of 40 with high/low counts of 40 does loop correctly, producing a 25kHz output.

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.

Re: RMT inconsistency when looping - no loop for low clock divider values

Posted: Sun Oct 01, 2017 2:42 am
by meowsqueak
The instability with looping seems to be related to the number of configured items within a block.

I know from a previous issue that it is important to only use the first 63 items of the 64-item block when wanting to use the looping feature. However it seems for some combinations of clock divider and pulse widths, the number of items required to be reserved is sometimes two, and in some cases even three!

I haven't been able to find a pattern to this yet, so I've limited my use of items per block to 60, and it seems to work for all combinations I've tried so far.