ESP32: Sending short pulses with the RMT

Well that was easy!  About an hour ago I wrapped up a blog post on creating stepper motor driver pulses with the ESP32 using timer interrupts. I added a to do list at the end to look into using the RMT peripheral to do this. It only took about an hour to figure out.

RMT stands for “remote control”. It was designed for things like an IR remote control where tight timing on GPIO is required. The peripheral has a lot of features that make it good for a lot of things. Some people have been using it for the notoriously tight timing of the NEO Pixels.

The documentation is pretty complete on the API, but there are very few examples and tutorials. Most that do exist are for complicated things and not too well commented. This Ebook by Neil Kolban has a good example that my code started from. Look for the section called “RMT – The Remote Peripheral”. Due to my limited knowledge of the RMT, I will only go over my implementation.

Basically you start with two structures…(also see code below)

rmt_config_t config;

This is used to setup the configuration. I set config.clk_div = 80 so that each unit of time in my setup is 1us.

rmt_item32_t items[1];

This is an array of items that represent the outputs transitions that you want. In my case I only want a transition to high for 3us and then transition to low with no duration . Here is the definition of that struct.

typedef struct {
    union {
        struct {
            uint32_t duration0 :15;
            uint32_t level0 :1;
            uint32_t duration1 :15;
            uint32_t level1 :1;
        };
        uint32_t val;
    };
} rmt_item32_t;

Here is my code. I had the pulse repeat with a 1us delay, so that is would be easy to catch some on my logic analyzer.

#include <driver/rmt>

#define STEP_PIN  GPIO_NUM_17

// Reference https://esp-idf.readthedocs.io/en/v1.0/api/rmt.html

rmt_config_t config;
rmt_item32_t items[1];



void setup() {
  // put your setup code here, to run once:
  config.rmt_mode = RMT_MODE_TX;
  config.channel = RMT_CHANNEL_0;
  config.gpio_num = STEP_PIN;
  config.mem_block_num = 1;
  config.tx_config.loop_en = 0;
  config.tx_config.carrier_en = 0;
  config.tx_config.idle_output_en = 1;
  config.tx_config.idle_level = RMT_IDLE_LEVEL_LOW;
  config.tx_config.carrier_level = RMT_CARRIER_LEVEL_HIGH;
  config.clk_div = 80; // 80MHx / 80 = 1MHz 0r 1uS per count

  rmt_config(&amp;config);
  rmt_driver_install(config.channel, 0, 0);  //  rmt_driver_install(rmt_channel_t channel, size_t rx_buf_size, int rmt_intr_num)
  
  items[0].duration0 = 3;
  items[0].level0 = 1;
  items[0].duration1 = 0;
  items[0].level1 = 0;  

}

void loop() {
  // esp_err_t rmt_write_items(rmt_channel_t channel, rmt_item32_t *rmt_item, int item_num, bool wait_tx_done)
  rmt_write_items(config.channel, items, 1, 0);
  delay(1);
  
  
}

Here is a screen shot of the output on a logic analyzer. (Step/dir signals are swapped in the labels)

Conclusion

I think this will work great. This will will be very efficient and rum completely in the background. I will definitely try to move ahead with this method.


If you want to be notified of future blog posts, please subscribe.

Share and Enjoy:
  • Print
  • Digg
  • StumbleUpon
  • del.icio.us
  • Facebook
  • Yahoo! Buzz
  • Twitter
  • Google Bookmarks
  1. No Comments

*