Merge branch 'master' into open-libmain

Conflicts:
	core/include/esp/rtc_regs.h
	include/espressif/spi_flash.h
This commit is contained in:
Alex Stewart 2016-03-22 16:24:50 -07:00
commit 769ca0d8f8
89 changed files with 4766 additions and 634 deletions

View file

@ -2,17 +2,16 @@ language: c
sudo: false sudo: false
env: env:
# Target commit for https://github.com/pfalcon/esp-open-sdk/ # Target commit for https://github.com/pfalcon/esp-open-sdk/
OPENSDK_COMMIT=b44afa47 OPENSDK_COMMIT=cd1d336
CROSS_ROOT="${HOME}/toolchain-${OPENSDK_COMMIT}" CROSS_ROOT="${HOME}/toolchain-${OPENSDK_COMMIT}"
CROSS_BINDIR="${CROSS_ROOT}/bin" CROSS_BINDIR="${CROSS_ROOT}/bin"
ESPTOOL2_COMMIT=92530bb8 ESPTOOL2_COMMIT=ec0e2c7
ESPTOOL2_BINDIR="${HOME}/esptool2-${ESPTOOL2_COMMIT}" ESPTOOL2_DIR="${HOME}/esptool2-${ESPTOOL2_COMMIT}"
PATH=${PATH}:${CROSS_BINDIR}:${ESPTOOL2_BINDIR} PATH=${PATH}:${CROSS_BINDIR}:${ESPTOOL2_DIR}
cache: cache:
directories: directories:
- ${CROSS_ROOT} - ${CROSS_ROOT}
- ${HOME}/.ccache - ${ESPTOOL2_DIR}
- ${ESPTOOL2_BINDIR}
addons: addons:
apt: apt:
packages: 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 -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} || sed -r -i 's%TOOLCHAIN ?=.*%TOOLCHAIN=${CROSS_ROOT}%' Makefile
- ${HAS_TC} || make STANDALONE=n - ${HAS_TC} || make STANDALONE=n
- export HAS_ET2="test -f ${ESPTOOL2_BINDIR}/esptool2" - export HAS_ET2="test -f ${ESPTOOL2_DIR}/esptool2"
- ${HAS_ET2} || git clone https://github.com/raburton/esp8266 ${HOME}/raburton - ${HAS_ET2} || git clone https://github.com/raburton/esptool2 ${ESPTOOL2_DIR}
- ${HAS_ET2} || make -C ${HOME}/raburton/esptool2 - ${HAS_ET2} || cd ${ESPTOOL2_DIR}
- ${HAS_ET2} || mkdir -p ${ESPTOOL2_BINDIR} - ${HAS_ET2} || git reset --hard ${ESPTOOL2_COMMIT}
- ${HAS_ET2} || cp -a ${HOME}/raburton/esptool2/esptool2 ${ESPTOOL2_BINDIR}/ - ${HAS_ET2} || make
script: script:
- cd ${TRAVIS_BUILD_DIR} - cd ${TRAVIS_BUILD_DIR}
# Remove ssid_config requirement for examples # Remove ssid_config requirement for examples
- sed -i "s%#warning%//#warning%" include/ssid_config.h - 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

View file

@ -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. 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 ## 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)). 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. 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 ## 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.) (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 ## 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. * [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. * [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. * 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. 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.

View file

@ -40,7 +40,7 @@ FLASH_SPEED ?= 40
# Output directories to store intermediate compiled files # Output directories to store intermediate compiled files
# relative to the program directory # relative to the program directory
BUILD_DIR ?= $(PROGRAM_DIR)build/ BUILD_DIR ?= $(PROGRAM_DIR)build/
FW_BASE ?= $(PROGRAM_DIR)firmware/ FIRMWARE_DIR ?= $(PROGRAM_DIR)firmware/
# esptool.py from https://github.com/themadinventor/esptool # esptool.py from https://github.com/themadinventor/esptool
ESPTOOL ?= esptool.py ESPTOOL ?= esptool.py
@ -48,6 +48,13 @@ ESPTOOL ?= esptool.py
ESPPORT ?= /dev/ttyUSB0 ESPPORT ?= /dev/ttyUSB0
ESPBAUD ?= 115200 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 # Set OTA to 1 to build an image that supports rBoot OTA bootloader
# #
# Currently only works with 16mbit or more flash sizes, with 8mbit # Currently only works with 16mbit or more flash sizes, with 8mbit
@ -100,13 +107,16 @@ ENTRY_SYMBOL ?= call_user_start
SPLIT_SECTIONS ?= 1 SPLIT_SECTIONS ?= 1
# Common flags for both C & C++_ # 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 # Flags for C only
CFLAGS = $(C_CXX_FLAGS) -std=gnu99 CFLAGS ?= $(C_CXX_FLAGS) -std=gnu99 $(EXTRA_CFLAGS)
# Flags for C++ only # 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) ifeq ($(SPLIT_SECTIONS),1)
C_CXX_FLAGS += -ffunction-sections -fdata-sections C_CXX_FLAGS += -ffunction-sections -fdata-sections
@ -128,11 +138,18 @@ else
LDFLAGS += -g -O2 LDFLAGS += -g -O2
endif endif
GITSHORTREV=\"$(shell cd $(ROOT); git rev-parse --short -q HEAD)\" GITSHORTREV=\"$(shell cd $(ROOT); git rev-parse --short -q HEAD 2> /dev/null)\"
CPPFLAGS += -DGITSHORTREV=$(GITSHORTREV) -DFLASH_SIZE=$(FLASH_SIZE) ifeq ($(GITSHORTREV),\"\")
GITSHORTREV="\"(nogit)\"" # (same length as a short git hash)
endif
CPPFLAGS += -DGITSHORTREV=$(GITSHORTREV)
# Linker scripts, all found in $(ROOT)/ld ifeq ($(OTA),0)
LINKER_SCRIPTS = eagle.app.v6.ld eagle.rom.addr.v6.ld 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 #### 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 # assume the program dir is the directory the top-level makefile was run in
PROGRAM_DIR := $(dir $(firstword $(MAKEFILE_LIST))) 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 # derive various parts of compiler/linker arguments
SDK_LIB_ARGS = $(addprefix -l,$(SDK_LIBS)) SDK_LIB_ARGS = $(addprefix -l,$(SDK_LIBS))
LIB_ARGS = $(addprefix -l,$(LIBS)) LIB_ARGS = $(addprefix -l,$(LIBS))
PROGRAM_OUT = $(BUILD_DIR)$(PROGRAM).out PROGRAM_OUT = $(BUILD_DIR)$(PROGRAM).out
LDFLAGS += $(addprefix -T,$(LINKER_SCRIPTS_PROCESSED)) LDFLAGS += $(addprefix -T,$(LINKER_SCRIPTS))
ifeq ($(OTA),0) ifeq ($(OTA),0)
# for non-OTA, we create two different files for uploading into the flash # for non-OTA, we create two different files for uploading into the flash
# these are the names and options to generate them # these are the names and options to generate them
FW_ADDR_1 = 0x00000 FW_ADDR_1 = 0x00000
FW_ADDR_2 = 0x20000 FW_ADDR_2 = 0x20000
FW_FILE_1 = $(addprefix $(FW_BASE),$(FW_ADDR_1).bin) FW_FILE_1 = $(addprefix $(FIRMWARE_DIR),$(FW_ADDR_1).bin)
FW_FILE_2 = $(addprefix $(FW_BASE),$(FW_ADDR_2).bin) FW_FILE_2 = $(addprefix $(FIRMWARE_DIR),$(FW_ADDR_2).bin)
else else
# for OTA, it's a single monolithic image # for OTA, it's a single monolithic image
FW_FILE = $(addprefix $(FW_BASE),$(PROGRAM).bin) FW_FILE = $(addprefix $(FIRMWARE_DIR),$(PROGRAM).bin)
endif endif
# firmware tool arguments # firmware tool arguments
@ -200,6 +209,9 @@ INC_DIRS = $(PROGRAM_DIR) $(PROGRAM_DIR)include $(ROOT)include
ifeq ($(OWN_LIBC),1) ifeq ($(OWN_LIBC),1)
INC_DIRS += $(ROOT)libc/xtensa-lx106-elf/include INC_DIRS += $(ROOT)libc/xtensa-lx106-elf/include
LDFLAGS += -L$(ROOT)libc/xtensa-lx106-elf/lib LDFLAGS += -L$(ROOT)libc/xtensa-lx106-elf/lib
ifeq ($(PRINTF_SCANF_FLOAT_SUPPORT),1)
LDFLAGS += -u _printf_float -u _scanf_float
endif
endif endif
ifeq ("$(V)","1") 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)) $(1)_MAKEFILE ?= $(lastword $(MAKEFILE_LIST))
### determine compiler arguments ### ### determine compiler arguments ###
$(1)_CPPFLAGS ?= $(CPPFLAGS)
$(1)_CFLAGS ?= $(CFLAGS) $(1)_CFLAGS ?= $(CFLAGS)
$(1)_CXXFLAGS ?= $(CXXFLAGS) $(1)_CXXFLAGS ?= $(CXXFLAGS)
$(1)_CC_ARGS = $(Q) $(CC) $$(addprefix -I,$$(INC_DIRS)) $$(addprefix -I,$$($(1)_INC_DIR)) $$($(1)_CFLAGS) $(1)_CC_BASE = $(Q) $(CC) $$(addprefix -I,$$(INC_DIRS)) $$(addprefix -I,$$($(1)_INC_DIR)) $$($(1)_CPPFLAGS)
$(1)_CXX_ARGS = $(Q) $(C++) $$(addprefix -I,$$(INC_DIRS)) $$(addprefix -I,$$($(1)_INC_DIR)) $$($(1)_CXXFLAGS)
$(1)_AR = $(call lc,$(BUILD_DIR)$(1).a) $(1)_AR = $(call lc,$(BUILD_DIR)$(1).a)
$$($(1)_OBJ_DIR)%.o: $$($(1)_REAL_ROOT)%.c $$($(1)_MAKEFILE) $(wildcard $(ROOT)*.mk) | $$($(1)_SRC_DIR) $$($(1)_OBJ_DIR)%.o: $$($(1)_REAL_ROOT)%.c $$($(1)_MAKEFILE) $(wildcard $(ROOT)*.mk) | $$($(1)_SRC_DIR)
$(vecho) "CC $$<" $(vecho) "CC $$<"
$(Q) mkdir -p $$(dir $$@) $(Q) mkdir -p $$(dir $$@)
$$($(1)_CC_ARGS) -c $$< -o $$@ $$($(1)_CC_BASE) $$($(1)_CFLAGS) -c $$< -o $$@
$$($(1)_CC_ARGS) -MM -MT $$@ -MF $$(@:.o=.d) $$< $$($(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) $$($(1)_OBJ_DIR)%.o: $$($(1)_REAL_ROOT)%.cpp $$($(1)_MAKEFILE) $(wildcard $(ROOT)*.mk) | $$($(1)_SRC_DIR)
$(vecho) "C++ $$<" $(vecho) "C++ $$<"
$(Q) mkdir -p $$(dir $$@) $(Q) mkdir -p $$(dir $$@)
$$($(1)_CXX_ARGS) -c $$< -o $$@ $$($(1)_CC_BASE) $$($(1)_CXXFLAGS) -c $$< -o $$@
$$($(1)_CXX_ARGS) -MM -MT $$@ -MF $$(@:.o=.d) $$< $$($(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) $$($(1)_OBJ_DIR)%.o: $$($(1)_REAL_ROOT)%.S $$($(1)_MAKEFILE) $(wildcard $(ROOT)*.mk) | $$($(1)_SRC_DIR)
$(vecho) "AS $$<" $(vecho) "AS $$<"
$(Q) mkdir -p $$(dir $$@) $(Q) mkdir -p $$(dir $$@)
$$($(1)_CC_ARGS) -c $$< -o $$@ $$($(1)_CC_BASE) -c $$< -o $$@
$$($(1)_CC_ARGS) -MM -MT $$@ -MF $$(@:.o=.d) $$< $$($(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 # 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 # for missing explicitly named source files
@ -294,7 +306,7 @@ endef
# - prefix all defined symbols with 'sdk_' # - prefix all defined symbols with 'sdk_'
# - weaken all global symbols so they can be overriden from the open SDK side # - 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))) SDK_PROCESSED_LIBS = $(addsuffix .a,$(addprefix $(BUILD_DIR)sdklib/lib,$(SDK_LIBS)))
# Make rules for preprocessing each SDK library # 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 # 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 $@" $(vecho) "LD $@"
$(Q) $(LD) $(LDFLAGS) -Wl,--start-group $(COMPONENT_ARS) $(LIB_ARGS) $(SDK_LIB_ARGS) -Wl,--end-group -o $@ $(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 $@ $(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 $@" $(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 $(Q) $(IMGTOOL) $(IMGTOOL_ARGS) -bin -boot2 $(PROGRAM_OUT) $(FW_FILE) .text .data .rodata
ifeq ($(OTA),0) ifeq ($(OTA),0)
@ -377,7 +385,7 @@ rebuild:
clean: clean:
$(Q) rm -rf $(BUILD_DIR) $(Q) rm -rf $(BUILD_DIR)
$(Q) rm -rf $(FW_BASE) $(Q) rm -rf $(FIRMWARE_DIR)
# prevent "intermediate" files from being deleted # prevent "intermediate" files from being deleted
.SECONDARY: .SECONDARY:

View file

@ -250,7 +250,7 @@ void IRAM sdk_user_start(void) {
// .text+0x3a8 // .text+0x3a8
void IRAM vApplicationStackOverflowHook(xTaskHandle task, char *task_name) { 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 // .text+0x3d8

41
core/esp_gpio.c Normal file
View 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);
}

View file

@ -7,14 +7,15 @@
#include "esp/iomux.h" #include "esp/iomux.h"
#include "common_macros.h" #include "common_macros.h"
/* These are non-static versions of the GPIO mapping tables in 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 };
iomux.h, so if they need to be linked only one copy is linked for 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 };
the entire program.
These are only ever linked in if the arguments to gpio_to_ionum uint8_t IRAM gpio_to_iomux(const uint8_t gpio_number)
or ionum_to_gpio are not known at compile time. {
return GPIO_TO_IOMUX[gpio_number];
}
Arrays are declared as 32-bit integers in IROM to save RAM. uint8_t IRAM iomux_to_gpio(const uint8_t iomux_number)
*/ {
const IROM uint32_t GPIO_TO_IOMUX_MAP[] = _GPIO_TO_IOMUX; return IOMUX_TO_GPIO[iomux_number];
const IROM uint32_t IOMUX_TO_GPIO_MAP[] = _IOMUX_TO_GPIO; }

251
core/esp_spi.c Normal file
View 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;
}

View file

@ -6,30 +6,143 @@
* BSD Licensed as described in the file LICENSE * BSD Licensed as described in the file LICENSE
*/ */
#include <esp/timer.h> #include <esp/timer.h>
#include <esp/dport_regs.h>
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
/* /* Timer divisor number to maximum frequency */
* These are the runtime implementations for functions that are linked in if any of #define _FREQ_DIV1 (80*1000*1000)
* the arguments aren't known at compile time (values are evaluated at #define _FREQ_DIV16 (5*1000*1000)
* compile time otherwise.) #define _FREQ_DIV256 312500
*/
uint32_t _timer_freq_to_count_runtime(const timer_frc_t frc, const uint32_t freq, const timer_clkdiv_t div) 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)
{ {
return _timer_freq_to_count_impl(frc, freq, div); 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_time_to_count_runtime(const timer_frc_t frc, uint32_t us, const timer_clkdiv_t div) uint32_t timer_freq_to_count(const timer_frc_t frc, const uint32_t freq, const timer_clkdiv_t div)
{ {
return _timer_time_to_count_runtime(frc, us, 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;
} }
bool _timer_set_frequency_runtime(const timer_frc_t frc, uint32_t freq) uint32_t timer_time_to_count(const timer_frc_t frc, uint32_t us, const timer_clkdiv_t div)
{ {
return _timer_set_frequency_runtime(frc, freq); 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;
}
} }
bool _timer_set_timeout_runtime(const timer_frc_t frc, uint32_t us) int timer_set_frequency(const timer_frc_t frc, uint32_t freq)
{ {
return _timer_set_timeout_impl(frc, us); 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;
}
int _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 -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;
}
int timer_set_timeout(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 -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;
} }

View file

@ -53,8 +53,30 @@
#define IROM __attribute__((section(".irom0.literal"))) const #define IROM __attribute__((section(".irom0.literal"))) const
#endif #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"))) #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 #endif

View file

@ -13,63 +13,74 @@
#include "esp/iomux.h" #include "esp/iomux.h"
#include "esp/interrupts.h" #include "esp/interrupts.h"
#ifdef __cplusplus
extern "C" {
#endif
typedef enum { typedef enum {
GPIO_INPUT, GPIO_INPUT,
GPIO_OUTPUT, /* "Standard" push-pull output */ GPIO_OUTPUT, /* "Standard" push-pull output */
GPIO_OUT_OPEN_DRAIN, /* Open drain output */ GPIO_OUT_OPEN_DRAIN, /* Open drain output */
GPIO_INPUT_PULLUP,
} gpio_direction_t; } gpio_direction_t;
/* Enable GPIO on the specified pin, and set it to input/output/ with /* Enable GPIO on the specified pin, and set it to input or output mode
* pullup as needed
*/ */
INLINED void gpio_enable(const uint8_t gpio_num, const gpio_direction_t direction) void gpio_enable(const uint8_t gpio_num, const gpio_direction_t direction);
{
uint32_t iomux_flags;
switch(direction) { /* Enable/disable internal pullup resistor for a particular GPIO
case GPIO_INPUT: *
iomux_flags = 0; * Note: According to Espressif, pullup resistor values are between 30K and
break; * 100K ohms (see http://bbs.espressif.com/viewtopic.php?t=1079#p4097)
case GPIO_OUTPUT: * However, measured values suggest that the actual value is likely to be close
iomux_flags = IOMUX_PIN_OUTPUT_ENABLE; * to 47K in reality.
break; *
case GPIO_OUT_OPEN_DRAIN: * NOTE: The enabled_during_sleep setting is currently untested (please send
iomux_flags = IOMUX_PIN_OUTPUT_ENABLE; * feedback if you give it a try)
break; */
case GPIO_INPUT_PULLUP: void gpio_set_pullup(uint8_t gpio_num, bool enabled, bool enabled_during_sleep);
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);
}
/* Disable GPIO on the specified pin, and set it Hi-Z. /* Disable GPIO on the specified pin, and set it Hi-Z.
* *
* If later muxing this pin to a different function, make sure to set * If later muxing this pin to a different function, make sure to set
* IOMUX_PIN_OUTPUT_ENABLE if necessary to enable the output buffer. * 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.ENABLE_OUT_CLEAR = BIT(gpio_num);
*gpio_iomux_reg(gpio_num) &= ~IOMUX_PIN_OUTPUT_ENABLE; *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. /* 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); GPIO.OUT_SET = BIT(gpio_num);
else else
GPIO.OUT_CLEAR = BIT(gpio_num); 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 /* 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? /* Why implement like this instead of GPIO_OUT_REG ^= xxx?
Concurrency. If an interrupt or higher priority task writes to 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. /* 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 GPIO_INPUT, this reads the level on the pin.
* If pin is set as an output, this reads the last value written to 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); return GPIO.IN & BIT(gpio_num);
} }
@ -107,9 +125,10 @@ extern void gpio_interrupt_handler(void);
/* Set the interrupt type for a given pin /* 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); GPIO.CONF[gpio_num] = SET_FIELD(GPIO.CONF[gpio_num], GPIO_CONF_INTTYPE, int_type);
if(int_type != GPIO_INTTYPE_NONE) { 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 */ /* 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]); return (gpio_inttype_t)FIELD2VAL(GPIO_CONF_INTTYPE, GPIO.CONF[gpio_num]);
} }
#ifdef __cplusplus
}
#endif
#endif #endif

137
core/include/esp/i2s_regs.h Normal file
View 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 */

View file

@ -17,6 +17,7 @@
/* Interrupt numbers for level 1 exception handler. */ /* Interrupt numbers for level 1 exception handler. */
typedef enum { typedef enum {
INUM_SLC = 1,
INUM_SPI = 2, INUM_SPI = 2,
INUM_GPIO = 4, INUM_GPIO = 4,
INUM_UART = 5, INUM_UART = 5,
@ -38,7 +39,7 @@ void sdk__xt_tick_timer_init (void);
void sdk__xt_timer_int(void); void sdk__xt_timer_int(void);
void sdk__xt_timer_int1(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; uint32_t level;
__asm__ volatile("rsr %0, intlevel" : "=a"(level)); __asm__ volatile("rsr %0, intlevel" : "=a"(level));
@ -52,7 +53,7 @@ INLINED uint32_t _xt_get_intlevel(void)
portDISABLE_INTERRUPTS/portENABLE_INTERRUPTS for portDISABLE_INTERRUPTS/portENABLE_INTERRUPTS for
non-FreeRTOS & non-portable code. non-FreeRTOS & non-portable code.
*/ */
INLINED uint32_t _xt_disable_interrupts(void) static inline uint32_t _xt_disable_interrupts(void)
{ {
uint32_t old_level; uint32_t old_level;
__asm__ volatile ("rsil %0, " XTSTR(XCHAL_EXCM_LEVEL) : "=a" (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 */ /* 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)); __asm__ volatile ("wsr %0, ps; rsync" :: "a" (new_ps));
} }
/* ESPTODO: the mask/unmask functions aren't thread safe */ /* 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; uint32_t intenable;
asm volatile ("rsr %0, intenable" : "=a" (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)); 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; uint32_t intenable;
asm volatile ("rsr %0, intenable" : "=a" (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)); 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; uint32_t interrupt;
asm volatile ("rsr %0, interrupt" : "=a" (interrupt)); asm volatile ("rsr %0, interrupt" : "=a" (interrupt));
return 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)); asm volatile ("wsr %0, intclear; esync" :: "a" (mask));
} }

View file

@ -22,7 +22,7 @@ extern "C" {
* known at compile time, or return the result from a lookup table if not. * 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. * 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. * 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 * 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)]); 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. * Set a pin to the GPIO function.
* *
* This allows you to set pins to GPIO without knowing in advance the * This allows you to set pins to GPIO without knowing in advance the
* exact register masks to use. * 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. * Sets the function and direction, but leaves the pullup configuration the
* * same as before.
* 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;
*/ */
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 uint8_t iomux_num = gpio_to_iomux(gpio_number);
const uint32_t func = (reg_idx > 11 ? IOMUX_FUNC(0) : IOMUX_FUNC(3)) | flags; const uint32_t func = iomux_num > 11 ? 0 : 3;
IOMUX.PIN[reg_idx] = func | flags; 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 #ifdef __cplusplus
} }
#endif #endif

View file

@ -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

View file

@ -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_PULLDOWN BIT(6)
#define IOMUX_PIN_PULLUP BIT(7) #define IOMUX_PIN_PULLUP BIT(7)
#define IOMUX_PIN_FUNC_HIGH_M 0x00000004 #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 */ /* WARNING: Macro evaluates argument twice */
#define IOMUX_FUNC(val) (VAL2FIELD_M(IOMUX_PIN_FUNC_LOW, val) | VAL2FIELD_M(IOMUX_PIN_FUNC_HIGH, val)) #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_GPIO IOMUX_FUNC(0)
#define IOMUX_GPIO2_FUNC_I2SO_WS IOMUX_FUNC(1) #define IOMUX_GPIO2_FUNC_I2SO_WS IOMUX_FUNC(1)
#define IOMUX_GPIO2_FUNC_UART1_TXD_BLINK IOMUX_FUNC(2) #define IOMUX_GPIO2_FUNC_UART1_TXD IOMUX_FUNC(2)
#define IOMUX_GPIO2_FUNC_UART0_TXD_BLINK IOMUX_FUNC(4) #define IOMUX_GPIO2_FUNC_UART0_TXD IOMUX_FUNC(4)
#define IOMUX_GPIO3_FUNC_UART0_RXD IOMUX_FUNC(0) #define IOMUX_GPIO3_FUNC_UART0_RXD IOMUX_FUNC(0)
#define IOMUX_GPIO3_FUNC_I2SO_DATA IOMUX_FUNC(1) #define IOMUX_GPIO3_FUNC_I2SO_DATA IOMUX_FUNC(1)

View file

@ -16,14 +16,17 @@
#include "common_macros.h" #include "common_macros.h"
#include "esp/types.h" #include "esp/types.h"
#include "esp/uart_regs.h" #include "esp/dport_regs.h"
#include "esp/spi_regs.h"
#include "esp/iomux_regs.h"
#include "esp/gpio_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/timer_regs.h"
#include "esp/wdt_regs.h" #include "esp/wdt_regs.h"
#include "esp/rtcmem_regs.h" #include "esp/uart_regs.h"
#include "esp/dport_regs.h"
/* Register base addresses /* Register base addresses
@ -44,7 +47,7 @@
//#define SPI_BASE (MMIO_BASE + 0x0200) //#define SPI_BASE (MMIO_BASE + 0x0200)
//#define GPIO0_BASE (MMIO_BASE + 0x0300) //#define GPIO0_BASE (MMIO_BASE + 0x0300)
//#define TIMER_BASE (MMIO_BASE + 0x0600) //#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 IOMUX_BASE (MMIO_BASE + 0x0800)
//#define WDT_BASE (MMIO_BASE + 0x0900) //#define WDT_BASE (MMIO_BASE + 0x0900)
#define I2C_BASE (MMIO_BASE + 0x0d00) #define I2C_BASE (MMIO_BASE + 0x0d00)

View file

@ -3,6 +3,16 @@
* ESP8266 RTC register definitions * ESP8266 RTC register definitions
* *
* Not compatible with ESP SDK register access code. * 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 #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 // Note: GPIO_CFG[3] is also known as PAD_XPD_DCDC_CONF in eagle_soc.h
struct RTC_REGS { struct RTC_REGS {
uint32_t volatile _unknown0; // 0x00 uint32_t volatile CTRL0; // 0x00
uint32_t volatile COUNTER_ALARM; // 0x04 uint32_t volatile COUNTER_ALARM; // 0x04
uint32_t volatile RESET_REASON0; // 0x08 //FIXME: need better name uint32_t volatile RESET_REASON0; // 0x08 //FIXME: need better name
uint32_t volatile _unknownc[2]; // 0x0c - 0x10 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"); _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 /* The following are used in sdk_rtc_get_reset_reason(). Details are still a
* bit sketchy regarding exactly what they mean/do.. */ * 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_M 0x0000003f
#define RTC_RESET_REASON2_CODE_S 8 #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 */ #endif /* _ESP_RTC_REGS_H */

37
core/include/esp/slc.h Normal file
View 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
View 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
View 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_ */

View file

@ -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_SETUP BIT(5)
#define SPI_USER0_CS_HOLD BIT(4) #define SPI_USER0_CS_HOLD BIT(4)
#define SPI_USER0_FLASH_MODE BIT(2) #define SPI_USER0_FLASH_MODE BIT(2)
#define SPI_USER0_DUPLEX BIT(0)
/* Details for USER1 register */ /* 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 */ /* Details for PIN register */
#define SPI_PIN_IDLE_EDGE BIT(29) ///< CPOL
#define SPI_PIN_CS2_DISABLE BIT(2) #define SPI_PIN_CS2_DISABLE BIT(2)
#define SPI_PIN_CS1_DISABLE BIT(1) #define SPI_PIN_CS1_DISABLE BIT(1)
#define SPI_PIN_CS0_DISABLE BIT(0) #define SPI_PIN_CS0_DISABLE BIT(0)

View file

@ -10,6 +10,7 @@
#define _ESP_TIMER_H #define _ESP_TIMER_H
#include <stdbool.h> #include <stdbool.h>
#include <errno.h>
#include "esp/timer_regs.h" #include "esp/timer_regs.h"
#include "esp/interrupts.h" #include "esp/interrupts.h"
@ -23,43 +24,73 @@ typedef enum {
} timer_frc_t; } timer_frc_t;
/* Return current count value for timer. */ /* 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. */ /* 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. */ /* 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. */ /* 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 */ /* 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 /* Enable or disable timer interrupts
This both sets the xtensa interrupt mask and writes to the DPORT register This both sets the xtensa interrupt mask and writes to the DPORT register
that allows timer interrupts. 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 */ /* 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) */ /* 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 */ /* 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) */ /* Get the auto-reload state of the timer (on or off) */
INLINED bool timer_get_reload(const timer_frc_t frc); static inline bool timer_get_reload(const timer_frc_t frc)
{
/* Return a suitable timer divider for the specified frequency, return TIMER(frc).CTRL & TIMER_CTRL_RELOAD;
or -1 if none is found. }
*/
INLINED timer_clkdiv_t timer_freq_to_div(uint32_t freq);
/* Return the number of timer counts to achieve the specified /* Return the number of timer counts to achieve the specified
* frequency with the specified divisor. * 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. * 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 /* Return a suitable timer divider for the specified duration in
microseconds or -1 if none is found. 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 /* Return the number of timer counts for the specified timer duration
* in microseconds, when using the specified divisor. * 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. * 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. /* 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 Does not start/stop the timer, you have to do this manually via
timer_set_run. timer_set_run.
Returns true on success, false if given frequency could not be set. Returns 0 on success, or -EINVAL if given frequency could not be set.
Compile-time evaluates to simple register writes if all arguments
are available at compile time.
*/ */
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. /* 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 also disable FRC1 in the timer interrupt handler by calling
timer_set_run(TIMER_FRC1, false); timer_set_run(TIMER_FRC1, false);
Returns true if the timeout was successfully set. Returns 0 on success, or -EINVAL if the given timeout could not be set.
Compile-time evaluates to simple register writes if all arguments
are available at compile time.
*/ */
INLINED bool timer_set_timeout(const timer_frc_t frc, uint32_t us); int timer_set_timeout(const timer_frc_t frc, uint32_t us);
#include "timer_private.h"
#ifdef __cplusplus #ifdef __cplusplus
} }

View file

@ -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

View file

@ -52,7 +52,7 @@ long _write_r(struct _reent *r, int fd, const char *ptr, int len )
} }
/* syscall implementation for stdio read from UART */ /* 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; int ch, i;

View file

@ -0,0 +1,5 @@
# Makefile for access_point example
PROGRAM=access_point
EXTRA_COMPONENTS=extras/dhcpserver
include ../../common.mk

View 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);
}
}

View file

@ -8,13 +8,10 @@
#include "task.h" #include "task.h"
#include "esp8266.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. /* 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) 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 The step that sets the iomux register can't be automatically
mapping from GPIO to IOMUX ports. 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 There is no significant performance benefit to this way over the
blinkenTask version, so it's probably better to use the blinkenTask blinkenTask version, so it's probably better to use the blinkenTask
@ -42,7 +41,7 @@ void blinkenTask(void *pvParameters)
void blinkenRegisterTask(void *pvParameters) void blinkenRegisterTask(void *pvParameters)
{ {
GPIO.ENABLE_OUT_SET = BIT(gpio); 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) { while(1) {
GPIO.OUT_SET = BIT(gpio); GPIO.OUT_SET = BIT(gpio);
vTaskDelay(1000 / portTICK_RATE_MS); vTaskDelay(1000 / portTICK_RATE_MS);

View file

@ -0,0 +1,3 @@
PROGRAM=ds18b20_broadcaster
EXTRA_COMPONENTS = extras/onewire extras/ds18b20
include ../../common.mk

View 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()
```

View 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);
}

View file

@ -0,0 +1,3 @@
PROGRAM=ds18b20_onewire
EXTRA_COMPONENTS = extras/onewire extras/ds18b20
include ../../common.mk

View 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);
}

View file

@ -17,7 +17,7 @@ const char *dramtest = TESTSTRING;
const __attribute__((section(".iram1.notrodata"))) char iramtest[] = TESTSTRING; const __attribute__((section(".iram1.notrodata"))) char iramtest[] = TESTSTRING;
const __attribute__((section(".text.notrodata"))) char iromtest[] = 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; uint32_t ccount;
asm volatile ("rsr.ccount %0" : "=a" (ccount)); asm volatile ("rsr.ccount %0" : "=a" (ccount));

View file

@ -10,30 +10,34 @@
#include <string.h> #include <string.h>
const char *server_root_cert = "-----BEGIN CERTIFICATE-----\r\n" const char *server_root_cert = "-----BEGIN CERTIFICATE-----\r\n"
"MIIEWTCCA0GgAwIBAgIDAjpjMA0GCSqGSIb3DQEBBQUAMEIxCzAJBgNVBAYTAlVT\r\n" "MIIFNzCCBB+gAwIBAgISAfl7TPw6Mf/F6VCBc5eaHA7kMA0GCSqGSIb3DQEBCwUA\r\n"
"MRYwFAYDVQQKEw1HZW9UcnVzdCBJbmMuMRswGQYDVQQDExJHZW9UcnVzdCBHbG9i\r\n" "MEoxCzAJBgNVBAYTAlVTMRYwFAYDVQQKEw1MZXQncyBFbmNyeXB0MSMwIQYDVQQD\r\n"
"YWwgQ0EwHhcNMTIwODI3MjA0MDQwWhcNMjIwNTIwMjA0MDQwWjBEMQswCQYDVQQG\r\n" "ExpMZXQncyBFbmNyeXB0IEF1dGhvcml0eSBYMTAeFw0xNTEyMzAwNzQ0MDBaFw0x\r\n"
"EwJVUzEWMBQGA1UEChMNR2VvVHJ1c3QgSW5jLjEdMBsGA1UEAxMUR2VvVHJ1c3Qg\r\n" "NjAzMjkwNzQ0MDBaMBwxGjAYBgNVBAMTEXd3dy5ob3dzbXlzc2wuY29tMIIBIjAN\r\n"
"U1NMIENBIC0gRzIwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQC5J/lP\r\n" "BgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEArKF7WzSrDPinQhd9mVfoW5u46/TC\r\n"
"2Pa3FT+Pzc7WjRxr/X/aVCFOA9jK0HJSFbjJgltYeYT/JHJv8ml/vJbZmnrDPqnP\r\n" "fbYKR3MEryetUSeQuwuXFj2xO6+a/JQ99UC3Eq+9s8uFdx1zFFS6qfW+HXBwGWVf\r\n"
"UCITDoYZ2+hJ74vm1kfy/XNFCK6PrF62+J589xD/kkNm7xzU7qFGiBGJSXl6Jc5L\r\n" "ajKEyIcXUJZCRn7aWpTWZq6cuv4bZSv1QklGViQs8UCZifcN0A/mYrH7zHG2WDn2\r\n"
"avDXHHYaKTzJ5P0ehdzgMWUFRxasCgdLLnBeawanazpsrwUSxLIRJdY+lynwg2xX\r\n" "fxNgA+nJBqbZPr1gP9hqGFCnX+dPR5WxtC9+Dv9Sx+wiOWVz/obVTCygdqqcpa5I\r\n"
"HNil78zs/dYS8T/bQLSuDxjTxa9Akl0HXk7+Yhc3iemLdCai7bgK52wVWzWQct3Y\r\n" "3/U9REVgO2VfT+xMty6NZTMCjTJ+GXZuB/BrMe9+ZmgWk0grJyqdrCxOCyK6B4g+\r\n"
"TSHUQCNcj+6AMRaraFX0DjtU6QRN8MxOgV7pb1JpTr6mFm1C9VH/4AtWPJhPc48O\r\n" "Fvs8WFRNTHdQnP3/NT5hPtreZ3nuY2YY7RbGFwUaBcvJwbbIqalpiQ1X7QIDAQAB\r\n"
"bxoj8cnI2d+87FLXAgMBAAGjggFUMIIBUDAfBgNVHSMEGDAWgBTAephojYn7qwVk\r\n" "o4ICQzCCAj8wDgYDVR0PAQH/BAQDAgWgMB0GA1UdJQQWMBQGCCsGAQUFBwMBBggr\r\n"
"DBF9qn1luMrMTjAdBgNVHQ4EFgQUEUrQcznVW2kIXLo9v2SaqIscVbwwEgYDVR0T\r\n" "BgEFBQcDAjAMBgNVHRMBAf8EAjAAMB0GA1UdDgQWBBQMAe087CSp3PjgqyIYyWTR\r\n"
"AQH/BAgwBgEB/wIBADAOBgNVHQ8BAf8EBAMCAQYwOgYDVR0fBDMwMTAvoC2gK4Yp\r\n" "a2aMnTAfBgNVHSMEGDAWgBSoSmpjBH3duubRObemRWXv86jsoTBwBggrBgEFBQcB\r\n"
"aHR0cDovL2NybC5nZW90cnVzdC5jb20vY3Jscy9ndGdsb2JhbC5jcmwwNAYIKwYB\r\n" "AQRkMGIwLwYIKwYBBQUHMAGGI2h0dHA6Ly9vY3NwLmludC14MS5sZXRzZW5jcnlw\r\n"
"BQUHAQEEKDAmMCQGCCsGAQUFBzABhhhodHRwOi8vb2NzcC5nZW90cnVzdC5jb20w\r\n" "dC5vcmcvMC8GCCsGAQUFBzAChiNodHRwOi8vY2VydC5pbnQteDEubGV0c2VuY3J5\r\n"
"TAYDVR0gBEUwQzBBBgpghkgBhvhFAQc2MDMwMQYIKwYBBQUHAgEWJWh0dHA6Ly93\r\n" "cHQub3JnLzBNBgNVHREERjBEgg1ob3dzbXlzc2wuY29tgg1ob3dzbXl0bHMuY29t\r\n"
"d3cuZ2VvdHJ1c3QuY29tL3Jlc291cmNlcy9jcHMwKgYDVR0RBCMwIaQfMB0xGzAZ\r\n" "ghF3d3cuaG93c215dGxzLmNvbYIRd3d3Lmhvd3NteXNzbC5jb20wgf4GA1UdIASB\r\n"
"BgNVBAMTElZlcmlTaWduTVBLSS0yLTI1NDANBgkqhkiG9w0BAQUFAAOCAQEAPOU9\r\n" "9jCB8zAIBgZngQwBAgEwgeYGCysGAQQBgt8TAQEBMIHWMCYGCCsGAQUFBwIBFhpo\r\n"
"WhuiNyrjRs82lhg8e/GExVeGd0CdNfAS8HgY+yKk3phLeIHmTYbjkQ9C47ncoNb/\r\n" "dHRwOi8vY3BzLmxldHNlbmNyeXB0Lm9yZzCBqwYIKwYBBQUHAgIwgZ4MgZtUaGlz\r\n"
"qfixeZeZ0cNsQqWSlOBdDDMYJckrlVPg5akMfUf+f1ExRF73Kh41opQy98nuwLbG\r\n" "IENlcnRpZmljYXRlIG1heSBvbmx5IGJlIHJlbGllZCB1cG9uIGJ5IFJlbHlpbmcg\r\n"
"mqzemSFqI6A4ZO6jxIhzMjtQzr+t03UepvTp+UJrYLLdRf1dVwjOLVDmEjIWE4ry\r\n" "UGFydGllcyBhbmQgb25seSBpbiBhY2NvcmRhbmNlIHdpdGggdGhlIENlcnRpZmlj\r\n"
"lKKbR6iGf9mY5ffldnRk2JG8hBYo2CVEMH6C2Kyx5MDkFWzbtiQnAioBEoW6MYhY\r\n" "YXRlIFBvbGljeSBmb3VuZCBhdCBodHRwczovL2xldHNlbmNyeXB0Lm9yZy9yZXBv\r\n"
"R3TjuNJkpsMyWS4pS0XxW4lJLoKaxhgVRNAuZAEVaDj59vlmAwxVG52/AECu8Egn\r\n" "c2l0b3J5LzANBgkqhkiG9w0BAQsFAAOCAQEALB2QrIrcxxFr81b6khy9LwVBpthL\r\n"
"TOCAXi25KhV6vGb4NQ==\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"; "-----END CERTIFICATE-----\r\n";

View file

@ -1,8 +1,8 @@
/* A very simple OTA example /* 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!!!! * NOT SUITABLE TO PUT ON THE INTERNET OR INTO A PRODUCTION ENVIRONMENT!!!!
*/ */

View file

@ -0,0 +1,4 @@
# Simple makefile for simple example
PROGRAM=pwm_test
COMPONENTS = FreeRTOS lwip core extras/pwm
include ../../common.mk

View 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);
}

View file

@ -14,14 +14,6 @@ void user_init(void)
printf("SDK version:%s\n", sdk_system_get_sdk_version()); printf("SDK version:%s\n", sdk_system_get_sdk_version());
printf("Going into echo mode...\n"); 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) { while(1) {
int c = getchar(); int c = getchar();
if(c != EOF) if(c != EOF)

View 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>

View file

@ -0,0 +1,3 @@
PROGRAM=terminal
EXTRA_COMPONENTS=extras/stdin_uart_interrupt
include ../../common.mk

View 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();
}

View file

@ -0,0 +1,4 @@
PROGRAM=tls_server
COMPONENTS = FreeRTOS lwip core extras/mbedtls
include ../../common.mk

View 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";

View 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);
}

View file

@ -0,0 +1,6 @@
# Makefile for the ws2812 Rainbow example
PROGRAM=ws2812_rainbow
EXTRA_COMPONENTS = extras/ws2812
include ../../common.mk

View 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
}

View 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))

View 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;
}

View 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

View 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
View 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
View 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

View file

@ -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 mbedtls_net_bind( mbedtls_net_context *ctx, const char *bind_ip, const char *port, int proto )
{ {
int n, ret; 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 ) if( ( ret = net_prepare() ) != 0 )
return( ret ); return( ret );
/* Bind to IPv6 and/or IPv4, but only in the desired protocol */ if(bind_ip == NULL) {
memset( &hints, 0, sizeof( hints ) ); /* mbedTLS docs specify bind_ip == NULL means all interfaces, but lwip getaddrinfo() assumes NULL
hints.ai_family = AF_UNSPEC; means localhost. So we swap in a precreated IPADDR_ANY addrinfo result here. */
hints.ai_socktype = proto == MBEDTLS_NET_PROTO_UDP ? SOCK_DGRAM : SOCK_STREAM; addr_list = &all_interfaces_addr;
hints.ai_protocol = proto == MBEDTLS_NET_PROTO_UDP ? IPPROTO_UDP : IPPROTO_TCP; }
else if( getaddrinfo( bind_ip, port, &hints, &addr_list ) != 0 ) {
if( getaddrinfo( bind_ip, port, &hints, &addr_list ) != 0 )
return( MBEDTLS_ERR_NET_UNKNOWN_HOST ); return( MBEDTLS_ERR_NET_UNKNOWN_HOST );
}
/* Try the sockaddrs until a binding succeeds */ /* Try the sockaddrs until a binding succeeds */
ret = MBEDTLS_ERR_NET_UNKNOWN_HOST; 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; break;
} }
freeaddrinfo( addr_list ); if(bind_ip != NULL) {
freeaddrinfo( addr_list );
}
return( ret ); return( ret );

31
extras/onewire/LICENSE Normal file
View 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
View 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.

View 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
View 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
View 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

View 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
View 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
View 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
View 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
View 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
View 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();

View 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.

View file

@ -20,6 +20,8 @@
* IMPORTANT: TFTP is not a secure protocol. * IMPORTANT: TFTP is not a secure protocol.
* Only allow TFTP OTA updates on trusted networks. * 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. /* Start a FreeRTOS task to wait to receive an OTA update from a TFTP client.

View file

@ -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 rBoot - User API and OTA support for rBoot on the ESP8266
--------------------------------------------------------- ---------------------------------------------------------
by Richard A Burton, richardaburton@gmail.com by Richard A Burton, richardaburton@gmail.com

View 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.

View 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))

View 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;
}

View 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

View 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
View 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
View 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 */

View file

@ -35,7 +35,7 @@ struct sdk_scan_config {
}; };
struct sdk_bss_info { struct sdk_bss_info {
STAILQ_ENTRY(bss_info) next; STAILQ_ENTRY(sdk_bss_info) next;
uint8_t bssid[6]; uint8_t bssid[6];
uint8_t ssid[32]; uint8_t ssid[32];

View file

@ -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_restore(void);
void sdk_system_restart(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); void sdk_system_deep_sleep(uint32_t time_in_us);
uint32_t sdk_system_get_time(void); 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); 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_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 #ifdef __cplusplus
} }

View file

@ -23,9 +23,48 @@ typedef enum {
uint32_t sdk_spi_flash_get_id(void); uint32_t sdk_spi_flash_get_id(void);
sdk_SpiFlashOpResult sdk_spi_flash_read_status(uint32_t *status); sdk_SpiFlashOpResult sdk_spi_flash_read_status(uint32_t *status);
sdk_SpiFlashOpResult sdk_spi_flash_write_status(uint32_t status_value); 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_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; extern sdk_flashchip_t sdk_flashchip;

View file

@ -1,7 +1,7 @@
/* This linker script generated from xt-genldscripts.tpp for LSP . /*
* Common (OTA and non-OTA) parts for the esp-open-rtos Linker Script
Modified for esp open RTOS, this linker script is no longer the same as the esp_iot_rtos_sdk one. *
*/ */
/* FreeRTOS memory management functions /* FreeRTOS memory management functions
@ -28,56 +28,6 @@ _lock_release_recursive = vPortExitCritical;
/* SDK compatibility */ /* SDK compatibility */
ets_printf = printf; 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 PHDRS
{ {
dport0_0_phdr PT_LOAD; dport0_0_phdr PT_LOAD;

15
ld/nonota.ld Normal file
View 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
View 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)
}

View file

@ -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_sector_erase = 0x400040c0 );
PROVIDE ( SPI_page_program = 0x40004174 ); PROVIDE ( SPI_page_program = 0x40004174 );
PROVIDE ( SPI_read_data = 0x400042ac ); PROVIDE ( SPI_read_data = 0x400042ac );
@ -8,22 +16,22 @@ PROVIDE ( Wait_SPI_Idle = 0x4000448c );
PROVIDE ( Enable_QMode = 0x400044c0 ); PROVIDE ( Enable_QMode = 0x400044c0 );
PROVIDE ( Disable_QMode = 0x40004508 ); 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 ( rom_Cache_Read_Enable = 0x40004678 );
PROVIDE ( Cache_Read_Enable = rom_Cache_Read_Enable );
PROVIDE ( Cache_Read_Disable = 0x400047f0 ); 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_build_chain = 0x40004f40 );
PROVIDE ( lldesc_num2link = 0x40005050 ); PROVIDE ( lldesc_num2link = 0x40005050 );
PROVIDE ( lldesc_set_owner = 0x4000507c ); 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 ( __adddf3 = 0x4000c538 );
PROVIDE ( __addsf3 = 0x4000c180 ); PROVIDE ( __addsf3 = 0x4000c180 );
PROVIDE ( __divdf3 = 0x4000cb94 ); PROVIDE ( __divdf3 = 0x4000cb94 );

View file

@ -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

View 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

View file

@ -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; return reason;
} }

48
utils/addrsource Executable file
View 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"