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

ESP32 task management #2371

Merged
merged 11 commits into from
Sep 23, 2021
8 changes: 8 additions & 0 deletions Sming/Arch/Esp32/Components/esp32/component.mk
Original file line number Diff line number Diff line change
Expand Up @@ -214,6 +214,14 @@ EXTRA_LDFLAGS := \
-u pthread_include_pthread_cond_impl \
-u pthread_include_pthread_local_storage_impl \
-Wl,--undefined=uxTopUsedPriority \
$(call Wrap,\
esp_event_loop_create_default \
esp_event_handler_register \
esp_event_handler_unregister \
esp_event_handler_instance_register \
esp_event_handler_instance_unregister \
esp_event_post \
esp_event_isr_post) \
$(LDFLAGS_$(ESP_VARIANT))

SDK_DEFAULT_PATH := $(COMPONENT_PATH)/sdk
Expand Down
3 changes: 2 additions & 1 deletion Sming/Arch/Esp32/Components/esp32/sdk/config/common
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,8 @@ CONFIG_ETH_SPI_ETHERNET_DM9051=y

# Mandatory Sming framework changes
CONFIG_ESP_TIMER_TASK_STACK_SIZE=16384
CONFIG_ESP_SYSTEM_EVENT_TASK_STACK_SIZE=8192
CONFIG_ESP_SYSTEM_EVENT_TASK_STACK_SIZE=16384
CONFIG_ESP_TASK_WDT_TIMEOUT_S=8
CONFIG_ESP_TIMER_IMPL_FRC2=y

# Required by HardwareSPI library
Expand Down
110 changes: 110 additions & 0 deletions Sming/Arch/Esp32/Components/esp32/src/event_loop.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
/****
* Sming Framework Project - Open Source framework for high efficiency native ESP8266 development.
* Created 2015 by Skurydin Alexey
* http://github.com/SmingHub/Sming
* All files of the Sming Core are provided under the LGPL v3 license.
*
* event_loop.cpp
*
* This code replaces the standard IDF event loop with our own, *without* associated task.
* This not only reduces the system overhead but avoids the need for additional synchronisation
* management because WiFi events, etc. are all called in the context of the main Sming task.
*/

#include <esp_event.h>

namespace
{
esp_event_loop_handle_t sming_event_loop;
}

esp_event_loop_handle_t sming_create_event_loop()
{
esp_event_loop_args_t loop_args = {
.queue_size = CONFIG_ESP_SYSTEM_EVENT_QUEUE_SIZE,
.task_name = nullptr,
};

ESP_ERROR_CHECK(esp_event_loop_create(&loop_args, &sming_event_loop));

return sming_event_loop;
}

namespace
{
#define WRAP(name) esp_err_t __wrap_##name

extern "C" {

WRAP(esp_event_loop_create_default)()
{
return ESP_ERR_INVALID_STATE;
}

WRAP(esp_event_handler_register)
(esp_event_base_t event_base, int32_t event_id, esp_event_handler_t event_handler, void* event_handler_arg)
{
if(sming_event_loop == nullptr) {
return ESP_ERR_INVALID_STATE;
}

return esp_event_handler_register_with(sming_event_loop, event_base, event_id, event_handler, event_handler_arg);
}

WRAP(esp_event_handler_unregister)
(esp_event_base_t event_base, int32_t event_id, esp_event_handler_t event_handler)
{
if(sming_event_loop == nullptr) {
return ESP_ERR_INVALID_STATE;
}

return esp_event_handler_unregister_with(sming_event_loop, event_base, event_id, event_handler);
}

WRAP(esp_event_handler_instance_register)
(esp_event_base_t event_base, int32_t event_id, esp_event_handler_t event_handler, void* event_handler_arg,
esp_event_handler_instance_t* instance)
{
if(sming_event_loop == nullptr) {
return ESP_ERR_INVALID_STATE;
}

return esp_event_handler_instance_register_with(sming_event_loop, event_base, event_id, event_handler,
event_handler_arg, instance);
}

WRAP(esp_event_handler_instance_unregister)
(esp_event_base_t event_base, int32_t event_id, esp_event_handler_instance_t context)
{
if(sming_event_loop == nullptr) {
return ESP_ERR_INVALID_STATE;
}

return esp_event_handler_instance_unregister_with(sming_event_loop, event_base, event_id, context);
}

WRAP(esp_event_post)
(esp_event_base_t event_base, int32_t event_id, void* event_data, size_t event_data_size, TickType_t ticks_to_wait)
{
if(sming_event_loop == nullptr) {
return ESP_ERR_INVALID_STATE;
}

return esp_event_post_to(sming_event_loop, event_base, event_id, event_data, event_data_size, ticks_to_wait);
}

#if CONFIG_ESP_EVENT_POST_FROM_ISR
IRAM_ATTR WRAP(esp_event_isr_post)(esp_event_base_t event_base, int32_t event_id, void* event_data,
size_t event_data_size, BaseType_t* task_unblocked)
{
if(sming_event_loop == nullptr) {
return ESP_ERR_INVALID_STATE;
}

return esp_event_isr_post_to(sming_event_loop, event_base, event_id, event_data, event_data_size, task_unblocked);
}
#endif

} // extern "C"

} // namespace
13 changes: 0 additions & 13 deletions Sming/Arch/Esp32/Components/esp32/src/include/esp_tasks.h
Original file line number Diff line number Diff line change
Expand Up @@ -14,27 +14,14 @@ typedef struct {
} os_event_t;

enum {
USER_TASK_PRIO_0,
USER_TASK_PRIO_1,
USER_TASK_PRIO_2,
USER_TASK_PRIO_MAX,
};

typedef void (*os_task_t)(os_event_t* e);

bool system_os_task(os_task_t task, uint8_t prio, os_event_t* queue, uint8_t qlen);
bool system_os_post(uint8_t prio, os_signal_t sig, os_param_t par);

// Setup default task queues
void ets_init_tasks();

// Hook function to process task queues
void ets_service_tasks();

typedef void (*host_task_callback_t)(uint32_t param);

bool host_queue_callback(host_task_callback_t callback, uint32_t param);

#ifdef __cplusplus
}
#endif
65 changes: 44 additions & 21 deletions Sming/Arch/Esp32/Components/esp32/src/startup.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,8 @@
#include <esp_system.h>
#include <esp_log.h>
#include <esp_task_wdt.h>
#include <esp_tasks.h>
#include <esp_task.h>
#include <esp_event.h>
#include <debug_progmem.h>
#include <Platform/System.h>
#include <driver/hw_timer.h>
Expand All @@ -22,23 +23,22 @@
#include <esp_netif.h>
#ifndef DISABLE_WIFI
#include <esp_wifi.h>
#include <esp_event.h>
#include <nvs_flash.h>
#endif
#endif

#ifndef ESP32_STACK_SIZE
#define ESP32_STACK_SIZE 16384U
#endif

extern void init();
extern esp_event_loop_handle_t sming_create_event_loop();

namespace
{
static constexpr uint32_t WDT_TIMEOUT_MS{8000};

#ifndef DISABLE_WIFI
void esp_init_flash()
esp_event_handler_t wifiEventHandler;

/*
* Initalise NVS which IDF WiFi uses to storage configuration parameters.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

uses to storage configuration ...

I guess you've meant: "uses to store configuration..."

*/
void esp_init_nvs()
{
esp_err_t ret = nvs_flash_init();
if(ret == ESP_ERR_NVS_NO_FREE_PAGES || ret == ESP_ERR_NVS_NEW_VERSION_FOUND) {
Expand All @@ -48,51 +48,74 @@ void esp_init_flash()
ESP_ERROR_CHECK(ret);
}

/*
* Initialise default WiFi stack
*/
void esp_init_wifi()
{
esp_netif_init();
esp_event_loop_create_default();

if(wifiEventHandler != nullptr) {
ESP_ERROR_CHECK(esp_event_handler_register(WIFI_EVENT, ESP_EVENT_ANY_ID, wifiEventHandler, nullptr));
ESP_ERROR_CHECK(esp_event_handler_register(IP_EVENT, IP_EVENT_STA_GOT_IP, wifiEventHandler, nullptr));
}
wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT();
ESP_ERROR_CHECK(esp_wifi_init(&cfg));
}
#endif

void main(void*)
{
assert(esp_task_wdt_init(WDT_TIMEOUT_MS, true) == ESP_OK);
assert(esp_task_wdt_init(CONFIG_ESP_TASK_WDT_TIMEOUT_S, true) == ESP_OK);
assert(esp_task_wdt_add(NULL) == ESP_OK);
assert(esp_task_wdt_status(NULL) == ESP_OK);

hw_timer_init();

smg_uart_detach_all();

esp_log_set_vprintf(m_vprintf);

auto loop = sming_create_event_loop();

#ifndef DISABLE_WIFI
esp_init_flash();
esp_init_nvs();
esp_init_wifi();
#endif
ets_init_tasks();
Storage::initialize();

System.initialize();
Storage::initialize();
init();

constexpr unsigned maxEventLoopInterval{1000 / portTICK_PERIOD_MS};
while(true) {
esp_task_wdt_reset();
ets_service_tasks();
esp_event_loop_run(loop, maxEventLoopInterval);
}
}

} // namespace

/*
* Called from WiFi event implementation constructor.
* Cannot register directly as event queue hasn't been created yet.
* NOTE: May only be called once.
*/
void wifi_set_event_handler_cb(esp_event_handler_t eventHandler)
{
#ifndef DISABLE_WIFI
wifiEventHandler = eventHandler;
#endif
}

extern void sming_create_task(TaskFunction_t);

extern "C" void app_main(void)
{
#ifdef CONFIG_FREERTOS_UNICORE
xTaskCreate(main, "Sming", ESP32_STACK_SIZE, nullptr, 1, nullptr);
#if defined(SUBARCH_ESP32) && !CONFIG_FREERTOS_UNICORE
constexpr unsigned core_id{1};
#else
esp_task_wdt_delete(xTaskGetIdleTaskHandleForCPU(1));
xTaskCreatePinnedToCore(main, "Sming", ESP32_STACK_SIZE, nullptr, 1, nullptr, 1);
constexpr unsigned core_id{0};
#endif

esp_task_wdt_delete(xTaskGetIdleTaskHandleForCPU(core_id));
xTaskCreatePinnedToCore(main, "Sming", ESP_TASKD_EVENT_STACK, nullptr, ESP_TASKD_EVENT_PRIO, nullptr, core_id);
}
Loading