Framework: ESP-IDF v5.2.2
Devkit: ESP32-S3-WROOM-1N8R8
IDE: VSCode
Repository: https://github.com/dpnebert/rmt_led_strip/tree/StackOverflowQuestion
I am making a RF remote. Apologies, I should have changed the project name from 'rmt_led_strip' to 'rmt_rf_remote', but I've started over so many times, I don't really care about the project name.
The 'led_strip' example works, but does not have 'loop_count = -1". The 'd_shot_esc' example is the only one that has a forever loop, so I modeled the stopping and restarting transmissions from that.
The forever loop pseudocode is:
rmt_enable(...)
while(1) {
rmt_transmit(...)
vTaskDelay(1000 / portTICK_PERIOD_MS);
rmt_disable(...)
rmt_enable(...)
}
and I've tried:
rmt_enable(...)
while(1) {
rmt_transmit(...)
vTaskDelay(1000 / portTICK_PERIOD_MS);
rmt_disable(...)
rmt_enable(...)
vTaskDelay(1000 / portTICK_PERIOD_MS);
}
Then I refactored the code to have 'rf_remote' instead of 'led_strip'.
But during the second time 'rmt_transmit' is called, the task WDT is triggered showing this message:
rst:0x8 (TG1WDT_SYS_RST),boot:0x8 (SPI_FAST_FLASH_BOOT)
Saved PC:0x4200295b
0x4200295b: panic_handler at C:/Espressif/frameworks/esp-idf-v5.2.1/components/esp_system/port/panic_handler.c:145
Starting over with the 'led_strip' example to test disable>enable>rmt_transmit in forever loop.
I've tried searching the web for similar issues.
Increasing the TWDT timeout.
Reading source code which lead me to believe it was a cache miss problem, but now we are getting out my comfort zone. I started to put the encode method in IRAM, but I swear, I always seem to fight the simple stuff like adding attributes. I started with:
static size_t encode_cb(rmt_encoder_t *encoder, rmt_channel_handle_t channel, const void *primary_data, size_t data_size, rmt_encode_state_t *ret_state)
and added 'IRAM_ATTR':
static size_t IRAM_ATTR encode_cb(rmt_encoder_t *encoder, rmt_channel_handle_t channel, const void *primary_data, size_t data_size, rmt_encode_state_t *ret_state)
but I got a red squiggle beneath 'encode_cb' with the error:
expected a ';'C/C++(65)
I almost never post here asking for help, but I'm getting to the end of my patience. Thank you in advance.
Here is the full terminal output:
SPIWP:0xee
mode:DIO, clock div:1
load:0x3fce3810,len:0x178c
load:0x403c9700,len:0x4
load:0x403c9704,len:0xcbc
load:0x403cc700,len:0x2da0
SHA-256 comparison failed:
Calculated: 9e89842ee358387a44c70bc3eec4cc7d29038b814dab02f777064dabcb8fa9f4
Expected: ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
Attempting to boot anyway...
entry 0x403c9914
I (49) boot: ESP-IDF v5.2.1 2nd stage bootloader
I (50) boot: compile time Jul 18 2024 15:36:16
I (50) boot: Multicore bootloader
I (53) boot: chip revision: v0.2
I (57) boot.esp32s3: Boot SPI Speed : 80MHz
I (61) boot.esp32s3: SPI Mode : DIO
I (66) boot.esp32s3: SPI Flash Size : 8MB
W (71) boot.esp32s3: PRO CPU has been reset by WDT.
W (76) boot.esp32s3: APP CPU has been reset by WDT.
I (82) boot: Enabling RNG early entropy source...
I (87) boot: Partition Table:
I (91) boot: ## Label Usage Type ST Offset Length
I (98) boot: 0 nvs WiFi data 01 02 00009000 00006000
I (106) boot: 1 phy_init RF data 01 01 0000f000 00001000
I (113) boot: 2 factory factory app 00 00 00010000 00100000
I (121) boot: End of partition table
I (125) esp_image: segment 0: paddr=00010020 vaddr=3c020020 size=0e888h ( 59528) map
I (140) esp_image: segment 1: paddr=0001e8b0 vaddr=3fc93400 size=01768h ( 5992) load
I (143) esp_image: segment 2: paddr=00020020 vaddr=42000020 size=1c928h (117032) map
I (163) esp_image: segment 3: paddr=0003c950 vaddr=3fc94b68 size=011d8h ( 4568) load
I (164) esp_image: segment 4: paddr=0003db30 vaddr=40374000 size=0f31ch ( 62236) load
I (185) boot: Loaded app from partition at offset 0x10000
I (185) boot: Disabling RNG early entropy source...
I (196) cpu_start: Multicore app
I (206) cpu_start: Pro cpu start user code
I (206) cpu_start: cpu freq: 160000000 Hz
I (206) cpu_start: Application information:
I (209) cpu_start: Project name: rmt_led_strip
I (214) cpu_start: App version: 1
I (219) cpu_start: Compile time: Jul 18 2024 15:36:04
I (225) cpu_start: ELF file SHA256: 7ad781edf...
I (230) cpu_start: ESP-IDF: v5.2.1
I (235) cpu_start: Min chip rev: v0.0
I (240) cpu_start: Max chip rev: v0.99
I (245) cpu_start: Chip rev: v0.2
I (249) heap_init: Initializing. RAM available for dynamic allocation:
I (257) heap_init: At 3FC96630 len 000530E0 (332 KiB): RAM
I (263) heap_init: At 3FCE9710 len 00005724 (21 KiB): RAM
I (269) heap_init: At 3FCF0000 len 00008000 (32 KiB): DRAM
I (275) heap_init: At 600FE010 len 00001FD8 (7 KiB): RTCRAM
I (282) spi_flash: detected chip: gd
I (286) spi_flash: flash io: dio
I (290) sleep: Configure to isolate all GPIO pins in sleep state
I (296) sleep: Enable automatic switching of GPIO sleep configuration
I (304) main_task: Started on CPU0
I (314) main_task: Calling app_main()
I (314) rf_remote_main: Create RMT TX channel config
I (314) rf_remote_main: Create RMT TX channel
I (324) gpio: GPIO[39]| InputEn: 0| OutputEn: 1| OpenDrain: 0| Pullup: 1| Pulldown: 0| Intr:0
I (334) rf_remote_main: RMT TX channel created
I (334) rf_remote_main: Install RF remote encoder
I (344) rf_remote_encoder: Memory allocated for remote encoder
I (344) rf_remote_encoder: Bytes encoder created
I (354) rf_remote_encoder: Copy encoder created
I (354) rf_remote_main: RF remote encoder installed
I (364) rf_remote_main: Enable RMT TX channel
I (374) rf_remote_main: RMT TX channel enabled
I (374) rf_remote_main: Configure RMT TX channel config
I (384) rf_remote_encoder: data.full: 0
I (384) rf_remote_main: RF remote data transmitted
I (1394) rf_remote_main: Disable RMT TX channel (to stop continuous transmission)
I (1394) rf_remote_main: RMT TX channel disabled
I (1394) rf_remote_main: Enable RMT TX channel
I (1394) rf_remote_main: RMT TX channel enabled
I (2404) rf_remote_encoder: data.full: 1
ESP-ROM:esp32s3-20210327
Build:Mar 27 2021
rst:0x8 (TG1WDT_SYS_RST),boot:0x8 (SPI_FAST_FLASH_BOOT)
Saved PC:0x4200295b
0x4200295b: panic_handler at C:/Espressif/frameworks/esp-idf-v5.2.1/components/esp_system/port/panic_handler.c:145
EDIT 7/19/24 8:13AM CST:
Following the suggestion to move code to FreeRTOS task, I now have this:
void app_task(void * parameters) {
ESP_LOGI(TAG, "Application Task Running");
payload[0] = 0x0;
initRMT();
while (1) {
// Flush RGB values to LEDs
esp_err_t ret = ESP_OK;
ret = rmt_transmit(rf_rmt->channel_handle, rf_rmt->encoder_handle, payload, sizeof(payload), &rf_rmt->tx_config);
if(ESP_OK != ret) {
ESP_LOGE(TAG, "Failed to transmit RF remote data");
return;
} else {
ESP_LOGI(TAG, "RF remote data transmitted");
}
payload[0] = payload[0] + 1;
vTaskDelay(1000 / portTICK_PERIOD_MS);
ESP_LOGI(TAG, "Disable RMT TX channel (to stop continuous transmission)");
ret = rmt_disable(rf_rmt->channel_handle);
if(ESP_OK != ret) {
ESP_LOGE(TAG, "Failed to disable RMT TX channel");
return;
} else {
ESP_LOGI(TAG, "RMT TX channel disabled");
}
ESP_LOGI(TAG, "Enable RMT TX channel");
ret = rmt_enable(rf_rmt->channel_handle);
if(ESP_OK != ret) {
ESP_LOGE(TAG, "Failed to enable RMT TX channel");
return;
} else {
ESP_LOGI(TAG, "RMT TX channel enabled");
}
vTaskDelay(1000 / portTICK_PERIOD_MS);
}
}
void app_main(void)
{
xTaskCreatePinnedToCore(app_task,
"Application Task",
1024 * 4,
NULL,
12,
&app_handle,
1);
vTaskDelete(NULL);
}
Ok, taking the DShot_ESC example and modifying it, everything worked up until I changed the example encoder for my customer encoder. Things broke. It was the encoder, so I fixed it.
The BROKEN encoder:
static size_t encode_cb(rmt_encoder_t *encoder, rmt_channel_handle_t channel, const void *primary_data, size_t data_size, rmt_encode_state_t *ret_state)
{
rmt_rf_remote_encoder_t *_encoder = __containerof(encoder, rmt_rf_remote_encoder_t, base);
rf_remote_payload_t data = *(rf_remote_payload_t *)primary_data;
rmt_encoder_handle_t bytes_encoder = _encoder->bytes_encoder;
rmt_encoder_handle_t copy_encoder = _encoder->copy_encoder;
rmt_encode_state_t session_state = RMT_ENCODING_RESET;
int state = RMT_ENCODING_RESET;
size_t encoded_symbols = 0;
//ESP_LOGI(TAG, "data.full: %llu", data.full);
uint64_t reverse_data = 0;
for(int i = 0; i < 64; i++)
{
reverse_data |= ((data.full >> i) & 1) << (63 - i);
}
switch (state) {
case 0: // encode and add pressedRelased
encoded_symbols += copy_encoder->encode(copy_encoder, channel, &_encoder->preamble_time, sizeof(_encoder->preamble_time), &session_state);
if (session_state & RMT_ENCODING_COMPLETE) {
state++; // we can only switch to next state when current encoder finished
}
if (session_state & RMT_ENCODING_MEM_FULL) {
state |= RMT_ENCODING_MEM_FULL;
*ret_state = (rmt_encode_state_t)state;
return encoded_symbols;
}
case 1: // encode and add pressedRelased
encoded_symbols += bytes_encoder->encode(bytes_encoder, channel, &reverse_data, sizeof(reverse_data), &session_state);
if (session_state & RMT_ENCODING_COMPLETE) {
state++;//state = RMT_ENCODING_COMPLETE; // we can only switch to next state when current encoder finished
}
if (session_state & RMT_ENCODING_MEM_FULL) {
state |= RMT_ENCODING_MEM_FULL;
*ret_state = (rmt_encode_state_t)state;
return encoded_symbols;
}
case 2:
encoded_symbols += copy_encoder->encode(copy_encoder, channel, &_encoder->dead_time, sizeof(_encoder->dead_time), &session_state);
if (session_state & RMT_ENCODING_COMPLETE) {
state++; // we can only switch to next state when current encoder finished
}
if (session_state & RMT_ENCODING_MEM_FULL) {
state |= RMT_ENCODING_MEM_FULL;
*ret_state = (rmt_encode_state_t)state;
return encoded_symbols;
}
case 3:
encoded_symbols += copy_encoder->encode(copy_encoder, channel, &_encoder->dead_time, sizeof(_encoder->dead_time), &session_state);
if (session_state & RMT_ENCODING_COMPLETE) {
state = RMT_ENCODING_COMPLETE; // we can only switch to next state when current encoder finished
}
if (session_state & RMT_ENCODING_MEM_FULL) {
state |= RMT_ENCODING_MEM_FULL;
*ret_state = (rmt_encode_state_t)state;
return encoded_symbols;
}
}
*ret_state = (rmt_encode_state_t)state;
return encoded_symbols;
}
The WORKING encoder:
static size_t encode_cb(rmt_encoder_t *encoder, rmt_channel_handle_t channel, const void *primary_data, size_t data_size, rmt_encode_state_t *ret_state) {
rmt_rf_remote_encoder_t *_encoder = __containerof(encoder, rmt_rf_remote_encoder_t, base);
rf_remote_payload_t data = *(rf_remote_payload_t *)primary_data;
rmt_encoder_handle_t bytes_encoder = _encoder->bytes_encoder;
rmt_encoder_handle_t copy_encoder = _encoder->copy_encoder;
rmt_encode_state_t session_state = RMT_ENCODING_RESET;
size_t encoded_symbols = 0;
// Reverse the bits in the data
uint64_t reverse_data = 0;
for(int i = 0; i < 64; i++) {
reverse_data |= ((data.full >> i) & 1) << (63 - i);
}
switch (_encoder->state) {
case 0: // Encode preamble
encoded_symbols += copy_encoder->encode(copy_encoder, channel, &_encoder->preamble_time, sizeof(_encoder->preamble_time), &session_state);
if (session_state & RMT_ENCODING_COMPLETE) {
_encoder->state++; // Switch to next state when current encoder finished
}
if (session_state & RMT_ENCODING_MEM_FULL) {
*ret_state = RMT_ENCODING_MEM_FULL;
return encoded_symbols;
}
// fall through
case 1: // Encode data
encoded_symbols += bytes_encoder->encode(bytes_encoder, channel, &reverse_data, sizeof(reverse_data), &session_state);
if (session_state & RMT_ENCODING_COMPLETE) {
_encoder->state++;
}
if (session_state & RMT_ENCODING_MEM_FULL) {
*ret_state = RMT_ENCODING_MEM_FULL;
return encoded_symbols;
}
// fall through
case 2: // Encode dead time
encoded_symbols += copy_encoder->encode(copy_encoder, channel, &_encoder->dead_time, sizeof(_encoder->dead_time), &session_state);
if (session_state & RMT_ENCODING_COMPLETE) {
_encoder->state++;
}
if (session_state & RMT_ENCODING_MEM_FULL) {
*ret_state = RMT_ENCODING_MEM_FULL;
return encoded_symbols;
}
// fall through
case 3: // Encode additional dead time
encoded_symbols += copy_encoder->encode(copy_encoder, channel, &_encoder->dead_time, sizeof(_encoder->dead_time), &session_state);
if (session_state & RMT_ENCODING_COMPLETE) {
_encoder->state = RMT_ENCODING_COMPLETE; // Mark encoding as complete
}
if (session_state & RMT_ENCODING_MEM_FULL) {
*ret_state = RMT_ENCODING_MEM_FULL;
return encoded_symbols;
}
break;
default:
break;
}
*ret_state = _encoder->state == RMT_ENCODING_COMPLETE ? RMT_ENCODING_COMPLETE : RMT_ENCODING_RESET;
return encoded_symbols;
}
I hope this helps someone digging for help!