Skip to content

Commit

Permalink
Merge pull request #10656 from gschorcht/esp8266_ets_handling
Browse files Browse the repository at this point in the history
cpu/esp8266: change of ETS task handling
  • Loading branch information
smlng authored Jan 21, 2019
2 parents 94d6baf + e4b0ace commit e22e582
Show file tree
Hide file tree
Showing 8 changed files with 223 additions and 112 deletions.
20 changes: 10 additions & 10 deletions cpu/esp8266/Makefile.dep
Original file line number Diff line number Diff line change
@@ -1,5 +1,15 @@
# additional modules dependencies

ifneq (, $(filter esp_sdk, $(USEMODULE)))
USEMODULE += core_thread_flags
endif

ifneq (, $(filter esp_spiffs, $(USEMODULE)))
export SPIFFS_STD_OPTION = -std=c99
USEMODULE += spiffs
USEMODULE += vfs
endif

ifneq (, $(filter lua, $(USEPKG)))
USEMODULE += newlib_syscalls_default
USEMODULE += xtimer
Expand Down Expand Up @@ -35,13 +45,3 @@ endif
ifneq (, $(filter newlib_syscalls_default, $(USEMODULE)))
USEMODULE += stdio_uart
endif

# network interface dependencies
ifneq (, $(filter netdev_default, $(USEMODULE)))
# if NETDEV_DEFAULT is empty, we use module mrf24j40 as default network device
ifndef NETDEV_DEFAULT
USEMODULE += mrf24j40
else
USEMODULE += $(NETDEV_DEFAULT)
endif
endif
52 changes: 28 additions & 24 deletions cpu/esp8266/Makefile.include
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,16 @@ endif

ifeq ($(ENABLE_GDBSTUB), 1)
USEMODULE += esp_gdbstub
endif

# SPECIAL module dependencies
# cannot be done in Makefile.dep since Makefile.dep is included too late

ifneq (, $(filter esp_sw_timer, $(USEMODULE)))
USEMODULE += esp_sdk
endif

ifneq (, $(filter esp_gdbstub, $(USEMODULE)))
USEMODULE += esp_gdb
endif

Expand All @@ -39,7 +49,17 @@ PSEUDOMODULES += esp_sdk_int_handling
PSEUDOMODULES += esp_sw_timer
PSEUDOMODULES += esp_spiffs

USEMODULE += esp
USEMODULE += mtd
USEMODULE += periph
USEMODULE += periph_common
USEMODULE += ps
USEMODULE += random
USEMODULE += sdk
USEMODULE += xtensa

ifneq (, $(filter pthread, $(USEMODULE)))
# has to be included before $(ESP8266_NEWLIB_DIR)
INCLUDES += -I$(RIOTBASE)/sys/posix/pthread/include
endif

Expand All @@ -49,13 +69,14 @@ INCLUDES += -I$(RIOTCPU)/$(CPU)
INCLUDES += -I$(RIOTCPU)/$(CPU)/vendor
INCLUDES += -I$(RIOTCPU)/$(CPU)/vendor/espressif

CFLAGS += -DESP_OPEN_SDK
CFLAGS += -DESP_OPEN_SDK -DSCHED_PRIO_LEVELS=32
CFLAGS += -Wno-unused-parameter -Wformat=0
CFLAGS += -mlongcalls -mtext-section-literals -fdata-sections
CFLAGS += -mlongcalls -mtext-section-literals
CFLAGS += -fdata-sections -fzero-initialized-in-bss
ASFLAGS += --longcalls --text-section-literals

ifneq (, $(filter esp_sw_timer, $(USEMODULE)))
USEMODULE += esp_sdk
ifeq (, $(filter esp_sdk_int_handling, $(USEMODULE)))
CFLAGS += -DCONTEXT_SWITCH_BY_INT
endif

ifneq (, $(filter esp_sdk, $(USEMODULE)))
Expand All @@ -70,17 +91,9 @@ ifneq (, $(filter esp_gdbstub, $(USEMODULE)))
endif

ifneq (, $(filter esp_gdb, $(USEMODULE)))
CFLAGS_OPT = -fzero-initialized-in-bss -Og -ggdb -g3
CFLAGS += -Og -ggdb -g3
else
CFLAGS_OPT = -fzero-initialized-in-bss -O2
endif

CFLAGS += $(CFLAGS_OPT)

ifneq (, $(filter esp_spiffs, $(USEMODULE)))
export SPIFFS_STD_OPTION = -std=c99
USEMODULE += spiffs
USEMODULE += vfs
CFLAGS += -Os
endif

ifeq ($(QEMU), 1)
Expand Down Expand Up @@ -115,15 +128,6 @@ LINKFLAGS += -T$(RIOTCPU)/$(CPU)/ld/eagle.rom.addr.v6.ld
LINKFLAGS += -nostdlib -lgcc -u ets_run -Wl,-gc-sections # -Wl,--print-gc-sections
LINKFLAGS += -Wl,--warn-unresolved-symbols

USEMODULE += esp
USEMODULE += mtd
USEMODULE += periph
USEMODULE += periph_common
USEMODULE += ps
USEMODULE += random
USEMODULE += sdk
USEMODULE += xtensa

# configure preflasher to convert .elf to .bin before flashing
FLASH_SIZE = -fs 8m
export PREFLASHER ?= esptool.py
Expand All @@ -143,5 +147,5 @@ else
export FFLAGS += -p $(PORT) -b $(PROGRAMMER_SPEED) write_flash
export FFLAGS += -fm $(FLASH_MODE)
export FFLAGS += 0 $(ELFFILE)-0x00000.bin
export FFLAGS += 0x10000 $(ELFFILE)-0x10000.bin
export FFLAGS += 0x10000 $(ELFFILE)-0x10000.bin; esptool.py -p $(PORT) run
endif
44 changes: 37 additions & 7 deletions cpu/esp8266/doc.txt
Original file line number Diff line number Diff line change
Expand Up @@ -710,13 +710,43 @@ INCLUDES += -I$(APPDIR)

# <a name="esp8266_sdk_task_handling"> SDK Task Handling </a> &nbsp;[[TOC](#esp8266_toc)]

With make command variable ```USE_SDK=1``` the Espressif SDK is used. This is necessary, for example, if you want to use the built-in WLAN module. The SDK internally uses its own tasks (SDK tasks) and its own scheduling mechanism to realize event-driven SDK functions such as WiFi functions and software timers, and to keep the system alive. For this purpose, the SDK regularly executes SDK tasks with pending events in an endless loop using the ROM function ```ets_run```.

Interrupt service routines do not process interrupts directly but use the ```ets_post``` ROM function to send an event to one of these SDK tasks, which then processes the interrupts asynchronously. A context switch is not possible in the interrupt service routines.

In the RIOT port, the task management of the SDK is replaced by the task management of the RIOT. To handle SDK tasks with pending events so that the SDK functions work and the system keeps alive, the ROM functions ```ets_run``` and ```ets_post``` are overwritten. The ```ets_run``` function performs all SDK tasks with pending events exactly once. It is executed at the end of the ```ets_post``` function and thus usually at the end of an SDK interrupt service routine or before the system goes into the lowest power mode.

@note Since the non-SDK version of RIOT is much smaller and faster than the SDK version, you should always compile your application without the SDK (```USE_SDK=0```, the default) if you don't need the built-in WiFi module.
With make command variable `USE_SDK=1`, the Espressif SDK is used. This is
necessary, for example, if you want to use the built-in WLAN module. The
SDK is also used automatically when software timers are used by activating
the `esp_sw_timer` module.

Internally, the SDK uses its own priority-based multitasking sytsem,
the **ETS**, to handle hardware components such as the WiFi interface, or to
implement event-driven functions such as software timers. ETS periodically
executes all ETS tasks with pending events in an infinite loop with the ROM
function `ets_run`.

ETS doesn't process interrupts directly in interrupt service routines.
Instead, they use the `ets_post` ROM function to send an event to one of the
ETS tasks, which then processes the interrupts asynchronously. Context
switches are not possible in interrupt service routines.

To use SDK functions and keep the system alive, ETS tasks with pending events
have to be handled. For that purpose

- the `ets_task_func` RIOT thread with highest possible priority is used
- the ROM functions `ets_run` and `ets_post` are overwritten.

The `ets_task_func` RIOT thread is waiting for a thread flag, which is set
by the `ets_post` function at the end of an ETS interrupt service routine.
The flag indicates that there are ETS tasks with pending events that need
to be executed. The `ets_task_func` RIOT thread then calls the `ets_run`
function, which performs all ETS tasks with pending events exactly once.

Thus, when a hardware component used by the SDK triggers an interrupt, e.g.
the WiFi interface, the interrupt sevice routine posts an event to the ETS
task by calling the `ets_post` function. The overwritten version of this
function sets the thread flag of the `ets_task_func` thread. The thread
then calls function `ets_run` to process pending events.

@note Since the non-SDK version of RIOT is much smaller and faster than the
SDK version, you should always compile your application without the SDK
(```USE_SDK=0```, the default) if you don't need the built-in WiFi module.

# <a name="esp8266_qemu_mode_and_gdb"> QEMU Mode and GDB </a> &nbsp;[[TOC](#esp8266_toc)]

Expand Down
60 changes: 53 additions & 7 deletions cpu/esp8266/include/cpu_conf.h
Original file line number Diff line number Diff line change
Expand Up @@ -29,18 +29,64 @@ extern "C" {
#endif

/**
* @brief Stack size configuration
* @name Stack size configuration
* @{
*/
#ifdef MODULE_ESP_SDK_INT_HANDLING

#ifndef THREAD_EXTRA_STACKSIZE_PRINTF
#define THREAD_EXTRA_STACKSIZE_PRINTF (0)
#define THREAD_STACKSIZE_DEFAULT (2048)
#define THREAD_STACKSIZE_IDLE (2048)
#else
#endif
#ifndef THREAD_STACKSIZE_DEFAULT
#define THREAD_STACKSIZE_DEFAULT (1536)
#endif
#ifndef THREAD_STACKSIZE_IDLE
#define THREAD_STACKSIZE_IDLE (1536)
#endif
#ifndef THREAD_STACKSIZE_MAIN
#define THREAD_STACKSIZE_MAIN (3072)
#endif

#ifndef GNRC_PKTDUMP_STACKSIZE
#define GNRC_PKTDUMP_STACKSIZE (THREAD_STACKSIZE_DEFAULT)
#endif

#ifndef ESP_NOW_STACKSIZE
#define ESP_NOW_STACKSIZE (2560)
#endif

#ifndef ETS_THREAD_STACKSIZE
#define ETS_THREAD_STACKSIZE (2048)
#endif

#else /* MODULE_ESP_SDK_INT_HANDLING */

#ifndef THREAD_EXTRA_STACKSIZE_PRINTF
#define THREAD_EXTRA_STACKSIZE_PRINTF (0)
#define THREAD_STACKSIZE_DEFAULT (2048)
#define THREAD_STACKSIZE_IDLE (2048)
#endif
#ifndef THREAD_STACKSIZE_DEFAULT
#define THREAD_STACKSIZE_DEFAULT (1024)
#endif
#ifndef THREAD_STACKSIZE_IDLE
#define THREAD_STACKSIZE_IDLE (1024)
#endif
#ifndef THREAD_STACKSIZE_MAIN
#define THREAD_STACKSIZE_MAIN (3072)
#endif

#ifndef GNRC_PKTDUMP_STACKSIZE
#define GNRC_PKTDUMP_STACKSIZE (THREAD_STACKSIZE_DEFAULT)
#endif

#ifndef ESP_NOW_STACKSIZE
#define ESP_NOW_STACKSIZE (2560)
#endif

#ifndef ETS_THREAD_STACKSIZE
#define ETS_THREAD_STACKSIZE (1536)
#endif

#endif /* MODULE_ESP_SDK_INT_HANDLING */
/** @} */

/**
Expand All @@ -60,7 +106,7 @@ extern "C" {

#ifdef __cplusplus
}
#endif /* CPU_CONF_H */
#endif

#endif /* CPU_CONF_H */
/** @} */
11 changes: 0 additions & 11 deletions cpu/esp8266/periph/pm.c
Original file line number Diff line number Diff line change
Expand Up @@ -35,10 +35,6 @@ void pm_set_lowest(void)
{
DEBUG ("%s\n", __func__);

/* execute all pending system tasks before going to sleep */
/* is it really necessary, the timer interrupt is thrown every some ms? */
ets_tasks_run ();

#if !defined(QEMU)
DEBUG ("%s enter to sleep @%u\n", __func__, phy_get_mactime());

Expand All @@ -47,13 +43,6 @@ void pm_set_lowest(void)

DEBUG ("%s exit from sleep @%u\n", __func__, phy_get_mactime());
#endif

/*
* We could execute all pending system tasks after an interrupt before
* continuing RIOT. However, to give RIOT tasks the highest priority,
* *ets_tasks_run* should be called only before going to sleep
*/
ets_tasks_run ();
}

void pm_off(void)
Expand Down
Loading

0 comments on commit e22e582

Please sign in to comment.