Merge branch 'master' into open-libmain
Conflicts: core/include/esp/rtc_regs.h include/espressif/spi_flash.h
This commit is contained in:
commit
769ca0d8f8
89 changed files with 4766 additions and 634 deletions
23
.travis.yml
23
.travis.yml
|
@ -2,17 +2,16 @@ language: c
|
|||
sudo: false
|
||||
env:
|
||||
# Target commit for https://github.com/pfalcon/esp-open-sdk/
|
||||
OPENSDK_COMMIT=b44afa47
|
||||
OPENSDK_COMMIT=cd1d336
|
||||
CROSS_ROOT="${HOME}/toolchain-${OPENSDK_COMMIT}"
|
||||
CROSS_BINDIR="${CROSS_ROOT}/bin"
|
||||
ESPTOOL2_COMMIT=92530bb8
|
||||
ESPTOOL2_BINDIR="${HOME}/esptool2-${ESPTOOL2_COMMIT}"
|
||||
PATH=${PATH}:${CROSS_BINDIR}:${ESPTOOL2_BINDIR}
|
||||
ESPTOOL2_COMMIT=ec0e2c7
|
||||
ESPTOOL2_DIR="${HOME}/esptool2-${ESPTOOL2_COMMIT}"
|
||||
PATH=${PATH}:${CROSS_BINDIR}:${ESPTOOL2_DIR}
|
||||
cache:
|
||||
directories:
|
||||
- ${CROSS_ROOT}
|
||||
- ${HOME}/.ccache
|
||||
- ${ESPTOOL2_BINDIR}
|
||||
- ${ESPTOOL2_DIR}
|
||||
addons:
|
||||
apt:
|
||||
packages:
|
||||
|
@ -49,14 +48,14 @@ before_install:
|
|||
- ${HAS_TC} || sed -i "s/2.69/2.68/" lx106-hal/configure.ac # this is a nasty hack as Ubuntu Precise only has autoconf 2.68 not 2.69...
|
||||
- ${HAS_TC} || sed -r -i 's%TOOLCHAIN ?=.*%TOOLCHAIN=${CROSS_ROOT}%' Makefile
|
||||
- ${HAS_TC} || make STANDALONE=n
|
||||
- export HAS_ET2="test -f ${ESPTOOL2_BINDIR}/esptool2"
|
||||
- ${HAS_ET2} || git clone https://github.com/raburton/esp8266 ${HOME}/raburton
|
||||
- ${HAS_ET2} || make -C ${HOME}/raburton/esptool2
|
||||
- ${HAS_ET2} || mkdir -p ${ESPTOOL2_BINDIR}
|
||||
- ${HAS_ET2} || cp -a ${HOME}/raburton/esptool2/esptool2 ${ESPTOOL2_BINDIR}/
|
||||
- export HAS_ET2="test -f ${ESPTOOL2_DIR}/esptool2"
|
||||
- ${HAS_ET2} || git clone https://github.com/raburton/esptool2 ${ESPTOOL2_DIR}
|
||||
- ${HAS_ET2} || cd ${ESPTOOL2_DIR}
|
||||
- ${HAS_ET2} || git reset --hard ${ESPTOOL2_COMMIT}
|
||||
- ${HAS_ET2} || make
|
||||
|
||||
script:
|
||||
- cd ${TRAVIS_BUILD_DIR}
|
||||
# Remove ssid_config requirement for examples
|
||||
- sed -i "s%#warning%//#warning%" include/ssid_config.h
|
||||
- make -C examples/ build-examples CROSS="ccache xtensa-lx106-elf-"
|
||||
- make -C examples/ build-examples CROSS="ccache xtensa-lx106-elf-" V=1
|
||||
|
|
10
README.md
10
README.md
|
@ -2,7 +2,7 @@
|
|||
|
||||
A community developed open source [FreeRTOS](http://www.freertos.org/)-based framework for ESP8266 WiFi-enabled microcontrollers. Intended for use in both commercial and open source projects.
|
||||
|
||||
Originally based on, but substantially different from, the [Espressif IOT RTOS SDK](https://github.com/espressif/esp_iot_rtos_sdk).
|
||||
Originally based on, but substantially different from, the [Espressif IOT RTOS SDK](https://github.com/espressif/ESP8266_RTOS_SDK).
|
||||
|
||||
## Resources
|
||||
|
||||
|
@ -12,13 +12,13 @@ Email discussion list: https://groups.google.com/d/forum/esp-open-rtos
|
|||
|
||||
IRC channel: #esp-open-rtos on Freenode ([Web Chat Link](http://webchat.freenode.net/?channels=%23esp-open-rtos&uio=d4)).
|
||||
|
||||
Github issues list/bugtracker: http://github.com/superhouse/esp-open-rtos/issues
|
||||
Github issues list/bugtracker: https://github.com/superhouse/esp-open-rtos/issues
|
||||
|
||||
Please note that this project is released with a [Contributor Code of Conduct](https://github.com/SuperHouse/esp-open-rtos/blob/master/code_of_conduct.md). By participating in this project you agree to abide by its terms.
|
||||
|
||||
## Quick Start
|
||||
|
||||
* Install [esp-open-sdk](https://github.com/pfalcon/esp-open-sdk/), build it with `make STANDALONE=n`, then edit your PATH and add the generated toolchain `bin` directory. (Despite the similar name esp-open-sdk has different maintainers - but we think it's fantastic!)
|
||||
* Install [esp-open-sdk](https://github.com/pfalcon/esp-open-sdk/), build it with `make STANDALONE=n`, then edit your PATH and add the generated toolchain `bin` directory. The path will be something like `/path/to/esp-open-sdk/xtensa-lx106-elf/bin`. (Despite the similar name esp-open-sdk has different maintainers - but we think it's fantastic!)
|
||||
|
||||
(Other toolchains may also work, as long as a gcc cross-compiler is available on the PATH and libhal (and libhal headers) are compiled and available to gcc. The proprietary Tensilica "xcc" compiler will probably not work.)
|
||||
|
||||
|
@ -79,7 +79,7 @@ Current status is alpha quality, actively developed. AP STATION mode (ie wifi cl
|
|||
|
||||
## Open Source Components
|
||||
|
||||
* [FreeRTOS](http://freertos.org) V7.5.2
|
||||
* [FreeRTOS](http://www.freertos.org/) V7.5.2
|
||||
* [lwIP](http://lwip.wikia.com/wiki/LwIP_Wiki) v1.4.1, modified via the [esp-lwip project](https://github.com/kadamski/esp-lwip) by @kadamski.
|
||||
* [newlib](https://github.com/projectgus/newlib-xtensa) v2.2.0, with patches for xtensa support and locking stubs for thread-safe operation on FreeRTOS.
|
||||
|
||||
|
@ -126,7 +126,7 @@ If you are contributing code, *please ensure that it can be licensed under the B
|
|||
|
||||
* Code from Espressif IoT SDK cannot be merged, as it is provided under either the "Espressif General Public License" or the "Espressif MIT License", which are not compatible with the BSD license.
|
||||
|
||||
* Recent releases of the Espressif IoT RTOS SDK cannot be merged, as they changed from MIT License to the "Espressif MIT License" which is not BSD compatible. The Espressif binaries used in esp-open-rtos were taken from [revision ec75c85, as this was the last MIT Licensed revision](https://github.com/espressif/esp_iot_rtos_sdk/commit/43585fa74550054076bdf4bfe185e808ad0da83e).
|
||||
* Recent releases of the Espressif IoT RTOS SDK cannot be merged, as they changed from MIT License to the "Espressif MIT License" which is not BSD compatible. The Espressif binaries used in esp-open-rtos were taken from [revision ec75c85, as this was the last MIT Licensed revision](https://github.com/espressif/ESP8266_RTOS_SDK/commit/43585fa74550054076bdf4bfe185e808ad0da83e).
|
||||
|
||||
For code submissions based on reverse engineered binary functionality, please either reverse engineer functionality from MIT Licensed Espressif releases or make sure that the reverse engineered code does not directly copy the code structure of the binaries - it cannot be a "derivative work" of an incompatible binary.
|
||||
|
||||
|
|
88
common.mk
88
common.mk
|
@ -40,7 +40,7 @@ FLASH_SPEED ?= 40
|
|||
# Output directories to store intermediate compiled files
|
||||
# relative to the program directory
|
||||
BUILD_DIR ?= $(PROGRAM_DIR)build/
|
||||
FW_BASE ?= $(PROGRAM_DIR)firmware/
|
||||
FIRMWARE_DIR ?= $(PROGRAM_DIR)firmware/
|
||||
|
||||
# esptool.py from https://github.com/themadinventor/esptool
|
||||
ESPTOOL ?= esptool.py
|
||||
|
@ -48,6 +48,13 @@ ESPTOOL ?= esptool.py
|
|||
ESPPORT ?= /dev/ttyUSB0
|
||||
ESPBAUD ?= 115200
|
||||
|
||||
# set this to 0 if you don't need floating point support in printf/scanf
|
||||
# this will save approx 14.5KB flash space and 448 bytes of statically allocated
|
||||
# data RAM
|
||||
#
|
||||
# NB: Setting the value to 0 requires a recent esptool.py (Feb 2016 / commit ebf02c9)
|
||||
PRINTF_SCANF_FLOAT_SUPPORT ?= 1
|
||||
|
||||
# Set OTA to 1 to build an image that supports rBoot OTA bootloader
|
||||
#
|
||||
# Currently only works with 16mbit or more flash sizes, with 8mbit
|
||||
|
@ -100,13 +107,16 @@ ENTRY_SYMBOL ?= call_user_start
|
|||
SPLIT_SECTIONS ?= 1
|
||||
|
||||
# Common flags for both C & C++_
|
||||
C_CXX_FLAGS = -Wall -Werror -Wl,-EL -nostdlib -mlongcalls -mtext-section-literals $(CPPFLAGS)
|
||||
C_CXX_FLAGS ?= -Wall -Werror -Wl,-EL -nostdlib $(EXTRA_C_CXX_FLAGS)
|
||||
# Flags for C only
|
||||
CFLAGS = $(C_CXX_FLAGS) -std=gnu99
|
||||
CFLAGS ?= $(C_CXX_FLAGS) -std=gnu99 $(EXTRA_CFLAGS)
|
||||
# Flags for C++ only
|
||||
CXXFLAGS = $(C_CXX_FLAGS) -fno-exceptions -fno-rtti
|
||||
CXXFLAGS ?= $(C_CXX_FLAGS) -fno-exceptions -fno-rtti $(EXTRA_CXXFLAGS)
|
||||
|
||||
LDFLAGS = -nostdlib -Wl,--no-check-sections -Wl,-L$(BUILD_DIR)sdklib -Wl,-L$(ROOT)lib -u $(ENTRY_SYMBOL) -Wl,-static -Wl,-Map=build/${PROGRAM}.map $(EXTRA_LDFLAGS)
|
||||
# these aren't technically preprocesor args, but used by all 3 of C, C++, assembler
|
||||
CPPFLAGS += -mlongcalls -mtext-section-literals
|
||||
|
||||
LDFLAGS = -nostdlib -Wl,--no-check-sections -L$(BUILD_DIR)sdklib -L$(ROOT)lib -u $(ENTRY_SYMBOL) -Wl,-static -Wl,-Map=$(BUILD_DIR)$(PROGRAM).map $(EXTRA_LDFLAGS)
|
||||
|
||||
ifeq ($(SPLIT_SECTIONS),1)
|
||||
C_CXX_FLAGS += -ffunction-sections -fdata-sections
|
||||
|
@ -128,11 +138,18 @@ else
|
|||
LDFLAGS += -g -O2
|
||||
endif
|
||||
|
||||
GITSHORTREV=\"$(shell cd $(ROOT); git rev-parse --short -q HEAD)\"
|
||||
CPPFLAGS += -DGITSHORTREV=$(GITSHORTREV) -DFLASH_SIZE=$(FLASH_SIZE)
|
||||
GITSHORTREV=\"$(shell cd $(ROOT); git rev-parse --short -q HEAD 2> /dev/null)\"
|
||||
ifeq ($(GITSHORTREV),\"\")
|
||||
GITSHORTREV="\"(nogit)\"" # (same length as a short git hash)
|
||||
endif
|
||||
CPPFLAGS += -DGITSHORTREV=$(GITSHORTREV)
|
||||
|
||||
# Linker scripts, all found in $(ROOT)/ld
|
||||
LINKER_SCRIPTS = eagle.app.v6.ld eagle.rom.addr.v6.ld
|
||||
ifeq ($(OTA),0)
|
||||
LINKER_SCRIPTS = $(ROOT)ld/nonota.ld
|
||||
else
|
||||
LINKER_SCRIPTS = $(ROOT)ld/ota.ld
|
||||
endif
|
||||
LINKER_SCRIPTS += $(ROOT)ld/common.ld $(ROOT)ld/rom.ld
|
||||
|
||||
####
|
||||
#### no user configurable options below here
|
||||
|
@ -152,30 +169,22 @@ lc = $(subst A,a,$(subst B,b,$(subst C,c,$(subst D,d,$(subst E,e,$(subst F,f,$(s
|
|||
# assume the program dir is the directory the top-level makefile was run in
|
||||
PROGRAM_DIR := $(dir $(firstword $(MAKEFILE_LIST)))
|
||||
|
||||
# linker scripts get run through the C preprocessor
|
||||
ifeq ($(OTA),1)
|
||||
LD_DIR = $(BUILD_DIR)ld-$(FLASH_SIZE)-ota/
|
||||
else
|
||||
LD_DIR = $(BUILD_DIR)ld-$(FLASH_SIZE)/
|
||||
endif
|
||||
LINKER_SCRIPTS_PROCESSED = $(addprefix $(LD_DIR),$(LINKER_SCRIPTS))
|
||||
|
||||
# derive various parts of compiler/linker arguments
|
||||
SDK_LIB_ARGS = $(addprefix -l,$(SDK_LIBS))
|
||||
LIB_ARGS = $(addprefix -l,$(LIBS))
|
||||
PROGRAM_OUT = $(BUILD_DIR)$(PROGRAM).out
|
||||
LDFLAGS += $(addprefix -T,$(LINKER_SCRIPTS_PROCESSED))
|
||||
LDFLAGS += $(addprefix -T,$(LINKER_SCRIPTS))
|
||||
|
||||
ifeq ($(OTA),0)
|
||||
# for non-OTA, we create two different files for uploading into the flash
|
||||
# these are the names and options to generate them
|
||||
FW_ADDR_1 = 0x00000
|
||||
FW_ADDR_2 = 0x20000
|
||||
FW_FILE_1 = $(addprefix $(FW_BASE),$(FW_ADDR_1).bin)
|
||||
FW_FILE_2 = $(addprefix $(FW_BASE),$(FW_ADDR_2).bin)
|
||||
FW_FILE_1 = $(addprefix $(FIRMWARE_DIR),$(FW_ADDR_1).bin)
|
||||
FW_FILE_2 = $(addprefix $(FIRMWARE_DIR),$(FW_ADDR_2).bin)
|
||||
else
|
||||
# for OTA, it's a single monolithic image
|
||||
FW_FILE = $(addprefix $(FW_BASE),$(PROGRAM).bin)
|
||||
FW_FILE = $(addprefix $(FIRMWARE_DIR),$(PROGRAM).bin)
|
||||
endif
|
||||
|
||||
# firmware tool arguments
|
||||
|
@ -200,6 +209,9 @@ INC_DIRS = $(PROGRAM_DIR) $(PROGRAM_DIR)include $(ROOT)include
|
|||
ifeq ($(OWN_LIBC),1)
|
||||
INC_DIRS += $(ROOT)libc/xtensa-lx106-elf/include
|
||||
LDFLAGS += -L$(ROOT)libc/xtensa-lx106-elf/lib
|
||||
ifeq ($(PRINTF_SCANF_FLOAT_SUPPORT),1)
|
||||
LDFLAGS += -u _printf_float -u _scanf_float
|
||||
endif
|
||||
endif
|
||||
|
||||
ifeq ("$(V)","1")
|
||||
|
@ -252,29 +264,29 @@ $(1)_OBJ_FILES = $$(patsubst $$($(1)_REAL_ROOT)%.S,$$($(1)_OBJ_DIR)%.o,$$($(1)_O
|
|||
$(1)_MAKEFILE ?= $(lastword $(MAKEFILE_LIST))
|
||||
|
||||
### determine compiler arguments ###
|
||||
$(1)_CPPFLAGS ?= $(CPPFLAGS)
|
||||
$(1)_CFLAGS ?= $(CFLAGS)
|
||||
$(1)_CXXFLAGS ?= $(CXXFLAGS)
|
||||
$(1)_CC_ARGS = $(Q) $(CC) $$(addprefix -I,$$(INC_DIRS)) $$(addprefix -I,$$($(1)_INC_DIR)) $$($(1)_CFLAGS)
|
||||
$(1)_CXX_ARGS = $(Q) $(C++) $$(addprefix -I,$$(INC_DIRS)) $$(addprefix -I,$$($(1)_INC_DIR)) $$($(1)_CXXFLAGS)
|
||||
$(1)_CC_BASE = $(Q) $(CC) $$(addprefix -I,$$(INC_DIRS)) $$(addprefix -I,$$($(1)_INC_DIR)) $$($(1)_CPPFLAGS)
|
||||
$(1)_AR = $(call lc,$(BUILD_DIR)$(1).a)
|
||||
|
||||
$$($(1)_OBJ_DIR)%.o: $$($(1)_REAL_ROOT)%.c $$($(1)_MAKEFILE) $(wildcard $(ROOT)*.mk) | $$($(1)_SRC_DIR)
|
||||
$(vecho) "CC $$<"
|
||||
$(Q) mkdir -p $$(dir $$@)
|
||||
$$($(1)_CC_ARGS) -c $$< -o $$@
|
||||
$$($(1)_CC_ARGS) -MM -MT $$@ -MF $$(@:.o=.d) $$<
|
||||
$$($(1)_CC_BASE) $$($(1)_CFLAGS) -c $$< -o $$@
|
||||
$$($(1)_CC_BASE) $$($(1)_CFLAGS) -MM -MT $$@ -MF $$(@:.o=.d) $$<
|
||||
|
||||
$$($(1)_OBJ_DIR)%.o: $$($(1)_REAL_ROOT)%.cpp $$($(1)_MAKEFILE) $(wildcard $(ROOT)*.mk) | $$($(1)_SRC_DIR)
|
||||
$(vecho) "C++ $$<"
|
||||
$(Q) mkdir -p $$(dir $$@)
|
||||
$$($(1)_CXX_ARGS) -c $$< -o $$@
|
||||
$$($(1)_CXX_ARGS) -MM -MT $$@ -MF $$(@:.o=.d) $$<
|
||||
$$($(1)_CC_BASE) $$($(1)_CXXFLAGS) -c $$< -o $$@
|
||||
$$($(1)_CC_BASE) $$($(1)_CXXFLAGS) -MM -MT $$@ -MF $$(@:.o=.d) $$<
|
||||
|
||||
$$($(1)_OBJ_DIR)%.o: $$($(1)_REAL_ROOT)%.S $$($(1)_MAKEFILE) $(wildcard $(ROOT)*.mk) | $$($(1)_SRC_DIR)
|
||||
$(vecho) "AS $$<"
|
||||
$(Q) mkdir -p $$(dir $$@)
|
||||
$$($(1)_CC_ARGS) -c $$< -o $$@
|
||||
$$($(1)_CC_ARGS) -MM -MT $$@ -MF $$(@:.o=.d) $$<
|
||||
$$($(1)_CC_BASE) -c $$< -o $$@
|
||||
$$($(1)_CC_BASE) -MM -MT $$@ -MF $$(@:.o=.d) $$<
|
||||
|
||||
# the component is shown to depend on both obj and source files so we get a meaningful error message
|
||||
# for missing explicitly named source files
|
||||
|
@ -294,7 +306,7 @@ endef
|
|||
# - prefix all defined symbols with 'sdk_'
|
||||
# - weaken all global symbols so they can be overriden from the open SDK side
|
||||
#
|
||||
# SDK binary libraries are preprocessed into build/sdklib
|
||||
# SDK binary libraries are preprocessed into $(BUILD_DIR)/sdklib
|
||||
SDK_PROCESSED_LIBS = $(addsuffix .a,$(addprefix $(BUILD_DIR)sdklib/lib,$(SDK_LIBS)))
|
||||
|
||||
# Make rules for preprocessing each SDK library
|
||||
|
@ -335,23 +347,19 @@ $(foreach component,$(COMPONENTS), \
|
|||
) \
|
||||
)
|
||||
|
||||
## Run linker scripts via C preprocessor to evaluate macros
|
||||
$(LD_DIR)%.ld: $(ROOT)ld/%.ld | $(LD_DIR)
|
||||
$(Q) $(CPP) $(CPPFLAGS) -E -C -P $< > $@
|
||||
|
||||
# final linking step to produce .elf
|
||||
$(PROGRAM_OUT): $(COMPONENT_ARS) $(SDK_PROCESSED_LIBS) $(LINKER_SCRIPTS_PROCESSED)
|
||||
$(PROGRAM_OUT): $(COMPONENT_ARS) $(SDK_PROCESSED_LIBS) $(LINKER_SCRIPTS)
|
||||
$(vecho) "LD $@"
|
||||
$(Q) $(LD) $(LDFLAGS) -Wl,--start-group $(COMPONENT_ARS) $(LIB_ARGS) $(SDK_LIB_ARGS) -Wl,--end-group -o $@
|
||||
|
||||
$(BUILD_DIR) $(FW_BASE) $(BUILD_DIR)sdklib $(LD_DIR):
|
||||
$(BUILD_DIR) $(FIRMWARE_DIR) $(BUILD_DIR)sdklib:
|
||||
$(Q) mkdir -p $@
|
||||
|
||||
$(FW_FILE_1) $(FW_FILE_2): $(PROGRAM_OUT) $(FW_BASE)
|
||||
$(FW_FILE_1) $(FW_FILE_2): $(PROGRAM_OUT) $(FIRMWARE_DIR)
|
||||
$(vecho) "FW $@"
|
||||
$(Q) $(ESPTOOL) elf2image $(ESPTOOL_ARGS) $< -o $(FW_BASE)
|
||||
$(Q) $(ESPTOOL) elf2image $(ESPTOOL_ARGS) $< -o $(FIRMWARE_DIR)
|
||||
|
||||
$(FW_FILE): $(PROGRAM_OUT) $(FW_BASE)
|
||||
$(FW_FILE): $(PROGRAM_OUT) $(FIRMWARE_DIR)
|
||||
$(Q) $(IMGTOOL) $(IMGTOOL_ARGS) -bin -boot2 $(PROGRAM_OUT) $(FW_FILE) .text .data .rodata
|
||||
|
||||
ifeq ($(OTA),0)
|
||||
|
@ -377,7 +385,7 @@ rebuild:
|
|||
|
||||
clean:
|
||||
$(Q) rm -rf $(BUILD_DIR)
|
||||
$(Q) rm -rf $(FW_BASE)
|
||||
$(Q) rm -rf $(FIRMWARE_DIR)
|
||||
|
||||
# prevent "intermediate" files from being deleted
|
||||
.SECONDARY:
|
||||
|
|
|
@ -250,7 +250,7 @@ void IRAM sdk_user_start(void) {
|
|||
|
||||
// .text+0x3a8
|
||||
void IRAM vApplicationStackOverflowHook(xTaskHandle task, char *task_name) {
|
||||
printf("\"%s\"(stack_size = %lu) overflow the heap_size.\n", task_name, uxTaskGetStackHighWaterMark(task));
|
||||
printf("Task stack overflow (high water mark=%lu name=\"%s\")\n", uxTaskGetStackHighWaterMark(task), task_name);
|
||||
}
|
||||
|
||||
// .text+0x3d8
|
||||
|
|
41
core/esp_gpio.c
Normal file
41
core/esp_gpio.c
Normal file
|
@ -0,0 +1,41 @@
|
|||
/* GPIO management functions
|
||||
*
|
||||
* Part of esp-open-rtos
|
||||
* Copyright (C) 2015 Angus Gratton
|
||||
* BSD Licensed as described in the file LICENSE
|
||||
*/
|
||||
#include <esp/gpio.h>
|
||||
|
||||
void gpio_enable(const uint8_t gpio_num, const gpio_direction_t direction)
|
||||
{
|
||||
switch (direction) {
|
||||
case GPIO_INPUT:
|
||||
GPIO.ENABLE_OUT_CLEAR = BIT(gpio_num);
|
||||
iomux_set_gpio_function(gpio_num, false);
|
||||
break;
|
||||
case GPIO_OUTPUT:
|
||||
GPIO.CONF[gpio_num] &= ~GPIO_CONF_OPEN_DRAIN;
|
||||
GPIO.ENABLE_OUT_SET = BIT(gpio_num);
|
||||
iomux_set_gpio_function(gpio_num, true);
|
||||
break;
|
||||
case GPIO_OUT_OPEN_DRAIN:
|
||||
GPIO.CONF[gpio_num] |= GPIO_CONF_OPEN_DRAIN;
|
||||
GPIO.ENABLE_OUT_SET = BIT(gpio_num);
|
||||
iomux_set_gpio_function(gpio_num, true);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void gpio_set_pullup(uint8_t gpio_num, bool enabled, bool enabled_during_sleep)
|
||||
{
|
||||
uint32_t flags = 0;
|
||||
|
||||
if (enabled) {
|
||||
flags |= IOMUX_PIN_PULLUP;
|
||||
}
|
||||
if (enabled_during_sleep) {
|
||||
flags |= IOMUX_PIN_PULLUP_SLEEP;
|
||||
}
|
||||
iomux_set_pullup_flags(gpio_to_iomux(gpio_num), flags);
|
||||
}
|
||||
|
|
@ -7,14 +7,15 @@
|
|||
#include "esp/iomux.h"
|
||||
#include "common_macros.h"
|
||||
|
||||
/* These are non-static versions of the GPIO mapping tables in
|
||||
iomux.h, so if they need to be linked only one copy is linked for
|
||||
the entire program.
|
||||
const static IRAM_DATA uint32_t IOMUX_TO_GPIO[] = { 12, 13, 14, 15, 3, 1, 6, 7, 8, 9, 10, 11, 0, 2, 4, 5 };
|
||||
const static IRAM_DATA uint32_t GPIO_TO_IOMUX[] = { 12, 5, 13, 4, 14, 15, 6, 7, 8, 9, 10, 11, 0, 1, 2, 3 };
|
||||
|
||||
These are only ever linked in if the arguments to gpio_to_ionum
|
||||
or ionum_to_gpio are not known at compile time.
|
||||
uint8_t IRAM gpio_to_iomux(const uint8_t gpio_number)
|
||||
{
|
||||
return GPIO_TO_IOMUX[gpio_number];
|
||||
}
|
||||
|
||||
Arrays are declared as 32-bit integers in IROM to save RAM.
|
||||
*/
|
||||
const IROM uint32_t GPIO_TO_IOMUX_MAP[] = _GPIO_TO_IOMUX;
|
||||
const IROM uint32_t IOMUX_TO_GPIO_MAP[] = _IOMUX_TO_GPIO;
|
||||
uint8_t IRAM iomux_to_gpio(const uint8_t iomux_number)
|
||||
{
|
||||
return IOMUX_TO_GPIO[iomux_number];
|
||||
}
|
||||
|
|
251
core/esp_spi.c
Normal file
251
core/esp_spi.c
Normal file
|
@ -0,0 +1,251 @@
|
|||
/*
|
||||
* ESP hardware SPI master driver
|
||||
*
|
||||
* Part of esp-open-rtos
|
||||
* Copyright (c) Ruslan V. Uss, 2016
|
||||
* BSD Licensed as described in the file LICENSE
|
||||
*/
|
||||
#include "esp/spi.h"
|
||||
|
||||
#include "esp/iomux.h"
|
||||
#include "esp/gpio.h"
|
||||
#include <string.h>
|
||||
|
||||
#define _SPI0_SCK_GPIO 6
|
||||
#define _SPI0_MISO_GPIO 7
|
||||
#define _SPI0_MOSI_GPIO 8
|
||||
#define _SPI0_HD_GPIO 9
|
||||
#define _SPI0_WP_GPIO 10
|
||||
#define _SPI0_CS0_GPIO 11
|
||||
|
||||
#define _SPI1_MISO_GPIO 12
|
||||
#define _SPI1_MOSI_GPIO 13
|
||||
#define _SPI1_SCK_GPIO 14
|
||||
#define _SPI1_CS0_GPIO 15
|
||||
|
||||
#define _SPI0_FUNC 1
|
||||
#define _SPI1_FUNC 2
|
||||
|
||||
#define _SPI_BUF_SIZE 64
|
||||
|
||||
static bool _minimal_pins[2] = {false, false};
|
||||
|
||||
inline static void _set_pin_function(uint8_t pin, uint32_t function)
|
||||
{
|
||||
iomux_set_function(gpio_to_iomux(pin), function);
|
||||
}
|
||||
|
||||
bool spi_init(uint8_t bus, spi_mode_t mode, uint32_t freq_divider, bool msb, spi_endianness_t endianness, bool minimal_pins)
|
||||
{
|
||||
switch (bus)
|
||||
{
|
||||
case 0:
|
||||
_set_pin_function(_SPI0_MISO_GPIO, _SPI0_FUNC);
|
||||
_set_pin_function(_SPI0_MOSI_GPIO, _SPI0_FUNC);
|
||||
_set_pin_function(_SPI0_SCK_GPIO, _SPI0_FUNC);
|
||||
if (!minimal_pins)
|
||||
{
|
||||
_set_pin_function(_SPI0_HD_GPIO, _SPI0_FUNC);
|
||||
_set_pin_function(_SPI0_WP_GPIO, _SPI0_FUNC);
|
||||
_set_pin_function(_SPI0_CS0_GPIO, _SPI0_FUNC);
|
||||
}
|
||||
break;
|
||||
case 1:
|
||||
_set_pin_function(_SPI1_MISO_GPIO, _SPI1_FUNC);
|
||||
_set_pin_function(_SPI1_MOSI_GPIO, _SPI1_FUNC);
|
||||
_set_pin_function(_SPI1_SCK_GPIO, _SPI1_FUNC);
|
||||
if (!minimal_pins)
|
||||
_set_pin_function(_SPI1_CS0_GPIO, _SPI1_FUNC);
|
||||
break;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
|
||||
_minimal_pins[bus] = minimal_pins;
|
||||
SPI(bus).USER0 = SPI_USER0_MOSI | SPI_USER0_CLOCK_IN_EDGE | SPI_USER0_DUPLEX |
|
||||
(minimal_pins ? 0 : (SPI_USER0_CS_HOLD | SPI_USER0_CS_SETUP));
|
||||
|
||||
spi_set_frequency_div(bus, freq_divider);
|
||||
spi_set_mode(bus, mode);
|
||||
spi_set_msb(bus, msb);
|
||||
spi_set_endianness(bus, endianness);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void spi_get_settings(uint8_t bus, spi_settings_t *s)
|
||||
{
|
||||
s->mode = spi_get_mode(bus);
|
||||
s->freq_divider = spi_get_frequency_div(bus);
|
||||
s->msb = spi_get_msb(bus);
|
||||
s->endianness = spi_get_endianness(bus);
|
||||
s->minimal_pins = _minimal_pins[bus];
|
||||
}
|
||||
|
||||
void spi_set_mode(uint8_t bus, spi_mode_t mode)
|
||||
{
|
||||
bool cpha = (uint8_t)mode & 1;
|
||||
bool cpol = (uint8_t)mode & 2;
|
||||
if (cpol)
|
||||
cpha = !cpha; // CPHA must be inverted when CPOL = 1, I have no idea why
|
||||
|
||||
// CPHA
|
||||
if (cpha)
|
||||
SPI(bus).USER0 |= SPI_USER0_CLOCK_OUT_EDGE;
|
||||
else
|
||||
SPI(bus).USER0 &= ~SPI_USER0_CLOCK_OUT_EDGE;
|
||||
|
||||
// CPOL - see http://bbs.espressif.com/viewtopic.php?t=342#p5384
|
||||
if (cpol)
|
||||
SPI(bus).PIN |= SPI_PIN_IDLE_EDGE;
|
||||
else
|
||||
SPI(bus).PIN &= ~SPI_PIN_IDLE_EDGE;
|
||||
}
|
||||
|
||||
spi_mode_t spi_get_mode(uint8_t bus)
|
||||
{
|
||||
uint8_t cpha = SPI(bus).USER0 & SPI_USER0_CLOCK_OUT_EDGE ? 1 : 0;
|
||||
uint8_t cpol = SPI(bus).PIN & SPI_PIN_IDLE_EDGE ? 2 : 0;
|
||||
|
||||
return (spi_mode_t)(cpol | (cpol ? 1 - cpha : cpha)); // see spi_set_mode
|
||||
}
|
||||
|
||||
void spi_set_msb(uint8_t bus, bool msb)
|
||||
{
|
||||
if (msb)
|
||||
SPI(bus).CTRL0 &= ~(SPI_CTRL0_WR_BIT_ORDER | SPI_CTRL0_RD_BIT_ORDER);
|
||||
else
|
||||
SPI(bus).CTRL0 |= (SPI_CTRL0_WR_BIT_ORDER | SPI_CTRL0_RD_BIT_ORDER);
|
||||
}
|
||||
|
||||
void spi_set_endianness(uint8_t bus, spi_endianness_t endianness)
|
||||
{
|
||||
if (endianness == SPI_BIG_ENDIAN)
|
||||
SPI(bus).USER0 |= (SPI_USER0_WR_BYTE_ORDER | SPI_USER0_RD_BYTE_ORDER);
|
||||
else
|
||||
SPI(bus).USER0 &= ~(SPI_USER0_WR_BYTE_ORDER | SPI_USER0_RD_BYTE_ORDER);
|
||||
}
|
||||
|
||||
void spi_set_frequency_div(uint8_t bus, uint32_t divider)
|
||||
{
|
||||
uint32_t predivider = (divider & 0xffff) - 1;
|
||||
uint32_t count = (divider >> 16) - 1;
|
||||
if (count || predivider)
|
||||
{
|
||||
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, predivider) |
|
||||
VAL2FIELD_M(SPI_CLOCK_COUNT_NUM, count) |
|
||||
VAL2FIELD_M(SPI_CLOCK_COUNT_HIGH, count / 2) |
|
||||
VAL2FIELD_M(SPI_CLOCK_COUNT_LOW, count);
|
||||
}
|
||||
else
|
||||
{
|
||||
IOMUX.CONF |= bus == 0 ? IOMUX_CONF_SPI0_CLOCK_EQU_SYS_CLOCK : IOMUX_CONF_SPI1_CLOCK_EQU_SYS_CLOCK;
|
||||
SPI(bus).CLOCK = SPI_CLOCK_EQU_SYS_CLOCK;
|
||||
}
|
||||
}
|
||||
|
||||
inline static void _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);
|
||||
}
|
||||
|
||||
inline static void _wait(uint8_t bus)
|
||||
{
|
||||
while (SPI(bus).CMD & SPI_CMD_USR)
|
||||
;
|
||||
}
|
||||
|
||||
inline static void _start(uint8_t bus)
|
||||
{
|
||||
SPI(bus).CMD |= SPI_CMD_USR;
|
||||
}
|
||||
|
||||
inline static uint32_t _swap_bytes(uint32_t value)
|
||||
{
|
||||
return (value << 24) | ((value << 8) & 0x00ff0000) | ((value >> 8) & 0x0000ff00) | (value >> 24);
|
||||
}
|
||||
|
||||
inline static uint32_t _swap_words(uint32_t value)
|
||||
{
|
||||
return (value << 16) | (value >> 16);
|
||||
}
|
||||
|
||||
static void _spi_buf_prepare(uint8_t bus, size_t len, spi_endianness_t e, spi_word_size_t word_size)
|
||||
{
|
||||
if (e == SPI_LITTLE_ENDIAN || word_size == SPI_32BIT) return;
|
||||
|
||||
size_t count = word_size == SPI_16BIT ? (len + 1) / 2 : (len + 3) / 4;
|
||||
uint32_t *data = (uint32_t *)&SPI(bus).W0;
|
||||
for (size_t i = 0; i < count; i ++)
|
||||
{
|
||||
data[i] = word_size == SPI_16BIT
|
||||
? _swap_words(data[i])
|
||||
: _swap_bytes(data[i]);
|
||||
}
|
||||
}
|
||||
|
||||
static void _spi_buf_transfer(uint8_t bus, const void *out_data, void *in_data,
|
||||
size_t len, spi_endianness_t e, spi_word_size_t word_size)
|
||||
{
|
||||
_wait(bus);
|
||||
size_t bytes = len * (uint8_t)word_size;
|
||||
_set_size(bus, bytes);
|
||||
memcpy((void *)&SPI(bus).W0, out_data, bytes);
|
||||
_spi_buf_prepare(bus, len, e, word_size);
|
||||
_start(bus);
|
||||
_wait(bus);
|
||||
if (in_data)
|
||||
{
|
||||
_spi_buf_prepare(bus, len, e, word_size);
|
||||
memcpy(in_data, (void *)&SPI(bus).W0, bytes);
|
||||
}
|
||||
}
|
||||
|
||||
uint8_t spi_transfer_8(uint8_t bus, uint8_t data)
|
||||
{
|
||||
uint8_t res;
|
||||
_spi_buf_transfer(bus, &data, &res, 1, spi_get_endianness(bus), SPI_8BIT);
|
||||
return res;
|
||||
}
|
||||
|
||||
uint16_t spi_transfer_16(uint8_t bus, uint16_t data)
|
||||
{
|
||||
uint16_t res;
|
||||
_spi_buf_transfer(bus, &data, &res, 1, spi_get_endianness(bus), SPI_16BIT);
|
||||
return res;
|
||||
}
|
||||
|
||||
uint32_t spi_transfer_32(uint8_t bus, uint32_t data)
|
||||
{
|
||||
uint32_t res;
|
||||
_spi_buf_transfer(bus, &data, &res, 1, spi_get_endianness(bus), SPI_32BIT);
|
||||
return res;
|
||||
}
|
||||
|
||||
size_t spi_transfer(uint8_t bus, const void *out_data, void *in_data, size_t len, spi_word_size_t word_size)
|
||||
{
|
||||
if (!out_data || !len) return 0;
|
||||
|
||||
spi_endianness_t e = spi_get_endianness(bus);
|
||||
uint8_t buf_size = _SPI_BUF_SIZE / (uint8_t)word_size;
|
||||
|
||||
size_t blocks = len / buf_size;
|
||||
for (size_t i = 0; i < blocks; i++)
|
||||
{
|
||||
size_t offset = i * _SPI_BUF_SIZE;
|
||||
_spi_buf_transfer(bus, (const uint8_t *)out_data + offset,
|
||||
in_data ? (uint8_t *)in_data + offset : NULL, buf_size, e, word_size);
|
||||
}
|
||||
|
||||
uint8_t tail = len % buf_size;
|
||||
if (tail)
|
||||
{
|
||||
_spi_buf_transfer(bus, (const uint8_t *)out_data + blocks * _SPI_BUF_SIZE,
|
||||
in_data ? (uint8_t *)in_data + blocks * _SPI_BUF_SIZE : NULL, tail, e, word_size);
|
||||
}
|
||||
|
||||
return len;
|
||||
}
|
139
core/esp_timer.c
139
core/esp_timer.c
|
@ -6,30 +6,143 @@
|
|||
* BSD Licensed as described in the file LICENSE
|
||||
*/
|
||||
#include <esp/timer.h>
|
||||
#include <esp/dport_regs.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
/*
|
||||
* These are the runtime implementations for functions that are linked in if any of
|
||||
* the arguments aren't known at compile time (values are evaluated at
|
||||
* compile time otherwise.)
|
||||
/* Timer divisor number to maximum frequency */
|
||||
#define _FREQ_DIV1 (80*1000*1000)
|
||||
#define _FREQ_DIV16 (5*1000*1000)
|
||||
#define _FREQ_DIV256 312500
|
||||
|
||||
const static uint32_t IROM _TIMER_FREQS[] = { _FREQ_DIV1, _FREQ_DIV16, _FREQ_DIV256 };
|
||||
|
||||
/* Timer divisor index to divisor value */
|
||||
const static uint32_t IROM _TIMER_DIV_VAL[] = { 1, 16, 256 };
|
||||
|
||||
void timer_set_interrupts(const timer_frc_t frc, bool enable)
|
||||
{
|
||||
const uint32_t dp_bit = (frc == FRC1) ? DPORT_INT_ENABLE_FRC1 : DPORT_INT_ENABLE_FRC2;
|
||||
const uint32_t int_mask = BIT((frc == FRC1) ? INUM_TIMER_FRC1 : INUM_TIMER_FRC2);
|
||||
if(enable) {
|
||||
DPORT.INT_ENABLE |= dp_bit;
|
||||
_xt_isr_unmask(int_mask);
|
||||
} else {
|
||||
DPORT.INT_ENABLE &= ~dp_bit;
|
||||
_xt_isr_mask(int_mask);
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t timer_freq_to_count(const timer_frc_t frc, const uint32_t freq, const timer_clkdiv_t div)
|
||||
{
|
||||
if(div < TIMER_CLKDIV_1 || div > TIMER_CLKDIV_256)
|
||||
return 0; /* invalid divider */
|
||||
|
||||
if(freq > _TIMER_FREQS[div])
|
||||
return 0; /* out of range for given divisor */
|
||||
|
||||
uint64_t counts = _TIMER_FREQS[div]/freq;
|
||||
return counts;
|
||||
}
|
||||
|
||||
uint32_t timer_time_to_count(const timer_frc_t frc, uint32_t us, const timer_clkdiv_t div)
|
||||
{
|
||||
if(div < TIMER_CLKDIV_1 || div > TIMER_CLKDIV_256)
|
||||
return 0; /* invalid divider */
|
||||
|
||||
const uint32_t TIMER_MAX = timer_max_load(frc);
|
||||
|
||||
if(div != TIMER_CLKDIV_256) /* timer tick in MHz */
|
||||
{
|
||||
/* timer is either 80MHz or 5MHz, so either 80 or 5 MHz counts per us */
|
||||
const uint32_t counts_per_us = ((div == TIMER_CLKDIV_1) ? _FREQ_DIV1 : _FREQ_DIV16)/1000/1000;
|
||||
if(us > TIMER_MAX/counts_per_us)
|
||||
return 0; /* Multiplying us by mhz_per_count will overflow TIMER_MAX */
|
||||
return us*counts_per_us;
|
||||
}
|
||||
else /* /256 divider, 312.5kHz freq so need to scale up */
|
||||
{
|
||||
/* derived from naive floating point equation that we can't use:
|
||||
counts = (us/1000/1000)*_FREQ_DIV256;
|
||||
counts = (us/2000)*(_FREQ_DIV256/500);
|
||||
counts = us*(_FREQ_DIV256/500)/2000;
|
||||
*/
|
||||
uint32_t _timer_freq_to_count_runtime(const timer_frc_t frc, const uint32_t freq, const timer_clkdiv_t div)
|
||||
{
|
||||
return _timer_freq_to_count_impl(frc, freq, div);
|
||||
const uint32_t scalar = _FREQ_DIV256/500;
|
||||
if(us > 1+UINT32_MAX/scalar)
|
||||
return 0; /* Multiplying us by _FREQ_DIV256/500 will overflow uint32_t */
|
||||
|
||||
uint32_t counts = (us*scalar)/2000;
|
||||
if(counts > TIMER_MAX)
|
||||
return 0; /* counts value too high for timer type */
|
||||
return counts;
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t _timer_time_to_count_runtime(const timer_frc_t frc, uint32_t us, const timer_clkdiv_t div)
|
||||
int timer_set_frequency(const timer_frc_t frc, uint32_t freq)
|
||||
{
|
||||
return _timer_time_to_count_runtime(frc, us, div);
|
||||
uint32_t counts = 0;
|
||||
timer_clkdiv_t div = timer_freq_to_div(freq);
|
||||
|
||||
counts = timer_freq_to_count(frc, freq, div);
|
||||
if(counts == 0)
|
||||
{
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
timer_set_divider(frc, div);
|
||||
if(frc == FRC1)
|
||||
{
|
||||
timer_set_load(frc, counts);
|
||||
timer_set_reload(frc, true);
|
||||
}
|
||||
else /* FRC2 */
|
||||
{
|
||||
/* assume that if this overflows it'll wrap, so we'll get desired behaviour */
|
||||
TIMER(1).ALARM = counts + TIMER(1).COUNT;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool _timer_set_frequency_runtime(const timer_frc_t frc, uint32_t freq)
|
||||
int _timer_set_timeout_impl(const timer_frc_t frc, uint32_t us)
|
||||
{
|
||||
return _timer_set_frequency_runtime(frc, freq);
|
||||
uint32_t counts = 0;
|
||||
timer_clkdiv_t div = timer_time_to_div(us);
|
||||
|
||||
counts = timer_time_to_count(frc, us, div);
|
||||
if(counts == 0)
|
||||
return -EINVAL; /* can't set frequency */
|
||||
|
||||
timer_set_divider(frc, div);
|
||||
if(frc == FRC1)
|
||||
{
|
||||
timer_set_load(frc, counts);
|
||||
}
|
||||
else /* FRC2 */
|
||||
{
|
||||
TIMER(1).ALARM = counts + TIMER(1).COUNT;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool _timer_set_timeout_runtime(const timer_frc_t frc, uint32_t us)
|
||||
int timer_set_timeout(const timer_frc_t frc, uint32_t us)
|
||||
{
|
||||
return _timer_set_timeout_impl(frc, us);
|
||||
uint32_t counts = 0;
|
||||
timer_clkdiv_t div = timer_time_to_div(us);
|
||||
|
||||
counts = timer_time_to_count(frc, us, div);
|
||||
if(counts == 0)
|
||||
return -EINVAL; /* can't set frequency */
|
||||
|
||||
timer_set_divider(frc, div);
|
||||
if(frc == FRC1)
|
||||
{
|
||||
timer_set_load(frc, counts);
|
||||
}
|
||||
else /* FRC2 */
|
||||
{
|
||||
TIMER(1).ALARM = counts + TIMER(1).COUNT;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -53,8 +53,30 @@
|
|||
#define IROM __attribute__((section(".irom0.literal"))) const
|
||||
#endif
|
||||
|
||||
#define INLINED inline static __attribute__((always_inline)) __attribute__((unused))
|
||||
/* Use this macro to place functions into Instruction RAM (IRAM)
|
||||
instead of flash memory (IROM).
|
||||
|
||||
This is useful for functions which are called when the flash may
|
||||
not be available (for example during NMI exceptions), or for
|
||||
functions which are called very frequently and need high
|
||||
performance.
|
||||
|
||||
Bear in mind IRAM is limited (32KB), compared to up to 1MB of flash.
|
||||
*/
|
||||
#define IRAM __attribute__((section(".iram1.text")))
|
||||
|
||||
/* Use this macro to place read-only data into Instruction RAM (IRAM)
|
||||
instead of loaded into rodata which resides in DRAM.
|
||||
|
||||
This may be useful to free up data RAM. However all data read from
|
||||
the instruction space must be 32-bit aligned word reads
|
||||
(non-aligned reads will use an interrupt routine to "fix" them and
|
||||
still work, but are very slow..
|
||||
*/
|
||||
#ifdef __cplusplus
|
||||
#define IRAM_DATA __attribute__((section(".iram1.rodata")))
|
||||
#else
|
||||
#define IRAM_DATA __attribute__((section(".iram1.rodata"))) const
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
|
|
@ -13,63 +13,74 @@
|
|||
#include "esp/iomux.h"
|
||||
#include "esp/interrupts.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
typedef enum {
|
||||
GPIO_INPUT,
|
||||
GPIO_OUTPUT, /* "Standard" push-pull output */
|
||||
GPIO_OUT_OPEN_DRAIN, /* Open drain output */
|
||||
GPIO_INPUT_PULLUP,
|
||||
} gpio_direction_t;
|
||||
|
||||
/* Enable GPIO on the specified pin, and set it to input/output/ with
|
||||
* pullup as needed
|
||||
/* Enable GPIO on the specified pin, and set it to input or output mode
|
||||
*/
|
||||
INLINED void gpio_enable(const uint8_t gpio_num, const gpio_direction_t direction)
|
||||
{
|
||||
uint32_t iomux_flags;
|
||||
void gpio_enable(const uint8_t gpio_num, const gpio_direction_t direction);
|
||||
|
||||
switch(direction) {
|
||||
case GPIO_INPUT:
|
||||
iomux_flags = 0;
|
||||
break;
|
||||
case GPIO_OUTPUT:
|
||||
iomux_flags = IOMUX_PIN_OUTPUT_ENABLE;
|
||||
break;
|
||||
case GPIO_OUT_OPEN_DRAIN:
|
||||
iomux_flags = IOMUX_PIN_OUTPUT_ENABLE;
|
||||
break;
|
||||
case GPIO_INPUT_PULLUP:
|
||||
iomux_flags = IOMUX_PIN_PULLUP;
|
||||
break;
|
||||
}
|
||||
iomux_set_gpio_function(gpio_num, iomux_flags);
|
||||
if(direction == GPIO_OUT_OPEN_DRAIN)
|
||||
GPIO.CONF[gpio_num] |= GPIO_CONF_OPEN_DRAIN;
|
||||
else
|
||||
GPIO.CONF[gpio_num] &= ~GPIO_CONF_OPEN_DRAIN;
|
||||
if (iomux_flags & IOMUX_PIN_OUTPUT_ENABLE)
|
||||
GPIO.ENABLE_OUT_SET = BIT(gpio_num);
|
||||
else
|
||||
GPIO.ENABLE_OUT_CLEAR = BIT(gpio_num);
|
||||
}
|
||||
/* Enable/disable internal pullup resistor for a particular GPIO
|
||||
*
|
||||
* Note: According to Espressif, pullup resistor values are between 30K and
|
||||
* 100K ohms (see http://bbs.espressif.com/viewtopic.php?t=1079#p4097)
|
||||
* However, measured values suggest that the actual value is likely to be close
|
||||
* to 47K in reality.
|
||||
*
|
||||
* NOTE: The enabled_during_sleep setting is currently untested (please send
|
||||
* feedback if you give it a try)
|
||||
*/
|
||||
void gpio_set_pullup(uint8_t gpio_num, bool enabled, bool enabled_during_sleep);
|
||||
|
||||
/* Disable GPIO on the specified pin, and set it Hi-Z.
|
||||
*
|
||||
* If later muxing this pin to a different function, make sure to set
|
||||
* IOMUX_PIN_OUTPUT_ENABLE if necessary to enable the output buffer.
|
||||
*/
|
||||
INLINED void gpio_disable(const uint8_t gpio_num)
|
||||
static inline void gpio_disable(const uint8_t gpio_num)
|
||||
{
|
||||
GPIO.ENABLE_OUT_CLEAR = BIT(gpio_num);
|
||||
*gpio_iomux_reg(gpio_num) &= ~IOMUX_PIN_OUTPUT_ENABLE;
|
||||
}
|
||||
|
||||
/* Set whether the specified pin continues to drive its output when the ESP8266
|
||||
* goes into sleep mode. Note that this setting is reset to off whenever
|
||||
* gpio_enable is called, so this must be called after calling that function.
|
||||
*
|
||||
* NOTE: This functionality is currently untested (please send feedback if you
|
||||
* give it a try)
|
||||
*/
|
||||
static inline void gpio_set_output_on_sleep(const uint8_t gpio_num, bool enabled)
|
||||
{
|
||||
if (enabled) {
|
||||
IOMUX.PIN[gpio_to_iomux(gpio_num)] |= IOMUX_PIN_OUTPUT_ENABLE_SLEEP;
|
||||
} else {
|
||||
IOMUX.PIN[gpio_to_iomux(gpio_num)] &= ~IOMUX_PIN_OUTPUT_ENABLE_SLEEP;
|
||||
}
|
||||
}
|
||||
|
||||
/* Set output of a pin high or low.
|
||||
*
|
||||
* Only works if pin has been set to GPIO_OUTPUT via gpio_enable()
|
||||
* Only works if pin has been set to GPIO_OUTPUT or GPIO_OUT_OPEN_DRAIN via
|
||||
* gpio_enable()
|
||||
*
|
||||
* If the mode is GPIO_OUT_OPEN_DRAIN, setting it low (false) will pull the pin
|
||||
* down to ground, but setting it high (true) will allow it to float. Note
|
||||
* that even in GPIO_OUT_OPEN_DRAIN mode, the input gates are still physically
|
||||
* connected to the pin, and can be damaged if the voltage is not in either the
|
||||
* "low" or "high" range. Make sure there is some sort of pull-up resistor on
|
||||
* the line to avoid floating logic lines!
|
||||
*/
|
||||
INLINED void gpio_write(const uint8_t gpio_num, const bool set)
|
||||
static inline void gpio_write(const uint8_t gpio_num, const bool set)
|
||||
{
|
||||
if(set)
|
||||
if (set)
|
||||
GPIO.OUT_SET = BIT(gpio_num);
|
||||
else
|
||||
GPIO.OUT_CLEAR = BIT(gpio_num);
|
||||
|
@ -77,9 +88,12 @@ INLINED void gpio_write(const uint8_t gpio_num, const bool set)
|
|||
|
||||
/* Toggle output of a pin
|
||||
*
|
||||
* Only works if pin has been set to GPIO_OUTPUT via gpio_enable()
|
||||
* Only works if pin has been set to GPIO_OUTPUT or GPIO_OUT_OPEN_DRAIN via
|
||||
* gpio_enable()
|
||||
*
|
||||
* See notes in gpio_write() about GPIO_OUT_OPEN_DRAIN mode.
|
||||
*/
|
||||
INLINED void gpio_toggle(const uint8_t gpio_num)
|
||||
static inline void gpio_toggle(const uint8_t gpio_num)
|
||||
{
|
||||
/* Why implement like this instead of GPIO_OUT_REG ^= xxx?
|
||||
Concurrency. If an interrupt or higher priority task writes to
|
||||
|
@ -95,10 +109,14 @@ INLINED void gpio_toggle(const uint8_t gpio_num)
|
|||
|
||||
/* Read input value of a GPIO pin.
|
||||
*
|
||||
* If pin is set as an input, this reads the value on the pin.
|
||||
* If pin is set as an output, this reads the last value written to the pin.
|
||||
* If pin is set GPIO_INPUT, this reads the level on the pin.
|
||||
* If pin is set GPIO_OUTPUT, this reads the level at which the pin is
|
||||
* currently being driven (i.e. the last value written).
|
||||
* If pin is set GPIO_OUT_OPEN_DRAIN, when the pin is written low, this will
|
||||
* return low (false), when the pin is written high, this will behave like
|
||||
* GPIO_INPUT.
|
||||
*/
|
||||
INLINED bool gpio_read(const uint8_t gpio_num)
|
||||
static inline bool gpio_read(const uint8_t gpio_num)
|
||||
{
|
||||
return GPIO.IN & BIT(gpio_num);
|
||||
}
|
||||
|
@ -107,9 +125,10 @@ extern void gpio_interrupt_handler(void);
|
|||
|
||||
/* Set the interrupt type for a given pin
|
||||
*
|
||||
* If int_type is not GPIO_INTTYPE_NONE, the gpio_interrupt_handler will be attached and unmasked.
|
||||
* If int_type is not GPIO_INTTYPE_NONE, the gpio_interrupt_handler will be
|
||||
* attached and unmasked.
|
||||
*/
|
||||
INLINED void gpio_set_interrupt(const uint8_t gpio_num, const gpio_inttype_t int_type)
|
||||
static inline void gpio_set_interrupt(const uint8_t gpio_num, const gpio_inttype_t int_type)
|
||||
{
|
||||
GPIO.CONF[gpio_num] = SET_FIELD(GPIO.CONF[gpio_num], GPIO_CONF_INTTYPE, int_type);
|
||||
if(int_type != GPIO_INTTYPE_NONE) {
|
||||
|
@ -119,9 +138,13 @@ INLINED void gpio_set_interrupt(const uint8_t gpio_num, const gpio_inttype_t int
|
|||
}
|
||||
|
||||
/* Return the interrupt type set for a pin */
|
||||
INLINED gpio_inttype_t gpio_get_interrupt(const uint8_t gpio_num)
|
||||
static inline gpio_inttype_t gpio_get_interrupt(const uint8_t gpio_num)
|
||||
{
|
||||
return (gpio_inttype_t)FIELD2VAL(GPIO_CONF_INTTYPE, GPIO.CONF[gpio_num]);
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
|
137
core/include/esp/i2s_regs.h
Normal file
137
core/include/esp/i2s_regs.h
Normal file
|
@ -0,0 +1,137 @@
|
|||
/* esp/i2s_regs.h
|
||||
*
|
||||
* ESP8266 I2S register definitions
|
||||
*
|
||||
* Not compatible with ESP SDK register access code.
|
||||
*/
|
||||
|
||||
#ifndef _ESP_I2S_REGS_H
|
||||
#define _ESP_I2S_REGS_H
|
||||
|
||||
#include "esp/types.h"
|
||||
#include "common_macros.h"
|
||||
|
||||
#define I2S_BASE 0x60000e00
|
||||
#define I2S (*(struct I2S_REGS *)I2S_BASE)
|
||||
|
||||
struct I2S_REGS {
|
||||
uint32_t volatile TXFIFO; // 0x00
|
||||
uint32_t volatile RXFIFO; // 0x04
|
||||
uint32_t volatile CONF; // 0x08
|
||||
uint32_t volatile INT_RAW; // 0x0c
|
||||
uint32_t volatile INT_STATUS; // 0x10
|
||||
uint32_t volatile INT_ENABLE; // 0x14
|
||||
uint32_t volatile INT_CLEAR; // 0x18
|
||||
uint32_t volatile TIMING; // 0x1c
|
||||
uint32_t volatile FIFO_CONF; // 0x20
|
||||
uint32_t volatile RX_EOF_NUM; // 0x24
|
||||
uint32_t volatile CONF_SINGLE_DATA; // 0x28
|
||||
uint32_t volatile CONF_CHANNELS; // 0x2c
|
||||
};
|
||||
|
||||
_Static_assert(sizeof(struct I2S_REGS) == 0x30, "I2S_REGS is the wrong size");
|
||||
|
||||
/* Details for CONF register */
|
||||
|
||||
#define I2S_CONF_BCK_DIV_M 0x0000003f
|
||||
#define I2S_CONF_BCK_DIV_S 22
|
||||
#define I2S_CONF_CLKM_DIV_M 0x0000003f
|
||||
#define I2S_CONF_CLKM_DIV_S 16
|
||||
#define I2S_CONF_BITS_MOD_M 0x0000000f
|
||||
#define I2S_CONF_BITS_MOD_S 12
|
||||
#define I2S_CONF_RX_MSB_SHIFT BIT(11)
|
||||
#define I2S_CONF_TX_MSB_SHIFT BIT(10)
|
||||
#define I2S_CONF_RX_START BIT(9)
|
||||
#define I2S_CONF_TX_START BIT(8)
|
||||
#define I2S_CONF_MSB_RIGHT BIT(7)
|
||||
#define I2S_CONF_RIGHT_FIRST BIT(6)
|
||||
#define I2S_CONF_RX_SLAVE_MOD BIT(5)
|
||||
#define I2S_CONF_TX_SLAVE_MOD BIT(4)
|
||||
#define I2S_CONF_RX_FIFO_RESET BIT(3)
|
||||
#define I2S_CONF_TX_FIFO_RESET BIT(2)
|
||||
#define I2S_CONF_RX_RESET BIT(1)
|
||||
#define I2S_CONF_TX_RESET BIT(0)
|
||||
#define I2S_CONF_RESET_MASK 0xf
|
||||
|
||||
/* Details for INT_RAW register */
|
||||
|
||||
#define I2S_INT_RAW_TX_REMPTY BIT(5)
|
||||
#define I2S_INT_RAW_TX_WFULL BIT(4)
|
||||
#define I2S_INT_RAW_RX_REMPTY BIT(3)
|
||||
#define I2S_INT_RAW_RX_WFULL BIT(2)
|
||||
#define I2S_INT_RAW_TX_PUT_DATA BIT(1)
|
||||
#define I2S_INT_RAW_RX_TAKE_DATA BIT(0)
|
||||
|
||||
/* Details for INT_STATUS register */
|
||||
|
||||
#define I2S_INT_STATUS_TX_REMPTY BIT(5)
|
||||
#define I2S_INT_STATUS_TX_WFULL BIT(4)
|
||||
#define I2S_INT_STATUS_RX_REMPTY BIT(3)
|
||||
#define I2S_INT_STATUS_RX_WFULL BIT(2)
|
||||
#define I2S_INT_STATUS_TX_PUT_DATA BIT(1)
|
||||
#define I2S_INT_STATUS_RX_TAKE_DATA BIT(0)
|
||||
|
||||
/* Details for INT_ENABLE register */
|
||||
|
||||
#define I2S_INT_ENABLE_TX_REMPTY BIT(5)
|
||||
#define I2S_INT_ENABLE_TX_WFULL BIT(4)
|
||||
#define I2S_INT_ENABLE_RX_REMPTY BIT(3)
|
||||
#define I2S_INT_ENABLE_RX_WFULL BIT(2)
|
||||
#define I2S_INT_ENABLE_TX_PUT_DATA BIT(1)
|
||||
#define I2S_INT_ENABLE_RX_TAKE_DATA BIT(0)
|
||||
|
||||
/* Details for INT_CLEAR register */
|
||||
|
||||
#define I2S_INT_CLEAR_TX_REMPTY BIT(5)
|
||||
#define I2S_INT_CLEAR_TX_WFULL BIT(4)
|
||||
#define I2S_INT_CLEAR_RX_REMPTY BIT(3)
|
||||
#define I2S_INT_CLEAR_RX_WFULL BIT(2)
|
||||
#define I2S_INT_CLEAR_TX_PUT_DATA BIT(1)
|
||||
#define I2S_INT_CLEAR_RX_TAKE_DATA BIT(0)
|
||||
|
||||
/* Details for TIMING register */
|
||||
|
||||
#define I2S_TIMING_TX_BCK_IN_INV BIT(22)
|
||||
#define I2S_TIMING_RX_DSYNC_SW BIT(21)
|
||||
#define I2S_TIMING_TX_DSYNC_SW BIT(20)
|
||||
#define I2S_TIMING_RX_BCK_OUT_DELAY_M 0x00000003
|
||||
#define I2S_TIMING_RX_BCK_OUT_DELAY_S 18
|
||||
#define I2S_TIMING_RX_WS_OUT_DELAY_M 0x00000003
|
||||
#define I2S_TIMING_RX_WS_OUT_DELAY_S 16
|
||||
#define I2S_TIMING_TX_SD_OUT_DELAY_M 0x00000003
|
||||
#define I2S_TIMING_TX_SD_OUT_DELAY_S 14
|
||||
#define I2S_TIMING_TX_WS_OUT_DELAY_M 0x00000003
|
||||
#define I2S_TIMING_TX_WS_OUT_DELAY_S 12
|
||||
#define I2S_TIMING_TX_BCK_OUT_DELAY_M 0x00000003
|
||||
#define I2S_TIMING_TX_BCK_OUT_DELAY_S 10
|
||||
#define I2S_TIMING_RX_SD_IN_DELAY_M 0x00000003
|
||||
#define I2S_TIMING_RX_SD_IN_DELAY_S 8
|
||||
#define I2S_TIMING_RX_WS_IN_DELAY 0x00000003
|
||||
#define I2S_TIMING_RX_WS_IN_DELAY_S 6
|
||||
#define I2S_TIMING_RX_BCK_IN_DELAY_M 0x00000003
|
||||
#define I2S_TIMING_RX_BCK_IN_DELAY_S 4
|
||||
#define I2S_TIMING_TX_WS_IN_DELAY_M 0x00000003
|
||||
#define I2S_TIMING_TX_WS_IN_DELAY_S 2
|
||||
#define I2S_TIMING_TX_BCK_IN_DELAY_M 0x00000003
|
||||
#define I2S_TIMING_TX_BCK_IN_DELAY_S 0
|
||||
|
||||
/* Details for FIFO_CONF register */
|
||||
|
||||
#define I2S_FIFO_CONF_RX_FIFO_MOD_M 0x00000007
|
||||
#define I2S_FIFO_CONF_RX_FIFO_MOD_S 16
|
||||
#define I2S_FIFO_CONF_TX_FIFO_MOD_M 0x00000007
|
||||
#define I2S_FIFO_CONF_TX_FIFO_MOD_S 13
|
||||
#define I2S_FIFO_CONF_DESCRIPTOR_ENABLE BIT(12)
|
||||
#define I2S_FIFO_CONF_TX_DATA_NUM_M 0x0000003f
|
||||
#define I2S_FIFO_CONF_TX_DATA_NUM_S 6
|
||||
#define I2S_FIFO_CONF_RX_DATA_NUM_M 0x0000003f
|
||||
#define I2S_FIFO_CONF_RX_DATA_NUM_S 0
|
||||
|
||||
/* Details for CONF_CHANNEL register */
|
||||
|
||||
#define I2S_CONF_CHANNELS_RX_CHANNEL_MOD_M 0x00000003
|
||||
#define I2S_CONF_CHANNELS_RX_CHANNEL_MOD_S 3
|
||||
#define I2S_CONF_CHANNELS_TX_CHANNEL_MOD_M 0x00000007
|
||||
#define I2S_CONF_CHANNELS_TX_CHANNEL_MOD_S 0
|
||||
|
||||
#endif /* _ESP_I2S_REGS_H */
|
|
@ -17,6 +17,7 @@
|
|||
|
||||
/* Interrupt numbers for level 1 exception handler. */
|
||||
typedef enum {
|
||||
INUM_SLC = 1,
|
||||
INUM_SPI = 2,
|
||||
INUM_GPIO = 4,
|
||||
INUM_UART = 5,
|
||||
|
@ -38,7 +39,7 @@ void sdk__xt_tick_timer_init (void);
|
|||
void sdk__xt_timer_int(void);
|
||||
void sdk__xt_timer_int1(void);
|
||||
|
||||
INLINED uint32_t _xt_get_intlevel(void)
|
||||
static inline uint32_t _xt_get_intlevel(void)
|
||||
{
|
||||
uint32_t level;
|
||||
__asm__ volatile("rsr %0, intlevel" : "=a"(level));
|
||||
|
@ -52,7 +53,7 @@ INLINED uint32_t _xt_get_intlevel(void)
|
|||
portDISABLE_INTERRUPTS/portENABLE_INTERRUPTS for
|
||||
non-FreeRTOS & non-portable code.
|
||||
*/
|
||||
INLINED uint32_t _xt_disable_interrupts(void)
|
||||
static inline uint32_t _xt_disable_interrupts(void)
|
||||
{
|
||||
uint32_t old_level;
|
||||
__asm__ volatile ("rsil %0, " XTSTR(XCHAL_EXCM_LEVEL) : "=a" (old_level));
|
||||
|
@ -60,14 +61,14 @@ INLINED uint32_t _xt_disable_interrupts(void)
|
|||
}
|
||||
|
||||
/* Restore PS level. Intended to be used with _xt_disable_interrupts */
|
||||
INLINED void _xt_restore_interrupts(uint32_t new_ps)
|
||||
static inline void _xt_restore_interrupts(uint32_t new_ps)
|
||||
{
|
||||
__asm__ volatile ("wsr %0, ps; rsync" :: "a" (new_ps));
|
||||
}
|
||||
|
||||
/* ESPTODO: the mask/unmask functions aren't thread safe */
|
||||
|
||||
INLINED void _xt_isr_unmask(uint32_t unmask)
|
||||
static inline void _xt_isr_unmask(uint32_t unmask)
|
||||
{
|
||||
uint32_t intenable;
|
||||
asm volatile ("rsr %0, intenable" : "=a" (intenable));
|
||||
|
@ -75,7 +76,7 @@ INLINED void _xt_isr_unmask(uint32_t unmask)
|
|||
asm volatile ("wsr %0, intenable; esync" :: "a" (intenable));
|
||||
}
|
||||
|
||||
INLINED void _xt_isr_mask (uint32_t mask)
|
||||
static inline void _xt_isr_mask (uint32_t mask)
|
||||
{
|
||||
uint32_t intenable;
|
||||
asm volatile ("rsr %0, intenable" : "=a" (intenable));
|
||||
|
@ -83,14 +84,14 @@ INLINED void _xt_isr_mask (uint32_t mask)
|
|||
asm volatile ("wsr %0, intenable; esync" :: "a" (intenable));
|
||||
}
|
||||
|
||||
INLINED uint32_t _xt_read_ints (void)
|
||||
static inline uint32_t _xt_read_ints (void)
|
||||
{
|
||||
uint32_t interrupt;
|
||||
asm volatile ("rsr %0, interrupt" : "=a" (interrupt));
|
||||
return interrupt;
|
||||
}
|
||||
|
||||
INLINED void _xt_clear_ints(uint32_t mask)
|
||||
static inline void _xt_clear_ints(uint32_t mask)
|
||||
{
|
||||
asm volatile ("wsr %0, intclear; esync" :: "a" (mask));
|
||||
}
|
||||
|
|
|
@ -22,7 +22,7 @@ extern "C" {
|
|||
* known at compile time, or return the result from a lookup table if not.
|
||||
*
|
||||
*/
|
||||
inline static uint8_t gpio_to_iomux(const uint8_t gpio_number);
|
||||
uint8_t IRAM gpio_to_iomux(const uint8_t gpio_number);
|
||||
|
||||
/**
|
||||
* Convert an iomux register index to a GPIO pin number.
|
||||
|
@ -31,7 +31,7 @@ inline static uint8_t gpio_to_iomux(const uint8_t gpio_number);
|
|||
* known at compile time, or return the result from a lookup table if not.
|
||||
*
|
||||
*/
|
||||
inline static uint8_t iomux_to_gpio(const uint8_t iomux_num);
|
||||
uint8_t IRAM iomux_to_gpio(const uint8_t iomux_num);
|
||||
|
||||
/**
|
||||
* Directly get the IOMUX register for a particular gpio number
|
||||
|
@ -43,31 +43,43 @@ inline static esp_reg_t gpio_iomux_reg(const uint8_t gpio_number)
|
|||
return &(IOMUX.PIN[gpio_to_iomux(gpio_number)]);
|
||||
}
|
||||
|
||||
inline static void iomux_set_function(uint8_t iomux_num, uint32_t func)
|
||||
{
|
||||
uint32_t prev = IOMUX.PIN[iomux_num] & ~IOMUX_PIN_FUNC_MASK;
|
||||
IOMUX.PIN[iomux_num] = IOMUX_FUNC(func) | prev;
|
||||
}
|
||||
|
||||
inline static void iomux_set_direction_flags(uint8_t iomux_num, uint32_t dir_flags)
|
||||
{
|
||||
uint32_t mask = IOMUX_PIN_OUTPUT_ENABLE | IOMUX_PIN_OUTPUT_ENABLE_SLEEP;
|
||||
uint32_t prev = IOMUX.PIN[iomux_num] & ~mask;
|
||||
IOMUX.PIN[iomux_num] = dir_flags | prev;
|
||||
}
|
||||
|
||||
inline static void iomux_set_pullup_flags(uint8_t iomux_num, uint32_t pullup_flags)
|
||||
{
|
||||
uint32_t mask = IOMUX_PIN_PULLUP | IOMUX_PIN_PULLDOWN | IOMUX_PIN_PULLUP_SLEEP | IOMUX_PIN_PULLDOWN_SLEEP;
|
||||
uint32_t prev = IOMUX.PIN[iomux_num] & ~mask;
|
||||
IOMUX.PIN[iomux_num] = pullup_flags | prev;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set a pin to the GPIO function.
|
||||
*
|
||||
* This allows you to set pins to GPIO without knowing in advance the
|
||||
* exact register masks to use.
|
||||
*
|
||||
* flags can be any of IOMUX_PIN_OUTPUT_ENABLE, IOMUX_PIN_PULLUP, IOMUX_PIN_PULLDOWN, etc. Any other flags will be cleared.
|
||||
*
|
||||
* Equivalent to a direct register operation if gpio_number is known at compile time.
|
||||
* ie the following are equivalent:
|
||||
*
|
||||
* iomux_set_gpio_function(12, IOMUX_PIN_OUTPUT_ENABLE);
|
||||
* IOMUX_GPIO12 = IOMUX_GPIO12_FUNC_GPIO | IOMUX_PIN_OUTPUT_ENABLE;
|
||||
* Sets the function and direction, but leaves the pullup configuration the
|
||||
* same as before.
|
||||
*/
|
||||
inline static void iomux_set_gpio_function(const uint8_t gpio_number, const uint32_t flags)
|
||||
inline static void iomux_set_gpio_function(uint8_t gpio_number, bool output_enable)
|
||||
{
|
||||
const uint8_t reg_idx = gpio_to_iomux(gpio_number);
|
||||
const uint32_t func = (reg_idx > 11 ? IOMUX_FUNC(0) : IOMUX_FUNC(3)) | flags;
|
||||
IOMUX.PIN[reg_idx] = func | flags;
|
||||
const uint8_t iomux_num = gpio_to_iomux(gpio_number);
|
||||
const uint32_t func = iomux_num > 11 ? 0 : 3;
|
||||
iomux_set_function(iomux_num, func);
|
||||
iomux_set_direction_flags(iomux_num, output_enable ? IOMUX_PIN_OUTPUT_ENABLE : 0);
|
||||
}
|
||||
|
||||
/* esp_iomux_private contains implementation parts of the inline functions
|
||||
declared above */
|
||||
#include "esp/iomux_private.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
|
|
@ -1,46 +0,0 @@
|
|||
/** esp/iomux_private.h
|
||||
*
|
||||
* Private implementation parts of iomux registers. In headers to
|
||||
* allow compile-time optimisations.
|
||||
*
|
||||
* Part of esp-open-rtos
|
||||
* Copyright (C) 2015 Superhouse Automation Pty Ltd
|
||||
* BSD Licensed as described in the file LICENSE
|
||||
*/
|
||||
|
||||
/* Mapping from register index to GPIO and from GPIO index to register
|
||||
number. DO NOT USE THESE IN YOUR CODE, call gpio_to_iomux(xxx) or
|
||||
iomux_to_gpio(xxx) instead.
|
||||
*/
|
||||
#ifndef _IOMUX_PRIVATE
|
||||
#define _IOMUX_PRIVATE
|
||||
|
||||
#include "common_macros.h"
|
||||
|
||||
#define _IOMUX_TO_GPIO { 12, 13, 14, 15, 3, 1, 6, 7, 8, 9, 10, 11, 0, 2, 4, 5 }
|
||||
#define _GPIO_TO_IOMUX { 12, 5, 13, 4, 14, 15, 6, 7, 8, 9, 10, 11, 0, 1, 2, 3 }
|
||||
|
||||
extern const IROM uint32_t GPIO_TO_IOMUX_MAP[];
|
||||
extern const IROM uint32_t IOMUX_TO_GPIO_MAP[];
|
||||
|
||||
INLINED uint8_t gpio_to_iomux(const uint8_t gpio_number)
|
||||
{
|
||||
if(__builtin_constant_p(gpio_number)) {
|
||||
static const uint8_t _regs[] = _GPIO_TO_IOMUX;
|
||||
return _regs[gpio_number];
|
||||
} else {
|
||||
return GPIO_TO_IOMUX_MAP[gpio_number];
|
||||
}
|
||||
}
|
||||
|
||||
INLINED uint8_t iomux_to_gpio(const uint8_t iomux_number)
|
||||
{
|
||||
if(__builtin_constant_p(iomux_number)) {
|
||||
static const uint8_t _regs[] = _IOMUX_TO_GPIO;
|
||||
return _regs[iomux_number];
|
||||
} else {
|
||||
return IOMUX_TO_GPIO_MAP[iomux_number];
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
|
@ -40,9 +40,9 @@ _Static_assert(sizeof(struct IOMUX_REGS) == 0x44, "IOMUX_REGS is the wrong size"
|
|||
#define IOMUX_PIN_PULLDOWN BIT(6)
|
||||
#define IOMUX_PIN_PULLUP BIT(7)
|
||||
#define IOMUX_PIN_FUNC_HIGH_M 0x00000004
|
||||
#define IOMUX_PIN_FUNC_HIGH_S 8
|
||||
#define IOMUX_PIN_FUNC_HIGH_S 6
|
||||
|
||||
#define IOMUX_PIN_FUNC_MASK 0x00001030
|
||||
#define IOMUX_PIN_FUNC_MASK 0x00000130
|
||||
|
||||
/* WARNING: Macro evaluates argument twice */
|
||||
#define IOMUX_FUNC(val) (VAL2FIELD_M(IOMUX_PIN_FUNC_LOW, val) | VAL2FIELD_M(IOMUX_PIN_FUNC_HIGH, val))
|
||||
|
@ -80,8 +80,8 @@ _Static_assert(sizeof(struct IOMUX_REGS) == 0x44, "IOMUX_REGS is the wrong size"
|
|||
|
||||
#define IOMUX_GPIO2_FUNC_GPIO IOMUX_FUNC(0)
|
||||
#define IOMUX_GPIO2_FUNC_I2SO_WS IOMUX_FUNC(1)
|
||||
#define IOMUX_GPIO2_FUNC_UART1_TXD_BLINK IOMUX_FUNC(2)
|
||||
#define IOMUX_GPIO2_FUNC_UART0_TXD_BLINK IOMUX_FUNC(4)
|
||||
#define IOMUX_GPIO2_FUNC_UART1_TXD IOMUX_FUNC(2)
|
||||
#define IOMUX_GPIO2_FUNC_UART0_TXD IOMUX_FUNC(4)
|
||||
|
||||
#define IOMUX_GPIO3_FUNC_UART0_RXD IOMUX_FUNC(0)
|
||||
#define IOMUX_GPIO3_FUNC_I2SO_DATA IOMUX_FUNC(1)
|
||||
|
|
|
@ -16,14 +16,17 @@
|
|||
#include "common_macros.h"
|
||||
#include "esp/types.h"
|
||||
|
||||
#include "esp/uart_regs.h"
|
||||
#include "esp/spi_regs.h"
|
||||
#include "esp/iomux_regs.h"
|
||||
#include "esp/dport_regs.h"
|
||||
#include "esp/gpio_regs.h"
|
||||
#include "esp/i2s_regs.h"
|
||||
#include "esp/iomux_regs.h"
|
||||
#include "esp/rtc_regs.h"
|
||||
#include "esp/rtcmem_regs.h"
|
||||
#include "esp/slc_regs.h"
|
||||
#include "esp/spi_regs.h"
|
||||
#include "esp/timer_regs.h"
|
||||
#include "esp/wdt_regs.h"
|
||||
#include "esp/rtcmem_regs.h"
|
||||
#include "esp/dport_regs.h"
|
||||
#include "esp/uart_regs.h"
|
||||
|
||||
/* Register base addresses
|
||||
|
||||
|
@ -44,7 +47,7 @@
|
|||
//#define SPI_BASE (MMIO_BASE + 0x0200)
|
||||
//#define GPIO0_BASE (MMIO_BASE + 0x0300)
|
||||
//#define TIMER_BASE (MMIO_BASE + 0x0600)
|
||||
#define RTC_BASE (MMIO_BASE + 0x0700)
|
||||
//#define RTC_BASE (MMIO_BASE + 0x0700)
|
||||
//#define IOMUX_BASE (MMIO_BASE + 0x0800)
|
||||
//#define WDT_BASE (MMIO_BASE + 0x0900)
|
||||
#define I2C_BASE (MMIO_BASE + 0x0d00)
|
||||
|
|
|
@ -3,6 +3,16 @@
|
|||
* ESP8266 RTC register definitions
|
||||
*
|
||||
* Not compatible with ESP SDK register access code.
|
||||
*
|
||||
* RTC peripheral remains powered during deep sleep, and RTC clock
|
||||
* is used to wake from deep sleep when RTC.COUNTER == RTC.COUNTER_ALARM.
|
||||
*
|
||||
* "GPIO16" is a special GPIO pin connected to the RTC subsystem,
|
||||
* GPIO16 must be connected to reset to allow wake from deep sleep.
|
||||
*
|
||||
* The contents of scratch registers RTC.SCRATCH[] are preserved
|
||||
* across reset, including wake from sleep (unconfirmed). Contents of
|
||||
* RTCMEM are also preserved.
|
||||
*/
|
||||
|
||||
#ifndef _ESP_RTC_REGS_H
|
||||
|
@ -18,7 +28,7 @@
|
|||
// Note: GPIO_CFG[3] is also known as PAD_XPD_DCDC_CONF in eagle_soc.h
|
||||
|
||||
struct RTC_REGS {
|
||||
uint32_t volatile _unknown0; // 0x00
|
||||
uint32_t volatile CTRL0; // 0x00
|
||||
uint32_t volatile COUNTER_ALARM; // 0x04
|
||||
uint32_t volatile RESET_REASON0; // 0x08 //FIXME: need better name
|
||||
uint32_t volatile _unknownc[2]; // 0x0c - 0x10
|
||||
|
@ -42,6 +52,14 @@ struct RTC_REGS {
|
|||
|
||||
_Static_assert(sizeof(struct RTC_REGS) == 0xac, "RTC_REGS is the wrong size");
|
||||
|
||||
/* Details for CTRL0 register */
|
||||
|
||||
/* Writing this bit causes a software reset but
|
||||
the device then fails in ets_main.c (needs other parameters set?) */
|
||||
#define RTC_CTRL0_BIT31 BIT(31)
|
||||
|
||||
/* Details for RESET_REASONx registers */
|
||||
|
||||
/* The following are used in sdk_rtc_get_reset_reason(). Details are still a
|
||||
* bit sketchy regarding exactly what they mean/do.. */
|
||||
|
||||
|
@ -51,6 +69,32 @@ _Static_assert(sizeof(struct RTC_REGS) == 0xac, "RTC_REGS is the wrong size");
|
|||
#define RTC_RESET_REASON2_CODE_M 0x0000003f
|
||||
#define RTC_RESET_REASON2_CODE_S 8
|
||||
|
||||
#define RTC_RESET_REASON0_SOMETHING BIT(21)
|
||||
/* Writing this bit causes the ESP to go into some kind of unrecoverable boot loop */
|
||||
#define RTC_RESET_REASON0_BIT20 BIT(20)
|
||||
|
||||
/* Both bits 20 & 21 can be set & cleared from software,
|
||||
BIT21 appears to be checked inside sdk_rtc_get_reset_reason() */
|
||||
#define RTC_RESET_REASON0_BIT21 BIT(21)
|
||||
#define RTC_RESET_REASON0_BIT22 BIT(22)
|
||||
|
||||
/* Details for GPIO_CONF register */
|
||||
|
||||
#define RTC_GPIO_CONF_OUT_ENABLE BIT(0)
|
||||
|
||||
/* Details for GPIO_CFG[3] register controlling GPIO16 (possibly others?) */
|
||||
|
||||
#define RTC_GPIO_CFG3_PIN_PULLUP BIT(2)
|
||||
#define RTC_GPIO_CFG3_PIN_PULLDOWN BIT(3)
|
||||
#define RTC_GPIO_CFG3_PIN_PULLUP_SLEEP BIT(4)
|
||||
#define RTC_GPIO_CFG3_PIN_PULLDOWN_SLEEP BIT(5)
|
||||
|
||||
/* The PIN_FUNC values here are probably similar to the
|
||||
values used to set the iomux registers...? */
|
||||
#define RTC_GPIO_CFG3_PIN_FUNC_M 0x00000043
|
||||
#define RTC_GPIO_CFG3_PIN_FUNC_S 0
|
||||
|
||||
/* This should be the function value needed to have GPIO16 be the alarm
|
||||
output from the RTC. FIXME: Needs to be validated. */
|
||||
#define RTC_GPIO_CFG3_PIN_FUNC_RTC_GPIO0 BIT(0)
|
||||
|
||||
#endif /* _ESP_RTC_REGS_H */
|
||||
|
|
37
core/include/esp/slc.h
Normal file
37
core/include/esp/slc.h
Normal file
|
@ -0,0 +1,37 @@
|
|||
/* esp/slc_regs.h
|
||||
*
|
||||
* ESP8266 SLC functions
|
||||
*/
|
||||
|
||||
#ifndef _ESP_SLC_H
|
||||
#define _ESP_SLC_H
|
||||
|
||||
#include "esp/slc_regs.h"
|
||||
|
||||
/* Memory layout for DMA transfer descriptors. */
|
||||
|
||||
struct SLCDescriptor
|
||||
{
|
||||
uint32_t flags;
|
||||
uint32_t buf_ptr;
|
||||
uint32_t next_link_ptr;
|
||||
};
|
||||
|
||||
#define SLC_DESCRIPTOR_FLAGS_BLOCKSIZE_M 0x00000fff
|
||||
#define SLC_DESCRIPTOR_FLAGS_BLOCKSIZE_S 0
|
||||
#define SLC_DESCRIPTOR_FLAGS_DATA_LENGTH_M 0x00000fff
|
||||
#define SLC_DESCRIPTOR_FLAGS_DATA_LENGTH_S 12
|
||||
#define SLC_DESCRIPTOR_FLAGS_SUB_SOF BIT(29)
|
||||
#define SLC_DESCRIPTOR_FLAGS_EOF BIT(30)
|
||||
#define SLC_DESCRIPTOR_FLAGS_OWNER BIT(31)
|
||||
|
||||
#define SLC_DESCRIPTOR_FLAGS(blocksize,datalen,sub_sof,eof,owner) ( \
|
||||
VAL2FIELD_M(SLC_DESCRIPTOR_FLAGS_BLOCKSIZE,blocksize)| \
|
||||
VAL2FIELD_M(SLC_DESCRIPTOR_FLAGS_DATA_LENGTH,datalen)| \
|
||||
((sub_sof)?SLC_DESCRIPTOR_FLAGS_SUB_SOF:0)| \
|
||||
((eof)?SLC_DESCRIPTOR_FLAGS_EOF:0)| \
|
||||
((owner)?SLC_DESCRIPTOR_FLAGS_OWNER:0) \
|
||||
)
|
||||
|
||||
|
||||
#endif /* _ESP_SLC_REGS_H */
|
289
core/include/esp/slc_regs.h
Normal file
289
core/include/esp/slc_regs.h
Normal file
|
@ -0,0 +1,289 @@
|
|||
/* esp/slc_regs.h
|
||||
*
|
||||
* ESP8266 SLC register definitions
|
||||
*
|
||||
* Not compatible with ESP SDK register access code.
|
||||
*/
|
||||
|
||||
#ifndef _ESP_SLC_REGS_H
|
||||
#define _ESP_SLC_REGS_H
|
||||
|
||||
#include "esp/types.h"
|
||||
#include "common_macros.h"
|
||||
|
||||
#define SLC_BASE 0x60000b00
|
||||
#define SLC (*(struct SLC_REGS *)SLC_BASE)
|
||||
|
||||
struct SLC_REGS {
|
||||
uint32_t volatile CONF0; // 0x00
|
||||
uint32_t volatile INT_RAW; // 0x04
|
||||
uint32_t volatile INT_STATUS; // 0x08
|
||||
uint32_t volatile INT_ENABLE; // 0x0c
|
||||
uint32_t volatile INT_CLEAR; // 0x10
|
||||
uint32_t volatile RX_STATUS; // 0x14
|
||||
uint32_t volatile RX_FIFO_PUSH; // 0x18
|
||||
uint32_t volatile TX_STATUS; // 0x1c
|
||||
uint32_t volatile TX_FIFO_POP; // 0x20
|
||||
uint32_t volatile RX_LINK; // 0x24
|
||||
uint32_t volatile TX_LINK; // 0x28
|
||||
uint32_t volatile INTVEC_TO_HOST; // 0x2c
|
||||
uint32_t volatile TOKEN0; // 0x30
|
||||
uint32_t volatile TOKEN1; // 0x34
|
||||
uint32_t volatile CONF1; // 0x38
|
||||
uint32_t volatile STATE0; // 0x3c
|
||||
uint32_t volatile STATE1; // 0x40
|
||||
uint32_t volatile BRIDGE_CONF; // 0x44
|
||||
uint32_t volatile RX_EOF_DESCRIPTOR_ADDR; // 0x48
|
||||
uint32_t volatile TX_EOF_DESCRIPTOR_ADDR; // 0x4c
|
||||
uint32_t volatile RX_EOF_BUFFER_DESCRIPTOR_ADDR; // 0x50 - Naming uncertain
|
||||
uint32_t volatile AHB_TEST; // 0x54
|
||||
uint32_t volatile SDIO_STATUS; // 0x58
|
||||
uint32_t volatile RX_DESCRIPTOR_CONF; // 0x5c
|
||||
uint32_t volatile TX_LINK_DESCRIPTOR; // 0x60
|
||||
uint32_t volatile TX_LINK_DESCRIPTOR_BF0; // 0x64
|
||||
uint32_t volatile TX_LINK_DESCRIPTOR_BF1; // 0x68
|
||||
uint32_t volatile RX_LINK_DESCRIPTOR; // 0x6c
|
||||
uint32_t volatile RX_LINK_DESCRIPTOR_BF0; // 0x70
|
||||
uint32_t volatile RX_LINK_DESCRIPTOR_BF1; // 0x74
|
||||
uint32_t volatile DATE; // 0x78
|
||||
uint32_t volatile ID; // 0x7c
|
||||
uint32_t volatile UNKNOWN_80; // 0x80
|
||||
uint32_t volatile UNKNOWN_84; // 0x84
|
||||
uint32_t volatile HOST_INT_RAW; // 0x88
|
||||
uint32_t volatile UNKNOWN_8C; // 0x8c
|
||||
uint32_t volatile UNKNOWN_90; // 0x90
|
||||
uint32_t volatile HOST_CONF_W0; // 0x94
|
||||
uint32_t volatile HOST_CONF_W1; // 0x98
|
||||
uint32_t volatile HOST_INT_STATUS; // 0x9c
|
||||
uint32_t volatile HOST_CONF_W2; // 0xa0
|
||||
uint32_t volatile HOST_CONF_W3; // 0xa4
|
||||
uint32_t volatile HOST_CONF_W4; // 0xa8
|
||||
uint32_t volatile UNKNOWN_AC; // 0xac
|
||||
uint32_t volatile HOST_INT_CLEAR; // 0xb0
|
||||
uint32_t volatile HOST_INT_ENABLE; // 0xb4
|
||||
uint32_t volatile UNKNOWN_B8; // 0xb8
|
||||
uint32_t volatile HOST_CONF_W5; // 0xbc
|
||||
};
|
||||
|
||||
_Static_assert(sizeof(struct SLC_REGS) == 0xc0, "SLC_REGS is the wrong size");
|
||||
|
||||
/* Details for CONF0 register */
|
||||
|
||||
#define SLC_CONF0_MODE_M 0x00000003
|
||||
#define SLC_CONF0_MODE_S 12
|
||||
#define SLC_CONF0_DATA_BURST_ENABLE BIT(9)
|
||||
#define SLC_CONF0_DESCRIPTOR_BURST_ENABLE BIT(8)
|
||||
#define SLC_CONF0_RX_NO_RESTART_CLEAR BIT(7)
|
||||
#define SLC_CONF0_RX_AUTO_WRITE_BACK BIT(6)
|
||||
#define SLC_CONF0_RX_LOOP_TEST BIT(5)
|
||||
#define SLC_CONF0_TX_LOOP_TEST BIT(4)
|
||||
#define SLC_CONF0_AHBM_RESET BIT(3)
|
||||
#define SLC_CONF0_AHBM_FIFO_RESET BIT(2)
|
||||
#define SLC_CONF0_RX_LINK_RESET BIT(1)
|
||||
#define SLC_CONF0_TX_LINK_RESET BIT(0)
|
||||
|
||||
/* Details for INT_RAW register */
|
||||
|
||||
#define SLC_INT_RAW_TX_DSCR_EMPTY BIT(21)
|
||||
#define SLC_INT_RAW_RX_DSCR_ERROR BIT(20)
|
||||
#define SLC_INT_RAW_TX_DSCR_ERROR BIT(19)
|
||||
#define SLC_INT_RAW_TO_HOST BIT(18)
|
||||
#define SLC_INT_RAW_RX_EOF BIT(17)
|
||||
#define SLC_INT_RAW_RX_DONE BIT(16)
|
||||
#define SLC_INT_RAW_TX_EOF BIT(15)
|
||||
#define SLC_INT_RAW_TX_DONE BIT(14)
|
||||
#define SLC_INT_RAW_TOKEN1_1TO0 BIT(13)
|
||||
#define SLC_INT_RAW_TOKEN0_1TO0 BIT(12)
|
||||
#define SLC_INT_RAW_TX_OVERFLOW BIT(11)
|
||||
#define SLC_INT_RAW_RX_UNDEFLOW BIT(10)
|
||||
#define SLC_INT_RAW_TX_START BIT(9)
|
||||
#define SLC_INT_RAW_RX_START BIT(8)
|
||||
#define SLC_INT_RAW_FROM_HOST_BIT7 BIT(7)
|
||||
#define SLC_INT_RAW_FROM_HOST_BIT6 BIT(6)
|
||||
#define SLC_INT_RAW_FROM_HOST_BIT5 BIT(5)
|
||||
#define SLC_INT_RAW_FROM_HOST_BIT4 BIT(4)
|
||||
#define SLC_INT_RAW_FROM_HOST_BIT3 BIT(3)
|
||||
#define SLC_INT_RAW_FROM_HOST_BIT2 BIT(2)
|
||||
#define SLC_INT_RAW_FROM_HOST_BIT1 BIT(1)
|
||||
#define SLC_INT_RAW_FROM_HOST_BIT0 BIT(0)
|
||||
|
||||
/* Details for INT_STATUS register */
|
||||
|
||||
#define SLC_INT_STATUS_TX_DSCR_EMPTY BIT(21)
|
||||
#define SLC_INT_STATUS_RX_DSCR_ERROR BIT(20)
|
||||
#define SLC_INT_STATUS_TX_DSCR_ERROR BIT(19)
|
||||
#define SLC_INT_STATUS_TO_HOST BIT(18)
|
||||
#define SLC_INT_STATUS_RX_EOF BIT(17)
|
||||
#define SLC_INT_STATUS_RX_DONE BIT(16)
|
||||
#define SLC_INT_STATUS_TX_EOF BIT(15)
|
||||
#define SLC_INT_STATUS_TX_DONE BIT(14)
|
||||
#define SLC_INT_STATUS_TOKEN1_1TO0 BIT(13)
|
||||
#define SLC_INT_STATUS_TOKEN0_1TO0 BIT(12)
|
||||
#define SLC_INT_STATUS_TX_OVERFLOW BIT(11)
|
||||
#define SLC_INT_STATUS_RX_UNDEFLOW BIT(10)
|
||||
#define SLC_INT_STATUS_TX_START BIT(9)
|
||||
#define SLC_INT_STATUS_RX_START BIT(8)
|
||||
#define SLC_INT_STATUS_FROM_HOST_BIT7 BIT(7)
|
||||
#define SLC_INT_STATUS_FROM_HOST_BIT6 BIT(6)
|
||||
#define SLC_INT_STATUS_FROM_HOST_BIT5 BIT(5)
|
||||
#define SLC_INT_STATUS_FROM_HOST_BIT4 BIT(4)
|
||||
#define SLC_INT_STATUS_FROM_HOST_BIT3 BIT(3)
|
||||
#define SLC_INT_STATUS_FROM_HOST_BIT2 BIT(2)
|
||||
#define SLC_INT_STATUS_FROM_HOST_BIT1 BIT(1)
|
||||
#define SLC_INT_STATUS_FROM_HOST_BIT0 BIT(0)
|
||||
|
||||
/* Details for INT_ENABLE register */
|
||||
|
||||
#define SLC_INT_ENABLE_TX_DSCR_EMPTY BIT(21)
|
||||
#define SLC_INT_ENABLE_RX_DSCR_ERROR BIT(20)
|
||||
#define SLC_INT_ENABLE_TX_DSCR_ERROR BIT(19)
|
||||
#define SLC_INT_ENABLE_TO_HOST BIT(18)
|
||||
#define SLC_INT_ENABLE_RX_EOF BIT(17)
|
||||
#define SLC_INT_ENABLE_RX_DONE BIT(16)
|
||||
#define SLC_INT_ENABLE_TX_EOF BIT(15)
|
||||
#define SLC_INT_ENABLE_TX_DONE BIT(14)
|
||||
#define SLC_INT_ENABLE_TOKEN1_1TO0 BIT(13)
|
||||
#define SLC_INT_ENABLE_TOKEN0_1TO0 BIT(12)
|
||||
#define SLC_INT_ENABLE_TX_OVERFLOW BIT(11)
|
||||
#define SLC_INT_ENABLE_RX_UNDEFLOW BIT(10)
|
||||
#define SLC_INT_ENABLE_TX_START BIT(9)
|
||||
#define SLC_INT_ENABLE_RX_START BIT(8)
|
||||
#define SLC_INT_ENABLE_FROM_HOST_BIT7 BIT(7)
|
||||
#define SLC_INT_ENABLE_FROM_HOST_BIT6 BIT(6)
|
||||
#define SLC_INT_ENABLE_FROM_HOST_BIT5 BIT(5)
|
||||
#define SLC_INT_ENABLE_FROM_HOST_BIT4 BIT(4)
|
||||
#define SLC_INT_ENABLE_FROM_HOST_BIT3 BIT(3)
|
||||
#define SLC_INT_ENABLE_FROM_HOST_BIT2 BIT(2)
|
||||
#define SLC_INT_ENABLE_FROM_HOST_BIT1 BIT(1)
|
||||
#define SLC_INT_ENABLE_FROM_HOST_BIT0 BIT(0)
|
||||
|
||||
#define SLC_INT_ENABLE_FROM_HOST_BIT_ALL 0xff
|
||||
|
||||
/* Details for INT_CLEAR register */
|
||||
|
||||
#define SLC_INT_CLEAR_TX_DSCR_EMPTY BIT(21)
|
||||
#define SLC_INT_CLEAR_RX_DSCR_ERROR BIT(20)
|
||||
#define SLC_INT_CLEAR_TX_DSCR_ERROR BIT(19)
|
||||
#define SLC_INT_CLEAR_TO_HOST BIT(18)
|
||||
#define SLC_INT_CLEAR_RX_EOF BIT(17)
|
||||
#define SLC_INT_CLEAR_RX_DONE BIT(16)
|
||||
#define SLC_INT_CLEAR_TX_EOF BIT(15)
|
||||
#define SLC_INT_CLEAR_TX_DONE BIT(14)
|
||||
#define SLC_INT_CLEAR_TOKEN1_1TO0 BIT(13)
|
||||
#define SLC_INT_CLEAR_TOKEN0_1TO0 BIT(12)
|
||||
#define SLC_INT_CLEAR_TX_OVERFLOW BIT(11)
|
||||
#define SLC_INT_CLEAR_RX_UNDEFLOW BIT(10)
|
||||
#define SLC_INT_CLEAR_TX_START BIT(9)
|
||||
#define SLC_INT_CLEAR_RX_START BIT(8)
|
||||
#define SLC_INT_CLEAR_FROM_HOST_BIT7 BIT(7)
|
||||
#define SLC_INT_CLEAR_FROM_HOST_BIT6 BIT(6)
|
||||
#define SLC_INT_CLEAR_FROM_HOST_BIT5 BIT(5)
|
||||
#define SLC_INT_CLEAR_FROM_HOST_BIT4 BIT(4)
|
||||
#define SLC_INT_CLEAR_FROM_HOST_BIT3 BIT(3)
|
||||
#define SLC_INT_CLEAR_FROM_HOST_BIT2 BIT(2)
|
||||
#define SLC_INT_CLEAR_FROM_HOST_BIT1 BIT(1)
|
||||
#define SLC_INT_CLEAR_FROM_HOST_BIT0 BIT(0)
|
||||
|
||||
/* Details for RX_STATUS register */
|
||||
|
||||
#define SLC_RX_STATUS_EMPTY BIT(1)
|
||||
#define SLC_RX_STATUS_FULL BIT(0)
|
||||
|
||||
/* Details for RX_FIFO_PUSH register */
|
||||
|
||||
#define SLC_RX_FIFO_PUSH_FLAG BIT(16)
|
||||
#define SLC_RX_FIFO_PUSH_DATA_M 0x000001ff
|
||||
#define SLC_RX_FIFO_PUSH_DATA_S 0
|
||||
|
||||
/* Details for TX_STATUS register */
|
||||
|
||||
#define SLC_TX_STATUS_EMPTY BIT(1)
|
||||
#define SLC_TX_STATUS_FULL BIT(0)
|
||||
|
||||
/* Details for TX_FIFO_POP register */
|
||||
|
||||
#define SLC_TX_FIFO_POP_FLAG BIT(16)
|
||||
#define SLC_TX_FIFO_POP_DATA_M 0x000007ff
|
||||
#define SLC_TX_FIFO_POP_DATA_S 0
|
||||
|
||||
/* Details for RX_LINK register */
|
||||
|
||||
#define SLC_RX_LINK_PARK BIT(31)
|
||||
#define SLC_RX_LINK_RESTART BIT(30)
|
||||
#define SLC_RX_LINK_START BIT(29)
|
||||
#define SLC_RX_LINK_STOP BIT(28)
|
||||
#define SLC_RX_LINK_DESCRIPTOR_ADDR_M 0x000fffff
|
||||
#define SLC_RX_LINK_DESCRIPTOR_ADDR_S 0
|
||||
|
||||
/* Details for TX_LINK register */
|
||||
|
||||
#define SLC_TX_LINK_PARK BIT(31)
|
||||
#define SLC_TX_LINK_RESTART BIT(30)
|
||||
#define SLC_TX_LINK_START BIT(29)
|
||||
#define SLC_TX_LINK_STOP BIT(28)
|
||||
#define SLC_TX_LINK_DESCRIPTOR_ADDR_M 0x000fffff
|
||||
#define SLC_TX_LINK_DESCRIPTOR_ADDR_S 0
|
||||
|
||||
/* Details for INTVEC_TO_HOST register */
|
||||
|
||||
#define SLC_INTVEC_TO_HOST_INTVEC_M 0x000000ff
|
||||
#define SLC_INTVEC_TO_HOST_INTVEC_S 0
|
||||
|
||||
/* Details for TOKEN0 register */
|
||||
|
||||
#define SLC_TOKEN0_M 0x00000fff
|
||||
#define SLC_TOKEN0_S 16
|
||||
#define SLC_TOKEN0_LOCAL_INC_MORE BIT(14)
|
||||
#define SLC_TOKEN0_LOCAL_INC BIT(13)
|
||||
#define SLC_TOKEN0_LOCAL_WRITE BIT(12)
|
||||
#define SLC_TOKEN0_LOCAL_DATA_M 0x00000FFF
|
||||
#define SLC_TOKEN0_LOCAL_DATA_S 0
|
||||
|
||||
/* Details for TOKEN1 register */
|
||||
|
||||
#define SLC_TOKEN1_MASK 0x00000fff
|
||||
#define SLC_TOKEN1_S 16
|
||||
#define SLC_TOKEN1_LOCAL_INC_MORE BIT(14)
|
||||
#define SLC_TOKEN1_LOCAL_INC BIT(13)
|
||||
#define SLC_TOKEN1_LOCAL_WRITE BIT(12)
|
||||
#define SLC_TOKEN1_LOCAL_DATA_M 0x00000fff
|
||||
#define SLC_TOKEN1_LOCAL_DATA_S 0
|
||||
|
||||
/* Details for BRIDGE_CONF register */
|
||||
|
||||
#define SLC_BRIDGE_CONF_TX_PUSH_IDLE_M 0x0000ffff
|
||||
#define SLC_BRIDGE_CONF_TX_PUSH_IDLE_S 16
|
||||
#define SLC_BRIDGE_CONF_TX_DUMMY_MODE BIT(12)
|
||||
#define SLC_BRIDGE_CONF_FIFO_MAP_ENABLE_M 0x0000000f
|
||||
#define SLC_BRIDGE_CONF_FIFO_MAP_ENABLE_S 8
|
||||
#define SLC_BRIDGE_CONF_TX_EOF_ENABLE_M 0x0000003f
|
||||
#define SLC_BRIDGE_CONF_TX_EOF_ENABLE_S 0
|
||||
|
||||
/* Details for AHB_TEST register */
|
||||
|
||||
#define SLC_AHB_TEST_ADDR_M 0x00000003
|
||||
#define SLC_AHB_TEST_ADDR_S 4
|
||||
#define SLC_AHB_TEST_MODE_M 0x00000007
|
||||
#define SLC_AHB_TEST_MODE_S 0
|
||||
|
||||
/* Details for SDIO_STATUS register */
|
||||
|
||||
#define SLC_SDIO_STATUS_BUS_M 0x00000007
|
||||
#define SLC_SDIO_STATUS_BUS_S 12
|
||||
#define SLC_SDIO_STATUS_WAKEUP BIT(8)
|
||||
#define SLC_SDIO_STATUS_FUNC_M 0x0000000f
|
||||
#define SLC_SDIO_STATUS_FUNC_S 4
|
||||
#define SLC_SDIO_STATUS_COMMAND_M 0x00000007
|
||||
#define SLC_SDIO_STATUS_COMMAND_S 0
|
||||
|
||||
/* Details for RX_DESCRIPTOR_CONF register */
|
||||
|
||||
#define SLC_RX_DESCRIPTOR_CONF_RX_FILL_ENABLE BIT(20)
|
||||
#define SLC_RX_DESCRIPTOR_CONF_RX_EOF_MODE BIT(19)
|
||||
#define SLC_RX_DESCRIPTOR_CONF_RX_FILL_MODE BIT(18)
|
||||
#define SLC_RX_DESCRIPTOR_CONF_INFOR_NO_REPLACE BIT(17)
|
||||
#define SLC_RX_DESCRIPTOR_CONF_TOKEN_NO_REPLACE BIT(16)
|
||||
#define SLC_RX_DESCRIPTOR_CONF_POP_IDLE_COUNT_M 0x0000ffff
|
||||
#define SLC_RX_DESCRIPTOR_CONF_POP_IDLE_COUNT_S 0
|
||||
|
||||
#endif /* _ESP_SLC_REGS_H */
|
272
core/include/esp/spi.h
Normal file
272
core/include/esp/spi.h
Normal file
|
@ -0,0 +1,272 @@
|
|||
/**
|
||||
* \file Hardware SPI master driver
|
||||
*
|
||||
* Part of esp-open-rtos
|
||||
*
|
||||
* \copyright Ruslan V. Uss, 2016
|
||||
* BSD Licensed as described in the file LICENSE
|
||||
*/
|
||||
#ifndef _ESP_SPI_H_
|
||||
#define _ESP_SPI_H_
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include "esp/spi_regs.h"
|
||||
#include "esp/clocks.h"
|
||||
|
||||
/**
|
||||
* Macro for use with spi_init and spi_set_frequency_div.
|
||||
* SPI frequency = 80000000 / divider / count
|
||||
* dvider must be in 1..8192 and count in 1..64
|
||||
*/
|
||||
#define SPI_GET_FREQ_DIV(divider, count) (((count) << 16) | ((divider) & 0xffff))
|
||||
|
||||
/**
|
||||
* Predefinded SPI frequency dividers
|
||||
*/
|
||||
#define SPI_FREQ_DIV_125K SPI_GET_FREQ_DIV(64, 10) ///< 125kHz
|
||||
#define SPI_FREQ_DIV_250K SPI_GET_FREQ_DIV(32, 10) ///< 250kHz
|
||||
#define SPI_FREQ_DIV_500K SPI_GET_FREQ_DIV(16, 10) ///< 500kHz
|
||||
#define SPI_FREQ_DIV_1M SPI_GET_FREQ_DIV(8, 10) ///< 1MHz
|
||||
#define SPI_FREQ_DIV_2M SPI_GET_FREQ_DIV(4, 10) ///< 2MHz
|
||||
#define SPI_FREQ_DIV_4M SPI_GET_FREQ_DIV(2, 10) ///< 4MHz
|
||||
#define SPI_FREQ_DIV_8M SPI_GET_FREQ_DIV(5, 2) ///< 8MHz
|
||||
#define SPI_FREQ_DIV_10M SPI_GET_FREQ_DIV(4, 2) ///< 10MHz
|
||||
#define SPI_FREQ_DIV_20M SPI_GET_FREQ_DIV(2, 2) ///< 20MHz
|
||||
#define SPI_FREQ_DIV_40M SPI_GET_FREQ_DIV(1, 2) ///< 40MHz
|
||||
#define SPI_FREQ_DIV_80M SPI_GET_FREQ_DIV(1, 1) ///< 80MHz
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C"
|
||||
{
|
||||
#endif
|
||||
|
||||
typedef enum _spi_mode_t {
|
||||
SPI_MODE0 = 0, ///< CPOL = 0, CPHA = 0
|
||||
SPI_MODE1, ///< CPOL = 0, CPHA = 1
|
||||
SPI_MODE2, ///< CPOL = 1, CPHA = 0
|
||||
SPI_MODE3 ///< CPOL = 1, CPHA = 1
|
||||
} spi_mode_t;
|
||||
|
||||
typedef enum _spi_endianness_t {
|
||||
SPI_LITTLE_ENDIAN = 0,
|
||||
SPI_BIG_ENDIAN
|
||||
} spi_endianness_t;
|
||||
|
||||
typedef enum _spi_word_size_t {
|
||||
SPI_8BIT = 1, ///< 1 byte
|
||||
SPI_16BIT = 2, ///< 2 bytes
|
||||
SPI_32BIT = 4 ///< 4 bytes
|
||||
} spi_word_size_t;
|
||||
|
||||
/**
|
||||
* SPI bus settings
|
||||
*/
|
||||
typedef struct
|
||||
{
|
||||
spi_mode_t mode; ///< Bus mode
|
||||
uint32_t freq_divider; ///< Bus frequency as a divider. See spi_init()
|
||||
bool msb; ///< MSB first if true
|
||||
spi_endianness_t endianness; ///< Bus byte order
|
||||
bool minimal_pins; ///< Minimal set of pins if true. Spee spi_init()
|
||||
} spi_settings_t;
|
||||
|
||||
/**
|
||||
* \brief Initalize SPI bus
|
||||
* Initalize specified SPI bus and setup appropriate pins:
|
||||
* Bus 0:
|
||||
* - MISO = GPIO 7
|
||||
* - MOSI = GPIO 8
|
||||
* - SCK = GPIO 6
|
||||
* - CS0 = GPIO 11 (if minimal_pins is false)
|
||||
* - HD = GPIO 9 (if minimal_pins is false)
|
||||
* - WP = GPIO 10 (if minimal_pins is false)
|
||||
* Bus 1:
|
||||
* - MISO = GPIO 12
|
||||
* - MOSI = GPIO 13
|
||||
* - SCK = GPIO 14
|
||||
* - CS0 = GPIO 15 (if minimal_pins is false)
|
||||
* Note that system flash memory is on the bus 0!
|
||||
* \param bus Bus ID: 0 - system, 1 - user
|
||||
* \param mode Bus mode
|
||||
* \param freq_divider SPI bus frequency divider, use SPI_GET_FREQ_DIV() or predefined value
|
||||
* \param msb Bit order, MSB first if true
|
||||
* \param endianness Byte order
|
||||
* \param minimal_pins If true use the minimal set of pins: MISO, MOSI and SCK.
|
||||
* \return false when error
|
||||
*/
|
||||
bool spi_init(uint8_t bus, spi_mode_t mode, uint32_t freq_divider, bool msb, spi_endianness_t endianness, bool minimal_pins);
|
||||
/**
|
||||
* \brief Initalize SPI bus
|
||||
* spi_init() wrapper.
|
||||
* Example:
|
||||
*
|
||||
* const spi_settings_t my_settings = {
|
||||
* .mode = SPI_MODE0,
|
||||
* .freq_divider = SPI_FREQ_DIV_4M,
|
||||
* .msb = true,
|
||||
* .endianness = SPI_LITTLE_ENDIAN,
|
||||
* .minimal_pins = true
|
||||
* }
|
||||
* ....
|
||||
* spi_settings_t old;
|
||||
* spi_get_settings(1, &old); // save current settings
|
||||
* //spi_init(1, SPI_MODE0, SPI_FREQ_DIV_4M, true, SPI_LITTLE_ENDIAN, true); // use own settings
|
||||
* // or
|
||||
* spi_set_settings(1, &my_settings);
|
||||
* // some work with spi here
|
||||
* ....
|
||||
* spi_set_settings(1, &old); // restore saved settings
|
||||
*
|
||||
* \param s Pointer to the settings structure
|
||||
* \return false when error
|
||||
*/
|
||||
static inline bool spi_set_settings(uint8_t bus, const spi_settings_t *s)
|
||||
{
|
||||
return spi_init(bus, s->mode, s->freq_divider, s->msb, s->endianness, s->minimal_pins);
|
||||
}
|
||||
/**
|
||||
* \brief Get current settings of the SPI bus
|
||||
* See spi_set_settings().
|
||||
* \param bus Bus ID: 0 - system, 1 - user
|
||||
* \param s Pointer to the structure that receives SPI bus settings
|
||||
*/
|
||||
void spi_get_settings(uint8_t bus, spi_settings_t *s);
|
||||
|
||||
/**
|
||||
* \brief Set SPI bus mode
|
||||
* \param bus Bus ID: 0 - system, 1 - user
|
||||
* \param mode Bus mode
|
||||
*/
|
||||
void spi_set_mode(uint8_t bus, spi_mode_t mode);
|
||||
/**
|
||||
* \brief Get mode of the SPI bus
|
||||
* \param bus Bus ID: 0 - system, 1 - user
|
||||
* \return Bus mode
|
||||
*/
|
||||
spi_mode_t spi_get_mode(uint8_t bus);
|
||||
|
||||
/**
|
||||
* \brief Set SPI bus frequency
|
||||
* Examples:
|
||||
*
|
||||
* spi_set_frequency_div(1, SPI_FREQ_DIV_8M); // 8 MHz, predefined value
|
||||
* ...
|
||||
* spi_set_frequency_div(1, SPI_GET_FREQ_DIV(8, 10)); // divider = 8, count = 10,
|
||||
* // frequency = 80000000 Hz / 8 / 10 = 1000000 Hz
|
||||
*
|
||||
* \param bus Bus ID: 0 - system, 1 - user
|
||||
* \param divider Predivider of the system bus frequency (80MHz) in the 2 low
|
||||
* bytes and period pulses count in the third byte. Please note that
|
||||
* divider must be be in range 1..8192 and count in range 2..64. Use the
|
||||
* macro SPI_GET_FREQ_DIV(divider, count) to get the correct parameter value.
|
||||
*/
|
||||
void spi_set_frequency_div(uint8_t bus, uint32_t divider);
|
||||
/**
|
||||
* \brief Get SPI bus frequency as a divider
|
||||
* Example:
|
||||
*
|
||||
* uint32_t old_freq = spi_get_frequency_div(1);
|
||||
* spi_set_frequency_div(1, SPI_FREQ_DIV_8M);
|
||||
* ...
|
||||
* spi_set_frequency_div(1, old_freq);
|
||||
*
|
||||
* \param bus Bus ID: 0 - system, 1 - user
|
||||
* \return SPI frequency, as divider.
|
||||
*/
|
||||
inline uint32_t spi_get_frequency_div(uint8_t bus)
|
||||
{
|
||||
return (FIELD2VAL(SPI_CLOCK_DIV_PRE, SPI(bus).CLOCK) + 1) |
|
||||
(FIELD2VAL(SPI_CLOCK_COUNT_NUM, SPI(bus).CLOCK) + 1);
|
||||
}
|
||||
/**
|
||||
* \brief Get SPI bus frequency in Hz
|
||||
* \param bus Bus ID: 0 - system, 1 - user
|
||||
* \return SPI frequency, Hz
|
||||
*/
|
||||
inline uint32_t spi_get_frequency_hz(uint8_t bus)
|
||||
{
|
||||
return APB_CLK_FREQ /
|
||||
(FIELD2VAL(SPI_CLOCK_DIV_PRE, SPI(bus).CLOCK) + 1) /
|
||||
(FIELD2VAL(SPI_CLOCK_COUNT_NUM, SPI(bus).CLOCK) + 1);
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Set SPI bus bit order
|
||||
* \param bus Bus ID: 0 - system, 1 - user
|
||||
* \param msb Bit order, MSB first if true
|
||||
*/
|
||||
void spi_set_msb(uint8_t bus, bool msb);
|
||||
/**
|
||||
* \brief Get SPI bus bit order
|
||||
* \param bus Bus ID: 0 - system, 1 - user
|
||||
* \return msb Bit order, MSB first if true
|
||||
*/
|
||||
inline bool spi_get_msb(uint8_t bus)
|
||||
{
|
||||
return !(SPI(bus).CTRL0 & (SPI_CTRL0_WR_BIT_ORDER | SPI_CTRL0_RD_BIT_ORDER));
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Set SPI bus byte order
|
||||
* \param bus Bus ID: 0 - system, 1 - user
|
||||
* \param endianness Byte order
|
||||
*/
|
||||
void spi_set_endianness(uint8_t bus, spi_endianness_t endianness);
|
||||
/**
|
||||
* \brief Get SPI bus byte order
|
||||
* \param bus Bus ID: 0 - system, 1 - user
|
||||
* \return endianness Byte order
|
||||
*/
|
||||
inline spi_endianness_t spi_get_endianness(uint8_t bus)
|
||||
{
|
||||
return SPI(bus).USER0 & (SPI_USER0_WR_BYTE_ORDER | SPI_USER0_RD_BYTE_ORDER)
|
||||
? SPI_BIG_ENDIAN
|
||||
: SPI_LITTLE_ENDIAN;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Transfer 8 bits over SPI
|
||||
* \param bus Bus ID: 0 - system, 1 - user
|
||||
* \param data Byte to send
|
||||
* \return Received byte
|
||||
*/
|
||||
uint8_t spi_transfer_8(uint8_t bus, uint8_t data);
|
||||
/**
|
||||
* \brief Transfer 16 bits over SPI
|
||||
* \param bus Bus ID: 0 - system, 1 - user
|
||||
* \param data Word to send
|
||||
* \return Received word
|
||||
*/
|
||||
uint16_t spi_transfer_16(uint8_t bus, uint16_t data);
|
||||
/**
|
||||
* \brief Transfer 32 bits over SPI
|
||||
* \param bus Bus ID: 0 - system, 1 - user
|
||||
* \param data dword to send
|
||||
* \return Received dword
|
||||
*/
|
||||
uint32_t spi_transfer_32(uint8_t bus, uint32_t data);
|
||||
/**
|
||||
* \brief Transfer buffer of words over SPI
|
||||
* Please note that the buffer size is in words, not in bytes!
|
||||
* Example:
|
||||
*
|
||||
* const uint16_t out_buf[] = { 0xa0b0, 0xa1b1, 0xa2b2, 0xa3b3 };
|
||||
* uint16_t in_buf[sizeof(out_buf)];
|
||||
* spi_init(1, SPI_MODE1, SPI_FREQ_DIV_4M, true, SPI_BIG_ENDIAN, true);
|
||||
* spi_transfer(1, out_buf, in_buf, sizeof(out_buf), SPI_16BIT); // len = 4 words * 2 bytes = 8 bytes
|
||||
*
|
||||
* \param bus Bus ID: 0 - system, 1 - user
|
||||
* \param out_data Data to send.
|
||||
* \param in_data Receive buffer. If NULL, received data will be lost.
|
||||
* \param len Buffer size in words
|
||||
* \param word_size Size of the word
|
||||
* \return Transmitted/received words count
|
||||
*/
|
||||
size_t spi_transfer(uint8_t bus, const void *out_data, void *in_data, size_t len, spi_word_size_t word_size);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* _ESP_SPI_H_ */
|
|
@ -150,6 +150,7 @@ _Static_assert(sizeof(struct SPI_REGS) == 0x100, "SPI_REGS is the wrong size");
|
|||
#define SPI_USER0_CS_SETUP BIT(5)
|
||||
#define SPI_USER0_CS_HOLD BIT(4)
|
||||
#define SPI_USER0_FLASH_MODE BIT(2)
|
||||
#define SPI_USER0_DUPLEX BIT(0)
|
||||
|
||||
/* Details for USER1 register */
|
||||
|
||||
|
@ -171,6 +172,7 @@ _Static_assert(sizeof(struct SPI_REGS) == 0x100, "SPI_REGS is the wrong size");
|
|||
|
||||
/* Details for PIN register */
|
||||
|
||||
#define SPI_PIN_IDLE_EDGE BIT(29) ///< CPOL
|
||||
#define SPI_PIN_CS2_DISABLE BIT(2)
|
||||
#define SPI_PIN_CS1_DISABLE BIT(1)
|
||||
#define SPI_PIN_CS0_DISABLE BIT(0)
|
||||
|
|
|
@ -10,6 +10,7 @@
|
|||
#define _ESP_TIMER_H
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <errno.h>
|
||||
#include "esp/timer_regs.h"
|
||||
#include "esp/interrupts.h"
|
||||
|
||||
|
@ -23,43 +24,73 @@ typedef enum {
|
|||
} timer_frc_t;
|
||||
|
||||
/* Return current count value for timer. */
|
||||
INLINED uint32_t timer_get_count(const timer_frc_t frc);
|
||||
static inline uint32_t timer_get_count(const timer_frc_t frc)
|
||||
{
|
||||
return TIMER(frc).COUNT;
|
||||
}
|
||||
|
||||
/* Return current load value for timer. */
|
||||
INLINED uint32_t timer_get_load(const timer_frc_t frc);
|
||||
static inline uint32_t timer_get_load(const timer_frc_t frc)
|
||||
{
|
||||
return TIMER(frc).LOAD;
|
||||
}
|
||||
|
||||
/* Write load value for timer. */
|
||||
INLINED void timer_set_load(const timer_frc_t frc, const uint32_t load);
|
||||
static inline void timer_set_load(const timer_frc_t frc, const uint32_t load)
|
||||
{
|
||||
TIMER(frc).LOAD = load;
|
||||
}
|
||||
|
||||
/* Returns maximum load value for timer. */
|
||||
INLINED uint32_t timer_max_load(const timer_frc_t frc);
|
||||
static inline uint32_t timer_max_load(const timer_frc_t frc)
|
||||
{
|
||||
return (frc == FRC1) ? TIMER_FRC1_MAX_LOAD : UINT32_MAX;
|
||||
}
|
||||
|
||||
/* Set the timer divider value */
|
||||
INLINED void timer_set_divider(const timer_frc_t frc, const timer_clkdiv_t div);
|
||||
static inline void timer_set_divider(const timer_frc_t frc, const timer_clkdiv_t div)
|
||||
{
|
||||
if(div < TIMER_CLKDIV_1 || div > TIMER_CLKDIV_256)
|
||||
return;
|
||||
TIMER(frc).CTRL = SET_FIELD(TIMER(frc).CTRL, TIMER_CTRL_CLKDIV, div);
|
||||
}
|
||||
|
||||
/* Enable or disable timer interrupts
|
||||
|
||||
This both sets the xtensa interrupt mask and writes to the DPORT register
|
||||
that allows timer interrupts.
|
||||
*/
|
||||
INLINED void timer_set_interrupts(const timer_frc_t frc, bool enable);
|
||||
void timer_set_interrupts(const timer_frc_t frc, bool enable);
|
||||
|
||||
/* Turn the timer on or off */
|
||||
INLINED void timer_set_run(const timer_frc_t frc, const bool run);
|
||||
static inline void timer_set_run(const timer_frc_t frc, const bool run)
|
||||
{
|
||||
if (run)
|
||||
TIMER(frc).CTRL |= TIMER_CTRL_RUN;
|
||||
else
|
||||
TIMER(frc).CTRL &= ~TIMER_CTRL_RUN;
|
||||
}
|
||||
|
||||
/* Get the run state of the timer (on or off) */
|
||||
INLINED bool timer_get_run(const timer_frc_t frc);
|
||||
static inline bool timer_get_run(const timer_frc_t frc)
|
||||
{
|
||||
return TIMER(frc).CTRL & TIMER_CTRL_RUN;
|
||||
}
|
||||
|
||||
/* Set timer auto-reload on or off */
|
||||
INLINED void timer_set_reload(const timer_frc_t frc, const bool reload);
|
||||
static inline void timer_set_reload(const timer_frc_t frc, const bool reload)
|
||||
{
|
||||
if (reload)
|
||||
TIMER(frc).CTRL |= TIMER_CTRL_RELOAD;
|
||||
else
|
||||
TIMER(frc).CTRL &= ~TIMER_CTRL_RELOAD;
|
||||
}
|
||||
|
||||
/* Get the auto-reload state of the timer (on or off) */
|
||||
INLINED bool timer_get_reload(const timer_frc_t frc);
|
||||
|
||||
/* Return a suitable timer divider for the specified frequency,
|
||||
or -1 if none is found.
|
||||
*/
|
||||
INLINED timer_clkdiv_t timer_freq_to_div(uint32_t freq);
|
||||
static inline bool timer_get_reload(const timer_frc_t frc)
|
||||
{
|
||||
return TIMER(frc).CTRL & TIMER_CTRL_RELOAD;
|
||||
}
|
||||
|
||||
/* Return the number of timer counts to achieve the specified
|
||||
* frequency with the specified divisor.
|
||||
|
@ -68,14 +99,41 @@ INLINED timer_clkdiv_t timer_freq_to_div(uint32_t freq);
|
|||
*
|
||||
* Returns 0 if the given freq/divisor combo cannot be achieved.
|
||||
*
|
||||
* Compile-time evaluates if all arguments are available at compile time.
|
||||
*/
|
||||
INLINED uint32_t timer_freq_to_count(const timer_frc_t frc, uint32_t freq, const timer_clkdiv_t div);
|
||||
uint32_t timer_freq_to_count(const timer_frc_t frc, uint32_t freq, const timer_clkdiv_t div);
|
||||
|
||||
/* Return a suitable timer divider for the specified frequency,
|
||||
or -1 if none is found.
|
||||
*/
|
||||
static inline timer_clkdiv_t timer_freq_to_div(uint32_t freq)
|
||||
{
|
||||
/*
|
||||
try to maintain resolution without risking overflows.
|
||||
these values are a bit arbitrary at the moment! */
|
||||
if(freq > 100*1000)
|
||||
return TIMER_CLKDIV_1;
|
||||
else if(freq > 100)
|
||||
return TIMER_CLKDIV_16;
|
||||
else
|
||||
return TIMER_CLKDIV_256;
|
||||
}
|
||||
|
||||
/* Return a suitable timer divider for the specified duration in
|
||||
microseconds or -1 if none is found.
|
||||
*/
|
||||
INLINED timer_clkdiv_t timer_time_to_div(uint32_t us);
|
||||
static inline timer_clkdiv_t timer_time_to_div(uint32_t us)
|
||||
{
|
||||
/*
|
||||
try to maintain resolution without risking overflows. Similar to
|
||||
timer_freq_to_div, these values are a bit arbitrary at the
|
||||
moment! */
|
||||
if(us < 1000)
|
||||
return TIMER_CLKDIV_1;
|
||||
else if(us < 10*1000)
|
||||
return TIMER_CLKDIV_16;
|
||||
else
|
||||
return TIMER_CLKDIV_256;
|
||||
}
|
||||
|
||||
/* Return the number of timer counts for the specified timer duration
|
||||
* in microseconds, when using the specified divisor.
|
||||
|
@ -84,9 +142,8 @@ INLINED timer_clkdiv_t timer_time_to_div(uint32_t us);
|
|||
*
|
||||
* Returns 0 if the given time/divisor combo cannot be achieved.
|
||||
*
|
||||
* Compile-time evaluates if all arguments are available at compile time.
|
||||
*/
|
||||
INLINED uint32_t timer_time_to_count(const timer_frc_t frc, uint32_t us, const timer_clkdiv_t div);
|
||||
uint32_t timer_time_to_count(const timer_frc_t frc, uint32_t us, const timer_clkdiv_t div);
|
||||
|
||||
/* Set a target timer interrupt frequency in Hz.
|
||||
|
||||
|
@ -103,12 +160,9 @@ INLINED uint32_t timer_time_to_count(const timer_frc_t frc, uint32_t us, const t
|
|||
Does not start/stop the timer, you have to do this manually via
|
||||
timer_set_run.
|
||||
|
||||
Returns true on success, false if given frequency could not be set.
|
||||
|
||||
Compile-time evaluates to simple register writes if all arguments
|
||||
are available at compile time.
|
||||
Returns 0 on success, or -EINVAL if given frequency could not be set.
|
||||
*/
|
||||
INLINED bool timer_set_frequency(const timer_frc_t frc, uint32_t freq);
|
||||
int timer_set_frequency(const timer_frc_t frc, uint32_t freq);
|
||||
|
||||
/* Sets the timer for a oneshot interrupt in 'us' microseconds.
|
||||
|
||||
|
@ -123,14 +177,9 @@ INLINED bool timer_set_frequency(const timer_frc_t frc, uint32_t freq);
|
|||
also disable FRC1 in the timer interrupt handler by calling
|
||||
timer_set_run(TIMER_FRC1, false);
|
||||
|
||||
Returns true if the timeout was successfully set.
|
||||
|
||||
Compile-time evaluates to simple register writes if all arguments
|
||||
are available at compile time.
|
||||
Returns 0 on success, or -EINVAL if the given timeout could not be set.
|
||||
*/
|
||||
INLINED bool timer_set_timeout(const timer_frc_t frc, uint32_t us);
|
||||
|
||||
#include "timer_private.h"
|
||||
int timer_set_timeout(const timer_frc_t frc, uint32_t us);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
|
|
@ -1,266 +0,0 @@
|
|||
/* Private header parts of the timer API implementation
|
||||
*
|
||||
* Part of esp-open-rtos
|
||||
* Copyright (C) 2015 Superhouse Automation Pty Ltd
|
||||
* BSD Licensed as described in the file LICENSE
|
||||
*/
|
||||
#ifndef _ESP_TIMER_PRIVATE_H
|
||||
#define _ESP_TIMER_PRIVATE_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include <limits.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include "esp/dport_regs.h"
|
||||
|
||||
/* Timer divisor index to max frequency */
|
||||
#define _FREQ_DIV1 (80*1000*1000)
|
||||
#define _FREQ_DIV16 (5*1000*1000)
|
||||
#define _FREQ_DIV256 312500
|
||||
const static uint32_t IROM _TIMER_FREQS[] = { _FREQ_DIV1, _FREQ_DIV16, _FREQ_DIV256 };
|
||||
|
||||
/* Timer divisor index to divisor value */
|
||||
const static uint32_t IROM _TIMER_DIV_VAL[] = { 1, 16, 256 };
|
||||
|
||||
INLINED uint32_t timer_get_count(const timer_frc_t frc)
|
||||
{
|
||||
return TIMER(frc).COUNT;
|
||||
}
|
||||
|
||||
INLINED uint32_t timer_get_load(const timer_frc_t frc)
|
||||
{
|
||||
return TIMER(frc).LOAD;
|
||||
}
|
||||
|
||||
INLINED void timer_set_load(const timer_frc_t frc, const uint32_t load)
|
||||
{
|
||||
TIMER(frc).LOAD = load;
|
||||
}
|
||||
|
||||
INLINED uint32_t timer_max_load(const timer_frc_t frc)
|
||||
{
|
||||
return (frc == FRC1) ? TIMER_FRC1_MAX_LOAD : UINT32_MAX;
|
||||
}
|
||||
|
||||
INLINED void timer_set_divider(const timer_frc_t frc, const timer_clkdiv_t div)
|
||||
{
|
||||
if(div < TIMER_CLKDIV_1 || div > TIMER_CLKDIV_256)
|
||||
return;
|
||||
TIMER(frc).CTRL = SET_FIELD(TIMER(frc).CTRL, TIMER_CTRL_CLKDIV, div);
|
||||
}
|
||||
|
||||
INLINED void timer_set_interrupts(const timer_frc_t frc, bool enable)
|
||||
{
|
||||
const uint32_t dp_bit = (frc == FRC1) ? DPORT_INT_ENABLE_FRC1 : DPORT_INT_ENABLE_FRC2;
|
||||
const uint32_t int_mask = BIT((frc == FRC1) ? INUM_TIMER_FRC1 : INUM_TIMER_FRC2);
|
||||
if(enable) {
|
||||
DPORT.INT_ENABLE |= dp_bit;
|
||||
_xt_isr_unmask(int_mask);
|
||||
} else {
|
||||
DPORT.INT_ENABLE &= ~dp_bit;
|
||||
_xt_isr_mask(int_mask);
|
||||
}
|
||||
}
|
||||
|
||||
INLINED void timer_set_run(const timer_frc_t frc, const bool run)
|
||||
{
|
||||
if (run)
|
||||
TIMER(frc).CTRL |= TIMER_CTRL_RUN;
|
||||
else
|
||||
TIMER(frc).CTRL &= ~TIMER_CTRL_RUN;
|
||||
}
|
||||
|
||||
INLINED bool timer_get_run(const timer_frc_t frc)
|
||||
{
|
||||
return TIMER(frc).CTRL & TIMER_CTRL_RUN;
|
||||
}
|
||||
|
||||
INLINED void timer_set_reload(const timer_frc_t frc, const bool reload)
|
||||
{
|
||||
if (reload)
|
||||
TIMER(frc).CTRL |= TIMER_CTRL_RELOAD;
|
||||
else
|
||||
TIMER(frc).CTRL &= ~TIMER_CTRL_RELOAD;
|
||||
}
|
||||
|
||||
INLINED bool timer_get_reload(const timer_frc_t frc)
|
||||
{
|
||||
return TIMER(frc).CTRL & TIMER_CTRL_RELOAD;
|
||||
}
|
||||
|
||||
INLINED timer_clkdiv_t timer_freq_to_div(uint32_t freq)
|
||||
{
|
||||
/*
|
||||
try to maintain resolution without risking overflows.
|
||||
these values are a bit arbitrary at the moment! */
|
||||
if(freq > 100*1000)
|
||||
return TIMER_CLKDIV_1;
|
||||
else if(freq > 100)
|
||||
return TIMER_CLKDIV_16;
|
||||
else
|
||||
return TIMER_CLKDIV_256;
|
||||
}
|
||||
|
||||
/* timer_timer_to_count implementation - inline if all args are constant, call normally otherwise */
|
||||
|
||||
INLINED uint32_t _timer_freq_to_count_impl(const timer_frc_t frc, const uint32_t freq, const timer_clkdiv_t div)
|
||||
{
|
||||
if(div < TIMER_CLKDIV_1 || div > TIMER_CLKDIV_256)
|
||||
return 0; /* invalid divider */
|
||||
|
||||
if(freq > _TIMER_FREQS[div])
|
||||
return 0; /* out of range for given divisor */
|
||||
|
||||
uint64_t counts = _TIMER_FREQS[div]/freq;
|
||||
return counts;
|
||||
}
|
||||
|
||||
uint32_t _timer_freq_to_count_runtime(const timer_frc_t frc, const uint32_t freq, const timer_clkdiv_t div);
|
||||
|
||||
INLINED uint32_t timer_freq_to_count(const timer_frc_t frc, const uint32_t freq, const timer_clkdiv_t div)
|
||||
{
|
||||
if(__builtin_constant_p(frc) && __builtin_constant_p(freq) && __builtin_constant_p(div))
|
||||
return _timer_freq_to_count_impl(frc, freq, div);
|
||||
else
|
||||
return _timer_freq_to_count_runtime(frc, freq, div);
|
||||
}
|
||||
|
||||
INLINED timer_clkdiv_t timer_time_to_div(uint32_t us)
|
||||
{
|
||||
/*
|
||||
try to maintain resolution without risking overflows. Similar to
|
||||
timer_freq_to_div, these values are a bit arbitrary at the
|
||||
moment! */
|
||||
if(us < 1000)
|
||||
return TIMER_CLKDIV_1;
|
||||
else if(us < 10*1000)
|
||||
return TIMER_CLKDIV_16;
|
||||
else
|
||||
return TIMER_CLKDIV_256;
|
||||
}
|
||||
|
||||
/* timer_timer_to_count implementation - inline if all args are constant, call normally otherwise */
|
||||
|
||||
INLINED uint32_t _timer_time_to_count_impl(const timer_frc_t frc, uint32_t us, const timer_clkdiv_t div)
|
||||
{
|
||||
if(div < TIMER_CLKDIV_1 || div > TIMER_CLKDIV_256)
|
||||
return 0; /* invalid divider */
|
||||
|
||||
const uint32_t TIMER_MAX = timer_max_load(frc);
|
||||
|
||||
if(div != TIMER_CLKDIV_256) /* timer tick in MHz */
|
||||
{
|
||||
/* timer is either 80MHz or 5MHz, so either 80 or 5 MHz counts per us */
|
||||
const uint32_t counts_per_us = ((div == TIMER_CLKDIV_1) ? _FREQ_DIV1 : _FREQ_DIV16)/1000/1000;
|
||||
if(us > TIMER_MAX/counts_per_us)
|
||||
return 0; /* Multiplying us by mhz_per_count will overflow TIMER_MAX */
|
||||
return us*counts_per_us;
|
||||
}
|
||||
else /* /256 divider, 312.5kHz freq so need to scale up */
|
||||
{
|
||||
/* derived from naive floating point equation that we can't use:
|
||||
counts = (us/1000/1000)*_FREQ_DIV256;
|
||||
counts = (us/2000)*(_FREQ_DIV256/500);
|
||||
counts = us*(_FREQ_DIV256/500)/2000;
|
||||
*/
|
||||
const uint32_t scalar = _FREQ_DIV256/500;
|
||||
if(us > 1+UINT32_MAX/scalar)
|
||||
return 0; /* Multiplying us by _FREQ_DIV256/500 will overflow uint32_t */
|
||||
|
||||
uint32_t counts = (us*scalar)/2000;
|
||||
if(counts > TIMER_MAX)
|
||||
return 0; /* counts value too high for timer type */
|
||||
return counts;
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t _timer_time_to_count_runtime(const timer_frc_t frc, uint32_t us, const timer_clkdiv_t div);
|
||||
|
||||
INLINED uint32_t timer_time_to_count(const timer_frc_t frc, uint32_t us, const timer_clkdiv_t div)
|
||||
{
|
||||
if(__builtin_constant_p(frc) && __builtin_constant_p(us) && __builtin_constant_p(div))
|
||||
return _timer_time_to_count_impl(frc, us, div);
|
||||
else
|
||||
return _timer_time_to_count_runtime(frc, us, div);
|
||||
}
|
||||
|
||||
/* timer_set_frequency implementation - inline if all args are constant, call normally otherwise */
|
||||
|
||||
INLINED bool _timer_set_frequency_impl(const timer_frc_t frc, uint32_t freq)
|
||||
{
|
||||
uint32_t counts = 0;
|
||||
timer_clkdiv_t div = timer_freq_to_div(freq);
|
||||
|
||||
counts = timer_freq_to_count(frc, freq, div);
|
||||
if(counts == 0)
|
||||
{
|
||||
printf("ABORT: No counter for timer %u frequency %u\r\n", frc, freq);
|
||||
abort();
|
||||
}
|
||||
|
||||
timer_set_divider(frc, div);
|
||||
if(frc == FRC1)
|
||||
{
|
||||
timer_set_load(frc, counts);
|
||||
timer_set_reload(frc, true);
|
||||
}
|
||||
else /* FRC2 */
|
||||
{
|
||||
/* assume that if this overflows it'll wrap, so we'll get desired behaviour */
|
||||
TIMER(1).ALARM = counts + TIMER(1).COUNT;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool _timer_set_frequency_runtime(const timer_frc_t frc, uint32_t freq);
|
||||
|
||||
INLINED bool timer_set_frequency(const timer_frc_t frc, uint32_t freq)
|
||||
{
|
||||
if(__builtin_constant_p(frc) && __builtin_constant_p(freq))
|
||||
return _timer_set_frequency_impl(frc, freq);
|
||||
else
|
||||
return _timer_set_frequency_runtime(frc, freq);
|
||||
}
|
||||
|
||||
/* timer_set_timeout implementation - inline if all args are constant, call normally otherwise */
|
||||
|
||||
INLINED bool _timer_set_timeout_impl(const timer_frc_t frc, uint32_t us)
|
||||
{
|
||||
uint32_t counts = 0;
|
||||
timer_clkdiv_t div = timer_time_to_div(us);
|
||||
|
||||
counts = timer_time_to_count(frc, us, div);
|
||||
if(counts == 0)
|
||||
return false; /* can't set frequency */
|
||||
|
||||
timer_set_divider(frc, div);
|
||||
if(frc == FRC1)
|
||||
{
|
||||
timer_set_load(frc, counts);
|
||||
}
|
||||
else /* FRC2 */
|
||||
{
|
||||
TIMER(1).ALARM = counts + TIMER(1).COUNT;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool _timer_set_timeout_runtime(const timer_frc_t frc, uint32_t us);
|
||||
|
||||
INLINED bool timer_set_timeout(const timer_frc_t frc, uint32_t us)
|
||||
{
|
||||
if(__builtin_constant_p(frc) && __builtin_constant_p(us))
|
||||
return _timer_set_timeout_impl(frc, us);
|
||||
else
|
||||
return _timer_set_timeout_runtime(frc, us);
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
|
@ -52,7 +52,7 @@ long _write_r(struct _reent *r, int fd, const char *ptr, int len )
|
|||
}
|
||||
|
||||
/* syscall implementation for stdio read from UART */
|
||||
long _read_r( struct _reent *r, int fd, char *ptr, int len )
|
||||
__attribute__((weak)) long _read_r( struct _reent *r, int fd, char *ptr, int len )
|
||||
{
|
||||
int ch, i;
|
||||
|
||||
|
|
5
examples/access_point/Makefile
Normal file
5
examples/access_point/Makefile
Normal file
|
@ -0,0 +1,5 @@
|
|||
# Makefile for access_point example
|
||||
PROGRAM=access_point
|
||||
EXTRA_COMPONENTS=extras/dhcpserver
|
||||
|
||||
include ../../common.mk
|
97
examples/access_point/access_point.c
Normal file
97
examples/access_point/access_point.c
Normal file
|
@ -0,0 +1,97 @@
|
|||
/* Very basic example showing usage of access point mode and the DHCP server.
|
||||
|
||||
The ESP in the example runs a telnet server on 172.16.0.1 (port 23) that
|
||||
outputs some status information if you connect to it, then closes
|
||||
the connection.
|
||||
|
||||
This example code is in the public domain.
|
||||
*/
|
||||
#include <string.h>
|
||||
|
||||
#include <espressif/esp_common.h>
|
||||
#include <esp/uart.h>
|
||||
#include <FreeRTOS.h>
|
||||
#include <task.h>
|
||||
#include <queue.h>
|
||||
#include <dhcpserver.h>
|
||||
|
||||
#include <lwip/api.h>
|
||||
|
||||
#define AP_SSID "esp-open-rtos AP"
|
||||
#define AP_PSK "esp-open-rtos"
|
||||
|
||||
#define TELNET_PORT 23
|
||||
|
||||
static void telnetTask(void *pvParameters);
|
||||
|
||||
void user_init(void)
|
||||
{
|
||||
uart_set_baud(0, 115200);
|
||||
printf("SDK version:%s\n", sdk_system_get_sdk_version());
|
||||
|
||||
sdk_wifi_set_opmode(SOFTAP_MODE);
|
||||
struct ip_info ap_ip;
|
||||
IP4_ADDR(&ap_ip.ip, 172, 16, 0, 1);
|
||||
IP4_ADDR(&ap_ip.gw, 0, 0, 0, 0);
|
||||
IP4_ADDR(&ap_ip.netmask, 255, 255, 0, 0);
|
||||
sdk_wifi_set_ip_info(1, &ap_ip);
|
||||
|
||||
struct sdk_softap_config ap_config = {
|
||||
.ssid = AP_SSID,
|
||||
.ssid_hidden = 0,
|
||||
.channel = 3,
|
||||
.ssid_len = strlen(AP_SSID),
|
||||
.authmode = AUTH_WPA_WPA2_PSK,
|
||||
.password = AP_PSK,
|
||||
.max_connection = 3,
|
||||
.beacon_interval = 100,
|
||||
};
|
||||
sdk_wifi_softap_set_config(&ap_config);
|
||||
|
||||
ip_addr_t first_client_ip;
|
||||
IP4_ADDR(&first_client_ip, 172, 16, 0, 2);
|
||||
dhcpserver_start(&first_client_ip, 4);
|
||||
|
||||
xTaskCreate(telnetTask, (signed char *)"telnetTask", 512, NULL, 2, NULL);
|
||||
}
|
||||
|
||||
/* Telnet task listens on port 23, returns some status information and then closes
|
||||
the connection if you connect to it.
|
||||
*/
|
||||
static void telnetTask(void *pvParameters)
|
||||
{
|
||||
struct netconn *nc = netconn_new (NETCONN_TCP);
|
||||
if(!nc) {
|
||||
printf("Status monitor: Failed to allocate socket.\r\n");
|
||||
return;
|
||||
}
|
||||
netconn_bind(nc, IP_ADDR_ANY, TELNET_PORT);
|
||||
netconn_listen(nc);
|
||||
|
||||
while(1) {
|
||||
struct netconn *client = NULL;
|
||||
err_t err = netconn_accept(nc, &client);
|
||||
|
||||
if ( err != ERR_OK ) {
|
||||
if(client)
|
||||
netconn_delete(client);
|
||||
continue;
|
||||
}
|
||||
|
||||
ip_addr_t client_addr;
|
||||
uint16_t port_ignore;
|
||||
netconn_peer(client, &client_addr, &port_ignore);
|
||||
|
||||
char buf[80];
|
||||
snprintf(buf, sizeof(buf), "Uptime %d seconds\r\n",
|
||||
xTaskGetTickCount()*portTICK_RATE_MS/1000);
|
||||
netconn_write(client, buf, strlen(buf), NETCONN_COPY);
|
||||
snprintf(buf, sizeof(buf), "Free heap %d bytes\r\n", (int)xPortGetFreeHeapSize());
|
||||
netconn_write(client, buf, strlen(buf), NETCONN_COPY);
|
||||
snprintf(buf, sizeof(buf), "Your address is %d.%d.%d.%d\r\n\r\n",
|
||||
ip4_addr1(&client_addr), ip4_addr2(&client_addr),
|
||||
ip4_addr3(&client_addr), ip4_addr4(&client_addr));
|
||||
netconn_write(client, buf, strlen(buf), NETCONN_COPY);
|
||||
netconn_delete(client);
|
||||
}
|
||||
}
|
|
@ -8,13 +8,10 @@
|
|||
#include "task.h"
|
||||
#include "esp8266.h"
|
||||
|
||||
const int gpio = 14;
|
||||
const int gpio = 2;
|
||||
|
||||
/* This task uses the high level GPIO API (esp_gpio.h) to blink an LED.
|
||||
*
|
||||
* Even though it reads better than the register-level version in blinkenRegisterTask,
|
||||
* they compile to the exact same instructions (except gpio_enable also set the output type in
|
||||
* the GPIO control register).
|
||||
*/
|
||||
void blinkenTask(void *pvParameters)
|
||||
{
|
||||
|
@ -28,10 +25,12 @@ void blinkenTask(void *pvParameters)
|
|||
}
|
||||
|
||||
|
||||
/* This task uses all raw register operations to set the pins.
|
||||
/* This task demonstrates an alternative way to use raw register
|
||||
operations to blink an LED.
|
||||
|
||||
It's not fully parameterised, as the IOMUX_GPIO# macros involve a non-linear
|
||||
mapping from GPIO to IOMUX ports.
|
||||
The step that sets the iomux register can't be automatically
|
||||
updated from the 'gpio' constant variable, so you need to change
|
||||
the line that sets IOMUX_GPIO2 if you change 'gpio'.
|
||||
|
||||
There is no significant performance benefit to this way over the
|
||||
blinkenTask version, so it's probably better to use the blinkenTask
|
||||
|
@ -42,7 +41,7 @@ void blinkenTask(void *pvParameters)
|
|||
void blinkenRegisterTask(void *pvParameters)
|
||||
{
|
||||
GPIO.ENABLE_OUT_SET = BIT(gpio);
|
||||
IOMUX_GPIO14 = IOMUX_GPIO14_FUNC_GPIO | IOMUX_PIN_OUTPUT_ENABLE; /* change this line if you change 'gpio' */
|
||||
IOMUX_GPIO2 = IOMUX_GPIO2_FUNC_GPIO | IOMUX_PIN_OUTPUT_ENABLE; /* change this line if you change 'gpio' */
|
||||
while(1) {
|
||||
GPIO.OUT_SET = BIT(gpio);
|
||||
vTaskDelay(1000 / portTICK_RATE_MS);
|
||||
|
|
3
examples/ds18b20_broadcaster/Makefile
Normal file
3
examples/ds18b20_broadcaster/Makefile
Normal file
|
@ -0,0 +1,3 @@
|
|||
PROGRAM=ds18b20_broadcaster
|
||||
EXTRA_COMPONENTS = extras/onewire extras/ds18b20
|
||||
include ../../common.mk
|
20
examples/ds18b20_broadcaster/README.md
Normal file
20
examples/ds18b20_broadcaster/README.md
Normal file
|
@ -0,0 +1,20 @@
|
|||
# DS19B20 Broadcaster
|
||||
|
||||
>In this example you can see how to get data from multiple
|
||||
>ds18b20 sensor and emit result over udb broadcaster address.
|
||||
|
||||
As a client server, you can use this simple udp receiver, writen in python:
|
||||
|
||||
```
|
||||
import select, socket
|
||||
|
||||
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
|
||||
s.bind(('<broadcast>', 8005))
|
||||
s.setblocking(0)
|
||||
|
||||
while True:
|
||||
result = select.select([s],[],[])
|
||||
msg = result[0][0].recv(1024)
|
||||
print msg.strip()
|
||||
|
||||
```
|
128
examples/ds18b20_broadcaster/ds18b20_broadcaster.c
Normal file
128
examples/ds18b20_broadcaster/ds18b20_broadcaster.c
Normal file
|
@ -0,0 +1,128 @@
|
|||
/*
|
||||
* This is example of udp broadcaster.
|
||||
* It grab data from ds18b20 sensor and emit result over wifi.
|
||||
*
|
||||
* Author Grzegorz Hetman : ghetman@gmail.com
|
||||
* License public domain/CC0
|
||||
*/
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#include "espressif/esp_common.h"
|
||||
#include "esp/uart.h"
|
||||
#include "FreeRTOS.h"
|
||||
#include "task.h"
|
||||
#include "timers.h"
|
||||
#include "queue.h"
|
||||
#include "lwip/api.h"
|
||||
#include "ssid_config.h"
|
||||
|
||||
// DS18B20 driver
|
||||
#include "ds18b20/ds18b20.h"
|
||||
// Onewire init
|
||||
#include "onewire/onewire.h"
|
||||
|
||||
void broadcast_temperature(void *pvParameters)
|
||||
{
|
||||
|
||||
uint8_t amount = 0;
|
||||
uint8_t sensors = 2;
|
||||
ds_sensor_t t[sensors];
|
||||
|
||||
// Use GPIO 13 as one wire pin.
|
||||
uint8_t GPIO_FOR_ONE_WIRE = 13;
|
||||
|
||||
char msg[100];
|
||||
|
||||
// Broadcaster part
|
||||
err_t err;
|
||||
// Initialize one wire bus.
|
||||
onewire_init(GPIO_FOR_ONE_WIRE);
|
||||
|
||||
while(1) {
|
||||
|
||||
// Send out some UDP data
|
||||
struct netconn* conn;
|
||||
|
||||
// Create UDP connection
|
||||
conn = netconn_new(NETCONN_UDP);
|
||||
|
||||
// Connect to local port
|
||||
err = netconn_bind(conn, IP_ADDR_ANY, 8004);
|
||||
|
||||
if (err != ERR_OK) {
|
||||
netconn_delete(conn);
|
||||
printf("%s : Could not bind! (%s)\n", __FUNCTION__, lwip_strerr(err));
|
||||
continue;
|
||||
}
|
||||
|
||||
err = netconn_connect(conn, IP_ADDR_BROADCAST, 8005);
|
||||
|
||||
if (err != ERR_OK) {
|
||||
netconn_delete(conn);
|
||||
printf("%s : Could not connect! (%s)\n", __FUNCTION__, lwip_strerr(err));
|
||||
continue;
|
||||
}
|
||||
|
||||
for(;;) {
|
||||
// Search all DS18B20, return its amount and feed 't' structure with result data.
|
||||
amount = ds18b20_read_all(GPIO_FOR_ONE_WIRE, t);
|
||||
|
||||
if (amount < sensors){
|
||||
printf("Something is wrong, I expect to see %d sensors \nbut just %d was detected!\n", sensors, amount);
|
||||
}
|
||||
|
||||
for (int i = 0; i < amount; ++i)
|
||||
{
|
||||
int intpart = (int)t[i].value;
|
||||
int fraction = (int)((t[i].value - intpart) * 100);
|
||||
// Multiple "" here is just to satisfy compiler and don`t raise 'hex escape sequence out of range' warning.
|
||||
sprintf(msg, "Sensor %d report: %d.%02d ""\xC2""\xB0""C\n",t[i].id, intpart, fraction);
|
||||
printf("%s", msg);
|
||||
|
||||
struct netbuf* buf = netbuf_new();
|
||||
void* data = netbuf_alloc(buf, strlen(msg));
|
||||
|
||||
memcpy (data, msg, strlen(msg));
|
||||
err = netconn_send(conn, buf);
|
||||
|
||||
if (err != ERR_OK) {
|
||||
printf("%s : Could not send data!!! (%s)\n", __FUNCTION__, lwip_strerr(err));
|
||||
continue;
|
||||
}
|
||||
netbuf_delete(buf); // De-allocate packet buffer
|
||||
}
|
||||
vTaskDelay(1000/portTICK_RATE_MS);
|
||||
}
|
||||
|
||||
err = netconn_disconnect(conn);
|
||||
printf("%s : Disconnected from IP_ADDR_BROADCAST port 12346 (%s)\n", __FUNCTION__, lwip_strerr(err));
|
||||
|
||||
err = netconn_delete(conn);
|
||||
printf("%s : Deleted connection (%s)\n", __FUNCTION__, lwip_strerr(err));
|
||||
|
||||
vTaskDelay(1000/portTICK_RATE_MS);
|
||||
}
|
||||
}
|
||||
|
||||
void user_init(void)
|
||||
{
|
||||
uart_set_baud(0, 115200);
|
||||
|
||||
printf("SDK version:%s\n", sdk_system_get_sdk_version());
|
||||
|
||||
// Set led to indicate wifi status.
|
||||
sdk_wifi_status_led_install(2, PERIPHS_IO_MUX_GPIO2_U, FUNC_GPIO2);
|
||||
|
||||
struct sdk_station_config config = {
|
||||
.ssid = WIFI_SSID,
|
||||
.password = WIFI_PASS,
|
||||
};
|
||||
|
||||
// Required to call wifi_set_opmode before station_set_config.
|
||||
sdk_wifi_set_opmode(STATION_MODE);
|
||||
sdk_wifi_station_set_config(&config);
|
||||
|
||||
xTaskCreate(&broadcast_temperature, (signed char *)"broadcast_temperature", 256, NULL, 2, NULL);
|
||||
}
|
||||
|
3
examples/ds18b20_onewire/Makefile
Normal file
3
examples/ds18b20_onewire/Makefile
Normal file
|
@ -0,0 +1,3 @@
|
|||
PROGRAM=ds18b20_onewire
|
||||
EXTRA_COMPONENTS = extras/onewire extras/ds18b20
|
||||
include ../../common.mk
|
59
examples/ds18b20_onewire/ds18b20_onewire.c
Normal file
59
examples/ds18b20_onewire/ds18b20_onewire.c
Normal file
|
@ -0,0 +1,59 @@
|
|||
/* ds18b20 - Retrieves temperature from ds18b20 sensors and print it out.
|
||||
*
|
||||
* This sample code is in the public domain.,
|
||||
*/
|
||||
#include "espressif/esp_common.h"
|
||||
#include "esp/uart.h"
|
||||
|
||||
#include "FreeRTOS.h"
|
||||
#include "task.h"
|
||||
#include "timers.h"
|
||||
#include "queue.h"
|
||||
|
||||
// DS18B20 driver
|
||||
#include "ds18b20/ds18b20.h"
|
||||
// Onewire init
|
||||
#include "onewire/onewire.h"
|
||||
|
||||
void print_temperature(void *pvParameters)
|
||||
{
|
||||
int delay = 500;
|
||||
uint8_t amount = 0;
|
||||
// Declare amount of sensors
|
||||
uint8_t sensors = 2;
|
||||
ds_sensor_t t[sensors];
|
||||
|
||||
// Use GPIO 13 as one wire pin.
|
||||
uint8_t GPIO_FOR_ONE_WIRE = 13;
|
||||
|
||||
onewire_init(GPIO_FOR_ONE_WIRE);
|
||||
|
||||
while(1) {
|
||||
// Search all DS18B20, return its amount and feed 't' structure with result data.
|
||||
amount = ds18b20_read_all(GPIO_FOR_ONE_WIRE, t);
|
||||
|
||||
if (amount < sensors){
|
||||
printf("Something is wrong, I expect to see %d sensors \nbut just %d was detected!\n", sensors, amount);
|
||||
}
|
||||
|
||||
for (int i = 0; i < amount; ++i)
|
||||
{
|
||||
int intpart = (int)t[i].value;
|
||||
int fraction = (int)((t[i].value - intpart) * 100);
|
||||
// Multiple "" here is just to satisfy compiler and don`t raise 'hex escape sequence out of range' warning.
|
||||
printf("Sensor %d report: %d.%02d ""\xC2""\xB0""C\n",t[i].id, intpart, fraction);
|
||||
}
|
||||
printf("\n");
|
||||
vTaskDelay(delay / portTICK_RATE_MS);
|
||||
}
|
||||
}
|
||||
|
||||
void user_init(void)
|
||||
{
|
||||
uart_set_baud(0, 115200);
|
||||
|
||||
printf("SDK version:%s\n", sdk_system_get_sdk_version());
|
||||
|
||||
xTaskCreate(&print_temperature, (signed char *)"print_temperature", 256, NULL, 2, NULL);
|
||||
}
|
||||
|
|
@ -17,7 +17,7 @@ const char *dramtest = TESTSTRING;
|
|||
const __attribute__((section(".iram1.notrodata"))) char iramtest[] = TESTSTRING;
|
||||
const __attribute__((section(".text.notrodata"))) char iromtest[] = TESTSTRING;
|
||||
|
||||
INLINED uint32_t get_ccount (void)
|
||||
static inline uint32_t get_ccount (void)
|
||||
{
|
||||
uint32_t ccount;
|
||||
asm volatile ("rsr.ccount %0" : "=a" (ccount));
|
||||
|
|
|
@ -10,30 +10,34 @@
|
|||
#include <string.h>
|
||||
|
||||
const char *server_root_cert = "-----BEGIN CERTIFICATE-----\r\n"
|
||||
"MIIEWTCCA0GgAwIBAgIDAjpjMA0GCSqGSIb3DQEBBQUAMEIxCzAJBgNVBAYTAlVT\r\n"
|
||||
"MRYwFAYDVQQKEw1HZW9UcnVzdCBJbmMuMRswGQYDVQQDExJHZW9UcnVzdCBHbG9i\r\n"
|
||||
"YWwgQ0EwHhcNMTIwODI3MjA0MDQwWhcNMjIwNTIwMjA0MDQwWjBEMQswCQYDVQQG\r\n"
|
||||
"EwJVUzEWMBQGA1UEChMNR2VvVHJ1c3QgSW5jLjEdMBsGA1UEAxMUR2VvVHJ1c3Qg\r\n"
|
||||
"U1NMIENBIC0gRzIwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQC5J/lP\r\n"
|
||||
"2Pa3FT+Pzc7WjRxr/X/aVCFOA9jK0HJSFbjJgltYeYT/JHJv8ml/vJbZmnrDPqnP\r\n"
|
||||
"UCITDoYZ2+hJ74vm1kfy/XNFCK6PrF62+J589xD/kkNm7xzU7qFGiBGJSXl6Jc5L\r\n"
|
||||
"avDXHHYaKTzJ5P0ehdzgMWUFRxasCgdLLnBeawanazpsrwUSxLIRJdY+lynwg2xX\r\n"
|
||||
"HNil78zs/dYS8T/bQLSuDxjTxa9Akl0HXk7+Yhc3iemLdCai7bgK52wVWzWQct3Y\r\n"
|
||||
"TSHUQCNcj+6AMRaraFX0DjtU6QRN8MxOgV7pb1JpTr6mFm1C9VH/4AtWPJhPc48O\r\n"
|
||||
"bxoj8cnI2d+87FLXAgMBAAGjggFUMIIBUDAfBgNVHSMEGDAWgBTAephojYn7qwVk\r\n"
|
||||
"DBF9qn1luMrMTjAdBgNVHQ4EFgQUEUrQcznVW2kIXLo9v2SaqIscVbwwEgYDVR0T\r\n"
|
||||
"AQH/BAgwBgEB/wIBADAOBgNVHQ8BAf8EBAMCAQYwOgYDVR0fBDMwMTAvoC2gK4Yp\r\n"
|
||||
"aHR0cDovL2NybC5nZW90cnVzdC5jb20vY3Jscy9ndGdsb2JhbC5jcmwwNAYIKwYB\r\n"
|
||||
"BQUHAQEEKDAmMCQGCCsGAQUFBzABhhhodHRwOi8vb2NzcC5nZW90cnVzdC5jb20w\r\n"
|
||||
"TAYDVR0gBEUwQzBBBgpghkgBhvhFAQc2MDMwMQYIKwYBBQUHAgEWJWh0dHA6Ly93\r\n"
|
||||
"d3cuZ2VvdHJ1c3QuY29tL3Jlc291cmNlcy9jcHMwKgYDVR0RBCMwIaQfMB0xGzAZ\r\n"
|
||||
"BgNVBAMTElZlcmlTaWduTVBLSS0yLTI1NDANBgkqhkiG9w0BAQUFAAOCAQEAPOU9\r\n"
|
||||
"WhuiNyrjRs82lhg8e/GExVeGd0CdNfAS8HgY+yKk3phLeIHmTYbjkQ9C47ncoNb/\r\n"
|
||||
"qfixeZeZ0cNsQqWSlOBdDDMYJckrlVPg5akMfUf+f1ExRF73Kh41opQy98nuwLbG\r\n"
|
||||
"mqzemSFqI6A4ZO6jxIhzMjtQzr+t03UepvTp+UJrYLLdRf1dVwjOLVDmEjIWE4ry\r\n"
|
||||
"lKKbR6iGf9mY5ffldnRk2JG8hBYo2CVEMH6C2Kyx5MDkFWzbtiQnAioBEoW6MYhY\r\n"
|
||||
"R3TjuNJkpsMyWS4pS0XxW4lJLoKaxhgVRNAuZAEVaDj59vlmAwxVG52/AECu8Egn\r\n"
|
||||
"TOCAXi25KhV6vGb4NQ==\r\n"
|
||||
"MIIFNzCCBB+gAwIBAgISAfl7TPw6Mf/F6VCBc5eaHA7kMA0GCSqGSIb3DQEBCwUA\r\n"
|
||||
"MEoxCzAJBgNVBAYTAlVTMRYwFAYDVQQKEw1MZXQncyBFbmNyeXB0MSMwIQYDVQQD\r\n"
|
||||
"ExpMZXQncyBFbmNyeXB0IEF1dGhvcml0eSBYMTAeFw0xNTEyMzAwNzQ0MDBaFw0x\r\n"
|
||||
"NjAzMjkwNzQ0MDBaMBwxGjAYBgNVBAMTEXd3dy5ob3dzbXlzc2wuY29tMIIBIjAN\r\n"
|
||||
"BgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEArKF7WzSrDPinQhd9mVfoW5u46/TC\r\n"
|
||||
"fbYKR3MEryetUSeQuwuXFj2xO6+a/JQ99UC3Eq+9s8uFdx1zFFS6qfW+HXBwGWVf\r\n"
|
||||
"ajKEyIcXUJZCRn7aWpTWZq6cuv4bZSv1QklGViQs8UCZifcN0A/mYrH7zHG2WDn2\r\n"
|
||||
"fxNgA+nJBqbZPr1gP9hqGFCnX+dPR5WxtC9+Dv9Sx+wiOWVz/obVTCygdqqcpa5I\r\n"
|
||||
"3/U9REVgO2VfT+xMty6NZTMCjTJ+GXZuB/BrMe9+ZmgWk0grJyqdrCxOCyK6B4g+\r\n"
|
||||
"Fvs8WFRNTHdQnP3/NT5hPtreZ3nuY2YY7RbGFwUaBcvJwbbIqalpiQ1X7QIDAQAB\r\n"
|
||||
"o4ICQzCCAj8wDgYDVR0PAQH/BAQDAgWgMB0GA1UdJQQWMBQGCCsGAQUFBwMBBggr\r\n"
|
||||
"BgEFBQcDAjAMBgNVHRMBAf8EAjAAMB0GA1UdDgQWBBQMAe087CSp3PjgqyIYyWTR\r\n"
|
||||
"a2aMnTAfBgNVHSMEGDAWgBSoSmpjBH3duubRObemRWXv86jsoTBwBggrBgEFBQcB\r\n"
|
||||
"AQRkMGIwLwYIKwYBBQUHMAGGI2h0dHA6Ly9vY3NwLmludC14MS5sZXRzZW5jcnlw\r\n"
|
||||
"dC5vcmcvMC8GCCsGAQUFBzAChiNodHRwOi8vY2VydC5pbnQteDEubGV0c2VuY3J5\r\n"
|
||||
"cHQub3JnLzBNBgNVHREERjBEgg1ob3dzbXlzc2wuY29tgg1ob3dzbXl0bHMuY29t\r\n"
|
||||
"ghF3d3cuaG93c215dGxzLmNvbYIRd3d3Lmhvd3NteXNzbC5jb20wgf4GA1UdIASB\r\n"
|
||||
"9jCB8zAIBgZngQwBAgEwgeYGCysGAQQBgt8TAQEBMIHWMCYGCCsGAQUFBwIBFhpo\r\n"
|
||||
"dHRwOi8vY3BzLmxldHNlbmNyeXB0Lm9yZzCBqwYIKwYBBQUHAgIwgZ4MgZtUaGlz\r\n"
|
||||
"IENlcnRpZmljYXRlIG1heSBvbmx5IGJlIHJlbGllZCB1cG9uIGJ5IFJlbHlpbmcg\r\n"
|
||||
"UGFydGllcyBhbmQgb25seSBpbiBhY2NvcmRhbmNlIHdpdGggdGhlIENlcnRpZmlj\r\n"
|
||||
"YXRlIFBvbGljeSBmb3VuZCBhdCBodHRwczovL2xldHNlbmNyeXB0Lm9yZy9yZXBv\r\n"
|
||||
"c2l0b3J5LzANBgkqhkiG9w0BAQsFAAOCAQEALB2QrIrcxxFr81b6khy9LwVBpthL\r\n"
|
||||
"2LSs0xWhA09gxHmPnVrqim3Wa9HFYRApSqtTQWSx58TO+MERXQ7eDX50k53oem+Q\r\n"
|
||||
"gXn90HVDkR0jbV1CsAD5qL00kKOofAyGkUhFlO2hcRU0CIj7Z9HZB8xpYdZWLUSZ\r\n"
|
||||
"BpgiXdf/YYRIwgx29GRQjhfl/H30fHyawY5SvquJuvAeEr7lxqAmEEg3a7J6ibHL\r\n"
|
||||
"90zf5KMkXGyVsXqxLqrEXQKgTvpUMeP5iYAxE45R5GNmYS2jajyTi4XkWw4nEu4Q\r\n"
|
||||
"dMTLuwxGz87KOwSSFOLU903hO3IIPvFIIMY6aVK2kAgQPNIqk9nFurTF9A==\r\n"
|
||||
"-----END CERTIFICATE-----\r\n";
|
||||
|
||||
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
/* A very simple OTA example
|
||||
*
|
||||
* Binds a TCP socket, reads an image from it and then flashes live.
|
||||
* Binds a TCP socket, reads an image from it over TFTP and then flashes live.
|
||||
*
|
||||
* This lets you flash from the command line via netcat.
|
||||
* For more information about esp-open-rtos OTA see https://github.com/SuperHouse/esp-open-rtos/wiki/OTA-Update-Configuration
|
||||
*
|
||||
* NOT SUITABLE TO PUT ON THE INTERNET OR INTO A PRODUCTION ENVIRONMENT!!!!
|
||||
*/
|
||||
|
|
4
examples/pwm_test/Makefile
Normal file
4
examples/pwm_test/Makefile
Normal file
|
@ -0,0 +1,4 @@
|
|||
# Simple makefile for simple example
|
||||
PROGRAM=pwm_test
|
||||
COMPONENTS = FreeRTOS lwip core extras/pwm
|
||||
include ../../common.mk
|
50
examples/pwm_test/pwm_test.c
Normal file
50
examples/pwm_test/pwm_test.c
Normal file
|
@ -0,0 +1,50 @@
|
|||
/* Very basic example to test the pwm library
|
||||
* Hook up an LED to pin14 and you should see the intensity change
|
||||
*
|
||||
* Part of esp-open-rtos
|
||||
* Copyright (C) 2015 Javier Cardona (https://github.com/jcard0na)
|
||||
* BSD Licensed as described in the file LICENSE
|
||||
*/
|
||||
#include "espressif/esp_common.h"
|
||||
#include "esp/uart.h"
|
||||
#include "FreeRTOS.h"
|
||||
#include "task.h"
|
||||
#include "pwm.h"
|
||||
|
||||
void task1(void *pvParameters)
|
||||
{
|
||||
printf("Hello from task1!\r\n");
|
||||
uint32_t const init_count = 0;
|
||||
uint32_t count = init_count;
|
||||
while(1) {
|
||||
vTaskDelay(100);
|
||||
printf("duty cycle set to %d/UINT16_MAX%%\r\n", count);
|
||||
pwm_set_duty(count);
|
||||
count += UINT16_MAX/17;
|
||||
if (count > UINT16_MAX)
|
||||
count = init_count;
|
||||
}
|
||||
}
|
||||
|
||||
void user_init(void)
|
||||
{
|
||||
uint8_t pins[1];
|
||||
uart_set_baud(0, 115200);
|
||||
|
||||
printf("SDK version:%s\n", sdk_system_get_sdk_version());
|
||||
|
||||
printf("pwm_init(1, [14])\n");
|
||||
pins[0] = 14;
|
||||
pwm_init(1, pins);
|
||||
|
||||
printf("pwm_set_freq(1000) # 1 kHz\n");
|
||||
pwm_set_freq(1000);
|
||||
|
||||
printf("pwm_set_duty(UINT16_MAX/2) # 50%%\n");
|
||||
pwm_set_duty(UINT16_MAX/2);
|
||||
|
||||
printf("pwm_start()\n");
|
||||
pwm_start();
|
||||
|
||||
xTaskCreate(task1, (signed char *)"tsk1", 256, NULL, 2, NULL);
|
||||
}
|
|
@ -14,14 +14,6 @@ void user_init(void)
|
|||
printf("SDK version:%s\n", sdk_system_get_sdk_version());
|
||||
printf("Going into echo mode...\n");
|
||||
|
||||
/* By default stdout is line-buffered, so you only see output
|
||||
after a newline is sent. This is helpful in a multithreaded
|
||||
environment so output doesn't get chopped up within a line.
|
||||
|
||||
Here we want to see the echo immediately, so disable buffering.
|
||||
*/
|
||||
setbuf(stdout, NULL);
|
||||
|
||||
while(1) {
|
||||
int c = getchar();
|
||||
if(c != EOF)
|
||||
|
|
12
examples/terminal/FreeRTOSConfig.h
Normal file
12
examples/terminal/FreeRTOSConfig.h
Normal file
|
@ -0,0 +1,12 @@
|
|||
/* Terminal FreeRTOSConfig overrides.
|
||||
|
||||
This is intended as an example of overriding some of the default FreeRTOSConfig settings,
|
||||
which are otherwise found in FreeRTOS/Source/include/FreeRTOSConfig.h
|
||||
*/
|
||||
|
||||
/* The serial driver depends on counting semaphores */
|
||||
#define configUSE_COUNTING_SEMAPHORES 1
|
||||
|
||||
/* Use the defaults for everything else */
|
||||
#include_next<FreeRTOSConfig.h>
|
||||
|
3
examples/terminal/Makefile
Normal file
3
examples/terminal/Makefile
Normal file
|
@ -0,0 +1,3 @@
|
|||
PROGRAM=terminal
|
||||
EXTRA_COMPONENTS=extras/stdin_uart_interrupt
|
||||
include ../../common.mk
|
117
examples/terminal/terminal.c
Normal file
117
examples/terminal/terminal.c
Normal file
|
@ -0,0 +1,117 @@
|
|||
/* Serial terminal example
|
||||
* UART RX is interrupt driven
|
||||
* Implements a simple GPIO terminal for setting and clearing GPIOs
|
||||
*
|
||||
* This sample code is in the public domain.
|
||||
*/
|
||||
|
||||
#include <stdint.h>
|
||||
#include <sys/types.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
#include <esp8266.h>
|
||||
#include <esp/uart.h>
|
||||
#include <stdio.h>
|
||||
#include "FreeRTOS.h"
|
||||
#include "task.h"
|
||||
|
||||
#define MAX_ARGC (10)
|
||||
|
||||
static void cmd_on(uint32_t argc, char *argv[])
|
||||
{
|
||||
if (argc >= 2) {
|
||||
for(int i=1; i<argc; i++) {
|
||||
uint8_t gpio_num = atoi(argv[i]);
|
||||
gpio_enable(gpio_num, GPIO_OUTPUT);
|
||||
gpio_write(gpio_num, true);
|
||||
printf("On %d\n", gpio_num);
|
||||
}
|
||||
} else {
|
||||
printf("Error: missing gpio number.\n");
|
||||
}
|
||||
}
|
||||
|
||||
static void cmd_off(uint32_t argc, char *argv[])
|
||||
{
|
||||
if (argc >= 2) {
|
||||
for(int i=1; i<argc; i++) {
|
||||
uint8_t gpio_num = atoi(argv[i]);
|
||||
gpio_enable(gpio_num, GPIO_OUTPUT);
|
||||
gpio_write(gpio_num, false);
|
||||
printf("Off %d\n", gpio_num);
|
||||
}
|
||||
} else {
|
||||
printf("Error: missing gpio number.\n");
|
||||
}
|
||||
}
|
||||
|
||||
static void cmd_help(uint32_t argc, char *argv[])
|
||||
{
|
||||
printf("on <gpio number> [ <gpio number>]+ Set gpio to 1\n");
|
||||
printf("off <gpio number> [ <gpio number>]+ Set gpio to 0\n");
|
||||
printf("sleep Take a nap\n");
|
||||
printf("\nExample:\n");
|
||||
printf(" on 0<enter> switches on gpio 0\n");
|
||||
printf(" on 0 2 4<enter> switches on gpios 0, 2 and 4\n");
|
||||
}
|
||||
|
||||
static void cmd_sleep(uint32_t argc, char *argv[])
|
||||
{
|
||||
printf("Type away while I take a 2 second nap (ie. let you test the UART HW FIFO\n");
|
||||
vTaskDelay(2000 / portTICK_RATE_MS);
|
||||
}
|
||||
|
||||
static void handle_command(char *cmd)
|
||||
{
|
||||
char *argv[MAX_ARGC];
|
||||
int argc = 1;
|
||||
char *temp, *rover;
|
||||
memset((void*) argv, 0, sizeof(argv));
|
||||
argv[0] = cmd;
|
||||
rover = cmd;
|
||||
// Split string "<command> <argument 1> <argument 2> ... <argument N>"
|
||||
// into argv, argc style
|
||||
while(argc < MAX_ARGC && (temp = strstr(rover, " "))) {
|
||||
rover = &(temp[1]);
|
||||
argv[argc++] = rover;
|
||||
*temp = 0;
|
||||
}
|
||||
|
||||
if (strlen(argv[0]) > 0) {
|
||||
if (strcmp(argv[0], "help") == 0) cmd_help(argc, argv);
|
||||
else if (strcmp(argv[0], "on") == 0) cmd_on(argc, argv);
|
||||
else if (strcmp(argv[0], "off") == 0) cmd_off(argc, argv);
|
||||
else if (strcmp(argv[0], "sleep") == 0) cmd_sleep(argc, argv);
|
||||
else printf("Unknown command %s, try 'help'\n", argv[0]);
|
||||
}
|
||||
}
|
||||
|
||||
static void gpiomon()
|
||||
{
|
||||
char ch;
|
||||
char cmd[81];
|
||||
int i = 0;
|
||||
printf("\n\n\nWelcome to gpiomon. Type 'help<enter>' for, well, help\n");
|
||||
printf("%% ");
|
||||
while(1) {
|
||||
if (read(0, (void*)&ch, 1)) { // 0 is stdin
|
||||
printf("%c", ch);
|
||||
if (ch == '\n' || ch == '\r') {
|
||||
cmd[i] = 0;
|
||||
i = 0;
|
||||
printf("\n");
|
||||
handle_command((char*) cmd);
|
||||
printf("%% ");
|
||||
} else {
|
||||
if (i < sizeof(cmd)) cmd[i++] = ch;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void user_init(void)
|
||||
{
|
||||
uart_set_baud(0, 115200);
|
||||
gpiomon();
|
||||
}
|
4
examples/tls_server/Makefile
Normal file
4
examples/tls_server/Makefile
Normal file
|
@ -0,0 +1,4 @@
|
|||
PROGRAM=tls_server
|
||||
COMPONENTS = FreeRTOS lwip core extras/mbedtls
|
||||
|
||||
include ../../common.mk
|
65
examples/tls_server/cert.c
Normal file
65
examples/tls_server/cert.c
Normal file
|
@ -0,0 +1,65 @@
|
|||
/* This is the unencrypted RSA 2048-bit private key and certificate to use for the server, in PEM
|
||||
format, as dumped via:
|
||||
|
||||
openssl req -x509 -nodes -days 365 -sha256 -newkey rsa:2048 -keyout cert.pem -out cert.pem
|
||||
|
||||
... and then the relevant parts of the .pem file copied out into the strings below.
|
||||
*/
|
||||
#include <stdio.h>
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
|
||||
const char *server_key =
|
||||
"-----BEGIN PRIVATE KEY-----\r\n"
|
||||
"MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQCr5Pq7VARJJKa5\r\n"
|
||||
"gl68F2TJARsJ71fp4a48uVPwwtm7L7ili+qxhtB73AOjpiR/ZqJBkpMrSjbNdHPp\r\n"
|
||||
"vz9Bk164msv81DXzDuzn5QXuvbI87IFdnCM+I+xLSPCjBbPjPQsm7UJUG9pfjAAZ\r\n"
|
||||
"lF4KAN53OLpKOeu6ut7b0lHJ1H/YLeBOMcReTbObYa6QHO4+Rl7n9MMkDg1geCsW\r\n"
|
||||
"as6LznPVM1Jy7kh7IZZ3As+4dQ+V3VJ3/t/+lOK5O+WtAWZ96b7AHxc0DkgCLWz9\r\n"
|
||||
"+4fpRxHtjD4sA7nXEpgk6qYqS/8N0tHKQBC+uDSWxE3t0mF2Jr1D1gGlFy3VV5r2\r\n"
|
||||
"fEfWN74JAgMBAAECggEBAI7gB4v3HIzTOwVMmIOMikgMdDYAy7jpzZJJlLy0qJdO\r\n"
|
||||
"5hIrxwqB/P5GdHvsl7+RRmJse4jq6bxCBCqQvPo7jOqyN8VRefoqOL3S/ehfoivD\r\n"
|
||||
"hQ+SvTRkVX6KBQHrtoa1cXSMlqokcJEkY9zfFn8IE+FStH0Hwaj2tFBQc4zn5M+A\r\n"
|
||||
"jXsfySLT5dbQws/mJwn5DcuBtNqUBaYmUxRVOpiqbidmiszcqOEcfqfbL+fLmmhB\r\n"
|
||||
"mMdsKj79yUG98XtAwDo6zYqrt/KZ+Zty/9KIw1KLmYa2Cf6UWTCj4CKyVJuI0vy7\r\n"
|
||||
"pqFYC5a5C/MtLt+R6CgbcRey598NkpDZwOyt0BgdKoECgYEA1eDFq9qhMmxKNUtE\r\n"
|
||||
"K4e9u90xYNhSdKQV/XyXp+Fk0aSGuDdjLJm+q1i2KD6RfbuxCy41VPNs/EOlp6mP\r\n"
|
||||
"+fCTDVSrBLkOS/d2Dib/0XWi3o/Np6ZB9PZbU8tXqqKcaKmkhTOI/P3c+4Ap2xfD\r\n"
|
||||
"BtN/GBe5DRO7Nn60va3A0cSF2fECgYEAzb9+kFnEf13XGvk529wgDbl3tHsNrHRZ\r\n"
|
||||
"OW+fBNt/5D+H8Ky4m1Hkejk28q77fCQPRvf0LeNKCWq/rDLjjkC7EB5hDztHXFf0\r\n"
|
||||
"ptNLyOVnh16hSs4BrzLebfsSqMCYgWGxGJe3udxm+wPnMA5tf0rATY2B0wlZ90ew\r\n"
|
||||
"pjjK5BdbTZkCgYA0zLef9GpFG2y6eWlL4cfaQAH3qY+5keSH3qFF5aPRCW/kvG+0\r\n"
|
||||
"TARBIrZdewzJ4HMVkoPCBBJMuJqFqJuNlXGIIfXSRakc4et4FPKkkAj0LsYTdDzm\r\n"
|
||||
"L4deSV3MFzbLs82UwKM56aYLRJmQp+4SmlXO6dRaQRu/mUofZWyrnHt60QKBgQCC\r\n"
|
||||
"5eUAs4vXOH2k9JDB9w8RjEDDO1KcuD0X1JMIBRodvemfzlN4xaYluIbj6T2oYkyx\r\n"
|
||||
"6wiXtTYiPZ8KUCoEE9yvSZSYmy8waekFxgI+Iu0165eUPvJFY4it0gGyCS49ikig\r\n"
|
||||
"i83g2n9ODdKk+Vjilk04SeIhwJ5TO3IAnrs+WDnHaQKBgC5wQI35xrhJKD12SI2P\r\n"
|
||||
"VFdX3+5WUEIJ5Sivu5r2a5nPY+Ee2H5NuhWf742VFAg6YCfK1yYuK2v/vJ/haLiZ\r\n"
|
||||
"qBZe3F6B0UBfQnzUtVbenNliLj60SbBve3INDgTw2abm0v3Dcx4wbMT8w2ShiC83\r\n"
|
||||
"7Rr0nUhGs0IUayU5dLpd3qB1\r\n"
|
||||
"-----END PRIVATE KEY-----\r\n";
|
||||
|
||||
const char *server_cert =
|
||||
"-----BEGIN CERTIFICATE-----\r\n"
|
||||
"MIIDyTCCArGgAwIBAgIJAPEyjXMZ6kAsMA0GCSqGSIb3DQEBCwUAMHsxCzAJBgNV\r\n"
|
||||
"BAYTAkFVMQwwCgYDVQQIDANWaWMxEjAQBgNVBAcMCU1lbGJvdXJuZTEeMBwGA1UE\r\n"
|
||||
"CgwVZXNwLW9wZW4tcnRvcyBQdHkgTHRkMRwwGgYDVQQLDBNTbmFrZW9pbCBTYWxl\r\n"
|
||||
"cyBVbml0MQwwCgYDVQQDDANlc3AwHhcNMTYwMjA4MDM0NDU1WhcNMTcwMjA3MDM0\r\n"
|
||||
"NDU1WjB7MQswCQYDVQQGEwJBVTEMMAoGA1UECAwDVmljMRIwEAYDVQQHDAlNZWxi\r\n"
|
||||
"b3VybmUxHjAcBgNVBAoMFWVzcC1vcGVuLXJ0b3MgUHR5IEx0ZDEcMBoGA1UECwwT\r\n"
|
||||
"U25ha2VvaWwgU2FsZXMgVW5pdDEMMAoGA1UEAwwDZXNwMIIBIjANBgkqhkiG9w0B\r\n"
|
||||
"AQEFAAOCAQ8AMIIBCgKCAQEAq+T6u1QESSSmuYJevBdkyQEbCe9X6eGuPLlT8MLZ\r\n"
|
||||
"uy+4pYvqsYbQe9wDo6Ykf2aiQZKTK0o2zXRz6b8/QZNeuJrL/NQ18w7s5+UF7r2y\r\n"
|
||||
"POyBXZwjPiPsS0jwowWz4z0LJu1CVBvaX4wAGZReCgDedzi6Sjnrurre29JRydR/\r\n"
|
||||
"2C3gTjHEXk2zm2GukBzuPkZe5/TDJA4NYHgrFmrOi85z1TNScu5IeyGWdwLPuHUP\r\n"
|
||||
"ld1Sd/7f/pTiuTvlrQFmfem+wB8XNA5IAi1s/fuH6UcR7Yw+LAO51xKYJOqmKkv/\r\n"
|
||||
"DdLRykAQvrg0lsRN7dJhdia9Q9YBpRct1Vea9nxH1je+CQIDAQABo1AwTjAdBgNV\r\n"
|
||||
"HQ4EFgQUkg2t3waA/P/HYDEebQS/6NbWryEwHwYDVR0jBBgwFoAUkg2t3waA/P/H\r\n"
|
||||
"YDEebQS/6NbWryEwDAYDVR0TBAUwAwEB/zANBgkqhkiG9w0BAQsFAAOCAQEApIvY\r\n"
|
||||
"FN+ufDkqiGYwZygX4uo2ysAE3QtruwsFnna0+asat/TNlrFivif9pEW50pHnZV2+\r\n"
|
||||
"WZte/LgemeSwSqGekVSYGzbeZciuOdrnwadyBqGJoLTB+JjJRJqdlVR+OrVme0J2\r\n"
|
||||
"rBZkQ85/LZAZ8XoLDPopg++nU35NBEK5qImEWyUJb1TPUZbVKQu4aPi9ArprDnDd\r\n"
|
||||
"62UyNiDWvHx9yR2hDb9oI5jVnMHNLSCrD2baBVktFwPgJ2gdnPXOzhWHaLVKzl+7\r\n"
|
||||
"TMjIxLP6uepl7rg0P6j0UCYt7dSTLlb06wi0zWpUVErpP+sGOXYLDLfls+Ewofd9\r\n"
|
||||
"MYQhZNPFw+6LzuwWCA==\r\n"
|
||||
"-----END CERTIFICATE-----\r\n";
|
258
examples/tls_server/tls_server.c
Normal file
258
examples/tls_server/tls_server.c
Normal file
|
@ -0,0 +1,258 @@
|
|||
/* tls_server - simple TLS server that outputs some statistics to a connecting client,
|
||||
* then closes the socket.
|
||||
*
|
||||
* Similar to the the ssl_server example in mbedtls.
|
||||
*
|
||||
* To test this program, connect to the ESP using openssl command line like this:
|
||||
*
|
||||
* openssl s_client -connect 192.168.66.209:800
|
||||
*
|
||||
* The openssl command line client will print some information for the (self-signed) server certificate,
|
||||
* then after a couple of seconds (validation) there will be a few lines of text output sent from the ESP.
|
||||
*
|
||||
* See the cert.c file for private key & certificate (PEM format), plus information for generation.
|
||||
*
|
||||
* Original Copyright (C) 2006-2015, ARM Limited, All Rights Reserved, Apache 2.0 License.
|
||||
* Additions Copyright (C) 2016 Angus Gratton, Apache 2.0 License.
|
||||
*/
|
||||
#include "espressif/esp_common.h"
|
||||
#include "esp/uart.h"
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#include "FreeRTOS.h"
|
||||
#include "task.h"
|
||||
|
||||
#include "lwip/err.h"
|
||||
#include "lwip/sockets.h"
|
||||
#include "lwip/sys.h"
|
||||
#include "lwip/netdb.h"
|
||||
#include "lwip/dns.h"
|
||||
#include "lwip/api.h"
|
||||
|
||||
#include "ssid_config.h"
|
||||
|
||||
/* Server cert & key */
|
||||
extern const char *server_cert;
|
||||
extern const char *server_key;
|
||||
|
||||
/* mbedtls/config.h MUST appear before all other mbedtls headers, or
|
||||
you'll get the default config.
|
||||
|
||||
(Although mostly that isn't a big problem, you just might get
|
||||
errors at link time if functions don't exist.) */
|
||||
#include "mbedtls/config.h"
|
||||
|
||||
#include "mbedtls/net.h"
|
||||
#include "mbedtls/debug.h"
|
||||
#include "mbedtls/ssl.h"
|
||||
#include "mbedtls/entropy.h"
|
||||
#include "mbedtls/ctr_drbg.h"
|
||||
#include "mbedtls/error.h"
|
||||
#include "mbedtls/certs.h"
|
||||
|
||||
#define PORT "800"
|
||||
|
||||
void tls_server_task(void *pvParameters)
|
||||
{
|
||||
int successes = 0, failures = 0, ret;
|
||||
printf("TLS server task starting...\n");
|
||||
|
||||
const char *pers = "tls_server";
|
||||
|
||||
mbedtls_entropy_context entropy;
|
||||
mbedtls_ctr_drbg_context ctr_drbg;
|
||||
mbedtls_ssl_context ssl;
|
||||
mbedtls_x509_crt srvcert;
|
||||
mbedtls_pk_context pkey;
|
||||
mbedtls_ssl_config conf;
|
||||
mbedtls_net_context server_ctx;
|
||||
|
||||
/*
|
||||
* 0. Initialize the RNG and the session data
|
||||
*/
|
||||
mbedtls_ssl_init(&ssl);
|
||||
mbedtls_x509_crt_init(&srvcert);
|
||||
mbedtls_pk_init( &pkey );
|
||||
mbedtls_ctr_drbg_init(&ctr_drbg);
|
||||
printf("\n . Seeding the random number generator...");
|
||||
|
||||
mbedtls_ssl_config_init(&conf);
|
||||
|
||||
mbedtls_entropy_init(&entropy);
|
||||
if((ret = mbedtls_ctr_drbg_seed(&ctr_drbg, mbedtls_entropy_func, &entropy,
|
||||
(const unsigned char *) pers,
|
||||
strlen(pers))) != 0)
|
||||
{
|
||||
printf(" failed\n ! mbedtls_ctr_drbg_seed returned %d\n", ret);
|
||||
while(1) {} /* todo: replace with abort() */
|
||||
}
|
||||
|
||||
printf(" ok\n");
|
||||
|
||||
/*
|
||||
* 0. Initialize certificates
|
||||
*/
|
||||
printf(" . Loading the server certificate ...");
|
||||
|
||||
ret = mbedtls_x509_crt_parse(&srvcert, (uint8_t*)server_cert, strlen(server_cert)+1);
|
||||
if(ret < 0)
|
||||
{
|
||||
printf(" failed\n ! mbedtls_x509_crt_parse returned -0x%x\n\n", -ret);
|
||||
while(1) {} /* todo: replace with abort() */
|
||||
}
|
||||
|
||||
printf(" ok (%d skipped)\n", ret);
|
||||
|
||||
printf(" . Loading the server private key ...");
|
||||
ret = mbedtls_pk_parse_key(&pkey, (uint8_t *)server_key, strlen(server_key)+1, NULL, 0);
|
||||
if(ret != 0)
|
||||
{
|
||||
printf(" failed\n ! mbedtls_pk_parse_key returned - 0x%x\n\n", -ret);
|
||||
while(1) { } /*todo: replace with abort() */
|
||||
}
|
||||
|
||||
printf(" ok\n");
|
||||
|
||||
/*
|
||||
* 2. Setup stuff
|
||||
*/
|
||||
printf(" . Setting up the SSL/TLS structure...");
|
||||
|
||||
if((ret = mbedtls_ssl_config_defaults(&conf,
|
||||
MBEDTLS_SSL_IS_SERVER,
|
||||
MBEDTLS_SSL_TRANSPORT_STREAM,
|
||||
MBEDTLS_SSL_PRESET_DEFAULT)) != 0)
|
||||
{
|
||||
printf(" failed\n ! mbedtls_ssl_config_defaults returned %d\n\n", ret);
|
||||
goto exit;
|
||||
}
|
||||
|
||||
printf(" ok\n");
|
||||
|
||||
mbedtls_ssl_conf_ca_chain(&conf, srvcert.next, NULL);
|
||||
if( ( ret = mbedtls_ssl_conf_own_cert( &conf, &srvcert, &pkey ) ) != 0 )
|
||||
{
|
||||
printf( " failed\n ! mbedtls_ssl_conf_own_cert returned %d\n\n", ret );
|
||||
while(1) { }
|
||||
}
|
||||
|
||||
mbedtls_ssl_conf_rng(&conf, mbedtls_ctr_drbg_random, &ctr_drbg);
|
||||
#ifdef MBEDTLS_DEBUG_C
|
||||
mbedtls_debug_set_threshold(DEBUG_LEVEL);
|
||||
mbedtls_ssl_conf_dbg(&conf, my_debug, stdout);
|
||||
#endif
|
||||
|
||||
if((ret = mbedtls_ssl_setup(&ssl, &conf)) != 0)
|
||||
{
|
||||
printf(" failed\n ! mbedtls_ssl_setup returned %d\n\n", ret);
|
||||
goto exit;
|
||||
}
|
||||
|
||||
while(1) {
|
||||
mbedtls_net_context client_ctx;
|
||||
mbedtls_net_init(&server_ctx);
|
||||
mbedtls_net_init(&client_ctx);
|
||||
printf("top of loop, free heap = %u\n", xPortGetFreeHeapSize());
|
||||
|
||||
/*
|
||||
* 1. Start the connection
|
||||
*/
|
||||
ret = mbedtls_net_bind(&server_ctx, NULL, PORT, MBEDTLS_NET_PROTO_TCP);
|
||||
if(ret != 0)
|
||||
{
|
||||
printf(" failed\n ! mbedtls_net_bind returned %d\n\n", ret);
|
||||
goto exit;
|
||||
}
|
||||
|
||||
printf(" ok\n");
|
||||
|
||||
ret=mbedtls_net_accept(&server_ctx, &client_ctx, NULL, 0 , NULL);
|
||||
if( ret != 0 ){
|
||||
printf(" Failed to accept connection. Restarting.\n");
|
||||
mbedtls_net_free(&server_ctx);
|
||||
continue;
|
||||
}
|
||||
|
||||
mbedtls_ssl_set_bio(&ssl, &client_ctx, mbedtls_net_send, mbedtls_net_recv, NULL);
|
||||
|
||||
/*
|
||||
* 4. Handshake
|
||||
*/
|
||||
printf(" . Performing the SSL/TLS handshake...");
|
||||
|
||||
while((ret = mbedtls_ssl_handshake(&ssl)) != 0)
|
||||
{
|
||||
if(ret != MBEDTLS_ERR_SSL_WANT_READ && ret != MBEDTLS_ERR_SSL_WANT_WRITE)
|
||||
{
|
||||
printf(" failed\n ! mbedtls_ssl_handshake returned -0x%x\n\n", -ret);
|
||||
goto exit;
|
||||
}
|
||||
}
|
||||
|
||||
printf(" ok\n");
|
||||
|
||||
|
||||
/*
|
||||
* 3. Write the GET request
|
||||
*/
|
||||
printf(" > Writing status to new client... ");
|
||||
|
||||
struct sockaddr_in peer_addr;
|
||||
socklen_t peer_addr_len = sizeof(struct sockaddr_in);
|
||||
getpeername(client_ctx.fd, (struct sockaddr *)&peer_addr, &peer_addr_len);
|
||||
unsigned char buf[256];
|
||||
int len = sprintf((char *) buf, "O hai, client %d.%d.%d.%d:%d\nFree heap size is %d bytes\n",
|
||||
ip4_addr1(&peer_addr.sin_addr), ip4_addr2(&peer_addr.sin_addr),
|
||||
ip4_addr3(&peer_addr.sin_addr), ip4_addr4(&peer_addr.sin_addr),
|
||||
peer_addr.sin_port, xPortGetFreeHeapSize());
|
||||
while((ret = mbedtls_ssl_write(&ssl, buf, len)) <= 0)
|
||||
{
|
||||
if(ret != MBEDTLS_ERR_SSL_WANT_READ && ret != MBEDTLS_ERR_SSL_WANT_WRITE)
|
||||
{
|
||||
printf(" failed\n ! mbedtls_ssl_write returned %d\n\n", ret);
|
||||
goto exit;
|
||||
}
|
||||
}
|
||||
|
||||
len = ret;
|
||||
printf(" %d bytes written. Closing socket on client.\n\n%s", len, (char *) buf);
|
||||
|
||||
mbedtls_ssl_close_notify(&ssl);
|
||||
|
||||
exit:
|
||||
mbedtls_ssl_session_reset(&ssl);
|
||||
mbedtls_net_free(&client_ctx);
|
||||
mbedtls_net_free(&server_ctx);
|
||||
|
||||
if(ret != 0)
|
||||
{
|
||||
char error_buf[100];
|
||||
mbedtls_strerror(ret, error_buf, 100);
|
||||
printf("\n\nLast error was: %d - %s\n\n", ret, error_buf);
|
||||
failures++;
|
||||
} else {
|
||||
successes++;
|
||||
}
|
||||
|
||||
printf("\n\nsuccesses = %d failures = %d\n", successes, failures);
|
||||
printf("Waiting for next client...\n");
|
||||
}
|
||||
}
|
||||
|
||||
void user_init(void)
|
||||
{
|
||||
uart_set_baud(0, 115200);
|
||||
printf("SDK version:%s\n", sdk_system_get_sdk_version());
|
||||
|
||||
struct sdk_station_config config = {
|
||||
.ssid = WIFI_SSID,
|
||||
.password = WIFI_PASS,
|
||||
};
|
||||
|
||||
/* required to call wifi_set_opmode before station_set_config */
|
||||
sdk_wifi_set_opmode(STATION_MODE);
|
||||
sdk_wifi_station_set_config(&config);
|
||||
|
||||
xTaskCreate(&tls_server_task, (signed char *)"server_task", 2048, NULL, 2, NULL);
|
||||
}
|
6
examples/ws2812_rainbow/Makefile
Normal file
6
examples/ws2812_rainbow/Makefile
Normal file
|
@ -0,0 +1,6 @@
|
|||
# Makefile for the ws2812 Rainbow example
|
||||
|
||||
PROGRAM=ws2812_rainbow
|
||||
EXTRA_COMPONENTS = extras/ws2812
|
||||
|
||||
include ../../common.mk
|
153
examples/ws2812_rainbow/ws2812_rainbow.c
Normal file
153
examples/ws2812_rainbow/ws2812_rainbow.c
Normal file
|
@ -0,0 +1,153 @@
|
|||
/**
|
||||
* @file es2812_rainbow.c
|
||||
* @author Ondřej Hruška, 2016
|
||||
*
|
||||
* @brief Example of a rainbow effect with
|
||||
* WS2812 connected to GPIO2.
|
||||
*
|
||||
* This demo is in the public domain.
|
||||
*/
|
||||
|
||||
#include "espressif/esp_common.h"
|
||||
#include "FreeRTOS.h"
|
||||
#include "task.h"
|
||||
#include "esp/uart.h" // uart_set_baud
|
||||
#include <stdio.h> // printf
|
||||
#include <stdint.h>
|
||||
|
||||
#include "ws2812.h"
|
||||
|
||||
|
||||
#define delay_ms(ms) vTaskDelay((ms) / portTICK_RATE_MS)
|
||||
|
||||
|
||||
/** GPIO number used to control the RGBs */
|
||||
static const uint8_t pin = 2;
|
||||
|
||||
|
||||
/**
|
||||
* @brief "rainbow" animation with a single RGB led.
|
||||
*/
|
||||
void demo_single(void)
|
||||
{
|
||||
// duration between color changes
|
||||
const uint8_t delay = 25;
|
||||
|
||||
ws2812_rgb_t x = {.num = 0xFF0000}; // RED color
|
||||
|
||||
while (1) {
|
||||
// iterate through the spectrum
|
||||
|
||||
// note: This would be _WAY_ easier with HSL
|
||||
|
||||
while(x.g < 0xFF) { x.g++; ws2812_set(pin, x.num); delay_ms(delay); } // R->RG
|
||||
while(x.r > 0x00) { x.r--; ws2812_set(pin, x.num); delay_ms(delay); } // RG->G
|
||||
while(x.b < 0xFF) { x.b++; ws2812_set(pin, x.num); delay_ms(delay); } // G->GB
|
||||
while(x.g > 0x00) { x.g--; ws2812_set(pin, x.num); delay_ms(delay); } // GB->B
|
||||
while(x.r < 0xFF) { x.r++; ws2812_set(pin, x.num); delay_ms(delay); } // B->BR
|
||||
while(x.b > 0x00) { x.b--; ws2812_set(pin, x.num); delay_ms(delay); } // BR->R
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief "rainbow" effect on a RGB strip (30 pixels - can be adjusted)
|
||||
*
|
||||
* This example shows how to use the "procedural generation" of colors.
|
||||
*
|
||||
* The pixel colors are calculated on the fly, which saves RAM
|
||||
* (especially with large displays).
|
||||
*/
|
||||
void demo_strip(void *pvParameters)
|
||||
{
|
||||
const uint8_t anim_step = 10;
|
||||
const uint8_t anim_max = 250;
|
||||
|
||||
// Number of your "pixels"
|
||||
const uint8_t pixel_count = 30;
|
||||
|
||||
// duration between color changes
|
||||
const uint8_t delay = 25;
|
||||
|
||||
ws2812_rgb_t color = WS2812_RGB(anim_max, 0, 0);
|
||||
uint8_t step = 0;
|
||||
|
||||
ws2812_rgb_t color2 = WS2812_RGB(anim_max, 0, 0);
|
||||
uint8_t step2 = 0;
|
||||
|
||||
while (1) {
|
||||
|
||||
color = color2;
|
||||
step = step2;
|
||||
|
||||
// Start a data sequence (disables interrupts)
|
||||
ws2812_seq_start();
|
||||
|
||||
for (uint8_t i = 0; i < pixel_count; i++) {
|
||||
|
||||
// send a color
|
||||
ws2812_seq_rgb(pin, color.num);
|
||||
|
||||
// now we have a few hundred nanoseconds
|
||||
// to calculate the next color
|
||||
|
||||
if (i == 1) {
|
||||
color2 = color;
|
||||
step2 = step;
|
||||
}
|
||||
|
||||
switch (step) {
|
||||
case 0: color.g += anim_step; if (color.g >= anim_max) step++; break;
|
||||
case 1: color.r -= anim_step; if (color.r == 0) step++; break;
|
||||
case 2: color.b += anim_step; if (color.b >= anim_max) step++; break;
|
||||
case 3: color.g -= anim_step; if (color.g == 0) step++; break;
|
||||
case 4: color.r += anim_step; if (color.r >= anim_max) step++; break;
|
||||
case 5: color.b -= anim_step; if (color.b == 0) step = 0; break;
|
||||
}
|
||||
}
|
||||
|
||||
// End the data sequence, display colors (interrupts are restored)
|
||||
ws2812_seq_end();
|
||||
|
||||
// wait a bit
|
||||
delay_ms(delay);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void user_init(void)
|
||||
{
|
||||
uart_set_baud(0, 115200);
|
||||
printf("--- RGB Rainbow demo ---");
|
||||
|
||||
// Configure the GPIO
|
||||
gpio_enable(pin, GPIO_OUTPUT);
|
||||
|
||||
// Select a demo function:
|
||||
|
||||
#if true
|
||||
# define demo demo_strip
|
||||
#else
|
||||
# define demo demo_single
|
||||
#endif
|
||||
|
||||
|
||||
// Choose how to run it:
|
||||
|
||||
#if true
|
||||
|
||||
// Blocking function - works OK, because WiFi isn't
|
||||
// initialized yet & we're hogging the CPU.
|
||||
|
||||
printf("Starting a blocking function.\r\n");
|
||||
demo(NULL);
|
||||
|
||||
#else
|
||||
|
||||
// Start a task. This is a real-life example,
|
||||
// notice the glitches due to NMI.
|
||||
|
||||
printf("Starting a task. There may be glitches!\r\n");
|
||||
xTaskCreate(&demo, (signed char *)"strip demo", 256, NULL, 10, NULL);
|
||||
#endif
|
||||
}
|
9
extras/dhcpserver/component.mk
Normal file
9
extras/dhcpserver/component.mk
Normal file
|
@ -0,0 +1,9 @@
|
|||
# Component makefile for extras/dhcpserver
|
||||
|
||||
INC_DIRS += $(dhcpserver_ROOT)include
|
||||
|
||||
# args for passing into compile rule generation
|
||||
dhcpserver_INC_DIR = $(dhcpserver_ROOT)
|
||||
dhcpserver_SRC_DIR = $(dhcpserver_ROOT)
|
||||
|
||||
$(eval $(call component_compile_rules,dhcpserver))
|
370
extras/dhcpserver/dhcpserver.c
Normal file
370
extras/dhcpserver/dhcpserver.c
Normal file
|
@ -0,0 +1,370 @@
|
|||
/* Very basic LWIP & FreeRTOS-based DHCP server
|
||||
*
|
||||
* Based on RFC2131 http://www.ietf.org/rfc/rfc2131.txt
|
||||
* ... although not fully RFC compliant yet.
|
||||
*
|
||||
* TODO
|
||||
* * Allow binding on a single interface only (for mixed AP/client mode), lwip seems to make it hard to
|
||||
* listen for or send broadcasts on a specific interface only.
|
||||
*
|
||||
* * Probably allocates more memory than it should, it should be possible to reuse netbufs in most cases.
|
||||
*
|
||||
* Part of esp-open-rtos
|
||||
* Copyright (C) 2015 Superhouse Automation Pty Ltd
|
||||
* BSD Licensed as described in the file LICENSE
|
||||
*/
|
||||
#include <string.h>
|
||||
|
||||
#include <FreeRTOS.h>
|
||||
#include <task.h>
|
||||
#include <lwip/netif.h>
|
||||
#include <lwip/api.h>
|
||||
|
||||
/* Grow the size of the lwip dhcp_msg struct's options field, as LWIP
|
||||
defaults to a 68 octet options field for its DHCP client, and most
|
||||
full-sized clients send us more than this. */
|
||||
#define DHCP_OPTIONS_LEN 312
|
||||
|
||||
#include <lwip/dhcp.h>
|
||||
|
||||
_Static_assert(sizeof(struct dhcp_msg) == offsetof(struct dhcp_msg, options) + 312, "dhcp_msg_t should have extended options size");
|
||||
|
||||
#include <lwip/netbuf.h>
|
||||
|
||||
#include "dhcpserver.h"
|
||||
|
||||
typedef struct {
|
||||
uint8_t hwaddr[NETIF_MAX_HWADDR_LEN];
|
||||
uint32_t expires;
|
||||
} dhcp_lease_t;
|
||||
|
||||
typedef struct {
|
||||
struct netconn *nc;
|
||||
uint8_t max_leases;
|
||||
ip_addr_t first_client_addr;
|
||||
struct netif *server_if;
|
||||
dhcp_lease_t *leases; /* length max_leases */
|
||||
} server_state_t;
|
||||
|
||||
/* Only one DHCP server task can run at once, so we have global state
|
||||
for it.
|
||||
*/
|
||||
static xTaskHandle dhcpserver_task_handle;
|
||||
static server_state_t *state;
|
||||
|
||||
/* Handlers for various kinds of incoming DHCP messages */
|
||||
static void handle_dhcp_discover(struct dhcp_msg *received);
|
||||
static void handle_dhcp_request(struct dhcp_msg *dhcpmsg);
|
||||
static void handle_dhcp_release(struct dhcp_msg *dhcpmsg);
|
||||
|
||||
static void send_dhcp_nak(struct dhcp_msg *dhcpmsg);
|
||||
|
||||
static void dhcpserver_task(void *pxParameter);
|
||||
|
||||
/* Utility functions */
|
||||
static uint8_t *find_dhcp_option(struct dhcp_msg *msg, uint8_t option_num, uint8_t min_length, uint8_t *length);
|
||||
static uint8_t *add_dhcp_option_byte(uint8_t *opt, uint8_t type, uint8_t value);
|
||||
static uint8_t *add_dhcp_option_bytes(uint8_t *opt, uint8_t type, void *value, uint8_t len);
|
||||
static dhcp_lease_t *find_lease_slot(uint8_t *hwaddr);
|
||||
|
||||
/* Copy IP address as dotted decimal to 'dest', must be at least 16 bytes long */
|
||||
inline static void sprintf_ipaddr(const ip_addr_t *addr, char *dest)
|
||||
{
|
||||
if(addr == NULL)
|
||||
sprintf(dest, "NULL");
|
||||
else
|
||||
sprintf(dest, "%d.%d.%d.%d", ip4_addr1(addr),
|
||||
ip4_addr2(addr), ip4_addr3(addr), ip4_addr4(addr));
|
||||
}
|
||||
|
||||
void dhcpserver_start(const ip_addr_t *first_client_addr, uint8_t max_leases)
|
||||
{
|
||||
/* Stop any existing running dhcpserver */
|
||||
if(dhcpserver_task_handle)
|
||||
dhcpserver_stop();
|
||||
|
||||
state = malloc(sizeof(server_state_t));
|
||||
state->max_leases = max_leases;
|
||||
state->leases = calloc(max_leases, sizeof(dhcp_lease_t));
|
||||
// state->server_if is assigned once the task is running - see comment in dhcpserver_task()
|
||||
ip_addr_copy(state->first_client_addr, *first_client_addr);
|
||||
|
||||
xTaskCreate(dhcpserver_task, (signed char *)"DHCPServer", 768, NULL, 8, &dhcpserver_task_handle);
|
||||
}
|
||||
|
||||
void dhcpserver_stop(void)
|
||||
{
|
||||
if(dhcpserver_task_handle) {
|
||||
vTaskDelete(dhcpserver_task_handle);
|
||||
free(state);
|
||||
dhcpserver_task_handle = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
static void dhcpserver_task(void *pxParameter)
|
||||
{
|
||||
/* netif_list isn't assigned until after user_init completes, which is why we do it inside the task */
|
||||
state->server_if = netif_list; /* TODO: Make this configurable */
|
||||
|
||||
state->nc = netconn_new (NETCONN_UDP);
|
||||
if(!state->nc) {
|
||||
printf("OTA TFTP: Failed to allocate socket.\r\n");
|
||||
return;
|
||||
}
|
||||
|
||||
netconn_bind(state->nc, IP_ADDR_ANY, DHCP_SERVER_PORT);
|
||||
|
||||
while(1)
|
||||
{
|
||||
struct netbuf *netbuf;
|
||||
struct dhcp_msg received = { 0 };
|
||||
|
||||
/* Receive a DHCP packet */
|
||||
err_t err = netconn_recv(state->nc, &netbuf);
|
||||
if(err != ERR_OK) {
|
||||
printf("DHCP Server Error: Failed to receive DHCP packet. err=%d\r\n", err);
|
||||
continue;
|
||||
}
|
||||
|
||||
/* expire any leases that have passed */
|
||||
uint32_t now = xTaskGetTickCount();
|
||||
for(int i = 0; i < state->max_leases; i++) {
|
||||
uint32_t expires = state->leases[i].expires;
|
||||
if(expires && expires < now)
|
||||
state->leases[i].expires = 0;
|
||||
}
|
||||
|
||||
ip_addr_t received_ip;
|
||||
u16_t port;
|
||||
netconn_addr(state->nc, &received_ip, &port);
|
||||
|
||||
if(netbuf_len(netbuf) < offsetof(struct dhcp_msg, options)) {
|
||||
/* too short to be a valid DHCP client message */
|
||||
netbuf_delete(netbuf);
|
||||
continue;
|
||||
}
|
||||
if(netbuf_len(netbuf) >= sizeof(struct dhcp_msg)) {
|
||||
printf("DHCP Server Warning: Client sent more options than we know how to parse. len=%d\r\n", netbuf_len(netbuf));
|
||||
}
|
||||
|
||||
netbuf_copy(netbuf, &received, sizeof(struct dhcp_msg));
|
||||
netbuf_delete(netbuf);
|
||||
|
||||
uint8_t *message_type = find_dhcp_option(&received, DHCP_OPTION_MESSAGE_TYPE,
|
||||
DHCP_OPTION_MESSAGE_TYPE_LEN, NULL);
|
||||
if(!message_type) {
|
||||
printf("DHCP Server Error: No message type field found");
|
||||
continue;
|
||||
}
|
||||
|
||||
|
||||
printf("State dump. Message type %d\n", *message_type);
|
||||
for(int i = 0; i < state->max_leases; i++) {
|
||||
dhcp_lease_t *lease = &state->leases[i];
|
||||
printf("lease slot %d expiry %d hwaddr %02x:%02x:%02x:%02x:%02x:%02x\r\n", i, lease->expires, lease->hwaddr[0],
|
||||
lease->hwaddr[1], lease->hwaddr[2], lease->hwaddr[3], lease->hwaddr[4],
|
||||
lease->hwaddr[5]);
|
||||
}
|
||||
|
||||
switch(*message_type) {
|
||||
case DHCP_DISCOVER:
|
||||
handle_dhcp_discover(&received);
|
||||
break;
|
||||
case DHCP_REQUEST:
|
||||
handle_dhcp_request(&received);
|
||||
break;
|
||||
case DHCP_RELEASE:
|
||||
handle_dhcp_release(&received);
|
||||
default:
|
||||
printf("DHCP Server Error: Unsupported message type %d\r\n", *message_type);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void handle_dhcp_discover(struct dhcp_msg *dhcpmsg)
|
||||
{
|
||||
if(dhcpmsg->htype != DHCP_HTYPE_ETH)
|
||||
return;
|
||||
if(dhcpmsg->hlen > NETIF_MAX_HWADDR_LEN)
|
||||
return;
|
||||
|
||||
dhcp_lease_t *freelease = find_lease_slot(dhcpmsg->chaddr);
|
||||
if(!freelease) {
|
||||
printf("DHCP Server: All leases taken.\r\n");
|
||||
return; /* Nothing available, so do nothing */
|
||||
}
|
||||
|
||||
/* Reuse the DISCOVER buffer for the OFFER response */
|
||||
dhcpmsg->op = DHCP_BOOTREPLY;
|
||||
bzero(dhcpmsg->options, DHCP_OPTIONS_LEN);
|
||||
|
||||
ip_addr_copy(dhcpmsg->yiaddr, state->first_client_addr);
|
||||
ip4_addr4(&(dhcpmsg->yiaddr)) += (freelease - state->leases);
|
||||
|
||||
uint8_t *opt = (uint8_t *)&dhcpmsg->options;
|
||||
opt = add_dhcp_option_byte(opt, DHCP_OPTION_MESSAGE_TYPE, DHCP_OFFER);
|
||||
opt = add_dhcp_option_bytes(opt, DHCP_OPTION_SERVER_ID, &state->server_if->ip_addr, 4);
|
||||
opt = add_dhcp_option_bytes(opt, DHCP_OPTION_SUBNET_MASK, &state->server_if->netmask, 4);
|
||||
opt = add_dhcp_option_bytes(opt, DHCP_OPTION_END, NULL, 0);
|
||||
|
||||
struct netbuf *netbuf = netbuf_new();
|
||||
netbuf_alloc(netbuf, sizeof(struct dhcp_msg));
|
||||
netbuf_take(netbuf, dhcpmsg, sizeof(struct dhcp_msg));
|
||||
netconn_sendto(state->nc, netbuf, IP_ADDR_BROADCAST, 68);
|
||||
netbuf_delete(netbuf);
|
||||
}
|
||||
|
||||
static void handle_dhcp_request(struct dhcp_msg *dhcpmsg)
|
||||
{
|
||||
static char ipbuf[16];
|
||||
if(dhcpmsg->htype != DHCP_HTYPE_ETH)
|
||||
return;
|
||||
if(dhcpmsg->hlen > NETIF_MAX_HWADDR_LEN)
|
||||
return;
|
||||
|
||||
ip_addr_t requested_ip;
|
||||
uint8_t *requested_ip_opt = find_dhcp_option(dhcpmsg, DHCP_OPTION_REQUESTED_IP, 4, NULL);
|
||||
if(requested_ip_opt) {
|
||||
memcpy(&requested_ip.addr, requested_ip_opt, 4);
|
||||
} else if(ip_addr_cmp(&requested_ip, IP_ADDR_ANY)) {
|
||||
ip_addr_copy(requested_ip, dhcpmsg->ciaddr);
|
||||
} else {
|
||||
printf("DHCP Server Error: No requested IP\r\n");
|
||||
send_dhcp_nak(dhcpmsg);
|
||||
return;
|
||||
}
|
||||
|
||||
/* Test the first 4 octets match */
|
||||
if(ip4_addr1(&requested_ip) != ip4_addr1(&state->first_client_addr)
|
||||
|| ip4_addr2(&requested_ip) != ip4_addr2(&state->first_client_addr)
|
||||
|| ip4_addr3(&requested_ip) != ip4_addr3(&state->first_client_addr)) {
|
||||
sprintf_ipaddr(&requested_ip, ipbuf);
|
||||
printf("DHCP Server Error: %s not an allowed IP\r\n", ipbuf);
|
||||
send_dhcp_nak(dhcpmsg);
|
||||
return;
|
||||
}
|
||||
/* Test the last octet is in the MAXCLIENTS range */
|
||||
int16_t octet_offs = ip4_addr4(&requested_ip) - ip4_addr4(&state->first_client_addr);
|
||||
if(octet_offs < 0 || octet_offs >= state->max_leases) {
|
||||
printf("DHCP Server Error: Address out of range\r\n");
|
||||
send_dhcp_nak(dhcpmsg);
|
||||
return;
|
||||
}
|
||||
|
||||
dhcp_lease_t *requested_lease = state->leases + octet_offs;
|
||||
if(requested_lease->expires != 0 && memcmp(requested_lease->hwaddr, dhcpmsg->chaddr,dhcpmsg->hlen))
|
||||
{
|
||||
printf("DHCP Server Error: Lease for address already taken\r\n");
|
||||
send_dhcp_nak(dhcpmsg);
|
||||
return;
|
||||
}
|
||||
|
||||
memcpy(requested_lease->hwaddr, dhcpmsg->chaddr, dhcpmsg->hlen);
|
||||
sprintf_ipaddr(&requested_ip, ipbuf);
|
||||
printf("DHCP lease addr %s assigned to MAC %02x:%02x:%02x:%02x:%02x:%02x\r\n", ipbuf, requested_lease->hwaddr[0],
|
||||
requested_lease->hwaddr[1], requested_lease->hwaddr[2], requested_lease->hwaddr[3], requested_lease->hwaddr[4],
|
||||
requested_lease->hwaddr[5]);
|
||||
requested_lease->expires = DHCPSERVER_LEASE_TIME * configTICK_RATE_HZ;
|
||||
|
||||
/* Reuse the REQUEST message as the ACK message */
|
||||
dhcpmsg->op = DHCP_BOOTREPLY;
|
||||
bzero(dhcpmsg->options, DHCP_OPTIONS_LEN);
|
||||
|
||||
ip_addr_copy(dhcpmsg->yiaddr, requested_ip);
|
||||
|
||||
uint8_t *opt = (uint8_t *)&dhcpmsg->options;
|
||||
opt = add_dhcp_option_byte(opt, DHCP_OPTION_MESSAGE_TYPE, DHCP_ACK);
|
||||
uint32_t expiry = htonl(DHCPSERVER_LEASE_TIME);
|
||||
opt = add_dhcp_option_bytes(opt, DHCP_OPTION_LEASE_TIME, &expiry, 4);
|
||||
opt = add_dhcp_option_bytes(opt, DHCP_OPTION_SERVER_ID, &state->server_if->ip_addr, 4);
|
||||
opt = add_dhcp_option_bytes(opt, DHCP_OPTION_SUBNET_MASK, &state->server_if->netmask, 4);
|
||||
opt = add_dhcp_option_bytes(opt, DHCP_OPTION_END, NULL, 0);
|
||||
|
||||
struct netbuf *netbuf = netbuf_new();
|
||||
netbuf_alloc(netbuf, sizeof(struct dhcp_msg));
|
||||
netbuf_take(netbuf, dhcpmsg, sizeof(struct dhcp_msg));
|
||||
netconn_sendto(state->nc, netbuf, IP_ADDR_BROADCAST, 68);
|
||||
netbuf_delete(netbuf);
|
||||
}
|
||||
|
||||
static void handle_dhcp_release(struct dhcp_msg *dhcpmsg)
|
||||
{
|
||||
dhcp_lease_t *lease = find_lease_slot(dhcpmsg->chaddr);
|
||||
if(lease) {
|
||||
lease->expires = 0;
|
||||
}
|
||||
}
|
||||
|
||||
static void send_dhcp_nak(struct dhcp_msg *dhcpmsg)
|
||||
{
|
||||
/* Reuse 'dhcpmsg' for the NAK */
|
||||
dhcpmsg->op = DHCP_BOOTREPLY;
|
||||
bzero(dhcpmsg->options, DHCP_OPTIONS_LEN);
|
||||
|
||||
uint8_t *opt = (uint8_t *)&dhcpmsg->options;
|
||||
opt = add_dhcp_option_byte(opt, DHCP_OPTION_MESSAGE_TYPE, DHCP_NAK);
|
||||
opt = add_dhcp_option_bytes(opt, DHCP_OPTION_SERVER_ID, &state->server_if->ip_addr, 4);
|
||||
opt = add_dhcp_option_bytes(opt, DHCP_OPTION_END, NULL, 0);
|
||||
|
||||
struct netbuf *netbuf = netbuf_new();
|
||||
netbuf_alloc(netbuf, sizeof(struct dhcp_msg));
|
||||
netbuf_take(netbuf, dhcpmsg, sizeof(struct dhcp_msg));
|
||||
netconn_sendto(state->nc, netbuf, IP_ADDR_BROADCAST, 68);
|
||||
netbuf_delete(netbuf);
|
||||
}
|
||||
|
||||
static uint8_t *find_dhcp_option(struct dhcp_msg *msg, uint8_t option_num, uint8_t min_length, uint8_t *length)
|
||||
{
|
||||
uint8_t *start = (uint8_t *)&msg->options;
|
||||
uint8_t *msg_end = (uint8_t *)msg + sizeof(struct dhcp_msg);
|
||||
|
||||
for(uint8_t *p = start; p < msg_end-2;) {
|
||||
uint8_t type = *p++;
|
||||
uint8_t len = *p++;
|
||||
if(type == DHCP_OPTION_END)
|
||||
return NULL;
|
||||
if(p+len >= msg_end)
|
||||
break; /* We've overrun our valid DHCP message size, or this isn't a valid option */
|
||||
if(type == option_num) {
|
||||
if(len < min_length)
|
||||
break;
|
||||
if(length)
|
||||
*length = len;
|
||||
return p; /* start of actual option data */
|
||||
}
|
||||
p += len;
|
||||
}
|
||||
return NULL; /* Not found */
|
||||
}
|
||||
|
||||
static uint8_t *add_dhcp_option_byte(uint8_t *opt, uint8_t type, uint8_t value)
|
||||
{
|
||||
*opt++ = type;
|
||||
*opt++ = 1;
|
||||
*opt++ = value;
|
||||
return opt;
|
||||
}
|
||||
|
||||
static uint8_t *add_dhcp_option_bytes(uint8_t *opt, uint8_t type, void *value, uint8_t len)
|
||||
{
|
||||
*opt++ = type;
|
||||
if(len) {
|
||||
*opt++ = len;
|
||||
memcpy(opt, value, len);
|
||||
}
|
||||
return opt+len;
|
||||
}
|
||||
|
||||
/* Find a free DHCP lease, or a lease already assigned to 'hwaddr' */
|
||||
static dhcp_lease_t *find_lease_slot(uint8_t *hwaddr)
|
||||
{
|
||||
dhcp_lease_t *empty_lease = NULL;
|
||||
for(int i = 0; i < state->max_leases; i++) {
|
||||
if(state->leases[i].expires == 0 && !empty_lease)
|
||||
empty_lease = &state->leases[i];
|
||||
else if (memcmp(hwaddr, state->leases[i].hwaddr, 6) == 0)
|
||||
return &state->leases[i];
|
||||
}
|
||||
return empty_lease;
|
||||
}
|
33
extras/dhcpserver/include/dhcpserver.h
Normal file
33
extras/dhcpserver/include/dhcpserver.h
Normal file
|
@ -0,0 +1,33 @@
|
|||
/* Very basic LWIP & FreeRTOS-based DHCP server
|
||||
*
|
||||
* Header file contains default configuration for the DHCP server.
|
||||
*
|
||||
*
|
||||
* Part of esp-open-rtos
|
||||
* Copyright (C) 2015 Superhouse Automation Pty Ltd
|
||||
* BSD Licensed as described in the file LICENSE
|
||||
*/
|
||||
#ifndef _DHCPSERVER_H
|
||||
#define _DHCPSERVER_H
|
||||
|
||||
#ifndef DHCPSERVER_LEASE_TIME
|
||||
#define DHCPSERVER_LEASE_TIME 3600
|
||||
#endif
|
||||
|
||||
/* Start DHCP server.
|
||||
|
||||
Static IP of server should already be set and network interface enabled.
|
||||
|
||||
first_client_addr is the IP address of the first lease to be handed
|
||||
to a client. Subsequent lease addresses are calculated by
|
||||
incrementing the final octet of the IPv4 address, up to max_leases.
|
||||
*/
|
||||
void dhcpserver_start(const ip_addr_t *first_client_addr, uint8_t max_leases);
|
||||
|
||||
void dhcpserver_get_lease(const ip_addr_t *first_client_addr, uint8_t max_leases);
|
||||
|
||||
/* Stop DHCP server.
|
||||
*/
|
||||
void dhcpserver_stop(void);
|
||||
|
||||
#endif
|
9
extras/ds18b20/component.mk
Normal file
9
extras/ds18b20/component.mk
Normal file
|
@ -0,0 +1,9 @@
|
|||
# Component makefile for extras/ds18b20
|
||||
|
||||
# expected anyone using bmp driver includes it as 'ds18b20/ds18b20.h'
|
||||
INC_DIRS += $(ds18b20_ROOT)..
|
||||
|
||||
# args for passing into compile rule generation
|
||||
ds18b20_SRC_DIR = $(ds18b20_ROOT)
|
||||
|
||||
$(eval $(call component_compile_rules,ds18b20))
|
108
extras/ds18b20/ds18b20.c
Normal file
108
extras/ds18b20/ds18b20.c
Normal file
|
@ -0,0 +1,108 @@
|
|||
#include "FreeRTOS.h"
|
||||
#include "task.h"
|
||||
|
||||
#include "onewire/onewire.h"
|
||||
#include "ds18b20.h"
|
||||
|
||||
#define DS1820_WRITE_SCRATCHPAD 0x4E
|
||||
#define DS1820_READ_SCRATCHPAD 0xBE
|
||||
#define DS1820_COPY_SCRATCHPAD 0x48
|
||||
#define DS1820_READ_EEPROM 0xB8
|
||||
#define DS1820_READ_PWRSUPPLY 0xB4
|
||||
#define DS1820_SEARCHROM 0xF0
|
||||
#define DS1820_SKIP_ROM 0xCC
|
||||
#define DS1820_READROM 0x33
|
||||
#define DS1820_MATCHROM 0x55
|
||||
#define DS1820_ALARMSEARCH 0xEC
|
||||
#define DS1820_CONVERT_T 0x44
|
||||
|
||||
uint8_t ds18b20_read_all(uint8_t pin, ds_sensor_t *result) {
|
||||
|
||||
uint8_t addr[8];
|
||||
uint8_t sensor_id = 0;
|
||||
onewire_reset_search(pin);
|
||||
|
||||
while(onewire_search(pin, addr)){
|
||||
uint8_t crc = onewire_crc8(addr, 7);
|
||||
if (crc != addr[7]){
|
||||
printf("CRC check failed: %02X %02X\n", addr[7], crc);
|
||||
return 0;
|
||||
}
|
||||
|
||||
onewire_reset(pin);
|
||||
onewire_select(pin, addr);
|
||||
onewire_write(pin, DS1820_CONVERT_T, ONEWIRE_DEFAULT_POWER);
|
||||
|
||||
vTaskDelay(750 / portTICK_RATE_MS);
|
||||
|
||||
onewire_reset(pin);
|
||||
onewire_select(pin, addr);
|
||||
onewire_write(pin, DS1820_READ_SCRATCHPAD, ONEWIRE_DEFAULT_POWER);
|
||||
|
||||
uint8_t get[10];
|
||||
|
||||
for (int k=0;k<9;k++){
|
||||
get[k]=onewire_read(pin);
|
||||
}
|
||||
|
||||
//printf("\n ScratchPAD DATA = %X %X %X %X %X %X %X %X %X\n",get[8],get[7],get[6],get[5],get[4],get[3],get[2],get[1],get[0]);
|
||||
crc = onewire_crc8(get, 8);
|
||||
|
||||
if (crc != get[8]){
|
||||
printf("CRC check failed: %02X %02X\n", get[8], crc);
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint8_t temp_msb = get[1]; // Sign byte + lsbit
|
||||
uint8_t temp_lsb = get[0]; // Temp data plus lsb
|
||||
uint16_t temp = temp_msb << 8 | temp_lsb;
|
||||
|
||||
float temperature;
|
||||
|
||||
temperature = (temp * 625.0)/10000;
|
||||
//printf("Got a DS18B20 Reading: %d.%02d\n", (int)temperature, (int)(temperature - (int)temperature) * 100);
|
||||
result[sensor_id].id = sensor_id;
|
||||
result[sensor_id].value = temperature;
|
||||
sensor_id++;
|
||||
}
|
||||
return sensor_id;
|
||||
}
|
||||
|
||||
float ds18b20_read_single(uint8_t pin) {
|
||||
|
||||
onewire_reset(pin);
|
||||
|
||||
onewire_write(pin, DS1820_SKIP_ROM, ONEWIRE_DEFAULT_POWER);
|
||||
onewire_write(pin, DS1820_CONVERT_T, ONEWIRE_DEFAULT_POWER);
|
||||
|
||||
vTaskDelay(750 / portTICK_RATE_MS);
|
||||
|
||||
onewire_reset(pin);
|
||||
onewire_write(pin, DS1820_SKIP_ROM, ONEWIRE_DEFAULT_POWER);
|
||||
onewire_write(pin, DS1820_READ_SCRATCHPAD, ONEWIRE_DEFAULT_POWER);
|
||||
|
||||
uint8_t get[10];
|
||||
|
||||
for (int k=0;k<9;k++){
|
||||
get[k]=onewire_read(pin);
|
||||
}
|
||||
|
||||
//printf("\n ScratchPAD DATA = %X %X %X %X %X %X %X %X %X\n",get[8],get[7],get[6],get[5],get[4],get[3],get[2],get[1],get[0]);
|
||||
uint8_t crc = onewire_crc8(get, 8);
|
||||
|
||||
if (crc != get[8]){
|
||||
printf("CRC check failed: %02X %02X", get[8], crc);
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint8_t temp_msb = get[1]; // Sign byte + lsbit
|
||||
uint8_t temp_lsb = get[0]; // Temp data plus lsb
|
||||
|
||||
uint16_t temp = temp_msb << 8 | temp_lsb;
|
||||
|
||||
float temperature;
|
||||
|
||||
temperature = (temp * 625.0)/10000;
|
||||
return temperature;
|
||||
//printf("Got a DS18B20 Reading: %d.%02d\n", (int)temperature, (int)(temperature - (int)temperature) * 100);
|
||||
}
|
17
extras/ds18b20/ds18b20.h
Normal file
17
extras/ds18b20/ds18b20.h
Normal file
|
@ -0,0 +1,17 @@
|
|||
#ifndef DRIVER_DS18B20_H_
|
||||
#define DRIVER_DS18B20_H_
|
||||
|
||||
typedef struct {
|
||||
uint8_t id;
|
||||
float value;
|
||||
} ds_sensor_t;
|
||||
|
||||
// Scan all ds18b20 sensors on bus and return its amount.
|
||||
// Result are saved in array of ds_sensor_t structure.
|
||||
uint8_t ds18b20_read_all(uint8_t pin, ds_sensor_t *result);
|
||||
|
||||
// This method is just to demonstrate how to read
|
||||
// temperature from single dallas chip.
|
||||
float ds18b20_read_single(uint8_t pin);
|
||||
|
||||
#endif
|
|
@ -129,19 +129,41 @@ int mbedtls_net_connect( mbedtls_net_context *ctx, const char *host, const char
|
|||
int mbedtls_net_bind( mbedtls_net_context *ctx, const char *bind_ip, const char *port, int proto )
|
||||
{
|
||||
int n, ret;
|
||||
struct addrinfo hints, *addr_list, *cur;
|
||||
struct addrinfo *addr_list, *cur;
|
||||
|
||||
/* Only request desired protocol */
|
||||
const struct addrinfo hints = {
|
||||
.ai_family = AF_UNSPEC,
|
||||
.ai_socktype = (proto == MBEDTLS_NET_PROTO_UDP ? SOCK_DGRAM : SOCK_STREAM),
|
||||
.ai_protocol = (proto == MBEDTLS_NET_PROTO_UDP ? IPPROTO_UDP : IPPROTO_TCP),
|
||||
};
|
||||
|
||||
struct sockaddr_in sockaddr_ipaddr_any = {
|
||||
.sin_len = sizeof(struct sockaddr_in),
|
||||
.sin_family = AF_INET,
|
||||
.sin_port = htons(atoi(port)),
|
||||
.sin_addr = { IPADDR_ANY },
|
||||
};
|
||||
|
||||
struct addrinfo all_interfaces_addr = {
|
||||
.ai_family = AF_INET,
|
||||
.ai_socktype = hints.ai_socktype,
|
||||
.ai_protocol = hints.ai_protocol,
|
||||
.ai_addrlen = sizeof(struct sockaddr_in),
|
||||
.ai_addr = (struct sockaddr *)&sockaddr_ipaddr_any,
|
||||
};
|
||||
|
||||
if( ( ret = net_prepare() ) != 0 )
|
||||
return( ret );
|
||||
|
||||
/* Bind to IPv6 and/or IPv4, but only in the desired protocol */
|
||||
memset( &hints, 0, sizeof( hints ) );
|
||||
hints.ai_family = AF_UNSPEC;
|
||||
hints.ai_socktype = proto == MBEDTLS_NET_PROTO_UDP ? SOCK_DGRAM : SOCK_STREAM;
|
||||
hints.ai_protocol = proto == MBEDTLS_NET_PROTO_UDP ? IPPROTO_UDP : IPPROTO_TCP;
|
||||
|
||||
if( getaddrinfo( bind_ip, port, &hints, &addr_list ) != 0 )
|
||||
if(bind_ip == NULL) {
|
||||
/* mbedTLS docs specify bind_ip == NULL means all interfaces, but lwip getaddrinfo() assumes NULL
|
||||
means localhost. So we swap in a precreated IPADDR_ANY addrinfo result here. */
|
||||
addr_list = &all_interfaces_addr;
|
||||
}
|
||||
else if( getaddrinfo( bind_ip, port, &hints, &addr_list ) != 0 ) {
|
||||
return( MBEDTLS_ERR_NET_UNKNOWN_HOST );
|
||||
}
|
||||
|
||||
/* Try the sockaddrs until a binding succeeds */
|
||||
ret = MBEDTLS_ERR_NET_UNKNOWN_HOST;
|
||||
|
@ -187,7 +209,9 @@ int mbedtls_net_bind( mbedtls_net_context *ctx, const char *bind_ip, const char
|
|||
break;
|
||||
}
|
||||
|
||||
if(bind_ip != NULL) {
|
||||
freeaddrinfo( addr_list );
|
||||
}
|
||||
|
||||
return( ret );
|
||||
|
||||
|
|
31
extras/onewire/LICENSE
Normal file
31
extras/onewire/LICENSE
Normal file
|
@ -0,0 +1,31 @@
|
|||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2014 zeroday nodemcu.com
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
|
||||
Portions copyright (C) 2000 Dallas Semiconductor Corporation, under the
|
||||
following additional terms:
|
||||
|
||||
Except as contained in this notice, the name of Dallas Semiconductor
|
||||
shall not be used except as stated in the Dallas Semiconductor
|
||||
Branding Policy.
|
||||
|
14
extras/onewire/README.md
Normal file
14
extras/onewire/README.md
Normal file
|
@ -0,0 +1,14 @@
|
|||
# Yet another one wire driver for the ESP8266
|
||||
|
||||
This is a port of a bit-banging one wire driver based on the implementation
|
||||
from NodeMCU.
|
||||
|
||||
This, in turn, appears to have been based on the PJRC Teensy driver
|
||||
(https://www.pjrc.com/teensy/td_libs_OneWire.html), by Jim Studt, Paul
|
||||
Stoffregen, and a host of others.
|
||||
|
||||
The original code is licensed under the MIT license. The CRC code was taken
|
||||
(at least partially) from Dallas Semiconductor sample code, which was licensed
|
||||
under an MIT license with an additional clause (prohibiting inappropriate use
|
||||
of the Dallas Semiconductor name). See the accompanying LICENSE file for
|
||||
details.
|
10
extras/onewire/component.mk
Normal file
10
extras/onewire/component.mk
Normal file
|
@ -0,0 +1,10 @@
|
|||
# Component makefile for extras/onewire
|
||||
|
||||
# expected anyone using onewire driver includes it as 'onewire/onewire.h'
|
||||
INC_DIRS += $(onewire_ROOT)..
|
||||
|
||||
# args for passing into compile rule generation
|
||||
onewire_INC_DIR =
|
||||
onewire_SRC_DIR = $(onewire_ROOT)
|
||||
|
||||
$(eval $(call component_compile_rules,onewire))
|
466
extras/onewire/onewire.c
Normal file
466
extras/onewire/onewire.c
Normal file
|
@ -0,0 +1,466 @@
|
|||
#include "onewire.h"
|
||||
|
||||
// global search state
|
||||
static unsigned char ROM_NO[ONEWIRE_NUM][8];
|
||||
static uint8_t LastDiscrepancy[ONEWIRE_NUM];
|
||||
static uint8_t LastFamilyDiscrepancy[ONEWIRE_NUM];
|
||||
static uint8_t LastDeviceFlag[ONEWIRE_NUM];
|
||||
|
||||
void onewire_init(uint8_t pin)
|
||||
{
|
||||
gpio_enable(pin, GPIO_INPUT);
|
||||
onewire_reset_search(pin);
|
||||
}
|
||||
|
||||
// Perform the onewire reset function. We will wait up to 250uS for
|
||||
// the bus to come high, if it doesn't then it is broken or shorted
|
||||
// and we return a 0;
|
||||
//
|
||||
// Returns 1 if a device asserted a presence pulse, 0 otherwise.
|
||||
//
|
||||
uint8_t onewire_reset(uint8_t pin)
|
||||
{
|
||||
uint8_t r;
|
||||
uint8_t retries = 125;
|
||||
|
||||
noInterrupts();
|
||||
DIRECT_MODE_INPUT(pin);
|
||||
interrupts();
|
||||
// wait until the wire is high... just in case
|
||||
do {
|
||||
if (--retries == 0) return 0;
|
||||
delayMicroseconds(2);
|
||||
} while ( !DIRECT_READ(pin));
|
||||
|
||||
noInterrupts();
|
||||
DIRECT_WRITE_LOW(pin);
|
||||
DIRECT_MODE_OUTPUT(pin); // drive output low
|
||||
interrupts();
|
||||
delayMicroseconds(480);
|
||||
noInterrupts();
|
||||
DIRECT_MODE_INPUT(pin); // allow it to float
|
||||
delayMicroseconds(70);
|
||||
r = !DIRECT_READ(pin);
|
||||
interrupts();
|
||||
delayMicroseconds(410);
|
||||
return r;
|
||||
}
|
||||
|
||||
// Write a bit. Port and bit is used to cut lookup time and provide
|
||||
// more certain timing.
|
||||
//
|
||||
static void onewire_write_bit(uint8_t pin, uint8_t v)
|
||||
{
|
||||
if (v & 1) {
|
||||
noInterrupts();
|
||||
DIRECT_WRITE_LOW(pin);
|
||||
DIRECT_MODE_OUTPUT(pin); // drive output low
|
||||
delayMicroseconds(10);
|
||||
DIRECT_WRITE_HIGH(pin); // drive output high
|
||||
interrupts();
|
||||
delayMicroseconds(55);
|
||||
} else {
|
||||
noInterrupts();
|
||||
DIRECT_WRITE_LOW(pin);
|
||||
DIRECT_MODE_OUTPUT(pin); // drive output low
|
||||
delayMicroseconds(65);
|
||||
DIRECT_WRITE_HIGH(pin); // drive output high
|
||||
interrupts();
|
||||
delayMicroseconds(5);
|
||||
}
|
||||
}
|
||||
|
||||
// Read a bit. Port and bit is used to cut lookup time and provide
|
||||
// more certain timing.
|
||||
//
|
||||
static uint8_t onewire_read_bit(uint8_t pin)
|
||||
{
|
||||
uint8_t r;
|
||||
|
||||
noInterrupts();
|
||||
DIRECT_MODE_OUTPUT(pin);
|
||||
DIRECT_WRITE_LOW(pin);
|
||||
delayMicroseconds(3);
|
||||
DIRECT_MODE_INPUT(pin); // let pin float, pull up will raise
|
||||
delayMicroseconds(10);
|
||||
r = DIRECT_READ(pin);
|
||||
interrupts();
|
||||
delayMicroseconds(53);
|
||||
return r;
|
||||
}
|
||||
|
||||
// Write a byte. The writing code uses the active drivers to raise the
|
||||
// pin high, if you need power after the write (e.g. DS18S20 in
|
||||
// parasite power mode) then set 'power' to 1, otherwise the pin will
|
||||
// go tri-state at the end of the write to avoid heating in a short or
|
||||
// other mishap.
|
||||
//
|
||||
void onewire_write(uint8_t pin, uint8_t v, uint8_t power /* = 0 */) {
|
||||
uint8_t bitMask;
|
||||
|
||||
for (bitMask = 0x01; bitMask; bitMask <<= 1) {
|
||||
onewire_write_bit(pin, (bitMask & v)?1:0);
|
||||
}
|
||||
if ( !power) {
|
||||
noInterrupts();
|
||||
DIRECT_MODE_INPUT(pin);
|
||||
DIRECT_WRITE_LOW(pin);
|
||||
interrupts();
|
||||
}
|
||||
}
|
||||
|
||||
void onewire_write_bytes(uint8_t pin, const uint8_t *buf, uint16_t count, bool power /* = 0 */) {
|
||||
uint16_t i;
|
||||
for (i = 0 ; i < count ; i++)
|
||||
onewire_write(pin, buf[i], ONEWIRE_DEFAULT_POWER);
|
||||
if (!power) {
|
||||
noInterrupts();
|
||||
DIRECT_MODE_INPUT(pin);
|
||||
DIRECT_WRITE_LOW(pin);
|
||||
interrupts();
|
||||
}
|
||||
}
|
||||
|
||||
// Read a byte
|
||||
//
|
||||
uint8_t onewire_read(uint8_t pin) {
|
||||
uint8_t bitMask;
|
||||
uint8_t r = 0;
|
||||
|
||||
for (bitMask = 0x01; bitMask; bitMask <<= 1) {
|
||||
if (onewire_read_bit(pin)) r |= bitMask;
|
||||
}
|
||||
return r;
|
||||
}
|
||||
|
||||
void onewire_read_bytes(uint8_t pin, uint8_t *buf, uint16_t count) {
|
||||
uint16_t i;
|
||||
for (i = 0 ; i < count ; i++)
|
||||
buf[i] = onewire_read(pin);
|
||||
}
|
||||
|
||||
// Do a ROM select
|
||||
//
|
||||
void onewire_select(uint8_t pin, const uint8_t rom[8])
|
||||
{
|
||||
uint8_t i;
|
||||
|
||||
onewire_write(pin, 0x55, ONEWIRE_DEFAULT_POWER); // Choose ROM
|
||||
|
||||
for (i = 0; i < 8; i++) onewire_write(pin, rom[i], ONEWIRE_DEFAULT_POWER);
|
||||
}
|
||||
|
||||
// Do a ROM skip
|
||||
//
|
||||
void onewire_skip(uint8_t pin)
|
||||
{
|
||||
onewire_write(pin, 0xCC, ONEWIRE_DEFAULT_POWER); // Skip ROM
|
||||
}
|
||||
|
||||
void onewire_depower(uint8_t pin)
|
||||
{
|
||||
noInterrupts();
|
||||
DIRECT_MODE_INPUT(pin);
|
||||
interrupts();
|
||||
}
|
||||
|
||||
// You need to use this function to start a search again from the beginning.
|
||||
// You do not need to do it for the first search, though you could.
|
||||
//
|
||||
void onewire_reset_search(uint8_t pin)
|
||||
{
|
||||
// reset the search state
|
||||
LastDiscrepancy[pin] = 0;
|
||||
LastDeviceFlag[pin] = 0;
|
||||
LastFamilyDiscrepancy[pin] = 0;
|
||||
int i;
|
||||
for(i = 7; ; i--) {
|
||||
ROM_NO[pin][i] = 0;
|
||||
if ( i == 0) break;
|
||||
}
|
||||
}
|
||||
|
||||
// Setup the search to find the device type 'family_code' on the next call
|
||||
// to search(*newAddr) if it is present.
|
||||
//
|
||||
void onewire_target_search(uint8_t pin, uint8_t family_code)
|
||||
{
|
||||
// set the search state to find SearchFamily type devices
|
||||
ROM_NO[pin][0] = family_code;
|
||||
uint8_t i;
|
||||
for (i = 1; i < 8; i++)
|
||||
ROM_NO[pin][i] = 0;
|
||||
LastDiscrepancy[pin] = 64;
|
||||
LastFamilyDiscrepancy[pin] = 0;
|
||||
LastDeviceFlag[pin] = 0;
|
||||
}
|
||||
|
||||
// Perform a search. If this function returns a '1' then it has
|
||||
// enumerated the next device and you may retrieve the ROM from the
|
||||
// OneWire::address variable. If there are no devices, no further
|
||||
// devices, or something horrible happens in the middle of the
|
||||
// enumeration then a 0 is returned. If a new device is found then
|
||||
// its address is copied to newAddr. Use OneWire::reset_search() to
|
||||
// start over.
|
||||
//
|
||||
// --- Replaced by the one from the Dallas Semiconductor web site ---
|
||||
//--------------------------------------------------------------------------
|
||||
// Perform the 1-Wire Search Algorithm on the 1-Wire bus using the existing
|
||||
// search state.
|
||||
// Return 1 : device found, ROM number in ROM_NO buffer
|
||||
// 0 : device not found, end of search
|
||||
//
|
||||
uint8_t onewire_search(uint8_t pin, uint8_t *newAddr)
|
||||
{
|
||||
uint8_t id_bit_number;
|
||||
uint8_t last_zero, rom_byte_number, search_result;
|
||||
uint8_t id_bit, cmp_id_bit;
|
||||
|
||||
unsigned char rom_byte_mask, search_direction;
|
||||
|
||||
// initialize for search
|
||||
id_bit_number = 1;
|
||||
last_zero = 0;
|
||||
rom_byte_number = 0;
|
||||
rom_byte_mask = 1;
|
||||
search_result = 0;
|
||||
|
||||
// if the last call was not the last one
|
||||
if (!LastDeviceFlag[pin])
|
||||
{
|
||||
// 1-Wire reset
|
||||
if (!onewire_reset(pin))
|
||||
{
|
||||
// reset the search
|
||||
LastDiscrepancy[pin] = 0;
|
||||
LastDeviceFlag[pin] = 0;
|
||||
LastFamilyDiscrepancy[pin] = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
// issue the search command
|
||||
onewire_write(pin, 0xF0, ONEWIRE_DEFAULT_POWER);
|
||||
|
||||
// loop to do the search
|
||||
do
|
||||
{
|
||||
// read a bit and its complement
|
||||
id_bit = onewire_read_bit(pin);
|
||||
cmp_id_bit = onewire_read_bit(pin);
|
||||
|
||||
// check for no devices on 1-wire
|
||||
if ((id_bit == 1) && (cmp_id_bit == 1))
|
||||
break;
|
||||
else
|
||||
{
|
||||
// all devices coupled have 0 or 1
|
||||
if (id_bit != cmp_id_bit)
|
||||
search_direction = id_bit; // bit write value for search
|
||||
else
|
||||
{
|
||||
// if this discrepancy if before the Last Discrepancy
|
||||
// on a previous next then pick the same as last time
|
||||
if (id_bit_number < LastDiscrepancy[pin])
|
||||
search_direction = ((ROM_NO[pin][rom_byte_number] & rom_byte_mask) > 0);
|
||||
else
|
||||
// if equal to last pick 1, if not then pick 0
|
||||
search_direction = (id_bit_number == LastDiscrepancy[pin]);
|
||||
|
||||
// if 0 was picked then record its position in LastZero
|
||||
if (search_direction == 0)
|
||||
{
|
||||
last_zero = id_bit_number;
|
||||
|
||||
// check for Last discrepancy in family
|
||||
if (last_zero < 9)
|
||||
LastFamilyDiscrepancy[pin] = last_zero;
|
||||
}
|
||||
}
|
||||
|
||||
// set or clear the bit in the ROM byte rom_byte_number
|
||||
// with mask rom_byte_mask
|
||||
if (search_direction == 1)
|
||||
ROM_NO[pin][rom_byte_number] |= rom_byte_mask;
|
||||
else
|
||||
ROM_NO[pin][rom_byte_number] &= ~rom_byte_mask;
|
||||
|
||||
// serial number search direction write bit
|
||||
onewire_write_bit(pin, search_direction);
|
||||
|
||||
// increment the byte counter id_bit_number
|
||||
// and shift the mask rom_byte_mask
|
||||
id_bit_number++;
|
||||
rom_byte_mask <<= 1;
|
||||
|
||||
// if the mask is 0 then go to new SerialNum byte rom_byte_number and reset mask
|
||||
if (rom_byte_mask == 0)
|
||||
{
|
||||
rom_byte_number++;
|
||||
rom_byte_mask = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
while(rom_byte_number < 8); // loop until through all ROM bytes 0-7
|
||||
|
||||
// if the search was successful then
|
||||
if (!(id_bit_number < 65))
|
||||
{
|
||||
// search successful so set LastDiscrepancy,LastDeviceFlag,search_result
|
||||
LastDiscrepancy[pin] = last_zero;
|
||||
|
||||
// check for last device
|
||||
if (LastDiscrepancy[pin] == 0)
|
||||
LastDeviceFlag[pin] = 1;
|
||||
|
||||
search_result = 1;
|
||||
}
|
||||
}
|
||||
|
||||
// if no device found then reset counters so next 'search' will be like a first
|
||||
if (!search_result || !ROM_NO[pin][0])
|
||||
{
|
||||
LastDiscrepancy[pin] = 0;
|
||||
LastDeviceFlag[pin] = 0;
|
||||
LastFamilyDiscrepancy[pin] = 0;
|
||||
search_result = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
for (rom_byte_number = 0; rom_byte_number < 8; rom_byte_number++)
|
||||
{
|
||||
newAddr[rom_byte_number] = ROM_NO[pin][rom_byte_number];
|
||||
//printf("Ok I found something at %d - %x...\n",rom_byte_number, newAddr[rom_byte_number]);
|
||||
}
|
||||
}
|
||||
return search_result;
|
||||
}
|
||||
|
||||
// The 1-Wire CRC scheme is described in Maxim Application Note 27:
|
||||
// "Understanding and Using Cyclic Redundancy Checks with Maxim iButton Products"
|
||||
//
|
||||
|
||||
#if ONEWIRE_CRC8_TABLE
|
||||
// This table comes from Dallas sample code where it is freely reusable,
|
||||
// though Copyright (C) 2000 Dallas Semiconductor Corporation
|
||||
static const uint8_t dscrc_table[] = {
|
||||
0, 94,188,226, 97, 63,221,131,194,156,126, 32,163,253, 31, 65,
|
||||
157,195, 33,127,252,162, 64, 30, 95, 1,227,189, 62, 96,130,220,
|
||||
35,125,159,193, 66, 28,254,160,225,191, 93, 3,128,222, 60, 98,
|
||||
190,224, 2, 92,223,129, 99, 61,124, 34,192,158, 29, 67,161,255,
|
||||
70, 24,250,164, 39,121,155,197,132,218, 56,102,229,187, 89, 7,
|
||||
219,133,103, 57,186,228, 6, 88, 25, 71,165,251,120, 38,196,154,
|
||||
101, 59,217,135, 4, 90,184,230,167,249, 27, 69,198,152,122, 36,
|
||||
248,166, 68, 26,153,199, 37,123, 58,100,134,216, 91, 5,231,185,
|
||||
140,210, 48,110,237,179, 81, 15, 78, 16,242,172, 47,113,147,205,
|
||||
17, 79,173,243,112, 46,204,146,211,141,111, 49,178,236, 14, 80,
|
||||
175,241, 19, 77,206,144,114, 44,109, 51,209,143, 12, 82,176,238,
|
||||
50,108,142,208, 83, 13,239,177,240,174, 76, 18,145,207, 45,115,
|
||||
202,148,118, 40,171,245, 23, 73, 8, 86,180,234,105, 55,213,139,
|
||||
87, 9,235,181, 54,104,138,212,149,203, 41,119,244,170, 72, 22,
|
||||
233,183, 85, 11,136,214, 52,106, 43,117,151,201, 74, 20,246,168,
|
||||
116, 42,200,150, 21, 75,169,247,182,232, 10, 84,215,137,107, 53};
|
||||
|
||||
#ifndef pgm_read_byte
|
||||
#define pgm_read_byte(addr) (*(const uint8_t *)(addr))
|
||||
#endif
|
||||
|
||||
//
|
||||
// Compute a Dallas Semiconductor 8 bit CRC. These show up in the ROM
|
||||
// and the registers. (note: this might better be done without to
|
||||
// table, it would probably be smaller and certainly fast enough
|
||||
// compared to all those delayMicrosecond() calls. But I got
|
||||
// confused, so I use this table from the examples.)
|
||||
//
|
||||
uint8_t onewire_crc8(const uint8_t *addr, uint8_t len)
|
||||
{
|
||||
uint8_t crc = 0;
|
||||
|
||||
while (len--) {
|
||||
crc = pgm_read_byte(dscrc_table + (crc ^ *addr++));
|
||||
}
|
||||
return crc;
|
||||
}
|
||||
#else
|
||||
//
|
||||
// Compute a Dallas Semiconductor 8 bit CRC directly.
|
||||
// this is much slower, but much smaller, than the lookup table.
|
||||
//
|
||||
uint8_t onewire_crc8(const uint8_t *addr, uint8_t len)
|
||||
{
|
||||
uint8_t crc = 0;
|
||||
|
||||
while (len--) {
|
||||
uint8_t inbyte = *addr++;
|
||||
uint8_t i;
|
||||
for (i = 8; i; i--) {
|
||||
uint8_t mix = (crc ^ inbyte) & 0x01;
|
||||
crc >>= 1;
|
||||
if (mix) crc ^= 0x8C;
|
||||
inbyte >>= 1;
|
||||
}
|
||||
}
|
||||
return crc;
|
||||
}
|
||||
#endif
|
||||
|
||||
// Compute the 1-Wire CRC16 and compare it against the received CRC.
|
||||
// Example usage (reading a DS2408):
|
||||
// // Put everything in a buffer so we can compute the CRC easily.
|
||||
// uint8_t buf[13];
|
||||
// buf[0] = 0xF0; // Read PIO Registers
|
||||
// buf[1] = 0x88; // LSB address
|
||||
// buf[2] = 0x00; // MSB address
|
||||
// WriteBytes(net, buf, 3); // Write 3 cmd bytes
|
||||
// ReadBytes(net, buf+3, 10); // Read 6 data bytes, 2 0xFF, 2 CRC16
|
||||
// if (!CheckCRC16(buf, 11, &buf[11])) {
|
||||
// // Handle error.
|
||||
// }
|
||||
//
|
||||
// @param input - Array of bytes to checksum.
|
||||
// @param len - How many bytes to use.
|
||||
// @param inverted_crc - The two CRC16 bytes in the received data.
|
||||
// This should just point into the received data,
|
||||
// *not* at a 16-bit integer.
|
||||
// @param crc - The crc starting value (optional)
|
||||
// @return 1, iff the CRC matches.
|
||||
bool onewire_check_crc16(const uint8_t* input, uint16_t len, const uint8_t* inverted_crc, uint16_t crc)
|
||||
{
|
||||
crc = ~onewire_crc16(input, len, crc);
|
||||
return (crc & 0xFF) == inverted_crc[0] && (crc >> 8) == inverted_crc[1];
|
||||
}
|
||||
|
||||
// Compute a Dallas Semiconductor 16 bit CRC. This is required to check
|
||||
// the integrity of data received from many 1-Wire devices. Note that the
|
||||
// CRC computed here is *not* what you'll get from the 1-Wire network,
|
||||
// for two reasons:
|
||||
// 1) The CRC is transmitted bitwise inverted.
|
||||
// 2) Depending on the endian-ness of your processor, the binary
|
||||
// representation of the two-byte return value may have a different
|
||||
// byte order than the two bytes you get from 1-Wire.
|
||||
// @param input - Array of bytes to checksum.
|
||||
// @param len - How many bytes to use.
|
||||
// @param crc - The crc starting value (optional)
|
||||
// @return The CRC16, as defined by Dallas Semiconductor.
|
||||
uint16_t onewire_crc16(const uint8_t* input, uint16_t len, uint16_t crc)
|
||||
{
|
||||
static const uint8_t oddparity[16] =
|
||||
{ 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0 };
|
||||
|
||||
uint16_t i;
|
||||
for (i = 0 ; i < len ; i++) {
|
||||
// Even though we're just copying a byte from the input,
|
||||
// we'll be doing 16-bit computation with it.
|
||||
uint16_t cdata = input[i];
|
||||
cdata = (cdata ^ crc) & 0xff;
|
||||
crc >>= 8;
|
||||
|
||||
if (oddparity[cdata & 0x0F] ^ oddparity[cdata >> 4])
|
||||
crc ^= 0xC001;
|
||||
|
||||
cdata <<= 6;
|
||||
crc ^= cdata;
|
||||
cdata <<= 1;
|
||||
crc ^= cdata;
|
||||
}
|
||||
return crc;
|
||||
}
|
138
extras/onewire/onewire.h
Normal file
138
extras/onewire/onewire.h
Normal file
|
@ -0,0 +1,138 @@
|
|||
#ifndef __ONEWIRE_H__
|
||||
#define __ONEWIRE_H__
|
||||
|
||||
#include <espressif/esp_misc.h> // sdk_os_delay_us
|
||||
#include "FreeRTOS.h"
|
||||
|
||||
// 1 for keeping the parasitic power on H
|
||||
#define ONEWIRE_DEFAULT_POWER 1
|
||||
|
||||
// Maximum number of devices.
|
||||
#define ONEWIRE_NUM 20
|
||||
|
||||
// You can exclude certain features from OneWire. In theory, this
|
||||
// might save some space. In practice, the compiler automatically
|
||||
// removes unused code (technically, the linker, using -fdata-sections
|
||||
// and -ffunction-sections when compiling, and Wl,--gc-sections
|
||||
// when linking), so most of these will not result in any code size
|
||||
// reduction. Well, unless you try to use the missing features
|
||||
// and redesign your program to not need them! ONEWIRE_CRC8_TABLE
|
||||
// is the exception, because it selects a fast but large algorithm
|
||||
// or a small but slow algorithm.
|
||||
|
||||
// Select the table-lookup method of computing the 8-bit CRC
|
||||
// by setting this to 1. The lookup table enlarges code size by
|
||||
// about 250 bytes. It does NOT consume RAM (but did in very
|
||||
// old versions of OneWire). If you disable this, a slower
|
||||
// but very compact algorithm is used.
|
||||
#ifndef ONEWIRE_CRC8_TABLE
|
||||
#define ONEWIRE_CRC8_TABLE 0
|
||||
#endif
|
||||
|
||||
// Platform specific I/O definitions
|
||||
#define noInterrupts portDISABLE_INTERRUPTS
|
||||
#define interrupts portENABLE_INTERRUPTS
|
||||
#define delayMicroseconds sdk_os_delay_us
|
||||
|
||||
#define DIRECT_READ(pin) gpio_read(pin)
|
||||
#define DIRECT_MODE_INPUT(pin) gpio_enable(pin, GPIO_INPUT)
|
||||
#define DIRECT_MODE_OUTPUT(pin) gpio_enable(pin, GPIO_OUTPUT)
|
||||
#define DIRECT_WRITE_LOW(pin) gpio_write(pin, 0)
|
||||
#define DIRECT_WRITE_HIGH(pin) gpio_write(pin, 1)
|
||||
|
||||
void onewire_init(uint8_t pin);
|
||||
|
||||
// Perform a 1-Wire reset cycle. Returns 1 if a device responds
|
||||
// with a presence pulse. Returns 0 if there is no device or the
|
||||
// bus is shorted or otherwise held low for more than 250uS
|
||||
uint8_t onewire_reset(uint8_t pin);
|
||||
|
||||
// Issue a 1-Wire rom select command, you do the reset first.
|
||||
void onewire_select(uint8_t pin, const uint8_t rom[8]);
|
||||
|
||||
// Issue a 1-Wire rom skip command, to address all on bus.
|
||||
void onewire_skip(uint8_t pin);
|
||||
|
||||
// Write a byte. If 'power' is one then the wire is held high at
|
||||
// the end for parasitically powered devices. You are responsible
|
||||
// for eventually depowering it by calling depower() or doing
|
||||
// another read or write.
|
||||
void onewire_write(uint8_t pin, uint8_t v, uint8_t power);
|
||||
|
||||
void onewire_write_bytes(uint8_t pin, const uint8_t *buf, uint16_t count, bool power);
|
||||
|
||||
// Read a byte.
|
||||
uint8_t onewire_read(uint8_t pin);
|
||||
|
||||
void onewire_read_bytes(uint8_t pin, uint8_t *buf, uint16_t count);
|
||||
|
||||
// Write a bit. The bus is always left powered at the end, see
|
||||
// note in write() about that.
|
||||
// void onewire_write_bit(uint8_t pin, uint8_t v);
|
||||
|
||||
// Read a bit.
|
||||
// uint8_t onewire_read_bit(uint8_t pin);
|
||||
|
||||
// Stop forcing power onto the bus. You only need to do this if
|
||||
// you used the 'power' flag to write() or used a write_bit() call
|
||||
// and aren't about to do another read or write. You would rather
|
||||
// not leave this powered if you don't have to, just in case
|
||||
// someone shorts your bus.
|
||||
void onewire_depower(uint8_t pin);
|
||||
|
||||
// Clear the search state so that if will start from the beginning again.
|
||||
void onewire_reset_search(uint8_t pin);
|
||||
|
||||
// Setup the search to find the device type 'family_code' on the next call
|
||||
// to search(*newAddr) if it is present.
|
||||
void onewire_target_search(uint8_t pin, uint8_t family_code);
|
||||
|
||||
// Look for the next device. Returns 1 if a new address has been
|
||||
// returned. A zero might mean that the bus is shorted, there are
|
||||
// no devices, or you have already retrieved all of them. It
|
||||
// might be a good idea to check the CRC to make sure you didn't
|
||||
// get garbage. The order is deterministic. You will always get
|
||||
// the same devices in the same order.
|
||||
uint8_t onewire_search(uint8_t pin, uint8_t *newAddr);
|
||||
|
||||
// Compute a Dallas Semiconductor 8 bit CRC, these are used in the
|
||||
// ROM and scratchpad registers.
|
||||
uint8_t onewire_crc8(const uint8_t *addr, uint8_t len);
|
||||
|
||||
// Compute the 1-Wire CRC16 and compare it against the received CRC.
|
||||
// Example usage (reading a DS2408):
|
||||
// // Put everything in a buffer so we can compute the CRC easily.
|
||||
// uint8_t buf[13];
|
||||
// buf[0] = 0xF0; // Read PIO Registers
|
||||
// buf[1] = 0x88; // LSB address
|
||||
// buf[2] = 0x00; // MSB address
|
||||
// WriteBytes(net, buf, 3); // Write 3 cmd bytes
|
||||
// ReadBytes(net, buf+3, 10); // Read 6 data bytes, 2 0xFF, 2 CRC16
|
||||
// if (!CheckCRC16(buf, 11, &buf[11])) {
|
||||
// // Handle error.
|
||||
// }
|
||||
//
|
||||
// @param input - Array of bytes to checksum.
|
||||
// @param len - How many bytes to use.
|
||||
// @param inverted_crc - The two CRC16 bytes in the received data.
|
||||
// This should just point into the received data,
|
||||
// *not* at a 16-bit integer.
|
||||
// @param crc - The crc starting value (optional)
|
||||
// @return True, iff the CRC matches.
|
||||
bool onewire_check_crc16(const uint8_t* input, uint16_t len, const uint8_t* inverted_crc, uint16_t crc);
|
||||
|
||||
// Compute a Dallas Semiconductor 16 bit CRC. This is required to check
|
||||
// the integrity of data received from many 1-Wire devices. Note that the
|
||||
// CRC computed here is *not* what you'll get from the 1-Wire network,
|
||||
// for two reasons:
|
||||
// 1) The CRC is transmitted bitwise inverted.
|
||||
// 2) Depending on the endian-ness of your processor, the binary
|
||||
// representation of the two-byte return value may have a different
|
||||
// byte order than the two bytes you get from 1-Wire.
|
||||
// @param input - Array of bytes to checksum.
|
||||
// @param len - How many bytes to use.
|
||||
// @param crc - The crc starting value (optional)
|
||||
// @return The CRC16, as defined by Dallas Semiconductor.
|
||||
uint16_t onewire_crc16(const uint8_t* input, uint16_t len, uint16_t crc);
|
||||
|
||||
#endif
|
6
extras/pcf8574/component.mk
Normal file
6
extras/pcf8574/component.mk
Normal file
|
@ -0,0 +1,6 @@
|
|||
# Component makefile for extras/pcf8574
|
||||
|
||||
INC_DIRS += $(pcf8574_ROOT)..
|
||||
pcf8574_SRC_DIR = $(pcf8574_ROOT)
|
||||
|
||||
$(eval $(call component_compile_rules,pcf8574))
|
54
extras/pcf8574/pcf8574.c
Normal file
54
extras/pcf8574/pcf8574.c
Normal file
|
@ -0,0 +1,54 @@
|
|||
#include "pcf8574.h"
|
||||
#include <i2c/i2c.h>
|
||||
|
||||
uint8_t pcf8574_port_read(uint8_t addr)
|
||||
{
|
||||
i2c_start();
|
||||
uint8_t res = i2c_write((addr << 1) | 1) ? i2c_read(1) : 0;
|
||||
i2c_stop();
|
||||
return res;
|
||||
}
|
||||
|
||||
size_t pcf8574_port_read_buf(uint8_t addr, void *buf, size_t len)
|
||||
{
|
||||
if (!len || !buf) return 0;
|
||||
uint8_t *_buf = (uint8_t *)buf;
|
||||
|
||||
i2c_start();
|
||||
if (!i2c_write((addr << 1) | 1)) return 0;
|
||||
for (size_t i = 0; i < len; i++)
|
||||
*_buf++ = i2c_read(i == len - 1);
|
||||
i2c_stop();
|
||||
return len;
|
||||
}
|
||||
|
||||
size_t pcf8574_port_write_buf(uint8_t addr, void *buf, size_t len)
|
||||
{
|
||||
if (!len || !buf) return 0;
|
||||
uint8_t *_buf = (uint8_t *)buf;
|
||||
|
||||
i2c_start();
|
||||
if (!i2c_write(addr << 1)) return 0;
|
||||
for (size_t i = 0; i < len; i++)
|
||||
i2c_write(*_buf++);
|
||||
return len;
|
||||
}
|
||||
|
||||
void pcf8574_port_write(uint8_t addr, uint8_t value)
|
||||
{
|
||||
i2c_start();
|
||||
if (i2c_write(addr << 1)) i2c_write(value);
|
||||
i2c_stop();
|
||||
}
|
||||
|
||||
bool pcf8574_gpio_read(uint8_t addr, uint8_t num)
|
||||
{
|
||||
return (bool)((pcf8574_port_read(addr) >> num) & 1);
|
||||
}
|
||||
|
||||
void pcf8574_gpio_write(uint8_t addr, uint8_t num, bool value)
|
||||
{
|
||||
uint8_t bit = (uint8_t)value << num;
|
||||
uint8_t mask = ~(1 << num);
|
||||
pcf8574_port_write (addr, (pcf8574_port_read(addr) & mask) | bit);
|
||||
}
|
71
extras/pcf8574/pcf8574.h
Normal file
71
extras/pcf8574/pcf8574.h
Normal file
|
@ -0,0 +1,71 @@
|
|||
/**
|
||||
* \file Driver for PCF8574 compartible remote 8-bit I/O expanders for I2C-bus
|
||||
* \author Ruslan V. Uss
|
||||
*/
|
||||
#ifndef PCF8574_PCF8574_H_
|
||||
#define PCF8574_PCF8574_H_
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C"
|
||||
{
|
||||
#endif
|
||||
|
||||
/**
|
||||
* \brief Read GPIO port value
|
||||
* \param addr I2C register address (0b0100<A2><A1><A0> for PCF8574)
|
||||
* \return 8-bit GPIO port value
|
||||
*/
|
||||
uint8_t pcf8574_port_read(uint8_t addr);
|
||||
|
||||
/**
|
||||
* \brief Continiously read GPIO port values to buffer
|
||||
* @param addr I2C register address (0b0100<A2><A1><A0> for PCF8574)
|
||||
* @param buf Target buffer
|
||||
* @param len Buffer length
|
||||
* @return Number of bytes read
|
||||
*/
|
||||
size_t pcf8574_port_read_buf(uint8_t addr, void *buf, size_t len);
|
||||
|
||||
/**
|
||||
* \brief Write value to GPIO port
|
||||
* \param addr I2C register address (0b0100<A2><A1><A0> for PCF8574)
|
||||
* \param value GPIO port value
|
||||
*/
|
||||
void pcf8574_port_write(uint8_t addr, uint8_t value);
|
||||
|
||||
/**
|
||||
* \brief Continiously write GPIO values to GPIO port
|
||||
* \param addr I2C register address (0b0100<A2><A1><A0> for PCF8574)
|
||||
* @param buf Buffer with values
|
||||
* @param len Buffer length
|
||||
* @return Number of bytes written
|
||||
*/
|
||||
size_t pcf8574_port_write_buf(uint8_t addr, void *buf, size_t len);
|
||||
|
||||
/**
|
||||
* \brief Read input value of a GPIO pin
|
||||
* \param addr I2C register address (0b0100<A2><A1><A0> for PCF8574)
|
||||
* \param num pin number (0..7)
|
||||
* \return GPIO pin value
|
||||
*/
|
||||
bool pcf8574_gpio_read(uint8_t addr, uint8_t num);
|
||||
|
||||
/**
|
||||
* \brief Set GPIO pin output
|
||||
* Note this is READ - MODIFY - WRITE operation! Please read PCF8574
|
||||
* datasheet first.
|
||||
* \param addr I2C register address (0b0100<A2><A1><A0> for PCF8574)
|
||||
* \param num pin number (0..7)
|
||||
* \param value true for high level
|
||||
*/
|
||||
void pcf8574_gpio_write(uint8_t addr, uint8_t num, bool value);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* PCF8574_PCF8574_H_ */
|
9
extras/pwm/component.mk
Normal file
9
extras/pwm/component.mk
Normal file
|
@ -0,0 +1,9 @@
|
|||
# Component makefile for extras/pwm
|
||||
|
||||
INC_DIRS += $(ROOT)extras/pwm
|
||||
|
||||
# args for passing into compile rule generation
|
||||
extras/pwm_INC_DIR = $(ROOT)extras/pwm
|
||||
extras/pwm_SRC_DIR = $(ROOT)extras/pwm
|
||||
|
||||
$(eval $(call component_compile_rules,extras/pwm))
|
181
extras/pwm/pwm.c
Normal file
181
extras/pwm/pwm.c
Normal file
|
@ -0,0 +1,181 @@
|
|||
/* Implementation of PWM support for the Espressif SDK.
|
||||
*
|
||||
* Part of esp-open-rtos
|
||||
* Copyright (C) 2015 Guillem Pascual Ginovart (https://github.com/gpascualg)
|
||||
* Copyright (C) 2015 Javier Cardona (https://github.com/jcard0na)
|
||||
* BSD Licensed as described in the file LICENSE
|
||||
*/
|
||||
#include "pwm.h"
|
||||
|
||||
#include <espressif/esp_common.h>
|
||||
#include <espressif/sdk_private.h>
|
||||
#include <FreeRTOS.h>
|
||||
#include <esp8266.h>
|
||||
|
||||
typedef struct PWMPinDefinition
|
||||
{
|
||||
uint8_t pin;
|
||||
uint8_t divider;
|
||||
} PWMPin;
|
||||
|
||||
typedef enum {
|
||||
PERIOD_ON = 0,
|
||||
PERIOD_OFF = 1
|
||||
} pwm_step_t;
|
||||
|
||||
|
||||
typedef struct pwmInfoDefinition
|
||||
{
|
||||
uint8_t running;
|
||||
|
||||
uint16_t freq;
|
||||
uint16_t dutyCicle;
|
||||
|
||||
/* private */
|
||||
uint32_t _maxLoad;
|
||||
uint32_t _onLoad;
|
||||
uint32_t _offLoad;
|
||||
pwm_step_t _step;
|
||||
|
||||
uint16_t usedPins;
|
||||
PWMPin pins[8];
|
||||
} PWMInfo;
|
||||
|
||||
static PWMInfo pwmInfo;
|
||||
|
||||
static void frc1_interrupt_handler(void)
|
||||
{
|
||||
uint8_t i = 0;
|
||||
bool out = true;
|
||||
uint32_t load = pwmInfo._onLoad;
|
||||
pwm_step_t step = PERIOD_ON;
|
||||
|
||||
if (pwmInfo._step == PERIOD_ON)
|
||||
{
|
||||
out = false;
|
||||
load = pwmInfo._offLoad;
|
||||
step = PERIOD_OFF;
|
||||
}
|
||||
|
||||
for (; i < pwmInfo.usedPins; ++i)
|
||||
{
|
||||
gpio_write(pwmInfo.pins[i].pin, out);
|
||||
}
|
||||
|
||||
timer_set_load(FRC1, load);
|
||||
pwmInfo._step = step;
|
||||
}
|
||||
|
||||
void pwm_init(uint8_t npins, uint8_t* pins)
|
||||
{
|
||||
/* Assert number of pins is correct */
|
||||
if (npins > MAX_PWM_PINS)
|
||||
{
|
||||
printf("Incorrect number of PWM pins (%d)\n", npins);
|
||||
return;
|
||||
}
|
||||
|
||||
/* Initialize */
|
||||
pwmInfo._maxLoad = 0;
|
||||
pwmInfo._onLoad = 0;
|
||||
pwmInfo._offLoad = 0;
|
||||
pwmInfo._step = PERIOD_ON;
|
||||
|
||||
/* Save pins information */
|
||||
pwmInfo.usedPins = npins;
|
||||
|
||||
uint8_t i = 0;
|
||||
for (; i < npins; ++i)
|
||||
{
|
||||
pwmInfo.pins[i].pin = pins[i];
|
||||
|
||||
/* configure GPIOs */
|
||||
gpio_enable(pins[i], GPIO_OUTPUT);
|
||||
}
|
||||
|
||||
/* Stop timers and mask interrupts */
|
||||
pwm_stop();
|
||||
|
||||
/* set up ISRs */
|
||||
_xt_isr_attach(INUM_TIMER_FRC1, frc1_interrupt_handler);
|
||||
|
||||
/* Flag not running */
|
||||
pwmInfo.running = 0;
|
||||
}
|
||||
|
||||
void pwm_set_freq(uint16_t freq)
|
||||
{
|
||||
pwmInfo.freq = freq;
|
||||
|
||||
/* Stop now to avoid load being used */
|
||||
if (pwmInfo.running)
|
||||
{
|
||||
pwm_stop();
|
||||
pwmInfo.running = 1;
|
||||
}
|
||||
|
||||
timer_set_frequency(FRC1, freq);
|
||||
pwmInfo._maxLoad = timer_get_load(FRC1);
|
||||
|
||||
if (pwmInfo.running)
|
||||
{
|
||||
pwm_start();
|
||||
}
|
||||
}
|
||||
|
||||
void pwm_set_duty(uint16_t duty)
|
||||
{
|
||||
bool output;
|
||||
|
||||
pwmInfo.dutyCicle = duty;
|
||||
if (duty > 0 && duty < UINT16_MAX) {
|
||||
pwm_restart();
|
||||
return;
|
||||
}
|
||||
|
||||
// 0% and 100% duty cycle are special cases: constant output.
|
||||
pwm_stop();
|
||||
pwmInfo.running = 1;
|
||||
output = (duty == UINT16_MAX);
|
||||
for (uint8_t i = 0; i < pwmInfo.usedPins; ++i)
|
||||
{
|
||||
gpio_write(pwmInfo.pins[i].pin, output);
|
||||
}
|
||||
}
|
||||
|
||||
void pwm_restart()
|
||||
{
|
||||
if (pwmInfo.running)
|
||||
{
|
||||
pwm_stop();
|
||||
pwm_start();
|
||||
}
|
||||
}
|
||||
|
||||
void pwm_start()
|
||||
{
|
||||
pwmInfo._onLoad = pwmInfo.dutyCicle * pwmInfo._maxLoad / UINT16_MAX;
|
||||
pwmInfo._offLoad = pwmInfo._maxLoad - pwmInfo._onLoad;
|
||||
pwmInfo._step = PERIOD_ON;
|
||||
|
||||
// Trigger ON
|
||||
uint8_t i = 0;
|
||||
for (; i < pwmInfo.usedPins; ++i)
|
||||
{
|
||||
gpio_write(pwmInfo.pins[i].pin, true);
|
||||
}
|
||||
|
||||
timer_set_load(FRC1, pwmInfo._onLoad);
|
||||
timer_set_reload(FRC1, false);
|
||||
timer_set_interrupts(FRC1, true);
|
||||
timer_set_run(FRC1, true);
|
||||
|
||||
pwmInfo.running = 1;
|
||||
}
|
||||
|
||||
void pwm_stop()
|
||||
{
|
||||
timer_set_interrupts(FRC1, false);
|
||||
timer_set_run(FRC1, false);
|
||||
pwmInfo.running = 0;
|
||||
}
|
18
extras/pwm/pwm.h
Normal file
18
extras/pwm/pwm.h
Normal file
|
@ -0,0 +1,18 @@
|
|||
/* Implementation of PWM support for the Espressif SDK.
|
||||
*
|
||||
* Part of esp-open-rtos
|
||||
* Copyright (C) 2015 Guillem Pascual Ginovart (https://github.com/gpascualg)
|
||||
* Copyright (C) 2015 Javier Cardona (https://github.com/jcard0na)
|
||||
* BSD Licensed as described in the file LICENSE
|
||||
*/
|
||||
#include <stdint.h>
|
||||
|
||||
#define MAX_PWM_PINS 8
|
||||
|
||||
void pwm_init(uint8_t npins, uint8_t* pins);
|
||||
void pwm_set_freq(uint16_t freq);
|
||||
void pwm_set_duty(uint16_t duty);
|
||||
|
||||
void pwm_restart();
|
||||
void pwm_start();
|
||||
void pwm_stop();
|
21
extras/rboot-ota/license.txt
Normal file
21
extras/rboot-ota/license.txt
Normal file
|
@ -0,0 +1,21 @@
|
|||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2015 Richard A Burton (richardaburton@gmail.com)
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
|
@ -20,6 +20,8 @@
|
|||
* IMPORTANT: TFTP is not a secure protocol.
|
||||
* Only allow TFTP OTA updates on trusted networks.
|
||||
*
|
||||
*
|
||||
* For more details, see https://github.com/SuperHouse/esp-open-rtos/wiki/OTA-Update-Configuration
|
||||
*/
|
||||
|
||||
/* Start a FreeRTOS task to wait to receive an OTA update from a TFTP client.
|
||||
|
|
|
@ -1,3 +1,8 @@
|
|||
*NOTE: This rboot-ota and the TFTP server ota-tftp.h are specific to esp-open-rtos. The below Makefile is from the upstream rboot-ota project.*
|
||||
|
||||
For more details on OTA in esp-open-rtos, see https://github.com/SuperHouse/esp-open-rtos/wiki/OTA-Update-Configuration
|
||||
|
||||
|
||||
rBoot - User API and OTA support for rBoot on the ESP8266
|
||||
---------------------------------------------------------
|
||||
by Richard A Burton, richardaburton@gmail.com
|
||||
|
|
11
extras/stdin_uart_interrupt/README.txt
Normal file
11
extras/stdin_uart_interrupt/README.txt
Normal file
|
@ -0,0 +1,11 @@
|
|||
This module adds interrupt driven receive on UART 0. Using semaphores, a thread
|
||||
calling read(...) when no data is available will block in an RTOS expected
|
||||
manner until data arrives.
|
||||
|
||||
This allows for a background thread running a serial terminal in your program
|
||||
for debugging and state inspection consuming no CPU cycles at all. Not using
|
||||
this module will make that thread while(1) until data arrives.
|
||||
|
||||
No code changes are needed for adding this module, all you need to do is to add
|
||||
it to EXTRA_COMPONENTS and add the directive configUSE_COUNTING_SEMAPHORES from
|
||||
FreeRTOSConfig.h in examples/terminal to your project.
|
13
extras/stdin_uart_interrupt/component.mk
Normal file
13
extras/stdin_uart_interrupt/component.mk
Normal file
|
@ -0,0 +1,13 @@
|
|||
# Component makefile for extras/stdin_uart_interrupt
|
||||
#
|
||||
# See examples/terminal for usage. Well, actually there is no need to see it
|
||||
# for 'usage' as this module is a drop-in replacement for the original polled
|
||||
# version of reading from the UART.
|
||||
|
||||
INC_DIRS += $(ROOT)extras/stdin_uart_interrupt
|
||||
|
||||
# args for passing into compile rule generation
|
||||
extras/stdin_uart_interrupt_INC_DIR = $(ROOT)extras/stdin_uart_interrupt
|
||||
extras/stdin_uart_interrupt_SRC_DIR = $(ROOT)extras/stdin_uart_interrupt
|
||||
|
||||
$(eval $(call component_compile_rules,extras/stdin_uart_interrupt))
|
118
extras/stdin_uart_interrupt/stdin_uart_interrupt.c
Normal file
118
extras/stdin_uart_interrupt/stdin_uart_interrupt.c
Normal file
|
@ -0,0 +1,118 @@
|
|||
/*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2015 Johan Kanflo (github.com/kanflo)
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <esp8266.h>
|
||||
#include <FreeRTOS.h>
|
||||
#include <semphr.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#if (configUSE_COUNTING_SEMAPHORES == 0)
|
||||
#error "You need to define configUSE_COUNTING_SEMAPHORES in a local FreeRTOSConfig.h, see examples/terminal/FreeRTOSConfig.h"
|
||||
#endif
|
||||
|
||||
// IRQ driven UART RX driver for ESP8266 written for use with esp-open-rtos
|
||||
// TODO: Handle UART1
|
||||
|
||||
#ifndef UART0
|
||||
#define UART0 (0)
|
||||
#endif
|
||||
|
||||
#define UART0_RX_SIZE (128) // ESP8266 UART HW FIFO size
|
||||
|
||||
static xSemaphoreHandle uart0_sem = NULL;
|
||||
static bool inited = false;
|
||||
static void uart0_rx_init(void);
|
||||
|
||||
IRAM void uart0_rx_handler(void)
|
||||
{
|
||||
// TODO: Handle UART1, see reg 0x3ff20020, bit2, bit0 represents uart1 and uart0 respectively
|
||||
if (!UART(UART0).INT_STATUS & UART_INT_STATUS_RXFIFO_FULL) {
|
||||
return;
|
||||
}
|
||||
// printf(" [%08x (%d)]\n", READ_PERI_REG(UART_INT_ST(UART0)), READ_PERI_REG(UART_STATUS(UART0)) & (UART_RXFIFO_CNT << UART_RXFIFO_CNT_S));
|
||||
if (UART(UART0).INT_STATUS & UART_INT_STATUS_RXFIFO_FULL) {
|
||||
UART(UART0).INT_CLEAR = UART_INT_CLEAR_RXFIFO_FULL;
|
||||
if (UART(UART0).STATUS & (UART_STATUS_RXFIFO_COUNT_M << UART_STATUS_RXFIFO_COUNT_S)) {
|
||||
long int xHigherPriorityTaskWoken;
|
||||
_xt_isr_mask(1 << INUM_UART);
|
||||
_xt_clear_ints(1<<INUM_UART);
|
||||
xSemaphoreGiveFromISR(uart0_sem, &xHigherPriorityTaskWoken);
|
||||
if(xHigherPriorityTaskWoken) {
|
||||
portYIELD();
|
||||
}
|
||||
}
|
||||
} else {
|
||||
printf("Error: unexpected uart irq, INT_STATUS 0x%02x\n", UART(UART0).INT_STATUS);
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t uart0_num_char(void)
|
||||
{
|
||||
uint32_t count;
|
||||
if (!inited) uart0_rx_init();
|
||||
count = UART(UART0).STATUS & (UART_STATUS_RXFIFO_COUNT_M << UART_STATUS_RXFIFO_COUNT_S);
|
||||
return count;
|
||||
}
|
||||
|
||||
// _read_r in core/newlib_syscalls.c will be skipped by the linker in favour
|
||||
// of this function
|
||||
long _read_r(struct _reent *r, int fd, char *ptr, int len)
|
||||
{
|
||||
if (!inited) uart0_rx_init();
|
||||
for(int i = 0; i < len; i++) {
|
||||
if (!(UART(UART0).STATUS & (UART_STATUS_RXFIFO_COUNT_M << UART_STATUS_RXFIFO_COUNT_S))) {
|
||||
_xt_isr_unmask(1 << INUM_UART);
|
||||
if (!xSemaphoreTake(uart0_sem, portMAX_DELAY)) {
|
||||
printf("\nFailed to get sem\n");
|
||||
}
|
||||
}
|
||||
ptr[i] = UART(UART0).FIFO & (UART_FIFO_DATA_M << UART_FIFO_DATA_S);
|
||||
}
|
||||
return len;
|
||||
}
|
||||
|
||||
static void uart0_rx_init(void)
|
||||
{
|
||||
int trig_lvl = 1;
|
||||
uart0_sem = xSemaphoreCreateCounting(UART0_RX_SIZE, 0);
|
||||
|
||||
_xt_isr_attach(INUM_UART, uart0_rx_handler);
|
||||
_xt_isr_unmask(1 << INUM_UART);
|
||||
|
||||
// reset the rx fifo
|
||||
uint32_t conf = UART(UART0).CONF0;
|
||||
UART(UART0).CONF0 = conf | UART_CONF0_RXFIFO_RESET;
|
||||
UART(UART0).CONF0 = conf & ~UART_CONF0_RXFIFO_RESET;
|
||||
|
||||
// set rx fifo trigger
|
||||
UART(UART0).CONF1 |= (trig_lvl & UART_CONF1_RXFIFO_FULL_THRESHOLD_M) << UART_CONF1_RXFIFO_FULL_THRESHOLD_S;
|
||||
|
||||
// clear all interrupts
|
||||
UART(UART0).INT_CLEAR = 0x1ff;
|
||||
|
||||
// enable rx_interrupt
|
||||
UART(UART0).INT_ENABLE = UART_INT_ENABLE_RXFIFO_FULL;
|
||||
|
||||
inited = true;
|
||||
}
|
32
extras/stdin_uart_interrupt/stdin_uart_interrupt.h
Normal file
32
extras/stdin_uart_interrupt/stdin_uart_interrupt.h
Normal file
|
@ -0,0 +1,32 @@
|
|||
/*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2015 Johan Kanflo (github.com/kanflo)
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef __STDIN_UART_INTERRUPT_H__
|
||||
#define __STDIN_UART_INTERRUPT_H__
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
// Return number of characters waiting in UART0
|
||||
uint32_t uart0_num_char(void);
|
||||
#endif
|
8
extras/ws2812/component.mk
Normal file
8
extras/ws2812/component.mk
Normal file
|
@ -0,0 +1,8 @@
|
|||
# Component makefile for extras/ws2812
|
||||
|
||||
INC_DIRS += $(ws2812_ROOT)
|
||||
|
||||
# args for passing into compile rule generation
|
||||
ws2812_SRC_DIR = $(ws2812_ROOT)
|
||||
|
||||
$(eval $(call component_compile_rules,ws2812))
|
44
extras/ws2812/ws2812.c
Normal file
44
extras/ws2812/ws2812.c
Normal file
|
@ -0,0 +1,44 @@
|
|||
/**
|
||||
* @file ws2812b.c
|
||||
* @brief ESP8266 driver for WS2812B
|
||||
* @author Ondřej Hruška, (c) 2016
|
||||
*
|
||||
* MIT License
|
||||
*/
|
||||
|
||||
#include "espressif/esp_common.h" // sdk_os_delay_us
|
||||
#include "FreeRTOS.h"
|
||||
#include "task.h"
|
||||
#include <stdint.h>
|
||||
|
||||
#include "ws2812.h"
|
||||
|
||||
|
||||
/** Set one RGB LED color */
|
||||
void ws2812_set(uint8_t gpio_num, uint32_t rgb)
|
||||
{
|
||||
ws2812_seq_start();
|
||||
ws2812_seq_rgb(gpio_num, rgb);
|
||||
ws2812_seq_end();
|
||||
}
|
||||
|
||||
|
||||
/** Set many RGBs */
|
||||
void ws2812_set_many(uint8_t gpio_num, uint32_t *rgbs, size_t count)
|
||||
{
|
||||
ws2812_seq_start();
|
||||
|
||||
for (size_t i = 0; i < count; i++) {
|
||||
uint32_t rgb = *rgbs++;
|
||||
ws2812_seq_rgb(gpio_num, rgb);
|
||||
}
|
||||
|
||||
ws2812_seq_end();
|
||||
}
|
||||
|
||||
|
||||
/** Set one RGB to black (when used as indicator) */
|
||||
void ws2812_off(uint8_t gpio_num)
|
||||
{
|
||||
ws2812_set(gpio_num, 0x000000);
|
||||
}
|
208
extras/ws2812/ws2812.h
Normal file
208
extras/ws2812/ws2812.h
Normal file
|
@ -0,0 +1,208 @@
|
|||
/**
|
||||
* @file ws2812.h
|
||||
* @brief ESP8266 driver for WS2812
|
||||
*
|
||||
* This is a simple bit-banging driver for WS2812.
|
||||
*
|
||||
* It will work for WS2812, WS2812B and possibly others,
|
||||
* with small alterations.
|
||||
*
|
||||
* The WS2812 protocol takes roughly 1µs per bit,
|
||||
* thus ~24µs per "pixel", plus 50µs to indicate
|
||||
* the end of data.
|
||||
*
|
||||
* @note
|
||||
* The GPIO must be configured for output before trying
|
||||
* to set colors!
|
||||
*
|
||||
* @attention
|
||||
* Due to the precise timing required, interrupts are
|
||||
* disabled until the data is sent. However, we currently
|
||||
* can't disable the NMI, so under some conditions
|
||||
* (heavy network load), the timing may be disturbed.
|
||||
*
|
||||
* @author Ondřej Hruška, (c) 2016
|
||||
*
|
||||
* MIT License
|
||||
*/
|
||||
|
||||
#ifndef WS2812_DRV_H
|
||||
#define WS2812_DRV_H
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stddef.h> // size_t
|
||||
|
||||
#include "espressif/esp_common.h" // sdk_os_delay_us
|
||||
#include "esp/gpio.h"
|
||||
|
||||
/**
|
||||
* @brief Struct for easy manipulation of RGB colors.
|
||||
*
|
||||
* Set components in the xrgb.r (etc.) and you will get
|
||||
* the hex in xrgb.num.
|
||||
*/
|
||||
typedef union {
|
||||
|
||||
/** Struct for access to individual color components */
|
||||
struct __attribute__((packed)) {
|
||||
uint8_t b;
|
||||
uint8_t g;
|
||||
uint8_t r;
|
||||
};
|
||||
|
||||
/** RGB color as a single uint32_t */
|
||||
uint32_t num;
|
||||
|
||||
} ws2812_rgb_t;
|
||||
|
||||
|
||||
/**
|
||||
* @brief Macro to compose the RGB struct.
|
||||
*
|
||||
* You can also use {.num = 0xFF0000} to set the hex directly.
|
||||
*/
|
||||
#define WS2812_RGB(r, g, b) {.num = (((r) & 0xFF) << 16) | (((g) & 0xFF) << 8) | ((b) & 0xFF)}
|
||||
|
||||
|
||||
/**
|
||||
* @brief Set a single RGB LED color, and display it.
|
||||
*
|
||||
* @param gpio_num : data line GPIO number
|
||||
* @param rgb : RGB color - 0x00RRGGBB
|
||||
*/
|
||||
void ws2812_set(uint8_t gpio_num, uint32_t rgb);
|
||||
|
||||
|
||||
/**
|
||||
* @brief Set color of multiple RGB LEDs, and display it.
|
||||
*
|
||||
* @note
|
||||
* Due to the precise timing required, interrupts are
|
||||
* disabled until all data is sent (roughly 25*count + 50µs)
|
||||
*
|
||||
* @param gpio_num : data line GPIO number
|
||||
* @param rgbs : array of RGB colors in the 0x00RRGGBB format
|
||||
* @param count : number of elements in the array
|
||||
*/
|
||||
void ws2812_set_many(uint8_t gpio_num, uint32_t *rgbs, size_t count);
|
||||
|
||||
|
||||
/**
|
||||
* @brief Turn a single WS2812B off
|
||||
*
|
||||
* This is a companion function to ws2812_set().
|
||||
*
|
||||
* It sets the color to BLACK, thus effectively
|
||||
* turning the RGB LED off.
|
||||
*
|
||||
* @param gpio_num : data line GPIO number
|
||||
*/
|
||||
void ws2812_off(uint8_t gpio_num);
|
||||
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////
|
||||
///
|
||||
/// The following part of the driver is used internally, and can
|
||||
/// also be used for "procedural generation" of colors.
|
||||
///
|
||||
/// - first call ws2812b_seq_start(),
|
||||
/// - then repeatedly ws2812b_seq_rgb() with your colors
|
||||
/// - and end the sequence with ws2812b_seq_end()
|
||||
///
|
||||
///////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
|
||||
// Ugly way to get short delays. Works for 80 MHz.
|
||||
|
||||
// 400 ns
|
||||
#ifndef WS2812_SHORT_DELAY
|
||||
#define WS2812_SHORT_DELAY() for (volatile uint32_t __j = 1; __j > 0; __j--)
|
||||
#endif
|
||||
|
||||
// 800 ns
|
||||
#ifndef WS2812_LONG_DELAY
|
||||
#define WS2812_LONG_DELAY() for (volatile uint32_t __j = 3; __j > 0; __j--)
|
||||
#endif
|
||||
|
||||
|
||||
/**
|
||||
* @brief Send a byte on the data line.
|
||||
*
|
||||
* The WS2812B is a form of PWM:
|
||||
* - each bit takes roughly 1 µs (but can be longer)
|
||||
* - the duration of the ON part determines the value
|
||||
* - 800 ns -> "1"
|
||||
* - 400 ns -> "0"
|
||||
*
|
||||
* The timing must be very precise, you may need to adjust
|
||||
* it according for particular RGB model.
|
||||
*
|
||||
* @param gpio_num : data line GPIO number
|
||||
* @param byte : byte to send
|
||||
*/
|
||||
static inline
|
||||
void ws2812_byte(uint8_t gpio_num, uint8_t byte)
|
||||
{
|
||||
for (register volatile uint8_t i = 0; i < 8; i++) {
|
||||
gpio_write(gpio_num, 1);
|
||||
|
||||
// duty cycle determines the bit value
|
||||
|
||||
if (byte & 0x80) {
|
||||
WS2812_LONG_DELAY();
|
||||
gpio_write(gpio_num, 0);
|
||||
WS2812_SHORT_DELAY();
|
||||
} else {
|
||||
WS2812_SHORT_DELAY();
|
||||
gpio_write(gpio_num, 0);
|
||||
WS2812_LONG_DELAY();
|
||||
}
|
||||
|
||||
byte <<= 1; // shift to next bit
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief Send a color to the RGB strip.
|
||||
*
|
||||
* This function must be called inside the data sequence.
|
||||
*
|
||||
* @param gpio_num : data line GPIO number
|
||||
* @param rgb : 0xRRGGBB color
|
||||
*/
|
||||
static inline
|
||||
void ws2812_seq_rgb(uint8_t gpio_num, uint32_t rgb)
|
||||
{
|
||||
ws2812_byte(gpio_num, (rgb & 0x00FF00) >> 8);
|
||||
ws2812_byte(gpio_num, (rgb & 0xFF0000) >> 16);
|
||||
ws2812_byte(gpio_num, (rgb & 0x0000FF) >> 0);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief Start a data sequence.
|
||||
*/
|
||||
static inline
|
||||
void ws2812_seq_start(void)
|
||||
{
|
||||
// interruption when sending data would break the timing
|
||||
taskENTER_CRITICAL();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief End the data sequence and display the colors.
|
||||
*/
|
||||
static inline
|
||||
void ws2812_seq_end(void)
|
||||
{
|
||||
taskEXIT_CRITICAL();
|
||||
|
||||
sdk_os_delay_us(50); // display the loaded colors
|
||||
}
|
||||
|
||||
|
||||
#endif /* WS2812_DRV_H */
|
|
@ -35,7 +35,7 @@ struct sdk_scan_config {
|
|||
};
|
||||
|
||||
struct sdk_bss_info {
|
||||
STAILQ_ENTRY(bss_info) next;
|
||||
STAILQ_ENTRY(sdk_bss_info) next;
|
||||
|
||||
uint8_t bssid[6];
|
||||
uint8_t ssid[32];
|
||||
|
|
|
@ -42,6 +42,7 @@ enum sdk_sleep_type sdk_wifi_get_sleep_type(enum sdk_sleep_type);
|
|||
|
||||
void sdk_system_restore(void);
|
||||
void sdk_system_restart(void);
|
||||
bool sdk_system_deep_sleep_set_option(uint8_t option);
|
||||
void sdk_system_deep_sleep(uint32_t time_in_us);
|
||||
|
||||
uint32_t sdk_system_get_time(void);
|
||||
|
@ -57,6 +58,25 @@ bool sdk_system_rtc_mem_read(uint8_t src, void *dst, uint16_t n);
|
|||
bool sdk_system_rtc_mem_write(uint8_t dst, const void *src, uint16_t n);
|
||||
|
||||
void sdk_system_uart_swap(void);
|
||||
void sdk_system_uart_de_swap(void);
|
||||
|
||||
#define SYS_CPU_80MHZ 80
|
||||
#define SYS_CPU_160MHZ 160
|
||||
/*
|
||||
Set CPU frequency in MHz. All peripheral devices are clocked by independent
|
||||
system bus, and CPU frequency change will not affect them.
|
||||
*/
|
||||
bool sdk_system_update_cpu_freq(uint8_t freq);
|
||||
uint8_t sdk_system_get_cpu_freq(void);
|
||||
|
||||
/*
|
||||
Measure voltage on the TOUT pin, 1V max. Returns 10 bits ADC value (1/1024V).
|
||||
Voltage range 0 .. 1.0V. RF must be enabled.
|
||||
Example:
|
||||
printf ("ADC voltage is %.3f", 1.0 / 1024 * sdk_system_adc_read());
|
||||
*/
|
||||
uint16_t sdk_system_adc_read(void);
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
|
|
@ -23,9 +23,48 @@ typedef enum {
|
|||
uint32_t sdk_spi_flash_get_id(void);
|
||||
sdk_SpiFlashOpResult sdk_spi_flash_read_status(uint32_t *status);
|
||||
sdk_SpiFlashOpResult sdk_spi_flash_write_status(uint32_t status_value);
|
||||
|
||||
/* Erase SPI flash sector. Parameter is sector index.
|
||||
|
||||
Sectors are SPI_FLASH_SEC_SIZE (4096) bytes long.
|
||||
*/
|
||||
sdk_SpiFlashOpResult sdk_spi_flash_erase_sector(uint16_t sec);
|
||||
sdk_SpiFlashOpResult sdk_spi_flash_write(uint32_t des_addr, uint32_t *src_addr, uint32_t size);
|
||||
sdk_SpiFlashOpResult sdk_spi_flash_read(uint32_t src_addr, uint32_t *des_addr, uint32_t size);
|
||||
|
||||
/* Write data to flash.
|
||||
|
||||
des_addr is byte offset to write to. Should be 4-byte aligned.
|
||||
src is pointer to a buffer to read bytes from.
|
||||
size is length of buffer in bytes. Should be a multiple of 4.
|
||||
*/
|
||||
sdk_SpiFlashOpResult sdk_spi_flash_write(uint32_t des_addr, const void *src, uint32_t size);
|
||||
|
||||
/* Read data from flash.
|
||||
|
||||
src_addr is byte offset to read from. Should be 4-byte aligned.
|
||||
des is pointer to a buffer to read bytes into.
|
||||
size is number of bytes to read. Should be a multiple of 4.
|
||||
*/
|
||||
sdk_SpiFlashOpResult sdk_spi_flash_read(uint32_t src_addr, void *des, uint32_t size);
|
||||
|
||||
|
||||
/* SDK uses this structure internally to account for flash size.
|
||||
|
||||
chip_size field is initialised during startup from the flash size
|
||||
saved in the image header (on the first 8 bytes of SPI flash).
|
||||
|
||||
Other field are initialised to hardcoded values by the SDK.
|
||||
|
||||
Based on RE work by @foogod at
|
||||
http://esp8266-re.foogod.com/wiki/Flashchip_%28IoT_RTOS_SDK_0.9.9%29
|
||||
*/
|
||||
typedef struct {
|
||||
uint32_t device_id;
|
||||
uint32_t chip_size; /* in bytes */
|
||||
uint32_t block_size; /* in bytes */
|
||||
uint32_t sector_size; /* in bytes */
|
||||
uint32_t page_size; /* in bytes */
|
||||
uint32_t status_mask;
|
||||
} sdk_flashchip_t;
|
||||
|
||||
extern sdk_flashchip_t sdk_flashchip;
|
||||
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
/* This linker script generated from xt-genldscripts.tpp for LSP .
|
||||
|
||||
Modified for esp open RTOS, this linker script is no longer the same as the esp_iot_rtos_sdk one.
|
||||
*/
|
||||
/*
|
||||
* Common (OTA and non-OTA) parts for the esp-open-rtos Linker Script
|
||||
*
|
||||
*/
|
||||
|
||||
/* FreeRTOS memory management functions
|
||||
|
||||
|
@ -28,56 +28,6 @@ _lock_release_recursive = vPortExitCritical;
|
|||
/* SDK compatibility */
|
||||
ets_printf = printf;
|
||||
|
||||
/* Evaluate FLASH_SIZE to calculate irom size, etc.
|
||||
*/
|
||||
#ifndef OTA
|
||||
|
||||
#define IROM0_START 0x40220000
|
||||
|
||||
/* Non-OTA sizes */
|
||||
#if FLASH_SIZE == 2 /* 256kB */
|
||||
#define IROM0_LEN 0x3C000
|
||||
#elif FLASH_SIZE == 4 /* 512kB */
|
||||
#define IROM0_LEN 0x7C000
|
||||
#elif FLASH_SIZE == 8 /* 1MB */
|
||||
#define IROM0_LEN 0xFC000
|
||||
#elif FLASH_SIZE == 16 /* 2MB */
|
||||
#define IROM0_LEN 0x1FC000
|
||||
#elif FLASH_SIZE == 32 /* 4MB */
|
||||
#define IROM0_LEN 0x3FC000
|
||||
#else /*FLASH_SIZE*/
|
||||
#error "Unknown flash size for linker script. Check the FLASH_SIZE variable in your Makefile."
|
||||
#endif
|
||||
|
||||
#else /* OTA */
|
||||
|
||||
/* IROM0 becomes an actual "section" of the bootloader image, so we need to leave
|
||||
space for the bootloader (0x2000 bytes) and space for the bootloader & section
|
||||
headers (0x10 bytes)
|
||||
*/
|
||||
#define IROM0_START 0x40202010
|
||||
|
||||
/* OTA sizes */
|
||||
#if FLASH_SIZE < 16
|
||||
#error "OTA support currently requires 16 or 32 megabit flash"
|
||||
#elif FLASH_SIZE == 16 || FLASH_SIZE == 32
|
||||
/* 1MB irom0 section regardless, minus the space for the bootloader */
|
||||
#define IROM0_LEN (0x100000 - 0x2010)
|
||||
#else /*FLASH_SIZE*/
|
||||
#error "Unknown flash size for linker script. Check the FLASH_SIZE variable in your Makefile."
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
/* Linker Script for ld -N */
|
||||
MEMORY
|
||||
{
|
||||
dport0_0_seg : org = 0x3FF00000, len = 0x10
|
||||
dram0_0_seg : org = 0x3FFE8000, len = 0x14000
|
||||
iram1_0_seg : org = 0x40100000, len = 0x08000
|
||||
irom0_0_seg : org = IROM0_START, len = IROM0_LEN
|
||||
}
|
||||
|
||||
PHDRS
|
||||
{
|
||||
dport0_0_phdr PT_LOAD;
|
15
ld/nonota.ld
Normal file
15
ld/nonota.ld
Normal file
|
@ -0,0 +1,15 @@
|
|||
/* Memory layout for esp-open-rtos when not using OTA
|
||||
(ie ROM bootloader only, no second stage rboot)
|
||||
*/
|
||||
MEMORY
|
||||
{
|
||||
dport0_0_seg : org = 0x3FF00000, len = 0x10
|
||||
dram0_0_seg : org = 0x3FFE8000, len = 0x14000
|
||||
iram1_0_seg : org = 0x40100000, len = 0x08000
|
||||
/* irom0 section, mapped from SPI flash
|
||||
- Origin is offset by 0x20000 to leave space for bootloader RAM sections.
|
||||
|
||||
- Length is max 8Mbit of mappable flash, minus start offset
|
||||
*/
|
||||
irom0_0_seg : org = 0x40220000, len = (1M - 0x20000)
|
||||
}
|
15
ld/ota.ld
Normal file
15
ld/ota.ld
Normal file
|
@ -0,0 +1,15 @@
|
|||
/* Memory layout for esp-open-rtos when using OTA second stage bootloader */
|
||||
|
||||
MEMORY
|
||||
{
|
||||
dport0_0_seg : org = 0x3FF00000, len = 0x10
|
||||
dram0_0_seg : org = 0x3FFE8000, len = 0x14000
|
||||
iram1_0_seg : org = 0x40100000, len = 0x08000
|
||||
/* irom0 section, mapped from SPI flash
|
||||
- Origin is offset by 0x2010 to create spacer for second stage bootloader image,
|
||||
header.
|
||||
|
||||
- Length is max 8Mbit of mappable flash, minus start offset
|
||||
*/
|
||||
irom0_0_seg : org = 0x40202010, len = (1M - 0x2010)
|
||||
}
|
|
@ -1,3 +1,11 @@
|
|||
/* Linker script containing Boot ROM functions for ESP8266
|
||||
|
||||
For more information, see:
|
||||
|
||||
http://esp8266-re.foogod.com/wiki/Boot_ROM
|
||||
https://github.com/jcmvbkbc/esp-elf-rom/
|
||||
*/
|
||||
|
||||
PROVIDE ( SPI_sector_erase = 0x400040c0 );
|
||||
PROVIDE ( SPI_page_program = 0x40004174 );
|
||||
PROVIDE ( SPI_read_data = 0x400042ac );
|
||||
|
@ -8,22 +16,22 @@ PROVIDE ( Wait_SPI_Idle = 0x4000448c );
|
|||
PROVIDE ( Enable_QMode = 0x400044c0 );
|
||||
PROVIDE ( Disable_QMode = 0x40004508 );
|
||||
|
||||
/* When using OTA, Cache_Read_Enable is defined in extras/rboot-ota so
|
||||
the ROM Cache_Read_Enable isn't picked up from here. However we
|
||||
also provide access to the ROM function in all cases, via the name
|
||||
rom_Cache_Read_Enable */
|
||||
PROVIDE ( rom_Cache_Read_Enable = 0x40004678 );
|
||||
PROVIDE ( Cache_Read_Enable = rom_Cache_Read_Enable );
|
||||
|
||||
PROVIDE ( Cache_Read_Disable = 0x400047f0 );
|
||||
|
||||
#ifndef OTA
|
||||
/* If not building an OTA image for boot, can use the default (simple)
|
||||
cache enable function from ROM.
|
||||
|
||||
Otherwise, we need an OTA-aware one (see extras/rboot-ota/rboot-cache.S)
|
||||
*/
|
||||
Cache_Read_Enable = rom_Cache_Read_Enable;
|
||||
#endif
|
||||
|
||||
PROVIDE ( lldesc_build_chain = 0x40004f40 );
|
||||
PROVIDE ( lldesc_num2link = 0x40005050 );
|
||||
PROVIDE ( lldesc_set_owner = 0x4000507c );
|
||||
|
||||
/* TODO: Nearly everything below here is probably provided by the
|
||||
libc, so never linked in, and can therefore be removed. */
|
||||
|
||||
PROVIDE ( __adddf3 = 0x4000c538 );
|
||||
PROVIDE ( __addsf3 = 0x4000c180 );
|
||||
PROVIDE ( __divdf3 = 0x4000cb94 );
|
|
@ -1,10 +0,0 @@
|
|||
# stop-gap until esptool.py patch for configurable entry point is merged
|
||||
call_user_start
|
||||
# this is a stop-gap to avoid renaming some useful libc
|
||||
# symbols to sdk_xxx
|
||||
puts
|
||||
printf
|
||||
putchar
|
||||
rand
|
||||
srand
|
||||
atoi
|
43
libc/xtensa-lx106-elf/include/config.h
Normal file
43
libc/xtensa-lx106-elf/include/config.h
Normal file
|
@ -0,0 +1,43 @@
|
|||
#ifndef __SYS_CONFIG_H__
|
||||
#define __SYS_CONFIG_H__
|
||||
|
||||
#include <machine/ieeefp.h> /* floating point macros */
|
||||
#include <sys/features.h> /* POSIX defs */
|
||||
|
||||
/*************************************************************************
|
||||
esp8266-specific xtensa stuff
|
||||
*************************************************************************/
|
||||
|
||||
#ifndef _REENT_SMALL
|
||||
#define _REENT_SMALL
|
||||
#endif
|
||||
|
||||
/* esp8266 hardware FIFO buffers are 128 bytes */
|
||||
#define __BUFSIZ__ 128
|
||||
|
||||
/*************************************************************************
|
||||
end of esp8266-specific stuff
|
||||
*************************************************************************/
|
||||
|
||||
#ifndef __EXPORT
|
||||
#define __EXPORT
|
||||
#endif
|
||||
|
||||
#ifndef __IMPORT
|
||||
#define __IMPORT
|
||||
#endif
|
||||
|
||||
/* Define return type of read/write routines. In POSIX, the return type
|
||||
for read()/write() is "ssize_t" but legacy newlib code has been using
|
||||
"int" for some time. If not specified, "int" is defaulted. */
|
||||
#ifndef _READ_WRITE_RETURN_TYPE
|
||||
#define _READ_WRITE_RETURN_TYPE int
|
||||
#endif
|
||||
/* Define `count' parameter of read/write routines. In POSIX, the `count'
|
||||
parameter is "size_t" but legacy newlib code has been using "int" for some
|
||||
time. If not specified, "int" is defaulted. */
|
||||
#ifndef _READ_WRITE_BUFSIZE_TYPE
|
||||
#define _READ_WRITE_BUFSIZE_TYPE int
|
||||
#endif
|
||||
|
||||
#endif /* __SYS_CONFIG_H__ */
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
@ -1 +1 @@
|
|||
Subproject commit c4765dccec5c01faeb87e5ed65db1c99ff5c9a05
|
||||
Subproject commit 3cf8d514bd76e6ef77e6fa514d0ec6d96da7fd9a
|
|
@ -54,6 +54,6 @@ uint8_t sdk_rtc_get_reset_reason(void) {
|
|||
}
|
||||
}
|
||||
}
|
||||
RTC.RESET_REASON0 &= ~RTC_RESET_REASON0_SOMETHING;
|
||||
RTC.RESET_REASON0 &= ~RTC_RESET_REASON0_BIT21;
|
||||
return reason;
|
||||
}
|
||||
|
|
48
utils/addrsource
Executable file
48
utils/addrsource
Executable file
|
@ -0,0 +1,48 @@
|
|||
#!/bin/bash
|
||||
#
|
||||
# addrsource <addr> [<filename>]
|
||||
#
|
||||
# Given a memory address (in hex), print (if available) the C source code line
|
||||
# and disassembly associated with that address.
|
||||
#
|
||||
# <filename>, if provided, should be the name of the ELF (*.out) file for the
|
||||
# firmware image (typically located in the "build" subdirectory). If
|
||||
# <filename> is not provided, the script will look for a "build" subdirectory
|
||||
# of the current directory, and look in there for a filename matching "*.out"
|
||||
# and use that.
|
||||
|
||||
print_usage() {
|
||||
echo "Usage: $0 addr [file.out]" >&2
|
||||
}
|
||||
|
||||
addr="$1"
|
||||
exefile="$2"
|
||||
|
||||
# If user didn't provide any parameters, or attempted to use a switch (such as
|
||||
# "--help"), just print the usage message and exit. If they provided an 'addr'
|
||||
# parameter, but it didn't start with "0x", then prepend "0x" to it before
|
||||
# continuing..
|
||||
case "$addr" in
|
||||
"") print_usage; exit 1 ;;
|
||||
-*) print_usage; exit 1 ;;
|
||||
0x*) ;;
|
||||
*) addr="0x$addr" ;;
|
||||
esac
|
||||
|
||||
if [[ -z "$exefile" ]]; then
|
||||
# User didn't specify what ELF (.out) file to look things up in.
|
||||
# See if we can find an appropriate .out file in the build subdirectory
|
||||
# (there's usually only one)
|
||||
exefile=$(ls build/*.out)
|
||||
if [[ -z "$exefile" ]] || [[ "${exefile#* }" != "$exefile" ]]; then
|
||||
# Either we couldn't find anything, or we found more than one of them.
|
||||
echo "Unable to determine which .out file to use. You will need to specify it explicitly on the command line." >&2
|
||||
echo "" >&2
|
||||
print_usage
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
|
||||
# All our parameters should be correct now.
|
||||
# Invoke GDB to do the hard work for us...
|
||||
xtensa-lx106-elf-gdb -batch "$exefile" -ex "list *$addr" -ex "info line *$addr" -ex "disassemble $addr"
|
Loading…
Reference in a new issue