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:
parent
074369fbb5
commit
ddc91df4ca
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
1033
cpu/esp8266/doc.txt
1033
cpu/esp8266/doc.txt
File diff suppressed because it is too large
Load Diff
@ -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
|
||||
|
@ -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
@ -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;
|
||||
|
||||
|
@ -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
103
cpu/esp8266/esp_events.c
Normal 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
|
||||
}
|
@ -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) { };
|
||||
}
|
||||
|
@ -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;
|
||||
|
@ -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 */
|
@ -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
|
||||
|
@ -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
|
||||
|
130
cpu/esp8266/include/esp_common.h
Normal file
130
cpu/esp8266/include/esp_common.h
Normal 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 */
|
150
cpu/esp8266/include/esp_common_log.h
Normal file
150
cpu/esp8266/include/esp_common_log.h
Normal 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 */
|
@ -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
|
||||
|
142
cpu/esp8266/include/gpio_arch.h
Normal file
142
cpu/esp8266/include/gpio_arch.h
Normal 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 */
|
@ -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
|
||||
|
60
cpu/esp8266/include/log_module.h
Normal file
60
cpu/esp8266/include/log_module.h
Normal 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 */
|
@ -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
|
||||
|
86
cpu/esp8266/include/sdk_conf.h
Normal file
86
cpu/esp8266/include/sdk_conf.h
Normal 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
748
cpu/esp8266/include/stdio.h
Normal 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 */
|
337
cpu/esp8266/include/sys/types.h
Normal file
337
cpu/esp8266/include/sys/types.h
Normal 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 */
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
}
|
||||
|
14
cpu/esp8266/ld/esp8266.peripherals.ld
Normal file
14
cpu/esp8266/ld/esp8266.peripherals.ld
Normal 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 );
|
@ -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
|
||||
|
60
cpu/esp8266/ld/esp8266.rom.ld
Normal file
60
cpu/esp8266/ld/esp8266.rom.ld
Normal 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;
|
@ -1,3 +1,3 @@
|
||||
MODULE = periph
|
||||
|
||||
include $(RIOTBASE)/Makefile.base
|
||||
include $(RIOTMAKE)/periph.mk
|
||||
|
@ -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");
|
||||
}
|
||||
|
@ -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 */
|
||||
|
@ -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)]];
|
||||
}
|
||||
|
@ -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++) {
|
||||
|
@ -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 */
|
||||
|
@ -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)
|
||||
|
@ -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 */
|
||||
|
@ -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)
|
||||
{
|
||||
|
@ -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 */
|
||||
|
@ -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 */
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -1,3 +1,3 @@
|
||||
MODULE=sdk
|
||||
MODULE=esp_sdk
|
||||
|
||||
include $(RIOTBASE)/Makefile.base
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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);
|
||||
|
@ -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
|
||||
|
@ -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
56
cpu/esp8266/sdk/system.c
Normal 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
60
cpu/esp8266/sdk/system.h
Normal 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 */
|
@ -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 */
|
@ -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 */
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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__ */
|
||||
|
@ -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");
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user