freertos-addons icon indicating copy to clipboard operation
freertos-addons copied to clipboard

Using it on ESP-IDF?

Open janoist1 opened this issue 7 years ago • 6 comments
trafficstars

I had a look at the source code and I think this is a great wrapper, thanks for writing and sharing it! I'd like to utilise it on a modified version of FreeRTOS. I took the simple task example and it has been compiled successfully but when it comes to run on an ESP32 chip it crashes with the following output:

Testing FreeRTOS C++ wrappers Simple Tasks configMAX_TASK_NAME_LEN = 16 C++ Thread names can be greater than 15 characters long. CORRUPT HEAP: multi_heap.c:429 detected at 0x3ffb9f5c abort() was called at PC 0x40086a37 on core 0 0x40086a37: multi_heap_assert at /Users/ist1/esp/esp-idf/components/heap/multi_heap_platform.h:54 (inlined by) multi_heap_malloc_impl at /Users/ist1/esp/esp-idf/components/heap/multi_heap.c:429 ...

I guess this might be due to differences in singe and multi core versions of FreeRTOS. Can you share your thoughts on this? I'm not an advanced C++ developer. Thanks.

janoist1 avatar Oct 30 '18 18:10 janoist1

I wrote the C++ Wrapper to sit only on supported FreeRTOS API calls, so it should work for you on this modified kernel, especially if it compiled successfully. You do have warnings set to the highest level on your compiler and it compiles clean?

If you are seeing heap corruption, my first guess would be a C++ / memory allocation issue. I leverage the new operator in the code, so I might start by figuring out how new is implemented with respect to your compiler and libraries. In most libraries, new turns into a call to malloc followed by a call to the class constructor. If malloc isn't thread safe, or multi-core safe, that could cause problems.

Can you successfully create any objects using new?

michaelbecker avatar Oct 30 '18 19:10 michaelbecker

Thanks for the response. I set the following flags: -std=c++17 -Wall -Wextra -Wwrite-strings -Werror - No error, compiles successfully.

When I add the following lines string *pStr = new string("Test"); cout << *pStr << endl; just before TestThread thread1("Thr_Name_1", 1, 1); then I start getting a different error, although the string "Test" gets written.

Testing FreeRTOS C++ wrappers Simple Tasks configMAX_TASK_NAME_LEN = 16 C++ Thread names can be greater than 15 characters long. Test abort() waboralled a callex40t PC 0xon cor23 o

Backtrace: 0x400870c0:0x3ffae4f0 0x40087263:0x3ffae510 0x400d3823:0x3ffae530 0x400850a7:0x3ffae560 0x400847b0:0x3ffae580 0x400848d1:0x3ffae5c0 0x40082be5:0x3ffae5e0 0x40082ccd:0x3ffae610 0x400d791b:0x3ffae630 0x400d3885:0x3ffae8f0 0x400d3820:0x3ffae940 0x400850a7:0x3ffae970 0x400847b0:0x3ffae990 0x400848d1:0x3ffae9d0 0x40082be5:0x3ffae9f0 0x40080ccd:0x3ffaea20 0x400d791b:0x3ffaea40 0x400d3885:0x3ffaed00 0x400d3820:0x3ffaed50 0x400850a7:0x3ffaed80 0x400847b0:0x3ffaeda0 0x400848d1:0x3ffaede0 0x40082be5:0x3ffaee00 0x40082ccd:0x3ffaee30 0x400d791b:0x3ffaee50 0x400d3885:0x3ffaf110 0x400d3820:0x3ffaf160 0x400850a7:0x3ffaf190 0x400847b0:0x3ffaf1b0 0x400848d1:0x3ffaf1f0 0x40082be5:0x3ffaf210 0x40082ccd:0x3ffaf240 0x400d791b:0x3ffaf260 0x400d3885:0x3ffaf520 0x400d3820:0x3ffaf570 0x400850a7:0x3ffaf5a0 0x400847b0:0x3ffaf5c0 0x400848d1:0x3ffaf600 0x40082be5:0x3ffaf620 0x40082ccd:0x3ffaf650 0x400d791b:0x3ffaf670 0x400d3885:0x3ffaf930 0x400d3820:0x3ffaf980 0x400850a7:0x3ffaf9b0 0x400847b0:0x3ffaf9d0 0x400848d1:0x3ffafa10 0x40082be5:0x3ffafa30 0x40082ccd:0x3ffafa60 0x400d791b:0x3ffafa80 0x400d3885:0x3ffafd40 0x400d3820:0x3ffafd90 0x400870c0: invoke_abort at /Users/ist1/esp/esp-idf/components/esp32/panic.c:649

0x40087263: abort at /Users/ist1/esp/esp-idf/components/esp32/panic.c:649

0x400d3823: __assert_func at /Users/ivan/e/newlib_xtensa-2.2.0-bin/newlib_xtensa-2.2.0/xtensa-esp32-elf/newlib/libc/stdlib/../../../.././newlib/libc/stdlib/assert.c:63 (discriminator 8)

0x400850a7: vPortCPUAcquireMutexIntsDisabledInternal at /Users/ist1/esp/esp-idf/components/freertos/tasks.c:4609 (inlined by) vPortCPUAcquireMutexIntsDisabled at /Users/ist1/esp/esp-idf/components/freertos/portmux_impl.h:98 (inlined by) vTaskEnterCritical at /Users/ist1/esp/esp-idf/components/freertos/tasks.c:4254

0x400847b0: xQueueGenericReceive at /Users/ist1/esp/esp-idf/components/freertos/queue.c:2037 ...

janoist1 avatar Oct 30 '18 21:10 janoist1

Update: Increasing STACK_SIZE and replacing xTaskCreate with xTaskCreatePinnedToCore in cthread.c has resolved the crash. I'm not sure what supposed to be the output of the thread demo, but it is now printing multiple strings at the same time overwriting itself:

Simple Tasks configMAX_TASK_NAME_LEN = 16 C++ Thread names can be greater than 15 characters long. Test Starting thread Starting scheduler...1 Starting thread Starting thread 4 Scheduler ended!Thr_Name_4444

Also, it prints Scheduler ended!... Which shouldn't happen.

janoist1 avatar Oct 31 '18 08:10 janoist1

The demos are targeted to the Linux port that I updated, so I can use more advanced tools like gdb and valgrind to verify that the code works and debug it when it doesn't. If you are actually working on an embedded processor, you may not want to use printf / cout for obvious reasons. In your case, my first guess would be an issue with multiple thread access to whatever stdout actually is for you. You could try wrapping every cout in a mutex lock, which may clean up your output.

You're right, you should never have seen "Scheduler ended!". I suspect that's related to the dual core implementation of this version of FreeRTOS. I have been looking into the ESP-IDF project, and it looks like they have done quite a lot of custom work, with FreeRTOS, with the gcc compiler, etc. This is why you needed to change xTaskCreate with xTaskCreatePinnedToCore, and may need more work past that.

I think you are going to need to really deeply understand how memory allocation is performed in this dev environment as well as how FreeRTOS was changed to make it work for this hardware. Unfortunately I don't have a dev kit to work with, so can't go much further. As you run into issues, I'll keep trying to help you as much as I can as you work through things. (If this is for a commercial project, you could consider hiring me as a consultant, which would allow me to purchase a devkit and carve out more time to directly create a port of the C++ wrappers that works with this permutation of FreeRTOS. But regardless of that, I'll try and help out here whenever I can.)

michaelbecker avatar Nov 04 '18 18:11 michaelbecker

I've been using freertos-addons on the ESP8266_RTOS_SDK and ESP-IDF for some time with minimal modifications. One thing to look out for is that there is an implicit call to vTaskStartScheduler() upon exiting the app_main function. Try commenting out the call to vTaskStartScheduler() in thread.hpp. Here's a simple example that approximates what I'm doing:

// SDK includes
#include <esp_err.h>
#include <esp_log.h>
#include <esp_spiffs.h>
#include <esp_wifi.h>
#include <freertos/FreeRTOS.h>
#include <freertos/task.h>
#include <nvs_flash.h>

// Libs
#include "thread.hpp"

class App : public cpp_freertos::Thread {
public:
  App() : cpp_freertos::Thread("CApp", 4096, tskIDLE_PRIORITY + 1) {
    // Other initialization stuff
    // ...

    // Create task
    Start();
  }

protected:
  // Implementation of your actual thread code
  void Run() override {
    // Run once
    // ...

    // Loop forever
    for (;;) {
      // Do work
    }
  }
};

static App *pApp = NULL;

extern "C" void app_main(void) {
  // Initialize non-volatile storage
  nvs_flash_init();

  // Init TCP/IP driver
  tcpip_adapter_init();

  // Init WiFi driver
  wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT();
  esp_wifi_init(&cfg);

  // Instantiate our app
  pApp = new App;

  // Start all app threads
  cpp_freertos::Thread::StartScheduler();
}

f00bard avatar Nov 13 '18 21:11 f00bard

Thanks for this repo, its great! I especially like the work queues. With some tweaking I was able to get this working for the ESP-IDF. I made the changes, tested a few of your examples and posted the repo here for anyone else that has issues with it here.

To further compile all the necessary changes in one place, I had to:

  • Remove the call to vTaskStartScheduler
  • Change xTaskCreate calls to xTaskCreatePinnedToCore
  • Add coreID parameters for any constructor that would create a task
  • Create a file that checks the IDF project sdkconfig.h file for the CONFIG_CXX_EXCEPTIONS macro and define the CPP_FREERTOS_NO_EXCEPTIONS macro accordingly
  • Change all the stack allocations in your example projects from 100 to a higher value, like 1000
  • Change all includes to use the IDF format of
#include "freertos/freertos_file_name.h"

eagi223 avatar Mar 20 '19 23:03 eagi223

Closing as the ESP-IDF multicore port is not an officially supported FreeRTOS port.

michaelbecker avatar Jul 07 '23 14:07 michaelbecker