RMT IR Rx - Processing Ring buffer takes 1000ms each cycle even when empty

bobslawblog
Posts: 11
Joined: Sun Dec 12, 2021 4:55 pm

RMT IR Rx - Processing Ring buffer takes 1000ms each cycle even when empty

Postby bobslawblog » Sun Dec 12, 2021 5:11 pm

I am using the RMT library to process both IR Tx (Channel 0) and Rx (Channel 1). Initially on one channel each but I plan to add more channels once I am comfortable with the performance.

I am not getting any error codes on install or run. The solution seems to be working. but it is dog slow and I haven't incorporated the other receive channels and features I would like to include in this project. Before proceeding I want to make sure the performance issue is resolved with this ring buffer parsing process.

The library seems to be working and I am successfully parsing data between my ESP32 solutions. However, my routine for processing the data in the ring buffer is taking 1000ms each cycle to complete and this is when no IR data is being sent.

My RX Config:
#define HEADER_US 2400 // Header is 2400 µS
#define SPACE_US 600 // Space between bits is 600 µS
#define ONE_US 1200 // Logic 1 is 12 µS
#define ZERO_US 600 // Logic 0 is 600 µS
#define OFFSET 100

Code: Select all

configRx.rmt_mode = RMT_MODE_RX;
  configRx.channel = RMT_CHANNEL_1;
  configRx.gpio_num = REC_PIN;
  configRx.mem_block_num = 1;
  configRx.rx_config.filter_en = true;
  configRx.rx_config.filter_ticks_thresh = 200;
  configRx.rx_config.idle_threshold = HEADER_US + OFFSET;
  configRx.clk_div = 80; // 80MHx / 80 = 1MHz 0r 1uS per count
My install completes once via setup

Code: Select all

// install the driver
    esp_err_t rmt_driver_install_result = rmt_driver_install(RMT_CHANNEL_1, 1000, 0);
    log_e("rmt_driver_install_result: %s", esp_err_to_name(rmt_driver_install_result));

     rmt_rx_start(RMT_CHANNEL_1, true);
Here is my procedure that seems to take 1000ms each cycle to process the buffer. This is called from the loop() function each cycle. My assumption is that when the ring buffer is empty this would just skip processing and move on. I based this heavily from example code found in the guidance.

Code: Select all

void MyRX::BufferPull() {
  unsigned long data = 0;
  RingbufHandle_t rb = NULL;
  rmt_get_ringbuf_handle(RMT_CHANNEL_1, &rb);

    while(rb) {
      size_t rx_size = 0;
      rmt_item32_t* item = (rmt_item32_t*) xRingbufferReceive(rb, &rx_size, 1000);
      if (item) {
        rmt_item32_t* itemproc = item;
        for(size_t i=0; i < (rx_size / 4); i++) {
          if(itemproc->duration0 < (HEADER_US+OFFSET) && itemproc->duration0 > (HEADER_US-OFFSET)) {
            for(int i=14; i >= 1; i--) {
              if (itemproc[i].duration0 < (ONE_US+OFFSET) && itemproc[i].duration0 > (ONE_US-OFFSET)) {
                data = data | 1 << (14 - i);
              } else if(itemproc[i].duration0 < (ZERO_US+OFFSET) && itemproc[i].duration0 > (ZERO_US-OFFSET)) {
                data = data | 0 << (14 - i);
              }
            }
            DataArray[RecordCount] = DecodeData(data);
            RecordCount++;
            data = 0;
          }
          ++itemproc;
        }
        vRingbufferReturnItem(rb, (void*) item);
      } else {
        break;
      }
    }
}
I am using the default ISR with the RMT. I can't seem to figure out what is hogging all of the processing time especially since no IR is being sent and I am still seeing 1000ms processing time for this procedure.

How do I know it is taking this long to run this process? I am taking a millis() comparison before and after running the bufferpull procedure and the result is showing 1000ms at the serial terminal.

Thanks in advance for any hints as to what I might be doing wrong.

ESP_Sprite
Posts: 9770
Joined: Thu Nov 26, 2015 4:08 am

Re: RMT IR Rx - Processing Ring buffer takes 1000ms each cycle even when empty

Postby ESP_Sprite » Mon Dec 13, 2021 1:35 am

bobslawblog wrote:
Sun Dec 12, 2021 5:11 pm
My assumption is that when the ring buffer is empty this would just skip processing and move on.
That's great foreshadowing :P

Code: Select all

      rmt_item32_t* item = (rmt_item32_t*) xRingbufferReceive(rb, &rx_size, 1000);
From the docs:
void *xRingbufferReceive(RingbufHandle_t xRingbuffer, size_t *pxItemSize, TickType_t xTicksToWait)

Retrieve an item from the ring buffer.

Attempt to retrieve an item from the ring buffer. This function will block until an item is available or until it times out.
You'll likely get the behaviour you want by setting that timeout to 0.

bobslawblog
Posts: 11
Joined: Sun Dec 12, 2021 4:55 pm

Re: RMT IR Rx - Processing Ring buffer takes 1000ms each cycle even when empty

Postby bobslawblog » Mon Dec 13, 2021 12:43 pm

Thanks so much for your response. I figured it out "sorta" right after my post. The problem was that my ring buffer size was set to "1000" so every time I saw the parameter value of "1000" in the xRingbufferReceive command I was making a bad assumption that the "1000" parameter was buffer size. In fact, it is a parameter to block for 1000 ticks awaiting data from the ring buffer before moving on. My clock divider is set to 80 which means a value of 1000 ticks is...... 1000ms which is exactly how long I was seeing as a delay (imagine that!).

I reduced the blocking value down to 50 ticks and my program ran much faster with no performance issues receiving the IR codes. I don't see why I should have to wait for data at all when polling the ring buffer. If the buffer is empty, I would rather just move on and not block processing. I will experiment with this setting but it does bring up a couple of follow on questions:

1) Any reason I shouldn't run this code with the value set to "0" ticks?

2) By setting the value to 0 would a race condition be a concern in the situation where the code happens to be reading from the ring buffer at the same time it is receiving data and being filled by the ISR? Does the ISR finish populating an "item" before releasing the blocking?

3) Should I have a few ticks of blocking (5-10) just to make sure the buffer is not in the middle of being populated?

ESP_Sprite
Posts: 9770
Joined: Thu Nov 26, 2015 4:08 am

Re: RMT IR Rx - Processing Ring buffer takes 1000ms each cycle even when empty

Postby ESP_Sprite » Tue Dec 14, 2021 1:53 am

Yeah, as I said in the previous response, you probably want to set that timeout to 0. It won't have any multithreading consequences; the ringbuffer (in the way used by RMT) takes care not to return any data before it's all written. My guess is that the example you cribbed the code from has a timeout because it doesn't really do anything else in the loop and it's bad form to simply sit in a tight loop to poll the hardware.

Who is online

Users browsing this forum: No registered users and 58 guests