diff --git a/components/services/accessors.c b/components/services/accessors.c index 58652bbd..a4c490bc 100644 --- a/components/services/accessors.c +++ b/components/services/accessors.c @@ -491,7 +491,7 @@ const gpio_exp_config_t* config_gpio_exp_get(int index) { // re-initialize config every time memset(&config, 0, sizeof(config)); - config.intr = -1; config.count = 16; config.base = GPIO_NUM_MAX; config.phy.port = i2c_system_port; + config.intr = -1; config.count = 16; config.base = GPIO_NUM_MAX; config.phy.port = i2c_system_port; config.phy.host = spi_system_host; nvs_item = config_alloc_get(NVS_TYPE_STR, "gpio_exp_config"); if (!nvs_item || !*nvs_item) return NULL; @@ -505,6 +505,8 @@ const gpio_exp_config_t* config_gpio_exp_get(int index) { } if ((p = strcasestr(item, "addr")) != NULL) config.phy.addr = atoi(strchr(p, '=') + 1); + if ((p = strcasestr(item, "cs_pin")) != NULL) config.phy.cs_pin = atoi(strchr(p, '=') + 1); + if ((p = strcasestr(item, "speed")) != NULL) config.phy.speed = atoi(strchr(p, '=') + 1); if ((p = strcasestr(item, "intr")) != NULL) config.intr = atoi(strchr(p, '=') + 1); if ((p = strcasestr(item, "base")) != NULL) config.base = atoi(strchr(p, '=') + 1); if ((p = strcasestr(item, "count")) != NULL) config.count = atoi(strchr(p, '=') + 1); diff --git a/components/services/gpio_exp.c b/components/services/gpio_exp.c index 9deb38fd..4dc52b39 100644 --- a/components/services/gpio_exp.c +++ b/components/services/gpio_exp.c @@ -16,6 +16,7 @@ #include "esp_log.h" #include "driver/gpio.h" #include "driver/i2c.h" +#include "driver/spi_master.h" #include "gpio_exp.h" #define GPIO_EXP_INTR 0x100 @@ -28,7 +29,10 @@ typedef struct gpio_exp_s { uint32_t first, last; - union gpio_exp_phy_u phy; + struct { + struct gpio_exp_phy_s phy; + spi_device_handle_t spi_handle; + }; uint32_t shadow, pending; TickType_t age; SemaphoreHandle_t mutex; @@ -54,35 +58,44 @@ static const char TAG[] = "gpio expander"; static void IRAM_ATTR intr_isr_handler(void* arg); static gpio_exp_t* find_expander(gpio_exp_t *expander, int *gpio); -static void pca9535_set_direction(gpio_exp_t* self); -static int pca9535_read(gpio_exp_t* self); -static void pca9535_write(gpio_exp_t* self); +static void pca9535_set_direction(gpio_exp_t* self); +static int pca9535_read(gpio_exp_t* self); +static void pca9535_write(gpio_exp_t* self); -static void pca85xx_set_direction(gpio_exp_t* self); -static int pca85xx_read(gpio_exp_t* self); -static void pca85xx_write(gpio_exp_t* self); +static void pca85xx_set_direction(gpio_exp_t* self); +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 esp_err_t 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 esp_err_t mcp23s17_init(gpio_exp_t* self); +static void mcp23s17_set_pull_mode(gpio_exp_t* self); +static void mcp23s17_set_direction(gpio_exp_t* self); +static int mcp23s17_read(gpio_exp_t* self); +static void mcp23s17_write(gpio_exp_t* self); static void service_handler(void *arg); static void debounce_handler( TimerHandle_t xTimer ); -static esp_err_t i2c_write_byte(uint8_t i2c_port, uint8_t i2c_addr, uint8_t reg, uint8_t val); -static uint16_t i2c_read(uint8_t i2c_port, uint8_t i2c_addr, uint8_t reg, bool word); -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(uint8_t port, uint8_t addr, uint8_t reg, uint32_t data, int len); +static uint32_t i2c_read(uint8_t port, uint8_t addr, uint8_t reg, int len); + +static spi_device_handle_t spi_config(struct gpio_exp_phy_s *phy); +static esp_err_t spi_write(spi_device_handle_t handle, uint8_t addr, uint8_t reg, uint32_t data, int len); +static uint32_t spi_read(spi_device_handle_t handle, uint8_t addr, uint8_t reg, int len); static const struct gpio_exp_model_s { char *model; gpio_int_type_t trigger; - void (*init)(gpio_exp_t* self); - int (*read)(gpio_exp_t* self); - void (*write)(gpio_exp_t* self); - void (*set_direction)(gpio_exp_t* self); - void (*set_pull_mode)(gpio_exp_t* self); + esp_err_t (*init)(gpio_exp_t* self); + int (*read)(gpio_exp_t* self); + void (*write)(gpio_exp_t* self); + void (*set_direction)(gpio_exp_t* self); + void (*set_pull_mode)(gpio_exp_t* self); } registered[] = { { .model = "pca9535", .trigger = GPIO_INTR_NEGEDGE, @@ -101,6 +114,13 @@ static const struct gpio_exp_model_s { .set_pull_mode = mcp23017_set_pull_mode, .read = mcp23017_read, .write = mcp23017_write, }, + { .model = "mcp23s17", + .trigger = GPIO_INTR_NEGEDGE, + .init = mcp23s17_init, + .set_direction = mcp23s17_set_direction, + .set_pull_mode = mcp23s17_set_pull_mode, + .read = mcp23s17_read, + .write = mcp23s17_write, }, }; static EXT_RAM_ATTR uint8_t n_expanders; @@ -150,7 +170,7 @@ gpio_exp_t* gpio_exp_create(const gpio_exp_config_t *config) { expander->last = config->base + config->count - 1; expander->mutex = xSemaphoreCreateMutex(); - memcpy(&expander->phy, &config->phy, sizeof(union gpio_exp_phy_u)); + memcpy(&expander->phy, &config->phy, sizeof(struct gpio_exp_phy_s)); if (expander->model->init) expander->model->init(expander); // create a task to handle asynchronous requests (only write at this time) @@ -372,87 +392,6 @@ esp_err_t gpio_isr_handler_remove_x(int gpio) { return gpio_exp_isr_handler_remove(gpio, NULL); } -/**************************************************************************************** - * Find the expander related to base - */ -static gpio_exp_t* find_expander(gpio_exp_t *expander, int *gpio) { - // a mutex would be better, but risk is so small... - for (int i = 0; !expander && i < n_expanders; i++) { - if (*gpio >= expanders[i].first && *gpio <= expanders[i].last) expander = expanders + i; - } - - // normalize GPIO number - if (expander && *gpio >= expander->first) *gpio -= expander->first; - - return expander; -} - -/**************************************************************************************** - * PCA9535 family : direction, read and write - */ -static void pca9535_set_direction(gpio_exp_t* self) { - i2c_write_word(self->phy.port, self->phy.addr, 0x06, self->r_mask); -} - -static int pca9535_read(gpio_exp_t* self) { - return i2c_read(self->phy.port, self->phy.addr, 0x00, true); -} - -static void pca9535_write(gpio_exp_t* self) { - i2c_write_word(self->phy.port, self->phy.addr, 0x02, self->shadow); -} - -/**************************************************************************************** - * PCA85xx family : read and write - */ -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 - i2c_write_word(self->phy.port, self->phy.addr, 0xff, self->r_mask | self->w_mask); -} - -static int pca85xx_read(gpio_exp_t* self) { - return i2c_read(self->phy.port, self->phy.addr, 0xff, true); -} - -static void pca85xx_write(gpio_exp_t* self) { - // all input must be set to 1 (open drain) - 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µ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(self->phy.port, self->phy.addr, 0x12, true); -} - -static void mcp23017_write(gpio_exp_t* self) { - i2c_write_word(self->phy.port, self->phy.addr, 0x12, self->shadow); -} /**************************************************************************************** * INTR low-level handler @@ -520,76 +459,152 @@ void service_handler(void *arg) { } /**************************************************************************************** - * + * Find the expander related to base */ -static esp_err_t i2c_write_byte(uint8_t i2c_port, uint8_t i2c_addr, uint8_t reg, uint8_t val) { - i2c_cmd_handle_t cmd = i2c_cmd_link_create(); - i2c_master_start(cmd); - - i2c_master_write_byte(cmd, (i2c_addr << 1) | I2C_MASTER_WRITE, I2C_MASTER_NACK); - i2c_master_write_byte(cmd, reg, I2C_MASTER_NACK); - i2c_master_write_byte(cmd, val, I2C_MASTER_NACK); - - i2c_master_stop(cmd); - esp_err_t ret = i2c_master_cmd_begin(i2c_port, cmd, 100 / portTICK_RATE_MS); - i2c_cmd_link_delete(cmd); - - if (ret != ESP_OK) { - ESP_LOGW(TAG, "I2C write failed"); +static gpio_exp_t* find_expander(gpio_exp_t *expander, int *gpio) { + // a mutex would be better, but risk is so small... + for (int i = 0; !expander && i < n_expanders; i++) { + if (*gpio >= expanders[i].first && *gpio <= expanders[i].last) expander = expanders + i; } - return ret; + // normalize GPIO number + if (expander && *gpio >= expander->first) *gpio -= expander->first; + + return expander; } /**************************************************************************************** - * I2C read 8 or 16 bits word + DRIVERS +****************************************************************************************/ + +/**************************************************************************************** + * PCA9535 family : direction, read and write */ -static uint16_t i2c_read(uint8_t i2c_port, uint8_t i2c_addr, uint8_t reg, bool word) { - uint8_t data[2]; - - i2c_cmd_handle_t cmd = i2c_cmd_link_create(); +static void pca9535_set_direction(gpio_exp_t* self) { + i2c_write(self->phy.port, self->phy.addr, 0x06, self->r_mask, 2); +} - i2c_master_start(cmd); - i2c_master_write_byte(cmd, (i2c_addr << 1) | I2C_MASTER_WRITE, I2C_MASTER_NACK); +static int pca9535_read(gpio_exp_t* self) { + return i2c_read(self->phy.port, self->phy.addr, 0x00, 2); +} - // when using a register, write it's value then the device address again - if (reg != 0xff) { - i2c_master_write_byte(cmd, reg, I2C_MASTER_NACK); - i2c_master_start(cmd); - i2c_master_write_byte(cmd, (i2c_addr << 1) | I2C_MASTER_READ, I2C_MASTER_NACK); - } - - if (word) { - i2c_master_read_byte(cmd, data, I2C_MASTER_ACK); - i2c_master_read_byte(cmd, data + 1, I2C_MASTER_NACK); - } else { - i2c_master_read_byte(cmd, data, I2C_MASTER_NACK); - } - - i2c_master_stop(cmd); - esp_err_t ret = i2c_master_cmd_begin(i2c_port, cmd, 100 / portTICK_RATE_MS); - i2c_cmd_link_delete(cmd); - - if (ret != ESP_OK) { - ESP_LOGW(TAG, "I2C read failed"); - } - - return *(uint16_t*) data; +static void pca9535_write(gpio_exp_t* self) { + i2c_write(self->phy.port, self->phy.addr, 0x02, self->shadow, 2); } /**************************************************************************************** - * I2C write 16 bits word + * PCA85xx family : read and write */ -static esp_err_t i2c_write_word(uint8_t i2c_port, uint8_t i2c_addr, uint8_t reg, uint16_t data) { +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 + i2c_write(self->phy.port, self->phy.addr, 0xff, self->r_mask | self->w_mask, true); +} + +static int pca85xx_read(gpio_exp_t* self) { + return i2c_read(self->phy.port, self->phy.addr, 0xff, 2); +} + +static void pca85xx_write(gpio_exp_t* self) { + // all input must be set to 1 (open drain) + i2c_write(self->phy.port, self->phy.addr, 0xff, self->shadow | self->r_mask, true); +} + +/**************************************************************************************** + * MCP23017 family : init, direction, read and write + */ +static esp_err_t mcp23017_init(gpio_exp_t* self) { + /* + 0111 x10x = same bank, mirrot single int, no sequentµial, open drain, active low + not sure about this funny change of mapping of the control register itself, really? + */ + esp_err_t err = i2c_write(self->phy.port, self->phy.addr, 0x05, 0x74, 1); + err |= i2c_write(self->phy.port, self->phy.addr, 0x0a, 0x74, 1); + + // no interrupt on comparison or on change + err |= i2c_write(self->phy.port, self->phy.addr, 0x04, 0x00, 2); + err |= i2c_write(self->phy.port, self->phy.addr, 0x08, 0x00, 2); + + return err; +} + +static void mcp23017_set_direction(gpio_exp_t* self) { + // default to input and set real input to generate interrupt + i2c_write(self->phy.port, self->phy.addr, 0x00, ~self->w_mask, 2); + i2c_write(self->phy.port, self->phy.addr, 0x04, self->r_mask, 2); +} + +static void mcp23017_set_pull_mode(gpio_exp_t* self) { + i2c_write(self->phy.port, self->phy.addr, 0x0c, self->pullup, 2); +} + +static int mcp23017_read(gpio_exp_t* self) { + // read the pins value, not the stored one @interrupt + return i2c_read(self->phy.port, self->phy.addr, 0x12, 2); +} + +static void mcp23017_write(gpio_exp_t* self) { + i2c_write(self->phy.port, self->phy.addr, 0x12, self->shadow, 2); +} + +/**************************************************************************************** + * MCP23s17 family : init, direction, read and write + */ +static esp_err_t mcp23s17_init(gpio_exp_t* self) { + self->spi_handle = spi_config(&self->phy); + + /* + 0111 x10x = same bank, mirrot single int, no sequentµial, open drain, active low + not sure about this funny change of mapping of the control register itself, really? + */ + esp_err_t err = spi_write(self->spi_handle, self->phy.addr, 0x05, 0x74, 1); + err |= spi_write(self->spi_handle, self->phy.addr, 0x0a, 0x74, 1); + + // no interrupt on comparison or on change + err |= spi_write(self->spi_handle, self->phy.addr, 0x04, 0x00, 2); + err |= spi_write(self->spi_handle, self->phy.addr, 0x08, 0x00, 2); + + return err; +} + +static void mcp23s17_set_direction(gpio_exp_t* self) { + // default to input and set real input to generate interrupt + spi_write(self->spi_handle, self->phy.addr, 0x00, ~self->w_mask, 2); + spi_write(self->spi_handle, self->phy.addr, 0x04, self->r_mask, 2); +} + +static void mcp23s17_set_pull_mode(gpio_exp_t* self) { + spi_write(self->spi_handle, self->phy.addr, 0x0c, self->pullup, 2); +} + +static int mcp23s17_read(gpio_exp_t* self) { + // read the pins value, not the stored one @interrupt + return spi_read(self->spi_handle, self->phy.addr, 0x12, 2); +} + +static void mcp23s17_write(gpio_exp_t* self) { + spi_write(self->spi_handle, self->phy.addr, 0x12, self->shadow, 2); +} + +/*************************************************************************************** + I2C low level +***************************************************************************************/ + +/**************************************************************************************** + * I2C write up to 32 bits + */ +static esp_err_t i2c_write(uint8_t port, uint8_t addr, uint8_t reg, uint32_t data, int len) { i2c_cmd_handle_t cmd = i2c_cmd_link_create(); i2c_master_start(cmd); - i2c_master_write_byte(cmd, (i2c_addr << 1) | I2C_MASTER_WRITE, I2C_MASTER_NACK); + i2c_master_write_byte(cmd, (addr << 1) | I2C_MASTER_WRITE, I2C_MASTER_NACK); if (reg != 0xff) i2c_master_write_byte(cmd, reg, I2C_MASTER_NACK); - i2c_master_write(cmd, (uint8_t*) &data, 2, I2C_MASTER_NACK); + + // works with out endianness + if (len > 1) i2c_master_write(cmd, (uint8_t*) &data, len, I2C_MASTER_NACK); + else i2c_master_write_byte(cmd, data, I2C_MASTER_NACK); i2c_master_stop(cmd); - esp_err_t ret = i2c_master_cmd_begin(i2c_port, cmd, 100 / portTICK_RATE_MS); + esp_err_t ret = i2c_master_cmd_begin(port, cmd, 100 / portTICK_RATE_MS); i2c_cmd_link_delete(cmd); if (ret != ESP_OK) { @@ -597,4 +612,99 @@ static esp_err_t i2c_write_word(uint8_t i2c_port, uint8_t i2c_addr, uint8_t reg, } return ret; +} + +/**************************************************************************************** + * I2C read up to 32 bits + */ +static uint32_t i2c_read(uint8_t port, uint8_t addr, uint8_t reg, int len) { + uint32_t data = 0; + + i2c_cmd_handle_t cmd = i2c_cmd_link_create(); + + i2c_master_start(cmd); + i2c_master_write_byte(cmd, (addr << 1) | I2C_MASTER_WRITE, I2C_MASTER_NACK); + + // when using a register, write it's value then the device address again + if (reg != 0xff) { + i2c_master_write_byte(cmd, reg, I2C_MASTER_NACK); + i2c_master_start(cmd); + i2c_master_write_byte(cmd, (addr << 1) | I2C_MASTER_READ, I2C_MASTER_NACK); + } + + // works with out endianness + if (len > 1) i2c_master_read(cmd, (uint8_t*) &data, len, I2C_MASTER_LAST_NACK); + else i2c_master_read_byte(cmd, (uint8_t*) &data, I2C_MASTER_NACK); + + i2c_master_stop(cmd); + esp_err_t ret = i2c_master_cmd_begin(port, cmd, 100 / portTICK_RATE_MS); + i2c_cmd_link_delete(cmd); + + if (ret != ESP_OK) { + ESP_LOGW(TAG, "I2C read failed"); + } + + return data; +} + +/*************************************************************************************** + SPI low level +***************************************************************************************/ + +/**************************************************************************************** + * SPI device addition + */ +static spi_device_handle_t spi_config(struct gpio_exp_phy_s *phy) { + spi_device_interface_config_t config; + spi_device_handle_t handle = NULL; + + // initialize ChipSelect (CS) + gpio_set_direction(phy->cs_pin, GPIO_MODE_OUTPUT ); + gpio_set_level(phy->cs_pin, 0 ); + + memset( &config, 0, sizeof( spi_device_interface_config_t ) ); + + config.command_bits = config.address_bits = 8; + config.clock_speed_hz = phy->speed ? phy->speed : SPI_MASTER_FREQ_8M; + config.spics_io_num = phy->cs_pin; + config.queue_size = 1; + config.flags = SPI_DEVICE_NO_DUMMY; + + spi_bus_add_device( phy->host, &config, &handle ); + + return handle; +} + +/**************************************************************************************** + * SPI write up to 32 bits + */ +static esp_err_t spi_write(spi_device_handle_t handle, uint8_t addr, uint8_t reg, uint32_t data, int len) { + spi_transaction_t transaction = { }; + + // rx_buffer is NULL, nothing to receive + transaction.flags = SPI_TRANS_USE_TXDATA; + transaction.cmd = addr << 1; + transaction.addr = reg; + transaction.tx_data[1] = data; transaction.tx_data[2] = data >> 8; + transaction.length = len * 8; + + // only do polling as we don't have contention on SPI (otherwise DMA for transfers > 16 bytes) + return spi_device_polling_transmit(handle, &transaction); +} + +/**************************************************************************************** + * SPI read up to 32 bits + */ +static uint32_t spi_read(spi_device_handle_t handle, uint8_t addr, uint8_t reg, int len) { + spi_transaction_t transaction = { }; + + // tx_buffer is NULL, nothing to transmit except cmd/addr + transaction.flags = SPI_TRANS_USE_RXDATA; + transaction.cmd = (addr << 1) | 1; + transaction.addr = reg; + transaction.length = len * 8; + + // only do polling as we don't have contention on SPI (otherwise DMA for transfers > 16 bytes) + spi_device_polling_transmit(handle, &transaction); + return *(uint32_t*) transaction.rx_data; } \ No newline at end of file diff --git a/components/services/gpio_exp.h b/components/services/gpio_exp.h index ae554260..1ab47197 100644 --- a/components/services/gpio_exp.h +++ b/components/services/gpio_exp.h @@ -19,12 +19,15 @@ typedef struct { uint8_t intr; uint8_t count; uint32_t base; - union gpio_exp_phy_u { - struct { - uint8_t addr, port; + struct gpio_exp_phy_s { + uint8_t addr; + struct { // for I2C + uint8_t port; }; - struct { - uint8_t cs_pin; + struct { // for SPI + uint32_t speed; + uint8_t host; + uint8_t cs_pin; }; } phy; } gpio_exp_config_t; diff --git a/components/services/services.c b/components/services/services.c index 2b84f0c5..810b94c7 100644 --- a/components/services/services.c +++ b/components/services/services.c @@ -39,20 +39,40 @@ static const char *TAG = "services"; /**************************************************************************************** * */ -void set_power_gpio(int gpio, char *value) { +void set_chip_power_gpio(int gpio, char *value) { bool parsed = true; + + // we only parse on-chip GPIOs + if (gpio >= GPIO_NUM_MAX) return; if (!strcasecmp(value, "vcc") ) { - gpio_pad_select_gpio_x(gpio); - gpio_set_direction_x(gpio, GPIO_MODE_OUTPUT); - gpio_set_level_x(gpio, 1); + gpio_pad_select_gpio(gpio); + gpio_set_direction(gpio, GPIO_MODE_OUTPUT); + gpio_set_level(gpio, 1); } else if (!strcasecmp(value, "gnd")) { - gpio_pad_select_gpio_x(gpio); - gpio_set_direction_x(gpio, GPIO_MODE_OUTPUT); - gpio_set_level_x(gpio, 0); + gpio_pad_select_gpio(gpio); + gpio_set_direction(gpio, GPIO_MODE_OUTPUT); + gpio_set_level(gpio, 0); } else parsed = false; if (parsed) ESP_LOGI(TAG, "set GPIO %u to %s", gpio, value); +} + +void set_exp_power_gpio(int gpio, char *value) { + bool parsed = true; + + // we only parse on-chip GPIOs + if (gpio < GPIO_NUM_MAX) return; + + if (!strcasecmp(value, "vcc") ) { + gpio_exp_set_direction(gpio, GPIO_MODE_OUTPUT, NULL); + gpio_exp_set_level(gpio, 1, true, NULL); + } else if (!strcasecmp(value, "gnd")) { + gpio_exp_set_direction(gpio, GPIO_MODE_OUTPUT, NULL); + gpio_exp_set_level(gpio, 0, true, NULL); + } else parsed = false; + + if (parsed) ESP_LOGI(TAG, "set expanded GPIO %u to %s", gpio, value); } @@ -70,6 +90,9 @@ void services_init(void) { } #endif + // set potential power GPIO on chip first in case expanders are power using these + parse_set_GPIO(set_chip_power_gpio); + // shared I2C bus const i2c_config_t * i2c_config = config_i2c_get(&i2c_system_port); ESP_LOGI(TAG,"Configuring I2C sda:%d scl:%d port:%u speed:%u", i2c_config->sda_io_num, i2c_config->scl_io_num, i2c_system_port, i2c_config->master.clk_speed); @@ -82,13 +105,6 @@ void services_init(void) { ESP_LOGW(TAG, "no I2C configured"); } - // create GPIO expanders - const gpio_exp_config_t* gpio_exp_config; - for (int count = 0; (gpio_exp_config = config_gpio_exp_get(count)); count++) gpio_exp_create(gpio_exp_config); - - // set potential power GPIO (a GPIO-powered expander might be an issue) - parse_set_GPIO(set_power_gpio); - const spi_bus_config_t * spi_config = config_spi_get((spi_host_device_t*) &spi_system_host); ESP_LOGI(TAG,"Configuring SPI data:%d clk:%d host:%u dc:%d", spi_config->mosi_io_num, spi_config->sclk_io_num, spi_system_host, spi_system_dc_gpio); @@ -105,6 +121,13 @@ void services_init(void) { ESP_LOGW(TAG, "no SPI configured"); } + // create GPIO expanders + const gpio_exp_config_t* gpio_exp_config; + for (int count = 0; (gpio_exp_config = config_gpio_exp_get(count)); count++) gpio_exp_create(gpio_exp_config); + + // now set potential power GPIO on expander + parse_set_GPIO(set_exp_power_gpio); + // system-wide PWM timer configuration ledc_timer_config_t pwm_timer = { .duty_resolution = LEDC_TIMER_13_BIT,