Skip to content

Commit 30f0182

Browse files
authored
Merge pull request #684 from espressif/feat/esp_io_expander_pi4ioe5v6408-
feat(io_expander): Added new IO expander PI4OE5V6408
2 parents 0cf0dc9 + 0246b10 commit 30f0182

File tree

16 files changed

+918
-3
lines changed

16 files changed

+918
-3
lines changed

.github/workflows/upload_component.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,7 @@ jobs:
9393
components/io_expander/esp_io_expander_tca9554
9494
components/io_expander/esp_io_expander_tca95xx_16bit
9595
components/io_expander/esp_io_expander_ht8574
96+
components/io_expander/esp_io_expander_pi4ioe5v6408
9697
namespace: "espressif"
9798
api_token: ${{ secrets.IDF_COMPONENT_API_TOKEN }}
9899
dry_run: ${{ github.ref_name != 'master' || github.repository_owner != 'espressif' }}

components/io_expander/.build-test-rules.yml

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,3 +21,11 @@ components/io_expander/esp_io_expander_tca9554:
2121
disable:
2222
- if: IDF_VERSION < "5.2.0"
2323
reason: Requires I2C Driver-NG which was introduced in v5.2
24+
25+
components/io_expander/esp_io_expander_pi4ioe5v6408:
26+
depends_filepatterns:
27+
- "components/io_expander/esp_io_expander/**"
28+
- "components/io_expander/esp_io_expander_pi4ioe5v6408/**"
29+
disable:
30+
- if: IDF_VERSION < "5.2.0"
31+
reason: Requires I2C Driver-NG which was introduced in v5.2

components/io_expander/esp_io_expander/README.md

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,10 +6,22 @@ This componnent is main esp_io_expander component which defines main functions a
66

77
## Supported features
88

9+
### From v1.0
10+
911
- [x] Set an IO's direction
1012
- [x] Get an IO's direction
1113
- [x] Set an IO's output level
1214
- [x] Get an IO's input level
1315
- [x] Show all IOs' status
16+
17+
### From v1.1
18+
19+
- [x] Set an IO's output mode (Push Pull / Open Drain)
20+
- [x] Set an IO's Pull-up / Pull-down state
21+
22+
### Future
23+
1424
- [ ] Interrupt mode
1525

26+
27+

components/io_expander/esp_io_expander/esp_io_expander.c

Lines changed: 92 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* SPDX-FileCopyrightText: 2015-2022 Espressif Systems (Shanghai) CO LTD
2+
* SPDX-FileCopyrightText: 2015-2025 Espressif Systems (Shanghai) CO LTD
33
*
44
* SPDX-License-Identifier: Apache-2.0
55
*/
@@ -23,6 +23,9 @@ typedef enum {
2323
REG_INPUT = 0,
2424
REG_OUTPUT,
2525
REG_DIRECTION,
26+
REG_HIGHZ,
27+
REG_PULLUP_EN,
28+
REG_PULLUP_SEL,
2629
} reg_type_t;
2730

2831
static char *TAG = "io_expander";
@@ -126,6 +129,76 @@ esp_err_t esp_io_expander_get_level(esp_io_expander_handle_t handle, uint32_t pi
126129
return ESP_OK;
127130
}
128131

132+
esp_err_t esp_io_expander_set_pullupdown(esp_io_expander_handle_t handle, uint32_t pin_num_mask, esp_io_expander_pullupdown_t state)
133+
{
134+
ESP_RETURN_ON_FALSE(handle, ESP_ERR_INVALID_ARG, TAG, "Invalid handle");
135+
if (pin_num_mask >= BIT64(VALID_IO_COUNT(handle))) {
136+
ESP_LOGW(TAG, "Pin num mask out of range, bit higher than %d won't work", VALID_IO_COUNT(handle) - 1);
137+
}
138+
139+
uint32_t pull_en, pull_set, pull_en_tmp, pull_set_tmp;
140+
ESP_RETURN_ON_ERROR(read_reg(handle, REG_PULLUP_EN, &pull_en), TAG, "Read Pull-up enable reg failed");
141+
ESP_RETURN_ON_ERROR(read_reg(handle, REG_PULLUP_SEL, &pull_set), TAG, "Read Pull-up select reg failed");
142+
pull_en_tmp = pull_en;
143+
pull_set_tmp = pull_set;
144+
145+
if ((state == IO_EXPANDER_PULL_UP && !handle->config.flags.pullup_high_bit_zero) || (state == IO_EXPANDER_PULL_DOWN && handle->config.flags.pullup_high_bit_zero)) {
146+
/* 1. High level && Set 1 to output high */
147+
/* 2. Low level && Set 1 to output low */
148+
pull_set |= pin_num_mask;
149+
} else {
150+
/* 3. High level && Set 0 to output high */
151+
/* 4. Low level && Set 0 to output low */
152+
pull_set &= ~pin_num_mask;
153+
}
154+
155+
/* Write to reg only when different */
156+
if (pull_set != pull_set_tmp) {
157+
ESP_RETURN_ON_ERROR(write_reg(handle, REG_PULLUP_SEL, pull_set), TAG, "Write Pull-up select reg failed");
158+
}
159+
160+
if (state == IO_EXPANDER_PULL_UP || state == IO_EXPANDER_PULL_DOWN) {
161+
/* Enable pull-up/pull-down */
162+
pull_en |= pin_num_mask;
163+
} else {
164+
/* Disable pull-up/pull-down */
165+
pull_en &= ~pin_num_mask;
166+
}
167+
168+
/* Write to reg only when different */
169+
if (pull_en != pull_en_tmp) {
170+
ESP_RETURN_ON_ERROR(write_reg(handle, REG_PULLUP_EN, pull_en), TAG, "Write Pull-up enable reg failed");
171+
}
172+
173+
return ESP_OK;
174+
}
175+
176+
esp_err_t esp_io_expander_set_output_mode(esp_io_expander_handle_t handle, uint32_t pin_num_mask, esp_io_expander_output_mode_t mode)
177+
{
178+
ESP_RETURN_ON_FALSE(handle, ESP_ERR_INVALID_ARG, TAG, "Invalid handle");
179+
if (pin_num_mask >= BIT64(VALID_IO_COUNT(handle))) {
180+
ESP_LOGW(TAG, "Pin num mask out of range, bit higher than %d won't work", VALID_IO_COUNT(handle) - 1);
181+
}
182+
183+
bool is_highz = (mode == IO_EXPANDER_OUTPUT_MODE_OPEN_DRAIN) ? true : false;
184+
uint32_t highz_reg, temp;
185+
ESP_RETURN_ON_ERROR(read_reg(handle, REG_HIGHZ, &highz_reg), TAG, "Read High-Z reg failed");
186+
temp = highz_reg;
187+
if (is_highz) {
188+
/* Open drain && Set 1 */
189+
highz_reg |= pin_num_mask;
190+
} else {
191+
/* Push pull && Set 0 */
192+
highz_reg &= ~pin_num_mask;
193+
}
194+
/* Write to reg only when different */
195+
if (highz_reg != temp) {
196+
ESP_RETURN_ON_ERROR(write_reg(handle, REG_HIGHZ, highz_reg), TAG, "Write High-Z reg failed");
197+
}
198+
199+
return ESP_OK;
200+
}
201+
129202
esp_err_t esp_io_expander_print_state(esp_io_expander_handle_t handle)
130203
{
131204
ESP_RETURN_ON_FALSE(handle, ESP_ERR_INVALID_ARG, TAG, "Invalid handle");
@@ -190,6 +263,15 @@ static esp_err_t write_reg(esp_io_expander_handle_t handle, reg_type_t reg, uint
190263
case REG_DIRECTION:
191264
ESP_RETURN_ON_FALSE(handle->write_direction_reg, ESP_ERR_NOT_SUPPORTED, TAG, "write_direction_reg isn't implemented");
192265
return handle->write_direction_reg(handle, value);
266+
case REG_HIGHZ:
267+
ESP_RETURN_ON_FALSE(handle->write_highz_reg, ESP_ERR_NOT_SUPPORTED, TAG, "write_highz_reg isn't implemented");
268+
return handle->write_highz_reg(handle, value);
269+
case REG_PULLUP_EN:
270+
ESP_RETURN_ON_FALSE(handle->write_pullup_en_reg, ESP_ERR_NOT_SUPPORTED, TAG, "write_pullup_en_reg isn't implemented");
271+
return handle->write_pullup_en_reg(handle, value);
272+
case REG_PULLUP_SEL:
273+
ESP_RETURN_ON_FALSE(handle->write_pullup_sel_reg, ESP_ERR_NOT_SUPPORTED, TAG, "write_pullup_sel_reg isn't implemented");
274+
return handle->write_pullup_sel_reg(handle, value);
193275
default:
194276
return ESP_ERR_NOT_SUPPORTED;
195277
}
@@ -220,6 +302,15 @@ static esp_err_t read_reg(esp_io_expander_handle_t handle, reg_type_t reg, uint3
220302
case REG_DIRECTION:
221303
ESP_RETURN_ON_FALSE(handle->read_direction_reg, ESP_ERR_NOT_SUPPORTED, TAG, "read_direction_reg isn't implemented");
222304
return handle->read_direction_reg(handle, value);
305+
case REG_HIGHZ:
306+
ESP_RETURN_ON_FALSE(handle->read_highz_reg, ESP_ERR_NOT_SUPPORTED, TAG, "read_highz_reg isn't implemented");
307+
return handle->read_highz_reg(handle, value);
308+
case REG_PULLUP_EN:
309+
ESP_RETURN_ON_FALSE(handle->read_pullup_en_reg, ESP_ERR_NOT_SUPPORTED, TAG, "read_pullup_en_reg isn't implemented");
310+
return handle->read_pullup_en_reg(handle, value);
311+
case REG_PULLUP_SEL:
312+
ESP_RETURN_ON_FALSE(handle->read_pullup_sel_reg, ESP_ERR_NOT_SUPPORTED, TAG, "read_pullup_sel_reg isn't implemented");
313+
return handle->read_pullup_sel_reg(handle, value);
223314
default:
224315
return ESP_ERR_NOT_SUPPORTED;
225316
}

components/io_expander/esp_io_expander/idf_component.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
version: "1.0.1"
1+
version: "1.1.0"
22
description: ESP IO Expander - main component for using io expander chip
33
url: https://github.com/espressif/esp-bsp/tree/master/components/io_expander/esp_io_expander
44
dependencies:

components/io_expander/esp_io_expander/include/esp_io_expander.h

Lines changed: 132 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD
2+
* SPDX-FileCopyrightText: 2022-2025 Espressif Systems (Shanghai) CO LTD
33
*
44
* SPDX-License-Identifier: Apache-2.0
55
*/
@@ -77,6 +77,25 @@ typedef enum {
7777
IO_EXPANDER_OUTPUT, /*!< Output dircetion */
7878
} esp_io_expander_dir_t;
7979

80+
/**
81+
* @brief IO Expander Pin output mode
82+
*
83+
*/
84+
typedef enum {
85+
IO_EXPANDER_OUTPUT_MODE_PUSH_PULL, /*!< Output High-Z = 0 */
86+
IO_EXPANDER_OUTPUT_MODE_OPEN_DRAIN, /*!< Output High-Z = 1 */
87+
} esp_io_expander_output_mode_t;
88+
89+
/**
90+
* @brief IO Expander Pin pull-up/pull-down
91+
*
92+
*/
93+
typedef enum {
94+
IO_EXPANDER_PULL_NONE, /*!< Not used pull-up/pull-down */
95+
IO_EXPANDER_PULL_UP, /*!< Set pull-up */
96+
IO_EXPANDER_PULL_DOWN, /*!< Set pull-down */
97+
} esp_io_expander_pullupdown_t;
98+
8099
/**
81100
* @brief IO Expander Configuration Type
82101
*
@@ -87,6 +106,7 @@ typedef struct {
87106
uint8_t dir_out_bit_zero : 1; /*!< If the direction of IO is output, the corresponding bit of the direction register is 0 */
88107
uint8_t input_high_bit_zero : 1; /*!< If the input level of IO is high, the corresponding bit of the input register is 0 */
89108
uint8_t output_high_bit_zero : 1; /*!< If the output level of IO is high, the corresponding bit of the output register is 0 */
109+
uint8_t pullup_high_bit_zero : 1; /*!< If the pullup/down level of IO is high, the corresponding bit of the output register is 0 */
90110
} flags;
91111
/* Don't support with interrupt mode yet, will be added soon */
92112
} esp_io_expander_config_t;
@@ -165,6 +185,87 @@ struct esp_io_expander_s {
165185
*/
166186
esp_err_t (*read_direction_reg)(esp_io_expander_handle_t handle, uint32_t *value);
167187

188+
/**
189+
* @brief Write value to high impedance register (optional)
190+
*
191+
* @note If there are multiple high impedance registers in the device, their values should be spliced together in order to form the `value`.
192+
*
193+
* @param handle: IO Expander handle
194+
* @param value: Register's value
195+
*
196+
* @return
197+
* - ESP_OK: Success, otherwise returns ESP_ERR_xxx
198+
*/
199+
esp_err_t (*write_highz_reg)(esp_io_expander_handle_t handle, uint32_t value);
200+
201+
/**
202+
* @brief Read value from high impedance register (optional)
203+
*
204+
* @note This function can be implemented by reading the physical direction register, or simply by reading a variable that record the direction value (more faster)
205+
* @note If there are multiple high impedance registers in the device, their values should be spliced together in order to form the `value`.
206+
*
207+
* @param handle: IO Expander handle
208+
* @param value: Register's value
209+
*
210+
* @return
211+
* - ESP_OK: Success, otherwise returns ESP_ERR_xxx
212+
*/
213+
esp_err_t (*read_highz_reg)(esp_io_expander_handle_t handle, uint32_t *value);
214+
215+
/**
216+
* @brief Write value to enable pullup register (optional)
217+
*
218+
* @note If there are multiple enable pullup registers in the device, their values should be spliced together in order to form the `value`.
219+
*
220+
* @param handle: IO Expander handle
221+
* @param value: Register's value
222+
*
223+
* @return
224+
* - ESP_OK: Success, otherwise returns ESP_ERR_xxx
225+
*/
226+
esp_err_t (*write_pullup_en_reg)(esp_io_expander_handle_t handle, uint32_t value);
227+
228+
/**
229+
* @brief Read value from enable pullup register (optional)
230+
*
231+
* @note This function can be implemented by reading the physical direction register, or simply by reading a variable that record the direction value (more faster)
232+
* @note If there are multiple enable pullup registers in the device, their values should be spliced together in order to form the `value`.
233+
*
234+
* @param handle: IO Expander handle
235+
* @param value: Register's value
236+
*
237+
* @return
238+
* - ESP_OK: Success, otherwise returns ESP_ERR_xxx
239+
*/
240+
esp_err_t (*read_pullup_en_reg)(esp_io_expander_handle_t handle, uint32_t *value);
241+
242+
/**
243+
* @brief Write value to select pullup register (optional)
244+
*
245+
* @note If there are multiple set pullup registers in the device, their values should be spliced together in order to form the `value`.
246+
*
247+
* @param handle: IO Expander handle
248+
* @param value: Register's value
249+
*
250+
* @return
251+
* - ESP_OK: Success, otherwise returns ESP_ERR_xxx
252+
*/
253+
esp_err_t (*write_pullup_sel_reg)(esp_io_expander_handle_t handle, uint32_t value);
254+
255+
/**
256+
* @brief Read value from select pullup register (optional)
257+
*
258+
* @note This function can be implemented by reading the physical direction register, or simply by reading a variable that record the direction value (more faster)
259+
* @note If there are multiple set pullup registers in the device, their values should be spliced together in order to form the `value`.
260+
*
261+
* @param handle: IO Expander handle
262+
* @param value: Register's value
263+
*
264+
* @return
265+
* - ESP_OK: Success, otherwise returns ESP_ERR_xxx
266+
*/
267+
esp_err_t (*read_pullup_sel_reg)(esp_io_expander_handle_t handle, uint32_t *value);
268+
168269
/**
169270
* @brief Reset the device to its initial state (mandatory)
170271
*
@@ -233,6 +334,36 @@ esp_err_t esp_io_expander_set_level(esp_io_expander_handle_t handle, uint32_t pi
233334
*/
234335
esp_err_t esp_io_expander_get_level(esp_io_expander_handle_t handle, uint32_t pin_num_mask, uint32_t *level_mask);
235336

337+
/**
338+
* @brief Set the pull-up/pull-down of a set of target IOs
339+
*
340+
* @note
341+
*
342+
* @param handle: IO Exapnder handle
343+
* @param pin_num_mask: Bitwise OR of allowed pin num with type of `esp_io_expander_pin_num_t`
344+
* @param state: State of pull-up/pull-down
345+
*
346+
* @return
347+
* - ESP_OK: Success, otherwise returns ESP_ERR_xxx
348+
*/
349+
esp_err_t esp_io_expander_set_pullupdown(esp_io_expander_handle_t handle, uint32_t pin_num_mask, esp_io_expander_pullupdown_t state);
350+
351+
352+
/**
353+
* @brief Set the output mode (High-Z) of a set of target IOs
354+
*
355+
* @note
356+
*
357+
* @param handle: IO Exapnder handle
358+
* @param pin_num_mask: Bitwise OR of allowed pin num with type of `esp_io_expander_pin_num_t`
359+
* @param mode: Output mode
360+
*
361+
* @return
362+
* - ESP_OK: Success, otherwise returns ESP_ERR_xxx
363+
*/
364+
esp_err_t esp_io_expander_set_output_mode(esp_io_expander_handle_t handle, uint32_t pin_num_mask, esp_io_expander_output_mode_t mode);
365+
366+
236367
/**
237368
* @brief Print the current status of each IO of the device, including direction, input level and output level
238369
*
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
set(req)
2+
if("${IDF_VERSION_MAJOR}.${IDF_VERSION_MINOR}" VERSION_GREATER_EQUAL "5.2.6")
3+
list(APPEND req "esp_driver_i2c")
4+
else()
5+
list(APPEND req "driver")
6+
endif()
7+
8+
idf_component_register(SRCS "esp_io_expander_pi4ioe5v6408.c" INCLUDE_DIRS "include" REQUIRES ${req})

0 commit comments

Comments
 (0)