HC-SR04 using RMT - very fast
HC-SR04 using RMT - very fast
I was testing RMT and it turned out to be excellent tool )
Here is a code for ultrasonic sensor HC-SR04 using full hardware capabilities of ESP hardware Remote Control module
[code]
#include <stdio.h>
#include <string.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "freertos/queue.h"
#include "freertos/semphr.h"
#include "esp_err.h"
#include "esp_log.h"
#include "driver/rmt.h"
#include "driver/periph_ctrl.h"
#include "soc/rmt_reg.h"
#include <sys/time.h>
#include "driver/gpio.h"
#define RMT_TX_CHANNEL 1 /* RMT channel for transmitter */
#define RMT_TX_GPIO_NUM PIN_TRIGGER /* GPIO number for transmitter signal */
#define RMT_RX_CHANNEL 0 /* RMT channel for receiver */
#define RMT_RX_GPIO_NUM PIN_ECHO /* GPIO number for receiver */
#define RMT_CLK_DIV 100 /* RMT counter clock divider */
#define RMT_TX_CARRIER_EN 0 /* Disable carrier */
#define rmt_item32_tIMEOUT_US 9500 /*!< RMT receiver timeout value(us) */
#define RMT_TICK_10_US (80000000/RMT_CLK_DIV/100000) /* RMT counter value for 10 us.(Source clock is APB clock) */
#define ITEM_DURATION(d) ((d & 0x7fff)*10/RMT_TICK_10_US)
#define PIN_TRIGGER 18
#define PIN_ECHO 19
static void HCSR04_tx_init()
{
rmt_config_t rmt_tx;
rmt_tx.channel = RMT_TX_CHANNEL;
rmt_tx.gpio_num = RMT_TX_GPIO_NUM;
rmt_tx.mem_block_num = 1;
rmt_tx.clk_div = RMT_CLK_DIV;
rmt_tx.tx_config.loop_en = false;
rmt_tx.tx_config.carrier_duty_percent = 50;
rmt_tx.tx_config.carrier_freq_hz = 3000;
rmt_tx.tx_config.carrier_level = 1;
rmt_tx.tx_config.carrier_en = RMT_TX_CARRIER_EN;
rmt_tx.tx_config.idle_level = 0;
rmt_tx.tx_config.idle_output_en = true;
rmt_tx.rmt_mode = 0;
rmt_config(&rmt_tx);
rmt_driver_install(rmt_tx.channel, 0, 0);
}
static void HCSR04_rx_init()
{
rmt_config_t rmt_rx;
rmt_rx.channel = RMT_RX_CHANNEL;
rmt_rx.gpio_num = RMT_RX_GPIO_NUM;
rmt_rx.clk_div = RMT_CLK_DIV;
rmt_rx.mem_block_num = 1;
rmt_rx.rmt_mode = RMT_MODE_RX;
rmt_rx.rx_config.filter_en = true;
rmt_rx.rx_config.filter_ticks_thresh = 100;
rmt_rx.rx_config.idle_threshold = rmt_item32_tIMEOUT_US / 10 * (RMT_TICK_10_US);
rmt_config(&rmt_rx);
rmt_driver_install(rmt_rx.channel, 1000, 0);
}
void app_main()
{
HCSR04_tx_init();
HCSR04_rx_init();
rmt_item32_t item;
item.level0 = 1;
item.duration0 = RMT_TICK_10_US;
item.level1 = 0;
item.duration1 = RMT_TICK_10_US; // for one pulse this doesn't matter
size_t rx_size = 0;
RingbufHandle_t rb = NULL;
rmt_get_ringbuf_handle(RMT_RX_CHANNEL, &rb);
rmt_rx_start(RMT_RX_CHANNEL, 1);
double distance = 0;
for(;;)
{
rmt_write_items(RMT_TX_CHANNEL, &item, 1, true);
rmt_wait_tx_done(RMT_TX_CHANNEL, portMAX_DELAY);
rmt_item32_t* item = (rmt_item32_t*)xRingbufferReceive(rb, &rx_size, 1000);
distance = 340.29 * ITEM_DURATION(item->duration0) / (1000 * 1000 * 2); // distance in meters
printf("Distance is %f cm\n", distance * 100); // distance in centimeters
vRingbufferReturnItem(rb, (void*) item);
vTaskDelay(200 / portTICK_PERIOD_MS);
}
}
[/code]
Here is a code for ultrasonic sensor HC-SR04 using full hardware capabilities of ESP hardware Remote Control module
[code]
#include <stdio.h>
#include <string.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "freertos/queue.h"
#include "freertos/semphr.h"
#include "esp_err.h"
#include "esp_log.h"
#include "driver/rmt.h"
#include "driver/periph_ctrl.h"
#include "soc/rmt_reg.h"
#include <sys/time.h>
#include "driver/gpio.h"
#define RMT_TX_CHANNEL 1 /* RMT channel for transmitter */
#define RMT_TX_GPIO_NUM PIN_TRIGGER /* GPIO number for transmitter signal */
#define RMT_RX_CHANNEL 0 /* RMT channel for receiver */
#define RMT_RX_GPIO_NUM PIN_ECHO /* GPIO number for receiver */
#define RMT_CLK_DIV 100 /* RMT counter clock divider */
#define RMT_TX_CARRIER_EN 0 /* Disable carrier */
#define rmt_item32_tIMEOUT_US 9500 /*!< RMT receiver timeout value(us) */
#define RMT_TICK_10_US (80000000/RMT_CLK_DIV/100000) /* RMT counter value for 10 us.(Source clock is APB clock) */
#define ITEM_DURATION(d) ((d & 0x7fff)*10/RMT_TICK_10_US)
#define PIN_TRIGGER 18
#define PIN_ECHO 19
static void HCSR04_tx_init()
{
rmt_config_t rmt_tx;
rmt_tx.channel = RMT_TX_CHANNEL;
rmt_tx.gpio_num = RMT_TX_GPIO_NUM;
rmt_tx.mem_block_num = 1;
rmt_tx.clk_div = RMT_CLK_DIV;
rmt_tx.tx_config.loop_en = false;
rmt_tx.tx_config.carrier_duty_percent = 50;
rmt_tx.tx_config.carrier_freq_hz = 3000;
rmt_tx.tx_config.carrier_level = 1;
rmt_tx.tx_config.carrier_en = RMT_TX_CARRIER_EN;
rmt_tx.tx_config.idle_level = 0;
rmt_tx.tx_config.idle_output_en = true;
rmt_tx.rmt_mode = 0;
rmt_config(&rmt_tx);
rmt_driver_install(rmt_tx.channel, 0, 0);
}
static void HCSR04_rx_init()
{
rmt_config_t rmt_rx;
rmt_rx.channel = RMT_RX_CHANNEL;
rmt_rx.gpio_num = RMT_RX_GPIO_NUM;
rmt_rx.clk_div = RMT_CLK_DIV;
rmt_rx.mem_block_num = 1;
rmt_rx.rmt_mode = RMT_MODE_RX;
rmt_rx.rx_config.filter_en = true;
rmt_rx.rx_config.filter_ticks_thresh = 100;
rmt_rx.rx_config.idle_threshold = rmt_item32_tIMEOUT_US / 10 * (RMT_TICK_10_US);
rmt_config(&rmt_rx);
rmt_driver_install(rmt_rx.channel, 1000, 0);
}
void app_main()
{
HCSR04_tx_init();
HCSR04_rx_init();
rmt_item32_t item;
item.level0 = 1;
item.duration0 = RMT_TICK_10_US;
item.level1 = 0;
item.duration1 = RMT_TICK_10_US; // for one pulse this doesn't matter
size_t rx_size = 0;
RingbufHandle_t rb = NULL;
rmt_get_ringbuf_handle(RMT_RX_CHANNEL, &rb);
rmt_rx_start(RMT_RX_CHANNEL, 1);
double distance = 0;
for(;;)
{
rmt_write_items(RMT_TX_CHANNEL, &item, 1, true);
rmt_wait_tx_done(RMT_TX_CHANNEL, portMAX_DELAY);
rmt_item32_t* item = (rmt_item32_t*)xRingbufferReceive(rb, &rx_size, 1000);
distance = 340.29 * ITEM_DURATION(item->duration0) / (1000 * 1000 * 2); // distance in meters
printf("Distance is %f cm\n", distance * 100); // distance in centimeters
vRingbufferReturnItem(rb, (void*) item);
vTaskDelay(200 / portTICK_PERIOD_MS);
}
}
[/code]
-
- Posts: 1
- Joined: Wed Oct 17, 2018 4:27 pm
Re: HC-SR04 using RMT - very fast
Great Example. Thanks for sharing !
Re: HC-SR04 using RMT - very fast
Hello,
First of all thank you for your code it works perfectly. now i'm traing to simplify the ligne:
distance = 340.29 * ITEM_DURATION(item->duration0) / (1000 * 1000 * 2);
Because the μC works for nothing if we break down in number of instructions. The sensor being linear, it is necessary to simplify this calculation with a constant, so any suggestions
Regards,
First of all thank you for your code it works perfectly. now i'm traing to simplify the ligne:
distance = 340.29 * ITEM_DURATION(item->duration0) / (1000 * 1000 * 2);
Because the μC works for nothing if we break down in number of instructions. The sensor being linear, it is necessary to simplify this calculation with a constant, so any suggestions
Regards,
-
- Posts: 23
- Joined: Wed Dec 09, 2015 8:11 pm
Re: HC-SR04 using RMT - very fast
I would be VERY surprised if the compiler did not perform constant folding by default.
oussama wrote: ↑Mon Feb 04, 2019 1:47 pmHello,
First of all thank you for your code it works perfectly. now i'm traing to simplify the ligne:
distance = 340.29 * ITEM_DURATION(item->duration0) / (1000 * 1000 * 2);
Because the μC works for nothing if we break down in number of instructions. The sensor being linear, it is necessary to simplify this calculation with a constant, so any suggestions
Regards,
Re: HC-SR04 using RMT - very fast
The compiler will indeed optimise out all the constant calculations.
If you want the very best performance, probably the only other optimisation would be not to use floats and to "think big" in the integer domain instead (ie have the calculation output integer centimeters or millimeters so all the math can be faster integer math not floating point.)
But I can't imagine this infrequent single FP calculation is a large bottleneck, either.
If you want the very best performance, probably the only other optimisation would be not to use floats and to "think big" in the integer domain instead (ie have the calculation output integer centimeters or millimeters so all the math can be faster integer math not floating point.)
But I can't imagine this infrequent single FP calculation is a large bottleneck, either.
Re: HC-SR04 using RMT - very fast
I'm not sure if this is FP32 or maybe better to use FP64 e.g. double.
Maybe optimized FP16 (manual calc?) would work fine as well
Maybe optimized FP16 (manual calc?) would work fine as well
Re: HC-SR04 using RMT - very fast
Single precision floating point (ie float not double) on the ESP32 will use the FPU. Double precision will use software so is much slower.
Integer will always be faster, so if you only care about X digits of precision then just pick an integer base large enough to capture all those digits, and divide down later into a float if you need to. Or use a fixed point math library.
In this case I don't think this calculation happens often enough for the choice of math type to make any difference to overall performance.
Re: HC-SR04 using RMT - very fast
I would like to know how many cycles a single float FPU operations take.
Why is this such a big case? I don't think it should be slower than software but I see all the time people saying it is a performance issue.
Could you please elaborate on that?
Why is this such a big case? I don't think it should be slower than software but I see all the time people saying it is a performance issue.
Could you please elaborate on that?
Re: HC-SR04 using RMT - very fast
I don't think we actually publish statistics for ESP32, although we probably should. The answer is "it depends" a bit, because of things like the CPU pipeline.
There are some user benchmarks here measuring 170MOPS for float multiply, which sounds about right. Their integer multiplication result is bad for some reason (they mark it as a problem case), in ideal conditions I believe integer multiplication should take one cycle so maximum 240MOPS.
As a rule of thumb: integer math is always faster than hardware floating point math (on any CPU), and software floating point math is always much slower than either of the other two (on any CPU, note the results for "double" in the linked post).
Re: HC-SR04 using RMT - very fast
Has anyone tried this code lately? All I get is this Guru meditation about core panic:
Code: Select all
I (114) cpu_start: App cpu up. [10/13182]
I (132) heap_init: Initializing. RAM available for dynamic allocation:
I (139) heap_init: At 3FFAE6E0 len 00001920 (6 KiB): DRAM
I (145) heap_init: At 3FFB2F80 len 0002D080 (180 KiB): DRAM
I (151) heap_init: At 3FFE0440 len 00003AE0 (14 KiB): D/IRAM
I (158) heap_init: At 3FFE4350 len 0001BCB0 (111 KiB): D/IRAM
I (164) heap_init: At 400892B4 len 00016D4C (91 KiB): IRAM
I (170) cpu_start: Pro cpu start user code
I (188) cpu_start: Starting scheduler on PRO CPU.
I (0) cpu_start: Starting scheduler on APP CPU.
Guru Meditation Error: Core 0 panic'ed (LoadProhibited). Exception was unhandled.
Core 0 register dump:
PC : 0x400d2491 PS : 0x00060730 A0 : 0x800d0b0d A1 : 0x3ffb4d10
0x400d2491: app_main at /home/thoth/git/A9thinker/GPRS_C_SDK/tank_gauge/sr04test/main/bstx03_XiuxinESP32.c:92 (discriminator 1)
A2 : 0x00000000 A3 : 0x00000001 A4 : 0x00000001 A5 : 0x00000001
A6 : 0x00060021 A7 : 0x00000000 A8 : 0x800d248f A9 : 0x3ffb4cd0
A10 : 0x00000000 A11 : 0x3ffb4d14 A12 : 0x000003e8 A13 : 0x00000001
A14 : 0x00000040 A15 : 0x3ffb699c SAR : 0x00000020 EXCCAUSE: 0x0000001c
EXCVADDR: 0x00000000 LBEG : 0x400014fd LEND : 0x4000150d LCOUNT : 0xffffffff
ELF file SHA256: f72eba0ee73b704e70e2cb3c46cc43357e7349cb9aa64dfb4204213e1d20c7f5
Backtrace: 0x400d2491:0x3ffb4d10 0x400d0b0a:0x3ffb4d40 0x40085625:0x3ffb4d60
0x400d2491: app_main at /home/thoth/git/A9thinker/GPRS_C_SDK/tank_gauge/sr04test/main/bstx03_XiuxinESP32.c:92 (discriminator 1)
0x400d0b0a: main_task at /home/thoth/esp/esp-idf/components/esp32/cpu_start.c:527
0x40085625: vPortTaskWrapper at /home/thoth/esp/esp-idf/components/freertos/port.c:403
Rebooting...
Who is online
Users browsing this forum: No registered users and 41 guests