4 Commits

4 changed files with 59 additions and 15 deletions

View File

@@ -4,6 +4,10 @@
1. [ESP32 ESP-IDF v5.5.1](https://docs.espressif.com/projects/esp-idf/en/v5.5.1/esp32/index.html) 1. [ESP32 ESP-IDF v5.5.1](https://docs.espressif.com/projects/esp-idf/en/v5.5.1/esp32/index.html)
## SAST Tools
[PVS-Studio](https://pvs-studio.com/pvs-studio/?utm_source=website&utm_medium=github&utm_campaign=open_source) - static analyzer for C, C++, C#, and Java code.
## Features ## Features
1. Support of 16 expanders on one bus. 1. Support of 16 expanders on one bus.
@@ -16,6 +20,14 @@
2. All the INT GPIO's on the extenders must be connected to the one GPIO on ESP. 2. All the INT GPIO's on the extenders must be connected to the one GPIO on ESP.
3. The input GPIO's are always pullup to the power supply. 3. The input GPIO's are always pullup to the power supply.
## Attention
For correct operation, please enable the following settings in the menuconfig:
```text
GPIO_CTRL_FUNC_IN_IRAM
```
## Dependencies ## Dependencies
1. [zh_vector](http://git.zh.com.ru/esp_components/zh_vector) 1. [zh_vector](http://git.zh.com.ru/esp_components/zh_vector)

View File

@@ -35,6 +35,8 @@ extern "C"
{ {
#endif #endif
extern TaskHandle_t zh_pcf8574; /*!< Unique task handle. */
/** /**
* @brief Structure for initial initialization of PCF8574 expander. * @brief Structure for initial initialization of PCF8574 expander.
*/ */

View File

@@ -1 +1 @@
2.0.0 2.1.0

View File

@@ -13,9 +13,12 @@ static const char *TAG = "zh_pcf8574";
return err; \ return err; \
} }
static uint8_t _interrupt_gpio = GPIO_NUM_MAX; TaskHandle_t zh_pcf8574 = NULL;
static SemaphoreHandle_t _interrupt_semaphore = NULL; static SemaphoreHandle_t _interrupt_semaphore = NULL;
static uint8_t _interrupt_gpio = GPIO_NUM_MAX;
static const uint8_t _gpio_matrix[8] = {0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80}; static const uint8_t _gpio_matrix[8] = {0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80};
static bool _is_prev_gpio_isr_service = false;
static zh_vector_t _vector = {0}; static zh_vector_t _vector = {0};
@@ -31,7 +34,7 @@ static esp_err_t _zh_pcf8574_write_register(zh_pcf8574_handle_t *handle, uint8_t
ESP_EVENT_DEFINE_BASE(ZH_PCF8574); ESP_EVENT_DEFINE_BASE(ZH_PCF8574);
esp_err_t zh_pcf8574_init(const zh_pcf8574_init_config_t *config, zh_pcf8574_handle_t *handle) esp_err_t zh_pcf8574_init(const zh_pcf8574_init_config_t *config, zh_pcf8574_handle_t *handle) // -V2008
{ {
ZH_LOGI("PCF8574 initialization started."); ZH_LOGI("PCF8574 initialization started.");
ZH_ERROR_CHECK(handle != NULL, ESP_ERR_INVALID_ARG, NULL, "PCF8574 initialization failed. Invalid argument."); ZH_ERROR_CHECK(handle != NULL, ESP_ERR_INVALID_ARG, NULL, "PCF8574 initialization failed. Invalid argument.");
@@ -47,11 +50,27 @@ esp_err_t zh_pcf8574_init(const zh_pcf8574_init_config_t *config, zh_pcf8574_han
err = _zh_pcf8574_gpio_init(config, handle); err = _zh_pcf8574_gpio_init(config, handle);
ZH_ERROR_CHECK(err == ESP_OK, err, i2c_master_bus_rm_device(handle->dev_handle), "PCF8574 initialization failed. Interrupt GPIO initialization failed."); ZH_ERROR_CHECK(err == ESP_OK, err, i2c_master_bus_rm_device(handle->dev_handle), "PCF8574 initialization failed. Interrupt GPIO initialization failed.");
err = _zh_pcf8574_resources_init(config); err = _zh_pcf8574_resources_init(config);
ZH_ERROR_CHECK(err == ESP_OK, err, i2c_master_bus_rm_device(handle->dev_handle); gpio_isr_handler_remove(config->interrupt_gpio); gpio_uninstall_isr_service(); if (_is_prev_gpio_isr_service == true)
gpio_reset_pin(config->interrupt_gpio); zh_vector_free(&_vector), "PCF8574 initialization failed. Resources initialization failed."); {
ZH_ERROR_CHECK(err == ESP_OK, err, i2c_master_bus_rm_device(handle->dev_handle); gpio_isr_handler_remove((gpio_num_t)config->interrupt_gpio);
gpio_reset_pin((gpio_num_t)config->interrupt_gpio); zh_vector_free(&_vector), "PCF8574 initialization failed. Resources initialization failed.");
}
else
{
ZH_ERROR_CHECK(err == ESP_OK, err, i2c_master_bus_rm_device(handle->dev_handle); gpio_isr_handler_remove((gpio_num_t)config->interrupt_gpio);
gpio_uninstall_isr_service(); gpio_reset_pin((gpio_num_t)config->interrupt_gpio); zh_vector_free(&_vector), "PCF8574 initialization failed. Resources initialization failed.");
}
err = _zh_pcf8574_task_init(config); err = _zh_pcf8574_task_init(config);
ZH_ERROR_CHECK(err == ESP_OK, err, i2c_master_bus_rm_device(handle->dev_handle); gpio_isr_handler_remove(config->interrupt_gpio); gpio_uninstall_isr_service(); if (_is_prev_gpio_isr_service == true)
gpio_reset_pin(config->interrupt_gpio); zh_vector_free(&_vector); vSemaphoreDelete(_interrupt_semaphore), "PCF8574 initialization failed. Task initialization failed."); {
ZH_ERROR_CHECK(err == ESP_OK, err, i2c_master_bus_rm_device(handle->dev_handle); gpio_isr_handler_remove((gpio_num_t)config->interrupt_gpio);
gpio_reset_pin((gpio_num_t)config->interrupt_gpio); zh_vector_free(&_vector); vSemaphoreDelete(_interrupt_semaphore), "PCF8574 initialization failed. Task initialization failed.");
}
else
{
ZH_ERROR_CHECK(err == ESP_OK, err, i2c_master_bus_rm_device(handle->dev_handle); gpio_isr_handler_remove((gpio_num_t)config->interrupt_gpio);
gpio_uninstall_isr_service(); gpio_reset_pin((gpio_num_t)config->interrupt_gpio); zh_vector_free(&_vector); vSemaphoreDelete(_interrupt_semaphore), "PCF8574 initialization failed. Task initialization failed.");
}
} }
handle->is_initialized = true; handle->is_initialized = true;
ZH_LOGI("PCF8574 initialization completed successfully."); ZH_LOGI("PCF8574 initialization completed successfully.");
@@ -91,7 +110,7 @@ esp_err_t zh_pcf8574_reset(zh_pcf8574_handle_t *handle)
return ESP_OK; return ESP_OK;
} }
esp_err_t zh_pcf8574_read_gpio(zh_pcf8574_handle_t *handle, uint8_t gpio, bool *status) esp_err_t zh_pcf8574_read_gpio(zh_pcf8574_handle_t *handle, uint8_t gpio, bool *status) // -V2008
{ {
ZH_LOGI("PCF8574 read GPIO started."); ZH_LOGI("PCF8574 read GPIO started.");
ZH_ERROR_CHECK(handle != NULL && status != NULL, ESP_ERR_INVALID_ARG, NULL, "PCF8574 read GPIO failed. Invalid argument."); ZH_ERROR_CHECK(handle != NULL && status != NULL, ESP_ERR_INVALID_ARG, NULL, "PCF8574 read GPIO failed. Invalid argument.");
@@ -106,7 +125,7 @@ esp_err_t zh_pcf8574_read_gpio(zh_pcf8574_handle_t *handle, uint8_t gpio, bool *
return ESP_OK; return ESP_OK;
} }
esp_err_t zh_pcf8574_write_gpio(zh_pcf8574_handle_t *handle, uint8_t gpio, bool status) esp_err_t zh_pcf8574_write_gpio(zh_pcf8574_handle_t *handle, uint8_t gpio, bool status) // -V2008
{ {
ZH_LOGI("PCF8574 write GPIO started."); ZH_LOGI("PCF8574 write GPIO started.");
ZH_ERROR_CHECK(handle != NULL, ESP_ERR_INVALID_ARG, NULL, "PCF8574 write GPIO failed. Invalid argument."); ZH_ERROR_CHECK(handle != NULL, ESP_ERR_INVALID_ARG, NULL, "PCF8574 write GPIO failed. Invalid argument.");
@@ -127,7 +146,7 @@ esp_err_t zh_pcf8574_write_gpio(zh_pcf8574_handle_t *handle, uint8_t gpio, bool
return ESP_OK; return ESP_OK;
} }
static esp_err_t _zh_pcf8574_validate_config(const zh_pcf8574_init_config_t *config) static esp_err_t _zh_pcf8574_validate_config(const zh_pcf8574_init_config_t *config) // -V2008
{ {
ZH_ERROR_CHECK(config != NULL, ESP_ERR_INVALID_ARG, NULL, "Initial config is NULL."); ZH_ERROR_CHECK(config != NULL, ESP_ERR_INVALID_ARG, NULL, "Initial config is NULL.");
ZH_ERROR_CHECK((config->i2c_address >= 0x20 && config->i2c_address <= 0x27) || (config->i2c_address >= 0x38 && config->i2c_address <= 0x3F), ESP_ERR_INVALID_ARG, NULL, "Invalid I2C address."); ZH_ERROR_CHECK((config->i2c_address >= 0x20 && config->i2c_address <= 0x27) || (config->i2c_address >= 0x38 && config->i2c_address <= 0x3F), ESP_ERR_INVALID_ARG, NULL, "Invalid I2C address.");
@@ -137,7 +156,7 @@ static esp_err_t _zh_pcf8574_validate_config(const zh_pcf8574_init_config_t *con
return ESP_OK; return ESP_OK;
} }
static esp_err_t _zh_pcf8574_gpio_init(const zh_pcf8574_init_config_t *config, zh_pcf8574_handle_t *handle) static esp_err_t _zh_pcf8574_gpio_init(const zh_pcf8574_init_config_t *config, zh_pcf8574_handle_t *handle) // -V2008
{ {
if (_interrupt_gpio != GPIO_NUM_MAX) if (_interrupt_gpio != GPIO_NUM_MAX)
{ {
@@ -159,9 +178,20 @@ static esp_err_t _zh_pcf8574_gpio_init(const zh_pcf8574_init_config_t *config, z
err = gpio_config(&interrupt_gpio_config); err = gpio_config(&interrupt_gpio_config);
ZH_ERROR_CHECK(err == ESP_OK, err, zh_vector_free(&_vector), "GPIO configuration failed.") ZH_ERROR_CHECK(err == ESP_OK, err, zh_vector_free(&_vector), "GPIO configuration failed.")
err = gpio_install_isr_service(ESP_INTR_FLAG_LOWMED); err = gpio_install_isr_service(ESP_INTR_FLAG_LOWMED);
ZH_ERROR_CHECK(err == ESP_OK, err, gpio_reset_pin(config->interrupt_gpio); zh_vector_free(&_vector), "Failed install isr service.") ZH_ERROR_CHECK(err == ESP_OK || err == ESP_ERR_INVALID_STATE, err, gpio_reset_pin((gpio_num_t)config->interrupt_gpio); zh_vector_free(&_vector), "Failed install isr service.")
err = gpio_isr_handler_add(config->interrupt_gpio, _zh_pcf8574_isr_handler, NULL); if (err == ESP_ERR_INVALID_STATE)
ZH_ERROR_CHECK(err == ESP_OK, err, gpio_uninstall_isr_service(); gpio_reset_pin(config->interrupt_gpio); zh_vector_free(&_vector), "Failed add isr handler.") {
_is_prev_gpio_isr_service = true;
}
err = gpio_isr_handler_add((gpio_num_t)config->interrupt_gpio, _zh_pcf8574_isr_handler, NULL);
if (_is_prev_gpio_isr_service == true)
{
ZH_ERROR_CHECK(err == ESP_OK, err, gpio_reset_pin((gpio_num_t)config->interrupt_gpio); zh_vector_free(&_vector), "Failed add isr handler.")
}
else
{
ZH_ERROR_CHECK(err == ESP_OK, err, gpio_uninstall_isr_service(); gpio_reset_pin((gpio_num_t)config->interrupt_gpio); zh_vector_free(&_vector), "Failed add isr handler.")
}
_interrupt_gpio = config->interrupt_gpio; _interrupt_gpio = config->interrupt_gpio;
return ESP_OK; return ESP_OK;
} }
@@ -196,7 +226,7 @@ static esp_err_t _zh_pcf8574_resources_init(const zh_pcf8574_init_config_t *conf
static esp_err_t _zh_pcf8574_task_init(const zh_pcf8574_init_config_t *config) static esp_err_t _zh_pcf8574_task_init(const zh_pcf8574_init_config_t *config)
{ {
BaseType_t err = xTaskCreatePinnedToCore(&_zh_pcf8574_isr_processing_task, "zh_pcf8574_isr_processing_task", config->stack_size, NULL, config->task_priority, NULL, tskNO_AFFINITY); BaseType_t err = xTaskCreatePinnedToCore(&_zh_pcf8574_isr_processing_task, "zh_pcf8574_isr_processing_task", config->stack_size, NULL, config->task_priority, &zh_pcf8574, tskNO_AFFINITY);
ZH_ERROR_CHECK(err == pdPASS, err, NULL, "Failed to create isr processing task.") ZH_ERROR_CHECK(err == pdPASS, err, NULL, "Failed to create isr processing task.")
return ESP_OK; return ESP_OK;
} }