diff --git a/CMakeLists.txt b/CMakeLists.txt index 9ab5c51..3a18d25 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1 +1 @@ -idf_component_register(SRCS "main.c" INCLUDE_DIRS "include") \ No newline at end of file +idf_component_register(SRCS "zh_mcp23s17.c" INCLUDE_DIRS "include" REQUIRES driver esp_event zh_vector) \ No newline at end of file diff --git a/MCP23S17 datasheet.pdf b/MCP23S17 datasheet.pdf new file mode 100644 index 0000000..a861b50 Binary files /dev/null and b/MCP23S17 datasheet.pdf differ diff --git a/README.md b/README.md index 3df3e4d..f763fa1 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,36 @@ -# esp_component_template +#include "zh_mcp23s17.h" -esp_component_template \ No newline at end of file +#define SPI_HOST (SPI_HOST_MAX - 1) + +spi_device_handle_t mcp23s17_handle = NULL; + +// To speed up transfers, every SPI transfer sends a bunch of lines. This define specifies how many. More means more memory use, +// but less overhead for setting up / finishing transfers. Make sure 240 is dividable by this. +#define PARALLEL_LINES 16 + +void app_main(void) +{ + esp_err_t ret; + spi_device_handle_t spi; + spi_bus_config_t buscfg = { + .miso_io_num = 25, + .mosi_io_num = 23, + .sclk_io_num = 19, + .quadwp_io_num = -1, + .quadhd_io_num = -1, + .max_transfer_sz = 16 * 320 * 2 + 8}; + + spi_device_interface_config_t devcfg = { + .clock_speed_hz = 10 * 1000 * 1000, // Clock out at 10 MHz + .mode = 0, // SPI mode 0 + .spics_io_num = 22, // CS pin + .queue_size = 7, // We want to be able to queue 7 transactions at a time + // .pre_cb = lcd_spi_pre_transfer_callback, // Specify pre-transfer callback to handle D/C line + }; + // Initialize the SPI bus + ret = spi_bus_initialize(SPI_HOST, &buscfg, SPI_DMA_CH_AUTO); + ESP_ERROR_CHECK(ret); + // Attach the LCD to the SPI bus + ret = spi_bus_add_device(SPI_HOST, &devcfg, &mcp23s17_handle); + ESP_ERROR_CHECK(ret); +} \ No newline at end of file diff --git a/include/main.h b/include/main.h deleted file mode 100644 index e69de29..0000000 diff --git a/include/zh_mcp23s17.h b/include/zh_mcp23s17.h new file mode 100644 index 0000000..8c15ba7 --- /dev/null +++ b/include/zh_mcp23s17.h @@ -0,0 +1,235 @@ +/** + * @file zh_mcp23s17.h + */ + +#pragma once + +#include "esp_log.h" +#include "driver/gpio.h" +#include "driver/spi_master.h" +#include "freertos/FreeRTOS.h" +#include "freertos/task.h" +#include "esp_event.h" +#include "zh_vector.h" + +#define ZH_MCP23S17_GPIO_OUTPUT false +#define ZH_MCP23S17_GPIO_INPUT true +#define ZH_MCP23S17_GPIO_LOW false +#define ZH_MCP23S17_GPIO_HIGH true + +/** + * @brief MCP23S17 expander initial default values. + */ +#define ZH_MCP23S17_INIT_CONFIG_DEFAULT() \ + { \ + .task_priority = 1, \ + .stack_size = configMINIMAL_STACK_SIZE, \ + .expander_number = 0, \ + .gpa0_gpio_work_mode = ZH_MCP23S17_GPIO_OUTPUT, \ + .gpa1_gpio_work_mode = ZH_MCP23S17_GPIO_OUTPUT, \ + .gpa2_gpio_work_mode = ZH_MCP23S17_GPIO_OUTPUT, \ + .gpa3_gpio_work_mode = ZH_MCP23S17_GPIO_OUTPUT, \ + .gpa4_gpio_work_mode = ZH_MCP23S17_GPIO_OUTPUT, \ + .gpa5_gpio_work_mode = ZH_MCP23S17_GPIO_OUTPUT, \ + .gpa6_gpio_work_mode = ZH_MCP23S17_GPIO_OUTPUT, \ + .gpa7_gpio_work_mode = ZH_MCP23S17_GPIO_OUTPUT, \ + .gpb0_gpio_work_mode = ZH_MCP23S17_GPIO_OUTPUT, \ + .gpb1_gpio_work_mode = ZH_MCP23S17_GPIO_OUTPUT, \ + .gpb2_gpio_work_mode = ZH_MCP23S17_GPIO_OUTPUT, \ + .gpb3_gpio_work_mode = ZH_MCP23S17_GPIO_OUTPUT, \ + .gpb4_gpio_work_mode = ZH_MCP23S17_GPIO_OUTPUT, \ + .gpb5_gpio_work_mode = ZH_MCP23S17_GPIO_OUTPUT, \ + .gpb6_gpio_work_mode = ZH_MCP23S17_GPIO_OUTPUT, \ + .gpb7_gpio_work_mode = ZH_MCP23S17_GPIO_OUTPUT, \ + .interrupt_gpio = GPIO_NUM_MAX} + +#ifdef __cplusplus +extern "C" +{ +#endif + + extern TaskHandle_t zh_mcp23s17; /*!< Unique task handle. */ + + /** + * @brief Enumeration of MCP23S17 expander GPIO. + */ + typedef enum + { + ZH_MCP23S17_GPIO_NUM_GPA0 = 0, + ZH_MCP23S17_GPIO_NUM_GPA1, + ZH_MCP23S17_GPIO_NUM_GPA2, + ZH_MCP23S17_GPIO_NUM_GPA3, + ZH_MCP23S17_GPIO_NUM_GPA4, + ZH_MCP23S17_GPIO_NUM_GPA5, + ZH_MCP23S17_GPIO_NUM_GPA6, + ZH_MCP23S17_GPIO_NUM_GPA7, + ZH_MCP23S17_GPIO_NUM_GPB0, + ZH_MCP23S17_GPIO_NUM_GPB1, + ZH_MCP23S17_GPIO_NUM_GPB2, + ZH_MCP23S17_GPIO_NUM_GPB3, + ZH_MCP23S17_GPIO_NUM_GPB4, + ZH_MCP23S17_GPIO_NUM_GPB5, + ZH_MCP23S17_GPIO_NUM_GPB6, + ZH_MCP23S17_GPIO_NUM_GPB7, + ZH_MCP23S17_GPIO_NUM_MAX + } zh_mcp23s17_gpio_num_t; + + /** + * @brief Structure for initial initialization of MCP23S17 expander. + */ + typedef struct + { + uint8_t task_priority; /*!< Task priority for the MCP23S17 expander isr processing. @note Minimum value is 1. */ + uint16_t stack_size; /*!< Stack size for task for the MCP23S17 expander isr processing processing. @note The minimum size is configMINIMAL_STACK_SIZE. */ + uint8_t expander_number; /*!< Unique expander number. */ + uint8_t cs_gpio; /*!< Unique CS GPIO. */ + bool p0_gpio_work_mode; /*!< Expander GPIO PO work mode. */ + bool p1_gpio_work_mode; /*!< Expander GPIO P1 work mode. */ + bool p2_gpio_work_mode; /*!< Expander GPIO P2 work mode. */ + bool p3_gpio_work_mode; /*!< Expander GPIO P3 work mode. */ + bool p4_gpio_work_mode; /*!< Expander GPIO P4 work mode. */ + bool p5_gpio_work_mode; /*!< Expander GPIO P5 work mode. */ + bool p6_gpio_work_mode; /*!< Expander GPIO P6 work mode. */ + bool p7_gpio_work_mode; /*!< Expander GPIO P7 work mode. */ + uint8_t interrupt_gpio; /*!< Interrupt GPIO. @attention Must be same for all MCP23S17 expanders. */ + spi_device_handle_t spi_handle; /*!< Unique SPI bus handle. @attention Must be same for all MCP23S17 expanders. */ + } zh_mcp23s17_init_config_t; + + /** + * @brief PCF8574 expander handle. + */ + typedef struct + { + // uint8_t i2c_address; /*!< Expander I2C address. */ + uint8_t gpio_work_mode; /*!< Expander GPIO's work mode. */ + uint8_t gpio_status; /*!< Expander GPIO's status. */ + bool is_initialized; /*!< Expander initialization flag. */ + // i2c_master_dev_handle_t dev_handle; /*!< Unique I2C device handle. */ + void *system; /*!< System pointer for use in another components. */ + } zh_mcp23s17_handle_t; + + /** + * @brief Structure for error statistics storage. + */ + typedef struct + { + uint32_t spi_driver_error; /*!< Number of SPI driver error. */ + uint32_t event_post_error; /*!< Number of event post error. */ + uint32_t vector_error; /*!< Number of vector error. */ + uint32_t queue_overflow_error; /*!< Number of queue overflow error. */ + uint32_t min_stack_size; /*!< Minimum free stack size. */ + } zh_mcp23s17_stats_t; + + ESP_EVENT_DECLARE_BASE(ZH_MCP23S17); + + /** + * @brief Structure for sending data to the event handler when cause an interrupt. + * + * @note Should be used with ZH_PCF8574 event base. + */ + typedef struct + { + // uint8_t i2c_address; /*!< The i2c address of PCF8574 expander that caused the interrupt. */ + uint8_t gpio_number; /*!< The GPIO that caused the interrupt. */ + bool gpio_level; /*!< The GPIO level that caused the interrupt. */ + } zh_mcp23s17_event_on_isr_t; + + // /** + // * @brief Initialize PCF8574 expander. + // * + // * @param[in] config Pointer to PCF8574 initialized configuration structure. Can point to a temporary variable. + // * @param[out] handle Pointer to unique PCF8574 handle. + // * + // * @attention I2C driver must be initialized first. + // * + // * @note Before initialize the expander recommend initialize zh_pcf8574_init_config_t structure with default values. + // * + // * @code zh_pcf8574_init_config_t config = ZH_PCF8574_INIT_CONFIG_DEFAULT() @endcode + // * + // * @return ESP_OK if success or an error code otherwise. + // */ + // esp_err_t zh_pcf8574_init(const zh_mcp23s17_init_config_t *config, zh_pcf8574_handle_t *handle); + + // /** + // * @brief Deinitialize PCF8574 expander. + // * + // * @param[in] handle Pointer to unique PCF8574 handle. + // * + // * @return ESP_OK if success or an error code otherwise. + // */ + // esp_err_t zh_pcf8574_deinit(zh_pcf8574_handle_t *handle); + + // /** + // * @brief Read PCF8574 all GPIO's status. + // * + // * @param[in] handle Pointer to unique PCF8574 handle. + // * @param[out] reg Pointer to GPIO's status. + // * + // * @note For input GPIO's status will be 1 (HIGH) always. + // * + // * @return ESP_OK if success or an error code otherwise. + // */ + // esp_err_t zh_pcf8574_read(zh_pcf8574_handle_t *handle, uint8_t *reg); + + // /** + // * @brief Set PCF8574 all GPIO's status. + // * + // * @param[in] handle Pointer to unique PCF8574 handle. + // * @param[in] reg GPIO's status. + // * + // * @attention Only the GPIO outputs are affected. + // * + // * @return ESP_OK if success or an error code otherwise. + // */ + // esp_err_t zh_pcf8574_write(zh_pcf8574_handle_t *handle, uint8_t reg); + + // /** + // * @brief Reset (set to initial) PCF8574 all GPIO's. + // * + // * @param[in] handle Pointer to unique PCF8574 handle. + // * + // * @return ESP_OK if success or an error code otherwise. + // */ + // esp_err_t zh_pcf8574_reset(zh_pcf8574_handle_t *handle); + + // /** + // * @brief Read PCF8574 GPIO status. + // * + // * @param[in] handle Pointer to unique PCF8574 handle. + // * @param[in] gpio GPIO number. + // * @param[out] status Pointer to GPIO status (true - HIGH, false - LOW). + // * + // * @note For input GPIO's status will be 1 (HIGH) always. + // * + // * @return ESP_OK if success or an error code otherwise. + // */ + // esp_err_t zh_pcf8574_read_gpio(zh_pcf8574_handle_t *handle, ZH_MCP23S17_GPIO_num_t gpio, bool *status); + + // /** + // * @brief Set PCF8574 GPIO status. + // * + // * @param[in] handle Pointer to unique PCF8574 handle. + // * @param[in] gpio GPIO number. + // * @param[in] status GPIO status (true - HIGH, false - LOW). + // * + // * @attention Only the GPIO output is affected. + // * + // * @return ESP_OK if success or an error code otherwise. + // */ + // esp_err_t zh_pcf8574_write_gpio(zh_pcf8574_handle_t *handle, ZH_MCP23S17_GPIO_num_t gpio, bool status); + + // /** + // * @brief Get error statistics. + // * + // * @return Pointer to the statistics structure. + // */ + // const zh_pcf8574_stats_t *zh_pcf8574_get_stats(void); + + // /** + // * @brief Reset error statistics. + // */ + // void zh_pcf8574_reset_stats(void); + +#ifdef __cplusplus +} +#endif \ No newline at end of file diff --git a/main.c b/main.c deleted file mode 100644 index e69de29..0000000 diff --git a/version.txt b/version.txt index e69de29..afaf360 100644 --- a/version.txt +++ b/version.txt @@ -0,0 +1 @@ +1.0.0 \ No newline at end of file diff --git a/component.mk b/zh_mcp23s17.c similarity index 100% rename from component.mk rename to zh_mcp23s17.c