diff --git a/.travis.yml b/.travis.yml new file mode 100644 index 0000000..6b51bde --- /dev/null +++ b/.travis.yml @@ -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-" diff --git a/README.md b/README.md index 1d1c456..7bfa2e0 100644 --- a/README.md +++ b/README.md @@ -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`): diff --git a/core/esp_gpio_interrupts.c b/core/esp_gpio_interrupts.c index 99c7640..ef0a47d 100644 --- a/core/esp_gpio_interrupts.c +++ b/core/esp_gpio_interrupts.c @@ -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](); } } diff --git a/core/esp_timer.c b/core/esp_timer.c index b00e086..bb23f51 100644 --- a/core/esp_timer.c +++ b/core/esp_timer.c @@ -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); } diff --git a/core/include/common_macros.h b/core/include/common_macros.h index 3afd593..2b4d73b 100644 --- a/core/include/common_macros.h +++ b/core/include/common_macros.h @@ -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) diff --git a/core/include/esp/dport_regs.h b/core/include/esp/dport_regs.h new file mode 100644 index 0000000..44a3b5b --- /dev/null +++ b/core/include/esp/dport_regs.h @@ -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 */ diff --git a/core/include/esp/gpio.h b/core/include/esp/gpio.h index 57d6d9a..1f1ce14 100644 --- a/core/include/esp/gpio.h +++ b/core/include/esp/gpio.h @@ -9,7 +9,7 @@ #ifndef _ESP_GPIO_H #define _ESP_GPIO_H #include -#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< -#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" diff --git a/core/include/esp/iomux_regs.h b/core/include/esp/iomux_regs.h new file mode 100644 index 0000000..d3b9653 --- /dev/null +++ b/core/include/esp/iomux_regs.h @@ -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 */ diff --git a/core/include/esp/registers.h b/core/include/esp/registers.h index 7468dfb..97e285b 100644 --- a/core/include/esp/registers.h +++ b/core/include/esp/registers.h @@ -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 diff --git a/core/include/esp/rtcmem_regs.h b/core/include/esp/rtcmem_regs.h new file mode 100644 index 0000000..8462b0e --- /dev/null +++ b/core/include/esp/rtcmem_regs.h @@ -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 */ diff --git a/core/include/esp/spi_regs.h b/core/include/esp/spi_regs.h new file mode 100644 index 0000000..7dcf4db --- /dev/null +++ b/core/include/esp/spi_regs.h @@ -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 */ diff --git a/core/include/esp/timer.h b/core/include/esp/timer.h index d1eea45..b83a0ee 100644 --- a/core/include/esp/timer.h +++ b/core/include/esp/timer.h @@ -11,12 +11,12 @@ #include #include -#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. diff --git a/core/include/esp/timer_private.h b/core/include/esp/timer_private.h index fad3283..530a396 100644 --- a/core/include/esp/timer_private.h +++ b/core/include/esp/timer_private.h @@ -10,6 +10,7 @@ #include #include #include +#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; diff --git a/core/include/esp/timer_regs.h b/core/include/esp/timer_regs.h new file mode 100644 index 0000000..f2aacfc --- /dev/null +++ b/core/include/esp/timer_regs.h @@ -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 */ diff --git a/core/include/esp/types.h b/core/include/esp/types.h new file mode 100644 index 0000000..3f0560a --- /dev/null +++ b/core/include/esp/types.h @@ -0,0 +1,8 @@ +#ifndef _ESP_TYPES_H +#define _ESP_TYPES_H + +#include + +typedef volatile uint32_t *esp_reg_t; + +#endif /* _ESP_TYPES_H */ diff --git a/core/include/esp/uart_regs.h b/core/include/esp/uart_regs.h new file mode 100644 index 0000000..fe8e03d --- /dev/null +++ b/core/include/esp/uart_regs.h @@ -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 */ diff --git a/core/include/esp/wdt_regs.h b/core/include/esp/wdt_regs.h new file mode 100644 index 0000000..a9ee063 --- /dev/null +++ b/core/include/esp/wdt_regs.h @@ -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 */ diff --git a/examples/Makefile b/examples/Makefile index 8f7edb6..0436a13 100644 --- a/examples/Makefile +++ b/examples/Makefile @@ -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: diff --git a/examples/blink/blink.c b/examples/blink/blink.c index be1c473..52d69a5 100644 --- a/examples/blink/blink.c +++ b/examples/blink/blink.c @@ -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); } } diff --git a/examples/blink_timers/blink_timers.c b/examples/blink_timers/blink_timers.c index c8baeb2..5b6b7a2 100644 --- a/examples/blink_timers/blink_timers.c +++ b/examples/blink_timers/blink_timers.c @@ -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); } diff --git a/examples/button/button.c b/examples/button/button.c index 042b838..bcca2b3 100644 --- a/examples/button/button.c +++ b/examples/button/button.c @@ -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 diff --git a/examples/experiments/timers/timers.c b/examples/experiments/timers/timers.c index efe5b2e..a840159 100644 --- a/examples/experiments/timers/timers.c +++ b/examples/experiments/timers/timers.c @@ -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< +#include + +#include #ifdef __cplusplus extern "C" { diff --git a/lwip/include/lwipopts.h b/lwip/include/lwipopts.h index d958ba6..8f46c7d 100644 --- a/lwip/include/lwipopts.h +++ b/lwip/include/lwipopts.h @@ -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. */ diff --git a/lwip/include/netbuf_helpers.h b/lwip/include/netbuf_helpers.h new file mode 100644 index 0000000..4f02ba5 --- /dev/null +++ b/lwip/include/netbuf_helpers.h @@ -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