mirror of
https://github.com/sle118/squeezelite-esp32.git
synced 2025-12-08 20:47:08 +03:00
add mcp23017 (untested) and refactor things a bit
This commit is contained in:
@@ -17,17 +17,46 @@
|
|||||||
#include "driver/i2c.h"
|
#include "driver/i2c.h"
|
||||||
#include "gpio_exp.h"
|
#include "gpio_exp.h"
|
||||||
|
|
||||||
|
typedef struct gpio_exp_s {
|
||||||
|
uint32_t first, last;
|
||||||
|
union gpio_exp_phy_u phy;
|
||||||
|
uint32_t shadow;
|
||||||
|
TickType_t age;
|
||||||
|
SemaphoreHandle_t mutex;
|
||||||
|
uint32_t r_mask, w_mask;
|
||||||
|
uint32_t pullup, pulldown;
|
||||||
|
struct {
|
||||||
|
gpio_exp_isr handler;
|
||||||
|
void *arg;
|
||||||
|
} isr[4];
|
||||||
|
struct gpio_exp_model_s const *model;
|
||||||
|
} gpio_exp_t;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
enum { ASYNC_WRITE } type;
|
||||||
|
int gpio;
|
||||||
|
int level;
|
||||||
|
gpio_exp_t *expander;
|
||||||
|
} async_request_t;
|
||||||
|
|
||||||
static const char TAG[] = "gpio expander";
|
static const char TAG[] = "gpio expander";
|
||||||
|
|
||||||
static void IRAM_ATTR intr_isr_handler(void* arg);
|
static void IRAM_ATTR intr_isr_handler(void* arg);
|
||||||
static struct gpio_exp_s* find_expander(struct gpio_exp_s *expander, int *gpio);
|
static gpio_exp_t* find_expander(gpio_exp_t *expander, int *gpio);
|
||||||
|
|
||||||
static void pca9535_set_direction(union gpio_exp_phy_u*, uint32_t, uint32_t);
|
static void pca9535_set_direction(gpio_exp_t* self);
|
||||||
static int pca9535_read(union gpio_exp_phy_u*);
|
static int pca9535_read(gpio_exp_t* self);
|
||||||
static void pca9535_write(union gpio_exp_phy_u*, uint32_t, uint32_t);
|
static void pca9535_write(gpio_exp_t* self);
|
||||||
static void pca85xx_set_direction(union gpio_exp_phy_u*, uint32_t, uint32_t);
|
|
||||||
static int pca85xx_read(union gpio_exp_phy_u*);
|
static void pca85xx_set_direction(gpio_exp_t* self);
|
||||||
static void pca85xx_write(union gpio_exp_phy_u*, uint32_t, uint32_t);
|
static int pca85xx_read(gpio_exp_t* self);
|
||||||
|
static void pca85xx_write(gpio_exp_t* self);
|
||||||
|
|
||||||
|
static void mcp23017_init(gpio_exp_t* self);
|
||||||
|
static void mcp23017_set_pull_mode(gpio_exp_t* self);
|
||||||
|
static void mcp23017_set_direction(gpio_exp_t* self);
|
||||||
|
static int mcp23017_read(gpio_exp_t* self);
|
||||||
|
static void mcp23017_write(gpio_exp_t* self);
|
||||||
|
|
||||||
static void async_handler(void *arg);
|
static void async_handler(void *arg);
|
||||||
|
|
||||||
@@ -36,21 +65,14 @@ static uint8_t i2c_read_byte(uint8_t i2c_port, uint8_t i2c_addr, uint8_t reg);
|
|||||||
static uint16_t i2c_read_word(uint8_t i2c_port, uint8_t i2c_addr, uint8_t reg);
|
static uint16_t i2c_read_word(uint8_t i2c_port, uint8_t i2c_addr, uint8_t reg);
|
||||||
static esp_err_t i2c_write_word(uint8_t i2c_port, uint8_t i2c_addr, uint8_t reg, uint16_t data);
|
static esp_err_t i2c_write_word(uint8_t i2c_port, uint8_t i2c_addr, uint8_t reg, uint16_t data);
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
enum { ASYNC_WRITE } type;
|
|
||||||
int gpio;
|
|
||||||
int level;
|
|
||||||
struct gpio_exp_s *expander;
|
|
||||||
} async_request_t;
|
|
||||||
|
|
||||||
static const struct gpio_exp_model_s {
|
static const struct gpio_exp_model_s {
|
||||||
char *model;
|
char *model;
|
||||||
gpio_int_type_t trigger;
|
gpio_int_type_t trigger;
|
||||||
void (*init)(union gpio_exp_phy_u*);
|
void (*init)(gpio_exp_t* self);
|
||||||
int (*read)(union gpio_exp_phy_u*);
|
int (*read)(gpio_exp_t* self);
|
||||||
void (*write)(union gpio_exp_phy_u*, uint32_t r_mask, uint32_t shadow);
|
void (*write)(gpio_exp_t* self);
|
||||||
void (*set_direction)(union gpio_exp_phy_u*, uint32_t r_mask, uint32_t w_mask);
|
void (*set_direction)(gpio_exp_t* self);
|
||||||
void (*set_pull_mode)(int, gpio_pull_mode_t);
|
void (*set_pull_mode)(gpio_exp_t* self);
|
||||||
} registered[] = {
|
} registered[] = {
|
||||||
{ .model = "pca9535",
|
{ .model = "pca9535",
|
||||||
.trigger = GPIO_INTR_NEGEDGE,
|
.trigger = GPIO_INTR_NEGEDGE,
|
||||||
@@ -61,37 +83,31 @@ static const struct gpio_exp_model_s {
|
|||||||
.trigger = GPIO_INTR_NEGEDGE,
|
.trigger = GPIO_INTR_NEGEDGE,
|
||||||
.set_direction = pca85xx_set_direction,
|
.set_direction = pca85xx_set_direction,
|
||||||
.read = pca85xx_read,
|
.read = pca85xx_read,
|
||||||
.write = pca85xx_write, }
|
.write = pca85xx_write, },
|
||||||
|
{ .model = "mcp23017",
|
||||||
|
.trigger = GPIO_INTR_NEGEDGE,
|
||||||
|
.init = mcp23017_init,
|
||||||
|
.set_direction = mcp23017_set_direction,
|
||||||
|
.set_pull_mode = mcp23017_set_pull_mode,
|
||||||
|
.read = mcp23017_read,
|
||||||
|
.write = mcp23017_write, },
|
||||||
};
|
};
|
||||||
|
|
||||||
static EXT_RAM_ATTR uint8_t n_expanders;
|
static EXT_RAM_ATTR uint8_t n_expanders;
|
||||||
static EXT_RAM_ATTR QueueHandle_t async_queue;
|
static EXT_RAM_ATTR QueueHandle_t async_queue;
|
||||||
|
static EXT_RAM_ATTR gpio_exp_t expanders[4];
|
||||||
static EXT_RAM_ATTR struct gpio_exp_s {
|
|
||||||
uint32_t first, last;
|
|
||||||
union gpio_exp_phy_u phy;
|
|
||||||
uint32_t shadow;
|
|
||||||
TickType_t age;
|
|
||||||
SemaphoreHandle_t mutex;
|
|
||||||
uint32_t r_mask, w_mask;
|
|
||||||
struct {
|
|
||||||
gpio_exp_isr handler;
|
|
||||||
void *arg;
|
|
||||||
} isr[4];
|
|
||||||
struct gpio_exp_model_s const *model;
|
|
||||||
} expanders[4];
|
|
||||||
|
|
||||||
/******************************************************************************
|
/******************************************************************************
|
||||||
* Retrieve base from an expander reference
|
* Retrieve base from an expander reference
|
||||||
*/
|
*/
|
||||||
uint32_t gpio_exp_get_base(struct gpio_exp_s *expander) {
|
uint32_t gpio_exp_get_base(gpio_exp_t *expander) {
|
||||||
return expander->first;
|
return expander->first;
|
||||||
}
|
}
|
||||||
|
|
||||||
/******************************************************************************
|
/******************************************************************************
|
||||||
* Retrieve reference from a GPIO
|
* Retrieve reference from a GPIO
|
||||||
*/
|
*/
|
||||||
struct gpio_exp_s *gpio_exp_get_expander(int gpio) {
|
gpio_exp_t *gpio_exp_get_expander(int gpio) {
|
||||||
int _gpio = gpio;
|
int _gpio = gpio;
|
||||||
return find_expander(NULL, &_gpio);
|
return find_expander(NULL, &_gpio);
|
||||||
}
|
}
|
||||||
@@ -99,10 +115,10 @@ struct gpio_exp_s *gpio_exp_get_expander(int gpio) {
|
|||||||
/******************************************************************************
|
/******************************************************************************
|
||||||
* Create an I2C expander
|
* Create an I2C expander
|
||||||
*/
|
*/
|
||||||
struct gpio_exp_s* gpio_exp_create(const gpio_exp_config_t *config) {
|
gpio_exp_t* gpio_exp_create(const gpio_exp_config_t *config) {
|
||||||
struct gpio_exp_s *expander = expanders + n_expanders;
|
gpio_exp_t *expander = expanders + n_expanders;
|
||||||
|
|
||||||
if (config->base < GPIO_NUM_MAX || n_expanders == sizeof(expanders)/sizeof(struct gpio_exp_s)) {
|
if (config->base < GPIO_NUM_MAX || n_expanders == sizeof(expanders)/sizeof(gpio_exp_t)) {
|
||||||
ESP_LOGE(TAG, "Base %d GPIO must be at least %d for %s or too many expanders %d", config->base, GPIO_NUM_MAX, config->model, n_expanders);
|
ESP_LOGE(TAG, "Base %d GPIO must be at least %d for %s or too many expanders %d", config->base, GPIO_NUM_MAX, config->model, n_expanders);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
@@ -123,7 +139,7 @@ struct gpio_exp_s* gpio_exp_create(const gpio_exp_config_t *config) {
|
|||||||
expander->last = config->base + config->count - 1;
|
expander->last = config->base + config->count - 1;
|
||||||
expander->mutex = xSemaphoreCreateMutex();
|
expander->mutex = xSemaphoreCreateMutex();
|
||||||
memcpy(&expander->phy, &config->phy, sizeof(union gpio_exp_phy_u));
|
memcpy(&expander->phy, &config->phy, sizeof(union gpio_exp_phy_u));
|
||||||
if (expander->model->init) expander->model->init(&expander->phy);
|
if (expander->model->init) expander->model->init(expander);
|
||||||
|
|
||||||
// create a task to handle asynchronous requests (only write at this time)
|
// create a task to handle asynchronous requests (only write at this time)
|
||||||
if (!async_queue) {
|
if (!async_queue) {
|
||||||
@@ -166,7 +182,7 @@ struct gpio_exp_s* gpio_exp_create(const gpio_exp_config_t *config) {
|
|||||||
/******************************************************************************
|
/******************************************************************************
|
||||||
* Add ISR handler
|
* Add ISR handler
|
||||||
*/
|
*/
|
||||||
bool gpio_exp_add_isr(gpio_exp_isr isr, void *arg, struct gpio_exp_s *expander) {
|
bool gpio_exp_add_isr(gpio_exp_isr isr, void *arg, gpio_exp_t *expander) {
|
||||||
xSemaphoreTake(expander->mutex, pdMS_TO_TICKS(portMAX_DELAY));
|
xSemaphoreTake(expander->mutex, pdMS_TO_TICKS(portMAX_DELAY));
|
||||||
|
|
||||||
for (int i = 0; i < sizeof(expander->isr)/sizeof(*expander->isr); i++) {
|
for (int i = 0; i < sizeof(expander->isr)/sizeof(*expander->isr); i++) {
|
||||||
@@ -187,7 +203,7 @@ bool gpio_exp_add_isr(gpio_exp_isr isr, void *arg, struct gpio_exp_s *expander)
|
|||||||
/******************************************************************************
|
/******************************************************************************
|
||||||
* Set GPIO direction
|
* Set GPIO direction
|
||||||
*/
|
*/
|
||||||
esp_err_t gpio_exp_set_direction(int gpio, gpio_mode_t mode, struct gpio_exp_s *expander) {
|
esp_err_t gpio_exp_set_direction(int gpio, gpio_mode_t mode, gpio_exp_t *expander) {
|
||||||
if ((expander = find_expander(expander, &gpio)) == NULL) return ESP_ERR_INVALID_ARG;
|
if ((expander = find_expander(expander, &gpio)) == NULL) return ESP_ERR_INVALID_ARG;
|
||||||
|
|
||||||
xSemaphoreTake(expander->mutex, pdMS_TO_TICKS(portMAX_DELAY));
|
xSemaphoreTake(expander->mutex, pdMS_TO_TICKS(portMAX_DELAY));
|
||||||
@@ -206,7 +222,7 @@ esp_err_t gpio_exp_set_direction(int gpio, gpio_mode_t mode, struct gpio_exp_s *
|
|||||||
}
|
}
|
||||||
|
|
||||||
// most expanders want unconfigured GPIO to be set to output
|
// most expanders want unconfigured GPIO to be set to output
|
||||||
if (expander->model->set_direction) expander->model->set_direction(&expander->phy, expander->r_mask, expander->w_mask);
|
if (expander->model->set_direction) expander->model->set_direction(expander);
|
||||||
|
|
||||||
xSemaphoreGive(expander->mutex);
|
xSemaphoreGive(expander->mutex);
|
||||||
return ESP_OK;
|
return ESP_OK;
|
||||||
@@ -215,7 +231,7 @@ esp_err_t gpio_exp_set_direction(int gpio, gpio_mode_t mode, struct gpio_exp_s *
|
|||||||
/******************************************************************************
|
/******************************************************************************
|
||||||
* Get GPIO level with cache
|
* Get GPIO level with cache
|
||||||
*/
|
*/
|
||||||
int gpio_exp_get_level(int gpio, uint32_t age, struct gpio_exp_s *expander) {
|
int gpio_exp_get_level(int gpio, uint32_t age, gpio_exp_t *expander) {
|
||||||
if ((expander = find_expander(expander, &gpio)) == NULL) return -1;
|
if ((expander = find_expander(expander, &gpio)) == NULL) return -1;
|
||||||
uint32_t now = xTaskGetTickCount();
|
uint32_t now = xTaskGetTickCount();
|
||||||
|
|
||||||
@@ -223,7 +239,7 @@ int gpio_exp_get_level(int gpio, uint32_t age, struct gpio_exp_s *expander) {
|
|||||||
if (now - expander->age >= pdMS_TO_TICKS(age)) {
|
if (now - expander->age >= pdMS_TO_TICKS(age)) {
|
||||||
if (xSemaphoreTake(expander->mutex, pdMS_TO_TICKS(50)) == pdFALSE) return -1;
|
if (xSemaphoreTake(expander->mutex, pdMS_TO_TICKS(50)) == pdFALSE) return -1;
|
||||||
|
|
||||||
expander->shadow = expander->model->read(&expander->phy);
|
expander->shadow = expander->model->read(expander);
|
||||||
expander->age = now;
|
expander->age = now;
|
||||||
|
|
||||||
xSemaphoreGive(expander->mutex);
|
xSemaphoreGive(expander->mutex);
|
||||||
@@ -237,7 +253,7 @@ int gpio_exp_get_level(int gpio, uint32_t age, struct gpio_exp_s *expander) {
|
|||||||
/******************************************************************************
|
/******************************************************************************
|
||||||
* Set GPIO level with cache
|
* Set GPIO level with cache
|
||||||
*/
|
*/
|
||||||
esp_err_t gpio_exp_set_level(int gpio, int level, bool direct, struct gpio_exp_s *expander) {
|
esp_err_t gpio_exp_set_level(int gpio, int level, bool direct, gpio_exp_t *expander) {
|
||||||
if ((expander = find_expander(expander, &gpio)) == NULL) return ESP_ERR_INVALID_ARG;
|
if ((expander = find_expander(expander, &gpio)) == NULL) return ESP_ERR_INVALID_ARG;
|
||||||
uint32_t mask = 1 << gpio;
|
uint32_t mask = 1 << gpio;
|
||||||
|
|
||||||
@@ -256,7 +272,7 @@ esp_err_t gpio_exp_set_level(int gpio, int level, bool direct, struct gpio_exp_s
|
|||||||
// only write if shadow not up to date
|
// only write if shadow not up to date
|
||||||
if ((mask ^ level) && expander->model->write) {
|
if ((mask ^ level) && expander->model->write) {
|
||||||
expander->shadow = (expander->shadow & ~(mask | level)) | level;
|
expander->shadow = (expander->shadow & ~(mask | level)) | level;
|
||||||
expander->model->write(&expander->phy, expander->r_mask, expander->shadow);
|
expander->model->write(expander);
|
||||||
}
|
}
|
||||||
|
|
||||||
xSemaphoreGive(expander->mutex);
|
xSemaphoreGive(expander->mutex);
|
||||||
@@ -272,9 +288,16 @@ esp_err_t gpio_exp_set_level(int gpio, int level, bool direct, struct gpio_exp_s
|
|||||||
/******************************************************************************
|
/******************************************************************************
|
||||||
* Set GPIO pullmode
|
* Set GPIO pullmode
|
||||||
*/
|
*/
|
||||||
esp_err_t gpio_exp_set_pull_mode(int gpio, gpio_pull_mode_t mode, struct gpio_exp_s *expander) {
|
esp_err_t gpio_exp_set_pull_mode(int gpio, gpio_pull_mode_t mode, gpio_exp_t *expander) {
|
||||||
if ((expander = find_expander(expander, &gpio)) != NULL && expander->model->set_pull_mode) {
|
if ((expander = find_expander(expander, &gpio)) != NULL && expander->model->set_pull_mode) {
|
||||||
expander->model->set_pull_mode(gpio, mode);
|
|
||||||
|
expander->pullup &= ~(1 << gpio);
|
||||||
|
expander->pulldown &= ~(1 << gpio);
|
||||||
|
|
||||||
|
if (mode == GPIO_PULLUP_ONLY || mode == GPIO_PULLUP_PULLDOWN) expander->pullup |= 1 << gpio;
|
||||||
|
if (mode == GPIO_PULLDOWN_ONLY || mode == GPIO_PULLUP_PULLDOWN) expander->pulldown |= 1 << gpio;
|
||||||
|
|
||||||
|
expander->model->set_pull_mode(expander);
|
||||||
return ESP_OK;
|
return ESP_OK;
|
||||||
}
|
}
|
||||||
return ESP_ERR_INVALID_ARG;
|
return ESP_ERR_INVALID_ARG;
|
||||||
@@ -283,8 +306,8 @@ esp_err_t gpio_exp_set_pull_mode(int gpio, gpio_pull_mode_t mode, struct gpio_ex
|
|||||||
/******************************************************************************
|
/******************************************************************************
|
||||||
* Enumerate modified GPIO
|
* Enumerate modified GPIO
|
||||||
*/
|
*/
|
||||||
void gpio_exp_enumerate(gpio_exp_enumerator enumerator, struct gpio_exp_s *expander) {
|
void gpio_exp_enumerate(gpio_exp_enumerator enumerator, gpio_exp_t *expander) {
|
||||||
uint32_t value = expander->model->read(&expander->phy) ^ expander->shadow;
|
uint32_t value = expander->model->read(expander) ^ expander->shadow;
|
||||||
uint8_t clz;
|
uint8_t clz;
|
||||||
|
|
||||||
// memorize newly read value and just update if requested
|
// memorize newly read value and just update if requested
|
||||||
@@ -327,7 +350,7 @@ esp_err_t gpio_set_level_u(int gpio, int level) {
|
|||||||
/****************************************************************************************
|
/****************************************************************************************
|
||||||
* Find the expander related to base
|
* Find the expander related to base
|
||||||
*/
|
*/
|
||||||
static struct gpio_exp_s* find_expander(struct gpio_exp_s *expander, int *gpio) {
|
static gpio_exp_t* find_expander(gpio_exp_t *expander, int *gpio) {
|
||||||
for (int i = 0; !expander && i < n_expanders; i++) {
|
for (int i = 0; !expander && i < n_expanders; i++) {
|
||||||
if (*gpio >= expanders[i].first && *gpio <= expanders[i].last) expander = expanders + i;
|
if (*gpio >= expanders[i].first && *gpio <= expanders[i].last) expander = expanders + i;
|
||||||
}
|
}
|
||||||
@@ -341,33 +364,68 @@ static struct gpio_exp_s* find_expander(struct gpio_exp_s *expander, int *gpio)
|
|||||||
/****************************************************************************************
|
/****************************************************************************************
|
||||||
* PCA9535 family : direction, read and write
|
* PCA9535 family : direction, read and write
|
||||||
*/
|
*/
|
||||||
static void pca9535_set_direction(union gpio_exp_phy_u *phy, uint32_t r_mask, uint32_t w_mask) {
|
static void pca9535_set_direction(gpio_exp_t* self) {
|
||||||
i2c_write_word(phy->port, phy->addr, 0x06, r_mask);
|
i2c_write_word(self->phy.port, self->phy.addr, 0x06, self->r_mask);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int pca9535_read(union gpio_exp_phy_u *phy) {
|
static int pca9535_read(gpio_exp_t* self) {
|
||||||
return i2c_read_word(phy->port, phy->addr, 0x00);
|
return i2c_read_word(self->phy.port, self->phy.addr, 0x00);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void pca9535_write(union gpio_exp_phy_u *phy, uint32_t r_mask, uint32_t shadow) {
|
static void pca9535_write(gpio_exp_t* self) {
|
||||||
i2c_write_word(phy->port, phy->addr, 0x02, shadow);
|
i2c_write_word(self->phy.port, self->phy.addr, 0x02, self->shadow);
|
||||||
}
|
}
|
||||||
|
|
||||||
/****************************************************************************************
|
/****************************************************************************************
|
||||||
* PCA85xx family : read and write
|
* PCA85xx family : read and write
|
||||||
*/
|
*/
|
||||||
static void pca85xx_set_direction(union gpio_exp_phy_u *phy, uint32_t r_mask, uint32_t w_mask) {
|
static void pca85xx_set_direction(gpio_exp_t* self) {
|
||||||
// all inputs must be set to 1 (open drain) and output are left open as well
|
// all inputs must be set to 1 (open drain) and output are left open as well
|
||||||
i2c_write_word(phy->port, phy->addr, 0xff, r_mask | w_mask);
|
i2c_write_word(self->phy.port, self->phy.addr, 0xff, self->r_mask | self->w_mask);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int pca85xx_read(union gpio_exp_phy_u *phy) {
|
static int pca85xx_read(gpio_exp_t* self) {
|
||||||
return i2c_read_word(phy->port, phy->addr, 0xff);
|
return i2c_read_word(self->phy.port, self->phy.addr, 0xff);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void pca85xx_write(union gpio_exp_phy_u *phy, uint32_t r_mask, uint32_t shadow) {
|
static void pca85xx_write(gpio_exp_t* self) {
|
||||||
// all input must be set to 1 (open drain)
|
// all input must be set to 1 (open drain)
|
||||||
i2c_write_word(phy->port, phy->addr, 0xff, shadow | r_mask);
|
i2c_write_word(self->phy.port, self->phy.addr, 0xff, self->shadow | self->r_mask);
|
||||||
|
}
|
||||||
|
|
||||||
|
/****************************************************************************************
|
||||||
|
* MCP23017 family : init, direction, read and write
|
||||||
|
*/
|
||||||
|
static void mcp23017_init(gpio_exp_t* self) {
|
||||||
|
/*
|
||||||
|
0111 x10x = same bank, mirrot single int, no sequent<6E>ial, open drain, active low
|
||||||
|
not sure about this funny change of mapping of the control register itself, really?
|
||||||
|
*/
|
||||||
|
i2c_write_byte(self->phy.port, self->phy.addr, 0x05, 0x74);
|
||||||
|
i2c_write_byte(self->phy.port, self->phy.addr, 0x0a, 0x74);
|
||||||
|
|
||||||
|
// no interrupt on comparison or on change
|
||||||
|
i2c_write_word(self->phy.port, self->phy.addr, 0x04, 0x00);
|
||||||
|
i2c_write_word(self->phy.port, self->phy.addr, 0x08, 0x00);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void mcp23017_set_direction(gpio_exp_t* self) {
|
||||||
|
// default to input and set real input to generate interrupt
|
||||||
|
i2c_write_word(self->phy.port, self->phy.addr, 0x00, ~self->w_mask);
|
||||||
|
i2c_write_word(self->phy.port, self->phy.addr, 0x04, self->r_mask);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void mcp23017_set_pull_mode(gpio_exp_t* self) {
|
||||||
|
i2c_write_word(self->phy.port, self->phy.addr, 0x0c, self->pullup);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int mcp23017_read(gpio_exp_t* self) {
|
||||||
|
// read the pin value, not the stored one @interrupt
|
||||||
|
return i2c_read_word(self->phy.port, self->phy.addr, 0x12);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void mcp23017_write(gpio_exp_t* self) {
|
||||||
|
i2c_write_word(self->phy.port, self->phy.addr, 0x12, self->shadow);
|
||||||
}
|
}
|
||||||
|
|
||||||
/****************************************************************************************
|
/****************************************************************************************
|
||||||
@@ -375,7 +433,7 @@ static void pca85xx_write(union gpio_exp_phy_u *phy, uint32_t r_mask, uint32_t s
|
|||||||
*/
|
*/
|
||||||
static void IRAM_ATTR intr_isr_handler(void* arg)
|
static void IRAM_ATTR intr_isr_handler(void* arg)
|
||||||
{
|
{
|
||||||
struct gpio_exp_s *expander = (struct gpio_exp_s*) arg;
|
gpio_exp_t *expander = (gpio_exp_t*) arg;
|
||||||
BaseType_t woken = pdFALSE;
|
BaseType_t woken = pdFALSE;
|
||||||
|
|
||||||
for (int i = 0; i < sizeof(expander->isr)/sizeof(*expander->isr); i++) {
|
for (int i = 0; i < sizeof(expander->isr)/sizeof(*expander->isr); i++) {
|
||||||
|
|||||||
Reference in New Issue
Block a user