Merge pull request #94 from foogod/gpio_pullup_changes

Separate pullup config out of `gpio_enable()`
This commit is contained in:
Angus Gratton 2016-02-24 09:17:39 +11:00
commit 2e8c370d2c
4 changed files with 101 additions and 40 deletions

View file

@ -8,32 +8,34 @@
void gpio_enable(const uint8_t gpio_num, const gpio_direction_t direction) void gpio_enable(const uint8_t gpio_num, const gpio_direction_t direction)
{ {
uint32_t iomux_flags;
switch (direction) { switch (direction) {
case GPIO_INPUT: case GPIO_INPUT:
iomux_flags = 0; GPIO.ENABLE_OUT_CLEAR = BIT(gpio_num);
iomux_set_gpio_function(gpio_num, false);
break; break;
case GPIO_OUTPUT: case GPIO_OUTPUT:
iomux_flags = IOMUX_PIN_OUTPUT_ENABLE; GPIO.CONF[gpio_num] &= ~GPIO_CONF_OPEN_DRAIN;
GPIO.ENABLE_OUT_SET = BIT(gpio_num);
iomux_set_gpio_function(gpio_num, true);
break; break;
case GPIO_OUT_OPEN_DRAIN: case GPIO_OUT_OPEN_DRAIN:
iomux_flags = IOMUX_PIN_OUTPUT_ENABLE;
break;
case GPIO_INPUT_PULLUP:
iomux_flags = IOMUX_PIN_PULLUP;
break;
default:
return; /* Invalid direction flag */
}
iomux_set_gpio_function(gpio_num, iomux_flags);
if(direction == GPIO_OUT_OPEN_DRAIN)
GPIO.CONF[gpio_num] |= GPIO_CONF_OPEN_DRAIN; GPIO.CONF[gpio_num] |= GPIO_CONF_OPEN_DRAIN;
else
GPIO.CONF[gpio_num] &= ~GPIO_CONF_OPEN_DRAIN;
if (iomux_flags & IOMUX_PIN_OUTPUT_ENABLE)
GPIO.ENABLE_OUT_SET = BIT(gpio_num); GPIO.ENABLE_OUT_SET = BIT(gpio_num);
else iomux_set_gpio_function(gpio_num, true);
GPIO.ENABLE_OUT_CLEAR = BIT(gpio_num); break;
}
}
void gpio_set_pullup(uint8_t gpio_num, bool enabled, bool enabled_during_sleep)
{
uint32_t flags = 0;
if (enabled) {
flags |= IOMUX_PIN_PULLUP;
}
if (enabled_during_sleep) {
flags |= IOMUX_PIN_PULLUP_SLEEP;
}
iomux_set_pullup_flags(gpio_to_iomux(gpio_num), flags);
} }

View file

@ -17,14 +17,24 @@ typedef enum {
GPIO_INPUT, GPIO_INPUT,
GPIO_OUTPUT, /* "Standard" push-pull output */ GPIO_OUTPUT, /* "Standard" push-pull output */
GPIO_OUT_OPEN_DRAIN, /* Open drain output */ GPIO_OUT_OPEN_DRAIN, /* Open drain output */
GPIO_INPUT_PULLUP,
} gpio_direction_t; } gpio_direction_t;
/* Enable GPIO on the specified pin, and set it to input/output/ with /* Enable GPIO on the specified pin, and set it to input or output mode
* pullup as needed
*/ */
void gpio_enable(const uint8_t gpio_num, const gpio_direction_t direction); void gpio_enable(const uint8_t gpio_num, const gpio_direction_t direction);
/* Enable/disable internal pullup resistor for a particular GPIO
*
* Note: According to Espressif, pullup resistor values are between 30K and
* 100K ohms (see http://bbs.espressif.com/viewtopic.php?t=1079#p4097)
* However, measured values suggest that the actual value is likely to be close
* to 47K in reality.
*
* NOTE: The enabled_during_sleep setting is currently untested (please send
* feedback if you give it a try)
*/
void gpio_set_pullup(uint8_t gpio_num, bool enabled, bool enabled_during_sleep);
/* Disable GPIO on the specified pin, and set it Hi-Z. /* Disable GPIO on the specified pin, and set it Hi-Z.
* *
* If later muxing this pin to a different function, make sure to set * If later muxing this pin to a different function, make sure to set
@ -36,9 +46,33 @@ static inline void gpio_disable(const uint8_t gpio_num)
*gpio_iomux_reg(gpio_num) &= ~IOMUX_PIN_OUTPUT_ENABLE; *gpio_iomux_reg(gpio_num) &= ~IOMUX_PIN_OUTPUT_ENABLE;
} }
/* Set whether the specified pin continues to drive its output when the ESP8266
* goes into sleep mode. Note that this setting is reset to off whenever
* gpio_enable is called, so this must be called after calling that function.
*
* NOTE: This functionality is currently untested (please send feedback if you
* give it a try)
*/
static inline void gpio_set_output_on_sleep(const uint8_t gpio_num, bool enabled)
{
if (enabled) {
IOMUX.PIN[gpio_to_iomux(gpio_num)] |= IOMUX_PIN_OUTPUT_ENABLE_SLEEP;
} else {
IOMUX.PIN[gpio_to_iomux(gpio_num)] &= ~IOMUX_PIN_OUTPUT_ENABLE_SLEEP;
}
}
/* Set output of a pin high or low. /* Set output of a pin high or low.
* *
* Only works if pin has been set to GPIO_OUTPUT via gpio_enable() * Only works if pin has been set to GPIO_OUTPUT or GPIO_OUT_OPEN_DRAIN via
* gpio_enable()
*
* If the mode is GPIO_OUT_OPEN_DRAIN, setting it low (false) will pull the pin
* down to ground, but setting it high (true) will allow it to float. Note
* that even in GPIO_OUT_OPEN_DRAIN mode, the input gates are still physically
* connected to the pin, and can be damaged if the voltage is not in either the
* "low" or "high" range. Make sure there is some sort of pull-up resistor on
* the line to avoid floating logic lines!
*/ */
static inline void gpio_write(const uint8_t gpio_num, const bool set) static inline void gpio_write(const uint8_t gpio_num, const bool set)
{ {
@ -50,7 +84,10 @@ static inline void gpio_write(const uint8_t gpio_num, const bool set)
/* Toggle output of a pin /* Toggle output of a pin
* *
* Only works if pin has been set to GPIO_OUTPUT via gpio_enable() * Only works if pin has been set to GPIO_OUTPUT or GPIO_OUT_OPEN_DRAIN via
* gpio_enable()
*
* See notes in gpio_write() about GPIO_OUT_OPEN_DRAIN mode.
*/ */
static inline void gpio_toggle(const uint8_t gpio_num) static inline void gpio_toggle(const uint8_t gpio_num)
{ {
@ -68,8 +105,12 @@ static inline void gpio_toggle(const uint8_t gpio_num)
/* Read input value of a GPIO pin. /* Read input value of a GPIO pin.
* *
* If pin is set as an input, this reads the value on the pin. * If pin is set GPIO_INPUT, this reads the level on the pin.
* If pin is set as an output, this reads the last value written to the pin. * If pin is set GPIO_OUTPUT, this reads the level at which the pin is
* currently being driven (i.e. the last value written).
* If pin is set GPIO_OUT_OPEN_DRAIN, when the pin is written low, this will
* return low (false), when the pin is written high, this will behave like
* GPIO_INPUT.
*/ */
static inline bool gpio_read(const uint8_t gpio_num) static inline bool gpio_read(const uint8_t gpio_num)
{ {
@ -80,7 +121,8 @@ extern void gpio_interrupt_handler(void);
/* Set the interrupt type for a given pin /* Set the interrupt type for a given pin
* *
* If int_type is not GPIO_INTTYPE_NONE, the gpio_interrupt_handler will be attached and unmasked. * If int_type is not GPIO_INTTYPE_NONE, the gpio_interrupt_handler will be
* attached and unmasked.
*/ */
static inline void gpio_set_interrupt(const uint8_t gpio_num, const gpio_inttype_t int_type) static inline void gpio_set_interrupt(const uint8_t gpio_num, const gpio_inttype_t int_type)
{ {

View file

@ -43,25 +43,41 @@ inline static esp_reg_t gpio_iomux_reg(const uint8_t gpio_number)
return &(IOMUX.PIN[gpio_to_iomux(gpio_number)]); return &(IOMUX.PIN[gpio_to_iomux(gpio_number)]);
} }
inline static void iomux_set_function(uint8_t iomux_num, uint32_t func)
{
uint32_t prev = IOMUX.PIN[iomux_num] & ~IOMUX_PIN_FUNC_MASK;
IOMUX.PIN[iomux_num] = IOMUX_FUNC(func) | prev;
}
inline static void iomux_set_direction_flags(uint8_t iomux_num, uint32_t dir_flags)
{
uint32_t mask = IOMUX_PIN_OUTPUT_ENABLE | IOMUX_PIN_OUTPUT_ENABLE_SLEEP;
uint32_t prev = IOMUX.PIN[iomux_num] & ~mask;
IOMUX.PIN[iomux_num] = dir_flags | prev;
}
inline static void iomux_set_pullup_flags(uint8_t iomux_num, uint32_t pullup_flags)
{
uint32_t mask = IOMUX_PIN_PULLUP | IOMUX_PIN_PULLDOWN | IOMUX_PIN_PULLUP_SLEEP | IOMUX_PIN_PULLDOWN_SLEEP;
uint32_t prev = IOMUX.PIN[iomux_num] & ~mask;
IOMUX.PIN[iomux_num] = pullup_flags | prev;
}
/** /**
* Set a pin to the GPIO function. * Set a pin to the GPIO function.
* *
* This allows you to set pins to GPIO without knowing in advance the * This allows you to set pins to GPIO without knowing in advance the
* exact register masks to use. * exact register masks to use.
* *
* flags can be any of IOMUX_PIN_OUTPUT_ENABLE, IOMUX_PIN_PULLUP, IOMUX_PIN_PULLDOWN, etc. Any other flags will be cleared. * Sets the function and direction, but leaves the pullup configuration the
* * same as before.
* Equivalent to a direct register operation if gpio_number is known at compile time.
* ie the following are equivalent:
*
* iomux_set_gpio_function(12, IOMUX_PIN_OUTPUT_ENABLE);
* IOMUX_GPIO12 = IOMUX_GPIO12_FUNC_GPIO | IOMUX_PIN_OUTPUT_ENABLE;
*/ */
inline static void iomux_set_gpio_function(const uint8_t gpio_number, const uint32_t flags) inline static void iomux_set_gpio_function(uint8_t gpio_number, bool output_enable)
{ {
const uint8_t reg_idx = gpio_to_iomux(gpio_number); const uint8_t iomux_num = gpio_to_iomux(gpio_number);
const uint32_t func = (reg_idx > 11 ? IOMUX_FUNC(0) : IOMUX_FUNC(3)) | flags; const uint32_t func = iomux_num > 11 ? 0 : 3;
IOMUX.PIN[reg_idx] = func | flags; iomux_set_function(iomux_num, func);
iomux_set_direction_flags(iomux_num, output_enable ? IOMUX_PIN_OUTPUT_ENABLE : 0);
} }
#ifdef __cplusplus #ifdef __cplusplus

View file

@ -2,6 +2,7 @@
#define _ESP_TYPES_H #define _ESP_TYPES_H
#include <stdint.h> #include <stdint.h>
#include <stdbool.h>
typedef volatile uint32_t *esp_reg_t; typedef volatile uint32_t *esp_reg_t;