1
0
mirror of https://github.com/RIOT-OS/RIOT.git synced 2024-12-29 04:50:03 +01:00

cpu/esp8266: changes for RTOS SDK

This commit is contained in:
Gunar Schorcht 2019-09-05 13:35:58 +02:00
parent 074369fbb5
commit ddc91df4ca
58 changed files with 5874 additions and 3071 deletions

View File

@ -12,4 +12,6 @@ ifneq (, $(filter esp_wifi, $(USEMODULE)))
DIRS += esp-wifi
endif
INCLUDES += -I$(ESP8266_SDK_DIR)/components/esp8266/include/internal
include $(RIOTBASE)/Makefile.base

View File

@ -1,17 +1,5 @@
# additional modules dependencies
ifneq (, $(filter esp_sdk, $(USEMODULE)))
USEMODULE += core_thread_flags
INCLUDES += -I$(ESP8266_SDK_DIR)/third_party/include
LINKFLAGS += -Wl,-wrap=malloc
LINKFLAGS += -Wl,-wrap=free
LINKFLAGS += -Wl,-wrap=calloc
LINKFLAGS += -Wl,-wrap=realloc
LINKFLAGS += -Wl,-wrap=_malloc_r
LINKFLAGS += -Wl,-wrap=_free_r
LINKFLAGS += -Wl,-wrap=_realloc_r
endif
ifneq (, $(filter esp_spiffs, $(USEMODULE)))
export SPIFFS_STD_OPTION = -std=c99
USEMODULE += spiffs
@ -19,12 +7,5 @@ ifneq (, $(filter esp_spiffs, $(USEMODULE)))
endif
ifneq (, $(filter esp_wifi, $(USEMODULE)))
CFLAGS += -DLWIP_OPEN_SRC
LINKFLAGS += -Wl,-wrap=ethernet_input
USEMODULE += netdev_eth
endif
ifneq (,$(filter ndn-riot,$(USEPKG)))
USEMODULE += crypto
USEMODULE += cipher_modes
endif

View File

@ -2,6 +2,7 @@
FEATURES_PROVIDED += arch_32bit
FEATURES_PROVIDED += arch_esp8266
FEATURES_PROVIDED += cpp
FEATURES_PROVIDED += periph_cpuid
FEATURES_PROVIDED += periph_hwrng
FEATURES_PROVIDED += periph_pm

View File

@ -1,23 +1,13 @@
# check some environment variables first
ifndef ESP8266_NEWLIB_DIR
$(info ESP8266_NEWLIB_DIR should be defined as /path/to/newlib directory)
$(info ESP8266_NEWLIB_DIR is set by default to /opt/esp/newlib-xtensa)
export ESP8266_NEWLIB_DIR=/opt/esp/newlib-xtensa
endif
ifndef ESP8266_SDK_DIR
$(info ESP8266_SDK_DIR should be defined as /path/to/sdk directory)
$(info ESP8266_SDK_DIR is set by default to /opt/esp/esp-open-sdk/sdk)
export ESP8266_SDK_DIR=/opt/esp/esp-open-sdk/sdk
export ESP8266_SDK_DIR=/opt/esp/ESP8266-RTOS-SDK
endif
# Options to control the compilation
ifeq ($(USE_SDK), 1)
USEMODULE += esp_sdk
endif
ifeq ($(ENABLE_GDB), 1)
USEMODULE += esp_gdb
endif
@ -29,35 +19,37 @@ 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_wifi, $(USEMODULE)))
ifneq (, $(filter esp_now esp_wifi, $(USEMODULE)))
$(eval GNRC_NETIF_NUMOF=$(shell echo $$(($(GNRC_NETIF_NUMOF)+1))))
USEMODULE += esp_sdk
USEMODULE += netopt
endif
ifneq (, $(filter esp_now, $(USEMODULE)))
$(eval GNRC_NETIF_NUMOF=$(shell echo $$(($(GNRC_NETIF_NUMOF)+1))))
USEMODULE += esp_sdk
USEMODULE += esp_wifi_any
USEMODULE += netopt
USEMODULE += xtimer
endif
ifneq (, $(filter esp_gdbstub, $(USEMODULE)))
USEMODULE += esp_gdb
endif
ifneq (, $(filter spiffs, $(USEMODULE)))
export RIOT_TEST_TIMEOUT = 300
endif
ifneq (, $(filter littlefs, $(USEMODULE)))
export RIOT_TEST_TIMEOUT = 300
endif
# regular Makefile
export TARGET_ARCH ?= xtensa-lx106-elf
# ESP8266 pseudomodules
PSEUDOMODULES += esp_gdb
PSEUDOMODULES += esp_sdk
PSEUDOMODULES += esp_log_colored
PSEUDOMODULES += esp_log_tagged
PSEUDOMODULES += esp_qemu
PSEUDOMODULES += esp_sw_timer
PSEUDOMODULES += esp_spiffs
PSEUDOMODULES += esp_wifi_any
USEMODULE += esp_freertos
USEMODULE += esp_idf
@ -66,54 +58,78 @@ USEMODULE += esp_idf_nvs_flash
USEMODULE += esp_idf_spi_flash
USEMODULE += esp_idf_util
USEMODULE += esp_idf_wpa_supplicant_crypto
USEMODULE += esp_sdk
USEMODULE += log
USEMODULE += mtd
USEMODULE += newlib
USEMODULE += newlib_nano
USEMODULE += newlib_syscalls_default
USEMODULE += periph
USEMODULE += periph_common
USEMODULE += periph_hrng
USEMODULE += periph_flash
USEMODULE += periph_uart
USEMODULE += ps
USEMODULE += random
USEMODULE += sdk
USEMODULE += stdio_uart
USEMODULE += xtensa
ifneq (, $(filter pthread, $(USEMODULE)))
# has to be included before $(ESP8266_NEWLIB_DIR)
INCLUDES += -I$(RIOTBASE)/sys/posix/pthread/include
endif
INCLUDES += -I$(ESP8266_NEWLIB_DIR)/$(TARGET_ARCH)/include
INCLUDES += -I$(RIOTBOARD)/common/$(CPU)/include
INCLUDES += -I$(RIOTCPU)/esp_common/vendor/
INCLUDES += -I$(RIOTCPU)/$(CPU)
INCLUDES += -I$(RIOTCPU)/$(CPU)/include
INCLUDES += -I$(RIOTCPU)/$(CPU)/include/freertos
INCLUDES += -I$(RIOTCPU)/$(CPU)/vendor
INCLUDES += -I$(RIOTCPU)/$(CPU)/vendor/espressif
INCLUDES += -I$(RIOTCPU)/$(CPU)/vendor/esp-idf/
INCLUDES += -I$(RIOTCPU)/$(CPU)/vendor/esp-idf/bootloader_support/include
INCLUDES += -I$(RIOTCPU)/$(CPU)/vendor/esp-idf/esp8266/include
INCLUDES += -I$(RIOTCPU)/$(CPU)/vendor/esp-idf/esp8266/include/esp8266
INCLUDES += -I$(RIOTCPU)/$(CPU)/vendor/esp-idf/heap/include
INCLUDES += -I$(RIOTCPU)/$(CPU)/vendor/esp-idf/log/include
INCLUDES += -I$(ESP8266_SDK_DIR)/components/
INCLUDES += -I$(ESP8266_SDK_DIR)/components/bootloader_support/include/
INCLUDES += -I$(ESP8266_SDK_DIR)/components/esp8266/include
INCLUDES += -I$(ESP8266_SDK_DIR)/components/esp8266/include/esp8266
INCLUDES += -I$(ESP8266_SDK_DIR)/components/heap/include
INCLUDES += -I$(ESP8266_SDK_DIR)/components/heap/port/esp8266/include
INCLUDES += -I$(ESP8266_SDK_DIR)/components/nvs_flash/include
INCLUDES += -I$(ESP8266_SDK_DIR)/components/spi_flash/include
CFLAGS += -DESP_OPEN_SDK -DSCHED_PRIO_LEVELS=32 -DCONTEXT_SWITCH_BY_INT
CFLAGS += -DESP_OPEN_SDK -DSCHED_PRIO_LEVELS=32 -DDEVELHELP
CFLAGS += -D__ESP_FILE__=__FILE__
CFLAGS += -Wno-unused-parameter -Wformat=0
CFLAGS += -mlongcalls -mtext-section-literals
CFLAGS += -ffunction-sections -fdata-sections -fzero-initialized-in-bss
CFLAGS += -mlongcalls -mtext-section-literals -fstrict-volatile-bitfields
CFLAGS += -fdata-sections -ffunction-sections -fzero-initialized-in-bss
OPTIONAL_CFLAGS_BLACKLIST += -fdiagnostics-color
OPTIONAL_CFLAGS_BLACKLIST += -Wformat-overflow
OPTIONAL_CFLAGS_BLACKLIST += -Wformat-truncation
OPTIONAL_CFLAGS_BLACKLIST += -gz
ASFLAGS += --longcalls --text-section-literals
ifneq (, $(filter esp_sdk, $(USEMODULE)))
INCLUDES += -I$(ESP8266_SDK_DIR)/include
CFLAGS += -DUSE_US_TIMER
endif
# thin archives trigger a reboot loop - see #12258, #12035, #12346
ARFLAGS = rcs
ifneq (, $(filter esp_gdbstub, $(USEMODULE)))
GDBSTUB_DIR ?= $(RIOTCPU)/$(CPU)/vendor/esp-gdbstub
CFLAGS += -DGDBSTUB_FREERTOS=0
CFLAGS += -DGDBSTUB_BREAK_ON_INIT=1
INCLUDES += -I$(GDBSTUB_DIR)
endif
ifneq (, $(filter esp_gdb, $(USEMODULE)))
CFLAGS += -Og -ggdb -g3
CFLAGS_OPT ?= -Og -ggdb -g3
else
CFLAGS += -Os
# TODO should be -Os
# With -Os char arrays have not to be 32-bit word aligned. This leads to
# an alignment exception when the address of an char array is assigned to
# an uint32_t pointer and the pointer is used for the access.
CFLAGS_OPT ?= -O2
endif
CFLAGS += $(CFLAGS_OPT)
ifeq ($(QEMU), 1)
CFLAGS += -DQEMU
USEMODULE += esp_qemu
endif
ifeq ($(FLASH_MODE), qio)
@ -124,51 +140,77 @@ ifeq ($(FLASH_MODE), qout)
CFLAGS += -DFLASH_MODE_QOUT
endif
LINKFLAGS += -L$(ESP8266_NEWLIB_DIR)/$(TARGET_ARCH)/lib
LINKFLAGS += -L$(ESP8266_SDK_DIR)/lib
LINKFLAGS += -L$(ESP8266_RTOS_SDK_DIR)/components/esp8266/lib
LINKFLAGS += $(CFLAGS_OPT)
ifneq (, $(filter esp_sdk, $(USEMODULE)))
LINKFLAGS += -Wl,--start-group $(BINDIR)/sdk.a
ifneq (, $(filter esp_now, $(USEMODULE)))
LINKFLAGS += -lespnow
endif
LINKFLAGS += -lmain -lnet80211 -lcrypto -lwpa2 -lwpa -llwip -lpp -lphy -lc -lhal
LINKFLAGS += -Wl,--end-group
LINKFLAGS += -T$(RIOTCPU)/$(CPU)/ld/esp8266.riot-os.sdk.app.ld
else
LINKFLAGS += -Wl,--start-group -lphy -lhal -lc -Wl,--end-group
LINKFLAGS += -T$(RIOTCPU)/$(CPU)/ld/esp8266.riot-os.no_sdk.app.ld
BASELIBS += -lc -lgcc -lwpa -lcore -lnet80211 -lphy -lpp -lhal -lstdc++
ifneq (, $(filter esp_now, $(USEMODULE)))
BASELIBS += -lespnow
endif
LINKFLAGS += -T$(RIOTCPU)/$(CPU)/ld/eagle.rom.addr.v6.ld
LINKFLAGS += -nostdlib -lgcc -u ets_run -Wl,-gc-sections # -Wl,--print-gc-sections
LINKFLAGS += -u _malloc_r
LINKFLAGS += -nostdlib -Wl,-gc-sections -Wl,-static # -Wl,--print-gc-sections
LINKFLAGS += -T$(RIOTCPU)/$(CPU)/ld/esp8266.rom.ld
LINKFLAGS += -T$(RIOTCPU)/$(CPU)/ld/esp8266.riot-os.ld
LINKFLAGS += -T$(RIOTCPU)/$(CPU)/ld/esp8266.peripherals.ld
ifneq (, $(filter esp_idf_heap, $(USEMODULE)))
LINKFLAGS += -Wl,-wrap=_malloc_r
LINKFLAGS += -Wl,-wrap=_calloc_r
LINKFLAGS += -Wl,-wrap=_free_r
LINKFLAGS += -Wl,-wrap=_realloc_r
endif
# The ELFFILE is the base one used for flashing
FLASHFILE ?= $(ELFFILE)
# configure preflasher to convert .elf to .bin before flashing
FLASH_SIZE = -fs 8m
PREFLASHER ?= esptool.py
PREFFLAGS ?= elf2image $(FLASH_SIZE) $(FLASHFILE)
FLASH_MODE = dout # FIX configuration, DO NOT CHANGE
FLASH_FREQ = 26m # FIX configuration, DO NOT CHANGE
FLASH_SIZE ?= 1MB
FLASHDEPS += preflash
# flasher configuration
ifeq ($(QEMU), 1)
FLASHER = cat
FFLAGS += $(FLASHFILE)-0x00000.bin /dev/zero | head -c $$((0x10000)) | cat -
FFLAGS += $(FLASHFILE)-0x10000.bin /dev/zero | head -c $$((0xfc000)) | cat -
FFLAGS += $(RIOTCPU)/$(CPU)/bin/esp_init_data_default.bin > $(FLASHFILE).bin
PREFLASHER ?= $(ESP8266_SDK_DIR)/components/esptool_py/esptool/esptool.py
PREFFLAGS = --chip esp8266 elf2image
PREFFLAGS += --flash_mode $(FLASH_MODE) --flash_size $(FLASH_SIZE)
PREFFLAGS += --flash_freq $(FLASH_FREQ) --version 3
PREFFLAGS += -o $(FLASHFILE).bin $(FLASHFILE);
PREFFLAGS += echo "" > $(BINDIR)/partitions.csv;
PREFFLAGS += echo "nvs, data, nvs, 0x9000, 0x6000" >> $(BINDIR)/partitions.csv;
PREFFLAGS += echo "phy_init, data, phy, 0xf000, 0x1000" >> $(BINDIR)/partitions.csv;
PREFFLAGS += echo -n "factory, app, factory, 0x10000, " >> $(BINDIR)/partitions.csv;
PREFFLAGS += ls -l $(FLASHFILE).bin | awk '{ print $$5 }' >> $(BINDIR)/partitions.csv;
PREFFLAGS += python $(RIOTCPU)/$(CPU)/vendor/esp-idf/partition_table/gen_esp32part.py
PREFFLAGS += --verify $(BINDIR)/partitions.csv $(BINDIR)/partitions.bin
ifneq (, $(filter esp_log_colored, $(USEMODULE)))
BOOTLOADER ?= bootloader_dout_115200_color.bin
else
FLASH_MODE ?= dout
export PROGRAMMER_SPEED ?= 460800
FLASHER = esptool.py
FFLAGS += -p $(PROG_DEV) -b $(PROGRAMMER_SPEED) write_flash
FFLAGS += -fm $(FLASH_MODE)
FFLAGS += 0 $(FLASHFILE)-0x00000.bin
FFLAGS += 0x10000 $(FLASHFILE)-0x10000.bin; esptool.py -p $(PROG_DEV) run
BOOTLOADER ?= bootloader_dout_115200_no_color.bin
endif
OPTIONAL_CFLAGS_BLACKLIST += -fdiagnostics-color
OPTIONAL_CFLAGS_BLACKLIST += -Wformat-overflow
OPTIONAL_CFLAGS_BLACKLIST += -Wformat-truncation
OPTIONAL_CFLAGS_BLACKLIST += -gz
ifneq (, $(filter esp_qemu, $(USEMODULE)))
FLASHER = dd
FFLAGS += if=/dev/zero bs=1M count=1 | tr "\\000" "\\377" > tmp.bin &&
FFLAGS += cat $(RIOTCPU)/$(CPU)/bin/$(BOOTLOADER) tmp.bin |
FFLAGS += head -c $$((0x8000)) |
FFLAGS += cat - $(BINDIR)/partitions.bin tmp.bin |
FFLAGS += head -c $$((0x10000)) |
FFLAGS += cat - $(FLASHFILE).bin tmp.bin |
FFLAGS += head -c $$((0xfc000)) |
FFLAGS += cat - $(RIOTCPU)/$(CPU)/bin/esp_init_data_default.bin tmp.bin |
FFLAGS += head -c $$((0x100000)) > $(BINDIR)/esp8266flash.bin && rm tmp.bin
else
export PROGRAMMER_SPEED ?= 460800
FLASHER = esptool.py
FFLAGS += --chip esp8266 --port $(PORT) --baud $(PROGRAMMER_SPEED)
FFLAGS += --before default_reset --after hard_reset write_flash -z
FFLAGS += --flash_size detect
FFLAGS += --flash_mode $(FLASH_MODE) --flash_freq $(FLASH_FREQ)
FFLAGS += 0x0000 $(RIOTCPU)/$(CPU)/bin/$(BOOTLOADER)
FFLAGS += 0x8000 $(BINDIR)/partitions.bin
FFLAGS += 0x10000 $(FLASHFILE).bin
endif

File diff suppressed because it is too large Load Diff

View File

@ -1,3 +1,7 @@
MODULE=esp_wifi
# we have to do it in that way to avoid that pkg/lwip is found first
CFLAGS += -I$(ESP8266_SDK_DIR)/components/lwip/lwip/src/include
CFLAGS += -I$(ESP8266_SDK_DIR)/components/lwip/port/esp8266/include/
include $(RIOTBASE)/Makefile.base

View File

@ -34,7 +34,7 @@ make -C examples/gnrc_networking BOARD=...
```
@note The Wifi network interface (module `esp_wifi`) and the
\ref esp32_esp_now_network_interface "ESP-NOW network interface" (module `esp_now`)
\ref esp8266_esp_now_network_interface "ESP-NOW network interface" (module `esp_now`)
can be used simultaneously, for example, to realize a border router for
a mesh network which uses ESP-NOW.
*/

File diff suppressed because it is too large Load Diff

View File

@ -11,7 +11,7 @@
* @{
*
* @file
* @brief Network device driver for the ESP8266 WiFi interface
* @brief Network device driver for the ESP32 WiFi interface
*
* @author Gunar Schorcht <gunar@schorcht.net>
*/
@ -20,35 +20,46 @@
#define ESP_WIFI_NETDEV_H
#include "net/netdev.h"
#include "ringbuffer.h"
#ifdef __cplusplus
extern "C" {
#endif
/**
* @brief State of the WiFi interface
* @brief Buffer size used for RX buffering
*/
typedef enum {
ESP_WIFI_NOT_WORKING, /**< interface is not working correctly */
ESP_WIFI_DISCONNECTED, /**< interface is not associated to the AP */
ESP_WIFI_CONNECTING, /**< interface is trying an association to the AP */
ESP_WIFI_CONNECTED /**< interface is not associated to the AP */
} esp_wifi_state_t;
#ifndef ESP_WIFI_BUFSIZE
#define ESP_WIFI_BUFSIZE (ETHERNET_MAX_LEN << 1)
#endif
/**
* @brief Device descriptor for ESP infrastructure mode WIFI device
* @brief Reference to the netdev device driver struct
*/
extern const netdev_driver_t esp_wifi_driver;
/**
* @brief Device descriptor for ESP WiFi devices
*/
typedef struct
{
netdev_t netdev; /**< netdev parent struct */
netdev_t netdev; /**< netdev parent struct */
uint8_t mac[ETHERNET_ADDR_LEN]; /**< MAC address of the device */
uint8_t rx_mem[ESP_WIFI_BUFSIZE]; /**< memory holding incoming packages */
ringbuffer_t rx_buf; /**< ringbuffer for incoming packages */
uint8_t rx_buf[ETHERNET_MAX_LEN]; /**< receive buffer */
uint16_t rx_len; /**< number of bytes received from lwIP */
uint16_t tx_len; /**< number of bytes in transmit buffer */
uint8_t tx_buf[ETHERNET_MAX_LEN]; /**< transmit buffer */
esp_wifi_state_t state; /**< indicates the interface state */
uint32_t event; /**< received event */
uint8_t event_recv; /**< number of frame received events */
uint8_t event_conn; /**< number of pending connect events */
uint8_t event_disc; /**< number of pending disc events */
bool connected; /**< indicates whether connected to AP */
gnrc_netif_t* netif; /**< reference to the corresponding netif */
mutex_t dev_lock; /**< device is already in use */
} esp_wifi_netdev_t;

View File

@ -12,7 +12,7 @@
* @{
*
* @file
* @brief Parameters for the ESP8266 WiFi netdev interface
* @brief Parameters for the ESP32 WiFi netdev interface
*
* @author Gunar Schorcht <gunar@schorcht.net>
*/
@ -20,10 +20,10 @@
#ifndef ESP_WIFI_PARAMS_H
#define ESP_WIFI_PARAMS_H
#if MODULE_ESP_WIFI || DOXYGEN
#if defined(MODULE_ESP_WIFI) || defined(DOXYGEN)
/**
* @name Set default configuration parameters for the ESP WIFI netdev driver
* @name Set default configuration parameters for the ESP WiFi netdev driver
* @{
*/
@ -31,30 +31,32 @@
* @brief The size of the stack used for the ESP WIFI netdev driver thread.
*/
#ifndef ESP_WIFI_STACKSIZE
#define ESP_WIFI_STACKSIZE (1536)
#define ESP_WIFI_STACKSIZE (THREAD_STACKSIZE_DEFAULT)
#endif
/**
* @brief The priority of the ESP WiFi netdev driver thread. Should not be changed.
*/
#ifndef ESP_WIFI_PRIO
#define ESP_WIFI_PRIO (GNRC_NETIF_PRIO)
#define ESP_WIFI_PRIO (GNRC_NETIF_PRIO)
#endif
/**
* @brief SSID of the AP to be used.
*/
#ifndef ESP_WIFI_SSID
#define ESP_WIFI_SSID "RIOT_AP"
#define ESP_WIFI_SSID "RIOT_AP"
#endif
/**
* @brief Passphrase used for the AP (max. 64 chars).
* @brief Passphrase used for the AP as clear text (max. 64 chars).
*/
#ifndef ESP_WIFI_PASS
#define ESP_WIFI_PASS "ThisistheRIOTporttoESP"
#define ESP_WIFI_PASS "ThisistheRIOTporttoESP"
#endif
/**@}*/
#ifdef __cplusplus
extern "C" {
#endif

103
cpu/esp8266/esp_events.c Normal file
View File

@ -0,0 +1,103 @@
/*
* Copyright (C) 2019 Gunar Schorcht
*
* This file is subject to the terms and conditions of the GNU Lesser
* General Public License v2.1. See the file LICENSE in the top level
* directory for more details.
*/
/**
* @ingroup cpu_esp8266
* @{
*
* @file
* @brief ESP system event handler
*
* @author Gunar Schorcht <gunar@schorcht.net>
*
* @}
*/
#if defined(MODULE_ESP_WIFI_ANY) || defined(MODULE_ESP_ETH)
#define ENABLE_DEBUG 0
#include "debug.h"
#include <string.h>
#include "esp_common.h"
#include "log.h"
#include "esp_attr.h"
#include "esp_event_loop.h"
#include "irq_arch.h"
#define MAX_HANDLER_NUM 5
static system_event_cb_t _handler[MAX_HANDLER_NUM] = {};
static void* _handler_arg[MAX_HANDLER_NUM] = {};
esp_err_t esp_system_event_add_handler (system_event_cb_t handler, void *arg)
{
int i;
/* determine next free handler entry */
for (i = 0; i < MAX_HANDLER_NUM; i++) {
if (_handler[i] == NULL) {
break;
}
}
/* return if there is no free entry */
if (i == MAX_HANDLER_NUM) {
return ESP_FAIL;
}
/* set the handler and argument entry */
_handler[i] = handler;
_handler_arg[i] = arg;
return ESP_OK;
}
esp_err_t esp_system_event_del_handler (system_event_cb_t handler)
{
int i;
/* determine the handler entry */
for (i = 0; i < MAX_HANDLER_NUM; i++) {
if (_handler[i] == handler) {
break;
}
}
/* return if entry was not found */
if (i == MAX_HANDLER_NUM) {
return ESP_FAIL;
}
/* clean handler and arg entry */
_handler[i] = NULL;
_handler_arg[i] = NULL;
return ESP_OK;
}
static esp_err_t esp_system_event_handler(void *ctx, system_event_t *event)
{
for (int i = 0; i < MAX_HANDLER_NUM; i++) {
if (_handler[i] != NULL) {
_handler[i](_handler_arg[i], event);
}
}
return ESP_OK;
}
#endif
void esp_event_handler_init(void)
{
#if defined(MODULE_ESP_WIFI_ANY) || defined(MODULE_ESP_ETH)
esp_event_loop_init(esp_system_event_handler, NULL);
#endif
}

View File

@ -1,5 +1,5 @@
/*
* Copyright (C) 2018 Gunar Schorcht
* Copyright (C) 2019 Gunar Schorcht
*
* This file is subject to the terms and conditions of the GNU Lesser
* General Public License v2.1. See the file LICENSE in the top level
@ -17,87 +17,144 @@
* @}
*/
#define ENABLE_DEBUG 0
#define ENABLE_DEBUG (0)
#include "debug.h"
#include <malloc.h>
#include <string.h>
#include <stdlib.h>
#include "common.h"
#include "log.h"
#include "periph/pm.h"
#include "ps.h"
#include "esp_common.h"
#include "esp/common_macros.h"
#include "esp/xtensa_ops.h"
#include "sdk/ets.h"
#include "tools.h"
#include "xtensa/corebits.h"
#include "xtensa/xtensa_api.h"
extern void heap_stats(void);
static const char* exception_names [] =
{
"IllegalInstructionCause", /* 0 */
"SyscallCause", /* 1 */
"InstructionFetchErrorCause", /* 2 */
"LoadStoreErrorCause", /* 3 */
"Level1InterruptCause", /* 4 */
"AllocaCause", /* 5 */
"IntegerDivideByZeroCause", /* 6 */
"", /* 7 - reserved */
"PrivilegedCause", /* 8 */
"LoadStoreAlignmentCause", /* 9 */
"", /* 10 - reserved */
"", /* 11 - reserved */
"InstrPIFDataErrorCause", /* 12 */
"LoadStorePIFDataErrorCause", /* 13 */
"InstrPIFAddrErrorCause", /* 14 */
"LoadStorePIFAddrErrorCause", /* 15 */
"InstTLBMissCause", /* 16 */
"InstTLBMultiHitCause", /* 17 */
"InstFetchPrivilegeCause", /* 18 */
"", /* 19 - reserved */
"InstFetchProhibitedCause", /* 20 */
"", /* 21 - reserved */
"", /* 22 - reserved */
"", /* 23 - reserved */
"LoadStoreTLBMissCause", /* 24 */
"LoadStoreTLBMultiHitCause", /* 25 */
"LoadStorePrivilegeCause", /* 26 */
"", /* 27 - reserved */
"LoadProhibitedCause", /* 28 */
"StoreProhibitedCause", /* 29 */
"", /* 30 - reserved */
"", /* 31 - reserved */
"Coprocessor0Disabled", /* 32 */
"Coprocessor1Disabled", /* 33 */
"Coprocessor2Disabled", /* 34 */
"Coprocessor3Disabled", /* 35 */
"Coprocessor4Disabled", /* 36 */
"Coprocessor5Disabled", /* 37 */
"Coprocessor6Disabled", /* 38 */
"Coprocessor7Disabled", /* 39 */
"IllegalInstructionCause", /* 0 */
"SyscallCause", /* 1 */
"InstructionFetchErrorCause", /* 2 */
"LoadStoreErrorCause", /* 3 */
"Level1InterruptCause", /* 4 */
"AllocaCause", /* 5 */
"IntegerDivideByZeroCause", /* 6 */
"", /* 7 - reserved */
"PrivilegedCause", /* 8 */
"LoadStoreAlignmentCause", /* 9 */
"", /* 10 - reserved */
"", /* 11 - reserved */
"InstrPIFDataErrorCause", /* 12 */
"LoadStorePIFDataErrorCause", /* 13 */
"InstrPIFAddrErrorCause", /* 14 */
"LoadStorePIFAddrErrorCause", /* 15 */
"InstTLBMissCause", /* 16 */
"InstTLBMultiHitCause", /* 17 */
"InstFetchPrivilegeCause", /* 18 */
"", /* 19 - reserved */
"InstFetchProhibitedCause", /* 20 */
"", /* 21 - reserved */
"", /* 22 - reserved */
"", /* 23 - reserved */
"LoadStoreTLBMissCause", /* 24 */
"LoadStoreTLBMultiHitCause", /* 25 */
"LoadStorePrivilegeCause", /* 26 */
"", /* 27 - reserved */
"LoadProhibitedCause", /* 28 */
"StoreProhibitedCause", /* 29 */
"", /* 30 - reserved */
"", /* 31 - reserved */
"Coprocessor0Disabled", /* 32 */
"Coprocessor1Disabled", /* 33 */
"Coprocessor2Disabled", /* 34 */
"Coprocessor3Disabled", /* 35 */
"Coprocessor4Disabled", /* 36 */
"Coprocessor5Disabled", /* 37 */
"Coprocessor6Disabled", /* 38 */
"Coprocessor7Disabled", /* 39 */
};
void IRAM NORETURN exception_handler (XtExcFrame *frame)
{
uint32_t excsave1;
uint32_t epc1;
uint32_t epc2;
uint32_t epc3;
RSR(excsave1, excsave1);
RSR(epc1, epc1);
RSR(epc2, epc2);
RSR(epc3, epc3);
ets_printf("EXCEPTION!! exccause=%d (%s) @%08lx excvaddr=%08lx\n",
#ifdef MCU_ESP32
uint32_t epc4;
RSR(epc4, epc4);
#endif
ets_printf("EXCEPTION!! exccause=%d (%s) @%08x excvaddr=%08x\n",
frame->exccause, exception_names[frame->exccause],
excsave1, frame->excvaddr);
#if defined(DEVELHELP)
#if defined(MODULE_PS)
ps();
#endif
print_meminfo();
#endif
/* flushing the buffer */
ets_printf(" \n");
ets_printf(" \n");
ets_printf(" \n");
#if defined(DEVELHELP)
#if defined(MODULE_PS)
ets_printf("processes:\n");
ps();
ets_printf("\n");
#endif /* MODULE_PS */
heap_stats();
ets_printf("\nregister set\n");
ets_printf("pc : %08x\t", frame->pc);
ets_printf("ps : %08x\t", frame->ps);
ets_printf("exccause: %08x\t", frame->exccause);
ets_printf("excvaddr: %08x\n", frame->excvaddr);
ets_printf("epc1 : %08x\t", epc1);
ets_printf("epc2 : %08x\t", epc2);
ets_printf("epc3 : %08x\t", epc3);
#ifdef MCU_ESP32
ets_printf("epc4 : %08x\n", epc4);
#else /* MCU_ESP32 */
ets_printf("epc3 : %08x\n", epc3);
#endif /* MCU_ESP32 */
ets_printf("a0 : %08x\t", frame->a0);
ets_printf("a1 : %08x\t", frame->a1);
ets_printf("a2 : %08x\t", frame->a2);
ets_printf("a3 : %08x\n", frame->a3);
ets_printf("a4 : %08x\t", frame->a4);
ets_printf("a5 : %08x\t", frame->a5);
ets_printf("a6 : %08x\t", frame->a6);
ets_printf("a7 : %08x\n", frame->a7);
ets_printf("a8 : %08x\t", frame->a8);
ets_printf("a9 : %08x\t", frame->a9);
ets_printf("a10 : %08x\t", frame->a10);
ets_printf("a11 : %08x\n", frame->a11);
ets_printf("a12 : %08x\t", frame->a12);
ets_printf("a13 : %08x\t", frame->a13);
ets_printf("a14 : %08x\t", frame->a14);
ets_printf("a15 : %08x\n", frame->a15);
#if XCHAL_HAVE_LOOPS
ets_printf("lbeg : %08x\t", frame->lbeg);
ets_printf("lend : %08x\t", frame->lend);
ets_printf("lcount : %08x\n", frame->lcount);
#endif /* XCHAL_HAVE_LOOPS */
#endif /* DEVELHELP */
/* restart */
/* TODO: Improvement
Normally, we should try to restart the system. However, this
will not work after some exceptions, e.g., the LoadStoreErrorCause.
One option is to break the execution and wait for the WDT reset. Maybe
there is better way. If debugger is active, 'break 0,0' stops the
execution in debugger. */
/* __asm__ volatile ("break 0,0"); */
/* hard reset */
__asm__ volatile (" call0 0x40000080 ");
@ -118,9 +175,7 @@ void init_exceptions (void)
void IRAM NORETURN panic_arch(void)
{
#if defined(DEVELHELP)
print_meminfo();
ets_printf(" \n");
ets_printf(" \n");
heap_stats();
#endif
/* hard reset */
@ -128,3 +183,10 @@ void IRAM NORETURN panic_arch(void)
UNREACHABLE();
}
void _panic_handler(uint32_t addr)
{
ets_printf("#! _xt_panic called from 0x%08x: powering off\n", addr);
pm_off();
while (1) { };
}

View File

@ -60,6 +60,10 @@ QueueHandle_t xQueueGenericCreate( const UBaseType_t uxQueueLength,
uint32_t queue_size = uxQueueLength * uxItemSize;
_queue_t* queue = malloc(sizeof(_queue_t) + queue_size);
if (!queue) {
return NULL;
}
queue->type = ucQueueType;
queue->receiving.next = NULL;
queue->sending.next = NULL;

View File

@ -1,98 +0,0 @@
/*
* Copyright (C) 2018 Gunar Schorcht
*
* This file is subject to the terms and conditions of the GNU Lesser
* General Public License v2.1. See the file LICENSE in the top level
* directory for more details.
*/
/**
* @ingroup cpu_esp8266
* @{
*
* @file
* @brief Common helper macros
*
* @author Gunar Schorcht <gunar@schorcht.net>
*
*/
#ifndef COMMON_H
#define COMMON_H
#ifndef DOXYGEN
#ifdef __cplusplus
extern "C" {
#endif
/** string representation of x */
#ifndef XTSTR
#define _XTSTR(x) # x
#define XTSTR(x) _XTSTR(x)
#endif
#endif
#if !defined(ICACHE_FLASH) || defined (DOXYGEN)
#ifndef ICACHE_RAM_ATTR
/** Places the code with this attribute in the IRAM. */
#define ICACHE_RAM_ATTR __attribute__((section(".iram.text")))
#endif
#else
#ifndef ICACHE_RAM_ATTR
#define ICACHE_RAM_ATTR
#endif
#endif
/** Print out a message that function is not yet implementd */
#define NOT_YET_IMPLEMENTED() LOG_INFO("%s not yet implemented\n", __func__)
/** Print out a message that function is not supported */
#define NOT_SUPPORTED() LOG_INFO("%s not supported\n", __func__)
#if defined(ENABLE_DEBUG) || defined(DOXYGEN)
/**
* @brief Parameter check with return a value.
*
* If ENABLE_DEBUG is true, the macro checks a condition and returns with a value
* if the condition is not fulfilled.
* @param cond the condition
* @param err the return value in the case the condition is not fulfilled.
*/
#define CHECK_PARAM_RET(cond,err) if (!(cond)) \
{ \
DEBUG("%s\n", "parameter condition (" #cond ") not fulfilled"); \
return err; \
}
/**
* @brief Parameter check without return value.
*
* If ENABLE_DEBUG is true, the macro checks a condition and returns without a
* value if the condition is not fulfilled.
* @param cond the condition
*/
#define CHECK_PARAM(cond) if (!(cond)) \
{ \
DEBUG("%s\n", "parameter condition (" #cond ") not fulfilled"); \
return; \
}
#else
#define CHECK_PARAM_RET(cond,err) if (!(cond)) return err;
#define CHECK_PARAM(cond) if (!(cond)) return;
#endif
#define LOG_TAG_ERROR(tag, fmt, ...) LOG_ERROR("[%s] " fmt, tag, ##__VA_ARGS__)
#define LOG_TAG_WARNING(tag, fmt, ...) LOG_WARNING("[%s] " fmt, tag, ##__VA_ARGS__)
#define LOG_TAG_INFO(tag, fmt, ...) LOG_INFO("[%s] " fmt, tag, ##__VA_ARGS__)
#define LOG_TAG_DEBUG(tag, fmt, ...) LOG_DEBUG("[%s] " fmt, tag, ##__VA_ARGS__)
/** @} */
#ifdef __cplusplus
}
#endif
#endif /* COMMON_H */

View File

@ -1,5 +1,5 @@
/*
* Copyright (C) 2018 Gunar Schorcht
* Copyright (C) 2019 Gunar Schorcht
*
* This file is subject to the terms and conditions of the GNU Lesser
* General Public License v2.1. See the file LICENSE in the top level

View File

@ -1,5 +1,5 @@
/*
* Copyright (C) 2018 Gunar Schorcht
* Copyright (C) 2019 Gunar Schorcht
*
* This file is subject to the terms and conditions of the GNU Lesser
* General Public License v2.1. See the file LICENSE in the top level
@ -29,7 +29,16 @@ extern "C" {
#endif
/**
* @name Stack size configuration
* @brief Defines the CPU frequency in MHz
*
* Possible values are 80 and 160 MHz.
*/
#ifndef ESP8266_CPU_FREQUENCY
#define ESP8266_CPU_FREQUENCY (80)
#endif
/**
* @name Stack size configurations
* @{
*/
#ifndef THREAD_EXTRA_STACKSIZE_PRINTF
@ -49,16 +58,12 @@ extern "C" {
#define GNRC_IPV6_STACK_SIZE (1536)
#endif
#ifndef GNRC_PKTDUMP_STACKSIZE
#define GNRC_PKTDUMP_STACKSIZE (THREAD_STACKSIZE_DEFAULT)
#define GNRC_PKTDUMP_STACKSIZE (THREAD_STACKSIZE_DEFAULT << 1)
#endif
#ifndef ESP_NOW_STACKSIZE
#define ESP_NOW_STACKSIZE (2560)
#endif
#ifndef ETS_THREAD_STACKSIZE
#define ETS_THREAD_STACKSIZE (1536)
#endif
/** @} */
/**
@ -66,16 +71,6 @@ extern "C" {
*/
#define PRINTF_BUFSIZ 256
/* Following include is neccessary to overwrite newlib's PRI*8 and PRI*32. */
/* PLEASE NOTE: ets_vprintf does not understand %i %li, or %hi */
#ifndef DOXYGEN
#include <inttypes.h>
#undef __INT8
#define __INT8
#undef __INT32
#define __INT32
#endif
#ifdef __cplusplus
}
#endif

View File

@ -0,0 +1,130 @@
/*
* Copyright (C) 2019 Gunar Schorcht
*
* This file is subject to the terms and conditions of the GNU Lesser
* General Public License v2.1. See the file LICENSE in the top level
* directory for more details.
*/
/**
* @ingroup cpu_esp8266
* @{
*
* @file
* @brief Common helper macros
*
* @author Gunar Schorcht <gunar@schorcht.net>
*
*/
#ifndef ESP_COMMON_H
#define ESP_COMMON_H
#ifndef DOXYGEN
#ifdef __cplusplus
extern "C" {
#endif
#include "log.h"
#include "esp_common_log.h"
#define asm __asm__
/** string representation of x */
#ifndef XTSTR
#define _XTSTR(x) # x
#define XTSTR(x) _XTSTR(x)
#endif /* XSTR */
#if !defined(ICACHE_FLASH)
#ifndef ICACHE_RAM_ATTR
/** Places the code with this attribute in the IRAM. */
#define ICACHE_RAM_ATTR __attribute__((section(".iram0.text")))
#endif
#else /* ICACHE_FLASH */
#ifndef ICACHE_RAM_ATTR
#define ICACHE_RAM_ATTR
#endif
#endif /* ICACHE_FLASH */
/** Print out a message that function is not yet implementd */
#define NOT_YET_IMPLEMENTED() LOG_INFO("%s not yet implemented\n", __func__)
/** Print out a message that function is not supported */
#define NOT_SUPPORTED() LOG_INFO("%s not supported\n", __func__)
#if ENABLE_DEBUG
/**
* @brief Parameter check with return a value.
*
* If ENABLE_DEBUG is true, the macro checks a condition and returns with a value
* if the condition is not fulfilled.
* @param cond the condition
* @param err the return value in the case the condition is not fulfilled.
*/
#define CHECK_PARAM_RET(cond,err) if (!(cond)) \
{ \
DEBUG("%s parameter condition (" #cond ") " \
"not fulfilled\n", __func__); \
return err; \
}
/**
* @brief Parameter check without return value.
*
* If ENABLE_DEBUG is true, the macro checks a condition and returns without a
* value if the condition is not fulfilled.
* @param cond the condition
*/
#define CHECK_PARAM(cond) if (!(cond)) \
{ \
DEBUG("%s parameter condition (" #cond ") " \
"not fulfilled\n", __func__); \
return; \
}
#else /* ENABLE_DEBUG */
#define CHECK_PARAM_RET(cond,err) if (!(cond)) return err;
#define CHECK_PARAM(cond) if (!(cond)) return;
#endif /* ENABLE_DEBUG */
/** gives the minimum of a and b */
#ifndef MIN
#define MIN(a,b) ((a) < (b) ? (a) : (b))
#endif
/** gives the maximum of a and b */
#ifndef MAX
#define MAX(a,b) ((a) > (b) ? (a) : (b))
#endif
/**
* @brief function name mappings for source code compatibility with ESP8266 port
* @{
*/
#ifdef MCU_ESP32
#define system_get_cpu_freq ets_get_cpu_frequency
#define system_update_cpu_freq ets_update_cpu_frequency
#endif /* MCU_ESP32 */
/** @} */
/** @} */
/** microseconds per millisecond */
#ifndef USEC_PER_MSEC
#define USEC_PER_MSEC 1000UL
#endif
#ifndef MSEC_PER_SEC
#define MSEC_PER_SEC 1000UL
#endif
#ifdef __cplusplus
}
#endif
#endif /* DOXYGEN */
#endif /* ESP_COMMON_H */

View File

@ -0,0 +1,150 @@
/*
* Copyright (C) 2019 Gunar Schorcht
*
* This file is subject to the terms and conditions of the GNU Lesser
* General Public License v2.1. See the file LICENSE in the top level
* directory for more details.
*/
/**
* @ingroup cpu_esp8266
* @{
*
* @file
* @brief Common log macros
*
* @author Gunar Schorcht <gunar@schorcht.net>
*
*/
#ifndef ESP_COMMON_LOG_H
#define ESP_COMMON_LOG_H
#ifndef DOXYGEN
#ifdef __cplusplus
extern "C" {
#endif
#include <stdio.h>
#include <stdint.h>
#include "log.h"
extern uint32_t system_get_time_ms (void);
extern int ets_printf(const char *fmt, ...);
#if MODULE_ESP_LOG_COLORED
#define LOG_RESET_COLOR "\033[0m"
#define LOG_COLOR_E "\033[1;31m"
#define LOG_COLOR_W "\033[1;33m"
#define LOG_COLOR_I "\033[1m"
#define LOG_COLOR_D "\033[0;32m"
#define LOG_COLOR_V
#else /* MODULE_ESP_LOG_COLORED */
#define LOG_RESET_COLOR
#define LOG_COLOR_E
#define LOG_COLOR_W
#define LOG_COLOR_I
#define LOG_COLOR_D
#define LOG_COLOR_V
#endif /* MODULE_ESP_LOG_COLORED */
#if MODULE_ESP_LOG_TAGGED
#define LOG_FORMAT(letter, format) LOG_COLOR_ ## letter #letter " (%d) [%s] " format LOG_RESET_COLOR
#define LOG_TAG(level, letter, tag, format, ...) \
do { \
if ((unsigned)level <= (unsigned)LOG_LEVEL) { \
printf(LOG_FORMAT(letter, format), system_get_time_ms(), tag, ##__VA_ARGS__); \
fflush(stdout); \
} \
} while(0)
#define LOG_TAG_EARLY(level, letter, tag, format, ...) \
do { \
if (LOG_LEVEL >= level) { \
ets_printf(LOG_FORMAT(letter, format), system_get_time_ms(), tag, ##__VA_ARGS__); \
} \
} while(0)
#else /* MODULE_ESP_LOG_TAGGED */
#define LOG_FORMAT(letter, format) LOG_COLOR_ ## letter format LOG_RESET_COLOR
#define LOG_TAG(level, letter, tag, format, ...) \
do { \
(void)tag; \
if ((unsigned)level <= (unsigned)LOG_LEVEL) { \
printf(LOG_FORMAT(letter, format), ##__VA_ARGS__); \
fflush(stdout); \
} \
} while (0U)
#define LOG_TAG_EARLY(level, letter, tag, format, ...) \
do { \
(void)tag; \
if ((unsigned)level <= (unsigned)LOG_LEVEL) { \
ets_printf(LOG_FORMAT(letter, format), ##__VA_ARGS__); \
} \
} while (0U)
#endif /* MODULE_ESP_LOG_TAGGED */
/**
* Override LOG_* definitions with a tagged version. By default the function
* name is used as tag.
*/
#ifndef MODULE_LOG_PRINTFNOFORMAT
#undef LOG_ERROR
#undef LOG_INFO
#undef LOG_WARNING
#undef LOG_DEBUG
#define LOG_ERROR(format, ...) LOG_TAG(LOG_ERROR , E, __func__, format, ##__VA_ARGS__)
#define LOG_WARNING(format, ...) LOG_TAG(LOG_WARNING, W, __func__, format, ##__VA_ARGS__)
#define LOG_INFO(format, ...) LOG_TAG(LOG_INFO , I, __func__, format, ##__VA_ARGS__)
#define LOG_DEBUG(format, ...) LOG_TAG(LOG_DEBUG , D, __func__, format, ##__VA_ARGS__)
#endif
/** Tagged LOG_* definitions */
#define LOG_TAG_ERROR(tag, format, ...) LOG_TAG(LOG_ERROR , E, tag, format, ##__VA_ARGS__)
#define LOG_TAG_WARNING(tag, format, ...) LOG_TAG(LOG_WARNING, W, tag, format, ##__VA_ARGS__)
#define LOG_TAG_INFO(tag, format, ...) LOG_TAG(LOG_INFO , I, tag, format, ##__VA_ARGS__)
#define LOG_TAG_DEBUG(tag, format, ...) LOG_TAG(LOG_DEBUG , D, tag, format, ##__VA_ARGS__)
/** definitions for source code compatibility with ESP-IDF */
#define ESP_EARLY_LOGE(tag, format, ...) LOG_TAG_EARLY(LOG_ERROR , E, tag, format "\n", ##__VA_ARGS__)
#define ESP_EARLY_LOGW(tag, format, ...) LOG_TAG_EARLY(LOG_WARNING, W, tag, format "\n", ##__VA_ARGS__)
#define ESP_EARLY_LOGI(tag, format, ...) LOG_TAG_EARLY(LOG_INFO , I, tag, format "\n", ##__VA_ARGS__)
#define ESP_LOGE(tag, format, ...) LOG_TAG(LOG_ERROR , E, tag, format "\n", ##__VA_ARGS__)
#define ESP_LOGW(tag, format, ...) LOG_TAG(LOG_WARNING, W, tag, format "\n", ##__VA_ARGS__)
#define ESP_LOGI(tag, format, ...) LOG_TAG(LOG_INFO , I, tag, format "\n", ##__VA_ARGS__)
#if ENABLE_DEBUG
#define ESP_EARLY_LOGD(tag, format, ...) LOG_TAG_EARLY(LOG_DEBUG, D, tag, format "\n", ##__VA_ARGS__)
#define ESP_EARLY_LOGV(tag, format, ...) LOG_TAG_EARLY(LOG_ALL , V, tag, format "\n", ##__VA_ARGS__)
#define ESP_LOGD(tag, format, ...) LOG_TAG(LOG_DEBUG, D, tag, format "\n", ##__VA_ARGS__)
#define ESP_LOGV(tag, format, ...) LOG_TAG(LOG_ALL , V, tag, format "\n", ##__VA_ARGS__)
#else /* ENABLE_DEBUG */
#define ESP_EARLY_LOGD( tag, format, ... ) (void)tag
#define ESP_EARLY_LOGV( tag, format, ... ) (void)tag
#define ESP_LOGD( tag, format, ... ) (void)tag
#define ESP_LOGV( tag, format, ... ) (void)tag
#endif /* ENABLE_DEBUG */
#ifdef __cplusplus
}
#endif
#endif /* DOXYGEN */
#endif /* ESP_COMMON_LOG_H */

View File

@ -1,5 +1,5 @@
/*
* Copyright (C) 2018 Gunar Schorcht
* Copyright (C) 2019 Gunar Schorcht
*
* This file is subject to the terms and conditions of the GNU Lesser
* General Public License v2.1. See the file LICENSE in the top level
@ -24,7 +24,7 @@
extern "C" {
#endif
/** Initalize exception handler */
/** Initialize exception handler */
extern void init_exceptions(void);
#ifdef __cplusplus

View File

@ -0,0 +1,142 @@
/*
* Copyright (C) 2019 Gunar Schorcht
*
* This file is subject to the terms and conditions of the GNU Lesser
* General Public License v2.1. See the file LICENSE in the top level
* directory for more details.
*/
/**
* @ingroup cpu_esp8266
* @{
*
* @file
* @brief Architecture specific GPIO functions for ESP8266
*
* @author Gunar Schorcht <gunar@schorcht.net>
* @}
*/
#ifndef GPIO_ARCH_H
#define GPIO_ARCH_H
#ifdef MCU_ESP32
#include "periph/gpio.h"
#include "soc/io_mux_reg.h"
#include "soc/gpio_sig_map.h"
#endif /* MCU_ESP32 */
#ifndef DOXYGEN
#ifdef __cplusplus
extern "C" {
#endif
/** Definitions for source code compatibility with ESP-IDF */
#define GPIO_MODE_INPUT GPIO_IN
#define GPIO_MODE_OUTPUT GPIO_OUT
#define GPIO_MODE_INPUT_OUTPUT GPIO_IN_OUT
/** Definition of possible GPIO usage types (for internal use only) */
typedef enum
{
_GPIO = 0, /**< pin used as standard GPIO */
#ifdef MCU_ESP32
_ADC, /**< pin used as ADC input */
_CAN, /**< pin used as CAN signal */
_DAC, /**< pin used as DAC output */
_EMAC, /**< pin used as EMAC signal */
#endif /* MCU_ESP32 */
_I2C, /**< pin used as I2C signal */
_PWM, /**< pin used as PWM output */
_SPI, /**< pin used as SPI interface */
_SPIF, /**< pin used as SPI flash interface */
_UART, /**< pin used as UART interface */
_NOT_EXIST /**< pin cannot be used at all */
} gpio_pin_usage_t;
#ifdef MCU_ESP32
/** Table of GPIO to IOMUX register mappings */
extern const uint32_t _gpio_to_iomux_reg[];
#define GPIO_PIN_MUX_REG _gpio_to_iomux_reg
#else /* MCU_ESP32 */
/** Map of GPIO pin numbers to IOMUX pin numbers */
extern const uint8_t _gpio_to_iomux[];
/** Map of IOMUX pin numbers to GPIO pin numbers */
extern const uint8_t _iomux_to_gpio[];
#endif /* MCU_ESP32 */
/**
* @brief Set the usage type of the pin
* @param pin GPIO pin
* @param usage GPIO pin usage type
* @return 0 on success
* -1 on error
*/
int gpio_set_pin_usage(gpio_t pin, gpio_pin_usage_t usage);
/**
* @brief Get the usage type of the pin
* @param pin GPIO pin
* @return GPIO pin usage type on success
* _NOT_EXIST on error
*/
gpio_pin_usage_t gpio_get_pin_usage(gpio_t pin);
/**
* @brief Get the usage type of the pin as string
* @param pin GPIO pin
* @return GPIO pin usage type string on success
* _NOT_EXIST on error
*/
const char* gpio_get_pin_usage_str(gpio_t pin);
#ifdef MCU_ESP32
/**
* @brief Disable the pullup of the pin
*/
void gpio_pullup_dis (gpio_t pin);
/**
* @brief Returns the RTCIO pin number or -1 if the pin is not an RTCIO pin
*/
int8_t gpio_is_rtcio (gpio_t pin);
/**
* @brief Configure sleep mode for an GPIO pin if the pin is an RTCIO pin
* @param pin GPIO pin
* @param mode active in sleep mode if true
* @param input as input if true, as output otherwise
* @return 0 on success
* @return -1 on invalid pin
*/
int gpio_config_sleep_mode (gpio_t pin, bool sleep_mode, bool input);
/**
* @brief GPIO set direction init the pin calling gpio_init
* @param pin GPIO pin
* @param mode active in sleep mode if true
* @return 0 on success
* -1 on invalid argument
*/
int gpio_set_direction(gpio_t pin, gpio_mode_t mode);
/**
* @brief extern declaration of ROM functions to avoid compilation problems
*/
void gpio_matrix_in (uint32_t gpio, uint32_t signal_idx, bool inv);
void gpio_matrix_out(uint32_t gpio, uint32_t signal_idx, bool out_inv, bool oen_inv);
#endif /* MCU_ESP32 */
#ifdef __cplusplus
}
#endif
#endif /* DOXYGEN */
#endif /* GPIO_ARCH_H */

View File

@ -1,5 +1,5 @@
/*
* Copyright (C) 2018 Gunar Schorcht
* Copyright (C) 2019 Gunar Schorcht
*
* This file is subject to the terms and conditions of the GNU Lesser
* General Public License v2.1. See the file LICENSE in the top level
@ -39,9 +39,8 @@ extern uint32_t irq_interrupt_nesting;
/**
* @name Macros to enter and exit an ISR
*
* In non-SDK interrupt handling all stuff is done in `_frxt_int_enter`
* and `_frxt_int_exit`. These macros do therefore nothing and are kept only
* for source code compatibility.
* Since all the stuff is done in `_frxt_int_enter` and `_frxt_int_exit`, these
* macros are doing nothing and are kept only for source code compatibility.
*
* @{
*/
@ -56,10 +55,28 @@ extern uint32_t irq_interrupt_nesting;
*
* @{
*/
#define critical_enter() int _irq_state = irq_disable ()
#define critical_enter() int _irq_state = irq_disable()
#define critical_exit() irq_restore(_irq_state)
/** @} */
/**
* @name Macros to enter and exit a critical region with state variable
* @{
*/
#define critical_enter_var(m) m = irq_disable()
#define critical_exit_var(m) irq_restore(m)
/** @} */
/**
* @name Software interrupt types
*
* These definitions are used to distinguish different types of software
* interrupts in software interrupt handler.
*/
#define ETS_SOFT_INT_NONE 0
#define ETS_SOFT_INT_YIELD 1
#define ETS_SOFT_INT_HDL_MAC 2
#ifdef __cplusplus
}
#endif

View File

@ -0,0 +1,60 @@
/*
* Copyright (C) 2019 Gunar Schorcht
*
* This file is subject to the terms and conditions of the GNU Lesser
* General Public License v2.1. See the file LICENSE in the top level
* directory for more details.
*/
/**
* @ingroup cpu_esp8266
* @{
*
* @file
* @brief Log module to realize consistent log messages
*
* @author Gunar Schorcht <gunar@schorcht.net>
*/
#ifndef LOG_MODULE_H
#define LOG_MODULE_H
#ifdef __cplusplus
extern "C" {
#endif
#include <stdio.h>
#include "esp_common_log.h"
#ifdef MODULE_LOG_PRINTFNOFORMAT
static inline void log_write(unsigned level, const char *format, ...) {
(void)level;
puts(format);
}
#else /* MODULE_LOG_PRINTFNOFORMAT */
#define log_write(level, ...) \
do { \
if (level == LOG_ERROR) { \
LOG_TAG(LOG_ERROR, E, __func__, ##__VA_ARGS__); \
} \
else if (level == LOG_WARNING) { \
LOG_TAG(LOG_WARNING, W, __func__, ##__VA_ARGS__); \
} \
else if (level == LOG_INFO) { \
LOG_TAG(LOG_INFO, D, __func__, ##__VA_ARGS__); \
} \
else if (level == LOG_DEBUG) { \
LOG_TAG(LOG_DEBUG, E, __func__, ##__VA_ARGS__); \
} \
} while (0)
#endif /* MODULE_LOG_PRINTFNOFORMAT */
#ifdef __cplusplus
}
#endif
/**@}*/
#endif /* LOG_MODULE_H */

View File

@ -1,5 +1,5 @@
/*
* Copyright (C) 2018 Gunar Schorcht
* Copyright (C) 2019 Gunar Schorcht
*
* This file is subject to the terms and conditions of the GNU Lesser
* General Public License v2.1. See the file LICENSE in the top level
@ -33,31 +33,55 @@ extern "C" {
#define CPUID_LEN (4U)
/**
* @name GPIO configuration of ESP8266
* @name GPIO configuration
* @{
*/
/**
* @brief Available ports on the ESP8266
* @brief Override the default gpio_t type definition
*
* This is required here to have gpio_t defined in this file.
* @{
*/
#define PORT_GPIO 0 /**< port GPIO */
#define HAVE_GPIO_T
typedef unsigned int gpio_t;
/** @} */
/**
* @brief Definition of a fitting UNDEF value
*/
#define GPIO_UNDEF (GPIO_ID_NONE)
#define GPIO_UNDEF ((gpio_t)(UINT_MAX))
/**
* @brief Define CPU specific GPIO pin generator macro
* @brief Define a CPU specific GPIO pin generator macro
*/
#define GPIO_PIN(x, y) ((x << 4) | y)
#define GPIO_PIN(x, y) ((x & 0) | y)
/**
* @brief Available GPIO ports on ESP8266
*/
#define PORT_GPIO (0)
/**
* @brief Define CPU specific number of GPIO pins
*/
#define GPIO_PIN_NUMOF GPIO_PIN_COUNT+1
#define GPIO_PIN_NUMOF (17)
/**
* @brief Override flank selection values
* @{
*/
#define HAVE_GPIO_FLANK_T
typedef enum {
GPIO_NONE = 0,
GPIO_RISING = 1, /**< emit interrupt on rising flank */
GPIO_FALLING = 2, /**< emit interrupt on falling flank */
GPIO_BOTH = 3, /**< emit interrupt on both flanks */
GPIO_LOW = 4, /**< emit interrupt on low level */
GPIO_HIGH = 5 /**< emit interrupt on low level */
} gpio_flank_t;
/** @} */
/** @} */
/**
* @name Predefined GPIO names
@ -82,51 +106,64 @@ extern "C" {
#define GPIO16 (GPIO_PIN(PORT_GPIO,16))
/** @} */
#ifndef DOXYGEN
#define GPIO0_MASK (BIT(0))
#define GPIO1_MASK (BIT(1))
#define GPIO2_MASK (BIT(2))
#define GPIO3_MASK (BIT(3))
#define GPIO4_MASK (BIT(4))
#define GPIO5_MASK (BIT(5))
#define GPIO6_MASK (BIT(6))
#define GPIO7_MASK (BIT(7))
#define GPIO8_MASK (BIT(8))
#define GPIO9_MASK (BIT(9))
#define GPIO10_MASK (BIT(10))
#define GPIO11_MASK (BIT(11))
#define GPIO12_MASK (BIT(12))
#define GPIO13_MASK (BIT(13))
#define GPIO14_MASK (BIT(14))
#define GPIO15_MASK (BIT(15))
#define GPIO16_MASK (BIT(16))
/**
* @brief Override flank selection values
* @{
*/
#define HAVE_GPIO_FLANK_T
typedef enum {
GPIO_NONE = 0,
GPIO_RISING = 1, /**< emit interrupt on rising flank */
GPIO_FALLING = 2, /**< emit interrupt on falling flank */
GPIO_BOTH = 3, /**< emit interrupt on both flanks */
GPIO_LOW = 4, /**< emit interrupt on low level */
GPIO_HIGH = 5 /**< emit interrupt on low level */
} gpio_flank_t;
/** @} */
#endif /* DOXYGEN */
/** @} */
/**
* @name I2C configuration
*
* ESP8266 provides up to two bit-banging I2C interfaces.
*
* The board-specific configuration of the I2C interface I2C_DEV(n) requires
* the definition of
*
* I2Cn_SPEED, the bus speed,
* I2Cn_SCL, the GPIO used as SCL signal, and
* I2Cn_SDA, the GPIO used as SDA signal,
*
* where n can be 0 or 1. If they are not defined, the I2C interface
* I2C_DEV(n) is not used.
*
* @note The configuration of the I2C interfaces I2C_DEV(n) must be in
* continuous ascending order of n.
*
* I2C_NUMOF is determined automatically from board-specific peripheral
* definitions of I2Cn_SPEED, I2Cn_SCK, and I2Cn_SDA.
*
* @{
*/
#define PERIPH_I2C_NEED_READ_REG
#define PERIPH_I2C_NEED_READ_REGS
#define PERIPH_I2C_NEED_WRITE_REG
#define PERIPH_I2C_NEED_WRITE_REGS
/**
* @brief Override I2C clock speed values
*
* This is required here to have i2c_speed_t defined in this file.
* @{
*/
#define HAVE_I2C_SPEED_T
typedef enum {
I2C_SPEED_LOW = 0, /**< 10 kbit/s */
I2C_SPEED_NORMAL, /**< 100 kbit/s */
I2C_SPEED_FAST, /**< 400 kbit/s */
I2C_SPEED_FAST_PLUS, /**< 1 Mbit/s */
I2C_SPEED_HIGH, /**< not supported */
} i2c_speed_t;
/** @} */
/**
* @brief I2C configuration structure type
*/
typedef struct {
i2c_speed_t speed; /**< I2C bus speed */
gpio_t scl; /**< GPIO used as SCL pin */
gpio_t sda; /**< GPIO used as SDA pin */
} i2c_conf_t;
/**
* @brief Maximum number of I2C interfaces that can be used by board definitions
*/
#define I2C_NUMOF_MAX (2)
#define PERIPH_I2C_NEED_READ_REG /**< i2c_read_reg required */
#define PERIPH_I2C_NEED_READ_REGS /**< i2c_read_regs required */
#define PERIPH_I2C_NEED_WRITE_REG /**< i2c_write_reg required */
#define PERIPH_I2C_NEED_WRITE_REGS /**< i2c_write_regs required */
/** @} */
/**
@ -139,24 +176,114 @@ typedef enum {
/** @} */
/**
* @name SPI configuration
* @name PWM configuration
*
* The hardware implementation of ESP8266 PWM supports only frequencies as
* power of two. Therefore a software implementation of one PWM device
* PWM_DEV(0) with up to 8 PWM channels (#PWM_CHANNEL_NUM_MAX) is used. The
* GPIOs that can be used as PWM channels are defined by #PWM0_GPIOS in board
* definition.
*
* @note The minimum PWM period that can be realized is 10 us or 100.000 PWM
* clock cycles per second. Therefore, the product of frequency and resolution
* should not be greater than 100.000. Otherwise the frequency is scaled down
* automatically.
*
* @{
*/
#if defined(MODULE_PERIPH_SPI)
#define PERIPH_SPI_NEEDS_TRANSFER_BYTE
#define PERIPH_SPI_NEEDS_TRANSFER_REG
#define PERIPH_SPI_NEEDS_TRANSFER_REGS
/**
* @brief Maximum number of PWM devices.
*/
#define PWM_NUMOF_MAX (1)
#endif /* MODULE_PERIPH_SPI */
/**
* @brief Maximum number of channels per PWM device.
*/
#define PWM_CHANNEL_NUM_MAX (8)
/** @} */
/**
* @name SPI configuration
*
* ESP8266 has two SPI controllers:
*
* - _CSPI_ for caching and accessing the flash memory<br>
* - _HSPI_ for peripherals
*
* Thus, _HSPI_ is the only SPI interface that is available for peripherals.
* It is exposed as RIOT's SPI_DEV(0). The pin configuration of the _HSPI_
* interface is fixed as shown in following table.
*
* Signal | Pin
* -- --------|-------
* #SPI0_MISO | GPIO12
* #SPI0_MOSI | GPIO13
* #SPI0_SCK | GPIO14
* #SPI0_CS0 | GPIOn with n = 0, 2, 4, 5, 15, 16 (additionally 9, 10 in DOUT flash mode)
*
* The only pin definition that can be overridden by an application-specific
* board configuration is the CS signal defined by #SPI0_CS0.
*
* @{
*/
/**
* @brief SPI controllers that can be used for peripheral interfaces
*/
typedef enum {
HSPI = 1, /**< HSPI interface controller */
} spi_ctrl_t;
/**
* @brief SPI configuration structure type
*/
typedef struct {
spi_ctrl_t ctrl; /**< SPI controller used for the interface */
gpio_t sck; /**< GPIO used as SCK pin */
gpio_t mosi; /**< GPIO used as MOSI pin */
gpio_t miso; /**< GPIO used as MISO pin */
gpio_t cs; /**< GPIO used as CS0 pin */
} spi_conf_t;
/**
* @brief Maximum number of SPI interfaces
*/
#define SPI_NUMOF_MAX (1)
#define PERIPH_SPI_NEEDS_TRANSFER_BYTE /**< requires function spi_transfer_byte */
#define PERIPH_SPI_NEEDS_TRANSFER_REG /**< requires function spi_transfer_reg */
#define PERIPH_SPI_NEEDS_TRANSFER_REGS /**< requires function spi_transfer_regs */
/** @} */
/**
* @brief Prevent shared timer functions from being used
*/
#define PERIPH_TIMER_PROVIDES_SET
/**
* @name UART configuration
*
* All ESP8266 boards have exactly one UART device with fixed pin mapping.
*
* @{
*/
/**
* @brief UART configuration structure type
*/
typedef struct {
gpio_t txd; /**< GPIO used as TxD pin */
gpio_t rxd; /**< GPIO used as RxD pin */
} uart_conf_t;
/**
* @brief Maximum number of UART interfaces
*/
#define UART_NUMOF_MAX (1)
/** @} */
#ifdef __cplusplus
}
#endif

View File

@ -0,0 +1,86 @@
/*
* Copyright (C) 2019 Gunar Schorcht
*
* This file is subject to the terms and conditions of the GNU Lesser
* General Public License v2.1. See the file LICENSE in the top level
* directory for more details.
*/
/**
* @ingroup cpu_esp8266
* @{
*
* @file
* @brief SDK configuration compatible to the ESP-IDF
*
* This file defines configuration parameters that are only required for source
* code compatibility with the SDK. These configuration parameters are not used
* directly to configure the compilation of RIOT-OS. However, some of them can
* be overrien overridden by application-specific board configuration.
*
* @author Gunar Schorcht <gunar@schorcht.net>
*/
#ifndef SDK_CONF_H
#define SDK_CONF_H
#ifndef DOXYGEN
#include "board.h"
#include "esp_image_format.h"
#ifdef __cplusplus
extern "C" {
#endif
/**
* @brief SDK version number
*
* Determined with `git describe --tags` in `$ESP8266_SDK_DIR`
*/
#define IDF_VER "v3.1-4-g08c234e"
/**
* @name Default console configuration
*
* STDIO_UART_BAUDRATE is used as CONFIG_CONSOLE_UART_BAUDRATE and
* can be overridden by an application specific configuration.
*
* @{
*/
#define CONFIG_CONSOLE_UART_NUM (0)
#ifndef CONFIG_CONSOLE_UART_BAUDRATE
#define CONFIG_CONSOLE_UART_BAUDRATE (STDIO_UART_BAUDRATE)
#endif
/** @} */
#define CONFIG_APP1_SIZE (0xf0000)
#define CONFIG_APP1_OFFSET (0x10000)
#define CONFIG_SOC_IRAM_SIZE (0xc000)
#define CONFIG_TASK_WDT_PANIC
#define CONFIG_TASK_WDT_TIMEOUT_S (15)
#define CONFIG_WIFI_PPT_TASKSTACK_SIZE (3584)
#define CONFIG_MAIN_TASK_STACK_SIZE (2048)
#define CONFIG_EVENT_LOOP_STACK_SIZE (2048)
#define CONFIG_ESP_PHY_CALIBRATION_AND_DATA_STORAGE
#define CONFIG_ESP_PHY_INIT_DATA_IN_PARTITION (0)
#define CONFIG_SPI_FLASH_FREQ (ESP_IMAGE_SPI_SPEED_40M) /* 40 MHz */
#define CONFIG_SPI_FLASH_MODE (ESP_IMAGE_SPI_MODE_DIO) /* DIO mode */
#define CONFIG_SPI_FLASH_SIZE (0x100000)
#define CONFIG_SCAN_AP_MAX (32)
#define CONFIG_USING_NEW_ETS_VPRINTF
#define CONFIG_NEWLIB_STDOUT_LINE_ENDING_CRLF
#ifdef __cplusplus
}
#endif
#endif /* DOXYGEN */
#endif /* SDK_CONF_H */

748
cpu/esp8266/include/stdio.h Normal file
View File

@ -0,0 +1,748 @@
/**
* This file is a modification of the original file to overwrite the *putchar*
* and *getchar* macros in the case the *uart_stdio* module is used. If the
* *uart_stdio* module is used, *putchar* and *getchar* are redirections to
* according *uart_stdio_* functions.
*/
/*
* Copyright (c) 1990 The Regents of the University of California.
* All rights reserved.
*
* Redistribution and use in source and binary forms are permitted
* provided that the above copyright notice and this paragraph are
* duplicated in all such forms and that any documentation,
* advertising materials, and other materials related to such
* distribution and use acknowledge that the software was developed
* by the University of California, Berkeley. The name of the
* University may not be used to endorse or promote products derived
* from this software without specific prior written permission.
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
*
* @(#)stdio.h 5.3 (Berkeley) 3/15/86
*/
/*
* NB: to fit things in six character monocase externals, the
* stdio code uses the prefix `__s' for stdio objects, typically
* followed by a three-character attempt at a mnemonic.
*/
#ifndef STDIO_H
#define STDIO_H
#ifndef DOXYGEN
#ifdef __cplusplus
extern "C" {
#endif
#include "_ansi.h"
#define _FSTDIO /* ``function stdio'' */
#define __need_size_t
#define __need_NULL
#include <sys/cdefs.h>
#include <stddef.h>
#define __need___va_list
#include <stdarg.h>
/*
* <sys/reent.h> defines __FILE, _fpos_t.
* They must be defined there because struct _reent needs them (and we don't
* want reent.h to include this file.
*/
#include <sys/reent.h>
#include <sys/types.h>
_BEGIN_STD_C
typedef __FILE FILE;
#ifdef __CYGWIN__
typedef _fpos64_t fpos_t;
#else
typedef _fpos_t fpos_t;
#ifdef __LARGE64_FILES
typedef _fpos64_t fpos64_t;
#endif
#endif /* !__CYGWIN__ */
#include <sys/stdio.h>
#define __SLBF 0x0001 /* line buffered */
#define __SNBF 0x0002 /* unbuffered */
#define __SRD 0x0004 /* OK to read */
#define __SWR 0x0008 /* OK to write */
/* RD and WR are never simultaneously asserted */
#define __SRW 0x0010 /* open for reading & writing */
#define __SEOF 0x0020 /* found EOF */
#define __SERR 0x0040 /* found error */
#define __SMBF 0x0080 /* _buf is from malloc */
#define __SAPP 0x0100 /* fdopen()ed in append mode - so must write to end */
#define __SSTR 0x0200 /* this is an sprintf/snprintf string */
#define __SOPT 0x0400 /* do fseek() optimisation */
#define __SNPT 0x0800 /* do not do fseek() optimisation */
#define __SOFF 0x1000 /* set iff _offset is in fact correct */
#define __SORD 0x2000 /* true => stream orientation (byte/wide) decided */
#if defined(__CYGWIN__)
#define __SCLE 0x4000 /* convert line endings CR/LF <-> NL */
#endif
#define __SL64 0x8000 /* is 64-bit offset large file */
/* _flags2 flags */
#define __SNLK 0x0001 /* stdio functions do not lock streams themselves */
#define __SWID 0x2000 /* true => stream orientation wide, false => byte, only valid if __SORD in _flags is true */
/*
* The following three definitions are for ANSI C, which took them
* from System V, which stupidly took internal interface macros and
* made them official arguments to setvbuf(), without renaming them.
* Hence, these ugly _IOxxx names are *supposed* to appear in user code.
*
* Although these happen to match their counterparts above, the
* implementation does not rely on that (so these could be renumbered).
*/
#define _IOFBF 0 /* setvbuf should set fully buffered */
#define _IOLBF 1 /* setvbuf should set line buffered */
#define _IONBF 2 /* setvbuf should set unbuffered */
#define EOF (-1)
#ifdef __BUFSIZ__
#define BUFSIZ __BUFSIZ__
#else
#define BUFSIZ 1024
#endif
#ifdef __FOPEN_MAX__
#define FOPEN_MAX __FOPEN_MAX__
#else
#define FOPEN_MAX 20
#endif
#ifdef __FILENAME_MAX__
#define FILENAME_MAX __FILENAME_MAX__
#else
#define FILENAME_MAX 1024
#endif
#ifdef __L_tmpnam__
#define L_tmpnam __L_tmpnam__
#else
#define L_tmpnam FILENAME_MAX
#endif
#ifndef __STRICT_ANSI__
#define P_tmpdir "/tmp"
#endif
#ifndef SEEK_SET
#define SEEK_SET 0 /* set file offset to offset */
#endif
#ifndef SEEK_CUR
#define SEEK_CUR 1 /* set file offset to current plus offset */
#endif
#ifndef SEEK_END
#define SEEK_END 2 /* set file offset to EOF plus offset */
#endif
#define TMP_MAX 26
#define stdin (_REENT->_stdin)
#define stdout (_REENT->_stdout)
#define stderr (_REENT->_stderr)
#define _stdin_r(x) ((x)->_stdin)
#define _stdout_r(x) ((x)->_stdout)
#define _stderr_r(x) ((x)->_stderr)
/*
* Functions defined in ANSI C standard.
*/
#ifndef __VALIST
#ifdef __GNUC__
#define __VALIST __gnuc_va_list
#else
#define __VALIST char*
#endif
#endif
FILE * _EXFUN(tmpfile, (void));
char * _EXFUN(tmpnam, (char *));
#if __BSD_VISIBLE || __XSI_VISIBLE || __POSIX_VISIBLE >= 200112
char * _EXFUN(tempnam, (const char *, const char *));
#endif
int _EXFUN(fclose, (FILE *));
int _EXFUN(fflush, (FILE *));
FILE * _EXFUN(freopen, (const char *__restrict, const char *__restrict, FILE *__restrict));
void _EXFUN(setbuf, (FILE *__restrict, char *__restrict));
int _EXFUN(setvbuf, (FILE *__restrict, char *__restrict, int, size_t));
int _EXFUN(fprintf, (FILE *__restrict, const char *__restrict, ...)
_ATTRIBUTE ((__format__ (__printf__, 2, 3))));
int _EXFUN(fscanf, (FILE *__restrict, const char *__restrict, ...)
_ATTRIBUTE ((__format__ (__scanf__, 2, 3))));
int _EXFUN(printf, (const char *__restrict, ...)
_ATTRIBUTE ((__format__ (__printf__, 1, 2))));
int _EXFUN(scanf, (const char *__restrict, ...)
_ATTRIBUTE ((__format__ (__scanf__, 1, 2))));
int _EXFUN(sscanf, (const char *__restrict, const char *__restrict, ...)
_ATTRIBUTE ((__format__ (__scanf__, 2, 3))));
int _EXFUN(vfprintf, (FILE *__restrict, const char *__restrict, __VALIST)
_ATTRIBUTE ((__format__ (__printf__, 2, 0))));
int _EXFUN(vprintf, (const char *, __VALIST)
_ATTRIBUTE ((__format__ (__printf__, 1, 0))));
int _EXFUN(vsprintf, (char *__restrict, const char *__restrict, __VALIST)
_ATTRIBUTE ((__format__ (__printf__, 2, 0))));
int _EXFUN(fgetc, (FILE *));
char * _EXFUN(fgets, (char *__restrict, int, FILE *__restrict));
int _EXFUN(fputc, (int, FILE *));
int _EXFUN(fputs, (const char *__restrict, FILE *__restrict));
int _EXFUN(getc, (FILE *));
int _EXFUN(getchar, (void));
char * _EXFUN(gets, (char *));
int _EXFUN(putc, (int, FILE *));
int _EXFUN(putchar, (int));
int _EXFUN(puts, (const char *));
int _EXFUN(ungetc, (int, FILE *));
size_t _EXFUN(fread, (_PTR __restrict, size_t _size, size_t _n, FILE *__restrict));
size_t _EXFUN(fwrite, (const _PTR __restrict , size_t _size, size_t _n, FILE *));
#ifdef _COMPILING_NEWLIB
int _EXFUN(fgetpos, (FILE *, _fpos_t *));
#else
int _EXFUN(fgetpos, (FILE *__restrict, fpos_t *__restrict));
#endif
int _EXFUN(fseek, (FILE *, long, int));
#ifdef _COMPILING_NEWLIB
int _EXFUN(fsetpos, (FILE *, const _fpos_t *));
#else
int _EXFUN(fsetpos, (FILE *, const fpos_t *));
#endif
long _EXFUN(ftell, ( FILE *));
void _EXFUN(rewind, (FILE *));
void _EXFUN(clearerr, (FILE *));
int _EXFUN(feof, (FILE *));
int _EXFUN(ferror, (FILE *));
void _EXFUN(perror, (const char *));
#ifndef _REENT_ONLY
FILE * _EXFUN(fopen, (const char *__restrict _name, const char *__restrict _type));
int _EXFUN(sprintf, (char *__restrict, const char *__restrict, ...)
_ATTRIBUTE ((__format__ (__printf__, 2, 3))));
int _EXFUN(remove, (const char *));
int _EXFUN(rename, (const char *, const char *));
#ifdef _COMPILING_NEWLIB
int _EXFUN(_rename, (const char *, const char *));
#endif
#endif
#if !defined(__STRICT_ANSI__) || defined(__USE_XOPEN2K)
#ifdef _COMPILING_NEWLIB
int _EXFUN(fseeko, (FILE *, _off_t, int));
_off_t _EXFUN(ftello, ( FILE *));
#else
int _EXFUN(fseeko, (FILE *, off_t, int));
off_t _EXFUN(ftello, ( FILE *));
#endif
#endif
#if __GNU_VISIBLE
int _EXFUN(fcloseall, (_VOID));
#endif
#if !defined(__STRICT_ANSI__) || (__STDC_VERSION__ >= 199901L) || (__cplusplus >= 201103L)
#ifndef _REENT_ONLY
int _EXFUN(asiprintf, (char **, const char *, ...)
_ATTRIBUTE ((__format__ (__printf__, 2, 3))));
char * _EXFUN(asniprintf, (char *, size_t *, const char *, ...)
_ATTRIBUTE ((__format__ (__printf__, 3, 4))));
char * _EXFUN(asnprintf, (char *__restrict, size_t *__restrict, const char *__restrict, ...)
_ATTRIBUTE ((__format__ (__printf__, 3, 4))));
int _EXFUN(asprintf, (char **__restrict, const char *__restrict, ...)
_ATTRIBUTE ((__format__ (__printf__, 2, 3))));
#ifndef diprintf
int _EXFUN(diprintf, (int, const char *, ...)
_ATTRIBUTE ((__format__ (__printf__, 2, 3))));
#endif
int _EXFUN(fiprintf, (FILE *, const char *, ...)
_ATTRIBUTE ((__format__ (__printf__, 2, 3))));
int _EXFUN(fiscanf, (FILE *, const char *, ...)
_ATTRIBUTE ((__format__ (__scanf__, 2, 3))));
int _EXFUN(iprintf, (const char *, ...)
_ATTRIBUTE ((__format__ (__printf__, 1, 2))));
int _EXFUN(iscanf, (const char *, ...)
_ATTRIBUTE ((__format__ (__scanf__, 1, 2))));
int _EXFUN(siprintf, (char *, const char *, ...)
_ATTRIBUTE ((__format__ (__printf__, 2, 3))));
int _EXFUN(siscanf, (const char *, const char *, ...)
_ATTRIBUTE ((__format__ (__scanf__, 2, 3))));
int _EXFUN(snprintf, (char *__restrict, size_t, const char *__restrict, ...)
_ATTRIBUTE ((__format__ (__printf__, 3, 4))));
int _EXFUN(sniprintf, (char *, size_t, const char *, ...)
_ATTRIBUTE ((__format__ (__printf__, 3, 4))));
int _EXFUN(vasiprintf, (char **, const char *, __VALIST)
_ATTRIBUTE ((__format__ (__printf__, 2, 0))));
char * _EXFUN(vasniprintf, (char *, size_t *, const char *, __VALIST)
_ATTRIBUTE ((__format__ (__printf__, 3, 0))));
char * _EXFUN(vasnprintf, (char *, size_t *, const char *, __VALIST)
_ATTRIBUTE ((__format__ (__printf__, 3, 0))));
int _EXFUN(vasprintf, (char **, const char *, __VALIST)
_ATTRIBUTE ((__format__ (__printf__, 2, 0))));
int _EXFUN(vdiprintf, (int, const char *, __VALIST)
_ATTRIBUTE ((__format__ (__printf__, 2, 0))));
int _EXFUN(vfiprintf, (FILE *, const char *, __VALIST)
_ATTRIBUTE ((__format__ (__printf__, 2, 0))));
int _EXFUN(vfiscanf, (FILE *, const char *, __VALIST)
_ATTRIBUTE ((__format__ (__scanf__, 2, 0))));
int _EXFUN(vfscanf, (FILE *__restrict, const char *__restrict, __VALIST)
_ATTRIBUTE ((__format__ (__scanf__, 2, 0))));
int _EXFUN(viprintf, (const char *, __VALIST)
_ATTRIBUTE ((__format__ (__printf__, 1, 0))));
int _EXFUN(viscanf, (const char *, __VALIST)
_ATTRIBUTE ((__format__ (__scanf__, 1, 0))));
int _EXFUN(vscanf, (const char *, __VALIST)
_ATTRIBUTE ((__format__ (__scanf__, 1, 0))));
int _EXFUN(vsiprintf, (char *, const char *, __VALIST)
_ATTRIBUTE ((__format__ (__printf__, 2, 0))));
int _EXFUN(vsiscanf, (const char *, const char *, __VALIST)
_ATTRIBUTE ((__format__ (__scanf__, 2, 0))));
int _EXFUN(vsniprintf, (char *, size_t, const char *, __VALIST)
_ATTRIBUTE ((__format__ (__printf__, 3, 0))));
int _EXFUN(vsnprintf, (char *__restrict, size_t, const char *__restrict, __VALIST)
_ATTRIBUTE ((__format__ (__printf__, 3, 0))));
int _EXFUN(vsscanf, (const char *__restrict, const char *__restrict, __VALIST)
_ATTRIBUTE ((__format__ (__scanf__, 2, 0))));
#endif /* !_REENT_ONLY */
#endif /* !__STRICT_ANSI__ */
/*
* Routines in POSIX 1003.1:2001.
*/
#ifndef __STRICT_ANSI__
#ifndef _REENT_ONLY
FILE * _EXFUN(fdopen, (int, const char *));
#endif
int _EXFUN(fileno, (FILE *));
int _EXFUN(getw, (FILE *));
int _EXFUN(pclose, (FILE *));
FILE * _EXFUN(popen, (const char *, const char *));
int _EXFUN(putw, (int, FILE *));
void _EXFUN(setbuffer, (FILE *, char *, int));
int _EXFUN(setlinebuf, (FILE *));
int _EXFUN(getc_unlocked, (FILE *));
int _EXFUN(getchar_unlocked, (void));
void _EXFUN(flockfile, (FILE *));
int _EXFUN(ftrylockfile, (FILE *));
void _EXFUN(funlockfile, (FILE *));
int _EXFUN(putc_unlocked, (int, FILE *));
int _EXFUN(putchar_unlocked, (int));
#endif /* ! __STRICT_ANSI__ */
/*
* Routines in POSIX 1003.1:200x.
*/
#ifndef __STRICT_ANSI__
# ifndef _REENT_ONLY
# ifndef dprintf
int _EXFUN(dprintf, (int, const char *__restrict, ...)
_ATTRIBUTE ((__format__ (__printf__, 2, 3))));
# endif
FILE * _EXFUN(fmemopen, (void *__restrict, size_t, const char *__restrict));
/* getdelim - see __getdelim for now */
/* getline - see __getline for now */
FILE * _EXFUN(open_memstream, (char **, size_t *));
#if __BSD_VISIBLE || __POSIX_VISIBLE >= 200809
int _EXFUN(renameat, (int, const char *, int, const char *));
#endif
int _EXFUN(vdprintf, (int, const char *__restrict, __VALIST)
_ATTRIBUTE ((__format__ (__printf__, 2, 0))));
# endif
#endif
/*
* Recursive versions of the above.
*/
int _EXFUN(_asiprintf_r, (struct _reent *, char **, const char *, ...)
_ATTRIBUTE ((__format__ (__printf__, 3, 4))));
char * _EXFUN(_asniprintf_r, (struct _reent *, char *, size_t *, const char *, ...)
_ATTRIBUTE ((__format__ (__printf__, 4, 5))));
char * _EXFUN(_asnprintf_r, (struct _reent *, char *__restrict, size_t *__restrict, const char *__restrict, ...)
_ATTRIBUTE ((__format__ (__printf__, 4, 5))));
int _EXFUN(_asprintf_r, (struct _reent *, char **__restrict, const char *__restrict, ...)
_ATTRIBUTE ((__format__ (__printf__, 3, 4))));
int _EXFUN(_diprintf_r, (struct _reent *, int, const char *, ...)
_ATTRIBUTE ((__format__ (__printf__, 3, 4))));
int _EXFUN(_dprintf_r, (struct _reent *, int, const char *__restrict, ...)
_ATTRIBUTE ((__format__ (__printf__, 3, 4))));
int _EXFUN(_fclose_r, (struct _reent *, FILE *));
int _EXFUN(_fcloseall_r, (struct _reent *));
FILE * _EXFUN(_fdopen_r, (struct _reent *, int, const char *));
int _EXFUN(_fflush_r, (struct _reent *, FILE *));
int _EXFUN(_fgetc_r, (struct _reent *, FILE *));
int _EXFUN(_fgetc_unlocked_r, (struct _reent *, FILE *));
char * _EXFUN(_fgets_r, (struct _reent *, char *__restrict, int, FILE *__restrict));
char * _EXFUN(_fgets_unlocked_r, (struct _reent *, char *__restrict, int, FILE *__restrict));
#ifdef _COMPILING_NEWLIB
int _EXFUN(_fgetpos_r, (struct _reent *, FILE *__restrict, _fpos_t *__restrict));
int _EXFUN(_fsetpos_r, (struct _reent *, FILE *, const _fpos_t *));
#else
int _EXFUN(_fgetpos_r, (struct _reent *, FILE *, fpos_t *));
int _EXFUN(_fsetpos_r, (struct _reent *, FILE *, const fpos_t *));
#endif
int _EXFUN(_fiprintf_r, (struct _reent *, FILE *, const char *, ...)
_ATTRIBUTE ((__format__ (__printf__, 3, 4))));
int _EXFUN(_fiscanf_r, (struct _reent *, FILE *, const char *, ...)
_ATTRIBUTE ((__format__ (__scanf__, 3, 4))));
FILE * _EXFUN(_fmemopen_r, (struct _reent *, void *__restrict, size_t, const char *__restrict));
FILE * _EXFUN(_fopen_r, (struct _reent *, const char *__restrict, const char *__restrict));
FILE * _EXFUN(_freopen_r, (struct _reent *, const char *__restrict, const char *__restrict, FILE *__restrict));
int _EXFUN(_fprintf_r, (struct _reent *, FILE *__restrict, const char *__restrict, ...)
_ATTRIBUTE ((__format__ (__printf__, 3, 4))));
int _EXFUN(_fpurge_r, (struct _reent *, FILE *));
int _EXFUN(_fputc_r, (struct _reent *, int, FILE *));
int _EXFUN(_fputc_unlocked_r, (struct _reent *, int, FILE *));
int _EXFUN(_fputs_r, (struct _reent *, const char *__restrict, FILE *__restrict));
int _EXFUN(_fputs_unlocked_r, (struct _reent *, const char *__restrict, FILE *__restrict));
size_t _EXFUN(_fread_r, (struct _reent *, _PTR __restrict, size_t _size, size_t _n, FILE *__restrict));
size_t _EXFUN(_fread_unlocked_r, (struct _reent *, _PTR __restrict, size_t _size, size_t _n, FILE *__restrict));
int _EXFUN(_fscanf_r, (struct _reent *, FILE *__restrict, const char *__restrict, ...)
_ATTRIBUTE ((__format__ (__scanf__, 3, 4))));
int _EXFUN(_fseek_r, (struct _reent *, FILE *, long, int));
int _EXFUN(_fseeko_r,(struct _reent *, FILE *, _off_t, int));
long _EXFUN(_ftell_r, (struct _reent *, FILE *));
_off_t _EXFUN(_ftello_r,(struct _reent *, FILE *));
void _EXFUN(_rewind_r, (struct _reent *, FILE *));
size_t _EXFUN(_fwrite_r, (struct _reent *, const _PTR __restrict, size_t _size, size_t _n, FILE *__restrict));
size_t _EXFUN(_fwrite_unlocked_r, (struct _reent *, const _PTR __restrict, size_t _size, size_t _n, FILE *__restrict));
int _EXFUN(_getc_r, (struct _reent *, FILE *));
int _EXFUN(_getc_unlocked_r, (struct _reent *, FILE *));
int _EXFUN(_getchar_r, (struct _reent *));
int _EXFUN(_getchar_unlocked_r, (struct _reent *));
char * _EXFUN(_gets_r, (struct _reent *, char *));
int _EXFUN(_iprintf_r, (struct _reent *, const char *, ...)
_ATTRIBUTE ((__format__ (__printf__, 2, 3))));
int _EXFUN(_iscanf_r, (struct _reent *, const char *, ...)
_ATTRIBUTE ((__format__ (__scanf__, 2, 3))));
FILE * _EXFUN(_open_memstream_r, (struct _reent *, char **, size_t *));
void _EXFUN(_perror_r, (struct _reent *, const char *));
int _EXFUN(_printf_r, (struct _reent *, const char *__restrict, ...)
_ATTRIBUTE ((__format__ (__printf__, 2, 3))));
int _EXFUN(_putc_r, (struct _reent *, int, FILE *));
int _EXFUN(_putc_unlocked_r, (struct _reent *, int, FILE *));
int _EXFUN(_putchar_unlocked_r, (struct _reent *, int));
int _EXFUN(_putchar_r, (struct _reent *, int));
int _EXFUN(_puts_r, (struct _reent *, const char *));
int _EXFUN(_remove_r, (struct _reent *, const char *));
int _EXFUN(_rename_r, (struct _reent *,
const char *_old, const char *_new));
int _EXFUN(_scanf_r, (struct _reent *, const char *__restrict, ...)
_ATTRIBUTE ((__format__ (__scanf__, 2, 3))));
int _EXFUN(_siprintf_r, (struct _reent *, char *, const char *, ...)
_ATTRIBUTE ((__format__ (__printf__, 3, 4))));
int _EXFUN(_siscanf_r, (struct _reent *, const char *, const char *, ...)
_ATTRIBUTE ((__format__ (__scanf__, 3, 4))));
int _EXFUN(_sniprintf_r, (struct _reent *, char *, size_t, const char *, ...)
_ATTRIBUTE ((__format__ (__printf__, 4, 5))));
int _EXFUN(_snprintf_r, (struct _reent *, char *__restrict, size_t, const char *__restrict, ...)
_ATTRIBUTE ((__format__ (__printf__, 4, 5))));
int _EXFUN(_sprintf_r, (struct _reent *, char *__restrict, const char *__restrict, ...)
_ATTRIBUTE ((__format__ (__printf__, 3, 4))));
int _EXFUN(_sscanf_r, (struct _reent *, const char *__restrict, const char *__restrict, ...)
_ATTRIBUTE ((__format__ (__scanf__, 3, 4))));
char * _EXFUN(_tempnam_r, (struct _reent *, const char *, const char *));
FILE * _EXFUN(_tmpfile_r, (struct _reent *));
char * _EXFUN(_tmpnam_r, (struct _reent *, char *));
int _EXFUN(_ungetc_r, (struct _reent *, int, FILE *));
int _EXFUN(_vasiprintf_r, (struct _reent *, char **, const char *, __VALIST)
_ATTRIBUTE ((__format__ (__printf__, 3, 0))));
char * _EXFUN(_vasniprintf_r, (struct _reent*, char *, size_t *, const char *, __VALIST)
_ATTRIBUTE ((__format__ (__printf__, 4, 0))));
char * _EXFUN(_vasnprintf_r, (struct _reent*, char *, size_t *, const char *, __VALIST)
_ATTRIBUTE ((__format__ (__printf__, 4, 0))));
int _EXFUN(_vasprintf_r, (struct _reent *, char **, const char *, __VALIST)
_ATTRIBUTE ((__format__ (__printf__, 3, 0))));
int _EXFUN(_vdiprintf_r, (struct _reent *, int, const char *, __VALIST)
_ATTRIBUTE ((__format__ (__printf__, 3, 0))));
int _EXFUN(_vdprintf_r, (struct _reent *, int, const char *__restrict, __VALIST)
_ATTRIBUTE ((__format__ (__printf__, 3, 0))));
int _EXFUN(_vfiprintf_r, (struct _reent *, FILE *, const char *, __VALIST)
_ATTRIBUTE ((__format__ (__printf__, 3, 0))));
int _EXFUN(_vfiscanf_r, (struct _reent *, FILE *, const char *, __VALIST)
_ATTRIBUTE ((__format__ (__scanf__, 3, 0))));
int _EXFUN(_vfprintf_r, (struct _reent *, FILE *__restrict, const char *__restrict, __VALIST)
_ATTRIBUTE ((__format__ (__printf__, 3, 0))));
int _EXFUN(_vfscanf_r, (struct _reent *, FILE *__restrict, const char *__restrict, __VALIST)
_ATTRIBUTE ((__format__ (__scanf__, 3, 0))));
int _EXFUN(_viprintf_r, (struct _reent *, const char *, __VALIST)
_ATTRIBUTE ((__format__ (__printf__, 2, 0))));
int _EXFUN(_viscanf_r, (struct _reent *, const char *, __VALIST)
_ATTRIBUTE ((__format__ (__scanf__, 2, 0))));
int _EXFUN(_vprintf_r, (struct _reent *, const char *__restrict, __VALIST)
_ATTRIBUTE ((__format__ (__printf__, 2, 0))));
int _EXFUN(_vscanf_r, (struct _reent *, const char *__restrict, __VALIST)
_ATTRIBUTE ((__format__ (__scanf__, 2, 0))));
int _EXFUN(_vsiprintf_r, (struct _reent *, char *, const char *, __VALIST)
_ATTRIBUTE ((__format__ (__printf__, 3, 0))));
int _EXFUN(_vsiscanf_r, (struct _reent *, const char *, const char *, __VALIST)
_ATTRIBUTE ((__format__ (__scanf__, 3, 0))));
int _EXFUN(_vsniprintf_r, (struct _reent *, char *, size_t, const char *, __VALIST)
_ATTRIBUTE ((__format__ (__printf__, 4, 0))));
int _EXFUN(_vsnprintf_r, (struct _reent *, char *__restrict, size_t, const char *__restrict, __VALIST)
_ATTRIBUTE ((__format__ (__printf__, 4, 0))));
int _EXFUN(_vsprintf_r, (struct _reent *, char *__restrict, const char *__restrict, __VALIST)
_ATTRIBUTE ((__format__ (__printf__, 3, 0))));
int _EXFUN(_vsscanf_r, (struct _reent *, const char *__restrict, const char *__restrict, __VALIST)
_ATTRIBUTE ((__format__ (__scanf__, 3, 0))));
/* Other extensions. */
int _EXFUN(fpurge, (FILE *));
ssize_t _EXFUN(__getdelim, (char **, size_t *, int, FILE *));
ssize_t _EXFUN(__getline, (char **, size_t *, FILE *));
#if __BSD_VISIBLE
void _EXFUN(clearerr_unlocked, (FILE *));
int _EXFUN(feof_unlocked, (FILE *));
int _EXFUN(ferror_unlocked, (FILE *));
int _EXFUN(fileno_unlocked, (FILE *));
int _EXFUN(fflush_unlocked, (FILE *));
int _EXFUN(fgetc_unlocked, (FILE *));
int _EXFUN(fputc_unlocked, (int, FILE *));
size_t _EXFUN(fread_unlocked, (_PTR __restrict, size_t _size, size_t _n, FILE *__restrict));
size_t _EXFUN(fwrite_unlocked, (const _PTR __restrict , size_t _size, size_t _n, FILE *));
#endif
#if __GNU_VISIBLE
char * _EXFUN(fgets_unlocked, (char *__restrict, int, FILE *__restrict));
int _EXFUN(fputs_unlocked, (const char *__restrict, FILE *__restrict));
#endif
#ifdef __LARGE64_FILES
#if !defined(__CYGWIN__) || defined(_COMPILING_NEWLIB)
FILE * _EXFUN(fdopen64, (int, const char *));
FILE * _EXFUN(fopen64, (const char *, const char *));
FILE * _EXFUN(freopen64, (_CONST char *, _CONST char *, FILE *));
_off64_t _EXFUN(ftello64, (FILE *));
_off64_t _EXFUN(fseeko64, (FILE *, _off64_t, int));
int _EXFUN(fgetpos64, (FILE *, _fpos64_t *));
int _EXFUN(fsetpos64, (FILE *, const _fpos64_t *));
FILE * _EXFUN(tmpfile64, (void));
FILE * _EXFUN(_fdopen64_r, (struct _reent *, int, const char *));
FILE * _EXFUN(_fopen64_r, (struct _reent *,const char *, const char *));
FILE * _EXFUN(_freopen64_r, (struct _reent *, _CONST char *, _CONST char *, FILE *));
_off64_t _EXFUN(_ftello64_r, (struct _reent *, FILE *));
_off64_t _EXFUN(_fseeko64_r, (struct _reent *, FILE *, _off64_t, int));
int _EXFUN(_fgetpos64_r, (struct _reent *, FILE *, _fpos64_t *));
int _EXFUN(_fsetpos64_r, (struct _reent *, FILE *, const _fpos64_t *));
FILE * _EXFUN(_tmpfile64_r, (struct _reent *));
#endif /* !__CYGWIN__ */
#endif /* __LARGE64_FILES */
/*
* Routines internal to the implementation.
*/
int _EXFUN(__srget_r, (struct _reent *, FILE *));
int _EXFUN(__swbuf_r, (struct _reent *, int, FILE *));
/*
* Stdio function-access interface.
*/
#ifndef __STRICT_ANSI__
# ifdef __LARGE64_FILES
FILE *_EXFUN(funopen,(const _PTR __cookie,
int (*__readfn)(_PTR __c, char *__buf,
_READ_WRITE_BUFSIZE_TYPE __n),
int (*__writefn)(_PTR __c, const char *__buf,
_READ_WRITE_BUFSIZE_TYPE __n),
_fpos64_t (*__seekfn)(_PTR __c, _fpos64_t __off, int __whence),
int (*__closefn)(_PTR __c)));
FILE *_EXFUN(_funopen_r,(struct _reent *, const _PTR __cookie,
int (*__readfn)(_PTR __c, char *__buf,
_READ_WRITE_BUFSIZE_TYPE __n),
int (*__writefn)(_PTR __c, const char *__buf,
_READ_WRITE_BUFSIZE_TYPE __n),
_fpos64_t (*__seekfn)(_PTR __c, _fpos64_t __off, int __whence),
int (*__closefn)(_PTR __c)));
# else
FILE *_EXFUN(funopen,(const _PTR __cookie,
int (*__readfn)(_PTR __cookie, char *__buf,
_READ_WRITE_BUFSIZE_TYPE __n),
int (*__writefn)(_PTR __cookie, const char *__buf,
_READ_WRITE_BUFSIZE_TYPE __n),
fpos_t (*__seekfn)(_PTR __cookie, fpos_t __off, int __whence),
int (*__closefn)(_PTR __cookie)));
FILE *_EXFUN(_funopen_r,(struct _reent *, const _PTR __cookie,
int (*__readfn)(_PTR __cookie, char *__buf,
_READ_WRITE_BUFSIZE_TYPE __n),
int (*__writefn)(_PTR __cookie, const char *__buf,
_READ_WRITE_BUFSIZE_TYPE __n),
fpos_t (*__seekfn)(_PTR __cookie, fpos_t __off, int __whence),
int (*__closefn)(_PTR __cookie)));
# endif /* !__LARGE64_FILES */
# define fropen(__cookie, __fn) funopen(__cookie, __fn, (int (*)())0, \
(fpos_t (*)())0, (int (*)())0)
# define fwopen(__cookie, __fn) funopen(__cookie, (int (*)())0, __fn, \
(fpos_t (*)())0, (int (*)())0)
typedef ssize_t cookie_read_function_t(void *__cookie, char *__buf, size_t __n);
typedef ssize_t cookie_write_function_t(void *__cookie, const char *__buf,
size_t __n);
# ifdef __LARGE64_FILES
typedef int cookie_seek_function_t(void *__cookie, _off64_t *__off,
int __whence);
# else
typedef int cookie_seek_function_t(void *__cookie, off_t *__off, int __whence);
# endif /* !__LARGE64_FILES */
typedef int cookie_close_function_t(void *__cookie);
typedef struct
{
/* These four struct member names are dictated by Linux; hopefully,
they don't conflict with any macros. */
cookie_read_function_t *read;
cookie_write_function_t *write;
cookie_seek_function_t *seek;
cookie_close_function_t *close;
} cookie_io_functions_t;
FILE *_EXFUN(fopencookie,(void *__cookie,
const char *__mode, cookie_io_functions_t __functions));
FILE *_EXFUN(_fopencookie_r,(struct _reent *, void *__cookie,
const char *__mode, cookie_io_functions_t __functions));
#endif /* ! __STRICT_ANSI__ */
#ifndef __CUSTOM_FILE_IO__
/*
* The __sfoo macros are here so that we can
* define function versions in the C library.
*/
#define __sgetc_raw_r(__ptr, __f) (--(__f)->_r < 0 ? __srget_r(__ptr, __f) : (int)(*(__f)->_p++))
#ifdef __SCLE
/* For a platform with CR/LF, additional logic is required by
__sgetc_r which would otherwise simply be a macro; therefore we
use an inlined function. The function is only meant to be inlined
in place as used and the function body should never be emitted.
There are two possible means to this end when compiling with GCC,
one when compiling with a standard C99 compiler, and for other
compilers we're just stuck. At the moment, this issue only
affects the Cygwin target, so we'll most likely be using GCC. */
_ELIDABLE_INLINE int __sgetc_r(struct _reent *__ptr, FILE *__p);
_ELIDABLE_INLINE int __sgetc_r(struct _reent *__ptr, FILE *__p)
{
int __c = __sgetc_raw_r(__ptr, __p);
if ((__p->_flags & __SCLE) && (__c == '\r'))
{
int __c2 = __sgetc_raw_r(__ptr, __p);
if (__c2 == '\n')
__c = __c2;
else
ungetc(__c2, __p);
}
return __c;
}
#else
#define __sgetc_r(__ptr, __p) __sgetc_raw_r(__ptr, __p)
#endif
#ifdef _never /* __GNUC__ */
/* If this inline is actually used, then systems using coff debugging
info get hopelessly confused. 21sept93 rich@cygnus.com. */
_ELIDABLE_INLINE int __sputc_r(struct _reent *_ptr, int _c, FILE *_p) {
if (--_p->_w >= 0 || (_p->_w >= _p->_lbfsize && (char)_c != '\n'))
return (*_p->_p++ = _c);
else
return (__swbuf_r(_ptr, _c, _p));
}
#else
/*
* This has been tuned to generate reasonable code on the vax using pcc
*/
#define __sputc_raw_r(__ptr, __c, __p) \
(--(__p)->_w < 0 ? \
(__p)->_w >= (__p)->_lbfsize ? \
(*(__p)->_p = (__c)), *(__p)->_p != '\n' ? \
(int)*(__p)->_p++ : \
__swbuf_r(__ptr, '\n', __p) : \
__swbuf_r(__ptr, (int)(__c), __p) : \
(*(__p)->_p = (__c), (int)*(__p)->_p++))
#ifdef __SCLE
#define __sputc_r(__ptr, __c, __p) \
((((__p)->_flags & __SCLE) && ((__c) == '\n')) \
? __sputc_raw_r(__ptr, '\r', (__p)) : 0 , \
__sputc_raw_r((__ptr), (__c), (__p)))
#else
#define __sputc_r(__ptr, __c, __p) __sputc_raw_r(__ptr, __c, __p)
#endif
#endif
#define __sfeof(p) ((int)(((p)->_flags & __SEOF) != 0))
#define __sferror(p) ((int)(((p)->_flags & __SERR) != 0))
#define __sclearerr(p) ((void)((p)->_flags &= ~(__SERR|__SEOF)))
#define __sfileno(p) ((p)->_file)
#ifndef _REENT_SMALL
#define feof(p) __sfeof(p)
#define ferror(p) __sferror(p)
#define clearerr(p) __sclearerr(p)
#if __BSD_VISIBLE
#define feof_unlocked(p) __sfeof(p)
#define ferror_unlocked(p) __sferror(p)
#define clearerr_unlocked(p) __sclearerr(p)
#endif /* __BSD_VISIBLE */
#endif /* _REENT_SMALL */
#if 0 /*ndef __STRICT_ANSI__ - FIXME: must initialize stdio first, use fn */
#define fileno(p) __sfileno(p)
#endif
#ifndef __CYGWIN__
#ifndef lint
#define getc(fp) __sgetc_r(_REENT, fp)
#define putc(x, fp) __sputc_r(_REENT, x, fp)
#endif /* lint */
#endif /* __CYGWIN__ */
#ifndef __STRICT_ANSI__
/* fast always-buffered version, true iff error */
#define fast_putc(x,p) (--(p)->_w < 0 ? \
__swbuf_r(_REENT, (int)(x), p) == EOF : (*(p)->_p = (x), (p)->_p++, 0))
#define L_cuserid 9 /* posix says it goes in stdio.h :( */
#ifdef __CYGWIN__
#define L_ctermid 16
#endif
#endif
#endif /* !__CUSTOM_FILE_IO__ */
#define getchar() getc(stdin)
#define putchar(x) putc(x, stdout)
#ifndef __STRICT_ANSI__
#define getchar_unlocked() getc_unlocked(stdin)
#define putchar_unlocked(x) putc_unlocked(x, stdout)
#endif
_END_STD_C
#undef putchar
#undef getchar
#ifdef __cplusplus
}
#endif
#endif /* DOXYGEN */
#endif /* STDIO_H */

View File

@ -0,0 +1,337 @@
/*
* Copyright (C) 2019 Gunar Schorcht
*
* This file is subject to the terms and conditions of the GNU Lesser
* General Public License v2.1. See the file LICENSE in the top level
* directory for more details.
*/
/**
* @ingroup cpu_esp8266
* @{
*
* @file
* @brief This file is a modification of original sys/types.h
*
* @author Gunar Schorcht <gunar@schorcht.net>
*
* This file is just a wrapper around sys/types.h to fix missing types
* fsblkcnt_t and fsfilcnt_t needed in statvfs.h and to avoid type conflicts
* with pthread types from pthread module.
*/
/* unified sys/types.h:
start with sef's sysvi386 version.
merge go32 version -- a few ifdefs.
h8300hms, h8300xray, and sysvnecv70 disagree on the following types:
typedef int gid_t;
typedef int uid_t;
typedef int dev_t;
typedef int ino_t;
typedef int mode_t;
typedef int caddr_t;
however, these aren't "reasonable" values, the sysvi386 ones make far
more sense, and should work sufficiently well (in particular, h8300
doesn't have a stat, and the necv70 doesn't matter.) -- eichin
*/
#ifndef SYS_TYPES_H
#define SYS_TYPES_H
#ifndef DOXYGEN
#ifdef __cplusplus
extern "C" {
#endif
#ifndef _FSBLKCNT_T_DECLARED
#include <stdint.h>
typedef uint32_t fsblkcnt_t;
typedef uint32_t fsfilcnt_t;
#define _FSBLKCNT_T_DECLARED
#endif
#ifndef _SYS_TYPES_H
#include <_ansi.h>
#ifndef __INTTYPES_DEFINED__
#define __INTTYPES_DEFINED__
#include <machine/_types.h>
#if defined(__rtems__) || defined(__XMK__)
/*
* The following section is RTEMS specific and is needed to more
* closely match the types defined in the BSD sys/types.h.
* This is needed to let the RTEMS/BSD TCP/IP stack compile.
*/
/* deprecated */
#if ___int8_t_defined
typedef __uint8_t u_int8_t;
#endif
#if ___int16_t_defined
typedef __uint16_t u_int16_t;
#endif
#if ___int32_t_defined
typedef __uint32_t u_int32_t;
#endif
#if ___int64_t_defined
typedef __uint64_t u_int64_t;
/* deprecated */
typedef __uint64_t u_quad_t;
typedef __int64_t quad_t;
typedef quad_t * qaddr_t;
#endif
#endif
#endif /* ! __INTTYPES_DEFINED */
#ifndef __need_inttypes
#define _SYS_TYPES_H
#include <sys/_types.h>
#ifdef __i386__
#if defined (GO32) || defined (__MSDOS__)
#define __MS_types__
#endif
#endif
# include <stddef.h>
# include <machine/types.h>
/* To ensure the stat struct's layout doesn't change when sizeof(int), etc.
changes, we assume sizeof short and long never change and have all types
used to define struct stat use them and not int where possible.
Where not possible, _ST_INTxx are used. It would be preferable to not have
such assumptions, but until the extra fluff is necessary, it's avoided.
No 64 bit targets use stat yet. What to do about them is postponed
until necessary. */
#ifdef __GNUC__
#define _ST_INT32 __attribute__ ((__mode__ (__SI__)))
#else
#define _ST_INT32
#endif
# ifndef _POSIX_SOURCE
# define physadr physadr_t
# define quad quad_t
#ifndef _BSDTYPES_DEFINED
/* also defined in mingw/gmon.h and in w32api/winsock[2].h */
#ifndef __u_char_defined
typedef unsigned char u_char;
#define __u_char_defined
#endif
#ifndef __u_short_defined
typedef unsigned short u_short;
#define __u_short_defined
#endif
#ifndef __u_int_defined
typedef unsigned int u_int;
#define __u_int_defined
#endif
#ifndef __u_long_defined
typedef unsigned long u_long;
#define __u_long_defined
#endif
#define _BSDTYPES_DEFINED
#endif
typedef unsigned short ushort; /* System V compatibility */
typedef unsigned int uint; /* System V compatibility */
typedef unsigned long ulong; /* System V compatibility */
# endif /*!_POSIX_SOURCE */
#ifndef __clock_t_defined
typedef _CLOCK_T_ clock_t;
#define __clock_t_defined
#endif
#ifndef __time_t_defined
typedef _TIME_T_ time_t;
#define __time_t_defined
#endif
#ifndef __timespec_defined
#define __timespec_defined
/* Time Value Specification Structures, P1003.1b-1993, p. 261 */
struct timespec {
time_t tv_sec; /* Seconds */
long tv_nsec; /* Nanoseconds */
};
#endif
struct itimerspec {
struct timespec it_interval; /* Timer period */
struct timespec it_value; /* Timer expiration */
};
#ifndef __daddr_t_defined
typedef long daddr_t;
#define __daddr_t_defined
#endif
#ifndef __caddr_t_defined
typedef char * caddr_t;
#define __caddr_t_defined
#endif
#ifndef __CYGWIN__
#if defined(__MS_types__) || defined(__rtems__) || \
defined(__sparc__) || defined(__SPU__)
typedef unsigned long ino_t;
#else
typedef unsigned short ino_t;
#endif
#endif /*__CYGWIN__*/
#ifdef __MS_types__
typedef unsigned long vm_offset_t;
typedef unsigned long vm_size_t;
#define __BIT_TYPES_DEFINED__
typedef signed char int8_t;
typedef unsigned char u_int8_t;
typedef short int16_t;
typedef unsigned short u_int16_t;
typedef int int32_t;
typedef unsigned int u_int32_t;
typedef long long int64_t;
typedef unsigned long long u_int64_t;
typedef int32_t register_t;
#endif /* __MS_types__ */
/*
* All these should be machine specific - right now they are all broken.
* However, for all of Cygnus' embedded targets, we want them to all be
* the same. Otherwise things like sizeof (struct stat) might depend on
* how the file was compiled (e.g. -mint16 vs -mint32, etc.).
*/
#ifndef __CYGWIN__ /* which defines these types in it's own types.h. */
typedef _off_t off_t;
typedef __dev_t dev_t;
typedef __uid_t uid_t;
typedef __gid_t gid_t;
#endif
#if defined(__XMK__)
typedef signed char pid_t;
#else
typedef int pid_t;
#endif
#if defined(__rtems__)
typedef _mode_t mode_t;
#endif
#ifndef __CYGWIN__
typedef long key_t;
#endif
typedef _ssize_t ssize_t;
#if !defined(__CYGWIN__) && !defined(__rtems__)
#ifdef __MS_types__
typedef char * addr_t;
typedef int mode_t;
#else
#if defined (__sparc__) && !defined (__sparc_v9__)
#ifdef __svr4__
typedef unsigned long mode_t;
#else
typedef unsigned short mode_t;
#endif
#else
typedef unsigned int mode_t _ST_INT32;
#endif
#endif /* ! __MS_types__ */
#endif /*__CYGWIN__*/
typedef unsigned short nlink_t;
/* We don't define fd_set and friends if we are compiling POSIX
source, or if we have included (or may include as indicated
by __USE_W32_SOCKETS) the W32api winsock[2].h header which
defines Windows versions of them. Note that a program which
includes the W32api winsock[2].h header must know what it is doing;
it must not call the cygwin32 select function.
*/
# if !(defined (_POSIX_SOURCE) || defined (_WINSOCK_H) || defined (_WINSOCKAPI_) || defined (__USE_W32_SOCKETS))
# define _SYS_TYPES_FD_SET
# define NBBY 8 /* number of bits in a byte */
/*
* Select uses bit masks of file descriptors in longs.
* These macros manipulate such bit fields (the filesystem macros use chars).
* FD_SETSIZE may be defined by the user, but the default here
* should be >= NOFILE (param.h).
*/
# ifndef FD_SETSIZE
# define FD_SETSIZE 64
# endif
typedef long fd_mask;
# define NFDBITS (sizeof (fd_mask) * NBBY) /* bits per mask */
# ifndef howmany
# define howmany(x,y) (((x)+((y)-1))/(y))
# endif
/* We use a macro for fd_set so that including Sockets.h afterwards
can work. */
typedef struct _types_fd_set {
fd_mask fds_bits[howmany(FD_SETSIZE, NFDBITS)];
} _types_fd_set;
#define fd_set _types_fd_set
# define FD_SET(n, p) ((p)->fds_bits[(n)/NFDBITS] |= (1L << ((n) % NFDBITS)))
# define FD_CLR(n, p) ((p)->fds_bits[(n)/NFDBITS] &= ~(1L << ((n) % NFDBITS)))
# define FD_ISSET(n, p) ((p)->fds_bits[(n)/NFDBITS] & (1L << ((n) % NFDBITS)))
# define FD_ZERO(p) (__extension__ (void)({ \
size_t __i; \
char *__tmp = (char *)p; \
for (__i = 0; __i < sizeof (*(p)); ++__i) \
*__tmp++ = 0; \
}))
# endif /* !(defined (_POSIX_SOURCE) || defined (_WINSOCK_H) || defined (_WINSOCKAPI_) || defined (__USE_W32_SOCKETS)) */
#undef __MS_types__
#undef _ST_INT32
#ifndef __clockid_t_defined
typedef _CLOCKID_T_ clockid_t;
#define __clockid_t_defined
#endif
#ifndef __timer_t_defined
typedef _TIMER_T_ timer_t;
#define __timer_t_defined
#endif
typedef unsigned long useconds_t;
typedef long suseconds_t;
#endif /* !__need_inttypes */
#undef __need_inttypes
#endif /* _SYS_TYPES_H */
#ifdef __cplusplus
}
#endif
#endif /* DOXYGEN */
#endif /* SYS_TYPES_H */

View File

@ -1,5 +1,5 @@
/*
* Copyright (C) 2018 Gunar Schorcht
* Copyright (C) 2019 Gunar Schorcht
*
* This file is subject to the terms and conditions of the GNU Lesser
* General Public License v2.1. See the file LICENSE in the top level
@ -23,6 +23,7 @@
#include <stdarg.h>
#include <stdbool.h>
#include <stdint.h>
#include <stdlib.h>
#ifdef __cplusplus
@ -35,12 +36,24 @@ extern void syscalls_init (void);
/** System standard printf function */
extern int printf(const char* format, ...);
/** Determine free heap size */
unsigned int get_free_heap_size (void);
/** System standard puts function */
extern int puts(const char * str);
/** Determine free heap size */
extern unsigned int get_free_heap_size (void);
/** Time since boot in us (32bit version) */
uint32_t system_get_time (void);
/** Time since boot in ms (32bit version) */
uint32_t system_get_time_ms (void);
/** memset version that the compiler should not be allowed to optimize this */
void *system_secure_memset(void *s, int c, size_t n);
#ifdef __cplusplus
}
#endif

View File

@ -1,5 +1,5 @@
/*
* Copyright (C) 2018 Gunar Schorcht
* Copyright (C) 2019 Gunar Schorcht
*
* This file is subject to the terms and conditions of the GNU Lesser
* General Public License v2.1. See the file LICENSE in the top level

View File

@ -1,5 +1,5 @@
/*
* Copyright (C) 2018 Gunar Schorcht
* Copyright (C) 2019 Gunar Schorcht
*
* This file is subject to the terms and conditions of the GNU Lesser
* General Public License v2.1. See the file LICENSE in the top level

View File

@ -1,5 +1,5 @@
/*
* Copyright (C) 2018 Gunar Schorcht
* Copyright (C) 2019 Gunar Schorcht
*
* This file is subject to the terms and conditions of the GNU Lesser
* General Public License v2.1. See the file LICENSE in the top level

View File

@ -1,5 +1,5 @@
/*
* Copyright (C) 2018 Gunar Schorcht
* Copyright (C) 2019 Gunar Schorcht
*
* This file is subject to the terms and conditions of the GNU Lesser
* General Public License v2.1. See the file LICENSE in the top level
@ -18,7 +18,7 @@
* @}
*/
#define ENABLE_DEBUG 0
#define ENABLE_DEBUG (0)
#include "debug.h"
#include <stdint.h>
@ -27,10 +27,9 @@
#include "irq.h"
#include "cpu.h"
#include "common.h"
#include "esp_common.h"
#include "esp/common_macros.h"
#include "esp/xtensa_ops.h"
#include "sdk/ets.h"
#include "xtensa/xtensa_context.h"
/**
@ -46,9 +45,9 @@ unsigned int IRAM irq_disable(void)
uint32_t _saved_interrupt_level;
/* read and set interrupt level (RSIL) */
__asm__ volatile ("rsil %0, " XTSTR(XCHAL_NUM_INTLEVELS+1) : "=a" (_saved_interrupt_level));
__asm__ volatile ("rsil %0, " XTSTR(XCHAL_EXCM_LEVEL) : "=a" (_saved_interrupt_level));
DEBUG ("%s %02x(%02x)\n", __func__,
(_saved_interrupt_level & 0xfffffff0) | (XCHAL_NUM_INTLEVELS+1),
(_saved_interrupt_level & 0xfffffff0) | (XCHAL_EXCM_LEVEL),
_saved_interrupt_level);
return _saved_interrupt_level;
}
@ -62,7 +61,7 @@ unsigned int IRAM irq_enable(void)
/* read and set interrupt level (RSIL) */
__asm__ volatile ("rsil %0, 0" : "=a" (_saved_interrupt_level));
DEBUG ("%s %02x(%02x)\n", __func__,
DEBUG ("%s %02x (%02x)\n", __func__,
_saved_interrupt_level & 0xfffffff0, _saved_interrupt_level);
return _saved_interrupt_level;
}

View File

@ -0,0 +1,14 @@
PROVIDE ( GPIO = 0x60000300);
PROVIDE ( uart0 = 0x60000000 );
PROVIDE ( uart1 = 0x60000f00 );
PROVIDE ( frc1 = 0x60000600 );
PROVIDE ( rtc_sys_info = 0x60001100 );
PROVIDE ( SLC = 0x60000B00 );
PROVIDE ( I2S = 0x60000e00 );
PROVIDE ( SPI1 = 0x60000100 );
PROVIDE ( SPI0 = 0x60000200 );

View File

@ -1,17 +1,15 @@
/**
* This linker script is a modified version of eagle.app.v6.ld that
* was generated from xt-genldscripts.tpp for LSP and shipped with
* ESP8266_NONOS_SDK
*/
/* Linker Script for ld -N */
* This linker script is a combined and modified version of esp8266.ld and
* esp8266.common.ld from ESP8266-RTOS-SDK.
*/
MEMORY
{
dport0_0_seg : org = 0x3FF00000, len = 0x10
dram0_0_seg : org = 0x3FFE8000, len = 0x14000
iram1_0_seg : org = 0x40100000, len = 0x8000
irom0_0_seg : org = 0x40210000, len = 0x5C000
dram0_0_seg : org = 0x3FFE8000, len = 0x18000
iram1_0_seg : org = 0x40100000, len = 0xC000
irom0_0_seg : org = 0x40200010 + 0x10000, len = 0x80000 - 0x10 - 0x10000
rtc_seg : org = 0x60001200, len = 0x200
}
PHDRS
@ -25,7 +23,7 @@ PHDRS
/* Default entry point: */
ENTRY(_call_user_start)
ENTRY(call_user_start)
EXTERN(_DebugExceptionVector)
EXTERN(_DoubleExceptionVector)
EXTERN(_KernelExceptionVector)
@ -50,17 +48,6 @@ _memmap_cacheattr_wt_allvalid = 0x22222112;
_memmap_cacheattr_bp_allvalid = 0x22222222;
PROVIDE(_memmap_cacheattr_reset = _memmap_cacheattr_wb_trapnull);
/* ROM variables */
/* source: disassembly of boot rom at https://github.com/trebisky/esp8266 */
PROVIDE( ets_task_min_prio = 0x3fffc6fc );
PROVIDE( ets_idle_cb = 0x3fffdab0 );
PROVIDE( ets_idle_arg = 0x3fffdab4 );
PROVIDE( ets_task_exec_mask = 0x3fffdab8 );
PROVIDE( ets_task_tab = 0x3fffdac0 );
PROVIDE( flashchip = 0x3fffc714 );
PROVIDE( sdk_flashchip = 0x3fffc718 );
PROVIDE( ets_phy_mactime = 0x3ff20a00 );
SECTIONS
{
@ -88,6 +75,15 @@ SECTIONS
_dport0_data_end = ABSOLUTE(.);
} >dport0_0_seg :dport0_0_phdr
/* RTC memory holds user's data/rodata */
.rtc.data :
{
_rtc_data_start = ABSOLUTE(.);
*(.rtc.data)
*(.rtc.rodata)
_rtc_data_end = ABSOLUTE(.);
} > rtc_seg
.data : ALIGN(4)
{
_data_start = ABSOLUTE(.);
@ -108,26 +104,30 @@ SECTIONS
.rodata : ALIGN(4)
{
_rodata_start = ABSOLUTE(.);
*(.sdk.version)
/* TODO put only necessary .rodata to dram
/* TODO put only necessary .rodata to dram */
/* *(.rodata .rodata.*) */
*libc.a:*.o(.rodata.* .rodata)
*core.a:*(.rodata.* .rodata)
*cpu.a:*(.rodata .rodata.*)
*/
*(.rodata .rodata.*)
*libpp.a:(.rodata.* .rodata)
*liblog.a:(.rodata.* .rodata)
*(.gnu.linkonce.r.*)
*(.rodata1)
__XT_EXCEPTION_TABLE__ = ABSOLUTE(.);
*(.xt_except_table)
*(.gcc_except_table)
*(.gcc_except_table.*)
*(.gnu.linkonce.e.*)
*(.gnu.version_r)
*(.eh_frame)
. = (. + 3) & ~ 3;
/* C++ constructor and destructor tables, properly ordered: */
__init_array_start = ABSOLUTE(.);
KEEP (*crtbegin.o(.ctors))
KEEP (*(EXCLUDE_FILE (*crtend.o) .ctors))
KEEP (*(SORT(.ctors.*)))
KEEP (*(.ctors))
__init_array_end = ABSOLUTE(.);
KEEP (*crtbegin.o(.dtors))
KEEP (*(EXCLUDE_FILE (*crtend.o) .dtors))
KEEP (*(SORT(.dtors.*)))
@ -140,7 +140,7 @@ SECTIONS
*(.xt_except_desc_end)
*(.dynamic)
*(.gnu.version_d)
. = ALIGN(4); /* this table MUST be 4-byte aligned */
. = ALIGN(4); /* this table MUST be 4-byte aligned */
_bss_table_start = ABSOLUTE(.);
LONG(_bss_start)
LONG(_bss_end)
@ -165,7 +165,6 @@ SECTIONS
*(.bss.*)
*(.gnu.linkonce.b.*)
*(COMMON)
. = ALIGN (8);
_bss_end = ABSOLUTE(.);
_sheap = ABSOLUTE(.);
@ -173,40 +172,39 @@ SECTIONS
} >dram0_0_seg :dram0_0_bss_phdr
/* ETS system memory starts at 0x3FFFC000 which is the top of the heap for the app */
. = 0x3FFFC000;
. = 0x3FFFFFF0;
_heap_top = ABSOLUTE(.);
_eheap = ABSOLUTE(.);
.text : ALIGN(4)
.text : ALIGN(4) /* IRAM */
{
_stext = .;
_text_start = ABSOLUTE(.);
*(.UserEnter.text)
LONG(_text_start)
. = ALIGN(16);
*(.DebugExceptionVector.text)
*(.DebugExceptionVector.text) /* 0x40100010 */
. = ALIGN(16);
*(.NMIExceptionVector.text)
*(.NMIExceptionVector.text) /* 0x40100020 */
. = ALIGN(16);
*(.KernelExceptionVector.text)
*(.KernelExceptionVector.text) /* 0x40100030 */
LONG(0)
LONG(0)
LONG(0)
LONG(0)
. = ALIGN(16);
*(.UserExceptionVector.text)
*(.UserExceptionVector.text) /* 0x40100050 */
LONG(0)
LONG(0)
LONG(0)
LONG(0)
. = ALIGN(16);
*(.DoubleExceptionVector.text)
*(.DoubleExceptionVector.text) /* 0x40100070 */
LONG(0)
LONG(0)
LONG(0)
LONG(0)
. = ALIGN (16);
*(.UserExceptionTrampoline.text)
*(.UserExceptionTrampoline.text) /* 0x40100090 */
. = ALIGN (16);
*(.entry.text)
*(.init.literal)
@ -214,30 +212,48 @@ SECTIONS
/* normal code should be in irom0 */
/*
*(.literal .text .literal.* .text.* .stub)
*(.gnu.warning .gnu.linkonce.literal.* .gnu.linkonce.t.*.literal .gnu.linkonce.t.*)
*(.literal .text)
*core.a:*(.literal .text .literal.* .text.*)
*/
*gdbstub.a:*(.literal .text .literal.* .text.*)
*(.stub .gnu.warning .gnu.linkonce.literal.* .gnu.linkonce.t.*.literal .gnu.linkonce.t.*)
/* RIOT-OS compiled source files that use the .iram1.* section names for IRAM
functions, etc. */
*(.iram1.*)
*(.iram1 .iram1.*)
/* SDK libraries expect their .text sections to link to iram, not irom */
*libcrypto.a:*(.literal .text)
*libmain.a:*(.literal .text .literal.* .text.*)
*libnet80211.a:*(.literal .text)
*libpp.a:*(.literal .text .literal.* .text.*)
*libphy.a:*(.literal .text .literal.* .text.*)
*libwpa.a:*(.literal .text)
*libwpa2.a:*(.literal .text)
*liblwip.a:*(.literal .text)
/* SDK libraries that expect their .text or .data sections to link to iram */
/* TODO *libcore.a:(.bss .data .bss.* .data.* COMMON) */
*esp_idf_spi_flash.a:spi_flash_raw.o(.literal .text .literal.* .text.*)
*esp_idf_esp8266.a:ets_printf.o(.literal .text .literal.* .text.*)
/*
*cpu.a:*.o(.literal .text .literal.* .text.*)
*/
*core.a:sched.o(.literal .text .literal.* .text.*)
*esp_wifi.a:*(.literal .text .literal.* .text.*)
*freertos.a:*(.literal .text .literal.* .text.*)
*periph.a:*(.literal .text .literal.* .text.*)
*xtimer.a:*(.literal .text .literal.* .text.*)
*libhal.a:clock.o(.literal .text .literal.* .text.*)
*libhal.a:int_asm--set_intclear.o(.literal .text .literal.* .text.*)
*libpp.a:esf_buf.o(.literal .text .literal.* .text.*)
*libpp.a:lmac.o(.literal .text .literal.* .text.*)
*libpp.a:pp.o(.literal .text .literal.* .text.*)
*libpp.a:rate_control.o(.literal .text .literal.* .text.*)
*libpp.a:trc.o(.literal .text .literal.* .text.*)
*libpp.a:wdev.o(.literal .text .literal.* .text.*)
*libphy.a:phy.o(.literal .text .literal.* .text.*)
*libphy.a:phy_chip_v6_cal.o(.literal .text .literal.* .text.*)
*libphy.a:phy_sleep.o(.literal .text .literal.* .text.*)
/* Xtensa basic functionality written in assembler should be placed in iram */
*xtensa.a:*(.literal .text .literal.* .text.*)
/* libgcc integer functions also need to be in .text, as some are called before
flash is mapped (also performance)
*/
/* libgcc functions required for debugging have to be in IRAM */
*libgcc.a:unwind-dw2.o(.literal .text .literal.* .text.*)
/* libgcc integer functions also need to be in .text */
/* some are called before flash is mapped and also for performance) */
*libgcc.a:*i3.o(.literal .text .literal.* .text.*)
*libgcc.a:*mulsf3.o(.literal .text .literal.* .text.*)
@ -245,6 +261,7 @@ SECTIONS
*libgcc.a:*fixsfsi.o(.literal .text .literal.* .text.*)
/* libc also in IRAM */
/*
*libc.a:*malloc.o(.literal .text .literal.* .text.*)
*libc.a:*mallocr.o(.literal .text .literal.* .text.*)
*libc.a:*freer.o(.literal .text .literal.* .text.*)
@ -260,6 +277,7 @@ SECTIONS
*libc.a:*printf.o(.literal .text .literal.* .text.*)
*libc.a:*findfp.o(.literal .text .literal.* .text.*)
*libc.a:*fputwc.o(.literal .text .literal.* .text.*)
*/
enc28j60.a:*(.literal .text .literal.* .text.*)
@ -274,15 +292,18 @@ SECTIONS
{
_irom0_text_start = ABSOLUTE(.);
*libmbedtls.a:(.literal .text .literal.* .text.*)
/* RIOT-OS compiled code goes into IROM by default
(except for libgcc which is matched above.) */
*(.literal .text .literal.* .text.* .rodata .rodata.*)
/* RIOT-OS compiled code and RO data go into IROM by default */
*(.literal .text .literal.* .text.*)
*(.rodata .rodata.*)
/* Anything explicitly marked as "irom" or "irom0" should go here */
*(.irom0.literal .irom.literal .irom.text.literal .irom0.text .irom.text)
. = ALIGN(16);
__start_ksymatabesp_socket = .;
*(ksymatabesp_socket)
__stop_ksymatabesp_socket = .;
_irom0_text_end = ABSOLUTE(.);
} >irom0_0_seg :irom0_0_phdr

View File

@ -0,0 +1,60 @@
SPI_sector_erase = 0x400040c0;
SPI_page_program = 0x40004174;
SPI_read_data = 0x400042ac;
SPI_read_status = 0x400043c8;
SPI_write_status = 0x40004400;
SPI_write_enable = 0x4000443c;
Wait_SPI_Idle = 0x4000448c;
Enable_QMode = 0x400044c0;
Disable_QMode = 0x40004508;
Cache_Read_Enable = 0x40004678;
Cache_Read_Disable = 0x400047f0;
lldesc_build_chain = 0x40004f40;
lldesc_num2link = 0x40005050;
lldesc_set_owner = 0x4000507c;
__adddf3 = 0x4000c538;
__addsf3 = 0x4000c180;
__divdf3 = 0x4000cb94;
__divdi3 = 0x4000ce60;
__divsi3 = 0x4000dc88;
__extendsfdf2 = 0x4000cdfc;
__fixdfsi = 0x4000ccb8;
__fixunsdfsi = 0x4000cd00;
__fixunssfsi = 0x4000c4c4;
__floatsidf = 0x4000e2f0;
__floatsisf = 0x4000e2ac;
__floatunsidf = 0x4000e2e8;
__floatunsisf = 0x4000e2a4;
__muldf3 = 0x4000c8f0;
__muldi3 = 0x40000650;
__mulsf3 = 0x4000c3dc;
__subdf3 = 0x4000c688;
__subsf3 = 0x4000c268;
__truncdfsf2 = 0x4000cd5c;
__udivdi3 = 0x4000d310;
__udivsi3 = 0x4000e21c;
__umoddi3 = 0x4000d770;
__umodsi3 = 0x4000e268;
__umulsidi3 = 0x4000dcf0;
bzero = 0x4000de84;
memcmp = 0x4000dea8;
memcpy = 0x4000df48;
memmove = 0x4000e04c;
memset = 0x4000e190;
strcmp = 0x4000bdc8;
strcpy = 0x4000bec8;
strlen = 0x4000bf4c;
strncmp = 0x4000bfa8;
strncpy = 0x4000c0a0;
strstr = 0x4000e1e0;
gpio_input_get = 0x40004cf0;
gpio_pin_wakeup_disable = 0x40004ed4;
gpio_pin_wakeup_enable = 0x40004e90;
ets_io_vprintf = 0x40001f00;

View File

@ -1,3 +1,3 @@
MODULE = periph
include $(RIOTBASE)/Makefile.base
include $(RIOTMAKE)/periph.mk

View File

@ -1,5 +1,5 @@
/*
* Copyright (C) 2018 Gunar Schorcht
* Copyright (C) 2019 Gunar Schorcht
*
* This file is subject to the terms and conditions of the GNU Lesser General
* Public License v2.1. See the file LICENSE in the top level directory for more
@ -28,10 +28,10 @@
#include "periph_conf.h"
#include "board.h"
#include "common.h"
#include "esp_common.h"
#include "sdk/sdk.h"
#if defined(ADC_NUMOF) && ADC_NUMOF > 0
extern uint16_t test_tout(void);
int adc_init(adc_t line)
{
@ -47,11 +47,10 @@ int adc_sample(adc_t line, adc_res_t res)
CHECK_PARAM_RET (line < ADC_NUMOF, -1)
CHECK_PARAM_RET (res == ADC_RES_10BIT, -1)
#ifdef MODULE_ESP_SDK
return system_adc_read ();
#else
return test_tout(false);
#endif
return test_tout();
}
#endif
void adc_print_config(void)
{
printf("\tADC\t\tpins=[ A0 ]\n");
}

View File

@ -1,5 +1,5 @@
/*
* Copyright (C) 2018 Gunar Schorcht
* Copyright (C) 2019 Gunar Schorcht
*
* This file is subject to the terms and conditions of the GNU Lesser
* General Public License v2.1. See the file LICENSE in the top level
@ -18,25 +18,42 @@
* @}
*/
#define ENABLE_DEBUG (0)
#include "debug.h"
#if MODULE_MTD
#include <errno.h>
#include <string.h>
#include <stdlib.h>
#include "board.h"
#include "common.h"
#include "esp_common.h"
#include "irq_arch.h"
#include "log.h"
#include "mtd.h"
#include "c_types.h"
#include "esp/spiflash.h"
#include "spi_flash.h"
#include "sdk/rom.h"
#include "esp_flash_data_types.h"
#include "esp_partition.h"
#define SDK_FLASH_FUNCTIONS
#ifdef MCU_ESP32
#include "rom/cache.h"
#include "rom/spi_flash.h"
#include "esp_spi_flash.h"
#else /* MCU_ESP32 */
#include "rom_functions.h"
#include "spi_flash.h"
#endif /* MCU_ESP32 */
#define ENABLE_DEBUG (0)
#include "debug.h"
#define ESP_PART_TABLE_ADDR 0x8000 /* TODO configurable as used in Makefile.include */
#define ESP_PART_TABLE_SIZE 0xC00
#define ESP_PART_ENTRY_SIZE 0x20
#define ESP_PART_ENTRY_MAGIC ESP_PARTITION_MAGIC
/* the external pointer to the system MTD device */
mtd_dev_t* mtd0 = 0;
@ -44,6 +61,18 @@ mtd_dev_t* mtd0 = 0;
mtd_dev_t _flash_dev;
mtd_desc_t _flash_driver;
#ifdef MCU_ESP8266
/* for source code compatibility with ESP32 SDK */
#define esp_rom_spiflash_chip_t esp_spi_flash_chip_t
#define g_rom_flashchip flashchip
/* defined in vendor/esp-idf/spi_flash.c */
extern esp_spi_flash_chip_t flashchip;
extern uint32_t spi_flash_get_id(void);
#endif /* MCU_ESP8266 */
/* forward declaration of mtd functions */
static int _flash_init (mtd_dev_t *dev);
static int _flash_read (mtd_dev_t *dev, void *buff, uint32_t addr, uint32_t size);
@ -55,60 +84,420 @@ static uint32_t _flash_beg; /* first byte addr of the flash drive in SPI flash
static uint32_t _flash_end; /* first byte addr after the flash drive in SPI flash */
static uint32_t _flash_size; /* resulting size of the flash drive in SPI flash */
#define SPIFFS_FLASH_BEGIN 0x80000 /* TODO determine real possible value */
static esp_rom_spiflash_chip_t* _flashchip = NULL;
void flash_drive_init (void)
/* flash_id determines the flash size in kByte */
static const uint32_t flash_sizes[] = {
256, /* last byte of id is 0x12 */
512, /* last byte of id is 0x13 */
1 * 1024, /* last byte of id is 0x14 */
2 * 1024, /* last byte of id is 0x15 */
4 * 1024, /* last byte of id is 0x16 */
8 * 1024, /* last byte of id is 0x17 */
16 * 1024 /* last byte of id is 0x18 */
};
void spi_flash_drive_init (void)
{
DEBUG("%s\n", __func__);
_flashchip = &g_rom_flashchip;
assert(_flashchip);
#ifdef MCU_ESP8266
_flashchip->deviceId = spi_flash_get_id();
uint8_t devid_lb = _flashchip->deviceId >> 16 & 0xff;
if (devid_lb >= 0x12 && devid_lb <= 0x18) {
_flashchip->chip_size = flash_sizes[devid_lb - 0x12] << 10;
}
else {
LOG_TAG_WARNING("spi_flash", "could not determine flash size, "
"4 MBytes are used as default size\n");
_flashchip->chip_size = 4 << 20;
}
#endif /* MCU_ESP8266 */
_flash_driver.init = &_flash_init;
_flash_driver.read = &_flash_read;
_flash_driver.write = &_flash_write;
_flash_driver.erase = &_flash_erase;
_flash_driver.power = &_flash_power;
_flash_beg = SPIFFS_FLASH_BEGIN;
_flash_end = flashchip->chip_size - 5 * flashchip->sector_size;
/* first, set the beginning of flash to 0x0 to read partition table */
_flash_beg = 0x0;
_flash_end = _flashchip->chip_size - 5 * _flashchip->sector_size;
_flash_size = _flash_end - _flash_beg;
/* read in partition table an determine the top of all partitions */
uint32_t part_addr = ESP_PART_TABLE_ADDR;
uint8_t part_buf[ESP_PART_ENTRY_SIZE];
bool part_read = true;
uint32_t part_top = 0;
esp_partition_info_t* part = (esp_partition_info_t*)part_buf;
while (part_read && part_addr < ESP_PART_TABLE_ADDR + ESP_PART_TABLE_SIZE) {
spi_flash_read (part_addr, (void*)part_buf, ESP_PART_ENTRY_SIZE);
if (part->magic == ESP_PART_ENTRY_MAGIC) {
DEBUG("%s partition @%08x size=%08x label=%s\n", __func__,
part->pos.offset, part->pos.size, part->label);
if (part->pos.offset + part->pos.size > part_top) {
part_top = part->pos.offset + part->pos.size;
}
part_addr += ESP_PART_ENTRY_SIZE;
}
else {
part_read = false;
}
}
#ifdef MCU_ESP32
/* map the partition top address to next higher multiple of 0x100000 (1 MB) */
part_top = (part_top + 0x100000) & ~0xfffff;
#else /* MCU_ESP32 */
/* map the partition top address to next higher multiple of 0x80000 (512 kB) */
part_top = (part_top + 0x80000) & ~0x7ffff;
#endif /* MCU_ESP32 */
/*
* if flash drive start address is not configured, use the determined
* one otherwise check the configured one and use it
*/
#if SPI_FLASH_DRIVE_START
if (part_top > SPI_FLASH_DRIVE_START) {
LOG_TAG_ERROR("spi_flash", "configured MTD start address in SPI Flash is to less\n");
}
else if (SPI_FLASH_DRIVE_START % _flashchip->sector_size) {
LOG_TAG_ERROR("spi_flash", "configured start address has to be a "
"multiple of %d byte\n", _flashchip->sector_size);
part_top = ((SPI_FLASH_DRIVE_START +
_flashchip->sector_size)) & ~(_flashchip->sector_size-1);
}
else {
part_top = SPI_FLASH_DRIVE_START;
}
#endif
/* second, change flash parameters according to partition table */
_flash_beg = part_top;
_flash_end = _flashchip->chip_size - 5 * _flashchip->sector_size;
_flash_size = _flash_end - _flash_beg; /* MUST be at least 3 sectors (0x3000) */
LOG_TAG_INFO("spi_flash", "MTD in SPI flash starts at address 0x%08x "
"with a size of %d kbytes\n", _flash_beg, _flash_size >> 10);
_flash_dev.driver = &_flash_driver;
_flash_dev.sector_count = _flash_size / flashchip->sector_size;
_flash_dev.sector_count = _flash_size / _flashchip->sector_size;
mtd0 = &_flash_dev;
_flash_dev.pages_per_sector = flashchip->sector_size / flashchip->page_size;
_flash_dev.page_size = flashchip->page_size;
_flash_dev.pages_per_sector = _flashchip->sector_size / _flashchip->page_size;
_flash_dev.page_size = _flashchip->page_size;
DEBUG("%s flashchip chip_size=%d block_size=%d sector_size=%d page_size=%d\n", __func__,
flashchip->chip_size, flashchip->block_size,
flashchip->sector_size, flashchip->page_size);
_flashchip->chip_size, _flashchip->block_size,
_flashchip->sector_size, _flashchip->page_size);
DEBUG("%s flash_dev sector_count=%d pages_per_sector=%d page_size=%d\n", __func__,
_flash_dev.sector_count, _flash_dev.pages_per_sector, _flash_dev.page_size);
DEBUG("\n");
}
#ifdef MCU_ESP32
#define RETURN_WITH_ESP_ERR_CODE(err) do { \
switch (err) { \
case ESP_ROM_SPIFLASH_RESULT_OK : return ESP_OK; \
case ESP_ROM_SPIFLASH_RESULT_ERR : return ESP_ERR_FLASH_OP_FAIL; \
case ESP_ROM_SPIFLASH_RESULT_TIMEOUT: return ESP_ERR_FLASH_OP_TIMEOUT; \
} \
return ESP_FAIL; \
} while(0)
uint8_t _flash_buf[ESP_ROM_SPIFLASH_BUFF_BYTE_READ_NUM];
esp_err_t IRAM_ATTR spi_flash_read(size_t addr, void *buff, size_t size)
{
DEBUG("%s addr=%08x size=%u buf=%p\n", __func__, addr, size, buff);
CHECK_PARAM_RET (buff != NULL, -ENOTSUP);
/* size must be within the flash address space */
CHECK_PARAM_RET (addr + size <= _flash_end, -EOVERFLOW);
int result = ESP_ROM_SPIFLASH_RESULT_OK;
uint32_t len = size;
/* if addr is not 4 byte aligned, we need to read the first full word */
if (addr & 0x3) {
uint32_t word_addr = addr & ~0x3;
uint32_t pos_in_word = addr & 0x3;
uint32_t len_in_word = 4 - pos_in_word;
len_in_word = (len_in_word < len) ? len_in_word : len;
/* disable interrupts and the cache */
critical_enter();
Cache_Read_Disable(PRO_CPU_NUM);
result = esp_rom_spiflash_read (word_addr, (uint32_t*)_flash_buf, 4);
memcpy(buff, _flash_buf + pos_in_word, len_in_word);
/* enable interrupts and the cache */
Cache_Read_Enable(PRO_CPU_NUM);
critical_exit();
buff = (uint8_t*)buff + len_in_word;
addr += len_in_word;
len -= len_in_word;
}
/* read all full words, maximum ESP_ROM_SPIFLASH_BUFF_BYTE_READ_NUM
in one read operation */
while (len > 4 && result == ESP_ROM_SPIFLASH_RESULT_OK) {
uint32_t len_full_words = len & ~0x3;
if (len_full_words > ESP_ROM_SPIFLASH_BUFF_BYTE_READ_NUM) {
len_full_words = ESP_ROM_SPIFLASH_BUFF_BYTE_READ_NUM;
}
/* disable interrupts and the cache */
critical_enter();
Cache_Read_Disable(PRO_CPU_NUM);
result |= esp_rom_spiflash_read (addr, (uint32_t*)_flash_buf, len_full_words);
memcpy(buff, _flash_buf, len_full_words);
/* enable interrupts and the cache */
Cache_Read_Enable(PRO_CPU_NUM);
critical_exit();
buff = (uint8_t*)buff + len_full_words;
addr += len_full_words;
len -= len_full_words;
}
/* if there is some remaining, we need to prepare last word */
if (len && result == ESP_ROM_SPIFLASH_RESULT_OK) {
/* disable interrupts and the cache */
critical_enter();
Cache_Read_Disable(PRO_CPU_NUM);
result |= esp_rom_spiflash_read (addr, (uint32_t*)_flash_buf, 4);
memcpy(buff, _flash_buf, len);
/* enable interrupts and the cache */
Cache_Read_Enable(PRO_CPU_NUM);
critical_exit();
}
/* return with the ESP-IDF error code that is mapped from ROM error code */
RETURN_WITH_ESP_ERR_CODE(result);
}
esp_err_t IRAM_ATTR spi_flash_write(size_t addr, const void *buff, size_t size)
{
DEBUG("%s addr=%08x size=%u buf=%p\n", __func__, addr, size, buff);
CHECK_PARAM_RET (buff != NULL, -ENOTSUP);
/* size must be within the flash address space */
CHECK_PARAM_RET (addr + size <= _flash_end, -EOVERFLOW);
/* prepare for write access */
int result = esp_rom_spiflash_unlock();
uint32_t len = size;
/* if addr is not 4 byte aligned, we need to prepare first full word */
if (addr & 0x3 && result == ESP_ROM_SPIFLASH_RESULT_OK) {
uint32_t word_addr = addr & ~0x3;
uint32_t pos_in_word = addr & 0x3;
uint32_t len_in_word = 4 - pos_in_word;
len_in_word = (len_in_word < len) ? len_in_word : len;
/* disable interrupts and the cache */
critical_enter();
Cache_Read_Disable(PRO_CPU_NUM);
result |= esp_rom_spiflash_read (word_addr, (uint32_t*)_flash_buf, 4);
memcpy(_flash_buf + pos_in_word, buff, len_in_word);
result |= esp_rom_spiflash_write (word_addr, (uint32_t*)_flash_buf, 4);
/* enable interrupts and the cache */
Cache_Read_Enable(PRO_CPU_NUM);
critical_exit();
buff = (uint8_t*)buff + len_in_word;
addr += len_in_word;
len -= len_in_word;
}
/* write all full words, maximum ESP_ROM_SPIFLASH_BUFF_BYTE_WRITE_NUM
in one write operation */
while (len > 4 && result == ESP_ROM_SPIFLASH_RESULT_OK) {
uint32_t len_full_words = len & ~0x3;
if (len_full_words > ESP_ROM_SPIFLASH_BUFF_BYTE_WRITE_NUM) {
len_full_words = ESP_ROM_SPIFLASH_BUFF_BYTE_WRITE_NUM;
}
/* disable interrupts and the cache */
critical_enter();
Cache_Read_Disable(PRO_CPU_NUM);
memcpy(_flash_buf, buff, len_full_words);
result |= esp_rom_spiflash_write (addr, (uint32_t*)_flash_buf, len_full_words);
/* enable interrupts and the cache */
Cache_Read_Enable(PRO_CPU_NUM);
critical_exit();
buff = (uint8_t*)buff + len_full_words;
addr += len_full_words;
len -= len_full_words;
}
/* if there is some remaining, we need to prepare last word */
if (len && result == ESP_ROM_SPIFLASH_RESULT_OK) {
/* disable interrupts and the cache */
critical_enter();
Cache_Read_Disable(PRO_CPU_NUM);
result |= esp_rom_spiflash_read (addr, (uint32_t*)_flash_buf, 4);
memcpy(_flash_buf, buff, len);
result |= esp_rom_spiflash_write (addr, (uint32_t*)_flash_buf, 4);
/* enable interrupts and the cache */
Cache_Read_Enable(PRO_CPU_NUM);
critical_exit();
}
/* reset write access */
esp_rom_spiflash_lock();
/* return with the ESP-IDF error code that is mapped from ROM error code */
RETURN_WITH_ESP_ERR_CODE(result);
}
esp_err_t IRAM_ATTR spi_flash_erase_sector(size_t sector)
{
return spi_flash_erase_range(sector * _flashchip->sector_size, 1);
}
esp_err_t IRAM_ATTR spi_flash_erase_range(size_t addr, size_t size)
{
/* size must be within the flash address space */
CHECK_PARAM_RET (addr + size <= _flash_end, -EOVERFLOW);
/* size must be a multiple of sector_size && at least one sector */
CHECK_PARAM_RET (size >= _flashchip->sector_size, -ENOTSUP);
CHECK_PARAM_RET (size % _flashchip->sector_size == 0, -ENOTSUP)
/* prepare for write access */
uint32_t result = esp_rom_spiflash_unlock();
/* erase as many sectors as necessary */
uint32_t sec = addr / _flashchip->sector_size;
uint32_t cnt = size / _flashchip->sector_size;
uint32_t sec_per_block = _flashchip->block_size / _flashchip->sector_size;
while (cnt && result == ESP_ROM_SPIFLASH_RESULT_OK) {
/* disable interrupts and the cache */
critical_enter();
Cache_Read_Disable(PRO_CPU_NUM);
/* erase block-wise (64 kByte) if cnt is at least sec_per_block */
if (cnt >= sec_per_block) {
result = esp_rom_spiflash_erase_block (sec / sec_per_block);
sec += sec_per_block;
cnt -= sec_per_block;
}
else {
result = esp_rom_spiflash_erase_sector (sec++);
cnt--;
}
/* enable interrupts and the cache */
Cache_Read_Enable(PRO_CPU_NUM);
critical_exit();
}
/* reset write access */
esp_rom_spiflash_lock();
/* return with the ESP-IDF error code that is mapped from ROM error code */
RETURN_WITH_ESP_ERR_CODE(result);
}
#endif /* MCU_ESP32 */
const esp_partition_t* esp_partition_find_first(esp_partition_type_t type,
esp_partition_subtype_t subtype,
const char* label)
{
uint32_t info_addr = ESP_PART_TABLE_ADDR;
uint8_t info_buf[ESP_PART_ENTRY_SIZE];
bool info_read = true;
esp_partition_info_t* info = (esp_partition_info_t*)info_buf;
esp_partition_t* part;
while (info_read && info_addr < ESP_PART_TABLE_ADDR + ESP_PART_TABLE_SIZE) {
spi_flash_read (info_addr, (void*)info_buf, ESP_PART_ENTRY_SIZE);
if (info->magic == ESP_PART_ENTRY_MAGIC) {
DEBUG("%s partition @%08x size=%08x label=%s\n", __func__,
info->pos.offset, info->pos.size, info->label);
if ((info->type == type) &&
(info->subtype == subtype || subtype == ESP_PARTITION_SUBTYPE_ANY) &&
(label == NULL || strcmp((const char*)info->label, label) == 0)) {
part = malloc(sizeof(esp_partition_t));
part->type = info->type;
part->subtype = info->subtype;
part->address = info->pos.offset;
part->size = info->pos.size;
part->encrypted = info->flags & PART_FLAG_ENCRYPTED;
strncpy(part->label, (const char*)info->label, sizeof(info->label));
part->label[sizeof(part->label) - 1] = 0x0;
return part;
}
info_addr += ESP_PART_ENTRY_SIZE;
}
else {
info_read = false;
}
}
return NULL;
}
esp_err_t esp_partition_erase_range(const esp_partition_t* part,
size_t addr, size_t size)
{
CHECK_PARAM_RET(part != NULL, ESP_ERR_INVALID_ARG);
/* start addr and size must be inside the partition */
CHECK_PARAM_RET(addr <= part->size, ESP_ERR_INVALID_ARG);
CHECK_PARAM_RET(addr + size <= part->size, ESP_ERR_INVALID_SIZE);
/* start addr and size must be a multiple of sector size */
CHECK_PARAM_RET(addr % SPI_FLASH_SEC_SIZE == 0, ESP_ERR_INVALID_ARG);
CHECK_PARAM_RET(size % SPI_FLASH_SEC_SIZE == 0, ESP_ERR_INVALID_SIZE);
return spi_flash_erase_range(part->address + addr, size);
}
static int _flash_init (mtd_dev_t *dev)
{
DEBUG("%s dev=%p driver=%p\n", __func__, dev, &_flash_driver);
CHECK_PARAM_RET (dev == &_flash_dev, -ENODEV);
#ifdef SPI_FLASH_CHIP_SIZE
if (SPI_FLASH_CHIP_SIZE <= SPIFFS_FLASH_BEGIN) {
#else
if (flashchip->chip_size <= SPIFFS_FLASH_BEGIN) {
#endif
if (_flashchip->chip_size <= _flash_beg) {
LOG_ERROR("Flash size is equal or less than %d Byte, "
"SPIFFS cannot be used\n", SPIFFS_FLASH_BEGIN);
"SPIFFS cannot be used\n", _flash_beg);
return -ENODEV;
}
return 0;
}
#define SPI_FLASH_BUF_SIZE 64
uint8_t _flash_buf[SPI_FLASH_BUF_SIZE];
static int _flash_read (mtd_dev_t *dev, void *buff, uint32_t addr, uint32_t size)
{
DEBUG("%s dev=%p addr=%08x size=%u buf=%p\n", __func__, dev, addr, size, buff);
@ -119,58 +508,7 @@ static int _flash_read (mtd_dev_t *dev, void *buff, uint32_t addr, uint32_t siz
/* size must be within the flash address space */
CHECK_PARAM_RET (_flash_beg + addr + size <= _flash_end, -EOVERFLOW);
#ifndef SDK_FLASH_FUNCTIONS
bool result = spiflash_read (_flash_beg + addr, buff, size);
return result ? (int)size : -EIO;
#else
critical_enter();
/* it would be great if would work in that way, but would be too easy :-( */
/* memcpy(buff, (void*)(_flash_beg + addr + 0x40200000), size); */
int result = SPI_FLASH_RESULT_OK;
uint32_t len = size;
/* if addr is not 4 byte aligned, we need to read the first full word */
if (addr & 0x3) {
uint32_t word_addr = addr & ~0x3;
uint32_t pos_in_word = addr & 0x3;
uint32_t len_in_word = 4 - pos_in_word;
len_in_word = (len_in_word < len) ? len_in_word : len;
result = spi_flash_read (_flash_beg + word_addr, (uint32_t*)_flash_buf, 4);
memcpy(buff, _flash_buf + pos_in_word, len_in_word);
buff = (uint8_t*)buff + len_in_word;
addr += len_in_word;
len -= len_in_word;
}
/* read all full words, maximum SPI_FLASH_BUF_SIZE in one write operation */
while (result == SPI_FLASH_RESULT_OK && len > 4) {
uint32_t len_full_words = len & ~0x3;
if (len_full_words > SPI_FLASH_BUF_SIZE) {
len_full_words = SPI_FLASH_BUF_SIZE;
}
result |= spi_flash_read (_flash_beg + addr, (uint32_t*)_flash_buf, len_full_words);
memcpy(buff, _flash_buf, len_full_words);
buff = (uint8_t*)buff + len_full_words;
addr += len_full_words;
len -= len_full_words;
}
/* if there is some remaining, we need to prepare last word */
if (result == SPI_FLASH_RESULT_OK && len) {
result |= spi_flash_read (_flash_beg + addr, (uint32_t*)_flash_buf, 4);
memcpy(buff, _flash_buf, len);
}
critical_exit();
return (result == SPI_FLASH_RESULT_OK) ? (int)size : -EIO;
#endif
return (spi_flash_read(_flash_beg + addr, buff, size) == ESP_OK) ? (int)size : -EIO;
}
static int _flash_write (mtd_dev_t *dev, const void *buff, uint32_t addr, uint32_t size)
@ -183,60 +521,11 @@ static int _flash_write (mtd_dev_t *dev, const void *buff, uint32_t addr, uint32
/* size must be within the flash address space */
CHECK_PARAM_RET (_flash_beg + addr + size <= _flash_end, -EOVERFLOW);
#ifndef SDK_FLASH_FUNCTIONS
/* addr + size must be within a page */
CHECK_PARAM_RET (size <= _flashchip->page_size, -EOVERFLOW);
CHECK_PARAM_RET ((addr % _flashchip->page_size) + size <= _flashchip->page_size, -EOVERFLOW);
bool result = spiflash_write (_flash_beg + addr, (uint8_t*)buff, size);
return result ? (int)size : -EIO;
#else
critical_enter();
int result = SPI_FLASH_RESULT_OK;
uint32_t len = size;
/* if addr is not 4 byte aligned, we need to prepare first full word */
if (addr & 0x3) {
uint32_t word_addr = addr & ~0x3;
uint32_t pos_in_word = addr & 0x3;
uint32_t len_in_word = 4 - pos_in_word;
len_in_word = (len_in_word < len) ? len_in_word : len;
result = spi_flash_read (_flash_beg + word_addr, (uint32_t*)_flash_buf, 4);
memcpy(_flash_buf + pos_in_word, buff, len_in_word);
result |= spi_flash_write (_flash_beg + word_addr, (uint32_t*)_flash_buf, 4);
buff = (uint8_t*)buff + len_in_word;
addr += len_in_word;
len -= len_in_word;
}
/* write all full words, maximum SPI_FLASH_BUF_SIZE in one write operation */
while (result == SPI_FLASH_RESULT_OK && len > 4) {
uint32_t len_full_words = len & ~0x3;
if (len_full_words > SPI_FLASH_BUF_SIZE) {
len_full_words = SPI_FLASH_BUF_SIZE;
}
memcpy(_flash_buf, buff, len_full_words);
result |= spi_flash_write (_flash_beg + addr, (uint32_t*)_flash_buf, len_full_words);
buff = (uint8_t*)buff + len_full_words;
addr += len_full_words;
len -= len_full_words;
}
/* if there is some remaining, we need to prepare last word */
if (result == SPI_FLASH_RESULT_OK && len) {
result |= spi_flash_read (_flash_beg + addr, (uint32_t*)_flash_buf, 4);
memcpy(_flash_buf, buff, len);
result |= spi_flash_write (_flash_beg + addr, (uint32_t*)_flash_buf, 4);
}
critical_exit();
return (result == SPI_FLASH_RESULT_OK) ? (int)size : -EIO;
#endif
return (spi_flash_write(_flash_beg + addr, buff, size) == ESP_OK) ? (int)size : -EIO;
}
static int _flash_erase (mtd_dev_t *dev, uint32_t addr, uint32_t size)
@ -249,34 +538,10 @@ static int _flash_erase (mtd_dev_t *dev, uint32_t addr, uint32_t size)
CHECK_PARAM_RET (_flash_beg + addr + size <= _flash_end, -EOVERFLOW);
/* size must be a multiple of sector_size && at least one sector */
CHECK_PARAM_RET (size >= flashchip->sector_size, -ENOTSUP);
CHECK_PARAM_RET (size % flashchip->sector_size == 0, -ENOTSUP)
CHECK_PARAM_RET (size >= _flashchip->sector_size, -EOVERFLOW);
CHECK_PARAM_RET (size % _flashchip->sector_size == 0, -EOVERFLOW)
#ifndef SDK_FLASH_FUNCTIONS
bool result = false;
uint32_t count = size / flashchip->sector_size;
while (count--) {
uint32_t sec = _flash_beg + addr + count * flashchip->sector_size;
if (!(result = spiflash_erase_sector (sec))) {
break;
}
}
return result ? 0 : -EIO;
#else
critical_enter();
uint32_t result = SPI_FLASH_RESULT_OK;
uint32_t count = size / flashchip->sector_size;
while (count--) {
uint32_t sec = (_flash_beg + addr) / flashchip->sector_size + count;
if ((result = spi_flash_erase_sector (sec)) != SPI_FLASH_RESULT_OK) {
break;
}
}
critical_exit();
return result;
#endif
return (spi_flash_erase_range(_flash_beg + addr, size) == ESP_OK) ? 0 : -EIO;
}
static int _flash_power (mtd_dev_t *dev, enum mtd_power_state power)
@ -285,3 +550,5 @@ static int _flash_power (mtd_dev_t *dev, enum mtd_power_state power)
return -ENOTSUP;
}
#endif /* MODULE_MTD */

View File

@ -1,5 +1,5 @@
/*
* Copyright (C) 2018 Gunar Schorcht
* Copyright (C) 2019 Gunar Schorcht
*
* This file is subject to the terms and conditions of the GNU Lesser
* General Public License v2.1. See the file LICENSE in the top level
@ -26,17 +26,17 @@
#include "log.h"
#include "periph/gpio.h" /* RIOT gpio.h */
#include "c_types.h"
#include "eagle_soc.h"
#include "ets_sys.h"
#include "esp8266/eagle_soc.h"
#include "esp8266/gpio_register.h"
#include "rom/ets_sys.h"
#include "sdk/ets.h"
#include "esp/gpio_regs.h"
#include "esp/iomux_regs.h"
#include "esp/rtc_regs.h"
#include "common.h"
#include "gpio_common.h"
#include "esp_common.h"
#include "gpio_arch.h"
#include "irq_arch.h"
#include "syscalls.h"
@ -48,7 +48,7 @@
const uint8_t _gpio_to_iomux[] = { 12, 5, 13, 4, 14, 15, 6, 7, 8, 9, 10, 11, 0, 1, 2, 3 };
const uint8_t _iomux_to_gpio[] = { 12, 13, 14, 15, 3, 1, 6, 7, 8, 9, 10, 11, 0, 2, 4, 5 };
_gpio_pin_usage_t _gpio_pin_usage [GPIO_PIN_NUMOF] =
gpio_pin_usage_t _gpio_pin_usage [GPIO_PIN_NUMOF] =
{
_GPIO, /* gpio0 */
@ -75,6 +75,12 @@ _gpio_pin_usage_t _gpio_pin_usage [GPIO_PIN_NUMOF] =
_GPIO /* gpio16 */
};
/* String representation of usage types */
const char* _gpio_pin_usage_str[] =
{
"GPIO", "I2C", "PWM", "SPI", "SPI Flash", "UART", "N/A"
};
int gpio_init(gpio_t pin, gpio_mode_t mode)
{
DEBUG("%s: %d %d\n", __func__, pin, mode);
@ -285,3 +291,20 @@ void gpio_toggle (gpio_t pin)
GPIO.OUT ^= BIT(pin);
}
int gpio_set_pin_usage(gpio_t pin, gpio_pin_usage_t usage)
{
CHECK_PARAM_RET(pin < GPIO_PIN_NUMOF, -1);
_gpio_pin_usage [pin] = usage;
return 0;
}
gpio_pin_usage_t gpio_get_pin_usage (gpio_t pin)
{
return (pin < GPIO_PIN_NUMOF) ? _gpio_pin_usage[pin] : _NOT_EXIST;
}
const char* gpio_get_pin_usage_str(gpio_t pin)
{
return _gpio_pin_usage_str[_gpio_pin_usage[((pin < GPIO_PIN_NUMOF) ? pin : _NOT_EXIST)]];
}

View File

@ -1,5 +1,5 @@
/*
* Copyright (C) 2018 Gunar Schorcht
* Copyright (C) 2019 Gunar Schorcht
*
* This file is subject to the terms and conditions of the GNU Lesser
* General Public License v2.1. See the file LICENSE in the top level
@ -22,8 +22,13 @@
#include "cpu.h"
#include "periph_conf.h"
#include "periph/hwrng.h"
#include "rom/ets_sys.h"
#include "esp/wdev_regs.h"
#ifdef MCU_ESP32
static const uint32_t* RNG_DATA_REG = (uint32_t*)0x3ff75144;
#else
static const uint32_t* RNG_DATA_REG = (uint32_t*)0x3ff20e44;
#endif
void hwrng_init(void)
{
@ -37,7 +42,7 @@ void hwrng_read(void *buf, unsigned int num)
while (count < num) {
/* read next 4 bytes of random data */
uint32_t tmp = WDEV.HWRNG;
uint32_t tmp = *RNG_DATA_REG;
/* copy data into result vector */
for (int i = 0; i < 4 && count < num; i++) {

View File

@ -1,5 +1,5 @@
/*
* Copyright (C) 2018 Gunar Schorcht
* Copyright (C) 2019 Gunar Schorcht
*
* This file is subject to the terms and conditions of the GNU Lesser
* General Public License v2.1. See the file LICENSE in the top level
@ -7,8 +7,8 @@
*/
/**
* @ingroup cpu_esp8266
* @ingroup drivers_periph_i2c
* @ingroup cpu_esp8266
* @ingroup drivers_periph_i2c
* @{
*
* @file
@ -22,18 +22,16 @@
/*
PLEASE NOTE:
Some parts of the implementation bases on the bit-banging implementation as
described in [wikipedia](https://en.wikipedia.org/wiki/I%C2%B2C) as well as
its implementation in [esp-open-rtos](https://github.com/SuperHouse/esp-open-rtos.git).
These parts are under the copyright of their respective owners.
The implementation bases on the bit-banging I2C master implementation as
described in [wikipedia](https://en.wikipedia.org/wiki/I%C2%B2C#Example_of_bit-banging_the_I%C2%B2C_master_protocol).
*/
#define ENABLE_DEBUG (0)
#include "debug.h"
#include <assert.h>
#include <stdbool.h>
#include <errno.h>
#include <stdbool.h>
#include "cpu.h"
#include "log.h"
@ -42,20 +40,36 @@
#include "periph/gpio.h"
#include "periph/i2c.h"
#include "common.h"
#include "esp_common.h"
#include "gpio_arch.h"
#include "rom/ets_sys.h"
#ifdef MCU_ESP32
#include "soc/gpio_reg.h"
#include "soc/gpio_struct.h"
/* max clock stretching counter */
#define I2C_CLOCK_STRETCH 200
/* gpio access macros */
#define GPIO_SET(l,h,b) if (b < 32) GPIO.l = BIT(b); else GPIO.h.val = BIT(32-b)
#define GPIO_GET(l,h,b) ((b < 32) ? GPIO.l & BIT(b) : GPIO.h.val & BIT(32-b))
#else /* MCU_ESP32 */
#include "esp/gpio_regs.h"
#include "sdk/ets.h"
#if defined(I2C_NUMOF) && I2C_NUMOF > 0
/* max clock stretching counter (ca. 10 ms) */
#define I2C_CLOCK_STRETCH 40000
/* has to be declared as extern since it is not possible to include */
/* user_interface.h due to conflicts with gpio_init */
/* following functions have to be declared as extern since it is not possible */
/* to include user_interface.h due to conflicts with gpio_init */
extern uint8_t system_get_cpu_freq(void);
extern bool system_update_cpu_freq(uint8_t freq);
/* max clock stretching counter (ca. 10 ms) */
#define I2C_CLOCK_STRETCH 40000
#endif /* MCU_ESP32 */
typedef struct
{
@ -71,50 +85,42 @@ typedef struct
uint32_t sda_bit; /* gpio bit mask for faster access */
uint32_t delay;
mutex_t lock;
} _i2c_bus_t;
static _i2c_bus_t _i2c_bus[] =
{
#if defined(I2C0_SDA) && defined(I2C0_SCL)
{
.speed = I2C0_SPEED,
.sda = I2C0_SDA,
.scl = I2C0_SCL
},
#endif
#if defined(I2C1_SDA) && defined(I2C1_SCL)
{
.speed = I2C1_SPEED,
.sda = I2C1_SDA,
.scl = I2C1_SCL
},
#endif
#if defined(I2C2_SDA) && defined(I2C2_SCL)
{
.speed = I2C2_SPEED,
.sda = I2C2_SDA,
.scl = I2C2_SCL
},
#endif
};
static _i2c_bus_t _i2c_bus[I2C_NUMOF] = {};
/* to ensure that I2C is always optimized with -O2 to use the defined delays */
#pragma GCC optimize ("O2")
#ifdef MCU_ESP32
static const uint32_t _i2c_delays[][3] =
{
/* values specify one half-period and are only valid for -O2 option */
/* value = [period - 0.25 us (240 MHz) / 0.5us(160MHz) / 1.0us(80MHz)] */
/* * cycles per second / 2 */
/* 1 us = 16 cycles (80 MHz) / 32 cycles (160 MHz) / 48 cycles (240) */
/* values for 80, 160, 240 MHz */
[I2C_SPEED_LOW] = {790, 1590, 2390}, /* 10 kbps (period 100 us) */
[I2C_SPEED_NORMAL] = { 70, 150, 230}, /* 100 kbps (period 10 us) */
[I2C_SPEED_FAST] = { 11, 31, 51}, /* 400 kbps (period 2.5 us) */
[I2C_SPEED_FAST_PLUS] = { 0, 7, 15}, /* 1 Mbps (period 1 us) */
[I2C_SPEED_HIGH] = { 0, 0, 0} /* 3.4 Mbps (period 0.3 us) not working */
};
#else /* MCU_ESP32 */
static const uint32_t _i2c_delays[][2] =
{
/* values specify one half-period and are only valid for -O2 option */
/* values specify one half-period and are only valid for -O2 option */
/* value = [period - 0.5us(160MHz) or 1.0us(80MHz)] * cycles per second / 2 */
/* cycles per us = ca. 20 (80 MHz) / ca. 40 (160 MHz) */
[I2C_SPEED_LOW] = {1990, 989}, /* 10 kbps (period 100 us) */
[I2C_SPEED_NORMAL] = { 190, 89}, /* 100 kbps (period 10 us) */
[I2C_SPEED_FAST] = { 40, 16}, /* 400 kbps (period 2.5 us) */
[I2C_SPEED_FAST_PLUS] = { 13, 0}, /* 1 Mbps (period 1 us) */
/* 1 us = 20 cycles (80 MHz) / 40 cycles (160 MHz) */
[I2C_SPEED_LOW] = {989, 1990}, /* 10 kbps (period 100 us) */
[I2C_SPEED_NORMAL] = { 89, 190}, /* 100 kbps (period 10 us) */
[I2C_SPEED_FAST] = { 16, 40}, /* 400 kbps (period 2.5 us) */
[I2C_SPEED_FAST_PLUS] = { 0, 13}, /* 1 Mbps (period 1 us) */
[I2C_SPEED_HIGH] = { 0, 0} /* 3.4 Mbps (period 0.3 us) is not working */
};
static mutex_t i2c_bus_lock[I2C_NUMOF] = { MUTEX_INIT };
#endif /* MCU_ESP32 */
/* forward declaration of internal functions */
@ -136,51 +142,86 @@ static void _i2c_abort (_i2c_bus_t* bus, const char* func);
static void _i2c_clear (_i2c_bus_t* bus);
/* implementation of i2c interface */
void i2c_init(i2c_t dev)
{
if (I2C_NUMOF != ARRAY_SIZE(_i2c_bus)) {
LOG_INFO("I2C_NUMOF does not match number of I2C_SDA_x/I2C_SCL_x definitions\n");
LOG_INFO("Please check your board configuration in 'board.h'\n");
assert(I2C_NUMOF < ARRAY_SIZE(_i2c_bus));
assert(dev < I2C_NUMOF_MAX);
assert(dev < I2C_NUMOF);
if (i2c_config[dev].speed == I2C_SPEED_HIGH) {
LOG_TAG_INFO("i2c", "I2C_SPEED_HIGH is not supported\n");
return;
}
CHECK_PARAM (dev < I2C_NUMOF)
mutex_init(&_i2c_bus[dev].lock);
if (_i2c_bus[dev].speed == I2C_SPEED_HIGH) {
LOG_INFO("I2C_SPEED_HIGH is not supported\n");
return;
}
i2c_acquire (dev);
_i2c_bus[dev].scl = i2c_config[dev].scl;
_i2c_bus[dev].sda = i2c_config[dev].sda;
_i2c_bus[dev].speed = i2c_config[dev].speed;
_i2c_bus[dev].dev = dev;
_i2c_bus[dev].delay =_i2c_delays[_i2c_bus[dev].speed][ets_get_cpu_frequency() == 80 ? 1 : 0];
_i2c_bus[dev].scl_bit = BIT(_i2c_bus[dev].scl); /* store bit mask for faster access */
_i2c_bus[dev].sda_bit = BIT(_i2c_bus[dev].sda); /* store bit mask for faster access */
_i2c_bus[dev].started = false; /* for handling of repeated start condition */
DEBUG ("%s: scl=%d sda=%d speed=%d\n", __func__,
_i2c_bus[dev].scl, _i2c_bus[dev].sda, _i2c_bus[dev].speed);
switch (ets_get_cpu_frequency()) {
case 80: _i2c_bus[dev].delay = _i2c_delays[_i2c_bus[dev].speed][0]; break;
case 160: _i2c_bus[dev].delay = _i2c_delays[_i2c_bus[dev].speed][1]; break;
#ifdef MCU_ESP32
case 240: _i2c_bus[dev].delay = _i2c_delays[_i2c_bus[dev].speed][2]; break;
#endif
default : LOG_TAG_INFO("i2c", "I2C software implementation is not "
"supported for this CPU frequency: %d MHz\n",
ets_get_cpu_frequency());
return;
}
DEBUG("%s: scl=%d sda=%d speed=%d\n", __func__,
_i2c_bus[dev].scl, _i2c_bus[dev].sda, _i2c_bus[dev].speed);
/* reset the GPIO usage if the pins were used for I2C before */
if (gpio_get_pin_usage(_i2c_bus[dev].scl) == _I2C) {
gpio_set_pin_usage(_i2c_bus[dev].scl, _GPIO);
}
if (gpio_get_pin_usage(_i2c_bus[dev].sda) == _I2C) {
gpio_set_pin_usage(_i2c_bus[dev].sda, _GPIO);
}
/* Configure and initialize SDA and SCL pin. */
#ifdef MCU_ESP32
/*
* Configure and initialize SDA and SCL pin.
* Note: Due to critical timing required by the I2C software
* implementation, the ESP8266 GPIOs can not be used directly in GPIO_OD_PU
* mode. Instead, the GPIOs are configured in GPIO_IN_PU mode with
* open-drain output driver. Signal levels are then realized as following:
* ESP32 pins are used in input/output mode with open-drain output driver.
* Signal levels are then realized as following:
*
* - HIGH: Output value 1 lets the pin floating and is pulled-up to high.
* - LOW : Output value 0 actively drives the pin to low.
*/
if (gpio_init(_i2c_bus[dev].scl, GPIO_IN_OD_PU) ||
gpio_init(_i2c_bus[dev].sda, GPIO_IN_OD_PU)) {
return;
}
#else /* MCU_ESP32 */
/*
* Due to critical timing required by the I2C software implementation,
* the ESP8266 GPIOs can not be used directly in GPIO_OD_PU mode.
* Instead, the GPIOs are configured in GPIO_IN_PU mode with open-drain
* output driver. Signal levels are then realized as following:
*
* - HIGH: The GPIO is used in the configured GPIO_IN_PU mode. In this
* mode, the output driver is in open-drain mode and pulled-up.
* - LOW : The GPIO is temporarily switched to GPIO_OD_PU mode. In this
* mode, the output value 0, which is written during
* initialization, actively drives the output to low.
* initialization, actively drives the pin to low.
*/
gpio_init (_i2c_bus[dev].scl, GPIO_IN_PU);
gpio_init (_i2c_bus[dev].sda, GPIO_IN_PU);
gpio_clear (_i2c_bus[dev].scl);
gpio_clear (_i2c_bus[dev].sda);
if (gpio_init(_i2c_bus[dev].scl, GPIO_IN_PU) ||
gpio_init(_i2c_bus[dev].sda, GPIO_IN_PU)) {
return;
}
#endif /* MCU_ESP32 */
/* store the usage type in GPIO table */
gpio_set_pin_usage(_i2c_bus[dev].scl, _I2C);
gpio_set_pin_usage(_i2c_bus[dev].sda, _I2C);
/* set SDA and SCL to be floating and pulled-up to high */
_i2c_sda_high (&_i2c_bus[dev]);
@ -189,16 +230,14 @@ void i2c_init(i2c_t dev)
/* clear the bus if necessary (SDA is driven permanently low) */
_i2c_clear (&_i2c_bus[dev]);
i2c_release (dev);
return;
}
int i2c_acquire(i2c_t dev)
{
CHECK_PARAM_RET (dev < I2C_NUMOF, -1)
assert(dev < I2C_NUMOF);
mutex_lock(&i2c_bus_lock[dev]);
mutex_lock(&_i2c_bus[dev].lock);
return 0;
}
@ -206,7 +245,7 @@ void i2c_release(i2c_t dev)
{
assert(dev < I2C_NUMOF);
mutex_unlock(&i2c_bus_lock[dev]);
mutex_unlock(&_i2c_bus[dev].lock);
}
int /* IRAM */ i2c_read_bytes(i2c_t dev, uint16_t addr, void *data, size_t len, uint8_t flags)
@ -214,7 +253,8 @@ int /* IRAM */ i2c_read_bytes(i2c_t dev, uint16_t addr, void *data, size_t len,
DEBUG ("%s: dev=%u addr=%02x data=%p len=%d flags=%01x\n",
__func__, dev, addr, data, len, flags);
CHECK_PARAM_RET (dev < I2C_NUMOF, -EINVAL);
assert(dev < I2C_NUMOF);
CHECK_PARAM_RET (len > 0, -EINVAL);
CHECK_PARAM_RET (data != NULL, -EINVAL);
@ -235,7 +275,7 @@ int /* IRAM */ i2c_read_bytes(i2c_t dev, uint16_t addr, void *data, size_t len,
/* prepare 10 bit address bytes */
uint8_t addr1 = 0xf0 | (addr & 0x0300) >> 7 | I2C_READ;
uint8_t addr2 = addr & 0xff;
/* send address bytes wit read flag */
/* send address bytes with read flag */
if ((res = _i2c_write_byte (bus, addr1)) != 0 ||
(res = _i2c_write_byte (bus, addr2)) != 0) {
/* abort transfer */
@ -275,7 +315,8 @@ int /* IRAM */ i2c_write_bytes(i2c_t dev, uint16_t addr, const void *data, size_
DEBUG ("%s: dev=%u addr=%02x data=%p len=%d flags=%01x\n",
__func__, dev, addr, data, len, flags);
CHECK_PARAM_RET (dev < I2C_NUMOF, -EINVAL);
assert(dev < I2C_NUMOF);
CHECK_PARAM_RET (len > 0, -EINVAL);
CHECK_PARAM_RET (data != NULL, -EINVAL);
@ -348,74 +389,99 @@ void i2c_poweroff(i2c_t dev)
static inline void _i2c_delay (_i2c_bus_t* bus)
{
/* produces a delay */
/* ca. 20 cycles = 1 us (80 MHz) or ca. 40 cycles = 1 us (160 MHz) */
uint32_t cycles = bus->delay;
if (cycles) {
__asm__ volatile ("1: _addi.n %0, %0, -1 \n"
" bnez %0, 1b \n" : "=r" (cycles) : "0" (cycles));
__asm__ volatile ("1: _addi.n %0, %0, -1 \n"
" bnez %0, 1b \n" : "=r" (cycles) : "0" (cycles));
}
}
/*
* Note: Due to critical timing required by the I2C software implementation,
* the ESP8266 GPIOs can not be used directly in GPIO_OD_PU mode. Instead,
* the GPIOs are configured in GPIO_IN_PU mode with open-drain output driver.
* Signal levels are then realized as following:
* Please note: SDA and SDL pins are used in GPIO_OD_PU mode
* (open-drain with pull-ups).
*
* - HIGH: The GPIO is used in the configured GPIO_IN_PU mode. In this mode,
* the output driver is in open-drain mode and pulled-up.
* - LOW : The GPIO is temporarily switched to GPIO_OD_PU mode. In this mode,
* the output value 0, which is written during initialization,
* actively drives the output to low.
* Setting a pin which is in open-drain mode leaves the pin floating and
* the signal is pulled up to high. The signal can then be actively driven
* to low by a slave. A read operation returns the current signal at the pin.
*
* Clearing a pin which is in open-drain mode actively drives the signal to
* low.
*/
static inline bool _i2c_scl_read(_i2c_bus_t* bus)
{
/* read SCL status */
/* read SCL status (pin is in open-drain mode and set) */
#ifdef MCU_ESP32
return GPIO_GET(in, in1, bus->scl);
#else /* MCU_ESP32 */
return GPIO.IN & bus->scl_bit;
#endif /* MCU_ESP32 */
}
static inline bool _i2c_sda_read(_i2c_bus_t* bus)
{
/* read SDA status */
/* read SDA status (pin is in open-drain mode and set) */
#ifdef MCU_ESP32
return GPIO_GET(in, in1, bus->sda);
#else /* MCU_ESP32 */
return GPIO.IN & bus->sda_bit;
}
static inline void _i2c_scl_low(_i2c_bus_t* bus)
{
/*
* set SCL signal low (switch temporarily to GPIO_OD_PU where the
* written output value 0 drives the pin actively to low)
*/
GPIO.ENABLE_OUT_SET = bus->scl_bit;
#endif /* MCU_ESP32 */
}
static inline void _i2c_scl_high(_i2c_bus_t* bus)
{
#ifdef MCU_ESP32
/* set SCL signal high (pin is in open-drain mode and pulled-up) */
GPIO_SET(out_w1ts, out1_w1ts, bus->scl);
#else /* MCU_ESP32 */
/*
* set SCL signal high (switch back to GPIO_IN_PU mode, that is the pin is
* in open-drain mode and pulled-up to high)
*/
GPIO.ENABLE_OUT_CLEAR = bus->scl_bit;
#endif /* MCU_ESP32 */
}
static inline void _i2c_sda_low(_i2c_bus_t* bus)
static inline void _i2c_scl_low(_i2c_bus_t* bus)
{
#ifdef MCU_ESP32
/* set SCL signal low (actively driven to low) */
GPIO_SET(out_w1tc, out1_w1tc, bus->scl);
#else /* MCU_ESP32 */
/*
* set SDA signal low (switch temporarily to GPIO_OD_PU where the
* set SCL signal low (switch temporarily to GPIO_OD_PU where the
* written output value 0 drives the pin actively to low)
*/
GPIO.ENABLE_OUT_SET = bus->sda_bit;
GPIO.ENABLE_OUT_SET = bus->scl_bit;
#endif /* MCU_ESP32 */
}
static inline void _i2c_sda_high(_i2c_bus_t* bus)
{
#ifdef MCU_ESP32
/* set SDA signal high (pin is in open-drain mode and pulled-up) */
GPIO_SET(out_w1ts, out1_w1ts, bus->sda);
#else /* MCU_ESP32 */
/*
* set SDA signal high (switch back to GPIO_IN_PU mode, that is the pin is
* in open-drain mode and pulled-up to high)
*/
GPIO.ENABLE_OUT_CLEAR = bus->sda_bit;
#endif /* MCU_ESP32 */
}
static inline void _i2c_sda_low(_i2c_bus_t* bus)
{
#ifdef MCU_ESP32
/* set SDA signal low (actively driven to low) */
GPIO_SET(out_w1tc, out1_w1tc, bus->sda);
#else /* MCU_ESP32 */
/*
* set SDA signal low (switch temporarily to GPIO_OD_PU where the
* written output value 0 drives the pin actively to low)
*/
GPIO.ENABLE_OUT_SET = bus->sda_bit;
#endif /* MCU_ESP32 */
}
static void _i2c_clear(_i2c_bus_t* bus)
@ -500,7 +566,7 @@ static /* IRAM */ int _i2c_start_cond(_i2c_bus_t* bus)
/* SDA = passive HIGH (floating and pulled-up) */
_i2c_sda_high (bus);
/* t_VD;DAT not neccessary */
/* t_VD;DAT not necessary */
/* _i2c_delay (bus); */
/* SCL = passive HIGH (floating and pulled-up) */
@ -724,7 +790,7 @@ static /* IRAM */ int _i2c_read_byte(_i2c_bus_t* bus, uint8_t *byte, bool ack)
if (res != 0) {
return res;
}
*byte = (*byte << 1) | bit;
*byte = (*byte << 1) | (bit ? 1 : 0);
}
/* write acknowledgement flag */
@ -735,17 +801,8 @@ static /* IRAM */ int _i2c_read_byte(_i2c_bus_t* bus, uint8_t *byte, bool ack)
void i2c_print_config(void)
{
for (unsigned bus = 0; bus < I2C_NUMOF; bus++) {
LOG_INFO("\tI2C_DEV(%d): scl=%d sda=%d\n",
bus, _i2c_bus[bus].scl, _i2c_bus[bus].sda);
for (unsigned dev = 0; dev < I2C_NUMOF; dev++) {
printf("\tI2C_DEV(%u)\tscl=%d sda=%d\n",
dev, i2c_config[dev].scl, i2c_config[dev].sda);
}
}
#else /* if defined(I2C_NUMOF) && I2C_NUMOF */
void i2c_print_config(void)
{
LOG_INFO("\tI2C: no devices\n");
}
#endif /* if defined(I2C_NUMOF) && I2C_NUMOF */

View File

@ -1,5 +1,5 @@
/*
* Copyright (C) 2018 Gunar Schorcht
* Copyright (C) 2019 Gunar Schorcht
*
* This file is subject to the terms and conditions of the GNU Lesser
* General Public License v2.1. See the file LICENSE in the top level
@ -18,31 +18,28 @@
* @}
*/
#define ENABLE_DEBUG 0
#define ENABLE_DEBUG (0)
#include "debug.h"
#include <stdbool.h>
#include "irq.h"
#include "esp/xtensa_ops.h"
#include "sdk/ets_task.h"
#include "sdk/sdk.h"
#include "syscalls.h"
void pm_set_lowest(void)
{
DEBUG ("%s\n", __func__);
DEBUG ("%s enter to sleep @%u\n", __func__, system_get_time());
#if !defined(QEMU)
DEBUG ("%s enter to sleep @%u\n", __func__, phy_get_mactime());
/* reset system watchdog timer */
system_wdt_feed();
#ifndef MODULE_ESP_QEMU
/* passive wait for interrupt to leave lowest power mode */
__asm__ volatile ("waiti 0");
DEBUG ("%s exit from sleep @%u\n", __func__, phy_get_mactime());
#endif
DEBUG ("%s exit from sleep @%u\n", __func__, system_get_time());
/* reset system watchdog timer */
system_wdt_feed();
}
void pm_off(void)

View File

@ -18,7 +18,7 @@
* @}
*/
#define ENABLE_DEBUG 0
#define ENABLE_DEBUG (0)
#include "debug.h"
#include "cpu.h"
@ -27,21 +27,19 @@
#include "periph/pwm.h"
#include "periph/gpio.h"
#include "common.h"
#include "esp_common.h"
#include "esp/iomux_regs.h"
#include "esp/timer_regs.h"
#include "gpio_common.h"
#include "sdk/ets.h"
#if defined(PWM_NUMOF) && PWM_NUMOF > 0
#include "gpio_arch.h"
#include "sdk/sdk.h"
#include "xtensa/xtensa_api.h"
#define TIMER_FRC1_CLKDIV_16 BIT(2)
#define TIMER_FRC1_CLKDIV_256 BIT(3)
#define ETS_FRC1_INT_ENABLE ETS_FRC1_INTR_ENABLE
#define ETS_FRC1_INT_DISABLE ETS_FRC1_INTR_DISABLE
#define ETS_FRC1_INT_ATTACH ETS_FRC_TIMER1_INTR_ATTACH
#define ETS_FRC1_NMI_ATTACH ETS_FRC_TIMER1_NMI_INTR_ATTACH
#define ETS_FRC1_INT_ENABLE() xt_ints_on(BIT(ETS_FRC_TIMER1_INUM))
#define ETS_FRC1_INT_DISABLE() xt_ints_off(BIT(ETS_FRC_TIMER1_INUM))
#define ETS_FRC1_INT_ATTACH(f, a) xt_set_interrupt_handler(ETS_FRC_TIMER1_INUM, f, a)
typedef struct
{
@ -65,8 +63,6 @@ typedef struct
static _pwm_dev_t _pwm_dev;
static const uint32_t _pwm_channel_gpios[] = PWM0_CHANNEL_GPIOS;
static void _pwm_timer_handler (void* arg)
{
irq_isr_enter ();
@ -119,14 +115,15 @@ uint32_t pwm_init(pwm_t pwm, pwm_mode_t mode, uint32_t freq, uint16_t res)
{
DEBUG ("%s pwm=%u mode=%u freq=%u, res=%u\n", __func__, pwm, mode, freq, res);
uint8_t _pwm_channel_gpio_num = sizeof(_pwm_channel_gpios) >> 2;
uint8_t _pwm_channel_gpio_num = sizeof(pwm0_channels) >> 2;
CHECK_PARAM_RET (pwm < PWM_NUMOF, 0);
CHECK_PARAM_RET (freq > 0, 0);
CHECK_PARAM_RET (_pwm_channel_gpio_num <= PWM_CHANNEL_NUM_MAX, 0);
assert(pwm < PWM_NUMOF_MAX);
assert(pwm < PWM_NUMOF);
assert(freq > 0);
assert(_pwm_channel_gpio_num <= PWM_CHANNEL_NUM_MAX);
/* maximum number of cycles per second (freq*res) should not be greater than */
/* 100.000 (period of 10 us), reduce freq if neccessary and keep resolution */
/* 100.000 (period of 10 us), reduce freq if necessary and keep resolution */
if (res * freq > PWM_MAX_CPS) {
freq = PWM_MAX_CPS / res;
}
@ -138,21 +135,21 @@ uint32_t pwm_init(pwm_t pwm, pwm_mode_t mode, uint32_t freq, uint16_t res)
_pwm_dev.mode = mode;
for (int i = 0; i < _pwm_channel_gpio_num; i++) {
if (_gpio_pin_usage[_pwm_channel_gpios[i]] != _GPIO) {
if (gpio_get_pin_usage(pwm0_channels[i]) != _GPIO) {
LOG_ERROR("GPIO%d is used for something else and cannot be used as PWM output\n", i);
return 0;
}
if (gpio_init(_pwm_channel_gpios[i], GPIO_OUT) < 0) {
if (gpio_init(pwm0_channels[i], GPIO_OUT) < 0) {
return 0;
}
gpio_clear (_pwm_channel_gpios[i]);
gpio_clear (pwm0_channels[i]);
_pwm_dev.chn[_pwm_dev.chn_num].duty = 0;
_pwm_dev.chn[_pwm_dev.chn_num].next_on = 0;
_pwm_dev.chn[_pwm_dev.chn_num].next_off = 0;
_pwm_dev.chn[_pwm_dev.chn_num].gpio = _pwm_channel_gpios[i];
_pwm_dev.chn[_pwm_dev.chn_num].gpio = pwm0_channels[i];
_pwm_dev.chn_num++;
}
@ -169,7 +166,7 @@ uint32_t pwm_init(pwm_t pwm, pwm_mode_t mode, uint32_t freq, uint16_t res)
uint8_t pwm_channels(pwm_t pwm)
{
CHECK_PARAM_RET (pwm < PWM_NUMOF, 0);
assert(pwm < PWM_NUMOF);
return _pwm_dev.chn_num;
}
@ -178,9 +175,9 @@ void pwm_set(pwm_t pwm, uint8_t channel, uint16_t value)
{
DEBUG("%s pwm=%u channel=%u value=%u\n", __func__, pwm, channel, value);
CHECK_PARAM (pwm < PWM_NUMOF);
CHECK_PARAM (channel < _pwm_dev.chn_num);
CHECK_PARAM (value <= _pwm_dev.res);
assert(pwm < PWM_NUMOF);
assert(channel < _pwm_dev.chn_num);
assert(value <= _pwm_dev.res);
uint32_t state = irq_disable();
uint32_t phase = _pwm_dev.cycles - _pwm_dev.cycles % _pwm_dev.res;
@ -226,25 +223,16 @@ void pwm_poweron(pwm_t pwm)
void pwm_poweroff(pwm_t pwm)
{
CHECK_PARAM (pwm < PWM_NUMOF);
assert(pwm < PWM_NUMOF);
_pwm_stop ();
}
void pwm_print_config(void)
{
LOG_INFO("\tPWM_DEV(0): channels=[ ");
for (unsigned i = 0; i < sizeof(_pwm_channel_gpios) >> 2; i++) {
LOG_INFO("%d ", _pwm_channel_gpios[i]);
printf("\tPWM_DEV(0)\tchannels=[ ");
for (unsigned i = 0; i < sizeof(pwm0_channels) >> 2; i++) {
printf("%d ", pwm0_channels[i]);
}
LOG_INFO("]\n");
printf("]\n");
}
#else /* defined(PWM_NUMOF) && PWM_NUMOF > 0 */
void pwm_print_config(void)
{
LOG_INFO("\tPWM: no devices\n");
}
#endif /* defined(PWM_NUMOF) && PWM_NUMOF > 0 */

View File

@ -26,9 +26,9 @@
#include "log.h"
#include "periph/rtc.h"
#include "common.h"
#include "esp_common.h"
#include "sdk/ets.h"
#include "sdk/sdk.h"
void rtc_init(void)
{

View File

@ -21,32 +21,77 @@
#define ENABLE_DEBUG (0)
#include "debug.h"
#include "common.h"
#include "esp_common.h"
#include "log.h"
#if defined(MODULE_PERIPH_SPI)
#include <string.h>
#include "cpu.h"
#include "mutex.h"
#include "periph/spi.h"
#include "esp_attr.h"
#include "gpio_arch.h"
#ifdef MCU_ESP32
#include "driver/periph_ctrl.h"
#include "rom/ets_sys.h"
#include "soc/gpio_reg.h"
#include "soc/gpio_sig_map.h"
#include "soc/gpio_struct.h"
#include "soc/io_mux_reg.h"
#include "soc/spi_reg.h"
#include "soc/spi_struct.h"
#else /* MCU_ESP32 */
#include "esp/iomux_regs.h"
#include "esp/spi_regs.h"
#include "esp8266/spi_register.h"
#include "esp8266/spi_struct.h"
#include "gpio_common.h"
#define SPI_DOUTDIN (BIT(0))
#define SPI_BUS_NUM 2
#define SPI_BLOCK_SIZE 64 /* number of bytes per SPI transfer */
#endif /* MCU_ESP32 */
static mutex_t _spi_lock[SPI_BUS_NUM] = { MUTEX_INIT };
#define SPI_BLOCK_SIZE 64 /* number of bytes per SPI transfer */
/* indicate whether SPI interface were already initilized */
static bool _spi_initialized[SPI_BUS_NUM] = { false };
/* pins of FSI are fixed */
#define FSPI_SCK GPIO6
#define FSPI_MISO GPIO7
#define FSPI_MOSI GPIO8
/* indicate whether pins of the SPI interface were already initilized */
static bool _spi_pins_initialized[SPI_BUS_NUM] = { false };
/** structure which describes all properties of one SPI bus */
struct _spi_bus_t {
spi_dev_t* regs; /* pointer to register data struct of the SPI device */
mutex_t lock; /* mutex for each possible SPI interface */
bool initialized; /* interface already initialized */
bool pins_initialized; /* pins interface initialized */
#ifdef MCU_ESP32
uint8_t mod; /* peripheral hardware module of the SPI interface */
uint8_t int_src; /* peripheral interrupt source used by the SPI device */
uint8_t signal_sck; /* SCK signal from the controller */
uint8_t signal_mosi; /* MOSI signal from the controller */
uint8_t signal_miso; /* MISO signal to the controller */
#endif /* MCU_ESP32 */
};
static struct _spi_bus_t _spi[] = {
#ifdef SPI0_CTRL
{
.initialized = false,
.pins_initialized = false,
.lock = MUTEX_INIT
},
#endif
#ifdef SPI1_CTRL
{
.initialized = false,
.pins_initialized = false,
.lock = MUTEX_INIT
},
#endif
};
/*
* GPIOs that were once initialized as SPI interface pins can not be used
@ -57,23 +102,48 @@ static bool _spi_pins_initialized[SPI_BUS_NUM] = { false };
* the *spi_init_cs* function or the *spi_acquire* function when the interface
* is used for the first time.
*/
void IRAM spi_init (spi_t bus)
void IRAM_ATTR spi_init (spi_t bus)
{
assert(bus < SPI_NUMOF_MAX);
assert(bus < SPI_NUMOF);
switch (spi_config[bus].ctrl) {
#ifdef MCU_ESP32
case HSPI: _spi[bus].regs = &SPI2;
_spi[bus].mod = PERIPH_HSPI_MODULE;
_spi[bus].int_src = ETS_SPI2_INTR_SOURCE;
_spi[bus].signal_sck = HSPICLK_OUT_IDX;
_spi[bus].signal_mosi = HSPID_OUT_IDX;
_spi[bus].signal_miso = HSPIQ_IN_IDX;
break;
case VSPI: _spi[bus].regs = &SPI3;
_spi[bus].mod = PERIPH_VSPI_MODULE;
_spi[bus].int_src = ETS_SPI3_INTR_SOURCE;
_spi[bus].signal_sck = VSPICLK_OUT_IDX;
_spi[bus].signal_mosi = VSPID_OUT_IDX;
_spi[bus].signal_miso = VSPIQ_IN_IDX;
break;
#else /* MCU_ESP32 */
case HSPI: _spi[bus].regs = &SPI1;
break;
#endif /* MCU_ESP32 */
default: LOG_TAG_ERROR("spi", "invalid SPI interface controller "
"used for SPI_DEV(%d)\n", bus);
break;
}
return;
}
void _spi_init_internal(spi_t bus)
/* Internal initialization function when the interface is used the first time */
static void IRAM_ATTR _spi_init_internal(spi_t bus)
{
/* only one physical SPI(1) bus (HSPI) can be used for peripherals */
/* RIOT's SPI_DEV(0) is mapped to SPI(1) bus (HSPI) */
/* TODO SPI overlap mode SPI and HSPI */
CHECK_PARAM (bus == SPI_DEV(0));
assert(bus < SPI_NUMOF);
/* avoid multiple initializations */
if (_spi_initialized[bus]) {
if (_spi[bus].initialized) {
return;
}
_spi_initialized[bus] = true;
_spi[bus].initialized = true;
DEBUG("%s bus=%u\n", __func__, bus);
@ -82,139 +152,176 @@ void _spi_init_internal(spi_t bus)
/* check whether pins could be initialized, otherwise return, CS is not
initialized in spi_init_pins */
if (_gpio_pin_usage[SPI0_SCK_GPIO] != _SPI &&
_gpio_pin_usage[SPI0_MOSI_GPIO] != _SPI &&
_gpio_pin_usage[SPI0_MISO_GPIO] != _SPI) {
if (gpio_get_pin_usage(spi_config[bus].sck) != _SPI &&
gpio_get_pin_usage(spi_config[bus].miso) != _SPI &&
gpio_get_pin_usage(spi_config[bus].mosi) != _SPI &&
gpio_get_pin_usage(spi_config[bus].cs) != _SPI) {
return;
}
/* set bus into a defined state */
SPI(bus).USER0 = SPI_USER0_MOSI | SPI_USER0_CLOCK_IN_EDGE | SPI_USER0_DUPLEX;
SPI(bus).USER0 |= SPI_USER0_CS_SETUP | SPI_USER0_CS_HOLD;
#ifdef MCU_ESP32
/* enable (power on) the according SPI module */
periph_module_enable(_spi[bus].mod);
#endif /* MCU_ESP32 */
/* bring the bus into a defined state */
_spi[bus].regs->user.val = SPI_USR_MOSI | SPI_CK_I_EDGE | SPI_DOUTDIN |
SPI_CS_SETUP | SPI_CS_HOLD;
/* set byte order to little endian for read and write operations */
SPI(bus).USER0 &= ~(SPI_USER0_WR_BYTE_ORDER | SPI_USER0_RD_BYTE_ORDER);
_spi[bus].regs->user.wr_byte_order = 0;
_spi[bus].regs->user.rd_byte_order = 0;
/* set bit order to most significant first for read and write operations */
SPI(bus).CTRL0 = 0; /* ~(SPI_CTRL0_WR_BIT_ORDER | SPI_CTRL0_RD_BIT_ORDER); */
_spi[bus].regs->ctrl.wr_bit_order = 0;
_spi[bus].regs->ctrl.rd_bit_order = 0;
DEBUG("%s SPI(bus).USER0=%08x SPI(bus).CTRL0=%08x\n",
__func__, SPI(bus).USER0, SPI(bus).CTRL0);
/* reset all DIO or QIO flags */
_spi[bus].regs->ctrl.fread_qio = 0;
_spi[bus].regs->ctrl.fread_dio = 0;
_spi[bus].regs->ctrl.fread_quad = 0;
_spi[bus].regs->ctrl.fread_dual = 0;
/* disable fast read mode and write protection */
_spi[bus].regs->ctrl.fastrd_mode = 0;
#ifdef MCU_ESP32
_spi[bus].regs->ctrl.wp = 0;
#endif /* MCU_ESP32 */
/* acquire and release to set default parameters */
spi_acquire(bus, GPIO_UNDEF, SPI_MODE_0, SPI_CLK_1MHZ);
spi_release(bus);
}
void spi_init_pins(spi_t bus)
{
/* see spi_init */
CHECK_PARAM (bus == SPI_DEV(0));
assert(bus < SPI_NUMOF);
/* call initialization of the SPI interface if it is not initialized yet */
if (!_spi_initialized[bus]) {
if (!_spi[bus].initialized) {
_spi_init_internal(bus);
}
/* avoid multiple pin initializations */
if (_spi_pins_initialized[bus]) {
if (_spi[bus].pins_initialized) {
return;
}
_spi_pins_initialized[bus] = true;
_spi[bus].pins_initialized = true;
DEBUG("%s bus=%u\n", __func__, bus);
uint32_t iomux_func = (bus == 0) ? IOMUX_FUNC(1) : IOMUX_FUNC(2);
if (gpio_init (spi_config[bus].sck, GPIO_OUT) ||
gpio_init (spi_config[bus].mosi, GPIO_OUT) ||
gpio_init (spi_config[bus].miso, GPIO_IN)) {
LOG_TAG_ERROR("spi",
"SPI_DEV(%d) pins could not be initialized\n", bus);
return;
}
if (spi_init_cs(bus, spi_config[bus].cs) != SPI_OK) {
LOG_TAG_ERROR("spi",
"SPI_DEV(%d) CS signal could not be initialized\n",
bus);
return;
}
/* store the usage type in GPIO table */
gpio_set_pin_usage(spi_config[bus].sck, _SPI);
gpio_set_pin_usage(spi_config[bus].mosi, _SPI);
gpio_set_pin_usage(spi_config[bus].miso, _SPI);
#ifdef MCU_ESP32
/* connect SCK and MOSI pins to the output signal through the GPIO matrix */
GPIO.func_out_sel_cfg[spi_config[bus].sck].func_sel = _spi[bus].signal_sck;
GPIO.func_out_sel_cfg[spi_config[bus].mosi].func_sel = _spi[bus].signal_mosi;
/* connect MISO input signal to the MISO pin through the GPIO matrix */
GPIO.func_in_sel_cfg[_spi[bus].signal_miso].sig_in_sel = 1;
GPIO.func_in_sel_cfg[_spi[bus].signal_miso].sig_in_inv = 0;
GPIO.func_in_sel_cfg[_spi[bus].signal_miso].func_sel = spi_config[bus].miso;
#else /* MCU_ESP32 */
/*
* CS is handled as normal GPIO ouptut. Due to the small number of GPIOs
* CS is handled as normal GPIO output. Due to the small number of GPIOs
* we have, we do not initialize the default CS pin here. Either the app
* uses spi_init_cs to initialize the CS pin explicitly, or we initialize
* the default CS when spi_aquire is used first time.
*/
IOMUX.PIN[_gpio_to_iomux[SPI0_MISO_GPIO]] &= ~IOMUX_PIN_FUNC_MASK;
IOMUX.PIN[_gpio_to_iomux[SPI0_MOSI_GPIO]] &= ~IOMUX_PIN_FUNC_MASK;
IOMUX.PIN[_gpio_to_iomux[SPI0_SCK_GPIO]] &= ~IOMUX_PIN_FUNC_MASK;
uint32_t iomux_func = IOMUX_FUNC(2);
IOMUX.PIN[_gpio_to_iomux[SPI0_MISO_GPIO]] |= iomux_func;
IOMUX.PIN[_gpio_to_iomux[SPI0_MOSI_GPIO]] |= iomux_func;
IOMUX.PIN[_gpio_to_iomux[SPI0_SCK_GPIO]] |= iomux_func;
IOMUX.PIN[_gpio_to_iomux[spi_config[bus].miso]] &= ~IOMUX_PIN_FUNC_MASK;
IOMUX.PIN[_gpio_to_iomux[spi_config[bus].mosi]] &= ~IOMUX_PIN_FUNC_MASK;
IOMUX.PIN[_gpio_to_iomux[spi_config[bus].sck]] &= ~IOMUX_PIN_FUNC_MASK;
_gpio_pin_usage [SPI0_MISO_GPIO] = _SPI; /* pin cannot be used for anything else */
_gpio_pin_usage [SPI0_MOSI_GPIO] = _SPI; /* pin cannot be used for anything else */
_gpio_pin_usage [SPI0_SCK_GPIO] = _SPI; /* pin cannot be used for anything else */
IOMUX.PIN[_gpio_to_iomux[spi_config[bus].miso]] |= iomux_func;
IOMUX.PIN[_gpio_to_iomux[spi_config[bus].mosi]] |= iomux_func;
IOMUX.PIN[_gpio_to_iomux[spi_config[bus].sck]] |= iomux_func;
#endif /* MCU_ESP32 */
}
int spi_init_cs(spi_t bus, spi_cs_t cs)
{
DEBUG("%s bus=%u cs=%u\n", __func__, bus, cs);
/* see spi_init */
CHECK_PARAM_RET (bus == SPI_DEV(0), SPI_NODEV);
assert(bus < SPI_NUMOF);
/* call initialization of the SPI interface if it is not initialized yet */
if (!_spi_initialized[bus]) {
if (!_spi[bus].initialized) {
_spi_init_internal(bus);
}
/* return if pin is already initialized as SPI CS signal */
if (_gpio_pin_usage [cs] == _SPI) {
if (gpio_get_pin_usage(cs) == _SPI) {
return SPI_OK;
}
if (_gpio_pin_usage [cs] != _GPIO) {
/* check whether CS pin is used otherwise */
if (gpio_get_pin_usage(cs) != _GPIO) {
return SPI_NOCS;
}
/* initialize the pin */
gpio_init(cs, GPIO_OUT);
gpio_set (cs);
gpio_set(cs);
_gpio_pin_usage [cs] = _SPI; /* pin cannot be used for anything else */
/* pin cannot be used for anything else */
gpio_set_pin_usage(cs, _SPI);
return SPI_OK;
}
int spi_acquire(spi_t bus, spi_cs_t cs, spi_mode_t mode, spi_clk_t clk)
int IRAM_ATTR spi_acquire(spi_t bus, spi_cs_t cs, spi_mode_t mode, spi_clk_t clk)
{
DEBUG("%s bus=%u cs=%u mode=%u clk=%u\n", __func__, bus, cs, mode, clk);
/* see spi_init */
CHECK_PARAM_RET (bus == SPI_DEV(0), SPI_NODEV);
assert(bus < SPI_NUMOF);
/* call initialization of the SPI interface if it is not initialized yet */
if (!_spi_initialized[bus]) {
if (!_spi[bus].initialized) {
_spi_init_internal(bus);
}
/* if parameter cs is GPIO_UNDEF, the default CS pin is used */
cs = (cs == GPIO_UNDEF) ? SPI0_CS0_GPIO : cs;
cs = (cs == GPIO_UNDEF) ? spi_config[bus].cs : cs;
/* if the CS pin used is not yet initialized, we do it now */
if (_gpio_pin_usage[cs] != _SPI && spi_init_cs(bus, cs) != SPI_OK) {
LOG_ERROR("SPI_DEV(%d) CS signal could not be initialized\n", bus);
if (gpio_get_pin_usage(cs) != _SPI && spi_init_cs(bus, cs) != SPI_OK) {
LOG_TAG_ERROR("spi",
"SPI_DEV(%d) CS signal could not be initialized\n",
bus);
return SPI_NOCS;
}
/* lock the bus */
mutex_lock(&_spi_lock[bus]);
mutex_lock(&_spi[bus].lock);
/* set SPI mode */
bool cpha = (mode == SPI_MODE_1 || mode == SPI_MODE_3);
bool cpol = (mode == SPI_MODE_2 || mode == SPI_MODE_3);
if (cpol) {
cpha = !cpha; /* CPHA must be inverted when CPOL = 1 */
}
if (cpha) {
SPI(bus).USER0 |= SPI_USER0_CLOCK_OUT_EDGE;
}
else {
SPI(bus).USER0 &= ~SPI_USER0_CLOCK_OUT_EDGE;
}
if (cpol) {
SPI(bus).PIN |= SPI_PIN_IDLE_EDGE;
}
else {
SPI(bus).PIN &= ~SPI_PIN_IDLE_EDGE;
}
/*
* set SPI mode
* see ESP32 Technical Reference, Table 25 and Section 7.4.2
*/
_spi[bus].regs->pin.ck_idle_edge = (mode == SPI_MODE_2 || mode == SPI_MODE_3);
_spi[bus].regs->user.ck_out_edge = (mode == SPI_MODE_1 || mode == SPI_MODE_2);
_spi[bus].regs->ctrl2.miso_delay_mode = (mode == SPI_MODE_0 || mode == SPI_MODE_3) ? 2 : 1;
_spi[bus].regs->ctrl2.miso_delay_num = 0;
_spi[bus].regs->ctrl2.mosi_delay_mode = 0;
_spi[bus].regs->ctrl2.mosi_delay_num = 0;
/* set SPI clock
* see ESP8266 Technical Reference Appendix 2 - SPI registers
@ -248,31 +355,53 @@ int spi_acquire(spi_t bus, spi_cs_t cs, spi_mode_t mode, spi_clk_t clk)
spi_clkdiv_pre--;
spi_clkcnt_N--;
DEBUG("%s spi_clkdiv_prev=%u spi_clkcnt_N=%u\n", __func__, spi_clkdiv_pre, spi_clkcnt_N);
DEBUG("%s spi_clkdiv_prev=%u spi_clkcnt_N=%u\n",
__func__, spi_clkdiv_pre, spi_clkcnt_N);
/* SPI clock is derived from system bus frequency and should not be affected by */
/* CPU clock */
#ifdef MCU_ESP8266
IOMUX.CONF &= ~IOMUX_CONF_SPI1_CLOCK_EQU_SYS_CLOCK;
#endif
IOMUX.CONF &= ~(bus == 0 ? IOMUX_CONF_SPI0_CLOCK_EQU_SYS_CLOCK
: IOMUX_CONF_SPI1_CLOCK_EQU_SYS_CLOCK);
SPI(bus).CLOCK = VAL2FIELD_M (SPI_CLOCK_DIV_PRE, spi_clkdiv_pre) |
VAL2FIELD_M (SPI_CLOCK_COUNT_NUM, spi_clkcnt_N) |
VAL2FIELD_M (SPI_CLOCK_COUNT_HIGH, (spi_clkcnt_N+1)/2-1) |
VAL2FIELD_M (SPI_CLOCK_COUNT_LOW, spi_clkcnt_N);
/* SPI clock is derived from APB clock by dividers */
_spi[bus].regs->clock.clk_equ_sysclk = 0;
DEBUG("%s IOMUX.CONF=%08x SPI(bus).CLOCK=%08x\n",
__func__, IOMUX.CONF, SPI(bus).CLOCK);
/* set SPI clock dividers */
_spi[bus].regs->clock.clkdiv_pre = spi_clkdiv_pre;
_spi[bus].regs->clock.clkcnt_n = spi_clkcnt_N;
_spi[bus].regs->clock.clkcnt_h = (spi_clkcnt_N+1)/2-1;
_spi[bus].regs->clock.clkcnt_l = spi_clkcnt_N;
DEBUG("%s bus %d: SPI_CLOCK_REG=%08x\n",
__func__, bus, _spi[bus].regs->clock.val);
return SPI_OK;
}
void spi_release(spi_t bus)
void IRAM_ATTR spi_release(spi_t bus)
{
/* see spi_init */
CHECK_PARAM (bus == SPI_DEV(0));
DEBUG("%s bus=%u\n", __func__, bus);
assert(bus < SPI_NUMOF);
/* release the bus */
mutex_unlock(&_spi_lock[bus]);
mutex_unlock(&_spi[bus].lock);
}
#ifdef MCU_ESP32
static const char* _spi_names[] = { "CSPI", "FSPI", "HSPI", "VSPI" };
#else /* MCU_ESP32 */
static const char* _spi_names[] = { "FSPI", "HSPI" };
#endif /* MCU_ESP32 */
void spi_print_config(void)
{
for (unsigned bus = 0; bus < SPI_NUMOF; bus++) {
printf("\tSPI_DEV(%u)\t%s ", bus, _spi_names[spi_config[bus].ctrl]);
printf("sck=%d " , spi_config[bus].sck);
printf("miso=%d ", spi_config[bus].miso);
printf("mosi=%d ", spi_config[bus].mosi);
printf("cs=%d\n" , spi_config[bus].cs);
}
}
/*
@ -284,29 +413,37 @@ void spi_release(spi_t bus)
* https://github.com/SuperHouse/esp-open-rtos/blob/master/LICENSE
*/
inline static void _set_size(uint8_t bus, uint8_t bytes)
inline static void IRAM_ATTR _set_size(uint8_t bus, uint8_t bytes)
{
uint32_t bits = ((uint32_t)bytes << 3) - 1;
SPI(bus).USER1 = SET_FIELD(SPI(bus).USER1, SPI_USER1_MISO_BITLEN, bits);
SPI(bus).USER1 = SET_FIELD(SPI(bus).USER1, SPI_USER1_MOSI_BITLEN, bits);
#ifdef MCU_ESP32
_spi[bus].regs->mosi_dlen.val = bits;
_spi[bus].regs->miso_dlen.val = bits;
#else /* MCU_ESP32 */
_spi[bus].regs->user1.usr_mosi_bitlen = bits;
_spi[bus].regs->user1.usr_miso_bitlen = bits;
#endif /* MCU_ESP32 */
}
inline static void _wait(uint8_t bus)
inline static void IRAM_ATTR _wait(uint8_t bus)
{
while (SPI(bus).CMD & SPI_CMD_USR) {}
/* SPI_CMD_REG.SPI_USR is cleared when operation has been finished */
while (_spi[bus].regs->cmd.usr) {}
}
inline static void _start(uint8_t bus)
inline static void IRAM_ATTR _start(uint8_t bus)
{
SPI(bus).CMD |= SPI_CMD_USR;
/* set SPI_CMD_REG.SPI_USR to start an operation */
_spi[bus].regs->cmd.usr = 1;
}
inline static void _store_data(uint8_t bus, const void *data, size_t len)
inline static void IRAM_ATTR _store_data(uint8_t bus, const void *data, size_t len)
{
uint8_t words = len / 4;
uint8_t tail = len % 4;
memcpy((void *)SPI(bus).W, data, len - tail);
memcpy((void *)_spi[bus].regs->data_buf, data, len - tail);
if (!tail) {
return;
@ -317,12 +454,12 @@ inline static void _store_data(uint8_t bus, const void *data, size_t len)
for (uint8_t i = 0; i < tail; i++) {
last = last | (offs[i] << (i * 8));
}
SPI(bus).W[words] = last;
_spi[bus].regs->data_buf[words] = last;
}
static const uint8_t spi_empty_out[SPI_BLOCK_SIZE] = { 0 };
static void _spi_buf_transfer(uint8_t bus, const void *out, void *in, size_t len)
static void IRAM_ATTR _spi_buf_transfer(uint8_t bus, const void *out, void *in, size_t len)
{
DEBUG("%s bus=%u out=%p in=%p len=%u\n", __func__, bus, out, in, len);
@ -333,15 +470,14 @@ static void _spi_buf_transfer(uint8_t bus, const void *out, void *in, size_t len
_start(bus);
_wait(bus);
if (in) {
memcpy(in, (void *)SPI(bus).W, len);
memcpy(in, (void *)_spi[bus].regs->data_buf, len);
}
}
void spi_transfer_bytes(spi_t bus, spi_cs_t cs, bool cont,
const void *out, void *in, size_t len)
void IRAM_ATTR spi_transfer_bytes(spi_t bus, spi_cs_t cs, bool cont,
const void *out, void *in, size_t len)
{
/* see spi_init */
CHECK_PARAM (bus == SPI_DEV(0));
assert(bus < SPI_NUMOF);
DEBUG("%s bus=%u cs=%u cont=%d out=%p in=%p len=%u\n",
__func__, bus, cs, cont, out, in, len);
@ -360,9 +496,7 @@ void spi_transfer_bytes(spi_t bus, spi_cs_t cs, bool cont,
}
#endif
if (cs != SPI_CS_UNDEF) {
gpio_clear (cs);
}
gpio_clear(cs != SPI_CS_UNDEF ? cs : spi_config[bus].cs);
size_t blocks = len / SPI_BLOCK_SIZE;
uint8_t tail = len % SPI_BLOCK_SIZE;
@ -382,8 +516,8 @@ void spi_transfer_bytes(spi_t bus, spi_cs_t cs, bool cont,
in ? (uint8_t *)in + blocks * SPI_BLOCK_SIZE : NULL, tail);
}
if (!cont && (cs != SPI_CS_UNDEF)) {
gpio_set (cs);
if (!cont) {
gpio_set(cs != SPI_CS_UNDEF ? cs : spi_config[bus].cs);
}
#if ENABLE_DEBUG
@ -396,21 +530,3 @@ void spi_transfer_bytes(spi_t bus, spi_cs_t cs, bool cont,
}
#endif
}
void spi_print_config(void)
{
LOG_INFO("\tSPI_DEV(0): ");
LOG_INFO("sck=%d " , SPI0_SCK_GPIO);
LOG_INFO("miso=%d ", SPI0_MISO_GPIO);
LOG_INFO("mosi=%d ", SPI0_MOSI_GPIO);
LOG_INFO("cs=%d\n" , SPI0_CS0_GPIO);
}
#else /* MODULE_PERIPH_SPI */
void spi_print_config(void)
{
LOG_INFO("\tSPI: no devices\n");
}
#endif /* MODULE_PERIPH_SPI */

View File

@ -1,5 +1,5 @@
/*
* Copyright (C) 2018 Gunar Schorcht
* Copyright (C) 2019 Gunar Schorcht
*
* This file is subject to the terms and conditions of the GNU Lesser
* General Public License v2.1. See the file LICENSE in the top level
@ -27,9 +27,10 @@
#include "xtimer.h"
#include "periph/timer.h"
#include "common.h"
#include "irq_arch.h"
#include "esp/common_macros.h"
#include "esp_common.h"
#include "irq_arch.h"
#include "rom/ets_sys.h"
#include "sdk/sdk.h"
#include "xtensa/hal.h"
@ -295,18 +296,14 @@ static void IRAM __timer_channel_stop (struct hw_timer_t* timer, struct hw_chann
void timer_print_config(void)
{
for (int i = 0; i < HW_TIMER_NUMOF; i++) {
LOG_INFO("\tTIMER_DEV(%d): %d channel(s)\n", i,
ARRAY_SIZE(timers[i].channels));
for (unsigned i = 0; i < HW_TIMER_NUMOF; i++) {
printf("\tTIMER_DEV(%u)\t%d channel(s)\n", i,
ARRAY_SIZE(timers[i].channels));
}
}
#else /* MODULE_ESP_SW_TIMER */
#ifndef MODULE_ESP_SDK
#error Software timers are not available in Non-SDK version, use USE_SDK=1 to enable SDK-version.
#else
/* software timer based on os_timer_arm functions */
#define OS_TIMER_NUMOF 1
@ -319,6 +316,8 @@ void timer_print_config(void)
#define OS_TIMER_DELTA_RSHIFT 16
#define OS_TIMER_CORRECTION 4
extern void os_timer_arm_us(os_timer_t *ptimer, uint32_t time, bool repeat_flag);
/* Since hardware timer FRC1 is needed to implement PWM, we have to map our */
/* timer using the exsting ETS timer with 1 us clock rate */
@ -560,12 +559,10 @@ static void IRAM __timer_channel_stop (struct phy_timer_t* timer, struct phy_cha
void timer_print_config(void)
{
for (int i = 0; i < OS_TIMER_NUMOF; i++) {
LOG_INFO("\tTIMER_DEV(%d): %d channel(s)\n", i,
ARRAY_SIZE(timers[i].channels));
for (unsigned i = 0; i < OS_TIMER_NUMOF; i++) {
printf("\tTIMER_DEV(%u)\t%d channel(s)\n", i,
ARRAY_SIZE(timers[i].channels));
}
}
#endif /* NON_SDK */
#endif /* MODULE_ESP_SW_TIMER */

View File

@ -1,5 +1,5 @@
/*
* Copyright (C) 2018 Gunar Schorcht
* Copyright (C) 2019 Gunar Schorcht
*
* This file is subject to the terms and conditions of the GNU Lesser
* General Public License v2.1. See the file LICENSE in the top level
@ -19,147 +19,461 @@
* @}
*/
#define ENABLE_DEBUG 0
#define ENABLE_DEBUG (0)
#include "debug.h"
#include "common.h"
#include "esp_common.h"
#include "cpu.h"
#include "irq_arch.h"
#include "log.h"
#include "sched.h"
#include "thread.h"
#include "periph/gpio.h"
#include "periph/uart.h"
#include "eagle_soc.h"
#include "stdio_uart.h"
#include "esp/common_macros.h"
#include "rom/ets_sys.h"
#include "xtensa/xtensa_api.h"
#ifdef MCU_ESP32
#include "gpio_arch.h"
#include "driver/periph_ctrl.h"
#include "soc/gpio_reg.h"
#include "soc/gpio_sig_map.h"
#include "soc/gpio_struct.h"
#include "soc/rtc.h"
#include "soc/uart_reg.h"
#include "soc/uart_struct.h"
#undef UART_CLK_FREQ
#define UART_CLK_FREQ rtc_clk_apb_freq_get() /* APB_CLK is used */
#else /* MCU_ESP32 */
#include "esp8266/uart_struct.h"
#ifdef MODULE_ESP_QEMU
#include "esp/uart_regs.h"
#include "sdk/sdk.h"
#endif /* MODULE_ESP_QEMU */
/**
* @brief Allocate memory to store the callback functions.
*/
static uart_isr_ctx_t isr_ctx[UART_NUMOF];
#define UART0 uart0
#define UART1 uart1
#define CPU_INUM_UART ETS_UART_INUM
static uint8_t IRAM __uart_rx_one_char (uart_t uart);
static void __uart_tx_one_char(uart_t uart, uint8_t data);
static void __uart_intr_enable (uart_t uart);
static void IRAM __uart_intr_handler (void *para);
#endif /* MCU_ESP32 */
struct uart_hw_t {
uart_dev_t* regs; /* pointer to register data struct of the UART device */
uint8_t pin_txd; /* TxD pin used */
uint8_t pin_rxd; /* RxD pin used */
bool used; /* indicates whether UART is used */
uint32_t baudrate; /* used baudrate */
uart_data_bits_t data; /* used data bits */
uart_stop_bits_t stop; /* used stop bits */
uart_parity_t parity; /* used parity bits */
uart_isr_ctx_t isr_ctx; /* callback functions */
#ifdef MCU_ESP32
uint8_t mod; /* peripheral hardware module of the UART interface */
uint8_t signal_txd; /* TxD signal from the controller */
uint8_t signal_rxd; /* RxD signal to the controller */
uint8_t int_src; /* peripheral interrupt source used by the UART device */
#endif
};
/* hardware resources */
static struct uart_hw_t _uarts[] = {
{
.regs = &UART0,
.used = false,
.baudrate = STDIO_UART_BAUDRATE,
.data = UART_DATA_BITS_8,
.stop = UART_STOP_BITS_1,
.parity = UART_PARITY_NONE,
#ifdef MCU_ESP32
.mod = PERIPH_UART0_MODULE,
.signal_txd = U0TXD_OUT_IDX,
.signal_rxd = U0RXD_IN_IDX,
.int_src = ETS_UART0_INTR_SOURCE
},
{
.regs = &UART1,
.used = false,
.baudrate = STDIO_UART_BAUDRATE,
.data = UART_DATA_BITS_8,
.stop = UART_STOP_BITS_1,
.parity = UART_PARITY_NONE,
.mod = PERIPH_UART1_MODULE,
.signal_txd = U1TXD_OUT_IDX,
.signal_rxd = U1RXD_IN_IDX,
.int_src = ETS_UART1_INTR_SOURCE
},
{
.regs = &UART2,
.used = false,
.baudrate = STDIO_UART_BAUDRATE,
.data = UART_DATA_BITS_8,
.stop = UART_STOP_BITS_1,
.parity = UART_PARITY_NONE,
.mod = PERIPH_UART2_MODULE,
.signal_txd = U2TXD_OUT_IDX,
.signal_rxd = U2RXD_IN_IDX,
.int_src = ETS_UART2_INTR_SOURCE
#endif /* MCU_ESP32 */
},
};
/* declaration of external functions */
extern void uart_div_modify(uint8_t uart_no, uint32_t div);
/* forward declaration of internal functions */
static int _uart_set_baudrate(uart_t uart, uint32_t baudrate);
static int _uart_set_mode(uart_t uart, uart_data_bits_t data_bits,
uart_parity_t parity, uart_stop_bits_t stop_bits);
static uint8_t IRAM _uart_rx_one_char(uart_t uart);
static void _uart_tx_one_char(uart_t uart, uint8_t data);
static void _uart_intr_enable(uart_t uart);
static void _uart_config (uart_t uart);
static void IRAM _uart_intr_handler(void *para);
int uart_init(uart_t uart, uint32_t baudrate, uart_rx_cb_t rx_cb, void *arg)
{
CHECK_PARAM_RET (uart < UART_NUMOF, -1);
DEBUG("%s uart=%d, rate=%d, rx_cb=%p, arg=%p\n", __func__, uart, baudrate, rx_cb, arg);
/* setup the baudrate */
uart_div_modify(uart, UART_CLK_FREQ / baudrate);
assert(uart < UART_NUMOF_MAX);
assert(uart < UART_NUMOF);
_uarts[uart].pin_txd = uart_config[uart].txd;
_uarts[uart].pin_rxd = uart_config[uart].rxd;
#ifdef MCU_ESP32
/* UART1 and UART2 have configurable pins */
if ((uart == UART_DEV(1) || uart == UART_DEV(2))) {
/* reset the pins when they were already used as UART pins */
if (gpio_get_pin_usage(_uarts[uart].pin_txd) == _UART) {
gpio_set_pin_usage(_uarts[uart].pin_txd, _GPIO);
}
if (gpio_get_pin_usage(_uarts[uart].pin_rxd) == _UART) {
gpio_set_pin_usage(_uarts[uart].pin_rxd, _GPIO);
}
/* try to initialize the pins as GPIOs first */
if (gpio_init(_uarts[uart].pin_txd, GPIO_OUT) ||
gpio_init(_uarts[uart].pin_rxd, GPIO_IN)) {
return -1;
}
/* store the usage type in GPIO table */
gpio_set_pin_usage(_uarts[uart].pin_txd, _UART);
gpio_set_pin_usage(_uarts[uart].pin_rxd, _UART);
/* connect TxD pin to the TxD output signal through the GPIO matrix */
GPIO.func_out_sel_cfg[_uarts[uart].pin_txd].func_sel = _uarts[uart].signal_txd;
/* connect RxD input signal to the RxD pin through the GPIO matrix */
GPIO.func_in_sel_cfg[_uarts[uart].signal_rxd].sig_in_sel = 1;
GPIO.func_in_sel_cfg[_uarts[uart].signal_rxd].sig_in_inv = 0;
GPIO.func_in_sel_cfg[_uarts[uart].signal_rxd].func_sel = _uarts[uart].pin_rxd;
}
#endif
_uarts[uart].baudrate = baudrate;
/* register interrupt context */
isr_ctx[uart].rx_cb = rx_cb;
isr_ctx[uart].arg = arg;
_uarts[uart].isr_ctx.rx_cb = rx_cb;
_uarts[uart].isr_ctx.arg = arg;
if (rx_cb) {
ets_isr_attach (ETS_UART_INUM, __uart_intr_handler, 0);
/* since reading is done byte for byte we set the RX FIFO FULL */
/* interrupt level to 1 byte */
UART(uart).CONF1 = SET_FIELD(UART(uart).CONF1, UART_CONF1_RXFIFO_FULL_THRESHOLD, 1);
/* enable the RX FIFO FULL interrupt */
__uart_intr_enable (uart);
}
/* enable and configure the according UART module */
uart_poweron(uart);
return UART_OK;
}
#if MODULE_PERIPH_UART_MODECFG
int uart_mode(uart_t uart, uart_data_bits_t data_bits, uart_parity_t parity,
uart_stop_bits_t stop_bits)
{
return _uart_set_mode(uart, data_bits, parity, stop_bits);
}
#endif
void uart_write(uart_t uart, const uint8_t *data, size_t len)
{
CHECK_PARAM (uart < UART_NUMOF);
CHECK_PARAM(uart < UART_NUMOF);
for (size_t i = 0; i < len; i++) {
__uart_tx_one_char(uart, data[i]);
_uart_tx_one_char(uart, data[i]);
}
}
void uart_poweron (uart_t uart)
{
/* UART can't be powered on/off, just return */
CHECK_PARAM(uart < UART_NUMOF);
#ifdef MCU_ESP32
periph_module_enable(_uarts[uart].mod);
#endif
_uart_config(uart);
}
void uart_poweroff (uart_t uart)
{
/* UART can't be powered on/off, just return */
CHECK_PARAM(uart < UART_NUMOF);
#ifdef MCU_ESP32
periph_module_disable(_uarts[uart].mod);
#endif
}
void IRAM __uart_intr_handler (void *arg)
/* systemwide UART initializations */
void uart_system_init (void)
{
for (unsigned uart = 0; uart < UART_NUMOF; uart++) {
/* reset all UART interrupt status registers */
_uarts[uart].regs->int_clr.val = ~0;
}
}
void uart_print_config(void)
{
for (unsigned uart = 0; uart < UART_NUMOF; uart++) {
printf("\tUART_DEV(%u)\ttxd=%d rxd=%d\n", uart,
uart_config[uart].txd, uart_config[uart].rxd);
}
}
static void IRAM _uart_intr_handler(void *arg)
{
/* to satisfy the compiler */
(void)arg;
irq_isr_enter ();
irq_isr_enter();
DEBUG("%s \n", __func__);
/* UART0, UART1, UART2 peripheral interrupt sources are routed to the same
interrupt, so we have to use the status to distinguish interruptees */
for (unsigned uart = 0; uart < UART_NUMOF; uart++) {
if (_uarts[uart].used) {
DEBUG("%s uart=%d int_st=%08x\n", __func__,
uart, _uarts[uart].regs->int_st.val);
/*
* UART0 and UART1 interrupts are combined togther. So we have to
* iterate over all UART devices and test the INT_STATUS register for
* interrupts
*/
for (int i = 0; i < UART_NUMOF; i++) {
uart_t uart = UART_DEV(0); /* UartDev.buff_uart_no; */
if (UART(uart).INT_STATUS & UART_INT_STATUS_RXFIFO_FULL) {
/* clear interrupt flag */
uint8_t data = __uart_rx_one_char (uart);
if (_uarts[uart].used && _uarts[uart].regs->int_st.rxfifo_full) {
/* read one byte of data */
uint8_t data = _uart_rx_one_char (uart);
/* if registered, call the RX callback function */
if (_uarts[uart].isr_ctx.rx_cb) {
_uarts[uart].isr_ctx.rx_cb(_uarts[uart].isr_ctx.arg, data);
}
/* clear interrupt flag */
_uarts[uart].regs->int_clr.rxfifo_full = 1;
}
/* call registered RX callback function */
isr_ctx[uart].rx_cb(isr_ctx[uart].arg, data);
/* clear interrupt flag */
UART(uart).INT_CLEAR |= UART_INT_CLEAR_RXFIFO_FULL;
}
else {
/* TODO handle other type of interrupts, for the moment just clear them */
UART(uart).INT_CLEAR = 0x1f;
/* TODO handle other types of interrupts, for the moment just clear them */
_uarts[uart].regs->int_clr.val = ~0x0;
}
}
irq_isr_exit ();
irq_isr_exit();
}
/* RX/TX FIFO capacity is 128 byte */
#define UART_FIFO_MAX 1
#define UART_FIFO_MAX 128
/* receive one data byte with wait */
static uint8_t IRAM __uart_rx_one_char (uart_t uart)
static uint8_t IRAM _uart_rx_one_char (uart_t uart)
{
/* uint8_t fifo_len = FIELD2VAL(UART_STATUS_RXFIFO_COUNT, UART(uart).STATUS); */
#if defined(MODULE_ESP_QEMU) && defined(MCU_ESP8266)
/* wait until at least von byte is in RX FIFO */
while (!FIELD2VAL(UART_STATUS_RXFIFO_COUNT, UART(uart).STATUS)) {}
/* read the lowest byte from RX FIFO register */
return UART(uart).FIFO & 0xff; /* only bit 0 ... 7 */
#else
/* wait until at least von byte is in RX FIFO */
while (!_uarts[uart].regs->status.rxfifo_cnt) {}
/* read the lowest byte from RX FIFO register */
return _uarts[uart].regs->fifo.rw_byte;
#endif
}
/* send one data byte with wait */
static void __uart_tx_one_char(uart_t uart, uint8_t data)
static void _uart_tx_one_char(uart_t uart, uint8_t data)
{
/* wait until at least one byte is avaiable in the TX FIFO */
while (FIELD2VAL(UART_STATUS_TXFIFO_COUNT, UART(uart).STATUS) >= UART_FIFO_MAX) {}
/* wait until at least one byte is available in the TX FIFO */
while (_uarts[uart].regs->status.txfifo_cnt >= UART_FIFO_MAX) {}
/* send the byte by placing it in the TX FIFO */
/* send the byte by placing it in the TX FIFO using MPU */
#ifdef MCU_ESP32
WRITE_PERI_REG(UART_FIFO_AHB_REG(uart), data);
#else /* MCU_ESP32 */
#ifdef MODULE_ESP_QEMU
UART(uart).FIFO = data;
#else /* MODULE_ESP_QEMU */
_uarts[uart].regs->fifo.rw_byte = data;
#endif /* MODULE_ESP_QEMU */
#endif /* MCU_ESP32 */
}
static void __uart_intr_enable(uart_t uart)
static void _uart_intr_enable(uart_t uart)
{
UART(uart).INT_ENABLE |= UART_INT_ENABLE_RXFIFO_FULL;
ETS_INTR_ENABLE(ETS_UART_INUM);
_uarts[uart].regs->int_ena.rxfifo_full = 1;
_uarts[uart].regs->int_clr.rxfifo_full = 1;
_uarts[uart].used = true;
DEBUG("%s %08x\n", __func__, UART(uart).INT_ENABLE);
DEBUG("%s %08x\n", __func__, _uarts[uart].regs->int_ena.val);
}
void uart_print_config(void)
static void _uart_config(uart_t uart)
{
LOG_INFO("\tUART_DEV(0): txd=%d rxd=%d\n", UART0_TXD, UART0_RXD);
assert(uart < UART_NUMOF);
while (_uarts[uart].regs->status.txfifo_cnt != 0) { }
#if 0
/* setup the baudrate */
if (uart == UART_DEV(0) || uart == UART_DEV(1)) {
/* for UART0 and UART1, we can us the ROM function */
uart_div_modify(uart, (UART_CLK_FREQ << 4) / _uarts[uart].baudrate);
}
else
#endif
if (_uart_set_baudrate(uart, _uarts[uart].baudrate) != UART_OK) {
return;
}
/* set number of data bits, stop bits and parity mode */
if (_uart_set_mode(uart, _uarts[uart].data, _uarts[uart].stop,
_uarts[uart].parity) != UART_OK) {
return;
}
/* reset the FIFOs */
_uarts[uart].regs->conf0.rxfifo_rst = 1;
_uarts[uart].regs->conf0.rxfifo_rst = 0;
_uarts[uart].regs->conf0.txfifo_rst = 1;
_uarts[uart].regs->conf0.txfifo_rst = 0;
if (_uarts[uart].isr_ctx.rx_cb) {
/* since reading can only be done byte by byte, we set
UART_RXFIFO_FULL_THRHD interrupt level to 1 byte */
_uarts[uart].regs->conf1.rxfifo_full_thrhd = 1;
/* enable the RX FIFO FULL interrupt */
_uart_intr_enable(uart);
#ifdef MCU_ESP32
/* route all UART interrupt sources to same the CPU interrupt */
intr_matrix_set(PRO_CPU_NUM, _uarts[uart].int_src, CPU_INUM_UART);
#endif /* MCU_ESP32 */
/* we have to enable therefore the CPU interrupt here */
xt_set_interrupt_handler(CPU_INUM_UART, _uart_intr_handler, NULL);
xt_ints_on(BIT(CPU_INUM_UART));
}
}
static int _uart_set_baudrate(uart_t uart, uint32_t baudrate)
{
DEBUG("%s uart=%d, rate=%d\n", __func__, uart, baudrate);
CHECK_PARAM_RET (uart < UART_NUMOF, -1);
/* wait until TX FIFO is empty */
while (_uarts[uart].regs->status.txfifo_cnt != 0) { }
critical_enter();
_uarts[uart].baudrate = baudrate;
#ifdef MCU_ESP32
/* use APB_CLK */
_uarts[uart].regs->conf0.tick_ref_always_on = 1;
/* compute and set the integral and the decimal part */
uint32_t clk_div = (UART_CLK_FREQ << 4) / _uarts[uart].baudrate;
_uarts[uart].regs->clk_div.div_int = clk_div >> 4;
_uarts[uart].regs->clk_div.div_frag = clk_div & 0xf;
#else
/* compute and set clock divider */
uint32_t clk_div = UART_CLK_FREQ / _uarts[uart].baudrate;
_uarts[uart].regs->clk_div.val = clk_div & 0xFFFFF;
#endif
critical_exit();
return UART_OK;
}
static int _uart_set_mode(uart_t uart, uart_data_bits_t data_bits,
uart_parity_t parity, uart_stop_bits_t stop_bits)
{
DEBUG("%s uart=%d, data_bits=%d parity=%d stop_bits=%d\n", __func__,
uart, data_bits, parity, stop_bits);
CHECK_PARAM_RET (uart < UART_NUMOF, UART_NODEV);
critical_enter();
/* set number of data bits */
switch (data_bits) {
case UART_DATA_BITS_5: _uarts[uart].regs->conf0.bit_num = 0; break;
case UART_DATA_BITS_6: _uarts[uart].regs->conf0.bit_num = 1; break;
case UART_DATA_BITS_7: _uarts[uart].regs->conf0.bit_num = 2; break;
case UART_DATA_BITS_8: _uarts[uart].regs->conf0.bit_num = 3; break;
default: LOG_TAG_ERROR("uart", "invalid number of data bits\n");
critical_exit();
return UART_NOMODE;
}
/* store changed number of data bits in configuration */
_uarts[uart].data = data_bits;
/* set number of stop bits */
#ifdef MCU_ESP32
/* workaround for hardware bug when stop bits are set to 2-bit mode. */
switch (stop_bits) {
case UART_STOP_BITS_1: _uarts[uart].regs->conf0.stop_bit_num = 1;
_uarts[uart].regs->rs485_conf.dl1_en = 0;
break;
case UART_STOP_BITS_2: _uarts[uart].regs->conf0.stop_bit_num = 1;
_uarts[uart].regs->rs485_conf.dl1_en = 1;
break;
default: LOG_TAG_ERROR("uart", "invalid number of stop bits\n");
critical_exit();
return UART_NOMODE;
}
#else
switch (stop_bits) {
case UART_STOP_BITS_1: _uarts[uart].regs->conf0.stop_bit_num = 1; break;
case UART_STOP_BITS_2: _uarts[uart].regs->conf0.stop_bit_num = 3; break;
default: LOG_TAG_ERROR("uart", "invalid number of stop bits\n");
critical_exit();
return UART_NOMODE;
}
#endif
/* store changed number of stop bits in configuration */
_uarts[uart].stop = stop_bits;
/* set parity mode */
switch (parity) {
case UART_PARITY_NONE: _uarts[uart].regs->conf0.parity_en = 0;
break;
case UART_PARITY_EVEN: _uarts[uart].regs->conf0.parity = 0;
_uarts[uart].regs->conf0.parity_en = 1;
break;
case UART_PARITY_ODD: _uarts[uart].regs->conf0.parity = 1;
_uarts[uart].regs->conf0.parity_en = 1;
break;
default: LOG_TAG_ERROR("uart", "invalid or unsupported parity mode\n");
critical_exit();
return UART_NOMODE;
}
/* store changed parity in configuration */
_uarts[uart].parity = parity;
critical_exit();
return UART_OK;
}

View File

@ -1,3 +1,3 @@
MODULE=sdk
MODULE=esp_sdk
include $(RIOTBASE)/Makefile.base

View File

@ -1,5 +1,5 @@
/*
* Copyright (C) 2018 Gunar Schorcht
* Copyright (C) 2019 Gunar Schorcht
*
* This file is subject to the terms and conditions of the GNU Lesser
* General Public License v2.1. See the file LICENSE in the top level
@ -16,8 +16,35 @@
* @author Gunar Schorcht <gunar@schorcht.net>
* @}
*/
#ifndef MODULE_ESP_SDK
#include "sdk/ets.h"
#include <string.h>
#endif /* MODULE_ESP_SDK */
#include "eagle_soc.h"
#include "sdk/sdk.h"
uint8_t ets_get_cpu_frequency(void)
{
return system_get_cpu_freq();
}
void *ets_memcpy(void *dst, const void *src, size_t size)
{
return memcpy(dst, src, size);
}
void ets_wdt_disable(void)
{
SET_PERI_REG_BITS(EDGE_INT_ENABLE_REG, BIT0, 0, BIT0);
SET_PERI_REG_BITS(PERIPHS_WDT_BASEADDR + WDT_CTL_ADDRESS, WDT_CTL_EN_MASK, 0, WDT_CTL_EN_LSB);
}
void ets_wdt_enable (void)
{
SET_PERI_REG_BITS(EDGE_INT_ENABLE_REG, BIT0, 1, BIT0);
SET_PERI_REG_BITS(PERIPHS_WDT_BASEADDR + WDT_CTL_ADDRESS, WDT_CTL_EN_MASK, 1, WDT_CTL_EN_LSB);
}
void ets_install_putc1(void (*p)(char c))
{
os_install_putc1(p);
}

View File

@ -1,5 +1,5 @@
/*
* Copyright (C) 2018 Gunar Schorcht
* Copyright (C) 2019 Gunar Schorcht
*
* This file is subject to the terms and conditions of the GNU Lesser
* General Public License v2.1. See the file LICENSE in the top level
@ -21,27 +21,25 @@
#ifndef DOXYGEN
#include <stdint.h>
#include <stdarg.h>
#include <stddef.h>
#include <stdint.h>
#include "c_types.h"
#include "ets_sys.h"
#include "rom/ets_sys.h"
#ifdef __cplusplus
extern "C" {
#endif
/* interrupts that are not defined in espressif/ets_sys.h */
/* interrupts that are not defined in rom/ets_sys.h */
#define ETS_WDEV_INUM 0 /* WDEV process FIQ interrupt */
#define ETS_RTC_INUM 3 /* RTC interrupt */
#define ETS_CCOM_INUM 6 /* CCOMPARE0 match interrupt */
#define ETS_SOFT_INUM 7 /* software interrupt */
#define ETS_WDT_INUM 8 /* SDK watchdog timer */
#define ETS_FRC2_INUM 10 /* SDK FRC2 timer interrupt */
/*
* The following functions are mappings or dummies for source code
* compatibility of SDK and NON-SDK version
* compatibility of NONOS-SDK and RTOS-SDK version
*/
#include "xtensa/xtensa_api.h"
@ -50,30 +48,20 @@ extern "C" {
#define ets_isr_unmask(x) xt_ints_on(x)
#define ets_isr_attach(i,f,a) xt_set_interrupt_handler(i,f,a)
#define ETS_INTR_ENABLE(inum) ets_isr_unmask((1<<inum))
#define ETS_INTR_DISABLE(inum) ets_isr_mask((1<<inum))
#define _xtos_set_exception_handler(n,f) xt_set_exception_handler(n,f)
#ifndef MODULE_ESP_SDK
extern void ets_delay_us(uint16_t us);
extern void ets_timer_arm_new(ETSTimer *ptimer, uint32_t ms_us, int repeat_flag, int is_ms);
extern void ets_timer_disarm(ETSTimer *ptimer);
extern void ets_timer_setfn(ETSTimer *ptimer, ETSTimerFunc *pfunction, void *arg);
#endif
extern void ets_timer_arm(ETSTimer *ptimer, uint32_t ms, bool repeat_flag);
extern void ets_timer_handler_isr(void);
extern void ets_install_uart_printf(void);
extern void ets_install_putc1(void (*p)(char c));
extern int ets_uart_printf(const char *format, ...);
extern int ets_putc(int);
extern int ets_printf(const char * format, ...);
extern int ets_vprintf(void *function, const char *format, va_list arg);
extern uint8_t ets_get_cpu_frequency(void);
extern void ets_update_cpu_frequency(uint8_t);
extern void ets_update_cpu_frequency(uint8_t);
extern void *ets_memcpy(void *to, const void *from, size_t size);
extern int ets_vprintf(const char *fmt, va_list ap);
extern int ets_printf(const char *fmt, ...);
extern int ets_putc(int c);
extern void ets_install_putc1(void (*p)(char c));
extern void *ets_memcpy(void *dst, const void *src, size_t size);
extern void ets_wdt_disable(void);
extern void ets_wdt_enable (void);

View File

@ -1,5 +1,5 @@
/*
* Copyright (C) 2018 Gunar Schorcht
* Copyright (C) 2019 Gunar Schorcht
*
* This file is subject to the terms and conditions of the GNU Lesser
* General Public License v2.1. See the file LICENSE in the top level
@ -25,29 +25,10 @@
#include <stdint.h>
#include <stdarg.h>
#include "c_types.h"
#ifdef __cplusplus
extern "C" {
#endif
#ifndef MODULE_ESP_SDK
/*
* The following functions are mappings or dummies for source code
* compatibility of SDK and NON-SDK version
*/
#include "esp/dport_regs.h"
extern void phy_afterwake_set_rfoption(int op);
extern int phy_check_data_table(void * gdctbl, int x, int flg);
extern int register_chipv6_phy(uint8_t * esp_init_data);
extern void sleep_reset_analog_rtcreg_8266(void);
extern uint32_t test_tout(bool);
extern void write_data_to_rtc(uint8_t *);
#endif /* MODULE_ESP_SDK */
extern uint32_t phy_get_mactime(void);
#ifdef __cplusplus

View File

@ -1,5 +1,5 @@
/*
* Copyright (C) 2018 Gunar Schorcht
* Copyright (C) 2019 Gunar Schorcht
*
* This file is subject to the terms and conditions of the GNU Lesser
* General Public License v2.1. See the file LICENSE in the top level
@ -20,25 +20,16 @@
#ifndef SDK_H
#define SDK_H
#include "c_types.h"
#include "ets_sys.h"
#include <stdint.h>
#include "sdk/ets.h"
#include "sdk/main.h"
#include "sdk/phy.h"
#include "sdk/pp.h"
#include "sdk/rom.h"
#include "sdk/user.h"
#include "sdk/system.h"
#ifdef __cplusplus
extern "C" {
#endif
#ifdef MODULE_ESP_SDK
#include "espressif/osapi.h"
#include "espressif/user_interface.h"
#endif /* MODULE_ESP_SDK */
#ifdef __cplusplus
}
#endif

56
cpu/esp8266/sdk/system.c Normal file
View File

@ -0,0 +1,56 @@
/*
* Copyright (C) 2019 Gunar Schorcht
*
* This file is subject to the terms and conditions of the GNU Lesser
* General Public License v2.1. See the file LICENSE in the top level
* directory for more details.
*/
/**
* @ingroup cpu_esp8266_sdk
* @{
*
* @file
* @brief ESP8266 user defined SDK functions
*
* @author Gunar Schorcht <gunar@schorcht.net>
* @}
*/
#include "sdk/sdk.h"
#include "esp/dport_regs.h"
#include "esp_sleep.h"
#include "esp_system.h"
uint32_t system_get_chip_id(void)
{
/* Chip ID as determined by NONOS SDK */
return (((DPORT.OTP_MAC1 << 8) & 0xffffff00) + ((DPORT.OTP_MAC0 >> 24) & 0xff));
}
const char* system_get_sdk_version(void)
{
return esp_get_idf_version();
}
void system_deep_sleep(uint32_t time_in_us)
{
/* TODO test */
esp_deep_sleep(time_in_us);
}
void system_restart(void)
{
esp_restart();
}
void system_update_cpu_freq(uint8_t freq)
{
if (freq == 160) {
rtc_clk_cpu_freq_set(RTC_CPU_FREQ_160M);
}
else {
rtc_clk_cpu_freq_set(RTC_CPU_FREQ_80M);
}
}

60
cpu/esp8266/sdk/system.h Normal file
View File

@ -0,0 +1,60 @@
/*
* Copyright (C) 2019 Gunar Schorcht
*
* This file is subject to the terms and conditions of the GNU Lesser
* General Public License v2.1. See the file LICENSE in the top level
* directory for more details.
*/
/**
* @ingroup cpu_esp8266_sdk
* @{
*
* @file
* @brief ESP8266 user defined SDK function prototypes
*
* @author Gunar Schorcht <gunar@schorcht.net>
* @}
*/
#ifndef SYSTEM_H
#define SYSTEM_H
#ifndef DOXYGEN
#include <stdint.h>
#include <stdarg.h>
#include "esp_task_wdt.h"
#include "sdk/ets.h"
#ifdef __cplusplus
extern "C" {
#endif
/**
* @name Functions for NONOS SDK compatibility
*
* @{
*/
extern uint8_t system_get_cpu_freq(void);
extern void system_update_cpu_freq(uint8_t);
extern uint32_t system_get_chip_id(void);
extern const char* system_get_sdk_version(void);
extern void system_deep_sleep(uint32_t time_in_us);
extern void system_restart(void);
#define system_wdt_init esp_task_wdt_init
#define system_wdt_feed esp_task_wdt_reset
#define system_wdt_start pp_soft_wdt_stop
#define system_wdt_stop pp_soft_wdt_restart
/** @} */
#ifdef __cplusplus
}
#endif
#endif /* DOXYGEN */
#endif /* SYSTEM_H */

View File

@ -1,47 +0,0 @@
/*
* Copyright (C) 2018 Gunar Schorcht
*
* This file is subject to the terms and conditions of the GNU Lesser
* General Public License v2.1. See the file LICENSE in the top level
* directory for more details.
*/
/**
* @ingroup cpu_esp8266_sdk
* @{
*
* @file
* @brief ESP8266 user defined SDK function prototypes
*
* @author Gunar Schorcht <gunar@schorcht.net>
* @}
*/
#ifndef USER_H
#define USER_H
#ifndef DOXYGEN
#include <stdint.h>
#include <stdarg.h>
#include "c_types.h"
#ifdef __cplusplus
extern "C" {
#endif
#ifndef MODULE_ESP_SDK
extern uint32_t user_rf_cal_sector_set(void);
extern void uart_tx_flush (uint32_t);
extern void system_set_pll (uint8_t);
#endif /* MODULE_ESP_SDK */
#ifdef __cplusplus
}
#endif
#endif /* DOXYGEN */
#endif /* USER_H */

View File

@ -1,5 +1,5 @@
/*
* Copyright (C) 2018 Gunar Schorcht
* Copyright (C) 2019 Gunar Schorcht
*
* This file is subject to the terms and conditions of the GNU Lesser
* General Public License v2.1. See the file LICENSE in the top level
@ -16,149 +16,82 @@
* @author Gunar Schorcht <gunar@schorcht.net>
* @}
*/
#define ENABLE_DEBUG 0
#include "debug.h"
#include <stdint.h>
#include <stdio.h>
#include <stddef.h>
#include <stdarg.h>
#include <string.h>
#include <stdlib.h>
#include "kernel_init.h"
#include "log.h"
#include "periph/init.h"
#include "c_types.h"
#include "spi_flash.h"
#include "periph/uart.h"
#include "board.h"
#include "common.h"
#include "esp/common_macros.h"
#include "esp_log.h"
#include "exceptions.h"
#include "stdio_base.h"
#include "syscalls.h"
#include "tools.h"
#include "thread_arch.h"
#include "esp/iomux_regs.h"
#include "esp/spi_regs.h"
#include "esp/xtensa_ops.h"
#include "rom_functions.h"
#include "sdk/sdk.h"
#if MODULE_ESP_GDBSTUB
#include "esp-gdbstub/gdbstub.h"
#include "gdbstub.h"
#endif
extern void board_init(void);
extern void board_print_config(void);
/* external esp function declarations */
extern uint32_t hwrand (void);
uint32_t hwrand (void);
void esp_riot_init(void)
{
/* enable cached read from flash */
Cache_Read_Enable_New();
#ifdef MODULE_NEWLIB_SYSCALLS_DEFAULT
/* initialization as it should be called from newlibc */
extern void _init(void);
/* initialize the ISR stack for usage measurements */
thread_isr_stack_init();
#ifndef MCU_ESP8266
/* initialize newlib system calls */
syscalls_init ();
#endif
extern uint8_t _bss_start;
extern uint8_t _bss_end;
extern uint8_t _sheap;
extern uint8_t _eheap;
/* set system frequency if not 80 MHz */
if (ESP8266_CPU_FREQUENCY != 80) {
system_update_cpu_freq(ESP8266_CPU_FREQUENCY);
}
#ifdef MODULE_ESP_SDK
#include "sdk/ets_task.h"
/* EST Task priority */
#define ETS_TASK_PRIORITY (1)
/* stack for the ETS task */
static char ets_task_stack[ETS_THREAD_STACKSIZE];
/* ETS task code */
extern void *ets_task_func(void *arg);
/**
* @brief System main loop called by the ETS
*
* This function is called by ETS after all initializations has been
* finished to start periodic processing of defined ETS tasks. We
* overwrite this ETS function to take over the control and to start RIOT.
*/
void ets_run(void)
{
#if ENABLE_DEBUG
register uint32_t *sp __asm__ ("a1");
ets_uart_printf("_stack %p\n", sp);
ets_uart_printf("_bss_start %p\n", &_bss_start);
ets_uart_printf("_bss_end %p\n", &_bss_end);
ets_uart_printf("_heap_start %p\n", &_sheap);
ets_uart_printf("_heap_end %p\n", &_eheap);
ets_uart_printf("_heap_free %lu\n", get_free_heap_size());
#endif
/* init min task priority */
ets_task_min_prio = 0;
#ifdef MODULE_NEWLIB_SYSCALLS_DEFAULT
_init();
#endif
ets_tasks_init();
/* enable interrupts used by ETS/SDK */
ets_isr_unmask(BIT(ETS_FRC2_INUM));
ets_isr_unmask(BIT(ETS_WDEV_INUM));
ets_isr_unmask(BIT(ETS_WDT_INUM));
#ifdef MODULE_ESP_GDBSTUB
gdbstub_init();
#endif
#if ENABLE_DEBUG==0
/* disable SDK messages */
system_set_os_print(0);
#endif
#ifdef CONTEXT_SWITCH_BY_INT
extern void IRAM thread_yield_isr(void* arg);
ets_isr_attach(ETS_SOFT_INUM, thread_yield_isr, NULL);
ets_isr_unmask(BIT(ETS_SOFT_INUM));
#endif
/* initialize dummy lwIP library to link it even if esp_wifi is not used */
extern void esp_lwip_init(void);
esp_lwip_init();
thread_create(ets_task_stack, sizeof(ets_task_stack),
ETS_TASK_PRIORITY,
THREAD_CREATE_WOUT_YIELD | THREAD_CREATE_STACKTEST,
ets_task_func, NULL, "ets");
/* does not return */
kernel_init();
}
/**
* @brief Initialize the CPU, the board and the peripherals
*
* This function is called by ESP8266 SDK when all system initializations
* has been finished.
*/
void system_init(void)
{
LOG_INFO("\nStarting ESP8266 CPU with ID: %08x", system_get_chip_id());
LOG_INFO("\nSDK Version %s\n\n", system_get_sdk_version());
/* avoid reconnection all the time */
wifi_station_disconnect();
ets_printf("\n");
ets_printf("Starting ESP8266 CPU with ID: %08x\n", system_get_chip_id());
ets_printf("ESP8266-RTOS-SDK Version %s\n\n", system_get_sdk_version());
ets_printf("CPU clock frequency: %d MHz\n", system_get_cpu_freq());
extern void heap_stats(void);
heap_stats();
ets_printf("\n");
/* set exception handlers */
init_exceptions ();
/* systemwide UART initialization */
extern void uart_system_init (void);
uart_system_init();
/* init watchdogs */
system_wdt_init();
/* init random number generator */
srand(hwrand());
#if MODULE_MTD
/* init flash drive */
extern void flash_drive_init (void);
flash_drive_init();
extern void spi_flash_drive_init (void);
spi_flash_drive_init();
#endif
/* initialize stdio*/
stdio_init();
@ -169,698 +102,25 @@ void system_init(void)
/* trigger board initialization */
board_init();
/* print memory info */
print_meminfo();
/* print the board config */
board_print_config();
}
/**
* @brief Entry point in user space after a system reset
*
* This function is called after system reset by the ESP8266 SDK. In this
* functions following steps are neccessary:
*
* 1. Reinit system timer as microsecond timer (precision is 500 us)
* 2. Set the UART parameters for serial output
* 3. Set the system initialization callback
*/
void IRAM user_init (void)
{
syscalls_init ();
thread_isr_stack_init ();
/* set system frequency */
system_update_cpu_freq(ESP8266_CPU_FREQUENCY);
/* reinit system timer as microsecond timer */
system_timer_reinit ();
/* setup the serial communication */
uart_div_modify(0, UART_CLK_FREQ / STDIO_UART_BAUDRATE);
/* once the ETS initialization is done we can start with our code as callback */
system_init_done_cb(system_init);
/* keep wifi interface in null mode per default */
wifi_set_opmode_current (0);
}
#else /* MODULE_ESP_SDK */
#include "esp/dport_regs.h"
#include "esp/phy_info.h"
#include "esp/spiflash.h"
#include "user_config.h"
/**
* @brief Defines the structure of the file header in SPI flash
*
* @see https://github.com/espressif/esptool/wiki/Firmware-Image-Format
*/
typedef struct __attribute__((packed))
{
uint8_t magic; /* always 0xe9 */
uint8_t segments; /* number of segments */
uint8_t mode; /* 0 - qio, 1 - qout, 2 - dio, 3 - dout */
uint8_t speed:4; /* 0 - 40 MHz, 1 - 26 MHz, 2 - 20 MHz, 15 - 80 MHz */
uint8_t size:4; /* 0 - 512 kB, 1 - 256 kB, 2 - 1 MB, 3 - 2 MB, 4 - 4 MB */
} _spi_flash_header;
#define SPI_FLASH_SECTOR_SIZE 4096
struct s_info {
uint32 ap_ip; /* +00 */
uint32 ap_mask; /* +04 */
uint32 ap_gw; /* +08 */
uint32 st_ip; /* +0C */
uint32 st_mask; /* +10 */
uint32 st_gw; /* +14 */
uint8 ap_mac[6]; /* +18 */
uint8 st_mac[6]; /* +1E */
} __attribute__((packed, aligned(4)));
static struct s_info info;
enum rst_reason {
REASON_DEFAULT_RST = 0,
REASON_WDT_RST = 1,
REASON_EXCEPTION_RST = 2,
REASON_SOFT_WDT_RST = 3,
REASON_SOFT_RESTART = 4,
REASON_DEEP_SLEEP_AWAKE = 5,
REASON_EXT_SYS_RST = 6
};
struct rst_info{
uint32 reason;
uint32 exccause;
uint32 epc1;
uint32 epc2;
uint32 epc3;
uint32 excvaddr;
uint32 depc;
};
/**
* @brief System configuration store formats
*
* source https://github.com/pvvx/esp8266web
* (c) PV` 2015
*
* @{
*/
/* SDK 2.0.0 */
#define wifi_config_size 0x494 /* 1172 bytes */
#define g_ic_size (wifi_config_size + 532) /* 1704 bytes */
struct ets_store_wifi_hdr { /* Sector flash addr flashchip->chip_size-0x1000 (0x4027F000) */
uint8 bank; /* +00 = 0, 1 WiFi config flash addr: */
/* 0 - flashchip->chip_size-0x3000 (0x7D000), */
/* 1 - flashchip->chip_size-0x2000 */
uint8 unused[3]; /* +01 = 0xff, 0xff, 0xff */
uint32 flag; /* +04 = 0x55aa55aa */
uint32 wr_cnt; /* +08 = 0x00000001 */
uint32 len[2]; /* +12 = 0x00000020, 0xffffffff */
uint32 chk[2]; /* +20 = 0x000000ed, 0xffffffff */
uint32 flag2; /* +28 = 0xaa55aa55 */
};
static const uint8_t
ets_store_wifi_hdr_default[sizeof(struct ets_store_wifi_hdr)] =
{
0x00, 0xff, 0xff, 0xff, 0xaa, 0x55, 0xaa, 0x55,
0x01, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00,
0xff, 0xff, 0xff, 0xff, 0xed, 0x00, 0x00, 0x00,
0xff, 0xff, 0xff, 0xff, 0x55, 0xaa, 0x55, 0xaa
};
struct s_wifi_store { /* WiFi config flash addr: flashchip->chip_size - 0x3000 or -0x2000 */
/* SDK >= 2.0.0 */
uint8 boot_info[8]; /* +000 0x000 (boot_info[1]) boot_version */
uint8 wfmode[4]; /* +008 0x008 */
uint32 st_ssid_len; /* +012 0x00c */
uint8 st_ssid[32]; /* +016 0x010 */
uint8 field_048[7]; /* +048 0x030 */
uint8 st_passw[64]; /* +055 0x037 */
uint8 field_119; /* +119 0x077 */
uint8 data_120[32]; /* +120 0x078 */
uint8 field_152[17]; /* +152 0x098 */
uint8 field_169; /* +169 0x0a9 */
uint8 field_170[6]; /* +170 0x0aa */
uint32 ap_ssid_len; /* +176 0x0b0 */
uint8 ap_ssid[32]; /* +180 0x0b4 */
uint8 ap_passw[64]; /* +212 0x0d4 */
uint8 field_276[32]; /* +276 0x114 */
uint8 field_308; /* +308 0x134 */
uint8 wfchl; /* +309 0x135 */
uint8 field_310; /* +310 0x136 */
uint8 field_311; /* +311 0x137 */
uint8 field_312; /* +312 0x138 */
uint8 field_313; /* +313 0x139 */
uint8 field_314; /* +314 0x13a */
uint8 field_315; /* +315 0x13b */
uint16 field_316; /* +316 0x13c */
uint8 field_318[2]; /* +318 0x13e */
uint32 st1ssid_len; /* +320 0x140 */
uint8 st1ssid[32]; /* +324 0x144 */
uint8 st1passw[64]; /* +356 0x164 */
uint8 field_420[400]; /* +420 0x1a4 */
uint32 field_820[3]; /* +820 0x334 */
uint8 field_832[4]; /* +832 0x340 wifi_station_set_auto_connect */
uint32 phy_mode; /* +836 0x344 */
uint8 field_840[36]; /* +840 0x348 */
uint16 beacon; /* +876 0x36c 876+532 g_ic+1408 */
uint8 field_878[2]; /* +878 0x36e */
uint32 field_880; /* +880 0x370 */
uint32 field_884; /* +884 0x374 */
uint32 field_888; /* +888 0x378 */
uint8 field_892[284]; /* +892 0x37c ... 1176 0x498 */
};
struct s_g_ic {
uint32 boot_info; /* +0000 g_ic+0 0x3FFF2324 boot_version? */
uint32 field_004; /* +0004 g_ic+4 */
uint32 field_008; /* +0008 g_ic+8 */
uint32 field_00C; /* +000C g_ic+12 */
struct netif **netif1; /* +0010 g_ic+16 */
struct netif **netif2; /* +0014 g_ic+20 */
uint32 field_018; /* +0018 g_ic+24 */
uint32 field_01C; /* +001C g_ic+28 */
uint32 field_020; /* +0020 g_ic+32 */
uint32 field_024; /* +0024 g_ic+36 */
uint32 field_028; /* +0028 g_ic+40 */
uint8 field_02C[84]; /* +002C g_ic+44 */
uint32 field_080; /* +0080 g_ic+128 */
uint8 field_084[200]; /* +0084 g_ic+132 */
/* [0x12c] */
void * field_14C; /* +014C g_ic+332 */
uint32 ratetable; /* +0150 g_ic+336 */
uint8 field_154[44]; /* +0154 g_ic+340 */
uint32 field_180; /* +0180 g_ic+384 */
/* [0x170..0x180] wifi_get_user_ie */
void * field_184; /* +0184 g_ic+388 user_ie_manufacturer_recv_cb */
uint32 field_188; /* +0188 g_ic+392 */
uint32 field_18C; /* +018C g_ic+396 */
uint32 field_190; /* +0190 g_ic+400 */
uint32 field_194; /* +0194 g_ic+404 */
uint32 field_198; /* +0198 g_ic+408 */
uint32 field_19C; /* +019C g_ic+412 */
uint32 field_1A0; /* +01A0 g_ic+416 */
uint32 field_1A4; /* +01A4 g_ic+420 */
uint32 field_1A8; /* +01A8 g_ic+424 */
uint32 field_1AC; /* +01AC g_ic+428 */
uint32 field_1B0; /* +01B0 g_ic+432 */
uint32 field_1B4; /* +01B4 g_ic+436 */
uint32 field_1B8; /* +01B8 g_ic+440 */
uint32 field_1BC; /* +01BC g_ic+444 */
uint32 field_1C0; /* +01C0 g_ic+448 */
uint32 field_1C4; /* +01C4 g_ic+452 */
uint32 field_1C8[19]; /* +01C8 g_ic+456 ...532 */
struct s_wifi_store wifi_store; /* g_ic+??? */
};
typedef union _u_g_ic{
struct s_g_ic g;
uint8 c[g_ic_size];
uint16 w[g_ic_size/2];
uint32 d[g_ic_size/4];
} u_g_ic;
static u_g_ic g_ic;
/** }@ */
/**
* Following functions are from https://github.com/pvvx/esp8266web
* (c) PV` 2015
*
* @{
*/
void read_macaddr_from_otp(uint8_t* mac)
{
/* fixed prefix */
mac[0] = 0x18;
mac[1] = 0xfe;
mac[2] = 0x34;
if ((!(DPORT.OTP_CHIPID & (1 << 15))) ||
((DPORT.OTP_MAC0 == 0) && (DPORT.OTP_MAC1 == 0))) {
mac[3] = 0x18;
mac[4] = 0xfe;
mac[5] = 0x34;
}
else {
mac[3] = (DPORT.OTP_MAC1 >> 8) & 0xff;
mac[4] = DPORT.OTP_MAC1 & 0xff;
mac[5] = (DPORT.OTP_MAC0 >> 24) & 0xff;
}
}
int ICACHE_FLASH_ATTR flash_data_check(uint8 *check_buf)
{
uint32 cbuf[32];
uint32 *pcbuf = cbuf;
uint8 *pbuf = check_buf;
int i = 27;
while (i--) {
*pcbuf = pbuf[0] | (pbuf[1]<<8) | (pbuf[2]<<16) | (pbuf[3]<<24);
pcbuf++;
pbuf+=4;
}
cbuf[24] = (DPORT.OTP_MAC1 & 0xFFFFFFF) | ((DPORT.OTP_CHIPID & 0xF000) << 16);
cbuf[25] = (DPORT.OTP_MAC2 & 0xFFFFFFF) | (DPORT.OTP_MAC0 & 0xFF000000);
pcbuf = cbuf;
uint32 xsum = 0;
do {
xsum += *pcbuf++;
} while (pcbuf != &cbuf[26]);
xsum ^= 0xFFFFFFFF;
if (cbuf[26] != xsum) {
return 1;
}
return 0;
}
/** }@ */
/**
* @brief Startup function hook placed at 0x40100000
*/
void __attribute__((section(".UserEnter.text"))) NORETURN _call_user_start_hook(void)
{
__asm__ volatile (
" vectors_base: .word 0x40100000 \n" /* must contain entry point */
" \n"
" _call_user_start: \n" /* system startup function */
" .global _call_user_start \n"
" l32r a2, vectors_base \n" /* set vector base */
" wsr a2, vecbase \n"
" call0 cpu_user_start \n" /* call startup function */
);
UNREACHABLE();
}
void ICACHE_FLASH_ATTR start_phase2 (void);
/**
* @brief Startup function
*
* This function is the entry point in the user application. It is called
* after a system reset to startup the system.
*/
void __attribute__((noreturn)) IRAM cpu_user_start (void)
{
register uint32_t *sp __asm__ ("a1"); (void)sp;
/* PHASE 1: startup in SDK */
struct rst_info rst_if = { .reason = 0 };
system_rtc_mem_read(0, &rst_if, sizeof(struct rst_info));
/**
* Setup the serial communication speed. After cold start UART_CLK_FREQ is
* only 26/40 (65 %). So the baud rate would be only 74880. To have 115200
* at the beginning of the cold start, we have to set it to 177231 baud.
* This is changed later in function system_set_pll.
*/
system_set_pll(1); /* parameter is fix (from esp_init_data_default.bin byte 48) */
#if 0
if (rst_if.reason > REASON_DEFAULT_RST) {
/* warm start */
uart_div_modify(0, UART_CLK_FREQ / STDIO_UART_BAUDRATE);
}
else {
/* cold start */
uart_div_modify(0, UART_CLK_FREQ / 177231);
}
#else
uart_div_modify(0, UART_CLK_FREQ / STDIO_UART_BAUDRATE);
#endif
/* flush uart_tx_buffer */
ets_uart_printf(" \n");
#if ENABLE_DEBUG
ets_uart_printf("reset reason: %d %d\n", rst_if.reason, rtc_get_reset_reason());
ets_uart_printf("exccause=%ld excvaddr=%08lx\n", rst_if.exccause, rst_if.excvaddr);
ets_uart_printf("epc1=%08lx epc2=%08lx epc3=%08lx\n", rst_if.epc1, rst_if.epc2, rst_if.epc3);
ets_uart_printf("depc=%ld\n", rst_if.depc);
ets_uart_printf("_stack %p\n", sp);
ets_uart_printf("_bss_start %p\n", &_bss_start);
ets_uart_printf("_bss_end %p\n", &_bss_end);
ets_uart_printf("_heap_start %p\n", &_sheap);
ets_uart_printf("_heap_end %p\n", &_eheap);
ets_uart_printf("_heap_free %lu\n", get_free_heap_size());
#endif
uint32_t flash_sectors;
uint32_t flash_size;
_spi_flash_header flash_header;
SPI(0).USER0 |= SPI_USER0_CS_SETUP;
SPIRead(0, (uint32_t*)&flash_header, 4);
assert (flash_header.magic == 0xe9);
/* SPI flash sectors a 4.096 byte */
switch (flash_header.size) {
case 0: flash_sectors = 128; break; /* 512 kByte */
case 1: flash_sectors = 64; break; /* 256 kByte */
case 2: flash_sectors = 256; break; /* 1 MByte */
case 3: flash_sectors = 512; break; /* 2 MByte */
case 4: flash_sectors = 1024; break; /* 4 MByte */
default: flash_sectors = 128; break; /* default 512 kByte */
}
flash_size = flash_sectors * SPI_FLASH_SECTOR_SIZE;
flashchip->chip_size = flash_size;
flashchip->sector_size = SPI_FLASH_SECTOR_SIZE;
/*
* SPI flash speed params
* speed = 80MHz / clkdiv_pre / clkcnt_N
*/
uint32_t clkdiv_pre = 1; /* default 40 MHz = 80 MHz / 1 / 2 */
uint32_t clkcnt_N = 2;
switch (flash_header.speed) {
case 0: clkdiv_pre = 1; /* 40 MHz = 80 MHz / 1 / 2 */
clkcnt_N = 2;
break;
case 1: clkdiv_pre = 1; /* 26 MHz = 80 MHz / 1 / 3 */
clkcnt_N = 3;
break;
case 2: clkdiv_pre = 1; /* 20 MHz = 80 MHz / 1 / 4 */
clkcnt_N = 4;
break;
case 15: clkdiv_pre = 0; /* clock is equal to system clock */
break;
default: break;
}
if (clkdiv_pre) {
IOMUX.CONF &= ~IOMUX_CONF_SPI0_CLOCK_EQU_SYS_CLOCK;
SPI(0).CLOCK = VAL2FIELD_M(SPI_CLOCK_DIV_PRE, clkdiv_pre - 1) |
VAL2FIELD_M(SPI_CLOCK_COUNT_NUM, clkcnt_N - 1) |
VAL2FIELD_M(SPI_CLOCK_COUNT_HIGH, clkcnt_N/2 - 1) |
VAL2FIELD_M(SPI_CLOCK_COUNT_LOW, clkcnt_N - 1);
}
else {
IOMUX.CONF |= IOMUX_CONF_SPI0_CLOCK_EQU_SYS_CLOCK;
SPI(0).CLOCK |= SPI_CLOCK_EQU_SYS_CLOCK;
}
ets_uart_printf("Flash size: %lu byte, speed %d MHz",
flash_size, clkdiv_pre ? 80 / clkdiv_pre / clkcnt_N : 80);
switch (flash_header.mode) {
case 0: ets_printf(", mode QIO\n"); break;
case 1: ets_printf(", mode QOUT\n"); break;
case 2: ets_printf(", mode DIO\n"); break;
case 3: ets_printf(", mode DOUT\n"); break;
default: ets_printf("\n");
}
ets_uart_printf("\nStarting ESP8266 CPU with ID: %08x\n\n", system_get_chip_id());
/* clear .bss to avoid startup problems because of compiler optimization options */
memset(&_bss_start, 0x0, &_bss_end-&_bss_start);
/**
* Following parts of code are partially from or inspired by the
* following projects:
*
* [esp8266web](https://github.com/pvvx/esp8266web)
* (c) PV` 2015
*
* [esp-open-rtos](https://github.com/SuperHouse/esp-open-rtos.git).
* Copyright (C) 2015 Superhouse Automation Pty Ltd
* BSD Licensed as described in the file LICENSE
*
* @{
*/
struct ets_store_wifi_hdr binfo;
struct s_wifi_store wscfg;
/* load boot info (32 byte) from last sector and */
uint32_t binfo_addr = flash_size - SPI_FLASH_SECTOR_SIZE;
SPIRead (binfo_addr, (uint32_t*)&binfo, sizeof(binfo));
/* load the system config (1176 byte) from last 3 or 2 sectors */
uint32_t wscfg_addr = flash_size - (binfo.bank ? 2 : 3) * SPI_FLASH_SECTOR_SIZE;
SPIRead (wscfg_addr, (uint32_t*)&wscfg, sizeof(wscfg));
Cache_Read_Enable(0, 0, 1);
#if ENABLE_DEBUG
printf("boot_inf sector @0x%x\n", flash_size - SPI_FLASH_SECTOR_SIZE);
esp_hexdump(&binfo, sizeof(binfo), 'b', 16);
#endif
LOG_INFO("load boot_inf 0x%x, len %d, chk %02x\n",
binfo_addr, sizeof(binfo),
system_get_checksum((uint8_t*)&binfo, sizeof(binfo)));
LOG_INFO("load wifi_cfg 0x%x, len %d, chk %02x\n",
wscfg_addr, sizeof(wscfg),
system_get_checksum((uint8_t*)&wscfg, sizeof(wscfg)));
/* check whether boot_inf sector could be loaded */
if (binfo.bank > 0 && binfo.flag == 0xffffffff) {
LOG_INFO("no boot_inf sector @0x%x, write a default one to flash\n", binfo_addr);
memcpy (&binfo, ets_store_wifi_hdr_default, sizeof(binfo));
spi_flash_write (binfo_addr, (uint32_t*)&binfo, sizeof(binfo));
}
/* check the checksum */
if (binfo.flag == 0x55aa55aa &&
binfo.chk[binfo.bank] == system_get_checksum((uint8_t*)&wscfg, binfo.len[binfo.bank])) {
/* checksum test is ok */
}
else {
/* checksum error but continue */
LOG_INFO("flash check sum error @0x%x\n", wscfg_addr);
/* check whether there is no wifi_cfg sector */
uint8_t* wscfg_sec = (uint8_t*)&wscfg;
size_t i = 0;
for ( ; i < sizeof(wscfg); i++) {
if (wscfg_sec[i] != 0xff) {
break;
}
}
/* no data different from 0xff found, we assume that the flash was erased */
if (i == sizeof(wscfg)) {
/* TODO write a default wifi_cfg sector automatically into the flash in that case */
LOG_INFO("\nno wifi_cfg sector found, use following command:\n"
"esptool.py write_flash 0x%x $(RIOT_CPU)/bin/wifi_cfg_default.bin\n\n",
wscfg_addr);
}
}
memcpy(&g_ic.g.wifi_store, &wscfg, sizeof(wscfg));
uart_tx_flush(0);
uart_tx_flush(1);
init_exceptions ();
/* PHASE 2: sdk_init in SDK */
start_phase2();
/** }@ */
/* set system frequency */
system_update_cpu_freq(ESP8266_CPU_FREQUENCY);
/* PHASE 3: start RIOT-OS kernel */
/* init random number generator */
srand(hwrand());
/* init flash drive */
extern void flash_drive_init (void);
flash_drive_init();
/* initialize stdio*/
stdio_init();
/* trigger static peripheral initialization */
periph_init();
/* initialize the board and startup the kernel */
board_init();
/* print memory info */
print_meminfo();
/* print the board config */
board_print_config();
#ifdef MODULE_NEWLIB_SYSCALLS_DEFAULT
_init();
#endif
/* initialize ESP system event loop */
extern void esp_event_handler_init(void);
esp_event_handler_init();
#ifdef MODULE_ESP_GDBSTUB
gdbstub_init();
#endif
#ifdef CONTEXT_SWITCH_BY_INT
/* activate software interrupt based context switch */
extern void IRAM thread_yield_isr(void* arg);
ets_isr_attach(ETS_SOFT_INUM, thread_yield_isr, NULL);
ets_isr_unmask(BIT(ETS_SOFT_INUM));
#endif
/* startup the kernel */
kernel_init();
/* should not be reached */
UNREACHABLE() ;
#ifdef MODULE_ESP_GDBSTUB
gdbstub_init();
#endif
}
void start_phase2 (void)
void esp_riot_start(void)
{
uint32_t flash_size = flashchip->chip_size;
struct rst_info rst_if;
system_rtc_mem_read(0, &rst_if, sizeof(struct rst_info));
/**
* Following parts of code are partially from or inspired by the
* following projects:
*
* [esp8266web](https://github.com/pvvx/esp8266web)
* (c) PV` 2015
*
* [esp-open-rtos](https://github.com/SuperHouse/esp-open-rtos.git).
* Copyright (C) 2015 Superhouse Automation Pty Ltd
* BSD Licensed as described in the file LICENSE
*
* @{
*/
/* changes clock freqeuncy and should be done before system_set_pll */
sleep_reset_analog_rtcreg_8266();
/* set correct system clock and adopt UART frequency */
system_set_pll(1); /* parameter is fixed (from esp_init_data_default.bin byte 48) */
uart_div_modify(0, UART_CLK_FREQ / STDIO_UART_BAUDRATE);
uart_tx_flush(0);
uart_tx_flush(1);
syscalls_init ();
thread_isr_stack_init ();
read_macaddr_from_otp(info.st_mac);
LOG_INFO("MAC %02x:%02x:%02x:%02x:%02x:%02x\n",
info.st_mac[0], info.st_mac[1], info.st_mac[2],
info.st_mac[3], info.st_mac[4], info.st_mac[5]);
/* load esp_init_data_default.bin */
uint8_t* pbuf = malloc(1024); (void)pbuf;
uint32_t phy_info_addr = flash_size - 4 * SPI_FLASH_SECTOR_SIZE;
sdk_phy_info_t* phy_info = (sdk_phy_info_t*)pbuf;
spi_flash_read (phy_info_addr, (uint32_t*)phy_info, sizeof(sdk_phy_info_t));
LOG_INFO("load phy_info 0x%x, len %d, chk %02x\n",
phy_info_addr, sizeof(sdk_phy_info_t),
system_get_checksum((uint8_t*)phy_info, sizeof(sdk_phy_info_t)));
/* load rf_cal_sec (default rf_cal_sec = flash_sectors - 5) */
uint32_t rf_cal_sec = user_rf_cal_sector_set();
uint32_t rf_cal_sec_addr = rf_cal_sec * SPI_FLASH_SECTOR_SIZE;
spi_flash_read (rf_cal_sec_addr, (uint32_t*)(pbuf + 128), 628);
LOG_INFO("rf_cal_sec=%d\n", rf_cal_sec);
LOG_INFO("load rf_cal 0x%x, len %d, chk %02x\n",
rf_cal_sec_addr, 628, system_get_checksum(pbuf + 128, 628));
LOG_INFO("reset reason: %d %d\n", rst_if.reason, rtc_get_reset_reason());
#if ENABLE_DEBUG
printf("phy_info sector @0x%x\n", phy_info_addr);
esp_hexdump(pbuf, 128, 'b', 16);
printf("rf_cal sector @0x%x\n", rf_cal_sec_addr);
/* esp_hexdump(pbuf+128, 628, 'b', 16); */
#endif
sdk_phy_info_t default_phy_info;
get_default_phy_info(&default_phy_info);
if (phy_info->version != default_phy_info.version) {
/* check whether there is no phy_info sector */
uint8_t* phy_info_sec = (uint8_t*)phy_info;
size_t i = 0;
for ( ; i < sizeof(sdk_phy_info_t); i++) {
if (phy_info_sec[i] != 0xff) {
break;
}
}
/* no data different from 0xff found, we assume that the flash was erased */
if (i == sizeof(sdk_phy_info_t)) {
/* write a default default phy_info sector into the flash */
LOG_INFO("no phy_info sector found @0x%x, "
"writing esp_init_data_default.bin into flash\n",
phy_info_addr);
spi_flash_write (phy_info_addr,
(uint32_t*)&default_phy_info, sizeof(sdk_phy_info_t));
}
LOG_INFO("set default esp_init_data!\n");
memcpy(pbuf, &default_phy_info, sizeof(sdk_phy_info_t));
}
extern uint8_t* phy_rx_gain_dc_table;
extern uint8_t phy_rx_gain_dc_flag;
phy_rx_gain_dc_table = &pbuf[0x100];
phy_rx_gain_dc_flag = 0;
int xflg = (flash_data_check(&pbuf[128]) != 0 ||
phy_check_data_table(phy_rx_gain_dc_table, 125, 1) != 0) ? 1 : 0;
if (rst_if.reason != REASON_DEEP_SLEEP_AWAKE) {
phy_afterwake_set_rfoption(1);
if (xflg == 0) {
write_data_to_rtc(pbuf+128);
}
}
g_ic.c[491] = ((phy_info->freq_correct_mode & 7 )== 3) ? 1 : 0;
pbuf[0xf8] = 0;
/* clear RTC memory */
memset(&rst_if, 0, sizeof(struct rst_info));
system_rtc_mem_write(0, &rst_if, sizeof(struct rst_info));
uart_tx_flush(0);
uart_tx_flush(1);
if (register_chipv6_phy(pbuf)) {
LOG_ERROR ("register_chipv6_phy failed");
}
free (pbuf);
/** @} */
/* does not return */
kernel_init();
}
#endif /* MODULE_ESP_SDK */

View File

@ -1,5 +1,5 @@
/*
* Copyright (C) 2018 Gunar Schorcht
* Copyright (C) 2019 Gunar Schorcht
*
* This file is subject to the terms and conditions of the GNU Lesser
* General Public License v2.1. See the file LICENSE in the top level
@ -18,342 +18,589 @@
* @}
*/
#define ENABLE_DEBUG 0
#define MEMLEAK_DEBUG 0
#include "debug.h"
#include "periph/pm.h"
#include "timex.h"
#include <sys/types.h>
#include <sys/errno.h>
#include <sys/reent.h>
#include <sys/stat.h>
#include <malloc.h>
#include <stdarg.h>
#include <stdbool.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <time.h>
#include <sys/errno.h>
#include <sys/stat.h>
#include <sys/times.h>
#include <sys/unistd.h>
#include "ets_sys.h"
#include "c_types.h"
#include "common.h"
#include "cpu_conf.h"
#include "irq.h"
#include "kernel_defines.h"
#include "log.h"
#include "mutex.h"
#include "rmutex.h"
#include "sched.h"
#include "esp_common.h"
#include "esp/common_macros.h"
#include "esp_attr.h"
#include "sdk/sdk.h"
#include "syscalls.h"
#include "esp/xtensa_ops.h"
#include "esp/common_macros.h"
#ifdef MODULE_STDIO_UART
#include "stdio_uart.h"
#endif
#include "sdk/sdk.h"
#ifdef MODULE_ESP_IDF_HEAP
#include "esp_heap_caps.h"
#else
#include "malloc.h"
#endif
#define ENABLE_DEBUG (0)
#include "debug.h"
#define MHZ 1000000UL
#ifndef MODULE_PTHREAD
#define PTHREAD_CANCEL_DISABLE 1
/*
* This is a dummy function to avoid undefined references when linking
* against newlib and module pthread is not used.
*/
int pthread_setcancelstate(int state, int *oldstate)
{
if (oldstate) {
*oldstate = PTHREAD_CANCEL_DISABLE;
}
return 0;
}
#endif /* MODULE_PTHREAD */
/*
* TODO: When the lock functions in this section are enabled, an application
* crashes when an ISR calls a `newlib` function that uses `_lock_acquire`
* or `_log_acquire_recursive` to be thread-safe, for example, `puts` in
* `tests/isr_yield_higher`. The reason is that the implementation of these
* functions uses `mutex` and `rmutex` that do not work in the interrupt
* context. Therefore, the lock functions are disabled for the moment, and
* instead `newlib`'s dummy lock functions are used which do not guarantee
* thread safety.
*/
#if 0
#ifdef MODULE_ESP_SDK
/**
* Map memory management functions to SDK memory management functions.
* This is necessary to use the same heap as the SDK internally does.
* Furthermore, these functions at least avoid interrupts during the
* execution of memory management functions. Memory management functions
* of ETS are not used and have not to be considered therefore.
*/
extern void *pvPortMalloc (size_t size, const char *, unsigned);
extern void vPortFree (void *ptr, const char *, unsigned);
extern void *pvPortZalloc (size_t size, const char *, unsigned);
extern void *pvPortCalloc (size_t nmemb, size_t size, const char *, unsigned);
extern void *pvPortRealloc (void *ptr, size_t size, const char *, unsigned);
extern unsigned int xPortGetFreeHeapSize(void);
void *__real_malloc(size_t size);
void __real_free(void *ptr);
void *__real_calloc(size_t nmemb, size_t size);
void *__real_realloc(void *ptr, size_t size);
void *__real__malloc_r (struct _reent *r, size_t size);
void __real__free_r (struct _reent *r, void *ptr);
void *__real__realloc_r (struct _reent *r, void *ptr, size_t size);
extern uint8_t _eheap; /* end of heap (defined in esp8266.riot-os.app.ld) */
extern uint8_t _sheap; /* start of heap (defined in esp8266.riot-os.app.ld) */
void* IRAM __wrap_malloc(size_t size)
{
#if MEMLEAK_DEBUG
static const char mem_debug_file[] ICACHE_RODATA_ATTR STORE_ATTR = __FILE__;
return pvPortMalloc(size, mem_debug_file, __LINE__);
#else
return pvPortMalloc(size, "", 0);
#endif
}
void IRAM __wrap_free(void *ptr)
{
#if MEMLEAK_DEBUG
static const char mem_debug_file[] ICACHE_RODATA_ATTR STORE_ATTR = __FILE__;
return vPortFree (ptr, mem_debug_file, __LINE__);
#else
return vPortFree (ptr, "", 0);
#endif
}
void* IRAM __wrap_calloc(size_t nmemb, size_t size)
{
#if MEMLEAK_DEBUG
static const char mem_debug_file[] ICACHE_RODATA_ATTR STORE_ATTR = __FILE__;
return pvPortCalloc(nmemb, size, mem_debug_file, __LINE__);
#else
return pvPortCalloc(nmemb, size, "", 0);
#endif
}
void* IRAM __wrap_realloc(void *ptr, size_t size)
{
#if MEMLEAK_DEBUG
static const char mem_debug_file[] ICACHE_RODATA_ATTR STORE_ATTR = __FILE__;
return pvPortRealloc(ptr, size, mem_debug_file, __LINE__);
#else
return pvPortRealloc(ptr, size, "", 0);
#endif
}
void* IRAM __wrap__malloc_r (struct _reent *r, size_t size)
{
return __wrap_malloc (size);
}
void IRAM __wrap__free_r (struct _reent *r, void *ptr)
{
__wrap_free (ptr);
}
void IRAM *__wrap__realloc_r (struct _reent *r, void *ptr, size_t size)
{
return __wrap_realloc (ptr, size);
}
unsigned int get_free_heap_size (void)
{
return xPortGetFreeHeapSize();
}
void IRAM syscalls_init (void)
{
}
#else /* MODULE_ESP_SDK */
/*
* To use the same heap as SDK internally does, SDK memory management
* functions have to be replaced by newlib memory functions. In that case,
* the _malloc_lock/_unlock functions have to be defined. Memory management
* functions of ETS are not used and have not to be considered here.
* @name Locking functions
*
* Following functions implement the lock mechanism for newlib.
*/
void* IRAM pvPortMalloc (size_t size, const char *file, unsigned line)
{
(void)file;
(void)line;
return malloc (size);
}
void IRAM vPortFree (void *ptr, const char *file, unsigned line)
{
(void)file;
(void)line;
free (ptr);
}
void* IRAM pvPortCalloc (size_t nmemb, size_t size, const char *file, unsigned line)
{
(void)file;
(void)line;
void *ptr = malloc (nmemb*size);
if (ptr) {
memset (ptr, 0x0, nmemb*size);
}
return ptr;
}
void* IRAM pvPortZalloc (size_t size, const char *file, unsigned line)
{
(void)file;
(void)line;
void *ptr = malloc (size);
if (ptr) {
memset (ptr, 0x0, size);
}
return ptr;
}
void* IRAM pvPortRealloc (void *ptr, size_t size, const char *file, unsigned line)
{
(void)file;
(void)line;
return realloc (ptr, size);
}
size_t IRAM xPortWantedSizeAlign(size_t size)
{
/* allign the size to a multiple of 8 */
return (size & 0x7) ? (size & ~0x7) + 8 : size;
}
size_t IRAM xPortGetFreeHeapSize (void)
{
return get_free_heap_size ();
}
/*
* Following functions implement the lock mechanism in newlib. The only static
* mutex defined here is the __malloc_recursive_mutex to avoid that memory
* management functions try to lock before RIOT's threads are running.
* These lock/unlock functions cannot be used in the SDK version since some ISR
* in SDK use malloc/free which does not work in interrupt context.
/**
* _malloc_rmtx is defined as static variable to avoid recursive calls of
* malloc when _malloc_r tries to lock __malloc_lock_object the first
* time. All other mutexes that are used for the lock mechanism are allocated
* dynamically.
*/
extern _lock_t __malloc_recursive_mutex;
static rmutex_t _malloc_rmtx = RMUTEX_INIT;
void IRAM syscalls_init (void)
{
__malloc_recursive_mutex = (_lock_t)&_malloc_rmtx;
}
/**
* To properly handle the static rmutex _malloc_rmtx, we have to know
* the address of newlib's static variable __malloc_lock_object.
*/
static _lock_t *__malloc_static_object = NULL;
void IRAM _lock_init(_lock_t *lock)
{
CHECK_PARAM (sched_active_thread != 0);
CHECK_PARAM (lock != NULL);
CHECK_PARAM (*lock != ((_lock_t)&_malloc_rmtx));
assert(lock != NULL);
mutex_t* mtx = malloc (sizeof(mutex_t));
mutex_t* mtx = malloc(sizeof(mutex_t));
if (mtx) {
memset (mtx, 0, sizeof(mutex_t));
memset(mtx, 0, sizeof(mutex_t));
*lock = (_lock_t)mtx;
}
}
void IRAM _lock_init_recursive(_lock_t *lock)
{
CHECK_PARAM (sched_active_thread != 0);
CHECK_PARAM (lock != NULL);
CHECK_PARAM (*lock != ((_lock_t)&_malloc_rmtx));
assert(lock != NULL);
rmutex_t* rmtx = malloc (sizeof(rmutex_t));
/**
* Since we don't have direct access to newlib's static variable
* __malloc_lock_object, we have to rely on the fact that function
* _lock_aqcuire_recursive, and thus function _lock_init_recursive
* is called for the first time with newlib's static variable
* __malloc_lock_object as parameter. This is ensured by calling
* malloc in the function syscalls_init.
*/
if (__malloc_static_object == NULL) {
*lock = (_lock_t)&_malloc_rmtx;
__malloc_static_object = lock;
return;
}
/* _malloc_rmtx is static and has not to be allocated */
if (lock == __malloc_static_object) {
return;
}
rmutex_t* rmtx = malloc(sizeof(rmutex_t));
if (rmtx) {
memset (rmtx, 0, sizeof(rmutex_t));
memset(rmtx, 0, sizeof(rmutex_t));
*lock = (_lock_t)rmtx;
}
}
void IRAM _lock_close(_lock_t *lock)
{
CHECK_PARAM (lock != NULL);
CHECK_PARAM (*lock != ((_lock_t)&_malloc_rmtx));
assert(lock != NULL);
assert(lock != __malloc_static_object);
free ((void*)*lock);
free((void*)*lock);
*lock = 0;
}
void IRAM _lock_close_recursive(_lock_t *lock)
{
CHECK_PARAM (lock != NULL);
CHECK_PARAM (*lock != ((_lock_t)&_malloc_rmtx));
assert(lock != NULL);
assert(lock != __malloc_static_object);
free ((void*)*lock);
free((void*)*lock);
*lock = 0;
}
void IRAM _lock_acquire(_lock_t *lock)
{
CHECK_PARAM (sched_active_thread != 0);
CHECK_PARAM (lock != NULL && *lock != 0);
assert(lock != NULL);
mutex_lock ((mutex_t*)*lock);
/* if the lock data structure is still not allocated, initialize it first */
if (*lock == 0) {
_lock_init(lock);
}
/* if scheduler is not running, we have not to lock the mutex */
if (sched_active_thread == NULL) {
return;
}
assert(!irq_is_in());
mutex_lock((mutex_t*)*lock);
}
void IRAM _lock_acquire_recursive(_lock_t *lock)
{
CHECK_PARAM (sched_active_thread != 0);
CHECK_PARAM (lock != NULL && *lock != 0);
assert(lock != NULL);
rmutex_lock ((rmutex_t*)*lock);
/* if the lock data structure is still not allocated, initialize it first */
if (*lock == 0) {
_lock_init_recursive(lock);
}
/* if scheduler is not running, we have not to lock the rmutex */
if (sched_active_thread == NULL) {
return;
}
assert(!irq_is_in());
rmutex_lock((rmutex_t*)*lock);
}
int IRAM _lock_try_acquire(_lock_t *lock)
{
CHECK_PARAM_RET (sched_active_thread != 0, 0);
CHECK_PARAM_RET (lock != NULL && *lock != 0, 0);
assert(lock != NULL);
return rmutex_trylock ((rmutex_t*)*lock);
/* if the lock data structure is still not allocated, initialize it first */
if (*lock == 0) {
_lock_init(lock);
}
/* if scheduler is not running, we have not to lock the mutex */
if (sched_active_thread == NULL) {
return 0;
}
if (irq_is_in()) {
return 0;
}
return mutex_trylock((mutex_t*)*lock);
}
int IRAM _lock_try_acquire_recursive(_lock_t *lock)
{
CHECK_PARAM_RET (sched_active_thread != 0, 0);
CHECK_PARAM_RET (lock != NULL && *lock != 0, 0);
assert(lock != NULL);
return mutex_trylock ((mutex_t*)*lock);
/* if the lock data structure is still not allocated, initialize it first */
if (*lock == 0) {
_lock_init_recursive(lock);
}
/* if scheduler is not running, we have not to lock the rmutex */
if (sched_active_thread == NULL) {
return 0;
}
if (irq_is_in()) {
return 0;
}
return rmutex_trylock((rmutex_t*)*lock);
}
void IRAM _lock_release(_lock_t *lock)
{
CHECK_PARAM (sched_active_thread != 0);
CHECK_PARAM (lock != NULL && *lock != 0);
assert(lock != NULL && *lock != 0);
mutex_unlock ((mutex_t*)*lock);
/* if scheduler is not running, we have not to unlock the mutex */
if (sched_active_thread == NULL) {
return;
}
mutex_unlock((mutex_t*)*lock);
}
void IRAM _lock_release_recursive(_lock_t *lock)
{
CHECK_PARAM (sched_active_thread != 0);
CHECK_PARAM (lock != NULL && *lock != 0);
assert(lock != NULL && *lock != 0);
rmutex_unlock ((rmutex_t*)*lock);
/* if scheduler is not running, we have not to unlock the rmutex */
if (sched_active_thread == NULL) {
return;
}
rmutex_unlock((rmutex_t*)*lock);
}
#define _cheap heap_top
#endif
extern char *heap_top;
extern char _eheap; /* end of heap (defined in esp8266.riot-os.app.ld) */
extern char _sheap; /* start of heap (defined in esp8266.riot-os.app.ld) */
/**
* @name Memory allocation functions
*/
unsigned int IRAM get_free_heap_size (void)
#ifdef MODULE_ESP_IDF_HEAP
#define MALLOC_CAP_DEFAULT MALLOC_CAP_8BIT
#define heap_caps_malloc_default(s) heap_caps_malloc(s, MALLOC_CAP_DEFAULT)
#define heap_caps_realloc_default(p,s) heap_caps_realloc(p, s, MALLOC_CAP_DEFAULT)
void* IRAM_ATTR __wrap__malloc_r(struct _reent *r, size_t size)
{
return heap_caps_malloc_default( size );
}
void IRAM_ATTR __wrap__free_r(struct _reent *r, void *ptr)
{
heap_caps_free( ptr );
}
void* IRAM_ATTR __wrap__realloc_r(struct _reent *r, void* ptr, size_t size)
{
return heap_caps_realloc_default( ptr, size );
}
void* IRAM_ATTR __wrap__calloc_r(struct _reent *r, size_t count, size_t size)
{
void *result = heap_caps_malloc_default(count * size);
if (result) {
bzero(result, count * size);
}
return result;
}
unsigned int get_free_heap_size(void)
{
return heap_caps_get_free_size(MALLOC_CAP_DEFAULT);
}
void heap_stats(void)
{
extern heap_region_t g_heap_region[HEAP_REGIONS_MAX];
for (int i = 0; i < HEAP_REGIONS_MAX; i++) {
ets_printf("Heap region %u @%p: %u (used %u, free %u) [bytes]\n", i,
g_heap_region[i].start_addr,
g_heap_region[i].total_size,
g_heap_region[i].total_size - g_heap_region[i].free_bytes,
g_heap_region[i].free_bytes);
}
}
#else /* MODULE_ESP_IDF_HEAP */
/* for compatibility with ESP-IDF heap functions */
void* _heap_caps_malloc(size_t size, uint32_t caps, const char *file, size_t line)
{
(void)caps;
return malloc(size);
}
void* _heap_caps_calloc(size_t n, size_t size, uint32_t caps, const char *file, size_t line)
{
(void)caps;
return calloc(n, size);
}
void* _heap_caps_realloc(void *ptr, size_t size, uint32_t caps, const char *file, size_t line)
{
return realloc(ptr, size);
}
void *_heap_caps_zalloc(size_t size, uint32_t caps, const char *file, size_t line)
{
void *ptr = malloc(size);
if (ptr) {
memset(ptr, 0, size);
}
return ptr;
}
void _heap_caps_free(void *ptr, const char *file, size_t line)
{
(void)file;
(void)line;
free(ptr);
}
void heap_caps_init(void)
{
}
extern uint8_t _eheap; /* end of heap (defined in esp32.common.ld) */
extern uint8_t _sheap; /* start of heap (defined in esp32.common.ld) */
unsigned int IRAM get_free_heap_size(void)
{
struct mallinfo minfo = mallinfo();
return &_eheap - &_sheap - minfo.uordblks;
}
#endif /* MODULE_ESP_SDK */
void heap_stats(void)
{
ets_printf("heap: %u (used %d, free %u) [bytes]\n",
ets_printf("heap: %u (used %u, free %u) [bytes]\n",
&_eheap - &_sheap, &_eheap - &_sheap - get_free_heap_size(),
get_free_heap_size());
}
int _rename_r (struct _reent *r, const char* old, const char* new)
/* alias for compatibility with espressif/wifi_libs */
uint32_t esp_get_free_heap_size( void ) __attribute__((alias("get_free_heap_size")));
#endif /* MODULE_ESP_IDF_HEAP */
/**
* @name Other system functions
*/
int _rename_r(struct _reent *r, const char *from, const char *to)
{
return 0;
}
void _abort(void)
{
ets_printf("#! abort called: powering off\n");
pm_off();
while (1) { };
}
void _exit_r(struct _reent *r, int status)
{
_exit(status);
}
struct _reent* __getreent(void) {
return _GLOBAL_REENT;
}
#ifdef MCU_ESP32
static int _no_sys_func(struct _reent *r)
{
DEBUG("%s: system function does not exist\n", __func__);
r->_errno = ENOSYS;
return -1;
}
#endif
#include <math.h>
static struct _reent s_reent;
double __ieee754_remainder(double x, double y) {
return x - y * floor(x/y);
#ifdef MCU_ESP32
static struct syscall_stub_table s_stub_table =
{
.__getreent = &__getreent,
._malloc_r = &_malloc_r,
._free_r = &_free_r,
._realloc_r = &_realloc_r,
._calloc_r = &_calloc_r,
._sbrk_r = &_sbrk_r,
._system_r = (int (*)(struct _reent *, const char*))&_no_sys_func,
._raise_r = (void (*)(struct _reent *))&_no_sys_func,
._abort = &_abort,
._exit_r = &_exit_r,
._getpid_r = &_getpid_r,
._kill_r = &_kill_r,
._times_r = &_times_r,
._gettimeofday_r = _gettimeofday_r,
._open_r = &_open_r,
._close_r = &_close_r,
._lseek_r = (int (*)(struct _reent *r, int, int, int))&_lseek_r,
._fstat_r = &_fstat_r,
._stat_r = &_stat_r,
._write_r = (int (*)(struct _reent *r, int, const void *, int))&_write_r,
._read_r = (int (*)(struct _reent *r, int, void *, int))&_read_r,
._unlink_r = &_unlink_r,
._link_r = (int (*)(struct _reent *r, const char*, const char*))&_no_sys_func,
._rename_r = (int (*)(struct _reent *r, const char*, const char*))&_no_sys_func,
._lock_init = &_lock_init,
._lock_init_recursive = &_lock_init_recursive,
._lock_close = &_lock_close,
._lock_close_recursive = &_lock_close_recursive,
._lock_acquire = &_lock_acquire,
._lock_acquire_recursive = &_lock_acquire_recursive,
._lock_try_acquire = &_lock_try_acquire,
._lock_try_acquire_recursive = &_lock_try_acquire_recursive,
._lock_release = &_lock_release,
._lock_release_recursive = &_lock_release_recursive,
#if CONFIG_NEWLIB_NANO_FORMAT
._printf_float = &_printf_float,
._scanf_float = &_scanf_float,
#else /* CONFIG_NEWLIB_NANO_FORMAT */
._printf_float = NULL,
._scanf_float = NULL,
#endif /* CONFIG_NEWLIB_NANO_FORMAT */
};
#endif
void syscalls_init(void)
{
#ifdef MCU_ESP32
/* enable the system timer in us (TMG0 is enabled by default) */
TIMER_SYSTEM.config.divider = rtc_clk_apb_freq_get()/MHZ;
TIMER_SYSTEM.config.autoreload = 0;
TIMER_SYSTEM.config.enable = 1;
syscall_table_ptr_pro = &s_stub_table;
syscall_table_ptr_app = &s_stub_table;
#endif
_GLOBAL_REENT = &s_reent;
environ = malloc(sizeof(char*));
environ[0] = NULL;
/*
* initialization of newlib, includes the ctors initialization
*/
extern void __libc_init_array(void);
__libc_init_array();
}
float __ieee754_remainderf(float x, float y) {
return x - y * floor(x/y);
uint32_t system_get_time(void)
{
return phy_get_mactime();
}
uint32_t system_get_time_ms(void)
{
return phy_get_mactime() / US_PER_MS;
}
#ifdef MCU_ESP32
uint64_t system_get_time_64(void)
{
uint64_t ret;
/* latch 64 bit timer value before read */
TIMER_SYSTEM.update = 0;
/* wait until instructions have been finished */
__asm__ volatile ("isync");
/* read the current timer value */
ret = TIMER_SYSTEM.cnt_low;
ret += ((uint64_t)TIMER_SYSTEM.cnt_high) << 32;
return ret;
}
/* alias for compatibility with espressif/wifi_libs */
int64_t esp_timer_get_time(void) __attribute__((alias("system_get_time_64")));
static IRAM void system_wdt_int_handler(void *arg)
{
TIMERG0.int_clr_timers.wdt=1; /* clear interrupt */
system_wdt_feed();
}
void IRAM system_wdt_feed(void)
{
DEBUG("%s\n", __func__);
TIMERG0.wdt_wprotect=TIMG_WDT_WKEY_VALUE; /* disable write protection */
TIMERG0.wdt_feed=1; /* reset MWDT */
TIMERG0.wdt_wprotect=0; /* enable write protection */
}
void system_wdt_init(void)
{
/* disable boot watchdogs */
TIMERG0.wdt_config0.flashboot_mod_en = 0;
RTCCNTL.wdt_config0.flashboot_mod_en = 0;
/* enable system watchdog */
TIMERG0.wdt_wprotect=TIMG_WDT_WKEY_VALUE; /* disable write protection */
TIMERG0.wdt_config0.stg0 = TIMG_WDT_STG_SEL_INT; /* stage0 timeout: interrupt */
TIMERG0.wdt_config0.stg1 = TIMG_WDT_STG_SEL_RESET_SYSTEM; /* stage1 timeout: sys reset */
TIMERG0.wdt_config0.sys_reset_length = 7; /* sys reset signal length: 3.2 us */
TIMERG0.wdt_config0.cpu_reset_length = 7; /* sys reset signal length: 3.2 us */
TIMERG0.wdt_config0.edge_int_en = 0;
TIMERG0.wdt_config0.level_int_en = 1;
/* MWDT clock = 80 * 12,5 ns = 1 us */
TIMERG0.wdt_config1.clk_prescale = 80;
/* define stage timeouts */
TIMERG0.wdt_config2 = 2 * US_PER_SEC; /* stage 0: 2 s (interrupt) */
TIMERG0.wdt_config3 = 4 * US_PER_SEC; /* stage 1: 4 s (sys reset) */
TIMERG0.wdt_config0.en = 1; /* enable MWDT */
TIMERG0.wdt_feed = 1; /* reset MWDT */
TIMERG0.wdt_wprotect = 0; /* enable write protection */
DEBUG("%s TIMERG0 wdt_config0=%08x wdt_config1=%08x wdt_config2=%08x\n",
__func__, TIMERG0.wdt_config0.val, TIMERG0.wdt_config1.val,
TIMERG0.wdt_config2);
/* route WDT peripheral interrupt source to CPU_INUM_WDT */
intr_matrix_set(PRO_CPU_NUM, ETS_TG0_WDT_LEVEL_INTR_SOURCE, CPU_INUM_WDT);
/* set the interrupt handler and activate the interrupt */
xt_set_interrupt_handler(CPU_INUM_WDT, system_wdt_int_handler, NULL);
xt_ints_on(BIT(CPU_INUM_WDT));
}
void system_wdt_stop(void)
{
xt_ints_off(BIT(CPU_INUM_WDT));
TIMERG0.wdt_wprotect=TIMG_WDT_WKEY_VALUE; /* disable write protection */
TIMERG0.wdt_config0.en = 0; /* disable MWDT */
TIMERG0.wdt_feed = 1; /* reset MWDT */
TIMERG0.wdt_wprotect = 0; /* enable write protection */
}
void system_wdt_start(void)
{
TIMERG0.wdt_wprotect=TIMG_WDT_WKEY_VALUE; /* disable write protection */
TIMERG0.wdt_config0.en = 1; /* disable MWDT */
TIMERG0.wdt_feed = 1; /* reset MWDT */
TIMERG0.wdt_wprotect = 0; /* enable write protection */
xt_ints_on(BIT(CPU_INUM_WDT));
}
#endif
__attribute__((weak)) void
_system_prevent_memset_lto(void *const s, int c, const size_t n)
{
(void)s;
(void)c;
(void)n;
}
void *system_secure_memset(void *s, int c, size_t n)
{
memset(s, c, n);
_system_prevent_memset_lto(s, c, n);
return s;
}

View File

@ -1,5 +1,5 @@
/*
* Copyright (C) 2018 Gunar Schorcht
* Copyright (C) 2019 Gunar Schorcht
*
* This file is subject to the terms and conditions of the GNU Lesser
* General Public License v2.1. See the file LICENSE in the top level
@ -45,7 +45,7 @@
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#define ENABLE_DEBUG 0
#define ENABLE_DEBUG (0)
#include "debug.h"
#include <stdio.h>
@ -58,15 +58,23 @@
#include "thread.h"
#include "sched.h"
#include "common.h"
#include "esp/common_macros.h"
#include "esp/xtensa_ops.h"
#include "sdk/ets_task.h"
#include "sdk/rom.h"
#include "sdk/sdk.h"
#include "esp_common.h"
#include "irq_arch.h"
#include "syscalls.h"
#include "tools.h"
#include "esp_attr.h"
#include "esp/xtensa_ops.h"
#include "rom/ets_sys.h"
#include "xtensa/xtensa_context.h"
#ifdef MCU_ESP32
#include "soc/dport_reg.h"
#else /* MCU_ESP32 */
#include "esp8266/rom_functions.h"
#include "sdk/sdk.h"
#endif /* MCU_ESP32 */
/* User exception dispatcher when exiting */
extern void _xt_user_exit(void);
@ -80,21 +88,29 @@ extern void _frxt_setup_switch(void);
extern void vPortYield(void);
extern void vPortYieldFromInt(void);
#ifdef __XTENSA_CALL0_ABI__
#define task_exit sched_task_exit
#else /* __XTENSA_CALL0_ABI__ */
/* forward declarations */
NORETURN void task_exit(void);
#endif /* __XTENSA_CALL0_ABI__ */
char* thread_stack_init(thread_task_func_t task_func, void *arg, void *stack_start, int stack_size)
{
/*
* Stack layout after task stack initialization
/* Stack layout after task stack initialization
*
* +------------------------+
* | | TOP
* | thread_control_block |
* stack_start + stack_size ==> | |
* stack_start + stack_size ==> | | top_of_stack+1
* +------------------------+
* top_of_stack ==> | |
* | XT_CP_FRAME |
* | XT_CP_SA |
* | (optional) |
* top_of_stack + 1 - XT_CP_SIZE ==> | |
* +------------------------+
* | ... | ...
* | cpstored | XT_CPSTORED
* top_of_stack + 1 - XT_CP_SIZE ==> | cpenable | XT_CPENABLE
* (cp_state) +------------------------+
* | |
* | XT_STK_FRAME |
* | | XT_STK_...
@ -126,39 +142,43 @@ char* thread_stack_init(thread_task_func_t task_func, void *arg, void *stack_sta
uint8_t *top_of_stack;
uint8_t *sp;
top_of_stack = (uint8_t*)((uint32_t)stack_start + stack_size-1);
/* Clear whole stack with a known value to assist debugging */
#if !defined(DEVELHELP) && !defined(SCHED_TEST_STACK)
/* Unfortunatly, this affects thread_measure_stack_free function */
memset(stack_start, 0, stack_size);
#endif
top_of_stack = (uint8_t*)((uint32_t)stack_start + stack_size - 1);
/* BEGIN - code from FreeRTOS port for Xtensa from Cadence */
/* Create interrupt stack frame aligned to 16 byte boundary */
sp = (uint8_t*)(((uint32_t)(top_of_stack+1) - XT_STK_FRMSZ - XT_CP_SIZE) & ~0xf);
sp = (uint8_t*)(((uint32_t)(top_of_stack + 1) - XT_STK_FRMSZ - XT_CP_SIZE) & ~0xf);
/* Clear whole stack with a known value to assist debugging */
#if !defined(DEVELHELP) && !defined(SCHED_TEST_STACK)
/* Unfortunately, this affects thread_measure_stack_free function */
memset(stack_start, 0, stack_size);
#else
memset(sp, 0, XT_STK_FRMSZ + XT_CP_SIZE);
#endif
/* ensure that stack is big enough */
assert (sp > (uint8_t*)stack_start);
XtExcFrame* exc_frame = (XtExcFrame*)sp;
/* Explicitly initialize certain saved registers */
/* Explicitly initialize certain saved registers for call0 ABI */
exc_frame->pc = (uint32_t)task_func; /* task entry point */
exc_frame->a0 = (uint32_t)sched_task_exit; /* task exit point (CHANGED) */
exc_frame->a0 = (uint32_t)task_exit; /* task exit point*/
exc_frame->a1 = (uint32_t)sp + XT_STK_FRMSZ; /* physical top of stack frame */
exc_frame->a2 = (uint32_t)arg; /* parameters for task_func */
exc_frame->exit = (uint32_t)_xt_user_exit; /* user exception exit dispatcher */
/* Set initial PS to int level 0, EXCM disabled ('rfe' will enable), user mode. */
/* Also set entry point argument parameter. */
#ifdef __XTENSA_CALL0_ABI__
/* CALL0 ABI */
/* for CALL0 ABI set in parameter a2 to task argument */
exc_frame->ps = PS_UM | PS_EXCM;
exc_frame->a2 = (uint32_t)arg; /* parameters for task_func */
#else
/* + for windowed ABI also set WOE and CALLINC (pretend task was 'call4'd). */
/* for windowed ABI also set WOE and CALLINC (pretend task was 'call4'd). */
exc_frame->ps = PS_UM | PS_EXCM | PS_WOE | PS_CALLINC(1);
exc_frame->a4 = (uint32_t)task_exit; /* task exit point*/
exc_frame->a6 = (uint32_t)arg; /* parameters for task_func */
#endif
#ifdef XT_USE_SWPRI
@ -174,7 +194,7 @@ char* thread_stack_init(thread_task_func_t task_func, void *arg, void *stack_sta
*/
uint32_t *p;
p = (uint32_t *)(((uint32_t) pxTopOfStack - XT_CP_SIZE));
p = (uint32_t *)(((uint32_t)(top_of_stack + 1) - XT_CP_SIZE));
p[0] = 0;
p[1] = 0;
p[2] = (((uint32_t) p) + 12 + XCHAL_TOTAL_SA_ALIGN - 1) & -XCHAL_TOTAL_SA_ALIGN;
@ -188,54 +208,97 @@ char* thread_stack_init(thread_task_func_t task_func, void *arg, void *stack_sta
return (char*)sp;
}
unsigned sched_interrupt_nesting = 0; /* Interrupt nesting level */
#ifdef CONTEXT_SWITCH_BY_INT
/**
* Context switches are realized using software interrupts
*/
void IRAM thread_yield_isr(void* arg)
{
/* set the context switch flag (indicates that context has to be switched
is switch on exit from interrupt in _frxt_int_exit */
_frxt_setup_switch();
}
#ifdef MCU_ESP8266
extern int MacIsrSigPostDefHdl(void);
unsigned int ets_soft_int_type = ETS_SOFT_INT_NONE;
#endif
void thread_yield_higher(void)
/**
* Context switches are realized using software interrupts since interrupt
* entry and exit functions are the only way to save and restore complete
* context including spilling the register windows to the stack
*/
void IRAM_ATTR thread_yield_isr(void* arg)
{
#ifdef MCU_ESP8266
ETS_NMI_LOCK();
if (ets_soft_int_type == ETS_SOFT_INT_HDL_MAC) {
ets_soft_int_type = MacIsrSigPostDefHdl() ? ETS_SOFT_INT_YIELD
: ETS_SOFT_INT_NONE;
}
if (ets_soft_int_type == ETS_SOFT_INT_YIELD) {
/*
* set the context switch flag (indicates that context has to be
* switched on exit from interrupt in _frxt_int_exit
*/
ets_soft_int_type = ETS_SOFT_INT_NONE;
_frxt_setup_switch();
}
ETS_NMI_UNLOCK();
#else
/* clear the interrupt first */
DPORT_WRITE_PERI_REG(DPORT_CPU_INTR_FROM_CPU_0_REG, 0);
/* set the context switch flag (indicates that context has to be switched
is switch on exit from interrupt in _frxt_int_exit */
_frxt_setup_switch();
#endif
}
/**
* If we are already in an interrupt handler, the function simply sets the
* context switch flag, which indicates that the context has to be switched
* in the _frxt_int_exit function when exiting the interrupt. Otherwise, we
* will generate a software interrupt to force the context switch when
* terminating the software interrupt (see thread_yield_isr).
*/
void IRAM_ATTR thread_yield_higher(void)
{
/* reset hardware watchdog */
system_soft_wdt_feed();
system_wdt_feed();
/* yield next task */
#if defined(ENABLE_DEBUG) && defined(DEVELHELP)
if (sched_active_thread) {
DEBUG("%u old task %u %s %u\n", phy_get_mactime(),
DEBUG("%u old task %u %s %u\n", system_get_time(),
sched_active_thread->pid, sched_active_thread->name,
sched_active_thread->sp - sched_active_thread-> stack_start);
}
#endif
if (!irq_is_in()) {
#ifdef CONTEXT_SWITCH_BY_INT
#ifdef MCU_ESP32
/* generate the software interrupt to switch the context */
DPORT_WRITE_PERI_REG(DPORT_CPU_INTR_FROM_CPU_0_REG, DPORT_CPU_INTR_FROM_CPU_0);
#else /* MCU_ESP32 */
critical_enter();
ets_soft_int_type = ETS_SOFT_INT_YIELD;
WSR(BIT(ETS_SOFT_INUM), interrupt);
#else
vPortYield();
#endif
critical_exit();
#endif /* MCU_ESP32 */
}
else {
/* set the context switch flag */
_frxt_setup_switch();
}
#if defined(ENABLE_DEBUG) && defined(DEVELHELP)
if (sched_active_thread) {
DEBUG("%u new task %u %s %u\n", phy_get_mactime(),
DEBUG("%u new task %u %s %u\n", system_get_time(),
sched_active_thread->pid, sched_active_thread->name,
sched_active_thread->sp - sched_active_thread-> stack_start);
}
#endif
/*
* Instruction fetch synchronize: Waits for all previously fetched load,
* store, cache, and special register write instructions that affect
* instruction fetch to be performed before fetching the next instruction.
*/
__asm__("isync");
return;
}
@ -265,7 +328,7 @@ void thread_print_stack(void)
return;
}
#if defined(DEVELHELP)
#ifdef DEVELHELP
extern uint8_t port_IntStack;
extern uint8_t port_IntStackTop;
@ -273,9 +336,14 @@ extern uint8_t port_IntStackTop;
void thread_isr_stack_init(void)
{
/* code from thread.c, please see the copyright notice there */
#ifdef MCU_ESP32
#define sp (&port_IntStackTop)
#else /* MCU_ESP32 */
register uint32_t *sp __asm__ ("a1");
#endif /* MCU_ESP32 */
/* assign each int of the stack the value of it's address */
uintptr_t *stackmax = (uintptr_t *)&port_IntStackTop;
uintptr_t *stackmax = (uintptr_t *)sp;
uintptr_t *stackp = (uintptr_t *)&port_IntStack;
while (stackp < stackmax) {
@ -314,10 +382,71 @@ void thread_isr_stack_init(void) {}
#endif /* DEVELHELP */
#ifndef __XTENSA_CALL0_ABI__
static bool _initial_exit = true;
#endif /* __XTENSA_CALL0_ABI__ */
NORETURN void cpu_switch_context_exit(void)
{
/* Switch context to the highest priority ready task without context save */
_frxt_dispatch();
DEBUG("%s\n", __func__);
/* Switch context to the highest priority ready task without context save */
#ifdef __XTENSA_CALL0_ABI__
_frxt_dispatch();
#else /* __XTENSA_CALL0_ABI__ */
if (_initial_exit) {
_initial_exit = false;
__asm__ volatile ("call0 _frxt_dispatch");
}
else {
task_exit();
}
#endif /* __XTENSA_CALL0_ABI__ */
UNREACHABLE();
}
#ifndef __XTENSA_CALL0_ABI__
/**
* The function is used on task exit to switch to the context to the next
* running task. It realizes only the second half of a complete context by
* simulating the exit from an interrupt handling where a context switch is
* forced. The old context is not saved here since it is no longer needed.
*/
NORETURN void task_exit(void)
{
DEBUG("sched_task_exit: ending thread %" PRIkernel_pid "...\n",
sched_active_thread ? sched_active_thread->pid : KERNEL_PID_UNDEF);
(void) irq_disable();
/* remove old task from scheduling if it is not already done */
if (sched_active_thread) {
sched_threads[sched_active_pid] = NULL;
sched_num_threads--;
sched_set_status((thread_t *)sched_active_thread, STATUS_STOPPED);
sched_active_thread = NULL;
}
/* determine the new running task */
sched_run();
/* set the context switch flag (indicates that context has to be switched
is switch on exit from interrupt in _frxt_int_exit */
_frxt_setup_switch();
/* set interrupt nesting level to the right value */
irq_interrupt_nesting++;
/* reset windowed registers */
__asm__ volatile ("movi a2, 0\n"
"wsr a2, windowstart\n"
"wsr a2, windowbase\n"
"rsync\n");
/* exit from simulated interrupt to switch to the new context */
__asm__ volatile ("call0 _frxt_int_exit");
/* should not be executed */
UNREACHABLE();
}
#endif /* __XTENSA_CALL0_ABI__ */

View File

@ -1,5 +1,5 @@
/*
* Copyright (C) 2018 Gunar Schorcht
* Copyright (C) 2019 Gunar Schorcht
*
* This file is subject to the terms and conditions of the GNU Lesser
* General Public License v2.1. See the file LICENSE in the top level
@ -19,11 +19,16 @@
*/
#include <stdio.h>
#include <inttypes.h>
#include <malloc.h>
#ifdef MCU_ESP8266
#include <inttypes.h>
#include "sdk/sdk.h"
#else
#include "rom/ets_sys.h"
#endif
#include "esp/common_macros.h"
#include "sdk/ets.h"
#include "tools.h"
extern void malloc_stats (void);
@ -58,19 +63,18 @@ void esp_hexdump (const void* addr, uint32_t num, char width, uint8_t per_line)
while (count < num) {
if (count % per_line == 0) {
printf ("%08x: ", (uint32_t)((uint8_t*)addr+count*size));
ets_printf ("%08" PRIx32 ": ", (uint32_t)((uint8_t*)addr+count*size));
}
switch (width) {
case 'b': printf("%02" PRIx8 " ", addr8[count++]); break;
case 'h': printf("%04" PRIx16 " ", addr16[count++]); break;
case 'w': printf("%08" PRIx32 " ", addr32[count++]); break;
case 'g': printf("%016" PRIx64 " ", addr64[count++]); break;
default : printf("."); count++; break;
case 'b': ets_printf("%02" PRIx8 " ", addr8[count++]); break;
case 'h': ets_printf("%04" PRIx16 " ", addr16[count++]); break;
case 'w': ets_printf("%08" PRIx32 " ", addr32[count++]); break;
case 'g': ets_printf("%016" PRIx64 " ", addr64[count++]); break;
default : ets_printf("."); count++; break;
}
if (count % per_line == 0) {
printf ("\n");
ets_printf ("\n");
}
}
printf ("\n");
ets_printf ("\n");
}