Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

RMT driver and Wi-fi driver coexistence. (IDFGH-10681) #11907

Closed
3 tasks done
guirespi opened this issue Jul 19, 2023 · 7 comments
Closed
3 tasks done

RMT driver and Wi-fi driver coexistence. (IDFGH-10681) #11907

guirespi opened this issue Jul 19, 2023 · 7 comments
Labels
Resolution: Done Issue is done internally Status: Done Issue is done internally Type: Bug bugs in IDF

Comments

@guirespi
Copy link

Answers checklist.

  • I have read the documentation ESP-IDF Programming Guide and the issue is not addressed there.
  • I have updated my IDF branch (master or release) to the latest version and checked that the issue is present there.
  • I have searched the issue tracker for a similar issue and not found a similar issue.

IDF version.

v4.4.2

Operating System used.

Windows

How did you build your project?

Eclipse IDE

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

None

Development Kit.

ESP32 WROVER KIT

Power Supply used.

USB

What is the expected behavior?

Wi-fi and RMT driver for WS2812 should coexist without freezing the program. The code I made starts a task that constantly creates and delete anoter task that turn the WS2812 leds.

What is the actual behavior?

When try to connect to an non existent SSID and the RMT driver is used to turn on and turn off a WS2812 led strip, the program freezes. Neither Wi-fi or led strip do something after.

Steps to reproduce.

Compile and run the following code . The base is the 'station' project in the examples folder (esp_idf>examples>wifi>getting_started). Then I add the component led_strip (esp_idf>examples>common_components) to the components folder.

This a draft code, the production code uses a different implementation of led_strip component but, I achieve to recreate the same scenario with espressif's components. In the production code, the program freezes after several hours of use and it is always at the use of the RMT driver.

/* WiFi station Example

   This example code is in the Public Domain (or CC0 licensed, at your option.)

   Unless required by applicable law or agreed to in writing, this
   software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
   CONDITIONS OF ANY KIND, either express or implied.
*/
#include <string.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "freertos/event_groups.h"
#include "esp_system.h"
#include "esp_wifi.h"
#include "esp_event.h"
#include "esp_log.h"
#include "nvs_flash.h"

#include "lwip/err.h"
#include "lwip/sys.h"
#include "../components/led_strip/include/led_strip.h"

/* The examples use WiFi configuration that you can set via project configura
 * tion menu

   If you'd rather not, just change the below entries to strings with
   the config you want - ie #define EXAMPLE_WIFI_SSID "mywifissid"
*/
#define EXAMPLE_ESP_WIFI_SSID      "RANDOM_SSID"
#define EXAMPLE_ESP_WIFI_PASS      "password"
#define EXAMPLE_ESP_MAXIMUM_RETRY  15

#if CONFIG_ESP_WIFI_AUTH_OPEN
#define ESP_WIFI_SCAN_AUTH_MODE_THRESHOLD WIFI_AUTH_OPEN
#elif CONFIG_ESP_WIFI_AUTH_WEP
#define ESP_WIFI_SCAN_AUTH_MODE_THRESHOLD WIFI_AUTH_WEP
#elif CONFIG_ESP_WIFI_AUTH_WPA_PSK
#define ESP_WIFI_SCAN_AUTH_MODE_THRESHOLD WIFI_AUTH_WPA_PSK
#elif CONFIG_ESP_WIFI_AUTH_WPA2_PSK
#define ESP_WIFI_SCAN_AUTH_MODE_THRESHOLD WIFI_AUTH_WPA2_PSK
#elif CONFIG_ESP_WIFI_AUTH_WPA_WPA2_PSK
#define ESP_WIFI_SCAN_AUTH_MODE_THRESHOLD WIFI_AUTH_WPA_WPA2_PSK
#elif CONFIG_ESP_WIFI_AUTH_WPA3_PSK
#define ESP_WIFI_SCAN_AUTH_MODE_THRESHOLD WIFI_AUTH_WPA3_PSK
#elif CONFIG_ESP_WIFI_AUTH_WPA2_WPA3_PSK
#define ESP_WIFI_SCAN_AUTH_MODE_THRESHOLD WIFI_AUTH_WPA2_WPA3_PSK
#elif CONFIG_ESP_WIFI_AUTH_WAPI_PSK
#define ESP_WIFI_SCAN_AUTH_MODE_THRESHOLD WIFI_AUTH_WAPI_PSK
#endif

/* FreeRTOS event group to signal when we are connected*/
static EventGroupHandle_t s_wifi_event_group;

/* The event group allows multiple bits for each event, but we only care about two events:
 * - we are connected to the AP with an IP
 * - we failed to connect after the maximum amount of retries */
#define WIFI_CONNECTED_BIT BIT0
#define WIFI_FAIL_BIT      BIT1

static const char *TAG = "wifi station";

static int s_retry_num = 0;


static void event_handler(void* arg, esp_event_base_t event_base,
                                int32_t event_id, void* event_data)
{
    if (event_base == WIFI_EVENT && event_id == WIFI_EVENT_STA_START) {
        esp_wifi_connect();
    } else if (event_base == WIFI_EVENT && event_id == WIFI_EVENT_STA_DISCONNECTED) {
        if (s_retry_num < EXAMPLE_ESP_MAXIMUM_RETRY) {
        	vTaskDelay(pdMS_TO_TICKS(100));
            esp_wifi_connect();
            s_retry_num++;
            ESP_LOGI(TAG, "retry to connect to the AP");
        } else {
            xEventGroupSetBits(s_wifi_event_group, WIFI_FAIL_BIT);
        }
        ESP_LOGI(TAG,"connect to the AP fail");
    } else if (event_base == IP_EVENT && event_id == IP_EVENT_STA_GOT_IP) {
        ip_event_got_ip_t* event = (ip_event_got_ip_t*) event_data;
        ESP_LOGI(TAG, "got ip:" IPSTR, IP2STR(&event->ip_info.ip));
        s_retry_num = 0;
        xEventGroupSetBits(s_wifi_event_group, WIFI_CONNECTED_BIT);
    }
}

led_strip_t * led = NULL;

static void exe_api(void *pv){
	while(true){
		printf("Init turn on\n");
		for(uint8_t i = 0; i<4; i++){
			led->set_pixel(led, i, 0xff,0xff,0xff);
		}
		led->refresh(led, 250);
		printf("Finish turn on\n");
	}
}

static void raw_api(void * pv){
	TaskHandle_t handler = NULL;
	while(true){
		xTaskCreate(exe_api, "test2", 2048, NULL, 1, &handler);
		vTaskDelay(pdMS_TO_TICKS(10));
		vTaskDelete(handler);
		handler = NULL;
		led->clear(led, 250);
	}

}

void wifi_init_sta(void)
{
	led = led_strip_init(0, 5, 4);
	xTaskCreate(raw_api, "test", 4096, NULL, 5, NULL);

    s_wifi_event_group = xEventGroupCreate();

    ESP_ERROR_CHECK(esp_netif_init());

    ESP_ERROR_CHECK(esp_event_loop_create_default());
    esp_netif_create_default_wifi_sta();

    wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT();
    ESP_ERROR_CHECK(esp_wifi_init(&cfg));

    esp_event_handler_instance_t instance_any_id;
    esp_event_handler_instance_t instance_got_ip;
    ESP_ERROR_CHECK(esp_event_handler_instance_register(WIFI_EVENT,
                                                        ESP_EVENT_ANY_ID,
                                                        &event_handler,
                                                        NULL,
                                                        &instance_any_id));
    ESP_ERROR_CHECK(esp_event_handler_instance_register(IP_EVENT,
                                                        IP_EVENT_STA_GOT_IP,
                                                        &event_handler,
                                                        NULL,
                                                        &instance_got_ip));

    wifi_config_t wifi_config = {
        .sta = {
            .ssid = EXAMPLE_ESP_WIFI_SSID,
            .password = EXAMPLE_ESP_WIFI_PASS,
            /* Setting a password implies station will connect to all security modes including WEP/WPA.
             * However these modes are deprecated and not advisable to be used. Incase your Access point
             * doesn't support WPA2, these mode can be enabled by commenting below line */
	     .threshold.authmode = ESP_WIFI_SCAN_AUTH_MODE_THRESHOLD,
        },
    };
    ESP_ERROR_CHECK(esp_wifi_set_mode(WIFI_MODE_STA) );
    ESP_ERROR_CHECK(esp_wifi_set_config(WIFI_IF_STA, &wifi_config) );
    ESP_ERROR_CHECK(esp_wifi_start() );

    ESP_LOGI(TAG, "wifi_init_sta finished.");

    /* Waiting until either the connection is established (WIFI_CONNECTED_BIT) or connection failed for the maximum
     * number of re-tries (WIFI_FAIL_BIT). The bits are set by event_handler() (see above) */
    EventBits_t bits = xEventGroupWaitBits(s_wifi_event_group,
            WIFI_CONNECTED_BIT | WIFI_FAIL_BIT,
            pdFALSE,
            pdFALSE,
            portMAX_DELAY);

    /* xEventGroupWaitBits() returns the bits before the call returned, hence we can test which event actually
     * happened. */
    if (bits & WIFI_CONNECTED_BIT) {
        ESP_LOGI(TAG, "connected to ap SSID:%s password:%s",
                 EXAMPLE_ESP_WIFI_SSID, EXAMPLE_ESP_WIFI_PASS);
    } else if (bits & WIFI_FAIL_BIT) {
        ESP_LOGI(TAG, "Failed to connect to SSID:%s, password:%s",
                 EXAMPLE_ESP_WIFI_SSID, EXAMPLE_ESP_WIFI_PASS);
    } else {
        ESP_LOGE(TAG, "UNEXPECTED EVENT");
    }
}

void app_main(void)
{
    //Initialize NVS
    esp_err_t ret = nvs_flash_init();
    if (ret == ESP_ERR_NVS_NO_FREE_PAGES || ret == ESP_ERR_NVS_NEW_VERSION_FOUND) {
      ESP_ERROR_CHECK(nvs_flash_erase());
      ret = nvs_flash_init();
    }
    ESP_ERROR_CHECK(ret);

    ESP_LOGI(TAG, "ESP_WIFI_MODE_STA");
    wifi_init_sta();
}

This is the code I use in the 'station_example_main.c' file. In using the ESP-IDF v4.4.2.

Debug Logs.

ets Jun  8 2016 00:22:57

rst:0x1 (POWERON_RESET),boot:0x1e (SPI_FAST_FLASH_BOOT)
configsip: 0, SPIWP:0xee
clk_drv:0x00,q_drv:0x00,d_drv:0x00,cs0_drv:0x00,hd_drv:0x00,wp_drv:0x00
mode:DIO, clock div:2
load:0x3fff0030,len:6664
load:0x40078000,len:14848
load:0x40080400,len:3792
entry 0x40080694
I (27) boot: ESP-IDF v4.4.2-dirty 2nd stage bootloader
I (27) boot: compile time 11:53:57
I (27) boot: chip revision: 1
I (30) boot_comm: chip revision: 1, min. bootloader chip revision: 0
I (37) boot.esp32: SPI Speed      : 40MHz
I (42) boot.esp32: SPI Mode       : DIO
I (46) boot.esp32: SPI Flash Size : 2MB
I (51) boot: Enabling RNG early entropy source...
I (56) boot: Partition Table:
I (60) boot: ## Label            Usage          Type ST Offset   Length
I (67) boot:  0 nvs              WiFi data        01 02 00009000 00006000
I (75) boot:  1 phy_init         RF data          01 01 0000f000 00001000
I (82) boot:  2 factory          factory app      00 00 00010000 00100000
I (90) boot: End of partition table
I (94) boot_comm: chip revision: 1, min. application chip revision: 0
I (101) esp_image: segment 0: paddr=00010020 vaddr=3f400020 size=1408ch ( 82060) map
I (139) esp_image: segment 1: paddr=000240b4 vaddr=3ffb0000 size=0384ch ( 14412) load
I (145) esp_image: segment 2: paddr=00027908 vaddr=40080000 size=08710h ( 34576) load
I (160) esp_image: segment 3: paddr=00030020 vaddr=400d0020 size=71bc4h (465860) map
I (328) esp_image: segment 4: paddr=000a1bec vaddr=40088710 size=0a8e8h ( 43240) load
I (347) esp_image: segment 5: paddr=000ac4dc vaddr=50000000 size=00010h (    16) load
I (356) boot: Loaded app from partition at offset 0x10000
I (356) boot: Disabling RNG early entropy source...
I (369) cpu_start: Pro cpu up.
I (369) cpu_start: Starting app cpu, entry point is 0x40081060
I (0) cpu_start: App cpu up.
I (385) cpu_start: Pro cpu start user code
I (385) cpu_start: cpu freq: 160000000
I (385) cpu_start: Application information:
I (390) cpu_start: Project name:     wifi_station
I (395) cpu_start: App version:      v4.4.2-dirty
I (401) cpu_start: Compile time:     Jul 19 2023 11:53:27
I (407) cpu_start: ELF file SHA256:  3bc20b1ca34f9941...
I (413) cpu_start: ESP-IDF:          v4.4.2-dirty
I (418) heap_init: Initializing. RAM available for dynamic allocation:
I (425) heap_init: At 3FFAE6E0 len 00001920 (6 KiB): DRAM
I (431) heap_init: At 3FFB7570 len 00028A90 (162 KiB): DRAM
I (438) heap_init: At 3FFE0440 len 00003AE0 (14 KiB): D/IRAM
I (444) heap_init: At 3FFE4350 len 0001BCB0 (111 KiB): D/IRAM
I (451) heap_init: At 40092FF8 len 0000D008 (52 KiB): IRAM
I (458) spi_flash: detected chip: generic
I (461) spi_flash: flash io: dio
W (465) spi_flash: Detected size(4096k) larger than the size in the binary image header(2048k). Using the size in the binary image header.
I (480) cpu_start: Starting scheduler on PRO CPU.
I (0) cpu_start: Starting scheduler on APP CPU.
I (550) wifi station: ESP_WIFI_MODE_STA
Init turn on
Finish turn on
Init turn on

More Information.

I don't know if this is related to #7602 but, I tried the same code with an S3 and stills freezes or crash.

@guirespi guirespi added the Type: Bug bugs in IDF label Jul 19, 2023
@espressif-bot espressif-bot added the Status: Opened Issue is new label Jul 19, 2023
@github-actions github-actions bot changed the title RMT driver and Wi-fi driver coexistence. RMT driver and Wi-fi driver coexistence. (IDFGH-10681) Jul 19, 2023
@Xartrick
Copy link

Xartrick commented Aug 3, 2023

RMT and Wi-Fi have issue working together, see led_strip - RMT-based driver for WS2812B/SK6812/APA106 LED strips — esp-idf-lib 1.0 documentation.

If you try to use this driver simultaneously with Wi-Fi, you may encounter RMT transmission bugs. To avoid them, simply initialize device from the task bound to the second processor core.

More information about it here : LED Strip Driver.

If the RMT hardware can't be assist by DMA, the driver will going into interrupt very frequently, thus result in a high CPU usage. What's worse, if the RMT interrupt is delayed or not serviced in time (e.g. if Wi-Fi interrupt happens on the same CPU core), the RMT transaction will be corrupted and the LEDs will display incorrect colors. If you want to use RMT to drive a large number of LEDs, you'd better to enable the DMA feature if possible.

You can run the task interacting with your led strip on another core by using xTaskCreatePinnedToCore().

@guirespi
Copy link
Author

guirespi commented Aug 8, 2023

I'll try it in my example and will comment the results.

@espressif-bot espressif-bot added the Awaiting Response awaiting a response from the author label Mar 20, 2024
@Sherry616
Copy link
Collaborator

Hi @guirespi, could you please share the latest status of this issue? Thanks.

@guirespi
Copy link
Author

Hi @Sherry616, I've already separated the WIFI and RMT tasks into different cores. The bug is less frequent but still happen. It's been a couple months since I worked on the project that uses the RMT driver and WIFI, but, I remember I use Nimble BLE too. So, do I need to keep the Nimble task in another core too?

@suda-morris
Copy link
Collaborator

There're some limitations you may want to know when using the RMT driver. https://docs.espressif.com/projects/esp-idf/en/latest/esp32/api-reference/peripherals/rmt.html#faq Although this documentation is written for the new RMT driver which only appears in the esp-idf v5.x

For the legacy driver you're using the esp-idf v4.x, I would provide the following suggestions:

  • increase the rmt_config_t::mem_block_num
  • Install the RMT driver on a separate CPU core to avoid competing for the same CPU resources with other interrupt heavy peripherals (e.g. WiFi, Bluetooth).

BTW, can you use a logic analyzer to capture the signal on the RMT GPIO when it fails to blink the LED? Can you also provide your crash log?

@guirespi
Copy link
Author

Hi,

For now it's quite difficult to use the logic analyzer on the project. The logs were provided in this issue, the program just stops waiting for an interruption.

Regards.

@Alvin1Zhang
Copy link
Collaborator

Alvin1Zhang commented Dec 23, 2024

Thanks for reporting, since 4.4 is end of life, suggest to update to much newer versions, feel free to reopen if the issue still happens

@espressif-bot espressif-bot added Status: Done Issue is done internally Resolution: Done Issue is done internally and removed Status: Opened Issue is new labels Dec 23, 2024
@Alvin1Zhang Alvin1Zhang removed the Awaiting Response awaiting a response from the author label Dec 23, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Resolution: Done Issue is done internally Status: Done Issue is done internally Type: Bug bugs in IDF
Projects
None yet
Development

No branches or pull requests

7 participants