Every 5 to 100 seconds the RMT output seems to miss a tick/beat or show some other glitch:
Below is a simplified example which still exhibits the issue. The code outputs simply 13 1's and then 13 0's within 400 RMT items; these are managed in typical 'double buffer' style.
Does this ring a bell with anyone ? I was assuming the RTM to be totally hardware based and essentially un-fased by anything happening elsewhere (and in the example below - loop() is empty; there is no WiFi -- and I still see the glitches).
Note that running it contineously without any refresh works fine; and that the digitalWrite() in the IRQ shows it getting called regularly at a steady clip.
Suggestions how to get to the bottom of this appreciated.
Dw.
Code: Select all
/* Simple 'RMT' example which uses a 'double buffering' method
* to populate the other buffer once it starts on the second one.
*
* (c) Copyright 2018 Dirk-Willem van Gulik - All rights reserved.
* Under the Apache Software License version 2.0.
*/
#include "driver/rmt.h"
#include "driver/gpio.h"
#include "esp_log.h"
#define RMT_TX_CHANNEL (RMT_CHANNEL_0)
#define RMT_TX_GPIO (GPIO_NUM_5)
// Lenght of 1's or 0's to emit until toggling to the other.
//
#define RUNLENGTH (13)
// Number of bits in our buffer -
#define ITEM_CNT_HALF (200)
#if ITEM_CNT_HALF*2 > 512
#error Only 512 rmt_item32 items for both our buffers.
#endif
// Our run spans multiple bottom/top halfs; so we keep a global counter./
static unsigned roll = 0;
// Keep track of wether we do the top of bottom half.
//
static unsigned int at = 0;
void IRAM_ATTR rmt_isr_handler(void *arg) {
RMT.int_clr.ch0_tx_thr_event = 1;
fillTopOrBottomHalf();
}
void setup() {
rmt_config_t config;
pinMode(RMT_TX_GPIO, OUTPUT);
config.rmt_mode = RMT_MODE_TX;
config.channel = RMT_TX_CHANNEL;
config.gpio_num = RMT_TX_GPIO;
config.mem_block_num = ((ITEM_CNT_HALF*2) / 64 + 1);
config.clk_div = 1;
config.tx_config.loop_en = 1;
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;
ESP_ERROR_CHECK(rmt_config(&config));
ESP_ERROR_CHECK(rmt_set_source_clk(RMT_TX_CHANNEL, RMT_BASECLK_APB)); // 80 Mhz.
ESP_ERROR_CHECK(rmt_isr_register(rmt_isr_handler, NULL, ESP_INTR_FLAG_LEVEL1, 0));
// Fill the entire block with 'end of block' markers.
for (int i = 0; i < config.mem_block_num; i++)
for (int j = 0 ; j < 64; j++)
RMTMEM.chan[RMT_TX_CHANNEL + i ].data32[j].val = 0;
fillTopOrBottomHalf();
fillTopOrBottomHalf();
/* Trigger the interupt every ITEM_CNT_HALF entries; i.e. at the start of the second block
* or the start of the first block - while the other is getting sent out.
*/
ESP_ERROR_CHECK(rmt_set_tx_thr_intr_en(RMT_TX_CHANNEL, true, ITEM_CNT_HALF));
ESP_ERROR_CHECK(rmt_tx_start(RMT_TX_CHANNEL, true));
}
void fillTopOrBottomHalf()
{
// specify which half we do; top or bottom.
//
if (at == ITEM_CNT_HALF) at = 0; else at = ITEM_CNT_HALF;
for (int i = 0; i < ITEM_CNT_HALF; i++) {
unsigned char level1 = 0 , level2 = 0;
if (roll < RUNLENGTH) level1 = 1;
roll++;
if (roll >= RUNLENGTH*2) roll = 0;
if (roll < RUNLENGTH) level2 = 1;
roll++;
if (roll >= RUNLENGTH*2) roll = 0;
rmt_item32_t w = {{{ 400, level1, 400, level2 }}};
RMTMEM.chan[RMT_TX_CHANNEL].data32[at + i].val = w.val;
}
}
void loop() {
}