Merge branch 'master' into feature/c++

This commit is contained in:
Angus Gratton 2015-08-26 10:46:48 +10:00
commit e43d2dd3de
27 changed files with 1352 additions and 591 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

@ -4,15 +4,17 @@ 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).
[![Build Status](https://travis-ci.org/SuperHouse/esp-open-rtos.svg?branch=master)](https://travis-ci.org/SuperHouse/esp-open-rtos)
## 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!)
(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 probably have these already.
* Use git to clone the esp-open-rtos project (note the `--recursive`):

View file

@ -25,7 +25,7 @@
OR
- 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
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)
{
uint32_t status_reg = GPIO_STATUS_REG;
GPIO_STATUS_CLEAR = status_reg;
uint32_t status_reg = GPIO.STATUS;
GPIO.STATUS_CLEAR = status_reg;
uint8_t gpio_idx;
while((gpio_idx = __builtin_ffs(status_reg)))
{
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]();
}
}

View file

@ -14,12 +14,12 @@
* the arguments aren't known at compile time (values are evaluated at
* 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);
}
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);
}

View file

@ -16,6 +16,16 @@
#define BIT(X) (1<<(X))
#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##_M) << 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))
/* Use this macro to store constant values in IROM flash instead
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
} __attribute__ (( packed ));
_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
#define _ESP_GPIO_H
#include <stdbool.h>
#include "esp/registers.h"
#include "esp/gpio_regs.h"
#include "esp/iomux.h"
#include "esp/cpu.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) {
case GPIO_INPUT:
iomux_flags = 0;
ctrl_val = GPIO_SOURCE_GPIO;
ctrl_val = 0;
break;
case GPIO_OUTPUT:
iomux_flags = IOMUX_OE;
ctrl_val = GPIO_DRIVE_PUSH_PULL|GPIO_SOURCE_GPIO;
iomux_flags = IOMUX_PIN_OUTPUT_ENABLE;
ctrl_val = GPIO_CONF_PUSH_PULL;
break;
case GPIO_OUT_OPEN_DRAIN:
iomux_flags = IOMUX_OE;
ctrl_val = GPIO_DRIVE_OPEN_DRAIN|GPIO_SOURCE_GPIO;
iomux_flags = IOMUX_PIN_OUTPUT_ENABLE;
ctrl_val = 0;
break;
case GPIO_INPUT_PULLUP:
iomux_flags = IOMUX_PU;
ctrl_val = GPIO_SOURCE_GPIO;
iomux_flags = IOMUX_PIN_PULLUP;
ctrl_val = 0;
break;
}
iomux_set_gpio_function(gpio_num, iomux_flags);
GPIO_CTRL_REG(gpio_num) = (GPIO_CTRL_REG(gpio_num)&GPIO_INT_MASK) | ctrl_val;
if(direction == GPIO_OUTPUT)
GPIO_DIR_SET = BIT(gpio_num);
GPIO.CONF[gpio_num] = (GPIO.CONF[gpio_num] & FIELD_MASK(GPIO_CONF_INTTYPE)) | ctrl_val;
if (iomux_flags & IOMUX_PIN_OUTPUT_ENABLE)
GPIO.ENABLE_OUT_SET = BIT(gpio_num);
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.
*
* 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)
{
GPIO_DIR_CLEAR = BIT(gpio_num);
*gpio_iomux_reg(gpio_num) &= ~IOMUX_OE;
GPIO.ENABLE_OUT_CLEAR = BIT(gpio_num);
*gpio_iomux_reg(gpio_num) &= ~IOMUX_PIN_OUTPUT_ENABLE;
}
/* 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)
{
if(set)
GPIO_OUT_SET = BIT(gpio_num);
GPIO.OUT_SET = BIT(gpio_num);
else
GPIO_OUT_CLEAR = BIT(gpio_num);
GPIO.OUT_CLEAR = BIT(gpio_num);
}
/* 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
task's pins, without needing to disable/enable interrupts.
*/
if(GPIO_OUT_REG & BIT(gpio_num))
GPIO_OUT_CLEAR = BIT(gpio_num);
if(GPIO.OUT & BIT(gpio_num))
GPIO.OUT_CLEAR = BIT(gpio_num);
else
GPIO_OUT_SET = BIT(gpio_num);
GPIO.OUT_SET = BIT(gpio_num);
}
/* 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)
{
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);
/* 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)
| (int_type & GPIO_INT_MASK);
if(int_type != INT_NONE) {
GPIO.CONF[gpio_num] = SET_FIELD(GPIO.CONF[gpio_num], GPIO_CONF_INTTYPE, int_type);
if(int_type != GPIO_INTTYPE_NONE) {
_xt_isr_attach(INUM_GPIO, gpio_interrupt_handler);
_xt_isr_unmask(1<<INUM_GPIO);
}
}
/* 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

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
} __attribute__ (( packed ));
_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
#define _ESP_IOMUX_H
#include <stdint.h>
#include "esp/registers.h"
#include "esp/types.h"
#include "esp/iomux_regs.h"
/**
* 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
*
* 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)
{
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
* 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.
* ie the following are equivalent:
*
* iomux_set_gpio_function(12, IOMUX_OE);
* IOMUX_GP12 = (IOMUX_GP12 & ~IOMUX_FUNC_MASK) | IOMUX_GP12_GPIO | IOMUX_OE;
* iomux_set_gpio_function(12, IOMUX_PIN_OUTPUT_ENABLE);
* IOMUX_GPIO12 = IOMUX_GPIO12_FUNC_GPIO | IOMUX_PIN_OUTPUT_ENABLE;
*/
inline static void iomux_set_gpio_function(const uint8_t gpio_number, const 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 esp_reg_t reg = &IOMUX_REG(reg_idx);
const uint32_t func = (reg_idx > 11 ? IOMUX_FUNC_A : IOMUX_FUNC_D) | flags;
const uint32_t val = *reg & ~(IOMUX_FUNC_MASK | IOMUX_FLAG_MASK);
*reg = val | func;
const uint32_t func = (reg_idx > 11 ? IOMUX_FUNC(0) : IOMUX_FUNC(3)) | flags;
IOMUX.PIN[reg_idx] = func | flags;
}
/**
* 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
declared above */
#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
} __attribute__ (( packed ));
_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
#define _ESP_REGISTERS
#include "common_macros.h"
#include "esp/types.h"
typedef volatile uint32_t *esp_reg_t;
/* Internal macro, only defined in header body */
#define _REG(BASE, OFFSET) (*(esp_reg_t)((BASE)+(OFFSET)))
#include "esp/uart_regs.h"
#include "esp/spi_regs.h"
#include "esp/iomux_regs.h"
#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
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 DPORT_BASE 0x3ff00000
//#define DPORT_BASE 0x3ff00000
#define UART0_BASE (MMIO_BASE + 0)
#define SPI1_BASE (MMIO_BASE + 0x0100)
#define SPI_BASE (MMIO_BASE + 0x0200)
#define GPIO0_BASE (MMIO_BASE + 0x0300)
#define TIMER_BASE (MMIO_BASE + 0x0600)
//#define UART0_BASE (MMIO_BASE + 0)
//#define SPI1_BASE (MMIO_BASE + 0x0100)
//#define SPI_BASE (MMIO_BASE + 0x0200)
//#define GPIO0_BASE (MMIO_BASE + 0x0300)
//#define TIMER_BASE (MMIO_BASE + 0x0600)
#define RTC_BASE (MMIO_BASE + 0x0700)
#define IOMUX_BASE (MMIO_BASE + 0x0800)
#define WDT_BASE (MMIO_BASE + 0x0900)
//#define IOMUX_BASE (MMIO_BASE + 0x0800)
//#define WDT_BASE (MMIO_BASE + 0x0900)
#define I2C_BASE (MMIO_BASE + 0x0d00)
#define UART1_BASE (MMIO_BASE + 0x0F00)
#define RTCB_BASE (MMIO_BASE + 0x1000)
#define RTCS_BASE (MMIO_BASE + 0x1100)
#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)
//#define UART1_BASE (MMIO_BASE + 0x0F00)
//#define RTCB_BASE (MMIO_BASE + 0x1000)
//#define RTCS_BASE (MMIO_BASE + 0x1100)
//#define RTCU_BASE (MMIO_BASE + 0x1200)
#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
} __attribute__ (( packed ));
_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 <xtensa_interrupts.h>
#include "esp/registers.h"
#include "esp/timer_regs.h"
#include "esp/cpu.h"
typedef enum {
TIMER_FRC1,
TIMER_FRC2,
FRC1 = 0,
FRC2 = 1,
} timer_frc_t;
/* 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. */
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 */
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
@ -62,7 +56,7 @@ INLINED bool timer_get_reload(const timer_frc_t frc);
/* Return a suitable timer divider for the specified frequency,
or -1 if none is found.
*/
INLINED timer_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
* 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.
*/
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
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
* 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.
*/
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.

View file

@ -10,6 +10,7 @@
#include <limits.h>
#include <stdio.h>
#include <stdlib.h>
#include "esp/dport_regs.h"
/* Timer divisor index to max frequency */
#define _FREQ_DIV1 (80*1000*1000)
@ -20,104 +21,90 @@ const static uint32_t IROM _TIMER_FREQS[] = { _FREQ_DIV1, _FREQ_DIV16, _FREQ_DIV
/* Timer divisor index to divisor value */
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)
{
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)
{
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)
{
if(frc == TIMER_FRC1)
TIMER_FRC1_LOAD_REG = load;
else
TIMER_FRC2_LOAD_REG = load;
TIMER(frc).LOAD = load;
}
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;
esp_reg_t ctrl = _timer_ctrl_reg(frc);
*ctrl = (*ctrl & ~TIMER_CTRL_DIV_MASK) | (_TIMER_DIV_REG[div] & TIMER_CTRL_DIV_MASK);
TIMER(frc).CTRL = SET_FIELD(TIMER(frc).CTRL, TIMER_CTRL_CLKDIV, div);
}
INLINED void timer_set_interrupts(const timer_frc_t frc, bool enable)
{
const uint32_t dp_bit = (frc == TIMER_FRC1) ? INT_ENABLE_FRC1 : INT_ENABLE_FRC2;
const uint32_t int_mask = BIT((frc == TIMER_FRC1) ? INUM_TIMER_FRC1 : INUM_TIMER_FRC2);
const uint32_t dp_bit = (frc == FRC1) ? DPORT_INT_ENABLE_FRC1 : DPORT_INT_ENABLE_FRC2;
const uint32_t int_mask = BIT((frc == FRC1) ? INUM_TIMER_FRC1 : INUM_TIMER_FRC2);
if(enable) {
DP_INT_ENABLE_REG |= dp_bit;
DPORT.INT_ENABLE |= dp_bit;
_xt_isr_unmask(int_mask);
} else {
DP_INT_ENABLE_REG &= ~dp_bit;
DPORT.INT_ENABLE &= ~dp_bit;
_xt_isr_mask(int_mask);
}
}
INLINED void timer_set_run(const timer_frc_t frc, const bool run)
{
esp_reg_t ctrl = _timer_ctrl_reg(frc);
if (run)
*ctrl |= TIMER_CTRL_RUN;
TIMER(frc).CTRL |= TIMER_CTRL_RUN;
else
*ctrl &= ~TIMER_CTRL_RUN;
TIMER(frc).CTRL &= ~TIMER_CTRL_RUN;
}
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)
{
esp_reg_t ctrl = _timer_ctrl_reg(frc);
if (reload)
*ctrl |= TIMER_CTRL_RELOAD;
TIMER(frc).CTRL |= TIMER_CTRL_RELOAD;
else
*ctrl &= ~TIMER_CTRL_RELOAD;
TIMER(frc).CTRL &= ~TIMER_CTRL_RELOAD;
}
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.
these values are a bit arbitrary at the moment! */
if(freq > 100*1000)
return TIMER_DIV1;
return TIMER_CLKDIV_1;
else if(freq > 100)
return TIMER_DIV16;
return TIMER_CLKDIV_16;
else
return TIMER_DIV256;
return TIMER_CLKDIV_256;
}
/* timer_timer_to_count implementation - inline if all args are constant, call normally otherwise */
INLINED uint32_t _timer_freq_to_count_impl(const timer_frc_t frc, const uint32_t freq, const timer_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 */
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;
}
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))
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);
}
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
timer_freq_to_div, these values are a bit arbitrary at the
moment! */
if(us < 1000)
return TIMER_DIV1;
return TIMER_CLKDIV_1;
else if(us < 10*1000)
return TIMER_DIV16;
return TIMER_CLKDIV_16;
else
return TIMER_DIV256;
return TIMER_CLKDIV_256;
}
/* timer_timer_to_count implementation - inline if all args are constant, call normally otherwise */
INLINED uint32_t _timer_time_to_count_impl(const timer_frc_t frc, uint32_t us, const timer_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 */
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 */
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)
return 0; /* Multiplying us by mhz_per_count will overflow TIMER_MAX */
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))
return _timer_time_to_count_impl(frc, us, div);
@ -201,7 +188,7 @@ 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)
{
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);
if(counts == 0)
@ -211,7 +198,7 @@ INLINED bool _timer_set_frequency_impl(const timer_frc_t frc, uint32_t freq)
}
timer_set_divider(frc, div);
if(frc == TIMER_FRC1)
if(frc == FRC1)
{
timer_set_load(frc, counts);
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 */
{
/* 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;
}
@ -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)
{
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);
if(counts == 0)
return false; /* can't set frequency */
timer_set_divider(frc, div);
if(frc == TIMER_FRC1)
if(frc == FRC1)
{
timer_set_load(frc, counts);
}
else /* FRC2 */
{
TIMER_FRC2_MATCH_REG = counts + TIMER_FRC2_COUNT_REG;
TIMER(1).ALARM = counts + TIMER(1).COUNT;
}
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
} __attribute__ (( packed ));
_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 *)(0x60000200 - (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
} __attribute__ (( packed ));
_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
} __attribute__ (( packed ));
_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

@ -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:
@echo "******************************************************"
@echo "You may not want this Makefile, even though it's here!"
@echo "******************************************************"
@echo ""
@echo "SUGGESTIONS:"
@echo "Running 'make' in one of the subdirectories will build a single example."
@echo "Running 'make help' in one of the subdirectories will print some help."
@echo "Running 'make' in one of the subdirectories of examples/ will build a single example."
@echo "Running 'make help' in one of the subdirectories of examples/ will print some help."
@echo ""
@echo "OTHERWISE:"
@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
build-examples:
set -e
for example in `find . -mindepth 2 -name Makefile | sed s/Makefile//)`; do
$(MAKE) -C $$example
done
build-examples: $(EXAMPLES_BUILD)
rebuild-examples:
set -e
for example in `find . -mindepth 2 -name Makefile | sed s/Makefile//)`; do
$(MAKE) -C $$example rebuild
done
rebuild-examples: $(EXAMPLES_REBUILD)
%.dummybuild:
make -C $(dir $@)
%.dummyrebuild:
make -C $(dir $@) rebuild
.PHONY: warning rebuild-examples build-examples
.NOTPARALLEL:

View file

@ -30,8 +30,8 @@ void blinkenTask(void *pvParameters)
/* 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
as part of the GPxx value.
It's not fully parameterised, as the IOMUX_GPIO# macros involve a non-linear
mapping from GPIO to IOMUX ports.
There is no significant performance benefit to this way over the
blinkenTask version, so it's probably better to use the blinkenTask
@ -41,12 +41,12 @@ void blinkenTask(void *pvParameters)
*/
void blinkenRegisterTask(void *pvParameters)
{
GPIO_DIR_SET = BIT(gpio);
IOMUX_SET(GP14,GPIO,IOMUX_OE); /* change this line if you change 'gpio' */
GPIO.ENABLE_OUT_SET = BIT(gpio);
IOMUX_GPIO14 = IOMUX_GPIO14_FUNC_GPIO | IOMUX_PIN_OUTPUT_ENABLE; /* change this line if you change 'gpio' */
while(1) {
GPIO_OUT_SET = BIT(gpio);
GPIO.OUT_SET = BIT(gpio);
vTaskDelay(1000 / portTICK_RATE_MS);
GPIO_OUT_CLEAR = BIT(gpio);
GPIO.OUT_CLEAR = BIT(gpio);
vTaskDelay(1000 / portTICK_RATE_MS);
}
}

View file

@ -26,7 +26,7 @@ void frc1_interrupt_handler(void)
void frc2_interrupt_handler(void)
{
/* 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++;
gpio_toggle(gpio_frc2);
}
@ -41,24 +41,24 @@ void user_init(void)
gpio_write(gpio_frc1, 1);
/* stop both timers and mask their interrupts as a precaution */
timer_set_interrupts(TIMER_FRC1, false);
timer_set_run(TIMER_FRC1, false);
timer_set_interrupts(TIMER_FRC2, false);
timer_set_run(TIMER_FRC2, false);
timer_set_interrupts(FRC1, false);
timer_set_run(FRC1, false);
timer_set_interrupts(FRC2, false);
timer_set_run(FRC2, false);
/* set up ISRs */
_xt_isr_attach(INUM_TIMER_FRC1, frc1_interrupt_handler);
_xt_isr_attach(INUM_TIMER_FRC2, frc2_interrupt_handler);
/* configure timer frequencies */
timer_set_frequency(TIMER_FRC1, freq_frc1);
timer_set_frequency(TIMER_FRC2, freq_frc2);
timer_set_frequency(FRC1, freq_frc1);
timer_set_frequency(FRC2, freq_frc2);
/* unmask interrupts and start timers */
timer_set_interrupts(TIMER_FRC1, true);
timer_set_run(TIMER_FRC1, true);
timer_set_interrupts(TIMER_FRC2, true);
timer_set_run(TIMER_FRC2, true);
timer_set_interrupts(FRC1, true);
timer_set_run(FRC1, true);
timer_set_interrupts(FRC2, true);
timer_set_run(FRC2, true);
gpio_write(gpio_frc1, 0);
}

View file

@ -15,7 +15,7 @@
/* pin config */
const int gpio = 0; /* gpio 0 usually has "PROGRAM" button attached */
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

View file

@ -11,14 +11,15 @@
#include "FreeRTOS.h"
#include "task.h"
#include "esp8266.h"
#include "common_macros.h"
#define DUMP_SZ 0x10 /* number of regs not size of buffer */
IRAM void dump_frc1_seq(void)
{
uint32_t f1_a = TIMER_FRC1_COUNT_REG;
uint32_t f1_b = TIMER_FRC1_COUNT_REG;
uint32_t f1_c = TIMER_FRC1_COUNT_REG;
uint32_t f1_a = TIMER(0).COUNT;
uint32_t f1_b = TIMER(0).COUNT;
uint32_t f1_c = TIMER(0).COUNT;
printf("FRC1 sequence 0x%08lx 0x%08lx 0x%08lx\r\n", f1_a, f1_b, f1_c);
printf("FRC1 deltas %ld %ld \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)
*
*/
uint32_t f2_a = TIMER_FRC2_COUNT_REG;
uint32_t f2_b = TIMER_FRC2_COUNT_REG;
uint32_t f2_c = TIMER_FRC2_COUNT_REG;
uint32_t f2_a = TIMER(1).COUNT;
uint32_t f2_b = TIMER(1).COUNT;
uint32_t f2_c = TIMER(1).COUNT;
printf("FRC2 sequence 0x%08lx 0x%08lx 0x%08lx\r\n", f2_a, f2_b, f2_c);
printf("FRC2 deltas %ld %ld \r\n", f2_b-f2_a, f2_c-f2_b);
}
@ -99,20 +100,20 @@ void timerRegTask(void *pvParameters)
IRAM void frc1_handler(void)
{
frc1_handler_call_count++;
frc1_last_count_val = TIMER_FRC1_COUNT_REG;
//TIMER_FRC1_LOAD_REG = 0x300000;
//TIMER_FRC1_CLEAR_INT = 0;
frc1_last_count_val = TIMER(0).COUNT;
//TIMER(0).LOAD = 0x300000;
//TIMER(0).STATUS = 0;
//TIMER_FRC1_MATCH_REG = frc1_last_count_val + 0x100000;
}
void frc2_handler(void)
{
frc2_handler_call_count++;
frc2_last_count_val = TIMER_FRC2_COUNT_REG;
TIMER_FRC2_MATCH_REG = frc2_last_count_val + 0x100000;
//TIMER_FRC2_LOAD_REG = 0;
//TIMER_FRC2_LOAD_REG = 0x2000000;
//TIMER_FRC2_CLEAR_INT_REG = 0;
frc2_last_count_val = TIMER(1).COUNT;
TIMER(1).ALARM = frc2_last_count_val + 0x100000;
//TIMER(1).LOAD = 0;
//TIMER(1).LOAD = 0x2000000;
//TIMER(1).STATUS = 0;
}
void user_init(void)
@ -120,19 +121,19 @@ void user_init(void)
sdk_uart_div_modify(0, UART_CLK_FREQ / 115200);
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_FRC1_LOAD_REG = 0x200000;
TIMER(0).CTRL = VAL2FIELD(TIMER_CTRL_CLKDIV, TIMER_CLKDIV_256) | TIMER_CTRL_RELOAD;
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_unmask(1<<INUM_TIMER_FRC1);
_xt_isr_attach(INUM_TIMER_FRC2, frc2_handler);
_xt_isr_unmask(1<<INUM_TIMER_FRC2);
TIMER_FRC1_CTRL_REG |= TIMER_CTRL_RUN;
TIMER_FRC2_CTRL_REG |= TIMER_CTRL_RUN;
TIMER(0).CTRL |= TIMER_CTRL_RUN;
TIMER(1).CTRL |= TIMER_CTRL_RUN;
dump_timer_regs("timer regs during user_init");
dump_timer_regs("#2 timer regs during user_init");

View file

@ -8,6 +8,10 @@
#ifndef __ESP_WIFI_H__
#define __ESP_WIFI_H__
#include <stdint.h>
#include <stdbool.h>
#include <lwip/ip_addr.h>
#ifdef __cplusplus
extern "C" {

View file

@ -39,9 +39,6 @@
#define ESP_TIMEWAIT_THRESHOLD 10000
#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 ----------
@ -390,6 +387,10 @@
---------- 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.
*/
@ -430,11 +431,22 @@
*/
#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.
*/
#define TCPIP_DEBUG LWIP_DBG_OFF
/**
* 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