From 2ffd3da71edf7561ce62d29bf69e78db16902f7b Mon Sep 17 00:00:00 2001 From: Alex Stewart Date: Tue, 18 Aug 2015 17:38:31 -0700 Subject: [PATCH 01/10] Add esp/iomux_regs.h --- core/include/common_macros.h | 9 ++ core/include/esp/gpio.h | 10 +-- core/include/esp/iomux.h | 150 ++----------------------------- core/include/esp/iomux_regs.h | 160 ++++++++++++++++++++++++++++++++++ core/include/esp/registers.h | 34 +------- core/include/esp/types.h | 8 ++ examples/blink/blink.c | 6 +- 7 files changed, 197 insertions(+), 180 deletions(-) create mode 100644 core/include/esp/iomux_regs.h create mode 100644 core/include/esp/types.h diff --git a/core/include/common_macros.h b/core/include/common_macros.h index fa13ff9..1ed2e22 100644 --- a/core/include/common_macros.h +++ b/core/include/common_macros.h @@ -16,6 +16,15 @@ #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 SETFIELD(regbits, fieldname, value) (((regbits) & ~(fieldname##_M << fieldname##_S)) | 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/gpio.h b/core/include/esp/gpio.h index 57d6d9a..c4bca56 100644 --- a/core/include/esp/gpio.h +++ b/core/include/esp/gpio.h @@ -35,15 +35,15 @@ INLINED void gpio_enable(const uint8_t gpio_num, const gpio_direction_t directio ctrl_val = GPIO_SOURCE_GPIO; break; case GPIO_OUTPUT: - iomux_flags = IOMUX_OE; + iomux_flags = IOMUX_PIN_OUTPUT_ENABLE; ctrl_val = GPIO_DRIVE_PUSH_PULL|GPIO_SOURCE_GPIO; break; case GPIO_OUT_OPEN_DRAIN: - iomux_flags = IOMUX_OE; + iomux_flags = IOMUX_PIN_OUTPUT_ENABLE; ctrl_val = GPIO_DRIVE_OPEN_DRAIN|GPIO_SOURCE_GPIO; break; case GPIO_INPUT_PULLUP: - iomux_flags = IOMUX_PU; + iomux_flags = IOMUX_PIN_PULLUP; ctrl_val = GPIO_SOURCE_GPIO; } iomux_set_gpio_function(gpio_num, iomux_flags); @@ -57,12 +57,12 @@ INLINED void gpio_enable(const uint8_t gpio_num, const gpio_direction_t directio /* 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_iomux_reg(gpio_num) &= ~IOMUX_PIN_OUTPUT_ENABLE; } /* Set output of a pin high or low. diff --git a/core/include/esp/iomux.h b/core/include/esp/iomux.h index fd5a51d..f4096ed 100644 --- a/core/include/esp/iomux.h +++ b/core/include/esp/iomux.h @@ -8,8 +8,8 @@ */ #ifndef _ESP_IOMUX_H #define _ESP_IOMUX_H -#include -#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; + 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..0e67a9c --- /dev/null +++ b/core/include/esp/iomux_regs.h @@ -0,0 +1,160 @@ +/* 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 )); + +/* Double-check the structure size to make sure the compiler hasn't done + * something strange (or somebody typoed in the struct definition, etc) + */ +_Static_assert(sizeof(struct IOMUX_REGS) == 0x44, "IOMUX_REGS is the wrong size"); + +/* Bit mapping for CONF register */ + +#define IOMUX_CONF_SPI0_CLOCK_EQU_SYS_CLOCK BIT(8) +#define IOMUX_CONF_SPI1_CLOCK_EQU_SYS_CLOCK BIT(9) + +/* Bit mapping 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_FUNC_A IOMUX_FUNC(0) +#define IOMUX_FUNC_B IOMUX_FUNC(1) +#define IOMUX_FUNC_C IOMUX_FUNC(2) +#define IOMUX_FUNC_D IOMUX_FUNC(3) +#define IOMUX_FUNC_E IOMUX_FUNC(4) + +#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..ae8f169 100644 --- a/core/include/esp/registers.h +++ b/core/include/esp/registers.h @@ -14,8 +14,9 @@ #ifndef _ESP_REGISTERS #define _ESP_REGISTERS #include "common_macros.h" +#include "esp/types.h" -typedef volatile uint32_t *esp_reg_t; +#include "esp/iomux_regs.h" /* Internal macro, only defined in header body */ #define _REG(BASE, OFFSET) (*(esp_reg_t)((BASE)+(OFFSET))) @@ -33,7 +34,7 @@ typedef volatile uint32_t *esp_reg_t; #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 IOMUX_BASE (MMIO_BASE + 0x0800) #define WDT_BASE (MMIO_BASE + 0x0900) #define I2C_BASE (MMIO_BASE + 0x0d00) #define UART1_BASE (MMIO_BASE + 0x0F00) @@ -41,35 +42,6 @@ typedef volatile uint32_t *esp_reg_t; #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 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/examples/blink/blink.c b/examples/blink/blink.c index be1c473..8f1b4bf 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 @@ -42,7 +42,7 @@ 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' */ + IOMUX_GPIO14 = IOMUX_GPIO14_FUNC_GPIO | IOMUX_PIN_OUTPUT_ENABLE; /* change this line if you change 'gpio' */ while(1) { GPIO_OUT_SET = BIT(gpio); vTaskDelay(1000 / portTICK_RATE_MS); From fc1a1a7d0a80b4aecf78a6cd8c4ffc3254b2e766 Mon Sep 17 00:00:00 2001 From: Alex Stewart Date: Tue, 18 Aug 2015 22:46:25 -0700 Subject: [PATCH 02/10] Add esp/gpio_regs.h --- core/esp_gpio_interrupts.c | 8 +-- core/include/common_macros.h | 3 +- core/include/esp/gpio.h | 55 ++++++--------- core/include/esp/gpio_regs.h | 133 +++++++++++++++++++++++++++++++++++ core/include/esp/registers.h | 76 +------------------- examples/blink/blink.c | 6 +- 6 files changed, 167 insertions(+), 114 deletions(-) create mode 100644 core/include/esp/gpio_regs.h 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/include/common_macros.h b/core/include/common_macros.h index 1ed2e22..669203a 100644 --- a/core/include/common_macros.h +++ b/core/include/common_macros.h @@ -23,7 +23,8 @@ #define VAL2FIELD(fieldname, value) (((value) & fieldname##_M) << fieldname##_S) #define FIELD2VAL(fieldname, regbits) (((regbits) >> fieldname##_S) & fieldname##_M) -#define SETFIELD(regbits, fieldname, value) (((regbits) & ~(fieldname##_M << fieldname##_S)) | VAL2FIELD(fieldname, value)) +#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/gpio.h b/core/include/esp/gpio.h index c4bca56..ab4b241 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,26 +32,27 @@ 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_PIN_OUTPUT_ENABLE; - ctrl_val = GPIO_DRIVE_PUSH_PULL|GPIO_SOURCE_GPIO; + ctrl_val = GPIO_CONF_DRIVER_ENABLE; break; case GPIO_OUT_OPEN_DRAIN: iomux_flags = IOMUX_PIN_OUTPUT_ENABLE; - ctrl_val = GPIO_DRIVE_OPEN_DRAIN|GPIO_SOURCE_GPIO; + ctrl_val = 0; break; case GPIO_INPUT_PULLUP: iomux_flags = IOMUX_PIN_PULLUP; - ctrl_val = GPIO_SOURCE_GPIO; + 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. @@ -61,7 +62,7 @@ INLINED void gpio_enable(const uint8_t gpio_num, const gpio_direction_t directio */ INLINED void gpio_disable(const uint8_t gpio_num) { - GPIO_DIR_CLEAR = BIT(gpio_num); + GPIO.ENABLE_OUT_CLEAR = BIT(gpio_num); *gpio_iomux_reg(gpio_num) &= ~IOMUX_PIN_OUTPUT_ENABLE; } @@ -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 "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 )); + +/* Double-check the structure size to make sure the compiler hasn't done + * something strange (or somebody typoed in the struct definition, etc) + */ +_Static_assert(sizeof(struct GPIO_REGS) == 0x74, "GPIO_REGS is the wrong size"); + +/* Bit mapping 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_DRIVER_ENABLE (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_DRIVER_ENABLE 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; + +/* Bit mapping 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 + +/* Bit mapping 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 + +/* Bit mapping 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 */ diff --git a/core/include/esp/registers.h b/core/include/esp/registers.h index ae8f169..5b8a785 100644 --- a/core/include/esp/registers.h +++ b/core/include/esp/registers.h @@ -17,6 +17,7 @@ #include "esp/types.h" #include "esp/iomux_regs.h" +#include "esp/gpio_regs.h" /* Internal macro, only defined in header body */ #define _REG(BASE, OFFSET) (*(esp_reg_t)((BASE)+(OFFSET))) @@ -31,7 +32,7 @@ #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 GPIO0_BASE (MMIO_BASE + 0x0300) #define TIMER_BASE (MMIO_BASE + 0x0600) #define RTC_BASE (MMIO_BASE + 0x0700) //#define IOMUX_BASE (MMIO_BASE + 0x0800) @@ -42,79 +43,6 @@ #define RTCS_BASE (MMIO_BASE + 0x1100) #define RTCU_BASE (MMIO_BASE + 0x1200) - -/* - * 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. diff --git a/examples/blink/blink.c b/examples/blink/blink.c index 8f1b4bf..52d69a5 100644 --- a/examples/blink/blink.c +++ b/examples/blink/blink.c @@ -41,12 +41,12 @@ void blinkenTask(void *pvParameters) */ void blinkenRegisterTask(void *pvParameters) { - GPIO_DIR_SET = BIT(gpio); + GPIO.ENABLE_OUT_SET = BIT(gpio); IOMUX_GPIO14 = IOMUX_GPIO14_FUNC_GPIO | IOMUX_PIN_OUTPUT_ENABLE; /* change this line if you change 'gpio' */ 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); } } From b84a69168f5d3a57bed9527bccd81e0a9ac01058 Mon Sep 17 00:00:00 2001 From: Alex Stewart Date: Wed, 19 Aug 2015 09:03:18 -0700 Subject: [PATCH 03/10] Fix cut-paste error in gpio_regs.h comment --- core/include/esp/gpio_regs.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/include/esp/gpio_regs.h b/core/include/esp/gpio_regs.h index cbda14b..7cfcbd1 100644 --- a/core/include/esp/gpio_regs.h +++ b/core/include/esp/gpio_regs.h @@ -1,4 +1,4 @@ -/* esp/iomux_regs.h +/* esp/gpio_regs.h * * ESP8266 GPIO register definitions * From b271e19b51a21aea45fcb1bff04875574ac66587 Mon Sep 17 00:00:00 2001 From: Alex Stewart Date: Wed, 19 Aug 2015 09:05:03 -0700 Subject: [PATCH 04/10] Replace stdint.h with esp/types.h in gpio_regs.h --- core/include/esp/gpio_regs.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/include/esp/gpio_regs.h b/core/include/esp/gpio_regs.h index 7cfcbd1..e775cec 100644 --- a/core/include/esp/gpio_regs.h +++ b/core/include/esp/gpio_regs.h @@ -8,7 +8,7 @@ #ifndef _ESP_GPIO_REGS_H #define _ESP_GPIO_REGS_H -#include +#include "esp/types.h" #include "common_macros.h" #define GPIO_BASE 0x60000300 From 4fa66ca391f9eb43ef8da3febf62b6a9db0c9004 Mon Sep 17 00:00:00 2001 From: Alex Stewart Date: Wed, 19 Aug 2015 11:34:18 -0700 Subject: [PATCH 05/10] Added esp/timer_regs.h and esp/dport_regs.h --- core/esp_timer.c | 4 +- core/include/esp/dport_regs.h | 53 ++++++++++ core/include/esp/registers.h | 160 +------------------------------ core/include/esp/timer.h | 22 ++--- core/include/esp/timer_private.h | 97 ++++++++----------- core/include/esp/timer_regs.h | 125 ++++++++++++++++++++++++ 6 files changed, 234 insertions(+), 227 deletions(-) create mode 100644 core/include/esp/dport_regs.h create mode 100644 core/include/esp/timer_regs.h 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/esp/dport_regs.h b/core/include/esp/dport_regs.h new file mode 100644 index 0000000..f80a01e --- /dev/null +++ b/core/include/esp/dport_regs.h @@ -0,0 +1,53 @@ +/* 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 _unknown0; // 0x00 + uint32_t volatile INT_ENABLE; // 0x04 +} __attribute__ (( packed )); + +_Static_assert(sizeof(struct DPORT_REGS) == 0x08, "DPORT_REGS is the wrong size"); + +/* Details for INT_ENABLE register */ + +/* 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_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_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 + +#endif /* _ESP_DPORT_REGS_H */ diff --git a/core/include/esp/registers.h b/core/include/esp/registers.h index 5b8a785..98c73c0 100644 --- a/core/include/esp/registers.h +++ b/core/include/esp/registers.h @@ -18,6 +18,8 @@ #include "esp/iomux_regs.h" #include "esp/gpio_regs.h" +#include "esp/timer_regs.h" +#include "esp/dport_regs.h" /* Internal macro, only defined in header body */ #define _REG(BASE, OFFSET) (*(esp_reg_t)((BASE)+(OFFSET))) @@ -27,13 +29,13 @@ You shouldn't need to use these directly. */ #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 TIMER_BASE (MMIO_BASE + 0x0600) #define RTC_BASE (MMIO_BASE + 0x0700) //#define IOMUX_BASE (MMIO_BASE + 0x0800) #define WDT_BASE (MMIO_BASE + 0x0900) @@ -43,135 +45,6 @@ #define RTCS_BASE (MMIO_BASE + 0x1100) #define RTCU_BASE (MMIO_BASE + 0x1200) -/* 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. @@ -180,29 +53,4 @@ */ #define WDT_CTRL _REG(WDT_BASE, 0x00) -/* DPORT registers - - Control various aspects of core/peripheral interaction... Not well - documented or understood. -*/ - -/* Set flags to enable CPU interrupts from some peripherals. Read/write. - - bit 0 - Is set by RTOS SDK startup code but function is unknown. - bit 1 - INT_ENABLE_FRC1 allows TIMER FRC1 to trigger interrupt INUM_TIMER_FRC1. - bit 2 - INT_ENABLE_FRC2 allows TIMER FRC2 to trigger interrupt INUM_TIMER_FRC2. - - Espressif calls this register "EDGE_INT_ENABLE_REG". The "edge" in - question is (I think) the interrupt line from the peripheral, as - the interrupt status bit is set. There may be a similar register - for enabling "level" interrupts instead of edge triggering - - this is unknown. -*/ -#define DP_INT_ENABLE_REG _REG(DPORT_BASE, 0x04) - -/* Set to enable interrupts from TIMER FRC1 */ -#define INT_ENABLE_FRC1 BIT(1) -/* Set to enable interrupts interrupts from TIMER FRC2 */ -#define INT_ENABLE_FRC2 BIT(2) - #endif 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 */ From 177ad281aa21905e5ccb63fccab6df206d40222c Mon Sep 17 00:00:00 2001 From: Alex Stewart Date: Wed, 19 Aug 2015 16:48:11 -0700 Subject: [PATCH 06/10] Add esp/wdt_regs.h --- core/include/esp/registers.h | 14 ++----------- core/include/esp/wdt_regs.h | 38 ++++++++++++++++++++++++++++++++++++ 2 files changed, 40 insertions(+), 12 deletions(-) create mode 100644 core/include/esp/wdt_regs.h diff --git a/core/include/esp/registers.h b/core/include/esp/registers.h index 98c73c0..0fcd30c 100644 --- a/core/include/esp/registers.h +++ b/core/include/esp/registers.h @@ -19,11 +19,9 @@ #include "esp/iomux_regs.h" #include "esp/gpio_regs.h" #include "esp/timer_regs.h" +#include "esp/wdt_regs.h" #include "esp/dport_regs.h" -/* Internal macro, only defined in header body */ -#define _REG(BASE, OFFSET) (*(esp_reg_t)((BASE)+(OFFSET))) - /* Register base addresses You shouldn't need to use these directly. @@ -38,19 +36,11 @@ //#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 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) -/* 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) - #endif 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 */ From d2231b7ff519cc52c5009a082c439630b448d81a Mon Sep 17 00:00:00 2001 From: Alex Stewart Date: Wed, 19 Aug 2015 16:50:56 -0700 Subject: [PATCH 07/10] Cleanup a few comments in *_regs.h files --- core/include/esp/gpio_regs.h | 11 ++++------- core/include/esp/iomux_regs.h | 13 ++----------- 2 files changed, 6 insertions(+), 18 deletions(-) diff --git a/core/include/esp/gpio_regs.h b/core/include/esp/gpio_regs.h index e775cec..d2b0770 100644 --- a/core/include/esp/gpio_regs.h +++ b/core/include/esp/gpio_regs.h @@ -59,12 +59,9 @@ struct GPIO_REGS { uint32_t volatile RTC_CALIB_RESULT; // 0x70 } __attribute__ (( packed )); -/* Double-check the structure size to make sure the compiler hasn't done - * something strange (or somebody typoed in the struct definition, etc) - */ _Static_assert(sizeof(struct GPIO_REGS) == 0x74, "GPIO_REGS is the wrong size"); -/* Bit mapping for CONF[i] registers */ +/* Details for CONF[i] registers */ /* GPIO.CONF[i] control the pin behavior for the corresponding GPIO in/output. * @@ -109,7 +106,7 @@ typedef enum { GPIO_INTTYPE_LEVEL_HIGH = 5, } gpio_inttype_t; -/* Bit mapping for PWM register */ +/* Details for PWM register */ #define GPIO_PWM_ENABLE BIT(16) #define GPIO_PWM_PRESCALER_M 0x000000ff @@ -117,13 +114,13 @@ typedef enum { #define GPIO_PWM_TARGET_M 0x000000ff #define GPIO_PWM_TARGET_S 0 -/* Bit mapping for RTC_CALIB register */ +/* 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 -/* Bit mapping for RTC_CALIB_RESULT register */ +/* Details for RTC_CALIB_RESULT register */ #define GPIO_RTC_CALIB_RESULT_READY BIT(31) #define GPIO_RTC_CALIB_RESULT_READY_REAL BIT(30) diff --git a/core/include/esp/iomux_regs.h b/core/include/esp/iomux_regs.h index 0e67a9c..d3b9653 100644 --- a/core/include/esp/iomux_regs.h +++ b/core/include/esp/iomux_regs.h @@ -22,17 +22,14 @@ struct IOMUX_REGS { uint32_t volatile PIN[16]; // 0x04 - 0x40 } __attribute__ (( packed )); -/* Double-check the structure size to make sure the compiler hasn't done - * something strange (or somebody typoed in the struct definition, etc) - */ _Static_assert(sizeof(struct IOMUX_REGS) == 0x44, "IOMUX_REGS is the wrong size"); -/* Bit mapping for CONF register */ +/* Details for CONF register */ #define IOMUX_CONF_SPI0_CLOCK_EQU_SYS_CLOCK BIT(8) #define IOMUX_CONF_SPI1_CLOCK_EQU_SYS_CLOCK BIT(9) -/* Bit mapping for PIN registers */ +/* Details for PIN registers */ #define IOMUX_PIN_OUTPUT_ENABLE BIT(0) #define IOMUX_PIN_OUTPUT_ENABLE_SLEEP BIT(1) @@ -55,12 +52,6 @@ _Static_assert(sizeof(struct IOMUX_REGS) == 0x44, "IOMUX_REGS is the wrong size" #define IOMUX_SET_FUNC(regbits, funcval) (((regbits) & ~IOMUX_PIN_FUNC_MASK) | (funcval)) -#define IOMUX_FUNC_A IOMUX_FUNC(0) -#define IOMUX_FUNC_B IOMUX_FUNC(1) -#define IOMUX_FUNC_C IOMUX_FUNC(2) -#define IOMUX_FUNC_D IOMUX_FUNC(3) -#define IOMUX_FUNC_E IOMUX_FUNC(4) - #define IOMUX_GPIO0 IOMUX.PIN[12] #define IOMUX_GPIO1 IOMUX.PIN[5] #define IOMUX_GPIO2 IOMUX.PIN[13] From 8263fce80f2167d6849fc9a3389775efebc1b2c3 Mon Sep 17 00:00:00 2001 From: Alex Stewart Date: Wed, 19 Aug 2015 16:53:02 -0700 Subject: [PATCH 08/10] Fix leftover IOMUX_FUNC_A/D references --- core/include/esp/iomux.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/include/esp/iomux.h b/core/include/esp/iomux.h index f4096ed..f6715f4 100644 --- a/core/include/esp/iomux.h +++ b/core/include/esp/iomux.h @@ -56,7 +56,7 @@ inline static esp_reg_t gpio_iomux_reg(const uint8_t gpio_number) 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 uint32_t func = (reg_idx > 11 ? IOMUX_FUNC_A : IOMUX_FUNC_D) | flags; + const uint32_t func = (reg_idx > 11 ? IOMUX_FUNC(0) : IOMUX_FUNC(3)) | flags; IOMUX.PIN[reg_idx] = func | flags; } From ab6f4b842065d37553f37f22a2e2467dd3d6e946 Mon Sep 17 00:00:00 2001 From: Alex Stewart Date: Thu, 20 Aug 2015 15:11:29 -0700 Subject: [PATCH 09/10] Fixup some constants used in examples --- examples/blink_timers/blink_timers.c | 22 +++++++-------- examples/button/button.c | 2 +- examples/experiments/timers/timers.c | 41 ++++++++++++++-------------- 3 files changed, 33 insertions(+), 32 deletions(-) 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< Date: Fri, 21 Aug 2015 09:54:20 -0700 Subject: [PATCH 10/10] rename GPIO_CONF_DRIVER_ENABLE back to GPIO_CONF_PUSH_PULL --- core/include/esp/gpio.h | 2 +- core/include/esp/gpio_regs.h | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/core/include/esp/gpio.h b/core/include/esp/gpio.h index ab4b241..1f1ce14 100644 --- a/core/include/esp/gpio.h +++ b/core/include/esp/gpio.h @@ -36,7 +36,7 @@ INLINED void gpio_enable(const uint8_t gpio_num, const gpio_direction_t directio break; case GPIO_OUTPUT: iomux_flags = IOMUX_PIN_OUTPUT_ENABLE; - ctrl_val = GPIO_CONF_DRIVER_ENABLE; + ctrl_val = GPIO_CONF_PUSH_PULL; break; case GPIO_OUT_OPEN_DRAIN: iomux_flags = IOMUX_PIN_OUTPUT_ENABLE; diff --git a/core/include/esp/gpio_regs.h b/core/include/esp/gpio_regs.h index d2b0770..21e2c29 100644 --- a/core/include/esp/gpio_regs.h +++ b/core/include/esp/gpio_regs.h @@ -76,7 +76,7 @@ _Static_assert(sizeof(struct GPIO_REGS) == 0x74, "GPIO_REGS is the wrong size"); * Under what conditions this GPIO input should generate an interrupt. * (see gpio_inttype_t enum below for values) * - * GPIO_CONF_DRIVER_ENABLE (boolean) + * 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"). @@ -91,9 +91,9 @@ _Static_assert(sizeof(struct GPIO_REGS) == 0x74, "GPIO_REGS is the wrong size"); #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_DRIVER_ENABLE BIT(2) +#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 */