espressif / esp-idf

Espressif IoT Development Framework. Official development framework for Espressif SoCs.
Apache License 2.0
13.34k stars 7.2k forks source link

RMT DShot Crashes With High Frequency Calls to rmt_transmit (IDFGH-13593) #14480

Open Juan-Elizondo opened 1 week ago

Juan-Elizondo commented 1 week ago

Answers checklist.

IDF version.

v5.3

Espressif SoC revision.

ESP32 revision v3.0

Operating System used.

Windows

How did you build your project?

Command line with idf.py

If you are using Windows, please specify command line type.

PowerShell

Development Kit.

Custom Board

Power Supply used.

External 3.3V

What is the expected behavior?

I have a working implementation for bidirectional dshot using the rmt peripheral on ESP-IDF v5.0. This implementation takes the official rmt dshot_esc as its starting point. The implementation of the bidirectional protocol requires setting the loop_count member of rmt_transmit_config_t to 0. Otherwise we would be interrupting the processor at too fast a rate when we setup a receive ISR. To keep the ESC from timing out, we then need to use the rmt_transmit function at a fairly high rate.

What is the actual behavior?

When updating my ESP-IDF version to v5.3, I started getting runtime crashes on the code that worked on v5.0. I went back to the basic dshot_esc example to reproduce the crashing and verified I can produce the same backtrace with a few modifications to the example.

Steps to reproduce.

I only modified the file dshot_esc_example_main.c from the example.

The modified dshot_esc_example_main.c file:

/*

include "freertos/FreeRTOS.h"

include "freertos/task.h"

include "esp_log.h"

include "driver/rmt_tx.h"

include "dshot_esc_encoder.h"

if CONFIG_IDF_TARGET_ESP32H2

define DSHOT_ESC_RESOLUTION_HZ 32000000 // 32MHz resolution, DSHot protocol needs a relative high resolution

else

define DSHOT_ESC_RESOLUTION_HZ 40000000 // 40MHz resolution, DSHot protocol needs a relative high resolution

endif

//#define DSHOT_ESC_GPIO_NUM 0

define DSHOT_ESC_GPIO_NUM GPIO_NUM_23

static const char *TAG = "example";

void app_main(void) { ESP_LOGI(TAG, "Create RMT TX channel"); rmt_channel_handle_t esc_chan = NULL; rmt_tx_channel_config_t tx_chan_config = { .clk_src = RMT_CLK_SRC_DEFAULT, // select a clock that can provide needed resolution .gpio_num = DSHOT_ESC_GPIO_NUM, .mem_block_symbols = 64, .resolution_hz = DSHOT_ESC_RESOLUTION_HZ, .trans_queue_depth = 10, // set the number of transactions that can be pending in the background }; ESP_ERROR_CHECK(rmt_new_tx_channel(&tx_chan_config, &esc_chan));

ESP_LOGI(TAG, "Install Dshot ESC encoder");
rmt_encoder_handle_t dshot_encoder = NULL;
dshot_esc_encoder_config_t encoder_config = {
    .resolution = DSHOT_ESC_RESOLUTION_HZ,
    .baud_rate = 300000, // DSHOT300 protocol
    .post_delay_us = 50, // extra delay between each frame
};
ESP_ERROR_CHECK(rmt_new_dshot_esc_encoder(&encoder_config, &dshot_encoder));

ESP_LOGI(TAG, "Enable RMT TX channel");
ESP_ERROR_CHECK(rmt_enable(esc_chan));

rmt_transmit_config_t tx_config = {
    .loop_count = -1, // infinite loop
};
dshot_esc_throttle_t throttle = {
    .throttle = 0,
    .telemetry_req = false, // telemetry is not supported in this example
};

ESP_LOGI(TAG, "Start ESC by sending zero throttle for a while...");
ESP_ERROR_CHECK(rmt_transmit(esc_chan, dshot_encoder, &throttle, sizeof(throttle), &tx_config));
//vTaskDelay(pdMS_TO_TICKS(5000));
vTaskDelay(pdMS_TO_TICKS(2000));
tx_config.loop_count = 0;
throttle.throttle = 100;

ESP_LOGI(TAG, "Increase throttle, no telemetry");
//for (uint16_t thro = 100; thro < 1000; thro += 10) {
//    throttle.throttle = thro;
while (true) {
    ESP_ERROR_CHECK(rmt_transmit(esc_chan, dshot_encoder, &throttle, sizeof(throttle), &tx_config));
    // the previous loop transfer is till undergoing, we need to stop it and restart,
    // so that the new throttle can be updated on the output
    ESP_ERROR_CHECK(rmt_disable(esc_chan));
    ESP_ERROR_CHECK(rmt_enable(esc_chan));
    //vTaskDelay(pdMS_TO_TICKS(1000));
    vTaskDelay(pdMS_TO_TICKS(100));
}

}

Debug Logs.

I (31) boot: ESP-IDF v5.3 2nd stage bootloader
I (31) boot: compile time Sep  1 2024 14:09:49
I (31) boot: Multicore bootloader
I (32) boot: chip revision: v3.0
I (32) boot.esp32: SPI Speed      : 40MHz
I (33) boot.esp32: SPI Mode       : DIO
I (33) boot.esp32: SPI Flash Size : 16MB
I (34) boot: Enabling RNG early entropy source...
I (34) boot: Partition Table:
I (35) boot: ## Label            Usage          Type ST Offset   Length
I (36) boot:  0 nvs              WiFi data        01 02 00009000 00006000
I (36) boot:  1 phy_init         RF data          01 01 0000f000 00001000
I (37) boot:  2 factory          factory app      00 00 00010000 00100000
I (38) boot: End of partition table
I (39) esp_image: segment 0: paddr=00010020 vaddr=3f400020 size=0ab74h ( 43892) map
I (55) esp_image: segment 1: paddr=0001ab9c vaddr=3ffb0000 size=02648h (  9800) load
I (59) esp_image: segment 2: paddr=0001d1ec vaddr=40080000 size=02e2ch ( 11820) load
I (64) esp_image: segment 3: paddr=00020020 vaddr=400d0020 size=162f8h ( 90872) map
I (95) esp_image: segment 4: paddr=00036320 vaddr=40082e2c size=0a8e0h ( 43232) load
I (119) boot: Loaded app from partition at offset 0x10000
I (119) boot: Disabling RNG early entropy source...
I (121) cpu_start: Multicore app
I (129) cpu_start: Pro cpu start user code
I (129) cpu_start: cpu freq: 240000000 Hz
I (129) app_init: Application information:
I (129) app_init: Project name:     DShot
I (130) app_init: App version:      1
I (131) app_init: Compile time:     Sep  1 2024 14:20:46
I (131) app_init: ELF file SHA256:  e426dba46...
I (132) app_init: ESP-IDF:          v5.3
I (132) efuse_init: Min chip rev:     v0.0
I (133) efuse_init: Max chip rev:     v3.99
I (133) efuse_init: Chip rev:         v3.0
I (134) heap_init: Initializing. RAM available for dynamic allocation:
I (135) heap_init: At 3FFAE6E0 len 00001920 (6 KiB): DRAM
I (136) heap_init: At 3FFB2F18 len 0002D0E8 (180 KiB): DRAM
I (136) heap_init: At 3FFE0440 len 00003AE0 (14 KiB): D/IRAM
I (137) heap_init: At 3FFE4350 len 0001BCB0 (111 KiB): D/IRAM
I (138) heap_init: At 4008D70C len 000128F4 (74 KiB): IRAM
I (140) spi_flash: detected chip: generic
I (140) spi_flash: flash io: dio
I (141) main_task: Started on CPU0
I (142) main_task: Calling app_main()
I (143) example: Create RMT TX channel
I (143) gpio: GPIO[23]| InputEn: 0| OutputEn: 1| OpenDrain: 0| Pullup: 1| Pulldown: 0| Intr:0
I (144) example: Install Dshot ESC encoder
I (144) example: Enable RMT TX channel
I (145) example: Start ESC by sending zero throttle for a while...
I (2146) example: Increase throttle, no telemetry
Guru Meditation Error: Core  0 panic'ed (LoadProhibited). Exception was unhandled.

Core  0 register dump:
PC      : 0x40084569  PS      : 0x00060e30  A0      : 0x80084648  A1      : 0x3ffb40d0
0x40084569: rmt_tx_mark_eof at C:/Espressif/frameworks/esp-idf-v5.3/components/esp_driver_rmt/src/rmt_tx.c:621

A2      : 0x3ffb4ed4  A3      : 0x3ffb4ed4  A4      : 0x3ffb41e8  A5      : 0x3ffb5254
A6      : 0x3ffb517c  A7      : 0x00000000  A8      : 0x00000000  A9      : 0x3ff56844
A10     : 0x3ff56800  A11     : 0x00000012  A12     : 0x3ffb5224  A13     : 0x00000011
A14     : 0x3ffb40c0  A15     : 0x00000030  SAR     : 0x00000020  EXCCAUSE: 0x0000001c
EXCVADDR: 0x00000018  LBEG    : 0x4000c2e0  LEND    : 0x4000c2f6  LCOUNT  : 0xffffffff
0x4000c2e0: memcpy in ROM
0x4000c2f6: memcpy in ROM

Backtrace: 0x40084566:0x3ffb40d0 0x40084645:0x3ffb40f0 0x40084811:0x3ffb4120 0x400d97dd:0x3ffb4140 0x400d9237:0x3ffb4180 0x400d63d8:0x3ffb41b0 0x400e5a28:0x3ffb4210 0x400869dd:0x3ffb4240
0x40084566: rmt_tx_mark_eof at C:/Espressif/frameworks/esp-idf-v5.3/components/esp_driver_rmt/src/rmt_tx.c:619
0x40084645: rmt_encode_check_result at C:/Espressif/frameworks/esp-idf-v5.3/components/esp_driver_rmt/src/rmt_tx.c:657
0x40084811: rmt_tx_do_transaction at C:/Espressif/frameworks/esp-idf-v5.3/components/esp_driver_rmt/src/rmt_tx.c:736
0x400d97dd: rmt_tx_enable at C:/Espressif/frameworks/esp-idf-v5.3/components/esp_driver_rmt/src/rmt_tx.c:791
0x400d9237: rmt_enable at C:/Espressif/frameworks/esp-idf-v5.3/components/esp_driver_rmt/src/rmt_common.c:213
0x400d63d8: app_main at D:/ESP/DShot/main/dshot_esc_example_main.c:71
0x400e5a28: main_task at C:/Espressif/frameworks/esp-idf-v5.3/components/freertos/app_startup.c:208
0x400869dd: vPortTaskWrapper at C:/Espressif/frameworks/esp-idf-v5.3/components/freertos/FreeRTOS-Kernel/portable/xtensa/port.c:134

ELF file SHA256: e426dba46

Rebooting...

More Information.

No response

suda-morris commented 1 week ago

@Juan-Elizondo Thanks for your interest in that example.

I see you set the loop_count to zero, which means, it will only transmit the packet for once, and then goes into idle state. So you don't need to call rmt_disable and rmt_enable within the loop. Please have a try.

Juan-Elizondo commented 1 week ago

Thank you for the reply. It did not work unfortunately. I called rmt disable and rmt_enable once after the arming sequence and removed from the loop.

Changed code:

ESP_LOGI(TAG, "Start ESC by sending zero throttle for a while..."); ESP_ERROR_CHECK(rmt_transmit(esc_chan, dshot_encoder, &throttle, sizeof(throttle), &tx_config)); //vTaskDelay(pdMS_TO_TICKS(5000)); vTaskDelay(pdMS_TO_TICKS(2000)); ESP_ERROR_CHECK(rmt_disable(esc_chan)); ESP_ERROR_CHECK(rmt_enable(esc_chan)); tx_config.loop_count = 0; throttle.throttle = 100;

ESP_LOGI(TAG, "Increase throttle, no telemetry"); //for (uint16_t thro = 100; thro < 1000; thro += 10) { // throttle.throttle = thro; while (true) { ESP_ERROR_CHECK(rmt_transmit(esc_chan, dshot_encoder, &throttle, sizeof(throttle), &tx_config)); // the previous loop transfer is till undergoing, we need to stop it and restart, // so that the new throttle can be updated on the output // ESP_ERROR_CHECK(rmt_disable(esc_chan)); // ESP_ERROR_CHECK(rmt_enable(esc_chan)); //vTaskDelay(pdMS_TO_TICKS(1000)); vTaskDelay(pdMS_TO_TICKS(100)); }

Log:

Guru Meditation Error: Core 0 panic'ed (LoadProhibited). Exception was unhandled.

Core 0 register dump: PC : 0x40084569 PS : 0x00060c30 A0 : 0x80084648 A1 : 0x3ffb4100 0x40084569: rmt_tx_mark_eof at C:/Espressif/frameworks/esp-idf-v5.3/components/esp_driver_rmt/src/rmt_tx.c:621

A2 : 0x3ffb4ed4 A3 : 0x3ffb4ed4 A4 : 0x3ffb41e8 A5 : 0x3ffb5254 A6 : 0x3ffb517c A7 : 0x00000000 A8 : 0x00000000 A9 : 0x3ff56844 A10 : 0x3ff56800 A11 : 0x00000012 A12 : 0x3ffb5224 A13 : 0x00000011 A14 : 0x3ffb40f0 A15 : 0x00000030 SAR : 0x00000020 EXCCAUSE: 0x0000001c EXCVADDR: 0x00000018 LBEG : 0x4000c2e0 LEND : 0x4000c2f6 LCOUNT : 0xffffffff 0x4000c2e0: memcpy in ROM 0x4000c2f6: memcpy in ROM

Backtrace: 0x40084566:0x3ffb4100 0x40084645:0x3ffb4120 0x40084811:0x3ffb4150 0x400da1fd:0x3ffb4170 0x400d63d9:0x3ffb41b0 0x400e5a2c:0x3ffb4210 0x400869dd:0x3ffb4240 0x40084566: rmt_tx_mark_eof at C:/Espressif/frameworks/esp-idf-v5.3/components/esp_driver_rmt/src/rmt_tx.c:619 0x40084645: rmt_encode_check_result at C:/Espressif/frameworks/esp-idf-v5.3/components/esp_driver_rmt/src/rmt_tx.c:657 0x40084811: rmt_tx_do_transaction at C:/Espressif/frameworks/esp-idf-v5.3/components/esp_driver_rmt/src/rmt_tx.c:736 0x400da1fd: rmt_transmit at C:/Espressif/frameworks/esp-idf-v5.3/components/esp_driver_rmt/src/rmt_tx.c:577 0x400d63d9: app_main at D:/ESP/DShot/main/dshot_esc_example_main.c:69 0x400e5a2c: main_task at C:/Espressif/frameworks/esp-idf-v5.3/components/freertos/app_startup.c:208 0x400869dd: vPortTaskWrapper at C:/Espressif/frameworks/esp-idf-v5.3/components/freertos/FreeRTOS-Kernel/portable/xtensa/port.c:134

ELF file SHA256: eb91d70e5

Rebooting...