forked from espressif/esp-bsp
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
TCA95xx_16bit (BSP-326) (espressif#174)
* TCA95xx_16bit espressif#137
- Loading branch information
Showing
7 changed files
with
488 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
1 change: 1 addition & 0 deletions
1
components/io_expander/esp_io_expander_tca95xx_16bit/CMakeLists.txt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
idf_component_register(SRCS "esp_io_expander_tca95xx_16bit.c" INCLUDE_DIRS "include" REQUIRES "driver") |
42 changes: 42 additions & 0 deletions
42
components/io_expander/esp_io_expander_tca95xx_16bit/README.md
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,42 @@ | ||
# ESP IO Expander Chip TCA9539 and TCA9555 | ||
|
||
[![Component Registry](https://components.espressif.com/components/espressif/esp_io_expander_tca95xx_16bit/badge.svg)](https://components.espressif.com/components/espressif/esp_io_expander_tca95xx_16bit) | ||
|
||
Implementation of the TCA9539 and TCA9555 io expander chip with esp_io_expander component. | ||
|
||
| Chip | Communication interface | Component name | Link to datasheet | | ||
| :--------------: | :---------------------: | :---------------------------: | :---------------: | | ||
| TCA9539 | I2C | esp_io_expander_tca95xx_16bit | [datasheet](https://www.ti.com/lit/gpn/tca9539) | | ||
| TCA9555 | I2C | esp_io_expander_tca95xx_16bit | [datasheet](https://www.ti.com/lit/gpn/tca9555) | | ||
|
||
## Add to project | ||
|
||
Packages from this repository are uploaded to [Espressif's component service](https://components.espressif.com/). | ||
You can add them to your project via `idf.py add-dependency`, e.g. | ||
``` | ||
idf.py add-dependency esp_io_expander_tca95xx_16bit==1.0.0 | ||
``` | ||
|
||
Alternatively, you can create `idf_component.yml`. More is in [Espressif's documentation](https://docs.espressif.com/projects/esp-idf/en/latest/esp32/api-guides/tools/idf-component-manager.html). | ||
|
||
## Example use | ||
|
||
Creation of the component. | ||
|
||
``` | ||
esp_io_expander_handle_t io_expander = NULL; | ||
esp_io_expander_new_i2c_tca95xx_16bit(1, ESP_IO_EXPANDER_I2C_TCA9539_ADDRESS_00, &io_expander); | ||
``` | ||
|
||
Set pin 0 and pin 1 with output dircetion and low level: | ||
|
||
``` | ||
esp_io_expander_set_dir(io_expander, IO_EXPANDER_PIN_NUM_0 | IO_EXPANDER_PIN_NUM_1, IO_EXPANDER_OUTPUT); | ||
esp_io_expander_set_level(io_expander, IO_EXPANDER_PIN_NUM_0 | IO_EXPANDER_PIN_NUM_1, 0); | ||
``` | ||
|
||
Print all pins's status to the log: | ||
|
||
``` | ||
esp_io_expander_print_state(io_expander); | ||
``` |
157 changes: 157 additions & 0 deletions
157
components/io_expander/esp_io_expander_tca95xx_16bit/esp_io_expander_tca95xx_16bit.c
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,157 @@ | ||
/* | ||
* SPDX-FileCopyrightText: 2015-2022 Espressif Systems (Shanghai) CO LTD | ||
* | ||
* SPDX-License-Identifier: Apache-2.0 | ||
*/ | ||
|
||
#include <inttypes.h> | ||
#include <string.h> | ||
#include <stdlib.h> | ||
|
||
#include "driver/i2c.h" | ||
#include "esp_bit_defs.h" | ||
#include "esp_check.h" | ||
#include "esp_log.h" | ||
|
||
#include "esp_io_expander.h" | ||
#include "esp_io_expander_tca95xx_16bit.h" | ||
|
||
/* Timeout of each I2C communication */ | ||
#define I2C_TIMEOUT_MS (10) | ||
|
||
#define IO_COUNT (16) | ||
|
||
/* Register address */ | ||
#define INPUT_REG_ADDR (0x00) | ||
#define OUTPUT_REG_ADDR (0x02) | ||
#define DIRECTION_REG_ADDR (0x06) | ||
|
||
/* Default register value on power-up */ | ||
#define DIR_REG_DEFAULT_VAL (0xffff) | ||
#define OUT_REG_DEFAULT_VAL (0xffff) | ||
|
||
/** | ||
* @brief Device Structure Type | ||
* | ||
*/ | ||
typedef struct { | ||
esp_io_expander_t base; | ||
i2c_port_t i2c_num; | ||
uint32_t i2c_address; | ||
struct { | ||
uint8_t direction; | ||
uint8_t output; | ||
} regs; | ||
} esp_io_expander_tca95xx_16bit_t; | ||
|
||
static char *TAG = "tca95xx_16"; | ||
|
||
static esp_err_t read_input_reg(esp_io_expander_handle_t handle, uint32_t *value); | ||
static esp_err_t write_output_reg(esp_io_expander_handle_t handle, uint32_t value); | ||
static esp_err_t read_output_reg(esp_io_expander_handle_t handle, uint32_t *value); | ||
static esp_err_t write_direction_reg(esp_io_expander_handle_t handle, uint32_t value); | ||
static esp_err_t read_direction_reg(esp_io_expander_handle_t handle, uint32_t *value); | ||
static esp_err_t reset(esp_io_expander_t *handle); | ||
static esp_err_t del(esp_io_expander_t *handle); | ||
|
||
esp_err_t esp_io_expander_new_i2c_tca95xx_16bit(i2c_port_t i2c_num, uint32_t i2c_address, esp_io_expander_handle_t *handle) | ||
{ | ||
ESP_RETURN_ON_FALSE(i2c_num < I2C_NUM_MAX, ESP_ERR_INVALID_ARG, TAG, "Invalid i2c num"); | ||
ESP_RETURN_ON_FALSE(handle, ESP_ERR_INVALID_ARG, TAG, "Invalid handle"); | ||
|
||
esp_io_expander_tca95xx_16bit_t *tca = (esp_io_expander_tca95xx_16bit_t *)calloc(1, sizeof(esp_io_expander_tca95xx_16bit_t)); | ||
ESP_RETURN_ON_FALSE(tca, ESP_ERR_NO_MEM, TAG, "Malloc failed"); | ||
|
||
tca->base.config.io_count = IO_COUNT; | ||
tca->base.config.flags.dir_out_bit_zero = 1; | ||
tca->i2c_num = i2c_num; | ||
tca->i2c_address = i2c_address; | ||
tca->base.read_input_reg = read_input_reg; | ||
tca->base.write_output_reg = write_output_reg; | ||
tca->base.read_output_reg = read_output_reg; | ||
tca->base.write_direction_reg = write_direction_reg; | ||
tca->base.read_direction_reg = read_direction_reg; | ||
tca->base.del = del; | ||
tca->base.reset = reset; | ||
|
||
esp_err_t ret = ESP_OK; | ||
/* Reset configuration and register status */ | ||
ESP_GOTO_ON_ERROR(reset(&tca->base), err, TAG, "Reset failed"); | ||
|
||
*handle = &tca->base; | ||
return ESP_OK; | ||
err: | ||
free(tca); | ||
return ret; | ||
} | ||
|
||
static esp_err_t read_input_reg(esp_io_expander_handle_t handle, uint32_t *value) | ||
{ | ||
esp_io_expander_tca95xx_16bit_t *tca = (esp_io_expander_tca95xx_16bit_t *)__containerof(handle, esp_io_expander_tca95xx_16bit_t, base); | ||
|
||
uint8_t temp[2] = {0, 0}; | ||
// *INDENT-OFF* | ||
ESP_RETURN_ON_ERROR( | ||
i2c_master_write_read_device(tca->i2c_num, tca->i2c_address, (uint8_t[]){INPUT_REG_ADDR}, 1, (uint8_t*)&temp, 2, pdMS_TO_TICKS(I2C_TIMEOUT_MS)), | ||
TAG, "Read input reg failed"); | ||
// *INDENT-ON* | ||
*value = (((uint32_t)temp[0]) << 8) | (temp[1]); | ||
return ESP_OK; | ||
} | ||
|
||
static esp_err_t write_output_reg(esp_io_expander_handle_t handle, uint32_t value) | ||
{ | ||
esp_io_expander_tca95xx_16bit_t *tca = (esp_io_expander_tca95xx_16bit_t *)__containerof(handle, esp_io_expander_tca95xx_16bit_t, base); | ||
value &= 0xffff; | ||
|
||
uint8_t data[] = {OUTPUT_REG_ADDR, value >> 8, value & 0xff}; | ||
ESP_RETURN_ON_ERROR( | ||
i2c_master_write_to_device(tca->i2c_num, tca->i2c_address, data, sizeof(data), pdMS_TO_TICKS(I2C_TIMEOUT_MS)), | ||
TAG, "Write output reg failed"); | ||
tca->regs.output = value; | ||
return ESP_OK; | ||
} | ||
|
||
static esp_err_t read_output_reg(esp_io_expander_handle_t handle, uint32_t *value) | ||
{ | ||
esp_io_expander_tca95xx_16bit_t *tca = (esp_io_expander_tca95xx_16bit_t *)__containerof(handle, esp_io_expander_tca95xx_16bit_t, base); | ||
|
||
*value = tca->regs.output; | ||
return ESP_OK; | ||
} | ||
|
||
static esp_err_t write_direction_reg(esp_io_expander_handle_t handle, uint32_t value) | ||
{ | ||
esp_io_expander_tca95xx_16bit_t *tca = (esp_io_expander_tca95xx_16bit_t *)__containerof(handle, esp_io_expander_tca95xx_16bit_t, base); | ||
value &= 0xffff; | ||
|
||
uint8_t data[] = {DIRECTION_REG_ADDR, value >> 8, value & 0xff}; | ||
ESP_RETURN_ON_ERROR( | ||
i2c_master_write_to_device(tca->i2c_num, tca->i2c_address, data, sizeof(data), pdMS_TO_TICKS(I2C_TIMEOUT_MS)), | ||
TAG, "Write direction reg failed"); | ||
tca->regs.direction = value; | ||
return ESP_OK; | ||
} | ||
|
||
static esp_err_t read_direction_reg(esp_io_expander_handle_t handle, uint32_t *value) | ||
{ | ||
esp_io_expander_tca95xx_16bit_t *tca = (esp_io_expander_tca95xx_16bit_t *)__containerof(handle, esp_io_expander_tca95xx_16bit_t, base); | ||
|
||
*value = tca->regs.direction; | ||
return ESP_OK; | ||
} | ||
|
||
static esp_err_t reset(esp_io_expander_t *handle) | ||
{ | ||
ESP_RETURN_ON_ERROR(write_direction_reg(handle, DIR_REG_DEFAULT_VAL), TAG, "Write dir reg failed"); | ||
ESP_RETURN_ON_ERROR(write_output_reg(handle, OUT_REG_DEFAULT_VAL), TAG, "Write output reg failed"); | ||
return ESP_OK; | ||
} | ||
|
||
static esp_err_t del(esp_io_expander_t *handle) | ||
{ | ||
esp_io_expander_tca95xx_16bit_t *tca = (esp_io_expander_tca95xx_16bit_t *)__containerof(handle, esp_io_expander_tca95xx_16bit_t, base); | ||
|
||
free(tca); | ||
return ESP_OK; | ||
} |
7 changes: 7 additions & 0 deletions
7
components/io_expander/esp_io_expander_tca95xx_16bit/idf_component.yml
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
dependencies: | ||
esp_io_expander: | ||
version: ^1.0.1 | ||
idf: '>=4.4.2' | ||
description: ESP IO Expander - tca9539 and tca9555 | ||
url: https://github.com/espressif/esp-bsp/tree/master/components/io_expander/esp_io_expander_tca95xx_16bit | ||
version: 1.0.0 |
78 changes: 78 additions & 0 deletions
78
components/io_expander/esp_io_expander_tca95xx_16bit/include/esp_io_expander_tca95xx_16bit.h
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,78 @@ | ||
/* | ||
* SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD | ||
* | ||
* SPDX-License-Identifier: Apache-2.0 | ||
*/ | ||
|
||
#pragma once | ||
|
||
#include <stdint.h> | ||
|
||
#include "driver/i2c.h" | ||
#include "esp_err.h" | ||
|
||
#include "esp_io_expander.h" | ||
|
||
#ifdef __cplusplus | ||
extern "C" { | ||
#endif | ||
|
||
/** | ||
* @brief Create a new TCA95xx_16bit IO expander driver | ||
* | ||
* @note The I2C communication should be initialized before use this function | ||
* | ||
* @param i2c_num: I2C port num | ||
* @param i2c_address: I2C address of chip (\see esp_io_expander_tca_95xx_16bit_address) | ||
* @param handle: IO expander handle | ||
* | ||
* @return | ||
* - ESP_OK: Success, otherwise returns ESP_ERR_xxx | ||
*/ | ||
esp_err_t esp_io_expander_new_i2c_tca95xx_16bit(i2c_port_t i2c_num, uint32_t i2c_address, esp_io_expander_handle_t *handle); | ||
|
||
/** | ||
* @brief I2C address of the TCA9539 or TCA9555 | ||
* | ||
* The 8-bit address format for the TCA9539 is as follows: | ||
* | ||
* (Slave Address) | ||
* ┌─────────────────┷─────────────────┐ | ||
* ┌─────┐─────┐─────┐─────┐─────┐─────┐─────┐─────┐ | ||
* | 1 | 1 | 1 | 0 | 1 | A1 | A0 | R/W | | ||
* └─────┘─────┘─────┘─────┘─────┘─────┘─────┘─────┘ | ||
* └────────┯──────────────┘ └──┯──┘ | ||
* (Fixed) (Hareware Selectable) | ||
* | ||
* The 8-bit address format for the TCA9555 is as follows: | ||
* | ||
* (Slave Address) | ||
* ┌─────────────────┷─────────────────┐ | ||
* ┌─────┐─────┐─────┐─────┐─────┐─────┐─────┐─────┐ | ||
* | 0 | 1 | 0 | 0 | A2 | A1 | A0 | R/W | | ||
* └─────┘─────┘─────┘─────┘─────┘─────┘─────┘─────┘ | ||
* └────────┯────────┘ └─────┯──────┘ | ||
* (Fixed) (Hareware Selectable) | ||
* | ||
* And the 7-bit slave address is the most important data for users. | ||
* For example, if a TCA9555 chip's A0,A1,A2 are connected to GND, it's 7-bit slave address is 0b0100000. | ||
* Then users can use `ESP_IO_EXPANDER_I2C_TCA9555_ADDRESS_000` to init it. | ||
*/ | ||
enum esp_io_expander_tca_95xx_16bit_address { | ||
ESP_IO_EXPANDER_I2C_TCA9539_ADDRESS_00 = 0b1110100, | ||
ESP_IO_EXPANDER_I2C_TCA9539_ADDRESS_01 = 0b1110101, | ||
ESP_IO_EXPANDER_I2C_TCA9539_ADDRESS_10 = 0b1110110, | ||
ESP_IO_EXPANDER_I2C_TCA9539_ADDRESS_11 = 0b1110111, | ||
ESP_IO_EXPANDER_I2C_TCA9555_ADDRESS_000 = 0b0100000, | ||
ESP_IO_EXPANDER_I2C_TCA9555_ADDRESS_001 = 0b0100001, | ||
ESP_IO_EXPANDER_I2C_TCA9555_ADDRESS_010 = 0b0100010, | ||
ESP_IO_EXPANDER_I2C_TCA9555_ADDRESS_011 = 0b0100011, | ||
ESP_IO_EXPANDER_I2C_TCA9555_ADDRESS_100 = 0b0100000, | ||
ESP_IO_EXPANDER_I2C_TCA9555_ADDRESS_101 = 0b0100101, | ||
ESP_IO_EXPANDER_I2C_TCA9555_ADDRESS_110 = 0b0100110, | ||
ESP_IO_EXPANDER_I2C_TCA9555_ADDRESS_111 = 0b0100111, | ||
}; | ||
|
||
#ifdef __cplusplus | ||
} | ||
#endif |
Oops, something went wrong.