2015-06-05 01:46:25 +00:00
|
|
|
/** esp_iomux.h
|
|
|
|
*
|
|
|
|
* GPIO functions.
|
|
|
|
*
|
|
|
|
* Part of esp-open-rtos
|
|
|
|
* Copyright (C) 2015 Superhouse Automation Pty Ltd
|
|
|
|
* BSD Licensed as described in the file LICENSE
|
|
|
|
*/
|
|
|
|
#ifndef _ESP_GPIO_H
|
2015-06-17 23:00:02 +00:00
|
|
|
#define _ESP_GPIO_H
|
2015-06-05 01:46:25 +00:00
|
|
|
#include <stdbool.h>
|
|
|
|
#include "esp/registers.h"
|
|
|
|
#include "esp/iomux.h"
|
2015-06-08 08:09:06 +00:00
|
|
|
#include "esp/cpu.h"
|
|
|
|
#include "xtensa_interrupts.h"
|
2015-06-05 01:46:25 +00:00
|
|
|
|
|
|
|
typedef enum {
|
2015-06-08 08:09:06 +00:00
|
|
|
GPIO_INPUT,
|
|
|
|
GPIO_OUTPUT, /* "Standard" push-pull output */
|
|
|
|
GPIO_OUT_OPEN_DRAIN, /* Open drain output */
|
|
|
|
GPIO_INPUT_PULLUP,
|
2015-06-05 01:46:25 +00:00
|
|
|
} gpio_direction_t;
|
|
|
|
|
|
|
|
/* Enable GPIO on the specified pin, and set it to input/output/ with
|
|
|
|
* pullup as needed
|
|
|
|
*/
|
|
|
|
INLINED void gpio_enable(const uint8_t gpio_num, const gpio_direction_t direction)
|
|
|
|
{
|
2015-06-08 08:09:06 +00:00
|
|
|
uint32_t iomux_flags;
|
|
|
|
uint32_t ctrl_val;
|
|
|
|
|
|
|
|
switch(direction) {
|
|
|
|
case GPIO_INPUT:
|
2015-06-08 23:00:32 +00:00
|
|
|
iomux_flags = 0;
|
|
|
|
ctrl_val = GPIO_SOURCE_GPIO;
|
|
|
|
break;
|
2015-06-08 08:09:06 +00:00
|
|
|
case GPIO_OUTPUT:
|
2015-08-19 00:38:31 +00:00
|
|
|
iomux_flags = IOMUX_PIN_OUTPUT_ENABLE;
|
2015-06-08 23:00:32 +00:00
|
|
|
ctrl_val = GPIO_DRIVE_PUSH_PULL|GPIO_SOURCE_GPIO;
|
|
|
|
break;
|
2015-06-08 08:09:06 +00:00
|
|
|
case GPIO_OUT_OPEN_DRAIN:
|
2015-08-19 00:38:31 +00:00
|
|
|
iomux_flags = IOMUX_PIN_OUTPUT_ENABLE;
|
2015-06-08 23:00:32 +00:00
|
|
|
ctrl_val = GPIO_DRIVE_OPEN_DRAIN|GPIO_SOURCE_GPIO;
|
|
|
|
break;
|
2015-06-08 08:09:06 +00:00
|
|
|
case GPIO_INPUT_PULLUP:
|
2015-08-19 00:38:31 +00:00
|
|
|
iomux_flags = IOMUX_PIN_PULLUP;
|
2015-06-08 23:00:32 +00:00
|
|
|
ctrl_val = GPIO_SOURCE_GPIO;
|
2015-06-08 08:09:06 +00:00
|
|
|
}
|
|
|
|
iomux_set_gpio_function(gpio_num, iomux_flags);
|
|
|
|
GPIO_CTRL_REG(gpio_num) = (GPIO_CTRL_REG(gpio_num)&GPIO_INT_MASK) | ctrl_val;
|
2015-06-05 01:46:25 +00:00
|
|
|
if(direction == GPIO_OUTPUT)
|
2015-06-08 23:00:32 +00:00
|
|
|
GPIO_DIR_SET = BIT(gpio_num);
|
2015-06-05 01:46:25 +00:00
|
|
|
else
|
2015-06-08 23:00:32 +00:00
|
|
|
GPIO_DIR_CLEAR = BIT(gpio_num);
|
2015-06-05 01:46:25 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/* Disable GPIO on the specified pin, and set it Hi-Z.
|
|
|
|
*
|
|
|
|
* If later muxing this pin to a different function, make sure to set
|
2015-08-19 00:38:31 +00:00
|
|
|
* IOMUX_PIN_OUTPUT_ENABLE if necessary to enable the output buffer.
|
2015-06-05 01:46:25 +00:00
|
|
|
*/
|
|
|
|
INLINED void gpio_disable(const uint8_t gpio_num)
|
|
|
|
{
|
|
|
|
GPIO_DIR_CLEAR = BIT(gpio_num);
|
2015-08-19 00:38:31 +00:00
|
|
|
*gpio_iomux_reg(gpio_num) &= ~IOMUX_PIN_OUTPUT_ENABLE;
|
2015-06-05 01:46:25 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/* Set output of a pin high or low.
|
|
|
|
*
|
|
|
|
* Only works if pin has been set to GPIO_OUTPUT via gpio_enable()
|
|
|
|
*/
|
2015-07-29 00:34:28 +00:00
|
|
|
INLINED void gpio_write(const uint8_t gpio_num, const bool set)
|
2015-06-05 01:46:25 +00:00
|
|
|
{
|
|
|
|
if(set)
|
2015-06-08 23:00:32 +00:00
|
|
|
GPIO_OUT_SET = BIT(gpio_num);
|
2015-06-05 01:46:25 +00:00
|
|
|
else
|
2015-06-08 23:00:32 +00:00
|
|
|
GPIO_OUT_CLEAR = BIT(gpio_num);
|
2015-06-05 01:46:25 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/* Toggle output of a pin
|
|
|
|
*
|
|
|
|
* Only works if pin has been set to GPIO_OUTPUT via gpio_enable()
|
|
|
|
*/
|
|
|
|
INLINED void gpio_toggle(const uint8_t gpio_num)
|
|
|
|
{
|
|
|
|
/* Why implement like this instead of GPIO_OUT_REG ^= xxx?
|
|
|
|
Concurrency. If an interrupt or higher priority task writes to
|
|
|
|
GPIO_OUT between reading and writing, only the gpio_num pin can
|
|
|
|
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))
|
2015-06-08 23:00:32 +00:00
|
|
|
GPIO_OUT_CLEAR = BIT(gpio_num);
|
2015-06-05 01:46:25 +00:00
|
|
|
else
|
2015-06-08 23:00:32 +00:00
|
|
|
GPIO_OUT_SET = BIT(gpio_num);
|
2015-06-05 01:46:25 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/* 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 as an output, this reads the last value written to the pin.
|
|
|
|
*/
|
|
|
|
INLINED bool gpio_read(const uint8_t gpio_num)
|
|
|
|
{
|
|
|
|
return GPIO_IN_REG & BIT(gpio_num);
|
|
|
|
}
|
|
|
|
|
2015-06-08 08:09:06 +00:00
|
|
|
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
|
2015-06-17 22:59:33 +00:00
|
|
|
*
|
|
|
|
* If int_type is not INT_NONE, the gpio_interrupt_handler will be attached and unmasked.
|
2015-06-08 08:09:06 +00:00
|
|
|
*/
|
|
|
|
INLINED void gpio_set_interrupt(const uint8_t gpio_num, const gpio_interrupt_t int_type)
|
|
|
|
{
|
|
|
|
GPIO_CTRL_REG(gpio_num) = (GPIO_CTRL_REG(gpio_num)&~GPIO_INT_MASK)
|
2015-06-08 23:00:32 +00:00
|
|
|
| (int_type & GPIO_INT_MASK);
|
2015-06-08 08:09:06 +00:00
|
|
|
if(int_type != INT_NONE) {
|
2015-06-08 23:00:32 +00:00
|
|
|
_xt_isr_attach(INUM_GPIO, gpio_interrupt_handler);
|
|
|
|
_xt_isr_unmask(1<<INUM_GPIO);
|
2015-06-08 08:09:06 +00:00
|
|
|
}
|
|
|
|
}
|
2015-06-05 01:46:25 +00:00
|
|
|
|
2015-06-17 22:59:33 +00:00
|
|
|
/* Return the interrupt type set for a pin */
|
|
|
|
INLINED gpio_interrupt_t gpio_get_interrupt(const uint8_t gpio_num)
|
|
|
|
{
|
|
|
|
return (gpio_interrupt_t)(GPIO_CTRL_REG(gpio_num) & GPIO_INT_MASK);
|
|
|
|
}
|
|
|
|
|
2015-06-05 01:46:25 +00:00
|
|
|
#endif
|