Merge branch 'master' into experiments/unaligned_load

This commit is contained in:
Angus Gratton 2015-09-10 08:19:42 +10:00
commit ac0a947453
60 changed files with 2509 additions and 858 deletions

62
.travis.yml Normal file
View file

@ -0,0 +1,62 @@
language: c
sudo: false
env:
# Target commit for https://github.com/pfalcon/esp-open-sdk/
OPENSDK_COMMIT=b44afa47
CROSS_ROOT="${HOME}/toolchain-${OPENSDK_COMMIT}"
CROSS_BINDIR="${CROSS_ROOT}/bin"
ESPTOOL2_COMMIT=92530bb8
ESPTOOL2_BINDIR="${HOME}/esptool2-${ESPTOOL2_COMMIT}"
PATH=${PATH}:${CROSS_BINDIR}:${ESPTOOL2_BINDIR}
cache:
directories:
- ${CROSS_ROOT}
- ${HOME}/.ccache
- ${ESPTOOL2_BINDIR}
addons:
apt:
packages:
- make
- unrar
- autoconf
- automake
- libtool
- gcc
- g++
- gperf
- flex
- bison
- texinfo
- gawk
- libncurses5-dev
- libexpat1-dev
- python
- python-serial
- sed
- git
before_install:
# Install a toolchain using esp-open-sdk (parts we need for this are the GNU toolchain and libhal)
#
# Adds hack of "{$HAS_TC} || -Buildstep-" to avoid rebuilding toolchain if it's already
# installed from the cache. If this gets any more complex it should be spun out to a standalone shell script.
- export HAS_TC="test -d ${CROSS_BINDIR}"
- unset CC # Travis sets this due to "language: c", but it confuses autotools configure when cross-building
- ${HAS_TC} || git clone --recursive https://github.com/pfalcon/esp-open-sdk.git
- ${HAS_TC} || cd esp-open-sdk
- ${HAS_TC} || git reset --hard ${OPENSDK_COMMIT}
- ${HAS_TC} || git submodule update
- ${HAS_TC} || sed -i "s/2.69/2.68/" lx106-hal/configure.ac # this is a nasty hack as Ubuntu Precise only has autoconf 2.68 not 2.69...
- ${HAS_TC} || sed -r -i 's%TOOLCHAIN ?=.*%TOOLCHAIN=${CROSS_ROOT}%' Makefile
- ${HAS_TC} || make STANDALONE=n
- export HAS_ET2="test -f ${ESPTOOL2_BINDIR}/esptool2"
- ${HAS_ET2} || git clone https://github.com/raburton/esp8266 ${HOME}/raburton
- ${HAS_ET2} || make -C ${HOME}/raburton/esptool2
- ${HAS_ET2} || mkdir -p ${ESPTOOL2_BINDIR}
- ${HAS_ET2} || cp -a ${HOME}/raburton/esptool2/esptool2 ${ESPTOOL2_BINDIR}/
script:
- cd ${TRAVIS_BUILD_DIR}
# Remove ssid_config requirement for examples
- sed -i "s%#warning%//#warning%" include/ssid_config.h
- make -C examples/ build-examples CROSS="ccache xtensa-lx106-elf-"

View file

@ -1,8 +1,7 @@
INC_DIRS += $(freertos_MAIN)/include $(freertos_MAIN)/portable/esp8266 INC_DIRS += $(freertos_MAIN)include $(freertos_MAIN)portable/esp8266
# args for passing into compile rule generation # args for passing into compile rule generation
freertos_ROOT = $(ROOT)FreeRTOS/
freertos_MAIN = $(freertos_ROOT)Source/ freertos_MAIN = $(freertos_ROOT)Source/
freertos_INC_DIR = $(freertos_MAIN)include $(freertos_MAIN)portable/esp8266 freertos_INC_DIR = $(freertos_MAIN)include $(freertos_MAIN)portable/esp8266
freertos_SRC_DIR = $(freertos_MAIN) $(freertos_MAIN)portable/esp8266 freertos_SRC_DIR = $(freertos_MAIN) $(freertos_MAIN)portable/esp8266

View file

@ -4,15 +4,25 @@ A community developed open source [FreeRTOS](http://www.freertos.org/)-based fra
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/esp_iot_rtos_sdk).
## Resources
[![Build Status](https://travis-ci.org/SuperHouse/esp-open-rtos.svg?branch=master)](https://travis-ci.org/SuperHouse/esp-open-rtos)
Email discussion list: https://groups.google.com/d/forum/esp-open-rtos
Github issues list/bugtracker: http://github.com/superhouse/esp-open-rtos/issues
Please note that this project is released with a [Contributor Code of Conduct](https://github.com/SuperHouse/esp-open-rtos/blob/master/code_of_conduct.md). By participating in this project you agree to abide by its terms.
## Quick Start ## 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. (Despite the similar name esp-open-sdk has different maintainers - but we think it's fantastic!)
(Other toolchains will also work, as long as a gcc cross-compiler is available on the PATH. 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.)
* Install [esptool.py](https://github.com/themadinventor/esptool) and make it available on your PATH. * Install [esptool.py](https://github.com/themadinventor/esptool) and make it available on your PATH. If you used esp-open-sdk then this is done already.
* The build process uses `GNU Make`, and the utilities `sed` and `grep`. Linux & OS X should have these already. Windows users can get these tools a variety of ways - [MingGW](http://www.mingw.org/wiki/mingw) is one option. * The esp-open-rtos build process uses `GNU Make`, and the utilities `sed` and `grep`. If you built esp-open-sdk then you have these already.
* Use git to clone the esp-open-rtos project (note the `--recursive`): * Use git to clone the esp-open-rtos project (note the `--recursive`):
@ -21,12 +31,15 @@ git clone --recursive https://github.com/Superhouse/esp-open-rtos.git
cd esp-open-rtos cd esp-open-rtos
``` ```
* To build any examples that use WiFi, create a file "local.h" in the top-level directory and add two macro defines to it: * To build any examples that use WiFi, edit `include/ssid_config.h` and change the two macro defines:
```c ```c
#define WIFI_SSID "mywifissid" #define WIFI_SSID "mywifissid"
#define WIFI_PASS "my secret password" #define WIFI_PASS "my secret password"
``` ```
Remove the `#warning` line and follow the git ignore instructions written in the header file to keep your credentials from being pushed to Github.
* Build an example project (found in the 'examples' directory) and flash it to a serial port: * Build an example project (found in the 'examples' directory) and flash it to a serial port:
``` ```
@ -35,6 +48,8 @@ make flash -j4 -C examples/http_get ESPPORT=/dev/ttyUSB0
Run `make help -C examples/http_get` for a summary of other Make targets. Run `make help -C examples/http_get` for a summary of other Make targets.
(Note: the `-C` option to make is the same as changing to that directory, then running make.)
The [Build Process wiki page](https://github.com/SuperHouse/esp-open-rtos/wiki/Build-Process) has in-depth details of the build process. The [Build Process wiki page](https://github.com/SuperHouse/esp-open-rtos/wiki/Build-Process) has in-depth details of the build process.
## Goals ## Goals
@ -44,7 +59,20 @@ The [Build Process wiki page](https://github.com/SuperHouse/esp-open-rtos/wiki/B
* Leave upstream source clean, for easy interaction with upstream projects. * Leave upstream source clean, for easy interaction with upstream projects.
* Flexible build and compilation settings. * Flexible build and compilation settings.
Current status is alpha quality, under development. AP STATION mode (ie wifi client mode) and UDP/TCP client modes are tested. Other functionality should work. Contributors and testers are welcome! Current status is alpha quality, actively developed. AP STATION mode (ie wifi client mode) and UDP/TCP client modes are tested. Other functionality should work. Contributors and testers are welcome!
## Code Structure
* `examples` contains a range of example projects (one per subdirectory). Check them out!
* `include` contains header files from Espressif RTOS SDK, relating to the binary libraries & Xtensa core.
* `core` contains source & headers for low-level ESP8266 functions & peripherals. `core/include/esp` contains useful headers for peripheral access, etc. Minimal to no FreeRTOS dependencies.
* `extras` is a directory that contains optional components that can be added to your project. Most 'extras' components will have a corresponding example in the `examples` directory. Extras include:
- i2c - software i2c driver ([upstream project](https://github.com/kanflo/esp-open-rtos-driver-i2c))
- rboot-ota - OTA support (over-the-air updates) including a TFTP server for receiving updates ([for rboot by @raburton](http://richard.burtons.org/2015/05/18/rboot-a-new-boot-loader-for-esp8266/))
- bmp180 driver for digital pressure sensor ([upstream project](https://github.com/Angus71/esp-open-rtos-driver-bmp180))
* `FreeRTOS` contains FreeRTOS implementation, subdirectory structure is the standard FreeRTOS structure. `FreeRTOS/source/portable/esp8266/` contains the ESP8266 port.
* `lwip` and `axtls` contain the lwIP TCP/IP library and the axTLS TLS library ('libssl' in the esp8266 SDKs), respectively. See [Third Party Libraries](https://github.com/SuperHouse/esp-open-rtos/wiki/Third-Party-Libraries) wiki page for details.
* `libc` contains the newlib libc. [Libc details here](https://github.com/SuperHouse/esp-open-rtos/wiki/libc-configuration).
## Open Source Components ## Open Source Components
@ -66,15 +94,6 @@ Some binary libraries appear to contain unattributed open source code:
* libnet80211.a & libwpa.a appear to be based on FreeBSD net80211/wpa, or forks of them. ([See this issue](https://github.com/SuperHouse/esp-open-rtos/issues/4)). * libnet80211.a & libwpa.a appear to be based on FreeBSD net80211/wpa, or forks of them. ([See this issue](https://github.com/SuperHouse/esp-open-rtos/issues/4)).
* libudhcp has been removed from esp-open-rtos. It was released with the Espressif RTOS SDK but udhcp is GPL licensed. * libudhcp has been removed from esp-open-rtos. It was released with the Espressif RTOS SDK but udhcp is GPL licensed.
## Code Structure
* `examples` contains a range of example projects (one per subdirectory). Check them out!
* `include` contains header files from Espressif RTOS SDK, relating to the binary libraries & Xtensa core.
* `core` contains source & headers for low-level ESP8266 functions & peripherals. `core/include/esp` contains useful headers for peripheral access, etc. Still being fleshed out. Minimal to no FreeRTOS dependencies.
* `FreeRTOS` contains FreeRTOS implementation, subdirectory structure is the standard FreeRTOS structure. `FreeRTOS/source/portable/esp8266/` contains the ESP8266 port.
* `lwip` and `axtls` contain the lwIP TCP/IP library and the axTLS TLS library ('libssl' in the esp8266 SDKs), respectively. See [Third Party Libraries](https://github.com/SuperHouse/esp-open-rtos/wiki/Third-Party-Libraries) wiki page for details.
## Licensing ## Licensing
* BSD license (as described in LICENSE) applies to original source files, [lwIP](http://lwip.wikia.com/wiki/LwIP_Wiki), and [axTLS](http://axtls.sourceforge.net/). lwIP is Copyright (C) Swedish Institute of Computer Science. axTLS is Copyright (C) Cameron Rich. * BSD license (as described in LICENSE) applies to original source files, [lwIP](http://lwip.wikia.com/wiki/LwIP_Wiki), and [axTLS](http://axtls.sourceforge.net/). lwIP is Copyright (C) Swedish Institute of Computer Science. axTLS is Copyright (C) Cameron Rich.
@ -85,6 +104,8 @@ Some binary libraries appear to contain unattributed open source code:
* Newlib is covered by several copyrights and licenses, as per the files in the `libc` directory. * Newlib is covered by several copyrights and licenses, as per the files in the `libc` directory.
Components under `extras/` may contain different licenses, please see those directories for details.
## Contributions ## Contributions
Contributions are very welcome! Contributions are very welcome!

View file

@ -6,13 +6,12 @@
# We supply our own hand tweaked config.h in the external 'include' dir. # We supply our own hand tweaked config.h in the external 'include' dir.
AXTLS_DIR = $(ROOT)axtls/axtls/ AXTLS_DIR = $(axtls_ROOT)axtls/
INC_DIRS += $(ROOT)axtls/include $(AXTLS_DIR)ssl $(AXTLS_DIR)crypto INC_DIRS += $(axtls_ROOT)include $(AXTLS_DIR)ssl $(AXTLS_DIR)crypto
# args for passing into compile rule generation # args for passing into compile rule generation
axtls_ROOT = $(ROOT)axtls
axtls_INC_DIR = $(AXTLS_DIR)include $(AXTLS_DIR) axtls_INC_DIR = $(AXTLS_DIR)include $(AXTLS_DIR)
axtls_SRC_DIR = $(AXTLS_DIR)crypto $(AXTLS_DIR)ssl $(ROOT)axtls axtls_SRC_DIR = $(AXTLS_DIR)crypto $(AXTLS_DIR)ssl $(axtls_ROOT)
#axtls_CFLAGS = $(CFLAGS) -Wno-address #axtls_CFLAGS = $(CFLAGS) -Wno-address

22
code_of_conduct.md Normal file
View file

@ -0,0 +1,22 @@
# Contributor Code of Conduct
As contributors and maintainers of this project, and in the interest of fostering an open and welcoming community, we pledge to respect all people who contribute through reporting issues, posting feature requests, updating documentation, submitting pull requests or patches, and other activities.
We are committed to making participation in this project a harassment-free experience for everyone, regardless of level of experience, gender, gender identity and expression, sexual orientation, disability, personal appearance, body size, race, ethnicity, age, religion, or nationality.
Examples of unacceptable behavior by participants include:
* The use of sexualized language or imagery
* Personal attacks
* Trolling or insulting/derogatory comments
* Public or private harassment
* Publishing other's private information, such as physical or electronic addresses, without explicit permission
* Other unethical or unprofessional conduct.
Project maintainers have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct. By adopting this Code of Conduct, project maintainers commit themselves to fairly and consistently applying these principles to every aspect of managing this project. Project maintainers who do not follow or enforce the Code of Conduct may be permanently removed from the project team.
This code of conduct applies both within project spaces and in public spaces when an individual is representing the project or its community.
Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by opening an issue or contacting one or more of the project maintainers.
This Code of Conduct is adapted from the [Contributor Covenant](http://contributor-covenant.org), version 1.2.0, available at [http://contributor-covenant.org/version/1/2/0/](http://contributor-covenant.org/version/1/2/0/)

View file

@ -80,7 +80,7 @@ OBJDUMP = $(CROSS)objdump
# Source components to compile and link. Each of these are subdirectories # Source components to compile and link. Each of these are subdirectories
# of the root, with a 'component.mk' file. # of the root, with a 'component.mk' file.
COMPONENTS ?= core FreeRTOS lwip axtls $(EXTRA_COMPONENTS) COMPONENTS ?= $(EXTRA_COMPONENTS) FreeRTOS lwip axtls core
# binary esp-iot-rtos SDK libraries to link. These are pre-processed prior to linking. # binary esp-iot-rtos SDK libraries to link. These are pre-processed prior to linking.
SDK_LIBS ?= main net80211 phy pp wpa SDK_LIBS ?= main net80211 phy pp wpa
@ -194,26 +194,25 @@ all: $(PROGRAM_OUT) $(FW_FILE_1) $(FW_FILE_2) $(FW_FILE)
# component_compile_rules: Produces compilation rules for a given # component_compile_rules: Produces compilation rules for a given
# component # component
# #
# For user-facing documentation, see:
# https://github.com/SuperHouse/esp-open-rtos/wiki/Build-Process#adding-a-new-component
#
# Call arguments are: # Call arguments are:
# $(1) - component name # $(1) - component name
# #
# Expects that the following component-specific variables are defined: # Expects that the following component-specific variables are defined:
# #
# $(1)_ROOT = Top-level dir containing component. Can be in-tree or out-of-tree. # $(1)_ROOT = Top-level dir containing component. Can be in-tree or out-of-tree.
# (if this variable isn't defined, directory containing component.mk is used)
# $(1)_SRC_DIR = List of source directories for the component. All must be under $(1)_ROOT # $(1)_SRC_DIR = List of source directories for the component. All must be under $(1)_ROOT
# $(1)_INC_DIR = List of include directories specific for the component # $(1)_INC_DIR = List of include directories specific for the component
# #
# As an alternative to $(1)_SRC_DIR, you can specify source filenames
# as $(1)_SRC_FILES. If you want to specify both directories and
# some additional files, specify directories in $(1)_SRC_DIR and
# additional files in $(1)_EXTRA_SRC_FILES.
#
# Optional variables:
# $(1)_CFLAGS = CFLAGS to override the default CFLAGS for this component only.
# #
# Each call appends to COMPONENT_ARS which is a list of archive files for compiled components # Each call appends to COMPONENT_ARS which is a list of archive files for compiled components
COMPONENT_ARS = COMPONENT_ARS =
define component_compile_rules define component_compile_rules
$(1)_DEFAULT_ROOT := $(dir $(lastword $(MAKEFILE_LIST)))
$(1)_ROOT ?= $$($(1)_DEFAULT_ROOT)
$(1)_OBJ_DIR = $(call lc,$(BUILD_DIR)$(1)/) $(1)_OBJ_DIR = $(call lc,$(BUILD_DIR)$(1)/)
### determine source files and object files ### ### determine source files and object files ###
$(1)_SRC_FILES ?= $$(foreach sdir,$$($(1)_SRC_DIR), \ $(1)_SRC_FILES ?= $$(foreach sdir,$$($(1)_SRC_DIR), \
@ -305,17 +304,18 @@ $(BUILD_DIR)sdklib/%.a: $(BUILD_DIR)sdklib/%_stage1.a $(BUILD_DIR)sdklib/allsymb
PROGRAM_SRC_DIR ?= $(PROGRAM_DIR) PROGRAM_SRC_DIR ?= $(PROGRAM_DIR)
PROGRAM_ROOT ?= $(PROGRAM_DIR) PROGRAM_ROOT ?= $(PROGRAM_DIR)
PROGRAM_MAKEFILE = $(firstword $(MAKEFILE_LIST)) PROGRAM_MAKEFILE = $(firstword $(MAKEFILE_LIST))
# if there's a local.h file in either the program dir or the
# root dir, load macros from it (for WIFI_SSID,WIFI_PASS, etc.)
PROGRAM_LOCAL_H = $(lastword $(wildcard $(ROOT)local.h $(PROGRAM_DIR)local.h))
ifneq ($(PROGRAM_LOCAL_H),)
PROGRAM_CFLAGS = $(CFLAGS) -imacros $(PROGRAM_LOCAL_H)
endif
$(eval $(call component_compile_rules,PROGRAM)) $(eval $(call component_compile_rules,PROGRAM))
## Include other components (this is where the actual compiler sections are generated) ## Include other components (this is where the actual compiler sections are generated)
$(foreach component,$(COMPONENTS), $(eval include $(ROOT)$(component)/component.mk)) ##
## if component directory exists relative to $(ROOT), use that.
## otherwise try to resolve it as an absolute path
$(foreach component,$(COMPONENTS), \
$(if $(wildcard $(ROOT)$(component)), \
$(eval include $(ROOT)$(component)/component.mk), \
$(eval include $(component)/component.mk) \
) \
)
## Run linker scripts via C preprocessor to evaluate macros ## Run linker scripts via C preprocessor to evaluate macros
$(LD_DIR)%.ld: $(ROOT)ld/%.ld | $(LD_DIR) $(LD_DIR)%.ld: $(ROOT)ld/%.ld | $(LD_DIR)
@ -324,7 +324,7 @@ $(LD_DIR)%.ld: $(ROOT)ld/%.ld | $(LD_DIR)
# 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_PROCESSED)
$(vecho) "LD $@" $(vecho) "LD $@"
$(Q) $(LD) $(LDFLAGS) -Wl,--start-group $(LIB_ARGS) $(SDK_LIB_ARGS) $(COMPONENT_ARS) -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) $(FW_BASE) $(BUILD_DIR)sdklib $(LD_DIR):
$(Q) mkdir -p $@ $(Q) mkdir -p $@

View file

@ -1,6 +1,6 @@
INC_DIRS += $(core_ROOT)include INC_DIRS += $(core_ROOT)include
# args for passing into compile rule generation # args for passing into compile rule generation
core_ROOT = $(ROOT)core/
core_SRC_DIR = $(core_ROOT) core_SRC_DIR = $(core_ROOT)
$(eval $(call component_compile_rules,core)) $(eval $(call component_compile_rules,core))

View file

@ -25,7 +25,7 @@
OR OR
- Implement a single function named gpio_interrupt_handler(). This - Implement a single function named gpio_interrupt_handler(). This
will need to manually check GPIO_STATUS_REG and clear any status will need to manually check GPIO.STATUS and clear any status
bits after handling interrupts. This gives you full control, but bits after handling interrupts. This gives you full control, but
you can't combine it with the first approach. you can't combine it with the first approach.
@ -67,14 +67,14 @@ const gpio_interrupt_handler_t gpio_interrupt_handlers[16] = {
void __attribute__((weak)) IRAM gpio_interrupt_handler(void) void __attribute__((weak)) IRAM gpio_interrupt_handler(void)
{ {
uint32_t status_reg = GPIO_STATUS_REG; uint32_t status_reg = GPIO.STATUS;
GPIO_STATUS_CLEAR = status_reg; GPIO.STATUS_CLEAR = status_reg;
uint8_t gpio_idx; uint8_t gpio_idx;
while((gpio_idx = __builtin_ffs(status_reg))) while((gpio_idx = __builtin_ffs(status_reg)))
{ {
gpio_idx--; gpio_idx--;
status_reg &= ~BIT(gpio_idx); status_reg &= ~BIT(gpio_idx);
if(GPIO_CTRL_REG(gpio_idx) & GPIO_INT_MASK) if(FIELD2VAL(GPIO_CONF_INTTYPE, GPIO.CONF[gpio_idx]))
gpio_interrupt_handlers[gpio_idx](); gpio_interrupt_handlers[gpio_idx]();
} }
} }

View file

@ -14,12 +14,12 @@
* the arguments aren't known at compile time (values are evaluated at * the arguments aren't known at compile time (values are evaluated at
* compile time otherwise.) * compile time otherwise.)
*/ */
uint32_t _timer_freq_to_count_runtime(const timer_frc_t frc, const uint32_t freq, const timer_div_t div) uint32_t _timer_freq_to_count_runtime(const timer_frc_t frc, const uint32_t freq, const timer_clkdiv_t div)
{ {
return _timer_freq_to_count_impl(frc, freq, div); return _timer_freq_to_count_impl(frc, freq, div);
} }
uint32_t _timer_time_to_count_runtime(const timer_frc_t frc, uint32_t us, const timer_div_t div) uint32_t _timer_time_to_count_runtime(const timer_frc_t frc, uint32_t us, const timer_clkdiv_t div)
{ {
return _timer_time_to_count_runtime(frc, us, div); return _timer_time_to_count_runtime(frc, us, div);
} }

View file

@ -16,6 +16,25 @@
#define BIT(X) (1<<(X)) #define BIT(X) (1<<(X))
#endif #endif
/* These macros convert values to/from bitfields specified by *_M and *_S (mask
* and shift) constants. Used primarily with ESP8266 register access.
*/
#define VAL2FIELD(fieldname, value) ((value) << fieldname##_S)
#define FIELD2VAL(fieldname, regbits) (((regbits) >> fieldname##_S) & fieldname##_M)
#define FIELD_MASK(fieldname) (fieldname##_M << fieldname##_S)
#define SET_FIELD(regbits, fieldname, value) (((regbits) & ~FIELD_MASK(fieldname)) | VAL2FIELD(fieldname, value))
/* VAL2FIELD/SET_FIELD do not normally check to make sure that the passed value
* will fit in the specified field (without clobbering other bits). This makes
* them faster and is usually fine. If you do need to make sure that the value
* will not overflow the field, use VAL2FIELD_M or SET_FIELD_M (which will
* first mask the supplied value to only the allowed number of bits) instead.
*/
#define VAL2FIELD_M(fieldname, value) (((value) & fieldname##_M) << fieldname##_S)
#define SET_FIELD_M(regbits, fieldname, value) (((regbits) & ~FIELD_MASK(fieldname)) | VAL2FIELD_M(fieldname, value))
/* Use this macro to store constant values in IROM flash instead /* Use this macro to store constant values in IROM flash instead
of having them loaded into rodata (which resides in DRAM) of having them loaded into rodata (which resides in DRAM)

View file

@ -0,0 +1,125 @@
/* esp/dport_regs.h
*
* ESP8266 DPORT0 register definitions
*
* Not compatible with ESP SDK register access code.
*/
#ifndef _ESP_DPORT_REGS_H
#define _ESP_DPORT_REGS_H
#include "esp/types.h"
#include "common_macros.h"
#define DPORT_BASE 0x3ff00000
#define DPORT (*(struct DPORT_REGS *)(DPORT_BASE))
/* DPORT registers
Control various aspects of core/peripheral interaction... Not well
documented or understood.
*/
struct DPORT_REGS {
uint32_t volatile DPORT0; // 0x00 FIXME: need a better name for this
uint32_t volatile INT_ENABLE; // 0x04
uint32_t volatile _unknown08; // 0x08
uint32_t volatile SPI_READY; // 0x0c
uint32_t volatile _unknown10; // 0x10
uint32_t volatile CPU_CLOCK; // 0x14
uint32_t volatile CLOCKGATE_WATCHDOG; // 0x18
uint32_t volatile _unknown1c; // 0x1c
uint32_t volatile SPI_INT_STATUS; // 0x20
uint32_t volatile SPI_CACHE_RAM; // 0x24
uint32_t volatile PERI_IO; // 0x28
uint32_t volatile SLC_TX_DESC_DEBUG; // 0x2c
uint32_t volatile _unknown30; // 0x30
uint32_t volatile _unknown34; // 0x34
uint32_t volatile _unknown38; // 0x38
uint32_t volatile _unknown3c; // 0x3c
uint32_t volatile _unknown40; // 0x40
uint32_t volatile _unknown44; // 0x44
uint32_t volatile _unknown48; // 0x48
uint32_t volatile _unknown4c; // 0x4c
uint32_t volatile OTP_MAC0; // 0x50
uint32_t volatile OTP_MAC1; // 0x54
uint32_t volatile OTP_CHIPID; // 0x58
uint32_t volatile OTP_MAC2; // 0x5c
};
_Static_assert(sizeof(struct DPORT_REGS) == 0x60, "DPORT_REGS is the wrong size");
/* Details for DPORT0 register */
/* Currently very little known about this register. The following is based on analysis of the startup code in the Espressif SDK: */
#define DPORT_DPORT0_FIELD0_M 0x0000007f
#define DPORT_DPORT0_FIELD0_S 0
/* Details for INT_ENABLE register */
/* Set flags to enable CPU interrupts from some peripherals. Read/write.
bit 0 - INT_ENABLE_WDT (unclear exactly how this works. Set by RTOS SDK startup code)
bit 1 - INT_ENABLE_TIMER0 allows TIMER 0 (FRC1) to trigger interrupt INUM_TIMER_FRC1.
bit 2 - INT_ENABLE_TIMER1 allows TIMER 1 (FRC2) to trigger interrupt INUM_TIMER_FRC2.
Espressif calls this register "EDGE_INT_ENABLE_REG". The "edge" in
question is (I think) the interrupt line from the peripheral, as
the interrupt status bit is set. There may be a similar register
for enabling "level" interrupts instead of edge triggering
- this is unknown.
*/
#define DPORT_INT_ENABLE_WDT BIT(0)
#define DPORT_INT_ENABLE_TIMER0 BIT(1)
#define DPORT_INT_ENABLE_TIMER1 BIT(2)
/* Aliases for the Espressif way of referring to TIMER0 (FRC1) and TIMER1
* (FRC2).. */
#define DPORT_INT_ENABLE_FRC1 DPORT_INT_ENABLE_TIMER0
#define DPORT_INT_ENABLE_FRC2 DPORT_INT_ENABLE_TIMER1
/* Details for SPI_READY register */
#define DPORT_SPI_READY_IDLE BIT(9)
/* Details for CPU_CLOCK register */
#define DPORT_CPU_CLOCK_X2 BIT(0)
/* Details for CLOCKGATE_WATCHDOG register */
/* Comment found in pvvx/mp3_decode headers: "use clockgate_watchdog(flg) { if(flg) 0x3FF00018 &= 0x77; else 0x3FF00018 |= 8; }". Not sure what this means or does. */
#define DPORT_CLOCKGATE_WATCHDOG_DISABLE BIT(3)
/* Details for SPI_INT_STATUS register */
#define DPORT_SPI_INT_STATUS_SPI0 BIT(4)
#define DPORT_SPI_INT_STATUS_SPI1 BIT(7)
#define DPORT_SPI_INT_STATUS_I2S BIT(9)
/* Details for SPI_CACHE_RAM register */
#define DPORT_SPI_CACHE_RAM_BANK1 BIT(3)
#define DPORT_SPI_CACHE_RAM_BANK0 BIT(4)
/* Details for PERI_IO register */
#define DPORT_PERI_IO_SWAP_UARTS BIT(0)
#define DPORT_PERI_IO_SWAP_SPIS BIT(1)
#define DPORT_PERI_IO_SWAP_UART0_PINS BIT(2)
#define DPORT_PERI_IO_SWAP_UART1_PINS BIT(3)
#define DPORT_PERI_IO_SPI1_PRIORITY BIT(5)
#define DPORT_PERI_IO_SPI1_SHARED BIT(6)
#define DPORT_PERI_IO_SPI0_SHARED BIT(7)
/* Details for SLC_TX_DESC_DEBUG register */
#define SLC_TX_DESC_DEBUG_VALUE_M 0x0000ffff
#define SLC_TX_DESC_DEBUG_VALUE_S 0
#define SLC_TX_DESC_DEBUG_VALUE_MAGIC 0xcccc
#endif /* _ESP_DPORT_REGS_H */

View file

@ -9,7 +9,7 @@
#ifndef _ESP_GPIO_H #ifndef _ESP_GPIO_H
#define _ESP_GPIO_H #define _ESP_GPIO_H
#include <stdbool.h> #include <stdbool.h>
#include "esp/registers.h" #include "esp/gpio_regs.h"
#include "esp/iomux.h" #include "esp/iomux.h"
#include "esp/cpu.h" #include "esp/cpu.h"
#include "xtensa_interrupts.h" #include "xtensa_interrupts.h"
@ -32,37 +32,38 @@ INLINED void gpio_enable(const uint8_t gpio_num, const gpio_direction_t directio
switch(direction) { switch(direction) {
case GPIO_INPUT: case GPIO_INPUT:
iomux_flags = 0; iomux_flags = 0;
ctrl_val = GPIO_SOURCE_GPIO; ctrl_val = 0;
break; break;
case GPIO_OUTPUT: case GPIO_OUTPUT:
iomux_flags = IOMUX_OE; iomux_flags = IOMUX_PIN_OUTPUT_ENABLE;
ctrl_val = GPIO_DRIVE_PUSH_PULL|GPIO_SOURCE_GPIO; ctrl_val = GPIO_CONF_PUSH_PULL;
break; break;
case GPIO_OUT_OPEN_DRAIN: case GPIO_OUT_OPEN_DRAIN:
iomux_flags = IOMUX_OE; iomux_flags = IOMUX_PIN_OUTPUT_ENABLE;
ctrl_val = GPIO_DRIVE_OPEN_DRAIN|GPIO_SOURCE_GPIO; ctrl_val = 0;
break; break;
case GPIO_INPUT_PULLUP: case GPIO_INPUT_PULLUP:
iomux_flags = IOMUX_PU; iomux_flags = IOMUX_PIN_PULLUP;
ctrl_val = GPIO_SOURCE_GPIO; ctrl_val = 0;
break;
} }
iomux_set_gpio_function(gpio_num, iomux_flags); iomux_set_gpio_function(gpio_num, iomux_flags);
GPIO_CTRL_REG(gpio_num) = (GPIO_CTRL_REG(gpio_num)&GPIO_INT_MASK) | ctrl_val; GPIO.CONF[gpio_num] = (GPIO.CONF[gpio_num] & FIELD_MASK(GPIO_CONF_INTTYPE)) | ctrl_val;
if(direction == GPIO_OUTPUT) if (iomux_flags & IOMUX_PIN_OUTPUT_ENABLE)
GPIO_DIR_SET = BIT(gpio_num); GPIO.ENABLE_OUT_SET = BIT(gpio_num);
else else
GPIO_DIR_CLEAR = BIT(gpio_num); 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_OE 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) INLINED void gpio_disable(const uint8_t gpio_num)
{ {
GPIO_DIR_CLEAR = BIT(gpio_num); GPIO.ENABLE_OUT_CLEAR = BIT(gpio_num);
*gpio_iomux_reg(gpio_num) &= ~IOMUX_OE; *gpio_iomux_reg(gpio_num) &= ~IOMUX_PIN_OUTPUT_ENABLE;
} }
/* Set output of a pin high or low. /* Set output of a pin high or low.
@ -72,9 +73,9 @@ INLINED void gpio_disable(const uint8_t gpio_num)
INLINED void gpio_write(const uint8_t gpio_num, const bool set) INLINED 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);
} }
/* Toggle output of a pin /* Toggle output of a pin
@ -89,10 +90,10 @@ INLINED void gpio_toggle(const uint8_t gpio_num)
get an invalid value. Prevents one task from clobbering another get an invalid value. Prevents one task from clobbering another
task's pins, without needing to disable/enable interrupts. task's pins, without needing to disable/enable interrupts.
*/ */
if(GPIO_OUT_REG & BIT(gpio_num)) if(GPIO.OUT & BIT(gpio_num))
GPIO_OUT_CLEAR = BIT(gpio_num); GPIO.OUT_CLEAR = BIT(gpio_num);
else else
GPIO_OUT_SET = BIT(gpio_num); GPIO.OUT_SET = BIT(gpio_num);
} }
/* Read input value of a GPIO pin. /* Read input value of a GPIO pin.
@ -102,38 +103,28 @@ INLINED void gpio_toggle(const uint8_t gpio_num)
*/ */
INLINED bool gpio_read(const uint8_t gpio_num) INLINED bool gpio_read(const uint8_t gpio_num)
{ {
return GPIO_IN_REG & BIT(gpio_num); return GPIO.IN & BIT(gpio_num);
} }
typedef enum {
INT_NONE = 0,
INT_RISING = GPIO_INT_RISING,
INT_FALLING = GPIO_INT_FALLING,
INT_CHANGE = GPIO_INT_CHANGE,
INT_LOW = GPIO_INT_LOW,
INT_HIGH = GPIO_INT_HIGH,
} gpio_interrupt_t;
extern void gpio_interrupt_handler(void); 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 INT_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_interrupt_t int_type) INLINED void gpio_set_interrupt(const uint8_t gpio_num, const gpio_inttype_t int_type)
{ {
GPIO_CTRL_REG(gpio_num) = (GPIO_CTRL_REG(gpio_num)&~GPIO_INT_MASK) GPIO.CONF[gpio_num] = SET_FIELD(GPIO.CONF[gpio_num], GPIO_CONF_INTTYPE, int_type);
| (int_type & GPIO_INT_MASK); if(int_type != GPIO_INTTYPE_NONE) {
if(int_type != INT_NONE) {
_xt_isr_attach(INUM_GPIO, gpio_interrupt_handler); _xt_isr_attach(INUM_GPIO, gpio_interrupt_handler);
_xt_isr_unmask(1<<INUM_GPIO); _xt_isr_unmask(1<<INUM_GPIO);
} }
} }
/* Return the interrupt type set for a pin */ /* Return the interrupt type set for a pin */
INLINED gpio_interrupt_t gpio_get_interrupt(const uint8_t gpio_num) INLINED gpio_inttype_t gpio_get_interrupt(const uint8_t gpio_num)
{ {
return (gpio_interrupt_t)(GPIO_CTRL_REG(gpio_num) & GPIO_INT_MASK); return FIELD2VAL(GPIO_CONF_INTTYPE, GPIO.CONF[gpio_num]);
} }
#endif #endif

View file

@ -0,0 +1,130 @@
/* esp/gpio_regs.h
*
* ESP8266 GPIO register definitions
*
* Not compatible with ESP SDK register access code.
*/
#ifndef _ESP_GPIO_REGS_H
#define _ESP_GPIO_REGS_H
#include "esp/types.h"
#include "common_macros.h"
#define GPIO_BASE 0x60000300
#define GPIO (*(struct GPIO_REGS *)(GPIO_BASE))
/** GPIO output registers GPIO.OUT, GPIO.OUT_SET, GPIO.OUT_CLEAR:
*
* _SET and _CLEAR write-only registers set and clear bits in the main register,
* respectively.
*
* i.e.
* GPIO.OUT_SET = BIT(3);
* and
* GPIO.OUT |= BIT(3);
*
* ... are equivalent, but the former uses fewer CPU cycles.
*
* ENABLE_OUT / ENABLE_OUT_SET / ENABLE_OUT_CLEAR:
*
* Determine whether the corresponding GPIO has its output enabled or not.
* When clear, GPIO can function as an input. When set, GPIO will drive its
* output (and IN register will simply reflect the output state).
*
* (_SET/_CLEAR function similarly to OUT registers)
*
* STATUS / STATUS_SET / STATUS_CLEAR:
*
* Indicates which GPIOs have triggered an interrupt. Interrupt status should
* be reset by writing to STATUS or STATUS_CLEAR.
*
* (_SET/_CLEAR function similarly to OUT registers)
*/
struct GPIO_REGS {
uint32_t volatile OUT; // 0x00
uint32_t volatile OUT_SET; // 0x04
uint32_t volatile OUT_CLEAR; // 0x08
uint32_t volatile ENABLE_OUT; // 0x0c
uint32_t volatile ENABLE_OUT_SET; // 0x10
uint32_t volatile ENABLE_OUT_CLEAR; // 0x14
uint32_t volatile IN; // 0x18
uint32_t volatile STATUS; // 0x1c
uint32_t volatile STATUS_SET; // 0x20
uint32_t volatile STATUS_CLEAR; // 0x24
uint32_t volatile CONF[16]; // 0x28 - 0x64
uint32_t volatile PWM; // 0x68
uint32_t volatile RTC_CALIB; // 0x6c
uint32_t volatile RTC_CALIB_RESULT; // 0x70
};
_Static_assert(sizeof(struct GPIO_REGS) == 0x74, "GPIO_REGS is the wrong size");
/* Details for CONF[i] registers */
/* GPIO.CONF[i] control the pin behavior for the corresponding GPIO in/output.
*
* GPIO_CONF_CONFIG (multi-value)
* FIXME: Unclear what these do. Need to find a better name.
*
* GPIO_CONF_WAKEUP_ENABLE (boolean)
* Can an interrupt contion on this pin wake the processor from a sleep
* state?
*
* GPIO_CONF_INTTYPE (multi-value)
* Under what conditions this GPIO input should generate an interrupt.
* (see gpio_inttype_t enum below for values)
*
* GPIO_CONF_PUSH_PULL (boolean)
* When set, a high output state will pull the pin up to +Vcc (3.3V). When
* cleared, output functions in "open drain" mode (low state will pull down
* to ground, but high state allows output to "float").
*
* GPIO_CONF_SOURCE_PWM (boolean)
* When set, GPIO pin output will be connected to the sigma-delta PWM
* generator (controlled by the GPIO.PWM register). When cleared, pin
* output will function as a normal GPIO output (controlled by the
* GPIO.OUT* registers).
*/
#define GPIO_CONF_CONFIG_M 0x00000003
#define GPIO_CONF_CONFIG_S 11
#define GPIO_CONF_WAKEUP_ENABLE BIT(10)
#define GPIO_CONF_INTTYPE_M 0x00000007
#define GPIO_CONF_INTTYPE_S 7
#define GPIO_CONF_PUSH_PULL BIT(2)
#define GPIO_CONF_SOURCE_PWM BIT(0)
/* Valid values for the GPIO_CONF_INTTYPE field */
typedef enum {
GPIO_INTTYPE_NONE = 0,
GPIO_INTTYPE_EDGE_POS = 1,
GPIO_INTTYPE_EDGE_NEG = 2,
GPIO_INTTYPE_EDGE_ANY = 3,
GPIO_INTTYPE_LEVEL_LOW = 4,
GPIO_INTTYPE_LEVEL_HIGH = 5,
} gpio_inttype_t;
/* Details for PWM register */
#define GPIO_PWM_ENABLE BIT(16)
#define GPIO_PWM_PRESCALER_M 0x000000ff
#define GPIO_PWM_PRESCALER_S 8
#define GPIO_PWM_TARGET_M 0x000000ff
#define GPIO_PWM_TARGET_S 0
/* Details for RTC_CALIB register */
#define GPIO_RTC_CALIB_START BIT(31)
#define GPIO_RTC_CALIB_PERIOD_M 0x000003ff
#define GPIO_RTC_CALIB_PERIOD_S 0
/* Details for RTC_CALIB_RESULT register */
#define GPIO_RTC_CALIB_RESULT_READY BIT(31)
#define GPIO_RTC_CALIB_RESULT_READY_REAL BIT(30)
#define GPIO_RTC_CALIB_RESULT_VALUE_M 0x000fffff
#define GPIO_RTC_CALIB_RESULT_VALUE_S 0
#endif /* _ESP_GPIO_REGS_H */

View file

@ -8,8 +8,8 @@
*/ */
#ifndef _ESP_IOMUX_H #ifndef _ESP_IOMUX_H
#define _ESP_IOMUX_H #define _ESP_IOMUX_H
#include <stdint.h> #include "esp/types.h"
#include "esp/registers.h" #include "esp/iomux_regs.h"
/** /**
* Convert a GPIO pin number to an iomux register index. * Convert a GPIO pin number to an iomux register index.
@ -32,11 +32,11 @@ inline static uint8_t 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
* *
* ie *gpio_iomux_reg(3) is equivalent to IOMUX_GP03 * ie *gpio_iomux_reg(3) is equivalent to IOMUX_GPIO3
*/ */
inline static esp_reg_t gpio_iomux_reg(const uint8_t gpio_number) inline static esp_reg_t gpio_iomux_reg(const uint8_t gpio_number)
{ {
return &IOMUX_REG(gpio_to_iomux(gpio_number)); return &(IOMUX.PIN[gpio_to_iomux(gpio_number)]);
} }
/** /**
@ -45,153 +45,21 @@ inline static esp_reg_t gpio_iomux_reg(const uint8_t gpio_number)
* 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_OE, IOMUX_PU, IOMUX_PD, etc. Any other flags will be cleared. * flags can be any of IOMUX_PIN_OUTPUT_ENABLE, IOMUX_PIN_PULLUP, IOMUX_PIN_PULLDOWN, etc. Any other flags will be cleared.
* *
* Equivalent to a direct register operation if gpio_number is known at compile time. * Equivalent to a direct register operation if gpio_number is known at compile time.
* ie the following are equivalent: * ie the following are equivalent:
* *
* iomux_set_gpio_function(12, IOMUX_OE); * iomux_set_gpio_function(12, IOMUX_PIN_OUTPUT_ENABLE);
* IOMUX_GP12 = (IOMUX_GP12 & ~IOMUX_FUNC_MASK) | IOMUX_GP12_GPIO | IOMUX_OE; * IOMUX_GPIO12 = IOMUX_GPIO12_FUNC_GPIO | IOMUX_PIN_OUTPUT_ENABLE;
*/ */
inline static void iomux_set_gpio_function(const uint8_t gpio_number, const uint8_t flags) inline static void iomux_set_gpio_function(const uint8_t gpio_number, const uint32_t flags)
{ {
const uint8_t reg_idx = gpio_to_iomux(gpio_number); const uint8_t reg_idx = gpio_to_iomux(gpio_number);
const esp_reg_t reg = &IOMUX_REG(reg_idx); const uint32_t func = (reg_idx > 11 ? IOMUX_FUNC(0) : IOMUX_FUNC(3)) | flags;
const uint32_t func = (reg_idx > 11 ? IOMUX_FUNC_A : IOMUX_FUNC_D) | flags; IOMUX.PIN[reg_idx] = func | flags;
const uint32_t val = *reg & ~(IOMUX_FUNC_MASK | IOMUX_FLAG_MASK);
*reg = val | func;
} }
/**
* Set an IOMUX register directly
*
* Shortcut for
* IOMUX_GPxx = (IOMUX_GPxx & ~IOMUX_FUNC_MASK) | IOMUX_GPxx_func
*
* instead call
* IOMUX_SET_FN(GPxx, func);
* can also do
* IOMUX_SET_FN(GP12, GPIO)|IOMUX_OE;
* ... to set the OE flag if it was previously cleared.
*
* but a better option is:
* IOMUX_SET(GP12, GPIO, IOMUX_OE);
* ...which clears any other flags at the same time.
*/
#define IOMUX_SET_FN(GP,FN) IOMUX_##GP = ((IOMUX_##GP & ~IOMUX_FUNC_MASK) | IOMUX_##GP##_##FN)
#define IOMUX_SET(GP,FN,FLAGS) IOMUX_##GP = ((IOMUX_##GP & ~(IOMUX_FUNC_MASK|IOMUX_FLAG_MASK)) | IOMUX_##GP##_##FN|FLAGS)
/* IOMUX register index 0, GPIO 12 */
#define IOMUX_GP12 IOMUX_REG(0)
#define IOMUX_GP12_MTDI IOMUX_FUNC_A
#define IOMUX_GP12_I2S_DIN IOMUX_FUNC_B
#define IOMUX_GP12_HSPI_MISO IOMUX_FUNC_C
#define IOMUX_GP12_GPIO IOMUX_FUNC_D
#define IOMUX_GP12_UART0_DTR IOMUX_FUNC_E
/* IOMUX register index 1, GPIO 13 */
#define IOMUX_GP13 IOMUX_REG(1)
#define IOMUX_GP13_MTCK IOMUX_FUNC_A
#define IOMUX_GP13_I2SI_BCK IOMUX_FUNC_B
#define IOMUX_GP13_HSPI_MOSI IOMUX_FUNC_C
#define IOMUX_GP13_GPIO IOMUX_FUNC_D
#define IOMUX_GP13_UART0_CTS IOMUX_FUNC_E
/* IOMUX register index 2, GPIO 14 */
#define IOMUX_GP14 IOMUX_REG(2)
#define IOMUX_GP14_MTMS IOMUX_FUNC_A
#define IOMUX_GP14_I2SI_WS IOMUX_FUNC_B
#define IOMUX_GP14_HSPI_CLK IOMUX_FUNC_C
#define IOMUX_GP14_GPIO IOMUX_FUNC_D
#define IOMUX_GP14_UART0_DSR IOMUX_FUNC_E
/* IOMUX register index 3, GPIO 15 */
#define IOMUX_GP15 IOMUX_REG(3)
#define IOMUX_GP15_MTDO IOMUX_FUNC_A
#define IOMUX_GP15_I2SO_BCK IOMUX_FUNC_B
#define IOMUX_GP15_HSPI_CS0 IOMUX_FUNC_C
#define IOMUX_GP15_GPIO IOMUX_FUNC_D
#define IOMUX_GP15_UART0_RTS IOMUX_FUNC_E
/* IOMUX register index 4, GPIO 3 */
#define IOMUX_GP03 IOMUX_REG(4)
#define IOMUX_GP03_UART0_RX IOMUX_FUNC_A
#define IOMUX_GP03_I2SO_DATA IOMUX_FUNC_B
#define IOMUX_GP03_GPIO IOMUX_FUNC_D
#define IOMUX_GP03_CLK_XTAL_BK IOMUX_FUNC_E
/* IOMUX register index 5, GPIO 1 */
#define IOMUX_GP01 IOMUX_REG(5)
#define IOMUX_GP01_UART0_TX IOMUX_FUNC_A
#define IOMUX_GP01_SPICS1 IOMUX_FUNC_B
#define IOMUX_GP01_GPIO IOMUX_FUNC_D
#define IOMUX_GP01_CLK_RTC_BK IOMUX_FUNC_E
/* IOMUX register index 6, GPIO 6 */
#define IOMUX_GP06 IOMUX_REG(6)
#define IOMUX_GP06_SD_CLK IOMUX_FUNC_A
#define IOMUX_GP06_SP_ICLK IOMUX_FUNC_B
#define IOMUX_GP06_GPIO IOMUX_FUNC_D
#define IOMUX_GP06_UART1_CTS IOMUX_FUNC_E
/* IOMUX register index 7, GPIO 7 */
#define IOMUX_GP07 IOMUX_REG(7)
#define IOMUX_GP07_SD_DATA0 IOMUX_FUNC_A
#define IOMUX_GP07_SPIQ_MISO IOMUX_FUNC_B
#define IOMUX_GP07_GPIO IOMUX_FUNC_D
#define IOMUX_GP07_UART1_TX IOMUX_FUNC_E
/* IOMUX register index 8, GPIO 8 */
#define IOMUX_GP08 IOMUX_REG(8)
#define IOMUX_GP08_SD_DATA1 IOMUX_FUNC_A
#define IOMUX_GP08_SPID_MOSI IOMUX_FUNC_B
#define IOMUX_GP08_GPIO IOMUX_FUNC_D
#define IOMUX_GP08_UART1_RX IOMUX_FUNC_E
/* IOMUX register index 9, GPIO 9 */
#define IOMUX_GP09 IOMUX_REG(9)
#define IOMUX_GP09_SD_DATA2 IOMUX_FUNC_A
#define IOMUX_GP09_SPI_HD IOMUX_FUNC_B
#define IOMUX_GP09_GPIO IOMUX_FUNC_D
#define IOMUX_GP09_UFNC_HSPIHD IOMUX_FUNC_E
/* IOMUX register index 10, GPIO 10 */
#define IOMUX_GP10 IOMUX_REG(10)
#define IOMUX_GP10_SD_DATA3 IOMUX_FUNC_A
#define IOMUX_GP10_SPI_WP IOMUX_FUNC_B
#define IOMUX_GP10_GPIO IOMUX_FUNC_D
#define IOMUX_GP10_HSPIWP IOMUX_FUNC_E
/* IOMUX register index 11, GPIO 11 */
#define IOMUX_GP11 IOMUX_REG(11)
#define IOMUX_GP11_SD_CMD IOMUX_FUNC_A
#define IOMUX_GP11_SPI_CS0 IOMUX_FUNC_B
#define IOMUX_GP11_GPIO IOMUX_FUNC_D
#define IOMUX_GP11_UART1_RTS IOMUX_FUNC_E
/* IOMUX register index 12, GPIO 0 */
#define IOMUX_GP00 IOMUX_REG(12)
#define IOMUX_GP00_GPIO IOMUX_FUNC_A
#define IOMUX_GP00_SPI_CS2 IOMUX_FUNC_B
#define IOMUX_GP00_CLK_OUT IOMUX_FUNC_E
/* IOMUX register index 13, GPIO 2 */
#define IOMUX_GP02 IOMUX_REG(13)
#define IOMUX_GP02_GPIO IOMUX_FUNC_A
#define IOMUX_GP02_I2SO_WS IOMUX_FUNC_B
#define IOMUX_GP02_UART1_TX IOMUX_FUNC_C
#define IOMUX_GP02_UART0_TX IOMUX_FUNC_E
/* IOMUX register index 14, GPIO 4 */
#define IOMUX_GP04 IOMUX_REG(14)
#define IOMUX_GP04_GPIO4 IOMUX_FUNC_A
#define IOMUX_GP04_CLK_XTAL IOMUX_FUNC_B
/* IOMUX register index 15, GPIO 5 */
#define IOMUX_GP05 IOMUX_REG(15)
#define IOMUX_GP05_GPIO5 IOMUX_FUNC_A
#define IOMUX_GP05_CLK_RTC IOMUX_FUNC_B
/* esp_iomux_private contains implementation parts of the inline functions /* esp_iomux_private contains implementation parts of the inline functions
declared above */ declared above */
#include "esp/iomux_private.h" #include "esp/iomux_private.h"

View file

@ -0,0 +1,151 @@
/* esp/iomux_regs.h
*
* ESP8266 IOMUX register definitions
*
* Not compatible with ESP SDK register access code.
*
* Note that IOMUX register order is _not_ the same as GPIO order. See
* esp/iomux.h for programmer-friendly IOMUX configuration options.
*/
#ifndef _ESP_IOMUX_REGS_H
#define _ESP_IOMUX_REGS_H
#include "esp/types.h"
#include "common_macros.h"
#define IOMUX_BASE 0x60000800
#define IOMUX (*(struct IOMUX_REGS *)(IOMUX_BASE))
struct IOMUX_REGS {
uint32_t volatile CONF; // 0x00
uint32_t volatile PIN[16]; // 0x04 - 0x40
};
_Static_assert(sizeof(struct IOMUX_REGS) == 0x44, "IOMUX_REGS is the wrong size");
/* Details for CONF register */
#define IOMUX_CONF_SPI0_CLOCK_EQU_SYS_CLOCK BIT(8)
#define IOMUX_CONF_SPI1_CLOCK_EQU_SYS_CLOCK BIT(9)
/* Details for PIN registers */
#define IOMUX_PIN_OUTPUT_ENABLE BIT(0)
#define IOMUX_PIN_OUTPUT_ENABLE_SLEEP BIT(1)
#define IOMUX_PIN_PULLDOWN_SLEEP BIT(2)
#define IOMUX_PIN_PULLUP_SLEEP BIT(3)
#define IOMUX_PIN_FUNC_LOW_M 0x00000003
#define IOMUX_PIN_FUNC_LOW_S 4
#define IOMUX_PIN_PULLDOWN BIT(6)
#define IOMUX_PIN_PULLUP BIT(7)
#define IOMUX_PIN_FUNC_HIGH_M 0x00000004
#define IOMUX_PIN_FUNC_HIGH_S 8
#define IOMUX_PIN_FUNC_MASK 0x00001030
/* WARNING: Macro evaluates argument twice */
#define IOMUX_FUNC(val) (VAL2FIELD(IOMUX_PIN_FUNC_LOW, val) | VAL2FIELD(IOMUX_PIN_FUNC_HIGH, val))
/* WARNING: Macro evaluates argument twice */
#define IOMUX_FUNC_VALUE(regbits) (FIELD2VAL(IOMUX_PIN_FUNC_LOW, regbits) | FIELD2VAL(IOMUX_PIN_FUNC_HIGH, regbits))
#define IOMUX_SET_FUNC(regbits, funcval) (((regbits) & ~IOMUX_PIN_FUNC_MASK) | (funcval))
#define IOMUX_GPIO0 IOMUX.PIN[12]
#define IOMUX_GPIO1 IOMUX.PIN[5]
#define IOMUX_GPIO2 IOMUX.PIN[13]
#define IOMUX_GPIO3 IOMUX.PIN[4]
#define IOMUX_GPIO4 IOMUX.PIN[14]
#define IOMUX_GPIO5 IOMUX.PIN[15]
#define IOMUX_GPIO6 IOMUX.PIN[6]
#define IOMUX_GPIO7 IOMUX.PIN[7]
#define IOMUX_GPIO8 IOMUX.PIN[8]
#define IOMUX_GPIO9 IOMUX.PIN[9]
#define IOMUX_GPIO10 IOMUX.PIN[10]
#define IOMUX_GPIO11 IOMUX.PIN[11]
#define IOMUX_GPIO12 IOMUX.PIN[0]
#define IOMUX_GPIO13 IOMUX.PIN[1]
#define IOMUX_GPIO14 IOMUX.PIN[2]
#define IOMUX_GPIO15 IOMUX.PIN[3]
#define IOMUX_GPIO0_FUNC_GPIO IOMUX_FUNC(0)
#define IOMUX_GPIO0_FUNC_SPI0_CS2 IOMUX_FUNC(1)
#define IOMUX_GPIO0_FUNC_CLOCK_OUT IOMUX_FUNC(4)
#define IOMUX_GPIO1_FUNC_UART0_TXD IOMUX_FUNC(0)
#define IOMUX_GPIO1_FUNC_SPI0_CS1 IOMUX_FUNC(1)
#define IOMUX_GPIO1_FUNC_GPIO IOMUX_FUNC(3)
#define IOMUX_GPIO1_FUNC_CLOCK_RTC_BLINK IOMUX_FUNC(4)
#define IOMUX_GPIO2_FUNC_GPIO IOMUX_FUNC(0)
#define IOMUX_GPIO2_FUNC_I2SO_WS IOMUX_FUNC(1)
#define IOMUX_GPIO2_FUNC_UART1_TXD_BLINK IOMUX_FUNC(2)
#define IOMUX_GPIO2_FUNC_UART0_TXD_BLINK IOMUX_FUNC(4)
#define IOMUX_GPIO3_FUNC_UART0_RXD IOMUX_FUNC(0)
#define IOMUX_GPIO3_FUNC_I2SO_DATA IOMUX_FUNC(1)
#define IOMUX_GPIO3_FUNC_GPIO IOMUX_FUNC(3)
#define IOMUX_GPIO3_FUNC_CLOCK_XTAL_BLINK IOMUX_FUNC(4)
#define IOMUX_GPIO4_FUNC_GPIO IOMUX_FUNC(0)
#define IOMUX_GPIO4_FUNC_CLOCK_XTAL IOMUX_FUNC(1)
#define IOMUX_GPIO5_FUNC_GPIO IOMUX_FUNC(0)
#define IOMUX_GPIO5_FUNC_CLOCK_RTC IOMUX_FUNC(1)
#define IOMUX_GPIO6_FUNC_SD_CLK IOMUX_FUNC(0)
#define IOMUX_GPIO6_FUNC_SPI0_CLK IOMUX_FUNC(1)
#define IOMUX_GPIO6_FUNC_GPIO IOMUX_FUNC(3)
#define IOMUX_GPIO6_FUNC_UART1_CTS IOMUX_FUNC(4)
#define IOMUX_GPIO7_FUNC_SD_DATA0 IOMUX_FUNC(0)
#define IOMUX_GPIO7_FUNC_SPI0_Q_MISO IOMUX_FUNC(1)
#define IOMUX_GPIO7_FUNC_GPIO IOMUX_FUNC(3)
#define IOMUX_GPIO7_FUNC_UART1_TXD IOMUX_FUNC(4)
#define IOMUX_GPIO8_FUNC_SD_DATA1 IOMUX_FUNC(0)
#define IOMUX_GPIO8_FUNC_SPI0_D_MOSI IOMUX_FUNC(1)
#define IOMUX_GPIO8_FUNC_GPIO IOMUX_FUNC(3)
#define IOMUX_GPIO8_FUNC_UART1_RXD IOMUX_FUNC(4)
#define IOMUX_GPIO9_FUNC_SD_DATA2 IOMUX_FUNC(0)
#define IOMUX_GPIO9_FUNC_SPI0_HD IOMUX_FUNC(1)
#define IOMUX_GPIO9_FUNC_GPIO IOMUX_FUNC(3)
#define IOMUX_GPIO9_FUNC_SPI1_HD IOMUX_FUNC(4)
#define IOMUX_GPIO10_FUNC_SD_DATA3 IOMUX_FUNC(0)
#define IOMUX_GPIO10_FUNC_SPI0_WP IOMUX_FUNC(1)
#define IOMUX_GPIO10_FUNC_GPIO IOMUX_FUNC(3)
#define IOMUX_GPIO10_FUNC_SPI1_WP IOMUX_FUNC(4)
#define IOMUX_GPIO11_FUNC_SD_CMD IOMUX_FUNC(0)
#define IOMUX_GPIO11_FUNC_SPI0_CS0 IOMUX_FUNC(1)
#define IOMUX_GPIO11_FUNC_GPIO IOMUX_FUNC(3)
#define IOMUX_GPIO11_FUNC_UART1_RTS IOMUX_FUNC(4)
#define IOMUX_GPIO12_FUNC_MTDI IOMUX_FUNC(0)
#define IOMUX_GPIO12_FUNC_I2SI_DATA IOMUX_FUNC(1)
#define IOMUX_GPIO12_FUNC_SPI1_Q_MISO IOMUX_FUNC(2)
#define IOMUX_GPIO12_FUNC_GPIO IOMUX_FUNC(3)
#define IOMUX_GPIO12_FUNC_UART0_DTR IOMUX_FUNC(4)
#define IOMUX_GPIO13_FUNC_MTCK IOMUX_FUNC(0)
#define IOMUX_GPIO13_FUNC_I2SI_BCK IOMUX_FUNC(1)
#define IOMUX_GPIO13_FUNC_SPI1_D_MOSI IOMUX_FUNC(2)
#define IOMUX_GPIO13_FUNC_GPIO IOMUX_FUNC(3)
#define IOMUX_GPIO13_FUNC_UART0_CTS IOMUX_FUNC(4)
#define IOMUX_GPIO14_FUNC_MTMS IOMUX_FUNC(0)
#define IOMUX_GPIO14_FUNC_I2SI_WS IOMUX_FUNC(1)
#define IOMUX_GPIO14_FUNC_SPI1_CLK IOMUX_FUNC(2)
#define IOMUX_GPIO14_FUNC_GPIO IOMUX_FUNC(3)
#define IOMUX_GPIO14_FUNC_UART0_DSR IOMUX_FUNC(4)
#define IOMUX_GPIO15_FUNC_MTDO IOMUX_FUNC(0)
#define IOMUX_GPIO15_FUNC_I2SO_BCK IOMUX_FUNC(1)
#define IOMUX_GPIO15_FUNC_SPI1_CS0 IOMUX_FUNC(2)
#define IOMUX_GPIO15_FUNC_GPIO IOMUX_FUNC(3)
#define IOMUX_GPIO15_FUNC_UART0_RTS IOMUX_FUNC(4)
#endif /* _ESP_IOMUX_REGS_H */

View file

@ -14,295 +14,43 @@
#ifndef _ESP_REGISTERS #ifndef _ESP_REGISTERS
#define _ESP_REGISTERS #define _ESP_REGISTERS
#include "common_macros.h" #include "common_macros.h"
#include "esp/types.h"
typedef volatile uint32_t *esp_reg_t; #include "esp/uart_regs.h"
#include "esp/spi_regs.h"
/* Internal macro, only defined in header body */ #include "esp/iomux_regs.h"
#define _REG(BASE, OFFSET) (*(esp_reg_t)((BASE)+(OFFSET))) #include "esp/gpio_regs.h"
#include "esp/timer_regs.h"
#include "esp/wdt_regs.h"
#include "esp/rtcmem_regs.h"
#include "esp/dport_regs.h"
/* Register base addresses /* Register base addresses
You shouldn't need to use these directly. The base addresses below are ones which haven't been migrated to
the new register header style yet. For any commented out lines, see
the matching xxx_regs.h header file referenced above.
If you want to access registers that aren't mapped to the new
register header system yet, you can either use the deprecated
Espressif SDK headers (in include/espressif), or you can create a
new register header file and contribute it to the project (hooray!)
*/ */
#define MMIO_BASE 0x60000000 #define MMIO_BASE 0x60000000
#define DPORT_BASE 0x3ff00000 //#define DPORT_BASE 0x3ff00000
#define UART0_BASE (MMIO_BASE + 0) //#define UART0_BASE (MMIO_BASE + 0)
#define SPI1_BASE (MMIO_BASE + 0x0100) //#define SPI1_BASE (MMIO_BASE + 0x0100)
#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)
#define UART1_BASE (MMIO_BASE + 0x0F00) //#define UART1_BASE (MMIO_BASE + 0x0F00)
#define RTCB_BASE (MMIO_BASE + 0x1000) //#define RTCB_BASE (MMIO_BASE + 0x1000)
#define RTCS_BASE (MMIO_BASE + 0x1100) //#define RTCS_BASE (MMIO_BASE + 0x1100)
#define RTCU_BASE (MMIO_BASE + 0x1200) //#define RTCU_BASE (MMIO_BASE + 0x1200)
/*
* iomux registers, apply to pin functions.
*
* Note that IOMUX register order is _not_ the same as GPIO order. See
* esp_iomux.h for programmer-friendly IOMUX configuration options
*/
#define IOMUX_REG(X) _REG(IOMUX_BASE,0x04+4*X)
#define IOMUX_OE BIT(0) /* iomux Output enable bit */
#define IOMUX_OE_SLEEP BIT(1) /* iomux Output during sleep bit */
#define IOMUX_PD BIT(6) /* iomux soft pulldown bit */
#define IOMUX_PD_SLEEP BIT(2) /* iomux soft pulldown during sleep bit */
#define IOMUX_PU BIT(7) /* iomux soft pullup bit */
#define IOMUX_PU_SLEEP BIT(3) /* iomux soft pullup during sleep bit */
#define IOMUX_FLAG_WAKE_MASK (IOMUX_OE|IOMUX_PD|IOMUX_PU)
#define IOMUX_FLAG_SLEEP_MASK (IOMUX_OE_SLEEP|IOMUX_PD_SLEEP|IOMUX_PU_SLEEP)
#define IOMUX_FLAG_MASK (IOMUX_FLAG_WAKE_MASK|IOMUX_FLAG_SLEEP_MASK)
#define IOMUX_FUNC_MASK (BIT(4)|BIT(5)|BIT(12))
/* All pins have FUNC_A on reset (unconfirmed) */
#define IOMUX_FUNC_A (0)
#define IOMUX_FUNC_B BIT(4)
#define IOMUX_FUNC_C BIT(5)
#define IOMUX_FUNC_D BIT(4)|BIT(5)
#define IOMUX_FUNC_E BIT(12)
/*
* Based on descriptions by mamalala at https://github.com/esp8266/esp8266-wiki/wiki/gpio-registers
*/
/** GPIO OUTPUT registers GPIO_OUT_REG, GPIO_OUT_SET, GPIO_OUT_CLEAR
*
* Registers for pin outputs.
*
* _SET and _CLEAR write-only registers set and clear bits in _REG,
* respectively.
*
* ie
* GPIO_OUT_REG |= BIT(3);
* and
* GPIO_OUT_SET = BIT(3);
*
* ... are equivalent, but latter uses less CPU cycles.
*/
#define GPIO_OUT_REG _REG(GPIO0_BASE, 0x00)
#define GPIO_OUT_SET _REG(GPIO0_BASE, 0x04)
#define GPIO_OUT_CLEAR _REG(GPIO0_BASE, 0x08)
/* GPIO DIR registers GPIO_DIR_REG, GPIO_DIR_SET, GPIO_DIR_CLEAR
*
* Set bit in DIR register for output pins. Writing to _SET and _CLEAR
* registers set and clear bits in _REG, respectively.
*/
#define GPIO_DIR_REG _REG(GPIO0_BASE, 0x0C)
#define GPIO_DIR_SET _REG(GPIO0_BASE, 0x10)
#define GPIO_DIR_CLEAR _REG(GPIO0_BASE, 0x14)
/* GPIO IN register GPIO_IN_REG
*
* Reads current input values.
*/
#define GPIO_IN_REG _REG(GPIO0_BASE, 0x18)
/* GPIO interrupt 'status' flag
Bit set if interrupt has fired (see below for interrupt config
registers.
Lower 16 bits only are used.
*/
#define GPIO_STATUS_REG _REG(GPIO0_BASE,0x1c)
#define GPIO_STATUS_SET _REG(GPIO0_BASE,0x20)
#define GPIO_STATUS_CLEAR _REG(GPIO0_BASE,0x24)
#define GPIO_STATUS_MASK 0x0000FFFFL
/* GPIO pin control registers for GPIOs 0-15
*
*/
#define GPIO_CTRL_REG(GPNUM) _REG(GPIO0_BASE, 0x28+(GPNUM*4))
#define GPIO_SOURCE_GPIO 0
#define GPIO_SOURCE_DAC BIT(0) /* "Sigma-Delta" */
#define GPIO_SOURCE_MASK BIT(0
#define GPIO_DRIVE_PUSH_PULL 0
#define GPIO_DRIVE_OPEN_DRAIN BIT(2)
#define GPIO_DRIVE_MASK BIT(2)
#define GPIO_INT_NONE 0
#define GPIO_INT_RISING BIT(7)
#define GPIO_INT_FALLING BIT(8)
#define GPIO_INT_CHANGE (BIT(7)|BIT(8))
#define GPIO_INT_LOW BIT(9)
#define GPIO_INT_HIGH (BIT(7)|BIT(9))
#define GPIO_INT_MASK (BIT(7)|BIT(8)|BIT(9))
/* TIMER registers
*
* ESP8266 has two hardware(?) timer counters, FRC1 and FRC2.
*
* FRC1 is a 24-bit countdown timer, triggers interrupt when reaches zero.
* FRC2 is a 32-bit countup timer, can set a variable match value to trigger an interrupt.
*
* FreeRTOS tick timer appears to come from XTensa core tick timer0,
* not either of these. FRC2 is used in the FreeRTOS SDK however. It
* is set to free-run, interrupting periodically via updates to the
* MATCH register. sdk_ets_timer_init configures FRC2 and assigns FRC2
* interrupt handler at sdk_vApplicationTickHook+0x68
*/
/* Load value for FRC1, read/write.
When TIMER_CTRL_RELOAD is cleared in TIMER_FRC1_CTRL_REG, FRC1 will
reload to TIMER_FRC1_MAX_LOAD once overflowed (unless the load
value is rewritten in the interrupt handler.)
When TIMER_CTRL_RELOAD is set in TIMER_FRC1_CTRL_REG, FRC1 will reload
from the load register value once overflowed.
*/
#define TIMER_FRC1_LOAD_REG _REG(TIMER_BASE, 0x00)
#define TIMER_FRC1_MAX_LOAD 0x7fffff
/* Current count value for FRC1, read only? */
#define TIMER_FRC1_COUNT_REG _REG(TIMER_BASE, 0x04)
/* Control register for FRC1, read/write.
See the bit definitions TIMER_CTRL_xxx lower down.
*/
#define TIMER_FRC1_CTRL_REG _REG(TIMER_BASE, 0x08)
/* Reading this register always returns the value in
* TIMER_FRC1_LOAD_REG.
*
* Writing zero to this register clears the FRC1
* interrupt status.
*/
#define TIMER_FRC1_CLEAR_INT_REG _REG(TIMER_BASE, 0x0c)
/* FRC2 load register.
*
* If TIMER_CTRL_RELOAD is cleared in TIMER_FRC2_CTRL_REG, writing to
* this register will update the FRC2 COUNT value.
*
* If TIMER_CTRL_RELOAD is set in TIMER_FRC2_CTRL_REG, the behaviour
* appears to be the same except that writing 0 to the load register
* both sets the COUNT register to 0 and disables the timer, even if
* the TIMER_CTRL_RUN bit is set.
*
* Offsets 0x34, 0x38, 0x3c all seem to read back the LOAD_REG value
* also (but have no known function.)
*/
#define TIMER_FRC2_LOAD_REG _REG(TIMER_BASE, 0x20)
/* FRC2 current count value. Read only? */
#define TIMER_FRC2_COUNT_REG _REG(TIMER_BASE, 0x24)
/* Control register for FRC2. Read/write.
See the bit definitions TIMER_CTRL_xxx lower down.
*/
#define TIMER_FRC2_CTRL_REG _REG(TIMER_BASE, 0x28)
/* Reading this value returns the current value of
* TIMER_FRC2_LOAD_REG.
*
* Writing zero to this value clears the FRC2 interrupt status.
*/
#define TIMER_FRC2_CLEAR_INT_REG _REG(TIMER_BASE, 0x2c)
/* Interrupt match value for FRC2. When COUNT == MATCH,
the interrupt fires.
*/
#define TIMER_FRC2_MATCH_REG _REG(TIMER_BASE, 0x30)
/* Timer control bits to set clock divisor values.
Divider from master 80MHz APB_CLK (unconfirmed, see esp/clocks.h).
*/
#define TIMER_CTRL_DIV_1 0
#define TIMER_CTRL_DIV_16 BIT(2)
#define TIMER_CTRL_DIV_256 BIT(3)
#define TIMER_CTRL_DIV_MASK (BIT(2)|BIT(3))
/* Set timer control bits to trigger interrupt on "edge" or "level"
*
* Observed behaviour is like this:
*
* * When TIMER_CTRL_INT_LEVEL is set, the interrupt status bit
* TIMER_CTRL_INT_STATUS remains set when the timer interrupt
* triggers, unless manually cleared by writing 0 to
* TIMER_FRCx_CLEAR_INT. While the interrupt status bit stays set
* the timer will continue to run normally, but the interrupt
* (INUM_TIMER_FRC1 or INUM_TIMER_FRC2) won't trigger again.
*
* * When TIMER_CTRL_INT_EDGE (default) is set, there's no need to
* manually write to TIMER_FRCx_CLEAR_INT. The interrupt status bit
* TIMER_CTRL_INT_STATUS automatically clears after the interrupt
* triggers, and the interrupt handler will run again
* automatically.
*
*/
#define TIMER_CTRL_INT_EDGE 0
#define TIMER_CTRL_INT_LEVEL BIT(0)
#define TIMER_CTRL_INT_MASK BIT(0)
/* Timer auto-reload bit
This bit interacts with TIMER_FRC1_LOAD_REG & TIMER_FRC2_LOAD_REG
differently, see those registers for details.
*/
#define TIMER_CTRL_RELOAD BIT(6)
/* Timer run bit */
#define TIMER_CTRL_RUN BIT(7)
/* Read-only timer interrupt status.
This bit gets set on FRC1 when interrupt fires, and cleared on a
write to TIMER_FRC1_CLEAR_INT (cleared automatically if
TIMER_CTRL_INT_LEVEL is not set).
*/
#define TIMER_CTRL_INT_STATUS BIT(8)
/* WDT register(s)
Not fully understood yet. Writing 0 here disables wdt.
See ROM functions esp_wdt_xxx
*/
#define WDT_CTRL _REG(WDT_BASE, 0x00)
/* DPORT registers
Control various aspects of core/peripheral interaction... Not well
documented or understood.
*/
/* Set flags to enable CPU interrupts from some peripherals. Read/write.
bit 0 - Is set by RTOS SDK startup code but function is unknown.
bit 1 - INT_ENABLE_FRC1 allows TIMER FRC1 to trigger interrupt INUM_TIMER_FRC1.
bit 2 - INT_ENABLE_FRC2 allows TIMER FRC2 to trigger interrupt INUM_TIMER_FRC2.
Espressif calls this register "EDGE_INT_ENABLE_REG". The "edge" in
question is (I think) the interrupt line from the peripheral, as
the interrupt status bit is set. There may be a similar register
for enabling "level" interrupts instead of edge triggering
- this is unknown.
*/
#define DP_INT_ENABLE_REG _REG(DPORT_BASE, 0x04)
/* Set to enable interrupts from TIMER FRC1 */
#define INT_ENABLE_FRC1 BIT(1)
/* Set to enable interrupts interrupts from TIMER FRC2 */
#define INT_ENABLE_FRC2 BIT(2)
#endif #endif

View file

@ -0,0 +1,44 @@
/* esp/rtcmem_regs.h
*
* ESP8266 RTC semi-persistent memory register definitions
*
* Not compatible with ESP SDK register access code.
*/
#ifndef _ESP_RTCMEM_REGS_H
#define _ESP_RTCMEM_REGS_H
#include "esp/types.h"
#include "common_macros.h"
/* The RTC memory is a range of 256 words (1 KB) of general-purpose memory
* within the Real Time Clock peripheral. Because it's part of the RTC, it
* continues to be powered (and retains its contents) even when the ESP8266 is
* in its deepest sleep mode (and other RAM is lost). It can therefore be
* useful for keeping data which must be persisted through sleep or a reset.
*
* Note, however, that it is not "battery backed", or flash memory, and thus
* will not keep its contents if power is removed entirely.
*/
// We could just define these as 'volatile uint32_t *', but doing things this
// way means that the RTCMEM* defines will include array size information, so
// the C compiler can do bounds-checking for static arguments.
typedef volatile uint32_t rtcmem_array64_t[64];
typedef volatile uint32_t rtcmem_array128_t[128];
typedef volatile uint32_t rtcmem_array256_t[256];
#define RTCMEM_BASE 0x60001000
/* RTCMEM is an array covering the entire semi-persistent memory range */
#define RTCMEM (*(rtcmem_array256_t *)(RTCMEM_BASE))
/* RTCMEM_BACKUP / RTCMEM_SYSTEM / RTCMEM_USER are the same range, divided up
* into chunks by application/use, as defined by Espressif */
#define RTCMEM_BACKUP (*(rtcmem_array64_t *)(RTCMEM_BASE))
#define RTCMEM_SYSTEM (*(rtcmem_array64_t *)(RTCMEM_BASE + 0x100))
#define RTCMEM_USER (*(rtcmem_array128_t *)(RTCMEM_BASE + 0x200))
#endif /* _ESP_RTCMEM_REGS_H */

244
core/include/esp/spi_regs.h Normal file
View file

@ -0,0 +1,244 @@
/** esp/spi.h
*
* Configuration of SPI registers.
*
* Part of esp-open-rtos
* Copyright (C) 2015 Superhouse Automation Pty Ltd
* BSD Licensed as described in the file LICENSE
*/
#ifndef _SPI_REGS_H
#define _SPI_REGS_H
#include "esp/types.h"
#include "common_macros.h"
/* Register definitions for the SPI peripherals on the ESP8266.
*
* There are twp SPI devices built into the ESP8266:
* SPI(0) is at 0x60000200
* SPI(1) is at 0x60000100
* (note that the device number order is reversed in memory)
*
* Each device is allocated a block of 64 32-bit registers (256 bytes of
* address space) to communicate with application code.
*/
#define SPI_BASE 0x60000200
#define SPI(i) (*(struct SPI_REGS *)(0x60000200 - (i)*0x100))
#define SPI0_BASE SPI_BASE
#define SPI1_BASE (SPI_BASE - 0x100)
struct SPI_REGS {
uint32_t volatile CMD; // 0x00
uint32_t volatile ADDR; // 0x04
uint32_t volatile CTRL0; // 0x08
uint32_t volatile CTRL1; // 0x0c
uint32_t volatile RSTATUS; // 0x10
uint32_t volatile CTRL2; // 0x14
uint32_t volatile CLOCK; // 0x18
uint32_t volatile USER0; // 0x1c
uint32_t volatile USER1; // 0x20
uint32_t volatile USER2; // 0x24
uint32_t volatile WSTATUS; // 0x28
uint32_t volatile PIN; // 0x2c
uint32_t volatile SLAVE0; // 0x30
uint32_t volatile SLAVE1; // 0x34
uint32_t volatile SLAVE2; // 0x38
uint32_t volatile SLAVE3; // 0x3c
uint32_t volatile W0; // 0x40
uint32_t volatile W1; // 0x44
uint32_t volatile W2; // 0x48
uint32_t volatile W3; // 0x4c
uint32_t volatile W4; // 0x50
uint32_t volatile W5; // 0x54
uint32_t volatile W6; // 0x58
uint32_t volatile W7; // 0x5c
uint32_t volatile W8; // 0x60
uint32_t volatile W9; // 0x64
uint32_t volatile W10; // 0x68
uint32_t volatile W11; // 0x6c
uint32_t volatile W12; // 0x70
uint32_t volatile W13; // 0x74
uint32_t volatile W14; // 0x78
uint32_t volatile W15; // 0x7c
uint32_t volatile _unused[28]; // 0x80 - 0xec
uint32_t volatile EXT0; // 0xf0
uint32_t volatile EXT1; // 0xf4
uint32_t volatile EXT2; // 0xf8
uint32_t volatile EXT3; // 0xfc
};
_Static_assert(sizeof(struct SPI_REGS) == 0x100, "SPI_REGS is the wrong size");
/* Details for CMD register */
#define SPI_CMD_USR BIT(18)
/* Details for CTRL0 register */
#define SPI_CTRL0_WR_BIT_ORDER BIT(26)
#define SPI_CTRL0_RD_BIT_ORDER BIT(25)
#define SPI_CTRL0_QIO_MODE BIT(24)
#define SPI_CTRL0_DIO_MODE BIT(23)
#define SPI_CTRL0_QOUT_MODE BIT(20)
#define SPI_CTRL0_DOUT_MODE BIT(14)
#define SPI_CTRL0_FASTRD_MODE BIT(13)
#define SPI_CTRL0_CLOCK_EQU_SYS_CLOCK BIT(12)
#define SPI_CTRL0_CLOCK_NUM_M 0x0000000F
#define SPI_CTRL0_CLOCK_NUM_S 8
#define SPI_CTRL0_CLOCK_HIGH_M 0x0000000F
#define SPI_CTRL0_CLOCK_HIGH_S 4
#define SPI_CTRL0_CLOCK_LOW_M 0x0000000F
#define SPI_CTRL0_CLOCK_LOW_S 0
/* Mask for the CLOCK_NUM/CLOCK_HIGH/CLOCK_LOW combined, in case one wants
* to set them all as a single value.
*/
#define SPI_CTRL0_CLOCK_M 0x00000FFF
#define SPI_CTRL0_CLOCK_S 0
/* Details for CTRL2 register */
#define SPI_CTRL2_CS_DELAY_NUM_M 0x0000000F
#define SPI_CTRL2_CS_DELAY_NUM_S 28
#define SPI_CTRL2_CS_DELAY_MODE_M 0x00000003
#define SPI_CTRL2_CS_DELAY_MODE_S 26
#define SPI_CTRL2_MOSI_DELAY_NUM_M 0x00000007
#define SPI_CTRL2_MOSI_DELAY_NUM_S 23
#define SPI_CTRL2_MOSI_DELAY_MODE_M 0x00000003
#define SPI_CTRL2_MOSI_DELAY_MODE_S 21
#define SPI_CTRL2_MISO_DELAY_NUM_M 0x00000007
#define SPI_CTRL2_MISO_DELAY_NUM_S 18
#define SPI_CTRL2_MISO_DELAY_MODE_M 0x00000003
#define SPI_CTRL2_MISO_DELAY_MODE_S 16
/* Details for CLOCK register */
#define SPI_CLOCK_EQU_SYS_CLOCK BIT(31)
#define SPI_CLOCK_DIV_PRE_M 0x00001FFF
#define SPI_CLOCK_DIV_PRE_S 18
#define SPI_CLOCK_COUNT_NUM_M 0x0000003F
#define SPI_CLOCK_COUNT_NUM_S 12
#define SPI_CLOCK_COUNT_HIGH_M 0x0000003F
#define SPI_CLOCK_COUNT_HIGH_S 6
#define SPI_CLOCK_COUNT_LOW_M 0x0000003F
#define SPI_CLOCK_COUNT_LOW_S 0
/* Mask for the COUNT_NUM/COUNT_HIGH/COUNT_LOW combined, in case one wants
* to set them all as a single value.
*/
#define SPI_CTRL0_COUNT_M 0x0003FFFF
#define SPI_CTRL0_COUNT_S 0
/* Details for USER0 register */
#define SPI_USER0_COMMAND BIT(31)
#define SPI_USER0_ADDR BIT(30)
#define SPI_USER0_DUMMY BIT(29)
#define SPI_USER0_MISO BIT(28)
#define SPI_USER0_MOSI BIT(27)
#define SPI_USER0_MOSI_HIGHPART BIT(25)
#define SPI_USER0_MISO_HIGHPART BIT(24)
#define SPI_USER0_SIO BIT(16)
#define SPI_USER0_FWRITE_QIO BIT(15)
#define SPI_USER0_FWRITE_DIO BIT(14)
#define SPI_USER0_FWRITE_QUAD BIT(13)
#define SPI_USER0_FWRITE_DUAL BIT(12)
#define SPI_USER0_WR_BYTE_ORDER BIT(11)
#define SPI_USER0_RD_BYTE_ORDER BIT(10)
#define SPI_USER0_CLOCK_OUT_EDGE BIT(7)
#define SPI_USER0_CLOCK_IN_EDGE BIT(6)
#define SPI_USER0_CS_SETUP BIT(5)
#define SPI_USER0_CS_HOLD BIT(4)
#define SPI_USER0_FLASH_MODE BIT(2)
/* Details for USER1 register */
#define SPI_USER1_ADDR_BITLEN_M 0x0000003F
#define SPI_USER1_ADDR_BITLEN_S 26
#define SPI_USER1_MOSI_BITLEN_M 0x000001FF
#define SPI_USER1_MOSI_BITLEN_S 17
#define SPI_USER1_MISO_BITLEN_M 0x000001FF
#define SPI_USER1_MISO_BITLEN_S 8
#define SPI_USER1_DUMMY_CYCLELEN_M 0x000000FF
#define SPI_USER1_DUMMY_CYCLELEN_S 0
/* Details for USER2 register */
#define SPI_USER2_COMMAND_BITLEN_M 0x0000000F
#define SPI_USER2_COMMAND_BITLEN_S 28
#define SPI_USER2_COMMAND_VALUE_M 0x0000FFFF
#define SPI_USER2_COMMAND_VALUE_S 0
/* Details for PIN register */
#define SPI_PIN_CS2_DISABLE BIT(2)
#define SPI_PIN_CS1_DISABLE BIT(1)
#define SPI_PIN_CS0_DISABLE BIT(0)
/* Details for SLAVE0 register */
#define SPI_SLAVE0_SYNC_RESET BIT(31)
#define SPI_SLAVE0_MODE BIT(30)
#define SPI_SLAVE0_WR_RD_BUF_EN BIT(29)
#define SPI_SLAVE0_WR_RD_STA_EN BIT(28)
#define SPI_SLAVE0_CMD_DEFINE BIT(27)
#define SPI_SLAVE0_TRANS_COUNT_M 0x0000000F
#define SPI_SLAVE0_TRANS_COUNT_S 23
#define SPI_SLAVE0_TRANS_DONE_EN BIT(9)
#define SPI_SLAVE0_WR_STA_DONE_EN BIT(8)
#define SPI_SLAVE0_RD_STA_DONE_EN BIT(7)
#define SPI_SLAVE0_WR_BUF_DONE_EN BIT(6)
#define SPI_SLAVE0_RD_BUF_DONE_EN BIT(5)
#define SPI_SLAVE0_INT_EN_M 0x0000001f
#define SPI_SLAVE0_INT_EN_S 5
#define SPI_SLAVE0_TRANS_DONE BIT(4)
#define SPI_SLAVE0_WR_STA_DONE BIT(3)
#define SPI_SLAVE0_RD_STA_DONE BIT(2)
#define SPI_SLAVE0_WR_BUF_DONE BIT(1)
#define SPI_SLAVE0_RD_BUF_DONE BIT(0)
/* Details for SLAVE1 register */
#define SPI_SLAVE1_STATUS_BITLEN_M 0x0000001F
#define SPI_SLAVE1_STATUS_BITLEN_S 27
#define SPI_SLAVE1_BUF_BITLEN_M 0x000001FF
#define SPI_SLAVE1_BUF_BITLEN_S 16
#define SPI_SLAVE1_RD_ADDR_BITLEN_M 0x0000003F
#define SPI_SLAVE1_RD_ADDR_BITLEN_S 10
#define SPI_SLAVE1_WR_ADDR_BITLEN_M 0x0000003F
#define SPI_SLAVE1_WR_ADDR_BITLEN_S 4
#define SPI_SLAVE1_WRSTA_DUMMY_ENABLE BIT(3)
#define SPI_SLAVE1_RDSTA_DUMMY_ENABLE BIT(2)
#define SPI_SLAVE1_WRBUF_DUMMY_ENABLE BIT(1)
#define SPI_SLAVE1_RDBUF_DUMMY_ENABLE BIT(0)
/* Details for SLAVE2 register */
#define SPI_SLAVE2_WRBUF_DUMMY_CYCLELEN_M 0x000000FF
#define SPI_SLAVE2_WRBUF_DUMMY_CYCLELEN_S 24
#define SPI_SLAVE2_RDBUF_DUMMY_CYCLELEN_M 0x000000FF
#define SPI_SLAVE2_RDBUF_DUMMY_CYCLELEN_S 16
#define SPI_SLAVE2_WRSTR_DUMMY_CYCLELEN_M 0x000000FF
#define SPI_SLAVE2_WRSTR_DUMMY_CYCLELEN_S 8
#define SPI_SLAVE2_RDSTR_DUMMY_CYCLELEN_M 0x000000FF
#define SPI_SLAVE2_RDSTR_DUMMY_CYCLELEN_S 0
/* Details for SLAVE3 register */
#define SPI_SLAVE3_WRSTA_CMD_VALUE_M 0x000000FF
#define SPI_SLAVE3_WRSTA_CMD_VALUE_S 24
#define SPI_SLAVE3_RDSTA_CMD_VALUE_M 0x000000FF
#define SPI_SLAVE3_RDSTA_CMD_VALUE_S 16
#define SPI_SLAVE3_WRBUF_CMD_VALUE_M 0x000000FF
#define SPI_SLAVE3_WRBUF_CMD_VALUE_S 8
#define SPI_SLAVE3_RDBUF_CMD_VALUE_M 0x000000FF
#define SPI_SLAVE3_RDBUF_CMD_VALUE_S 0
/* Details for EXT3 register */
#define SPI_EXT3_INT_HOLD_ENABLE_M 0x00000003
#define SPI_EXT3_INT_HOLD_ENABLE_S 0
#endif /* _SPI_REGS_H */

View file

@ -11,12 +11,12 @@
#include <stdbool.h> #include <stdbool.h>
#include <xtensa_interrupts.h> #include <xtensa_interrupts.h>
#include "esp/registers.h" #include "esp/timer_regs.h"
#include "esp/cpu.h" #include "esp/cpu.h"
typedef enum { typedef enum {
TIMER_FRC1, FRC1 = 0,
TIMER_FRC2, FRC2 = 1,
} timer_frc_t; } timer_frc_t;
/* Return current count value for timer. */ /* Return current count value for timer. */
@ -31,14 +31,8 @@ INLINED void timer_set_load(const timer_frc_t frc, const uint32_t load);
/* Returns maximum load value for timer. */ /* Returns maximum load value for timer. */
INLINED uint32_t timer_max_load(const timer_frc_t frc); INLINED uint32_t timer_max_load(const timer_frc_t frc);
typedef enum {
TIMER_DIV1,
TIMER_DIV16,
TIMER_DIV256,
} timer_div_t;
/* Set the timer divider value */ /* Set the timer divider value */
INLINED void timer_set_divider(const timer_frc_t frc, const timer_div_t div); INLINED void timer_set_divider(const timer_frc_t frc, const timer_clkdiv_t div);
/* Enable or disable timer interrupts /* Enable or disable timer interrupts
@ -62,7 +56,7 @@ INLINED bool timer_get_reload(const timer_frc_t frc);
/* Return a suitable timer divider for the specified frequency, /* Return a suitable timer divider for the specified frequency,
or -1 if none is found. or -1 if none is found.
*/ */
INLINED timer_div_t timer_freq_to_div(uint32_t freq); 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.
@ -73,12 +67,12 @@ INLINED timer_div_t timer_freq_to_div(uint32_t freq);
* *
* Compile-time evaluates if all arguments are available at compile time. * 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_div_t div); INLINED 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 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_div_t timer_time_to_div(uint32_t us); INLINED timer_clkdiv_t timer_time_to_div(uint32_t us);
/* 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.
@ -89,7 +83,7 @@ INLINED timer_div_t timer_time_to_div(uint32_t us);
* *
* Compile-time evaluates if all arguments are available at compile time. * 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_div_t div); INLINED 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.

View file

@ -10,6 +10,7 @@
#include <limits.h> #include <limits.h>
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include "esp/dport_regs.h"
/* Timer divisor index to max frequency */ /* Timer divisor index to max frequency */
#define _FREQ_DIV1 (80*1000*1000) #define _FREQ_DIV1 (80*1000*1000)
@ -20,104 +21,90 @@ const static uint32_t IROM _TIMER_FREQS[] = { _FREQ_DIV1, _FREQ_DIV16, _FREQ_DIV
/* Timer divisor index to divisor value */ /* Timer divisor index to divisor value */
const static uint32_t IROM _TIMER_DIV_VAL[] = { 1, 16, 256 }; const static uint32_t IROM _TIMER_DIV_VAL[] = { 1, 16, 256 };
/* Timer divisor to mask value */
const static uint32_t IROM _TIMER_DIV_REG[] = { TIMER_CTRL_DIV_1, TIMER_CTRL_DIV_16, TIMER_CTRL_DIV_256 };
INLINED esp_reg_t _timer_ctrl_reg(const timer_frc_t frc)
{
return (frc == TIMER_FRC1) ? &TIMER_FRC1_CTRL_REG : &TIMER_FRC2_CTRL_REG;
}
INLINED uint32_t timer_get_count(const timer_frc_t frc) INLINED uint32_t timer_get_count(const timer_frc_t frc)
{ {
return (frc == TIMER_FRC1) ? TIMER_FRC1_COUNT_REG : TIMER_FRC2_COUNT_REG; return TIMER(frc).COUNT;
} }
INLINED uint32_t timer_get_load(const timer_frc_t frc) INLINED uint32_t timer_get_load(const timer_frc_t frc)
{ {
return (frc == TIMER_FRC1) ? TIMER_FRC1_LOAD_REG : TIMER_FRC2_LOAD_REG; return TIMER(frc).LOAD;
} }
INLINED void timer_set_load(const timer_frc_t frc, const uint32_t load) INLINED void timer_set_load(const timer_frc_t frc, const uint32_t load)
{ {
if(frc == TIMER_FRC1) TIMER(frc).LOAD = load;
TIMER_FRC1_LOAD_REG = load;
else
TIMER_FRC2_LOAD_REG = load;
} }
INLINED uint32_t timer_max_load(const timer_frc_t frc) INLINED uint32_t timer_max_load(const timer_frc_t frc)
{ {
return (frc == TIMER_FRC1) ? TIMER_FRC1_MAX_LOAD : UINT32_MAX; return (frc == FRC1) ? TIMER_FRC1_MAX_LOAD : UINT32_MAX;
} }
INLINED void timer_set_divider(const timer_frc_t frc, const timer_div_t div) INLINED void timer_set_divider(const timer_frc_t frc, const timer_clkdiv_t div)
{ {
if(div < TIMER_DIV1 || div > TIMER_DIV256) if(div < TIMER_CLKDIV_1 || div > TIMER_CLKDIV_256)
return; return;
esp_reg_t ctrl = _timer_ctrl_reg(frc); TIMER(frc).CTRL = SET_FIELD(TIMER(frc).CTRL, TIMER_CTRL_CLKDIV, div);
*ctrl = (*ctrl & ~TIMER_CTRL_DIV_MASK) | (_TIMER_DIV_REG[div] & TIMER_CTRL_DIV_MASK);
} }
INLINED void timer_set_interrupts(const timer_frc_t frc, bool enable) INLINED void timer_set_interrupts(const timer_frc_t frc, bool enable)
{ {
const uint32_t dp_bit = (frc == TIMER_FRC1) ? INT_ENABLE_FRC1 : INT_ENABLE_FRC2; const uint32_t dp_bit = (frc == FRC1) ? DPORT_INT_ENABLE_FRC1 : DPORT_INT_ENABLE_FRC2;
const uint32_t int_mask = BIT((frc == TIMER_FRC1) ? INUM_TIMER_FRC1 : INUM_TIMER_FRC2); const uint32_t int_mask = BIT((frc == FRC1) ? INUM_TIMER_FRC1 : INUM_TIMER_FRC2);
if(enable) { if(enable) {
DP_INT_ENABLE_REG |= dp_bit; DPORT.INT_ENABLE |= dp_bit;
_xt_isr_unmask(int_mask); _xt_isr_unmask(int_mask);
} else { } else {
DP_INT_ENABLE_REG &= ~dp_bit; DPORT.INT_ENABLE &= ~dp_bit;
_xt_isr_mask(int_mask); _xt_isr_mask(int_mask);
} }
} }
INLINED void timer_set_run(const timer_frc_t frc, const bool run) INLINED void timer_set_run(const timer_frc_t frc, const bool run)
{ {
esp_reg_t ctrl = _timer_ctrl_reg(frc);
if (run) if (run)
*ctrl |= TIMER_CTRL_RUN; TIMER(frc).CTRL |= TIMER_CTRL_RUN;
else else
*ctrl &= ~TIMER_CTRL_RUN; TIMER(frc).CTRL &= ~TIMER_CTRL_RUN;
} }
INLINED bool timer_get_run(const timer_frc_t frc) INLINED bool timer_get_run(const timer_frc_t frc)
{ {
return *_timer_ctrl_reg(frc) & TIMER_CTRL_RUN; return TIMER(frc).CTRL & TIMER_CTRL_RUN;
} }
INLINED void timer_set_reload(const timer_frc_t frc, const bool reload) INLINED void timer_set_reload(const timer_frc_t frc, const bool reload)
{ {
esp_reg_t ctrl = _timer_ctrl_reg(frc);
if (reload) if (reload)
*ctrl |= TIMER_CTRL_RELOAD; TIMER(frc).CTRL |= TIMER_CTRL_RELOAD;
else else
*ctrl &= ~TIMER_CTRL_RELOAD; TIMER(frc).CTRL &= ~TIMER_CTRL_RELOAD;
} }
INLINED bool timer_get_reload(const timer_frc_t frc) INLINED bool timer_get_reload(const timer_frc_t frc)
{ {
return *_timer_ctrl_reg(frc) & TIMER_CTRL_RELOAD; return TIMER(frc).CTRL & TIMER_CTRL_RELOAD;
} }
INLINED timer_div_t timer_freq_to_div(uint32_t freq) INLINED timer_clkdiv_t timer_freq_to_div(uint32_t freq)
{ {
/* /*
try to maintain resolution without risking overflows. try to maintain resolution without risking overflows.
these values are a bit arbitrary at the moment! */ these values are a bit arbitrary at the moment! */
if(freq > 100*1000) if(freq > 100*1000)
return TIMER_DIV1; return TIMER_CLKDIV_1;
else if(freq > 100) else if(freq > 100)
return TIMER_DIV16; return TIMER_CLKDIV_16;
else else
return TIMER_DIV256; return TIMER_CLKDIV_256;
} }
/* timer_timer_to_count implementation - inline if all args are constant, call normally otherwise */ /* 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_div_t div) 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_DIV1 || div > TIMER_DIV256) if(div < TIMER_CLKDIV_1 || div > TIMER_CLKDIV_256)
return 0; /* invalid divider */ return 0; /* invalid divider */
if(freq > _TIMER_FREQS[div]) if(freq > _TIMER_FREQS[div])
@ -127,9 +114,9 @@ INLINED uint32_t _timer_freq_to_count_impl(const timer_frc_t frc, const uint32_t
return counts; return counts;
} }
uint32_t _timer_freq_to_count_runtime(const timer_frc_t frc, const uint32_t freq, const timer_div_t div); 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_div_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)) if(__builtin_constant_p(frc) && __builtin_constant_p(freq) && __builtin_constant_p(div))
return _timer_freq_to_count_impl(frc, freq, div); return _timer_freq_to_count_impl(frc, freq, div);
@ -137,33 +124,33 @@ INLINED uint32_t timer_freq_to_count(const timer_frc_t frc, const uint32_t freq,
return _timer_freq_to_count_runtime(frc, freq, div); return _timer_freq_to_count_runtime(frc, freq, div);
} }
INLINED timer_div_t timer_time_to_div(uint32_t us) INLINED timer_clkdiv_t timer_time_to_div(uint32_t us)
{ {
/* /*
try to maintain resolution without risking overflows. Similar to try to maintain resolution without risking overflows. Similar to
timer_freq_to_div, these values are a bit arbitrary at the timer_freq_to_div, these values are a bit arbitrary at the
moment! */ moment! */
if(us < 1000) if(us < 1000)
return TIMER_DIV1; return TIMER_CLKDIV_1;
else if(us < 10*1000) else if(us < 10*1000)
return TIMER_DIV16; return TIMER_CLKDIV_16;
else else
return TIMER_DIV256; return TIMER_CLKDIV_256;
} }
/* timer_timer_to_count implementation - inline if all args are constant, call normally otherwise */ /* 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_div_t div) INLINED uint32_t _timer_time_to_count_impl(const timer_frc_t frc, uint32_t us, const timer_clkdiv_t div)
{ {
if(div < TIMER_DIV1 || div > TIMER_DIV256) if(div < TIMER_CLKDIV_1 || div > TIMER_CLKDIV_256)
return 0; /* invalid divider */ return 0; /* invalid divider */
const uint32_t TIMER_MAX = timer_max_load(frc); const uint32_t TIMER_MAX = timer_max_load(frc);
if(div != TIMER_DIV256) /* timer tick in MHz */ if(div != TIMER_CLKDIV_256) /* timer tick in MHz */
{ {
/* timer is either 80MHz or 5MHz, so either 80 or 5 MHz counts per us */ /* timer is either 80MHz or 5MHz, so either 80 or 5 MHz counts per us */
const uint32_t counts_per_us = ((div == TIMER_DIV1) ? _FREQ_DIV1 : _FREQ_DIV16)/1000/1000; const uint32_t counts_per_us = ((div == TIMER_CLKDIV_1) ? _FREQ_DIV1 : _FREQ_DIV16)/1000/1000;
if(us > TIMER_MAX/counts_per_us) if(us > TIMER_MAX/counts_per_us)
return 0; /* Multiplying us by mhz_per_count will overflow TIMER_MAX */ return 0; /* Multiplying us by mhz_per_count will overflow TIMER_MAX */
return us*counts_per_us; return us*counts_per_us;
@ -186,9 +173,9 @@ INLINED uint32_t _timer_time_to_count_impl(const timer_frc_t frc, uint32_t us, c
} }
} }
uint32_t _timer_time_to_count_runtime(const timer_frc_t frc, uint32_t us, const timer_div_t div); 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_div_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)) if(__builtin_constant_p(frc) && __builtin_constant_p(us) && __builtin_constant_p(div))
return _timer_time_to_count_impl(frc, us, div); return _timer_time_to_count_impl(frc, us, div);
@ -201,17 +188,17 @@ INLINED uint32_t timer_time_to_count(const timer_frc_t frc, uint32_t us, const t
INLINED bool _timer_set_frequency_impl(const timer_frc_t frc, uint32_t freq) INLINED bool _timer_set_frequency_impl(const timer_frc_t frc, uint32_t freq)
{ {
uint32_t counts = 0; uint32_t counts = 0;
timer_div_t div = timer_freq_to_div(freq); timer_clkdiv_t div = timer_freq_to_div(freq);
counts = timer_freq_to_count(frc, freq, div); counts = timer_freq_to_count(frc, freq, div);
if(counts == 0) if(counts == 0)
{ {
printf("ABORT: No counter for timer %u frequency %lu\r\n", frc, freq); printf("ABORT: No counter for timer %u frequency %u\r\n", frc, freq);
abort(); abort();
} }
timer_set_divider(frc, div); timer_set_divider(frc, div);
if(frc == TIMER_FRC1) if(frc == FRC1)
{ {
timer_set_load(frc, counts); timer_set_load(frc, counts);
timer_set_reload(frc, true); timer_set_reload(frc, true);
@ -219,7 +206,7 @@ INLINED bool _timer_set_frequency_impl(const timer_frc_t frc, uint32_t freq)
else /* FRC2 */ else /* FRC2 */
{ {
/* assume that if this overflows it'll wrap, so we'll get desired behaviour */ /* assume that if this overflows it'll wrap, so we'll get desired behaviour */
TIMER_FRC2_MATCH_REG = counts + TIMER_FRC2_COUNT_REG; TIMER(1).ALARM = counts + TIMER(1).COUNT;
} }
return true; return true;
} }
@ -239,20 +226,20 @@ INLINED bool timer_set_frequency(const timer_frc_t frc, uint32_t freq)
INLINED bool _timer_set_timeout_impl(const timer_frc_t frc, uint32_t us) INLINED bool _timer_set_timeout_impl(const timer_frc_t frc, uint32_t us)
{ {
uint32_t counts = 0; uint32_t counts = 0;
timer_div_t div = timer_time_to_div(us); timer_clkdiv_t div = timer_time_to_div(us);
counts = timer_time_to_count(frc, us, div); counts = timer_time_to_count(frc, us, div);
if(counts == 0) if(counts == 0)
return false; /* can't set frequency */ return false; /* can't set frequency */
timer_set_divider(frc, div); timer_set_divider(frc, div);
if(frc == TIMER_FRC1) if(frc == FRC1)
{ {
timer_set_load(frc, counts); timer_set_load(frc, counts);
} }
else /* FRC2 */ else /* FRC2 */
{ {
TIMER_FRC2_MATCH_REG = counts + TIMER_FRC2_COUNT_REG; TIMER(1).ALARM = counts + TIMER(1).COUNT;
} }
return true; return true;

View file

@ -0,0 +1,125 @@
/* esp/timer_regs.h
*
* ESP8266 Timer register definitions
*
* Not compatible with ESP SDK register access code.
*/
#ifndef _ESP_TIMER_REGS_H
#define _ESP_TIMER_REGS_H
#include "esp/types.h"
#include "common_macros.h"
#define TIMER_BASE 0x60000600
#define TIMER(i) (*(struct TIMER_REGS *)(TIMER_BASE + (i)*0x20))
#define TIMER_FRC1 TIMER(0)
#define TIMER_FRC2 TIMER(1)
/* TIMER registers
*
* ESP8266 has two hardware timer counters, FRC1 and FRC2.
*
* FRC1 is a 24-bit countdown timer, triggers interrupt when reaches zero.
* FRC2 is a 32-bit countup timer, can set a variable match value to trigger an interrupt.
*
* FreeRTOS tick timer appears to come from XTensa core tick timer0,
* not either of these. FRC2 is used in the FreeRTOS SDK however. It
* is set to free-run, interrupting periodically via updates to the
* ALARM register. sdk_ets_timer_init configures FRC2 and assigns FRC2
* interrupt handler at sdk_vApplicationTickHook+0x68
*/
struct TIMER_REGS { // FRC1 FRC2
uint32_t volatile LOAD; // 0x00 0x20
uint32_t volatile COUNT; // 0x04 0x24
uint32_t volatile CTRL; // 0x08 0x28
uint32_t volatile STATUS; // 0x0c 0x2c
uint32_t volatile ALARM; // 0x30
};
_Static_assert(sizeof(struct TIMER_REGS) == 0x14, "TIMER_REGS is the wrong size");
#define TIMER_FRC1_MAX_LOAD 0x7fffff
/* Details for LOAD registers */
/* Behavior for FRC1:
*
* When TIMER_CTRL_RELOAD is cleared in TIMER(0).CTRL, FRC1 will
* reload to its max value once underflowed (unless the load
* value is rewritten in the interrupt handler.)
*
* When TIMER_CTRL_RELOAD is set in TIMER(0).CTRL, FRC1 will reload
* from the load register value once underflowed.
*
* Behavior for FRC2:
*
* If TIMER_CTRL_RELOAD is cleared in TIMER(1).CTRL, writing to
* this register will update the FRC2 COUNT value.
*
* If TIMER_CTRL_RELOAD is set in TIMER(1).CTRL, the behaviour
* appears to be the same except that writing 0 to the load register
* both sets the COUNT register to 0 and disables the timer, even if
* the TIMER_CTRL_RUN bit is set.
*
* Offsets 0x34, 0x38, 0x3c all seem to read back the LOAD_REG value
* also (but have no known function.)
*/
/* Details for CTRL registers */
/* Observed behaviour is like this:
*
* * When TIMER_CTRL_INT_HOLD is set, the interrupt status bit
* TIMER_CTRL_INT_STATUS remains set when the timer interrupt
* triggers, unless manually cleared by writing 0 to
* TIMER(x).STATUS. While the interrupt status bit stays set
* the timer will continue to run normally, but the interrupt
* (INUM_TIMER_FRC1 or INUM_TIMER_FRC2) won't trigger again.
*
* * When TIMER_CTRL_INT_HOLD is cleared (default), there's no need to
* manually write to TIMER(x).STATUS. The interrupt status bit
* TIMER_CTRL_INT_STATUS automatically clears after the interrupt
* triggers, and the interrupt handler will run again
* automatically.
*/
/* The values for TIMER_CTRL_CLKDIV control how many CPU clock cycles amount to
* one timer clock cycle. For valid values, see the timer_clkdiv_t enum below.
*/
/* TIMER_CTRL_INT_STATUS gets set when interrupt fires, and cleared on a write
* to TIMER(x).STATUS (or cleared automatically if TIMER_CTRL_INT_HOLD is not
* set).
*/
#define TIMER_CTRL_INT_HOLD BIT(0)
#define TIMER_CTRL_CLKDIV_M 0x00000003
#define TIMER_CTRL_CLKDIV_S 2
#define TIMER_CTRL_RELOAD BIT(6)
#define TIMER_CTRL_RUN BIT(7)
#define TIMER_CTRL_INT_STATUS BIT(8)
typedef enum {
TIMER_CLKDIV_1 = 0,
TIMER_CLKDIV_16 = 1,
TIMER_CLKDIV_256 = 2,
} timer_clkdiv_t;
/* Details for STATUS registers */
/* Reading this register always returns the value in
* TIMER(x).LOAD
*
* Writing zero to this register clears the FRC1
* interrupt status.
*/
/* Details for FRC2.ALARM register */
/* Interrupt match value for FRC2. When COUNT == ALARM,
the interrupt fires.
*/
#endif /* _ESP_TIMER_REGS_H */

8
core/include/esp/types.h Normal file
View file

@ -0,0 +1,8 @@
#ifndef _ESP_TYPES_H
#define _ESP_TYPES_H
#include <stdint.h>
typedef volatile uint32_t *esp_reg_t;
#endif /* _ESP_TYPES_H */

View file

@ -0,0 +1,186 @@
/** esp/uart.h
*
* Configuration of UART registers.
*
* Part of esp-open-rtos
* Copyright (C) 2015 Superhouse Automation Pty Ltd
* BSD Licensed as described in the file LICENSE
*/
#ifndef _UART_REGS_H
#define _UART_REGS_H
#include "esp/types.h"
#include "common_macros.h"
/* Register definitions for the UART peripherals on the ESP8266.
*
* There are twp UART devices built into the ESP8266:
* UART(0) is at 0x60000000
* UART(1) is at 0x60000F00
*
* Each device is allocated a block of 64 32-bit registers (256 bytes of
* address space) to communicate with application code.
*/
#define UART_BASE 0x60000000
#define UART(i) (*(struct UART_REGS *)(UART_BASE + (i)*0xf00))
#define UART0_BASE UART_BASE
#define UART1_BASE (UART_BASE + 0xf00)
struct UART_REGS {
uint32_t volatile FIFO; // 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 CLOCK_DIVIDER; // 0x14
uint32_t volatile AUTOBAUD; // 0x18
uint32_t volatile STATUS; // 0x1c
uint32_t volatile CONF0; // 0x20
uint32_t volatile CONF1; // 0x24
uint32_t volatile LOW_PULSE; // 0x28
uint32_t volatile HIGH_PULSE; // 0x2c
uint32_t volatile PULSE_COUNT; // 0x30
uint32_t volatile _unused[17]; // 0x34 - 0x74
uint32_t volatile DATE; // 0x78
uint32_t volatile ID; // 0x7c
};
_Static_assert(sizeof(struct UART_REGS) == 0x80, "UART_REGS is the wrong size");
/* Details for FIFO register */
#define UART_FIFO_DATA_M 0x000000ff
#define UART_FIFO_DATA_S 0
/* Details for INT_RAW register */
#define UART_INT_RAW_RXFIFO_TIMEOUT BIT(8)
#define UART_INT_RAW_BREAK_DETECTED BIT(7)
#define UART_INT_RAW_CTS_CHANGED BIT(6)
#define UART_INT_RAW_DSR_CHANGED BIT(5)
#define UART_INT_RAW_RXFIFO_OVERFLOW BIT(4)
#define UART_INT_RAW_FRAMING_ERR BIT(3)
#define UART_INT_RAW_PARITY_ERR BIT(2)
#define UART_INT_RAW_TXFIFO_EMPTY BIT(1)
#define UART_INT_RAW_RXFIFO_FULL BIT(0)
/* Details for INT_STATUS register */
#define UART_INT_STATUS_RXFIFO_TIMEOUT BIT(8)
#define UART_INT_STATUS_BREAK_DETECTED BIT(7)
#define UART_INT_STATUS_CTS_CHANGED BIT(6)
#define UART_INT_STATUS_DSR_CHANGED BIT(5)
#define UART_INT_STATUS_RXFIFO_OVERFLOW BIT(4)
#define UART_INT_STATUS_FRAMING_ERR BIT(3)
#define UART_INT_STATUS_PARITY_ERR BIT(2)
#define UART_INT_STATUS_TXFIFO_EMPTY BIT(1)
#define UART_INT_STATUS_RXFIFO_FULL BIT(0)
/* Details for INT_ENABLE register */
#define UART_INT_ENABLE_RXFIFO_TIMEOUT BIT(8)
#define UART_INT_ENABLE_BREAK_DETECTED BIT(7)
#define UART_INT_ENABLE_CTS_CHANGED BIT(6)
#define UART_INT_ENABLE_DSR_CHANGED BIT(5)
#define UART_INT_ENABLE_RXFIFO_OVERFLOW BIT(4)
#define UART_INT_ENABLE_FRAMING_ERR BIT(3)
#define UART_INT_ENABLE_PARITY_ERR BIT(2)
#define UART_INT_ENABLE_TXFIFO_EMPTY BIT(1)
#define UART_INT_ENABLE_RXFIFO_FULL BIT(0)
/* Details for INT_CLEAR register */
#define UART_INT_CLEAR_RXFIFO_TIMEOUT BIT(8)
#define UART_INT_CLEAR_BREAK_DETECTED BIT(7)
#define UART_INT_CLEAR_CTS_CHANGED BIT(6)
#define UART_INT_CLEAR_DSR_CHANGED BIT(5)
#define UART_INT_CLEAR_RXFIFO_OVERFLOW BIT(4)
#define UART_INT_CLEAR_FRAMING_ERR BIT(3)
#define UART_INT_CLEAR_PARITY_ERR BIT(2)
#define UART_INT_CLEAR_TXFIFO_EMPTY BIT(1)
#define UART_INT_CLEAR_RXFIFO_FULL BIT(0)
/* Details for CLOCK_DIVIDER register */
#define UART_CLOCK_DIVIDER_VALUE_M 0x000fffff
#define UART_CLOCK_DIVIDER_VALUE_S 0
/* Details for AUTOBAUD register */
#define UART_AUTOBAUD_GLITCH_FILTER_M 0x000000FF
#define UART_AUTOBAUD_GLITCH_FILTER_S 8
#define UART_AUTOBAUD_ENABLE BIT(0)
/* Details for STATUS register */
#define UART_STATUS_TXD BIT(31)
#define UART_STATUS_RTS BIT(30)
#define UART_STATUS_DTR BIT(29)
#define UART_STATUS_TXFIFO_COUNT_M 0x000000ff
#define UART_STATUS_TXFIFO_COUNT_S 16
#define UART_STATUS_RXD BIT(15)
#define UART_STATUS_CTS BIT(14)
#define UART_STATUS_DSR BIT(13)
#define UART_STATUS_RXFIFO_COUNT_M 0x000000ff
#define UART_STATUS_RXFIFO_COUNT_S 0
/* Details for CONF0 register */
#define UART_CONF0_DTR_INVERTED BIT(24)
#define UART_CONF0_RTS_INVERTED BIT(23)
#define UART_CONF0_TXD_INVERTED BIT(22)
#define UART_CONF0_DSR_INVERTED BIT(21)
#define UART_CONF0_CTS_INVERTED BIT(20)
#define UART_CONF0_RXD_INVERTED BIT(19)
#define UART_CONF0_TXFIFO_RESET BIT(18)
#define UART_CONF0_RXFIFO_RESET BIT(17)
#define UART_CONF0_IRDA_ENABLE BIT(16)
#define UART_CONF0_TX_FLOW_ENABLE BIT(15)
#define UART_CONF0_LOOPBACK BIT(14)
#define UART_CONF0_IRDA_RX_INVERTED BIT(13)
#define UART_CONF0_IRDA_TX_INVERTED BIT(12)
#define UART_CONF0_IRDA_WCTL BIT(11)
#define UART_CONF0_IRDA_TX_ENABLE BIT(10)
#define UART_CONF0_IRDA_DUPLEX BIT(9)
#define UART_CONF0_TXD_BREAK BIT(8)
#define UART_CONF0_SW_DTR BIT(7)
#define UART_CONF0_SW_RTS BIT(6)
#define UART_CONF0_STOP_BITS_M 0x00000003
#define UART_CONF0_STOP_BITS_S 4
#define UART_CONF0_BYTE_LEN_M 0x00000003
#define UART_CONF0_BYTE_LEN_S 2
#define UART_CONF0_PARITY_ENABLE BIT(1)
#define UART_CONF0_PARITY BIT(0) //FIXME: does this indicate odd or even?
/* Details for CONF1 register */
#define UART_CONF1_RX_TIMEOUT_ENABLE BIT(31)
#define UART_CONF1_RX_TIMEOUT_THRESHOLD_M 0x0000007f
#define UART_CONF1_RX_TIMEOUT_THRESHOLD_S 24
#define UART_CONF1_RX_FLOWCTRL_ENABLE BIT(23)
#define UART_CONF1_RX_FLOWCTRL_THRESHOLD_M 0x0000007f
#define UART_CONF1_RX_FLOWCTRL_THRESHOLD_S 16
#define UART_CONF1_TXFIFO_EMPTY_THRESHOLD_M 0x0000007f
#define UART_CONF1_TXFIFO_EMPTY_THRESHOLD_S 8
#define UART_CONF1_RXFIFO_FULL_THRESHOLD_M 0x0000007f
#define UART_CONF1_RXFIFO_FULL_THRESHOLD_S 0
/* Details for LOW_PULSE register */
#define UART_LOW_PULSE_MIN_M 0x000fffff
#define UART_LOW_PULSE_MIN_S 0
/* Details for HIGH_PULSE register */
#define UART_HIGH_PULSE_MIN_M 0x000fffff
#define UART_HIGH_PULSE_MIN_S 0
/* Details for PULSE_COUNT register */
#define UART_PULSE_COUNT_VALUE_M 0x000003ff
#define UART_PULSE_COUNT_VALUE_S 0
#endif /* _UART_REGS_H */

View file

@ -0,0 +1,38 @@
/* esp/wdt_regs.h
*
* ESP8266 Watchdog Timer register definitions
*
* Not compatible with ESP SDK register access code.
*/
#ifndef _ESP_WDT_REGS_H
#define _ESP_WDT_REGS_H
#include "esp/types.h"
#include "common_macros.h"
#define WDT_BASE 0x60000900
#define WDT (*(struct WDT_REGS *)(WDT_BASE))
/* WDT register(s)
Not fully understood yet. Writing 0 to CTRL disables WDT.
See ROM functions esp_wdt_xxx
*/
struct WDT_REGS {
uint32_t volatile CTRL; // 0x00
uint32_t volatile REG1; // 0x04
uint32_t volatile REG2; // 0x08
uint32_t volatile _unused[2]; // 0x0c - 0x10
uint32_t volatile FEED; // 0x14
};
_Static_assert(sizeof(struct WDT_REGS) == 0x18, "WDT_REGS is the wrong size");
/* Writing WDT_FEED_MAGIC to WDT.FEED register "feeds the dog" and holds off
* triggering for another cycle (unconfirmed) */
#define WDT_FEED_MAGIC 0x73
#endif /* _ESP_WDT_REGS_H */

View file

@ -6,6 +6,7 @@
*/ */
#include <sys/reent.h> #include <sys/reent.h>
#include <sys/types.h> #include <sys/types.h>
#include <sys/errno.h>
#include <espressif/sdk_private.h> #include <espressif/sdk_private.h>
#include <common_macros.h> #include <common_macros.h>
#include <stdlib.h> #include <stdlib.h>
@ -37,6 +38,10 @@ IRAM caddr_t _sbrk_r (struct _reent *r, int incr)
*/ */
long _write_r(struct _reent *r, int fd, const char *ptr, int len ) long _write_r(struct _reent *r, int fd, const char *ptr, int len )
{ {
if(fd != r->_stdout->_file) {
r->_errno = EBADF;
return -1;
}
for(int i = 0; i < len; i++) for(int i = 0; i < len; i++)
sdk_os_putc(ptr[i]); sdk_os_putc(ptr[i]);
return len; return len;
@ -48,25 +53,31 @@ long _write_r(struct _reent *r, int fd, const char *ptr, int len )
*/ */
long _read_r( struct _reent *r, int fd, char *ptr, int len ) long _read_r( struct _reent *r, int fd, char *ptr, int len )
{ {
for(int i = 0; i < len; i++) if(fd != r->_stdin->_file) {
ptr[i] = sdk_uart_rx_one_char(); r->_errno = EBADF;
return -1;
}
for(int i = 0; i < len; i++) {
char ch;
while (sdk_uart_rx_one_char(&ch)) ;
ptr[i] = ch;
}
return len; return len;
} }
/* These are stub implementations for the reentrant syscalls that /* Stub syscall implementations follow, to allow compiling newlib functions that
* newlib is configured to expect */ pull these in via various codepaths
int _fstat_r(struct _reent *r, int fd, void *buf) */
__attribute__((alias("syscall_returns_enosys"))) int _open_r(struct _reent *r, const char *pathname, int flags, int mode);
__attribute__((alias("syscall_returns_enosys"))) int _fstat_r(struct _reent *r, int fd, void *buf);
__attribute__((alias("syscall_returns_enosys"))) int _close_r(struct _reent *r, int fd);
__attribute__((alias("syscall_returns_enosys"))) off_t _lseek_r(struct _reent *r, int fd, off_t offset, int whence);
/* Generic stub for any newlib syscall that fails with errno ENOSYS
("Function not implemented") and a return value equivalent to
(int)-1. */
static int syscall_returns_enosys(struct _reent *r)
{ {
r->_errno=ENOSYS;
return -1; return -1;
} }
int _close_r(struct _reent *r, int fd)
{
return -1;
}
off_t _lseek_r(struct _reent *r, int fd, off_t offset, int whence)
{
return (off_t)-1;
}

View file

@ -1,28 +1,31 @@
EXAMPLES = $(shell find $(dir $(lastword $(MAKEFILE_LIST))) -mindepth 2 -name Makefile | sed s/Makefile//g)
# Generate some dummy .dummybuild/.dummyrebuild target files
EXAMPLES_BUILD = $(patsubst %,%.dummybuild,$(EXAMPLES))
EXAMPLES_REBUILD = $(patsubst %,%.dummyrebuild,$(EXAMPLES))
warning: warning:
@echo "******************************************************" @echo "******************************************************"
@echo "You may not want this Makefile, even though it's here!" @echo "You may not want this Makefile, even though it's here!"
@echo "******************************************************" @echo "******************************************************"
@echo "" @echo ""
@echo "SUGGESTIONS:" @echo "SUGGESTIONS:"
@echo "Running 'make' in one of the subdirectories will build a single example." @echo "Running 'make' in one of the subdirectories of examples/ will build a single example."
@echo "Running 'make help' in one of the subdirectories will print some help." @echo "Running 'make help' in one of the subdirectories of examples/ will print some help."
@echo "" @echo ""
@echo "OTHERWISE:" @echo "OTHERWISE:"
@echo "This makefile is for building all of the examples at once, as a developer test." @echo "This makefile is for building all of the examples at once, as a developer test."
@echo "To use it, run 'make build-examples' or 'make rebuild-examples'" @echo "To use it, run 'make build-examples' or 'make rebuild-examples'"
@echo @echo
build-examples: build-examples: $(EXAMPLES_BUILD)
set -e
for example in `find . -mindepth 2 -name Makefile | sed s/Makefile//)`; do
$(MAKE) -C $$example
done
rebuild-examples: rebuild-examples: $(EXAMPLES_REBUILD)
set -e
for example in `find . -mindepth 2 -name Makefile | sed s/Makefile//)`; do %.dummybuild:
$(MAKE) -C $$example rebuild make -C $(dir $@)
done
%.dummyrebuild:
make -C $(dir $@) rebuild
.PHONY: warning rebuild-examples build-examples .PHONY: warning rebuild-examples build-examples
.NOTPARALLEL: .NOTPARALLEL:

View file

@ -30,8 +30,8 @@ void blinkenTask(void *pvParameters)
/* This task uses all raw register operations to set the pins. /* This task uses all raw register operations to set the pins.
It's not fully parameterised, as the IOMUX_SET macro requires the pin number It's not fully parameterised, as the IOMUX_GPIO# macros involve a non-linear
as part of the GPxx value. mapping from GPIO to IOMUX ports.
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
@ -41,12 +41,12 @@ void blinkenTask(void *pvParameters)
*/ */
void blinkenRegisterTask(void *pvParameters) void blinkenRegisterTask(void *pvParameters)
{ {
GPIO_DIR_SET = BIT(gpio); GPIO.ENABLE_OUT_SET = BIT(gpio);
IOMUX_SET(GP14,GPIO,IOMUX_OE); /* change this line if you change 'gpio' */ IOMUX_GPIO14 = IOMUX_GPIO14_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);
GPIO_OUT_CLEAR = BIT(gpio); GPIO.OUT_CLEAR = BIT(gpio);
vTaskDelay(1000 / portTICK_RATE_MS); vTaskDelay(1000 / portTICK_RATE_MS);
} }
} }

View file

@ -26,7 +26,7 @@ void frc1_interrupt_handler(void)
void frc2_interrupt_handler(void) void frc2_interrupt_handler(void)
{ {
/* FRC2 needs the match register updated on each timer interrupt */ /* FRC2 needs the match register updated on each timer interrupt */
timer_set_frequency(TIMER_FRC2, freq_frc2); timer_set_frequency(FRC2, freq_frc2);
frc2_count++; frc2_count++;
gpio_toggle(gpio_frc2); gpio_toggle(gpio_frc2);
} }
@ -41,24 +41,24 @@ void user_init(void)
gpio_write(gpio_frc1, 1); gpio_write(gpio_frc1, 1);
/* stop both timers and mask their interrupts as a precaution */ /* stop both timers and mask their interrupts as a precaution */
timer_set_interrupts(TIMER_FRC1, false); timer_set_interrupts(FRC1, false);
timer_set_run(TIMER_FRC1, false); timer_set_run(FRC1, false);
timer_set_interrupts(TIMER_FRC2, false); timer_set_interrupts(FRC2, false);
timer_set_run(TIMER_FRC2, false); timer_set_run(FRC2, false);
/* set up ISRs */ /* set up ISRs */
_xt_isr_attach(INUM_TIMER_FRC1, frc1_interrupt_handler); _xt_isr_attach(INUM_TIMER_FRC1, frc1_interrupt_handler);
_xt_isr_attach(INUM_TIMER_FRC2, frc2_interrupt_handler); _xt_isr_attach(INUM_TIMER_FRC2, frc2_interrupt_handler);
/* configure timer frequencies */ /* configure timer frequencies */
timer_set_frequency(TIMER_FRC1, freq_frc1); timer_set_frequency(FRC1, freq_frc1);
timer_set_frequency(TIMER_FRC2, freq_frc2); timer_set_frequency(FRC2, freq_frc2);
/* unmask interrupts and start timers */ /* unmask interrupts and start timers */
timer_set_interrupts(TIMER_FRC1, true); timer_set_interrupts(FRC1, true);
timer_set_run(TIMER_FRC1, true); timer_set_run(FRC1, true);
timer_set_interrupts(TIMER_FRC2, true); timer_set_interrupts(FRC2, true);
timer_set_run(TIMER_FRC2, true); timer_set_run(FRC2, true);
gpio_write(gpio_frc1, 0); gpio_write(gpio_frc1, 0);
} }

View file

@ -0,0 +1,3 @@
PROGRAM=BMP180_Reader
EXTRA_COMPONENTS = extras/i2c extras/bmp180
include ../../common.mk

View file

@ -0,0 +1,7 @@
# I2C / BMP180 Example
This example references two addtional drivers [i2c](https://github.com/kanflo/esp-open-rtos-driver-i2c) and [bmp180](https://github.com/Angus71/esp-open-rtos-driver-bmp180), which are provided in the `../../extras` folder.
If you plan to use one or both of this drivers in your own projects, please check the main development pages for updated versions or reported issues.
To run this example connect the BMP085/BMP180 SCL to GPIO0 and SDA to GPIO2.

View file

@ -0,0 +1,132 @@
/* Simple example for I2C / BMP180 / Timer & Event Handling
*
* This sample code is in the public domain.
*/
#include "espressif/esp_common.h"
#include "espressif/sdk_private.h"
#include "FreeRTOS.h"
#include "task.h"
#include "timers.h"
#include "queue.h"
// BMP180 driver
#include "bmp180/bmp180.h"
#define MY_EVT_TIMER 0x01
#define MY_EVT_BMP180 0x02
#define SCL_PIN GPIO_ID_PIN((0))
#define SDA_PIN GPIO_ID_PIN((2))
typedef struct
{
uint8_t event_type;
bmp180_result_t bmp180_data;
} my_event_t;
// Communication Queue
static xQueueHandle mainqueue;
static xTimerHandle timerHandle;
// Own BMP180 User Inform Implementation
bool bmp180_i2c_informUser(const xQueueHandle* resultQueue, uint8_t cmd, bmp180_temp_t temperatue, bmp180_press_t pressure)
{
my_event_t ev;
ev.event_type = MY_EVT_BMP180;
ev.bmp180_data.cmd = cmd;
ev.bmp180_data.temperatue = temperatue;
ev.bmp180_data.pressure = pressure;
return (xQueueSend(*resultQueue, &ev, 0) == pdTRUE);
}
// Timer call back
static void bmp180_i2c_timer_cb(xTimerHandle xTimer)
{
my_event_t ev;
ev.event_type = MY_EVT_TIMER;
xQueueSend(mainqueue, &ev, 0);
}
// Check for communiction events
void bmp180_task(void *pvParameters)
{
// Received pvParameters is communication queue
xQueueHandle *com_queue = (xQueueHandle *)pvParameters;
printf("%s: Started user interface task\n", __FUNCTION__);
while(1)
{
my_event_t ev;
xQueueReceive(*com_queue, &ev, portMAX_DELAY);
switch(ev.event_type)
{
case MY_EVT_TIMER:
printf("%s: Received Timer Event\n", __FUNCTION__);
bmp180_trigger_measurement(com_queue);
break;
case MY_EVT_BMP180:
printf("%s: Received BMP180 Event temp:=%d.%d°C press=%d.%02dhPa\n", __FUNCTION__, \
(int32_t)ev.bmp180_data.temperatue, abs((int32_t)(ev.bmp180_data.temperatue*10)%10), \
ev.bmp180_data.pressure/100, ev.bmp180_data.pressure%100 );
break;
default:
break;
}
}
}
// Setup HW
void user_setup(void)
{
// Set UART Parameter
sdk_uart_div_modify(0, UART_CLK_FREQ / 115200);
// Give the UART some time to settle
sdk_os_delay_us(500);
}
void user_init(void)
{
// Setup HW
user_setup();
// Just some infomations
printf("\n");
printf("SDK version : %s\n", sdk_system_get_sdk_version());
printf("GIT version : %s\n", GITSHORTREV);
// Use our user inform implementation
bmp180_informUser = bmp180_i2c_informUser;
// Init BMP180 Interface
bmp180_init(SCL_PIN, SDA_PIN);
// Create Main Communication Queue
mainqueue = xQueueCreate(10, sizeof(my_event_t));
// Create user interface task
xTaskCreate(bmp180_task, (signed char *)"bmp180_task", 256, &mainqueue, 2, NULL);
// Create Timer (Trigger a measurement every second)
timerHandle = xTimerCreate((signed char *)"BMP180 Trigger", 1000/portTICK_RATE_MS, pdTRUE, NULL, bmp180_i2c_timer_cb);
if (timerHandle != NULL)
{
if (xTimerStart(timerHandle, 0) != pdPASS)
{
printf("%s: Unable to start Timer ...\n", __FUNCTION__);
}
}
else
{
printf("%s: Unable to create Timer ...\n", __FUNCTION__);
}
}

View file

@ -15,7 +15,7 @@
/* pin config */ /* pin config */
const int gpio = 0; /* gpio 0 usually has "PROGRAM" button attached */ const int gpio = 0; /* gpio 0 usually has "PROGRAM" button attached */
const int active = 0; /* active == 0 for active low */ const int active = 0; /* active == 0 for active low */
const gpio_interrupt_t int_type = INT_FALLING; const gpio_inttype_t int_type = GPIO_INTTYPE_EDGE_NEG;
#define GPIO_HANDLER gpio00_interrupt_handler #define GPIO_HANDLER gpio00_interrupt_handler

View file

@ -11,14 +11,15 @@
#include "FreeRTOS.h" #include "FreeRTOS.h"
#include "task.h" #include "task.h"
#include "esp8266.h" #include "esp8266.h"
#include "common_macros.h"
#define DUMP_SZ 0x10 /* number of regs not size of buffer */ #define DUMP_SZ 0x10 /* number of regs not size of buffer */
IRAM void dump_frc1_seq(void) IRAM void dump_frc1_seq(void)
{ {
uint32_t f1_a = TIMER_FRC1_COUNT_REG; uint32_t f1_a = TIMER(0).COUNT;
uint32_t f1_b = TIMER_FRC1_COUNT_REG; uint32_t f1_b = TIMER(0).COUNT;
uint32_t f1_c = TIMER_FRC1_COUNT_REG; uint32_t f1_c = TIMER(0).COUNT;
printf("FRC1 sequence 0x%08x 0x%08x 0x%08x\r\n", f1_a, f1_b, f1_c); printf("FRC1 sequence 0x%08x 0x%08x 0x%08x\r\n", f1_a, f1_b, f1_c);
printf("FRC1 deltas %d %d \r\n", f1_b-f1_a, f1_c-f1_b); printf("FRC1 deltas %d %d \r\n", f1_b-f1_a, f1_c-f1_b);
} }
@ -33,9 +34,9 @@ IRAM void dump_frc2_seq(void)
* /16 = 0 or 1 (usually 1) * /16 = 0 or 1 (usually 1)
* *
*/ */
uint32_t f2_a = TIMER_FRC2_COUNT_REG; uint32_t f2_a = TIMER(1).COUNT;
uint32_t f2_b = TIMER_FRC2_COUNT_REG; uint32_t f2_b = TIMER(1).COUNT;
uint32_t f2_c = TIMER_FRC2_COUNT_REG; uint32_t f2_c = TIMER(1).COUNT;
printf("FRC2 sequence 0x%08x 0x%08x 0x%08x\r\n", f2_a, f2_b, f2_c); printf("FRC2 sequence 0x%08x 0x%08x 0x%08x\r\n", f2_a, f2_b, f2_c);
printf("FRC2 deltas %d %d \r\n", f2_b-f2_a, f2_c-f2_b); printf("FRC2 deltas %d %d \r\n", f2_b-f2_a, f2_c-f2_b);
} }
@ -99,20 +100,20 @@ void timerRegTask(void *pvParameters)
IRAM void frc1_handler(void) IRAM void frc1_handler(void)
{ {
frc1_handler_call_count++; frc1_handler_call_count++;
frc1_last_count_val = TIMER_FRC1_COUNT_REG; frc1_last_count_val = TIMER(0).COUNT;
//TIMER_FRC1_LOAD_REG = 0x300000; //TIMER(0).LOAD = 0x300000;
//TIMER_FRC1_CLEAR_INT = 0; //TIMER(0).STATUS = 0;
//TIMER_FRC1_MATCH_REG = frc1_last_count_val + 0x100000; //TIMER_FRC1_MATCH_REG = frc1_last_count_val + 0x100000;
} }
void frc2_handler(void) void frc2_handler(void)
{ {
frc2_handler_call_count++; frc2_handler_call_count++;
frc2_last_count_val = TIMER_FRC2_COUNT_REG; frc2_last_count_val = TIMER(1).COUNT;
TIMER_FRC2_MATCH_REG = frc2_last_count_val + 0x100000; TIMER(1).ALARM = frc2_last_count_val + 0x100000;
//TIMER_FRC2_LOAD_REG = 0; //TIMER(1).LOAD = 0;
//TIMER_FRC2_LOAD_REG = 0x2000000; //TIMER(1).LOAD = 0x2000000;
//TIMER_FRC2_CLEAR_INT_REG = 0; //TIMER(1).STATUS = 0;
} }
void user_init(void) void user_init(void)
@ -120,19 +121,19 @@ void user_init(void)
sdk_uart_div_modify(0, UART_CLK_FREQ / 115200); sdk_uart_div_modify(0, UART_CLK_FREQ / 115200);
xTaskCreate(timerRegTask, (signed char *)"timerRegTask", 1024, NULL, 2, NULL); xTaskCreate(timerRegTask, (signed char *)"timerRegTask", 1024, NULL, 2, NULL);
TIMER_FRC1_CTRL_REG = TIMER_CTRL_DIV_256|TIMER_CTRL_INT_EDGE|TIMER_CTRL_RELOAD; TIMER(0).CTRL = VAL2FIELD(TIMER_CTRL_CLKDIV, TIMER_CLKDIV_256) | TIMER_CTRL_RELOAD;
TIMER_FRC1_LOAD_REG = 0x200000; TIMER(0).LOAD = 0x200000;
TIMER_FRC2_CTRL_REG = TIMER_CTRL_DIV_256|TIMER_CTRL_INT_EDGE; TIMER(1).LOAD = VAL2FIELD(TIMER_CTRL_CLKDIV, TIMER_CLKDIV_256);
DP_INT_ENABLE_REG |= INT_ENABLE_FRC1|INT_ENABLE_FRC2; DPORT.INT_ENABLE |= DPORT_INT_ENABLE_TIMER0 | DPORT_INT_ENABLE_TIMER1;
_xt_isr_attach(INUM_TIMER_FRC1, frc1_handler); _xt_isr_attach(INUM_TIMER_FRC1, frc1_handler);
_xt_isr_unmask(1<<INUM_TIMER_FRC1); _xt_isr_unmask(1<<INUM_TIMER_FRC1);
_xt_isr_attach(INUM_TIMER_FRC2, frc2_handler); _xt_isr_attach(INUM_TIMER_FRC2, frc2_handler);
_xt_isr_unmask(1<<INUM_TIMER_FRC2); _xt_isr_unmask(1<<INUM_TIMER_FRC2);
TIMER_FRC1_CTRL_REG |= TIMER_CTRL_RUN; TIMER(0).CTRL |= TIMER_CTRL_RUN;
TIMER_FRC2_CTRL_REG |= TIMER_CTRL_RUN; TIMER(1).CTRL |= TIMER_CTRL_RUN;
dump_timer_regs("timer regs during user_init"); dump_timer_regs("timer regs during user_init");
dump_timer_regs("#2 timer regs during user_init"); dump_timer_regs("#2 timer regs during user_init");

View file

@ -18,14 +18,12 @@
#include "lwip/netdb.h" #include "lwip/netdb.h"
#include "lwip/dns.h" #include "lwip/dns.h"
#include "ssid_config.h"
#define WEB_SERVER "chainxor.org" #define WEB_SERVER "chainxor.org"
#define WEB_PORT 80 #define WEB_PORT 80
#define WEB_URL "http://chainxor.org/" #define WEB_URL "http://chainxor.org/"
#if !defined(WIFI_SSID) || !defined(WIFI_PASS)
#error "Please define macros WIFI_SSID & WIFI_PASS (here, or better in a local.h file at root level or in program dir."
#endif
void http_get_task(void *pvParameters) void http_get_task(void *pvParameters)
{ {
int successes = 0, failures = 0; int successes = 0, failures = 0;

View file

@ -22,14 +22,12 @@
#include "ssl.h" #include "ssl.h"
#include "ssid_config.h"
#define WEB_SERVER "192.168.0.18" #define WEB_SERVER "192.168.0.18"
#define WEB_PORT "8000" #define WEB_PORT "8000"
#define WEB_URL "/test" #define WEB_URL "/test"
#if !defined(WIFI_SSID) || !defined(WIFI_PASS)
#error "Please define macros WIFI_SSID & WIFI_PASS (here, or better in a local.h file at root level or in program dir."
#endif
static void display_cipher(SSL *ssl); static void display_cipher(SSL *ssl);
static void display_session_id(SSL *ssl); static void display_session_id(SSL *ssl);

View file

@ -11,14 +11,11 @@
#include "FreeRTOS.h" #include "FreeRTOS.h"
#include "task.h" #include "task.h"
#include "esp8266.h" #include "esp8266.h"
#include "ssid_config.h"
#include "ota-tftp.h" #include "ota-tftp.h"
#include "rboot-ota.h" #include "rboot-ota.h"
#if !defined(WIFI_SSID) || !defined(WIFI_PASS)
#error "Please define macros WIFI_SSID & WIFI_PASS (here, or better in a local.h file at root level or in program dir."
#endif
void user_init(void) void user_init(void)
{ {
sdk_uart_div_modify(0, UART_CLK_FREQ / 115200); sdk_uart_div_modify(0, UART_CLK_FREQ / 115200);
@ -29,7 +26,7 @@ void user_init(void)
printf("Image addresses in flash:\r\n"); printf("Image addresses in flash:\r\n");
for(int i = 0; i <conf.count; i++) { for(int i = 0; i <conf.count; i++) {
printf("%c%d: offset 0x%08lx\r\n", i == conf.current_rom ? '*':' ', i, conf.roms[i]); printf("%c%d: offset 0x%08x\r\n", i == conf.current_rom ? '*':' ', i, conf.roms[i]);
} }
struct sdk_station_config config = { struct sdk_station_config config = {

View file

@ -25,7 +25,7 @@ void task2(void *pvParameters)
while(1) { while(1) {
uint32_t count; uint32_t count;
if(xQueueReceive(*queue, &count, 1000)) { if(xQueueReceive(*queue, &count, 1000)) {
printf("Got %lu\n", count); printf("Got %u\n", count);
} else { } else {
printf("No msg :(\n"); printf("No msg :(\n");
} }

22
extras/bmp180/LICENSE Normal file
View file

@ -0,0 +1,22 @@
The MIT License (MIT)
Copyright (c) 2015 Frank Bargstedt
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.

56
extras/bmp180/README.md Normal file
View file

@ -0,0 +1,56 @@
# Driver for BMP085/BMP180 digital pressure sensor
This driver is written for usage with the ESP8266 and FreeRTOS ([esp-open-rtos](https://github.com/SuperHouse/esp-open-rtos) and [esp-open-rtos-driver-i2c](https://github.com/kanflo/esp-open-rtos-driver-i2c)).
### Usage
Before using the BMP180 module, the function `bmp180_init(SCL_PIN, SDA_PIN)` needs to be called to setup the I2C interface and do validation if the BMP180/BMP085 is accessible.
If the setup is sucessfully and a measurement is triggered, the result of the measurement is provided to the user as an event send via the `qQueue` provided with `bmp180_trigger_*measurement(pQueue);`
#### Example
```
#define SCL_PIN GPIO_ID_PIN(0)
#define SDA_PIN GPIO_ID_PIN(2)
...
if (!bmp180_init(SCL_PIN, SDA_PIN)) {
// An error occured, while dong the init (E.g device not found etc.)
}
// Trigger a measurement
bmp180_trigger_measurement(pQueue);
```
#### Change queue event
Per default the event send to the user via the provided queue is of the type `bmp180_result_t`. As this might not always be desired, a way is provided so that the user can provide a function, which creates and sends the event via the provided queue.
As all data aqquired from the BMP180/BMP085 is provided to the `bmp180_informUser` function, it is also possible to calculate new informations (E.g altitude etc.)
##### Example
```
// Own BMP180 User Inform Implementation
bool my_informUser(const xQueueHandle* resultQueue, uint8_t cmd, bmp180_temp_t temperatue, bmp180_press_t pressure) {
my_event_t ev;
ev.event_type = MY_EVT_BMP180;
ev.bmp180_data.cmd = cmd;
ev.bmp180_data.temperatue = temperatue;
ev.bmp180_data.pressure = pressure;
return (xQueueSend(*resultQueue, &ev, 0) == pdTRUE);
}
...
// Use our user inform implementation
// needs to be set before first measurement is triggered
bmp180_informUser = my_informUser;
```

351
extras/bmp180/bmp180.c Normal file
View file

@ -0,0 +1,351 @@
#include "bmp180.h"
#include "FreeRTOS.h"
#include "queue.h"
#include "task.h"
#include "espressif/esp_common.h"
#include "espressif/sdk_private.h"
#include "i2c/i2c.h"
#define BMP180_RX_QUEUE_SIZE 10
#define BMP180_TASK_PRIORITY 9
#define BMP180_DEVICE_ADDRESS 0x77
#define BMP180_VERSION_REG 0xD0
#define BMP180_CONTROL_REG 0xF4
#define BMP180_RESET_REG 0xE0
#define BMP180_OUT_MSB_REG 0xF6
#define BMP180_OUT_LSB_REG 0xF7
#define BMP180_OUT_XLSB_REG 0xF8
#define BMP180_CALIBRATION_REG 0xAA
//
// Values for BMP180_CONTROL_REG
//
#define BMP180_MEASURE_TEMP 0x2E
#define BMP180_MEASURE_PRESS_OSS0 0x34
#define BMP180_MEASURE_PRESS_OSS1 0x74
#define BMP180_MEASURE_PRESS_OSS2 0xB4
#define BMP180_MEASURE_PRESS_OSS3 0xF4
#define BMP180_DEFAULT_CONV_TIME 5000
//
// CHIP ID stored in BMP180_VERSION_REG
//
#define BMP180_CHIP_ID 0x55
//
// Reset value for BMP180_RESET_REG
//
#define BMP180_RESET_VALUE 0xB6
// BMP180_Event_Command
typedef struct
{
uint8_t cmd;
const xQueueHandle* resultQueue;
} bmp180_command_t;
// Just works due to the fact that xQueueHandle is a "void *"
static xQueueHandle bmp180_rx_queue = NULL;
static xTaskHandle bmp180_task_handle = NULL;
// Calibration constants
static int16_t AC1;
static int16_t AC2;
static int16_t AC3;
static uint16_t AC4;
static uint16_t AC5;
static uint16_t AC6;
static int16_t B1;
static int16_t B2;
static int16_t MB;
static int16_t MC;
static int16_t MD;
//
// Forward declarations
//
static void bmp180_meassure(const bmp180_command_t* command);
static bool bmp180_informUser_Impl(const xQueueHandle* resultQueue, uint8_t cmd, bmp180_temp_t temperatue, bmp180_press_t pressure);
// Set default implementation .. User gets result as bmp180_result_t event
bool (*bmp180_informUser)(const xQueueHandle* resultQueue, uint8_t cmd, bmp180_temp_t temperatue, bmp180_press_t pressure) = bmp180_informUser_Impl;
// I2C Driver Task
static void bmp180_driver_task(void *pvParameters)
{
// Data to be received from user
bmp180_command_t current_command;
#ifdef BMP180_DEBUG
// Wait for commands from the outside
printf("%s: Started Task\n", __FUNCTION__);
#endif
while(1)
{
// Wait for user to insert commands
if (xQueueReceive(bmp180_rx_queue, &current_command, portMAX_DELAY) == pdTRUE)
{
#ifdef BMP180_DEBUG
printf("%s: Received user command %d 0x%p\n", __FUNCTION__, current_command.cmd, current_command.resultQueue);
#endif
// use user provided queue
if (current_command.resultQueue != NULL)
{
// Work on it ...
bmp180_meassure(&current_command);
}
}
}
}
static uint8_t bmp180_readRegister8(uint8_t reg)
{
uint8_t r = 0;
if (!i2c_slave_read(BMP180_DEVICE_ADDRESS, reg, &r, 1))
{
r = 0;
}
return r;
}
static int16_t bmp180_readRegister16(uint8_t reg)
{
uint8_t d[] = { 0, 0 };
int16_t r = 0;
if (i2c_slave_read(BMP180_DEVICE_ADDRESS, reg, d, 2))
{
r = ((int16_t)d[0]<<8) | (d[1]);
}
return r;
}
static void bmp180_start_Messurement(uint8_t cmd)
{
uint8_t d[] = { BMP180_CONTROL_REG, cmd };
i2c_slave_write(BMP180_DEVICE_ADDRESS, d, 2);
}
static int16_t bmp180_getUncompensatedMessurement(uint8_t cmd)
{
// Write Start Code into reg 0xF4 (Currently without oversampling ...)
bmp180_start_Messurement((cmd==BMP180_TEMPERATURE)?BMP180_MEASURE_TEMP:BMP180_MEASURE_PRESS_OSS0);
// Wait 5ms Datasheet states 4.5ms
sdk_os_delay_us(BMP180_DEFAULT_CONV_TIME);
return (int16_t)bmp180_readRegister16(BMP180_OUT_MSB_REG);
}
static void bmp180_fillInternalConstants(void)
{
AC1 = bmp180_readRegister16(BMP180_CALIBRATION_REG+0);
AC2 = bmp180_readRegister16(BMP180_CALIBRATION_REG+2);
AC3 = bmp180_readRegister16(BMP180_CALIBRATION_REG+4);
AC4 = bmp180_readRegister16(BMP180_CALIBRATION_REG+6);
AC5 = bmp180_readRegister16(BMP180_CALIBRATION_REG+8);
AC6 = bmp180_readRegister16(BMP180_CALIBRATION_REG+10);
B1 = bmp180_readRegister16(BMP180_CALIBRATION_REG+12);
B2 = bmp180_readRegister16(BMP180_CALIBRATION_REG+14);
MB = bmp180_readRegister16(BMP180_CALIBRATION_REG+16);
MC = bmp180_readRegister16(BMP180_CALIBRATION_REG+18);
MD = bmp180_readRegister16(BMP180_CALIBRATION_REG+20);
#ifdef BMP180_DEBUG
printf("%s: AC1:=%d AC2:=%d AC3:=%d AC4:=%u AC5:=%u AC6:=%u \n", __FUNCTION__, AC1, AC2, AC3, AC4, AC5, AC6);
printf("%s: B1:=%d B2:=%d\n", __FUNCTION__, B1, B2);
printf("%s: MB:=%d MC:=%d MD:=%d\n", __FUNCTION__, MB, MC, MD);
#endif
}
static bool bmp180_create_communication_queues()
{
// Just create them once
if (bmp180_rx_queue==NULL)
{
bmp180_rx_queue = xQueueCreate(BMP180_RX_QUEUE_SIZE, sizeof(bmp180_result_t));
}
return (bmp180_rx_queue!=NULL);
}
static bool bmp180_is_avaialble()
{
return (bmp180_readRegister8(BMP180_VERSION_REG)==BMP180_CHIP_ID);
}
static bool bmp180_createTask()
{
// We already have a task
portBASE_TYPE x = pdPASS;
if (bmp180_task_handle==NULL)
{
x = xTaskCreate(bmp180_driver_task, (signed char *)"bmp180_driver_task", 256, NULL, BMP180_TASK_PRIORITY, &bmp180_task_handle);
}
return (x==pdPASS);
}
static void bmp180_meassure(const bmp180_command_t* command)
{
int32_t T, P;
// Init result to 0
T = P = 0;
if (command->resultQueue != NULL)
{
int32_t UT, X1, X2, B5;
//
// Temperature is always needed ... Also required for pressure only
//
// Calculation taken from BMP180 Datasheet
UT = (int32_t)bmp180_getUncompensatedMessurement(BMP180_TEMPERATURE);
X1 = (UT - (int32_t)AC6) * ((int32_t)AC5) >> 15;
X2 = ((int32_t)MC << 11) / (X1 + (int32_t)MD);
B5 = X1 + X2;
T = (B5 + 8) >> 4;
#ifdef BMP180_DEBUG
printf("%s: T:= %ld.%d\n", __FUNCTION__, T/10, abs(T%10));
#endif
// Do we also need pressure?
if (command->cmd & BMP180_PRESSURE)
{
int32_t X3, B3, B6;
uint32_t B4, B7, UP;
UP = ((uint32_t)bmp180_getUncompensatedMessurement(BMP180_PRESSURE) & 0xFFFF);
// Calculation taken from BMP180 Datasheet
B6 = B5 - 4000;
X1 = ((int32_t)B2 * ((B6 * B6) >> 12)) >> 11;
X2 = ((int32_t)AC2 * B6) >> 11;
X3 = X1 + X2;
B3 = (((int32_t)AC1 * 4 + X3) + 2) >> 2;
X1 = ((int32_t)AC3 * B6) >> 13;
X2 = ((int32_t)B1 * ((B6 * B6) >> 12)) >> 16;
X3 = ((X1 + X2) + 2) >> 2;
B4 = ((uint32_t)AC4 * (uint32_t)(X3 + 32768)) >> 15;
B7 = (UP - B3) * (uint32_t)(50000UL);
if (B7 < 0x80000000)
{
P = (B7 * 2) / B4;
}
else
{
P = (B7 / B4) * 2;
}
X1 = (P >> 8) * (P >> 8);
X1 = (X1 * 3038) >> 16;
X2 = (-7357 * P) >> 16;
P = P + ((X1 + X2 + (int32_t)3791) >> 4);
#ifdef BMP180_DEBUG
printf("%s: P:= %ld\n", __FUNCTION__, P);
#endif
}
// Inform the user ...
if (!bmp180_informUser(command->resultQueue, command->cmd, ((bmp180_temp_t)T)/10.0, (bmp180_press_t)P))
{
// Failed to send info to user
printf("%s: Unable to inform user bmp180_informUser returned \"false\"\n", __FUNCTION__);
}
}
}
// Default user inform implementation
static bool bmp180_informUser_Impl(const xQueueHandle* resultQueue, uint8_t cmd, bmp180_temp_t temperatue, bmp180_press_t pressure)
{
bmp180_result_t result;
result.cmd = cmd;
result.temperatue = temperatue;
result.pressure = pressure;
return (xQueueSend(*resultQueue, &result, 0) == pdTRUE);
}
// Just init all needed queues
bool bmp180_init(uint8_t scl, uint8_t sda)
{
// 1. Create required queues
bool result = false;
if (bmp180_create_communication_queues())
{
// 2. Init i2c driver
i2c_init(scl, sda);
// 3. Check for bmp180 ...
if (bmp180_is_avaialble())
{
// 4. Init all internal constants ...
bmp180_fillInternalConstants();
// 5. Start driver task
if (bmp180_createTask())
{
// We are finished
result = true;
}
}
}
return result;
}
void bmp180_trigger_measurement(const xQueueHandle* resultQueue)
{
bmp180_command_t c;
c.cmd = BMP180_PRESSURE + BMP180_TEMPERATURE;
c.resultQueue = resultQueue;
xQueueSend(bmp180_rx_queue, &c, 0);
}
void bmp180_trigger_pressure_measurement(const xQueueHandle* resultQueue)
{
bmp180_command_t c;
c.cmd = BMP180_PRESSURE;
c.resultQueue = resultQueue;
xQueueSend(bmp180_rx_queue, &c, 0);
}
void bmp180_trigger_temperature_measurement(const xQueueHandle* resultQueue)
{
bmp180_command_t c;
c.cmd = BMP180_TEMPERATURE;
c.resultQueue = resultQueue;
xQueueSend(bmp180_rx_queue, &c, 0);
}

55
extras/bmp180/bmp180.h Normal file
View file

@ -0,0 +1,55 @@
/*
* bmp180.h
*
* Created on: 23.08.2015
* Author: fbargste
*/
#ifndef DRIVER_BMP180_H_
#define DRIVER_BMP180_H_
#include "stdint.h"
#include "stdbool.h"
#include "FreeRTOS.h"
#include "queue.h"
// Uncomment to enable debug output
//#define BMP180_DEBUG
#define BMP180_TEMPERATURE (1<<0)
#define BMP180_PRESSURE (1<<1)
//
// Create bmp180_types
//
// temperature in °C
typedef float bmp180_temp_t;
// pressure in mPa (To get hPa divide by 100)
typedef uint32_t bmp180_press_t;
// BMP180_Event_Result
typedef struct
{
uint8_t cmd;
bmp180_temp_t temperatue;
bmp180_press_t pressure;
} bmp180_result_t;
// Init bmp180 driver ...
bool bmp180_init(uint8_t scl, uint8_t sda);
// Trigger a "complete" measurement (temperature and pressure will be valid when given to "bmp180_informUser)
void bmp180_trigger_measurement(const xQueueHandle* resultQueue);
// Trigger a "temperature only" measurement (only temperature will be valid when given to "bmp180_informUser)
void bmp180_trigger_temperature_measurement(const xQueueHandle* resultQueue);
// Trigger a "pressure only" measurement (only pressure will be valid when given to "bmp180_informUser)
void bmp180_trigger_pressure_measurement(const xQueueHandle* resultQueue);
// Give the user the chance to create it's own handler
extern bool (*bmp180_informUser)(const xQueueHandle* resultQueue, uint8_t cmd, bmp180_temp_t temperatue, bmp180_press_t pressure);
#endif /* DRIVER_BMP180_H_ */

View file

@ -0,0 +1,9 @@
# Component makefile for extras/bmp180
# expected anyone using bmp driver includes it as 'bmp180/bmp180.h'
INC_DIRS += $(bmp180_ROOT)..
# args for passing into compile rule generation
bmp180_SRC_DIR = $(bmp180_ROOT)
$(eval $(call component_compile_rules,bmp180))

22
extras/i2c/LICENSE Normal file
View file

@ -0,0 +1,22 @@
The MIT License (MIT)
Copyright (c) 2015 Johan 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.

40
extras/i2c/README.md Normal file
View file

@ -0,0 +1,40 @@
# Yet another I2C driver for the ESP8266
This time a driver for the excellent esp-open-rtos. This is a bit banging I2C driver based on the Wikipedia pesudo C code [1].
### Adding to your project
Add the driver to your project as a submodule rather than cloning it:
````
% git submodule add https://github.com/kanflo/esp-open-rtos-driver-i2c.git i2c
````
The esp-open-rtos makefile-fu will make sure the driver is built.
### Usage
````
#include <i2c.h>
#define SCL_PIN (0)
#define SDA_PIN (2)
uint8_t slave_addr = 0x20;
uint8_t reg_addr = 0x1f;
uint8_t reg_data;
uint8_t data[] = {reg_addr, 0xc8};
i2c_init(SCL_PIN, SDA_PIN);
// Write data to slave
bool success = i2c_slave_write(slave_addr, data, sizeof(data));
// Issue write to slave, sending reg_addr, followed by reading 1 byte
success = i2c_slave_read(slave_addr, &reg_addr, reg_data, 1);
````
The driver is released under the MIT license.
[1] https://en.wikipedia.org/wiki/I²C#Example_of_bit-banging_the_I.C2.B2C_Master_protocol

10
extras/i2c/component.mk Normal file
View file

@ -0,0 +1,10 @@
# Component makefile for extras/i2c
# expected anyone using i2c driver includes it as 'i2c/i2c.h'
INC_DIRS += $(i2c_ROOT)..
# args for passing into compile rule generation
i2c_INC_DIR =
i2c_SRC_DIR = $(i2c_ROOT)
$(eval $(call component_compile_rules,i2c))

229
extras/i2c/i2c.c Normal file
View file

@ -0,0 +1,229 @@
/*
* 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 <espressif/esp_misc.h> // sdk_os_delay_us
#include "i2c.h"
// I2C driver for ESP8266 written for use with esp-open-rtos
// Based on https://en.wikipedia.org/wiki/I²C#Example_of_bit-banging_the_I.C2.B2C_Master_protocol
// With calling overhead, we end up at ~100kbit/s
#define CLK_HALF_PERIOD_US (1)
#define CLK_STRETCH (10)
static bool started;
static uint8_t g_scl_pin;
static uint8_t g_sda_pin;
void i2c_init(uint8_t scl_pin, uint8_t sda_pin)
{
started = false;
g_scl_pin = scl_pin;
g_sda_pin = sda_pin;
}
static void i2c_delay(void)
{
sdk_os_delay_us(CLK_HALF_PERIOD_US);
}
// Set SCL as input and return current level of line, 0 or 1
static bool read_scl(void)
{
gpio_enable(g_scl_pin, GPIO_INPUT);
return gpio_read(g_scl_pin); // Clock high, valid ACK
}
// Set SDA as input and return current level of line, 0 or 1
static bool read_sda(void)
{
gpio_enable(g_sda_pin, GPIO_INPUT);
// TODO: Without this delay we get arbitration lost in i2c_stop
i2c_delay();
return gpio_read(g_sda_pin); // Clock high, valid ACK
}
// Actively drive SCL signal low
static void clear_scl(void)
{
gpio_enable(g_scl_pin, GPIO_OUTPUT);
gpio_write(g_scl_pin, 0);
}
// Actively drive SDA signal low
static void clear_sda(void)
{
gpio_enable(g_sda_pin, GPIO_OUTPUT);
gpio_write(g_sda_pin, 0);
}
// Output start condition
void i2c_start(void)
{
uint32_t clk_stretch = CLK_STRETCH;
if (started) { // if started, do a restart cond
// Set SDA to 1
(void) read_sda();
i2c_delay();
while (read_scl() == 0 && clk_stretch--) ;
// Repeated start setup time, minimum 4.7us
i2c_delay();
}
if (read_sda() == 0) {
printf("I2C: arbitration lost in i2c_start\n");
}
// SCL is high, set SDA from 1 to 0.
clear_sda();
i2c_delay();
clear_scl();
started = true;
}
// Output stop condition
void i2c_stop(void)
{
uint32_t clk_stretch = CLK_STRETCH;
// Set SDA to 0
clear_sda();
i2c_delay();
// Clock stretching
while (read_scl() == 0 && clk_stretch--) ;
// Stop bit setup time, minimum 4us
i2c_delay();
// SCL is high, set SDA from 0 to 1
if (read_sda() == 0) {
printf("I2C: arbitration lost in i2c_stop\n");
}
i2c_delay();
started = false;
}
// Write a bit to I2C bus
static void i2c_write_bit(bool bit)
{
uint32_t clk_stretch = CLK_STRETCH;
if (bit) {
(void) read_sda();
} else {
clear_sda();
}
i2c_delay();
// Clock stretching
while (read_scl() == 0 && clk_stretch--) ;
// SCL is high, now data is valid
// If SDA is high, check that nobody else is driving SDA
if (bit && read_sda() == 0) {
printf("I2C: arbitration lost in i2c_write_bit\n");
}
i2c_delay();
clear_scl();
}
// Read a bit from I2C bus
static bool i2c_read_bit(void)
{
uint32_t clk_stretch = CLK_STRETCH;
bool bit;
// Let the slave drive data
(void) read_sda();
i2c_delay();
// Clock stretching
while (read_scl() == 0 && clk_stretch--) ;
// SCL is high, now data is valid
bit = read_sda();
i2c_delay();
clear_scl();
return bit;
}
bool i2c_write(uint8_t byte)
{
bool nack;
uint8_t bit;
for (bit = 0; bit < 8; bit++) {
i2c_write_bit((byte & 0x80) != 0);
byte <<= 1;
}
nack = i2c_read_bit();
return !nack;
}
uint8_t i2c_read(bool ack)
{
uint8_t byte = 0;
uint8_t bit;
for (bit = 0; bit < 8; bit++) {
byte = (byte << 1) | i2c_read_bit();
}
i2c_write_bit(ack);
return byte;
}
bool i2c_slave_write(uint8_t slave_addr, uint8_t *data, uint8_t len)
{
bool success = false;
do {
i2c_start();
if (!i2c_write(slave_addr << 1))
break;
while (len--) {
if (!i2c_write(*data++))
break;
}
i2c_stop();
success = true;
} while(0);
return success;
}
bool i2c_slave_read(uint8_t slave_addr, uint8_t data, uint8_t *buf, uint32_t len)
{
bool success = false;
do {
i2c_start();
if (!i2c_write(slave_addr << 1)) {
break;
}
i2c_write(data);
i2c_stop();
i2c_start();
if (!i2c_write(slave_addr << 1 | 1)) { // Slave address + read
break;
}
while(len) {
*buf = i2c_read(len == 1);
buf++;
len--;
}
success = true;
} while(0);
i2c_stop();
if (!success) {
printf("I2C: write error\n");
}
return success;
}

51
extras/i2c/i2c.h Normal file
View file

@ -0,0 +1,51 @@
/*
* 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 __I2C_H__
#define __I2C_H__
#endif
#include <stdint.h>
#include <stdbool.h>
// Init bitbanging I2C driver on given pins
void i2c_init(uint8_t scl_pin, uint8_t sda_pin);
// Write a byte to I2C bus. Return true if slave acked.
bool i2c_write(uint8_t byte);
// Read a byte from I2C bus. Return true if slave acked.
uint8_t i2c_read(bool ack);
// Write 'len' bytes from 'buf' to slave. Return true if slave acked.
bool i2c_slave_write(uint8_t slave_addr, uint8_t *buf, uint8_t len);
// Issue a read operation and send 'data', followed by reading 'len' bytes
// from slave into 'buf'. Return true if slave acked.
bool i2c_slave_read(uint8_t slave_addr, uint8_t data, uint8_t *buf, uint32_t len);
// Send start and stop conditions. Only needed when implementing protocols for
// devices where the i2c_slave_[read|write] functions above are of no use.
void i2c_start(void);
void i2c_stop(void);

View file

@ -1,9 +1,9 @@
# Component makefile for extras/rboot-ota # Component makefile for extras/rboot-ota
INC_DIRS += $(ROOT)extras/rboot-ota INC_DIRS += $(rboot-ota_ROOT)
# args for passing into compile rule generation # args for passing into compile rule generation
extras/rboot-ota_INC_DIR = $(ROOT)extras/rboot-ota rboot-ota_SRC_DIR = $(rboot-ota_ROOT)
extras/rboot-ota_SRC_DIR = $(ROOT)extras/rboot-ota
$(eval $(call component_compile_rules,rboot-ota))
$(eval $(call component_compile_rules,extras/rboot-ota))

View file

@ -8,6 +8,10 @@
#ifndef __ESP_WIFI_H__ #ifndef __ESP_WIFI_H__
#define __ESP_WIFI_H__ #define __ESP_WIFI_H__
#include <stdint.h>
#include <stdbool.h>
#include <lwip/ip_addr.h>
enum { enum {
NULL_MODE = 0, NULL_MODE = 0,

View file

@ -30,8 +30,9 @@ struct ip_addr;
void sdk_uart_div_modify(uint32_t uart_no, uint32_t new_divisor); void sdk_uart_div_modify(uint32_t uart_no, uint32_t new_divisor);
/* Read a single character from the UART. /* Read a single character from the UART.
Returns 0 on success, 1 if no character in fifo
*/ */
char sdk_uart_rx_one_char(void); int sdk_uart_rx_one_char(char *buf);
/* Write a single character to the UART. /* Write a single character to the UART.
*/ */

31
include/ssid_config.h Normal file
View file

@ -0,0 +1,31 @@
//
// Why this file?
//
// We all need to add our personal SSID/password to each ESP project but we
// do not want that information pushed to Github. This file solves that
// problem.
//
// First tell git to ignore changes to this file:
//
// git update-index --assume-unchanged include/ssid_config.h
//
// Then, enter your SSID and passphrase below and it will never be committed
// to Github.
//
// Change password on project basis? Copy the default version this file to your
// project directory, redo the instructions and you have separate wifi settings
// for that project.
//
// For reference, see
// https://www.kernel.org/pub/software/scm/git/docs/git-update-index.html
//
#warning "You need to enter your wifi credentials in this file and follow the instructions here to keep the password safe from Github commits."
#ifndef __SSID_CONFIG_H__
#define __SSID_CONFIG_H__
#define WIFI_SSID "mywifissid"
#define WIFI_PASS "my secret password"
#endif // __SSID_CONFIG_H__

View file

@ -268,8 +268,8 @@ SECTIONS
(except for libgcc which is matched above.) (except for libgcc which is matched above.)
*/ */
*(.literal .text .literal.* .text.*) *(.literal .text .literal.* .text.*)
/* SDK libraries expect ICACHE_FLASH_ATTR/etc functions to be loaded explicitly as IROM */ /* Anything explicitly marked as "irom" or "irom0" should go here */
*sdklib*:*(.irom.* .irom.*.* .irom0.*) *(.irom.* .irom.*.* .irom0.*)
_irom0_text_end = ABSOLUTE(.); _irom0_text_end = ABSOLUTE(.);
} >irom0_0_seg :irom0_0_phdr } >irom0_0_seg :irom0_0_phdr

View file

@ -1,5 +1,8 @@
/* /*
* $Id$ * _default_types implementation for xtensa lx106 arch
*
* Simplified version of generic _default_types.h, ignores gcc
* built-in standard types.
*/ */
#ifndef _MACHINE__DEFAULT_TYPES_H #ifndef _MACHINE__DEFAULT_TYPES_H
@ -7,211 +10,44 @@
#include <sys/features.h> #include <sys/features.h>
/*
* Guess on types by examining *_MIN / *_MAX defines.
*/
#if __GNUC_PREREQ (3, 3)
/* GCC >= 3.3.0 has __<val>__ implicitly defined. */
#define __EXP(x) __##x##__
#else
/* Fall back to POSIX versions from <limits.h> */
#define __EXP(x) x
#include <limits.h>
#endif
#ifdef __cplusplus #ifdef __cplusplus
extern "C" { extern "C" {
#endif #endif
#ifdef __INT8_TYPE__
typedef __INT8_TYPE__ __int8_t;
#ifdef __UINT8_TYPE__
typedef __UINT8_TYPE__ __uint8_t;
#else
typedef unsigned __INT8_TYPE__ __uint8_t;
#endif
#define ___int8_t_defined 1
#elif __EXP(SCHAR_MAX) == 0x7f
typedef signed char __int8_t ; typedef signed char __int8_t ;
typedef unsigned char __uint8_t ; typedef unsigned char __uint8_t ;
#define ___int8_t_defined 1 #define ___int8_t_defined 1
#endif
#ifdef __INT16_TYPE__
typedef __INT16_TYPE__ __int16_t;
#ifdef __UINT16_TYPE__
typedef __UINT16_TYPE__ __uint16_t;
#else
typedef unsigned __INT16_TYPE__ __uint16_t;
#endif
#define ___int16_t_defined 1
#elif __EXP(INT_MAX) == 0x7fff
typedef signed int __int16_t;
typedef unsigned int __uint16_t;
#define ___int16_t_defined 1
#elif __EXP(SHRT_MAX) == 0x7fff
typedef signed short __int16_t; typedef signed short __int16_t;
typedef unsigned short __uint16_t; typedef unsigned short __uint16_t;
#define ___int16_t_defined 1 #define ___int16_t_defined 1
#elif __EXP(SCHAR_MAX) == 0x7fff
typedef signed char __int16_t;
typedef unsigned char __uint16_t;
#define ___int16_t_defined 1
#endif
#ifdef __INT32_TYPE__
typedef __INT32_TYPE__ __int32_t;
#ifdef __UINT32_TYPE__
typedef __UINT32_TYPE__ __uint32_t;
#else
typedef unsigned __INT32_TYPE__ __uint32_t;
#endif
#define ___int32_t_defined 1
#elif __EXP(INT_MAX) == 0x7fffffffL
typedef signed int __int32_t; typedef signed int __int32_t;
typedef unsigned int __uint32_t; typedef unsigned int __uint32_t;
#define ___int32_t_defined 1 #define ___int32_t_defined 1
#elif __EXP(LONG_MAX) == 0x7fffffffL
typedef signed long __int32_t;
typedef unsigned long __uint32_t;
#define ___int32_t_defined 1
#elif __EXP(SHRT_MAX) == 0x7fffffffL
typedef signed short __int32_t;
typedef unsigned short __uint32_t;
#define ___int32_t_defined 1
#elif __EXP(SCHAR_MAX) == 0x7fffffffL
typedef signed char __int32_t;
typedef unsigned char __uint32_t;
#define ___int32_t_defined 1
#endif
#ifdef __INT64_TYPE__
typedef __INT64_TYPE__ __int64_t;
#ifdef __UINT64_TYPE__
typedef __UINT64_TYPE__ __uint64_t;
#else
typedef unsigned __INT64_TYPE__ __uint64_t;
#endif
#define ___int64_t_defined 1
#elif __EXP(LONG_MAX) > 0x7fffffff
typedef signed long __int64_t;
typedef unsigned long __uint64_t;
#define ___int64_t_defined 1
/* GCC has __LONG_LONG_MAX__ */
#elif defined(__LONG_LONG_MAX__) && (__LONG_LONG_MAX__ > 0x7fffffff)
typedef signed long long __int64_t; typedef signed long long __int64_t;
typedef unsigned long long __uint64_t; typedef unsigned long long __uint64_t;
#define ___int64_t_defined 1 #define ___int64_t_defined 1
/* POSIX mandates LLONG_MAX in <limits.h> */
#elif defined(LLONG_MAX) && (LLONG_MAX > 0x7fffffff)
typedef signed long long __int64_t;
typedef unsigned long long __uint64_t;
#define ___int64_t_defined 1
#elif __EXP(INT_MAX) > 0x7fffffff
typedef signed int __int64_t;
typedef unsigned int __uint64_t;
#define ___int64_t_defined 1
#endif
#ifdef __INT_LEAST8_TYPE__
typedef __INT_LEAST8_TYPE__ __int_least8_t;
#ifdef __UINT_LEAST8_TYPE__
typedef __UINT_LEAST8_TYPE__ __uint_least8_t;
#else
typedef unsigned __INT_LEAST8_TYPE__ __uint_least8_t;
#endif
#define ___int_least8_t_defined 1
#elif defined(___int8_t_defined)
typedef __int8_t __int_least8_t; typedef __int8_t __int_least8_t;
typedef __uint8_t __uint_least8_t; typedef __uint8_t __uint_least8_t;
#define ___int_least8_t_defined 1 #define ___int_least8_t_defined
#elif defined(___int16_t_defined)
typedef __int16_t __int_least8_t;
typedef __uint16_t __uint_least8_t;
#define ___int_least8_t_defined 1
#elif defined(___int32_t_defined)
typedef __int32_t __int_least8_t;
typedef __uint32_t __uint_least8_t;
#define ___int_least8_t_defined 1
#elif defined(___int64_t_defined)
typedef __int64_t __int_least8_t;
typedef __uint64_t __uint_least8_t;
#define ___int_least8_t_defined 1
#endif
#ifdef __INT_LEAST16_TYPE__
typedef __INT_LEAST16_TYPE__ __int_least16_t;
#ifdef __UINT_LEAST16_TYPE__
typedef __UINT_LEAST16_TYPE__ __uint_least16_t;
#else
typedef unsigned __INT_LEAST16_TYPE__ __uint_least16_t;
#endif
#define ___int_least16_t_defined 1
#elif defined(___int16_t_defined)
typedef __int16_t __int_least16_t; typedef __int16_t __int_least16_t;
typedef __uint16_t __uint_least16_t; typedef __uint16_t __uint_least16_t;
#define ___int_least16_t_defined 1 #define ___int_least16_t_defined
#elif defined(___int32_t_defined)
typedef __int32_t __int_least16_t;
typedef __uint32_t __uint_least16_t;
#define ___int_least16_t_defined 1
#elif defined(___int64_t_defined)
typedef __int64_t __int_least16_t;
typedef __uint64_t __uint_least16_t;
#define ___int_least16_t_defined 1
#endif
#ifdef __INT_LEAST32_TYPE__
typedef __INT_LEAST32_TYPE__ __int_least32_t;
#ifdef __UINT_LEAST32_TYPE__
typedef __UINT_LEAST32_TYPE__ __uint_least32_t;
#else
typedef unsigned __INT_LEAST32_TYPE__ __uint_least32_t;
#endif
#define ___int_least32_t_defined 1
#elif defined(___int32_t_defined)
typedef __int32_t __int_least32_t; typedef __int32_t __int_least32_t;
typedef __uint32_t __uint_least32_t; typedef __uint32_t __uint_least32_t;
#define ___int_least32_t_defined 1 #define ___int_least32_t_defined
#elif defined(___int64_t_defined)
typedef __int64_t __int_least32_t;
typedef __uint64_t __uint_least32_t;
#define ___int_least32_t_defined 1
#endif
#ifdef __INT_LEAST64_TYPE__
typedef __INT_LEAST64_TYPE__ __int_least64_t;
#ifdef __UINT_LEAST64_TYPE__
typedef __UINT_LEAST64_TYPE__ __uint_least64_t;
#else
typedef unsigned __INT_LEAST64_TYPE__ __uint_least64_t;
#endif
#define ___int_least64_t_defined 1
#elif defined(___int64_t_defined)
typedef __int64_t __int_least64_t; typedef __int64_t __int_least64_t;
typedef __uint64_t __uint_least64_t; typedef __uint64_t __uint_least64_t;
#define ___int_least64_t_defined 1 #define ___int_least64_t_defined
#endif
#ifdef __INTPTR_TYPE__
typedef __INTPTR_TYPE__ __intptr_t; typedef __INTPTR_TYPE__ __intptr_t;
#ifdef __UINTPTR_TYPE__
typedef __UINTPTR_TYPE__ __uintptr_t; typedef __UINTPTR_TYPE__ __uintptr_t;
#else
typedef unsigned __INTPTR_TYPE__ __uintptr_t;
#endif
#elif defined(__PTRDIFF_TYPE__)
typedef __PTRDIFF_TYPE__ __intptr_t;
typedef unsigned __PTRDIFF_TYPE__ __uintptr_t;
#else
typedef long __intptr_t;
typedef unsigned long __uintptr_t;
#endif
#undef __EXP
#ifdef __cplusplus #ifdef __cplusplus
} }

View file

@ -4,6 +4,8 @@
* *
* Permission to use, copy, modify, and distribute this software * Permission to use, copy, modify, and distribute this software
* is freely granted, provided that this notice is preserved. * is freely granted, provided that this notice is preserved.
*
* Modified for xtensa arch & non-long int32_t, removes automatic setting of __have_long32.
*/ */
#ifndef _SYS__INTSUP_H #ifndef _SYS__INTSUP_H
@ -11,26 +13,8 @@
#include <sys/features.h> #include <sys/features.h>
#if __GNUC_PREREQ (3, 2)
/* gcc > 3.2 implicitly defines the values we are interested */
#define __STDINT_EXP(x) __##x##__ #define __STDINT_EXP(x) __##x##__
#else
#define __STDINT_EXP(x) x
#include <limits.h>
#endif
/* Check if "long long" is 64bit wide */
/* Modern GCCs provide __LONG_LONG_MAX__, SUSv3 wants LLONG_MAX */
#if ( defined(__LONG_LONG_MAX__) && (__LONG_LONG_MAX__ > 0x7fffffff) ) \
|| ( defined(LLONG_MAX) && (LLONG_MAX > 0x7fffffff) )
#define __have_longlong64 1 #define __have_longlong64 1
#endif
/* Check if "long" is 64bit or 32bit wide */
#if __STDINT_EXP(LONG_MAX) > 0x7fffffff
#define __have_long64 1
#elif __STDINT_EXP(LONG_MAX) == 0x7fffffff && !defined(__SPU__)
#define __have_long32 1
#endif
#endif /* _SYS__INTSUP_H */ #endif /* _SYS__INTSUP_H */

Binary file not shown.

Binary file not shown.

Binary file not shown.

View file

@ -1,12 +1,11 @@
# Component makefile for LWIP # Component makefile for LWIP
LWIP_DIR = $(ROOT)lwip/lwip/src/ LWIP_DIR = $(lwip_ROOT)lwip/src/
INC_DIRS += $(LWIP_DIR)include $(ROOT)lwip/include $(ROOT)lwip/include $(LWIP_DIR)include/ipv4 $(LWIP_DIR)include/ipv4/lwip $(LWIP_DIR)include/lwip INC_DIRS += $(LWIP_DIR)include $(ROOT)lwip/include $(lwip_ROOT)include $(LWIP_DIR)include/ipv4 $(LWIP_DIR)include/ipv4/lwip $(LWIP_DIR)include/lwip
# args for passing into compile rule generation # args for passing into compile rule generation
lwip_ROOT = $(ROOT)/lwip
lwip_INC_DIR = # all in INC_DIRS, needed for normal operation lwip_INC_DIR = # all in INC_DIRS, needed for normal operation
lwip_SRC_DIR = $(ROOT)/lwip $(LWIP_DIR)api $(LWIP_DIR)core $(LWIP_DIR)core/ipv4 $(LWIP_DIR)netif lwip_SRC_DIR = $(lwip_ROOT) $(LWIP_DIR)api $(LWIP_DIR)core $(LWIP_DIR)core/ipv4 $(LWIP_DIR)netif
# LWIP 1.4.1 generates a single warning so we need to disable -Werror when building it # LWIP 1.4.1 generates a single warning so we need to disable -Werror when building it
lwip_CFLAGS = $(CFLAGS) -Wno-address lwip_CFLAGS = $(CFLAGS) -Wno-address

View file

@ -39,9 +39,6 @@
#define ESP_TIMEWAIT_THRESHOLD 10000 #define ESP_TIMEWAIT_THRESHOLD 10000
#define LWIP_TIMEVAL_PRIVATE 0 #define LWIP_TIMEVAL_PRIVATE 0
// Uncomment this line, and set the debug options you want below, for IP stack debug output
//#define LWIP_DEBUG
/* /*
----------------------------------------------- -----------------------------------------------
---------- Platform specific locking ---------- ---------- Platform specific locking ----------
@ -390,6 +387,10 @@
---------- Debugging options ---------- ---------- Debugging options ----------
--------------------------------------- ---------------------------------------
*/ */
// Uncomment this line, and set the individual debug options you want, for IP stack debug output
//#define LWIP_DEBUG
/** /**
* ETHARP_DEBUG: Enable debugging in etharp.c. * ETHARP_DEBUG: Enable debugging in etharp.c.
*/ */
@ -430,11 +431,22 @@
*/ */
#define TCP_OUTPUT_DEBUG LWIP_DBG_OFF #define TCP_OUTPUT_DEBUG LWIP_DBG_OFF
/**
* UDP_DEBUG: Enable debugging in udp.c.
*/
#define UDP_DEBUG LWIP_DBG_OFF
/**
* ICMP_DEBUG: Enable debugging in udp.c.
*/
#define ICMP_DEBUG LWIP_DBG_OFF
/** /**
* TCPIP_DEBUG: Enable debugging in tcpip.c. * TCPIP_DEBUG: Enable debugging in tcpip.c.
*/ */
#define TCPIP_DEBUG LWIP_DBG_OFF #define TCPIP_DEBUG LWIP_DBG_OFF
/** /**
* DHCP_DEBUG: Enable debugging in dhcp.c. * DHCP_DEBUG: Enable debugging in dhcp.c.
*/ */

View file

@ -0,0 +1,28 @@
/* Some netbuf helpers that should probably be rolled into a patch to lwip soon */
#ifndef _NETBUF_HELPERS_H
#define _NETBUF_HELPERS_H
#include "lwip/netbuf.h"
/* Read a 16 bit wide unsigned integer, stored host order, from the netbuf */
inline static u16_t netbuf_read_u16_h(struct netbuf *netbuf, u16_t offs)
{
u16_t raw;
netbuf_copy_partial(netbuf, &raw, 2, offs);
return raw;
}
/* Read a 16 bit wide unsigned integer, stored network order, from the netbuf */
inline static u16_t netbuf_read_u16_n(struct netbuf *netbuf, u16_t offs)
{
return ntohs(netbuf_read_u16_h(netbuf, offs));
}
/* Read an 8 bit unsigned integer from the netbuf */
inline static u8_t netbuf_read_u8(struct netbuf *netbuf, u16_t offs)
{
u8_t result;
netbuf_copy_partial(netbuf, &result, 1, offs);
return result;
}
#endif