forked from espressif/esp-idf
Merge branch 'feat/dedic_gpio_enable_pad_input' into 'master'
feat(dedic_gpio): enable pad input for a input signal Closes IDF-11282 See merge request espressif/esp-idf!34140
This commit is contained in:
@@ -269,6 +269,7 @@ esp_err_t dedic_gpio_new_bundle(const dedic_gpio_bundle_config_t *config, dedic_
|
|||||||
if (config->flags.in_en) {
|
if (config->flags.in_en) {
|
||||||
for (size_t i = 0; i < config->array_size; i++) {
|
for (size_t i = 0; i < config->array_size; i++) {
|
||||||
gpio_func_sel(config->gpio_array[i], PIN_FUNC_GPIO);
|
gpio_func_sel(config->gpio_array[i], PIN_FUNC_GPIO);
|
||||||
|
gpio_input_enable(config->gpio_array[i]);
|
||||||
esp_rom_gpio_connect_in_signal(config->gpio_array[i], dedic_gpio_periph_signals.cores[core_id].in_sig_per_channel[in_offset + i], config->flags.in_invert);
|
esp_rom_gpio_connect_in_signal(config->gpio_array[i], dedic_gpio_periph_signals.cores[core_id].in_sig_per_channel[in_offset + i], config->flags.in_invert);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -325,6 +326,17 @@ esp_err_t dedic_gpio_del_bundle(dedic_gpio_bundle_handle_t bundle)
|
|||||||
}
|
}
|
||||||
portEXIT_CRITICAL(&s_platform[core_id]->spinlock);
|
portEXIT_CRITICAL(&s_platform[core_id]->spinlock);
|
||||||
|
|
||||||
|
if (bundle->in_mask > 0) {
|
||||||
|
for (size_t i = 0; i < bundle->nr_gpio; i++) {
|
||||||
|
esp_rom_gpio_connect_in_signal(GPIO_MATRIX_CONST_ZERO_INPUT, dedic_gpio_periph_signals.cores[core_id].in_sig_per_channel[bundle->in_offset + i], 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (bundle->out_mask > 0) {
|
||||||
|
for (size_t i = 0; i < bundle->nr_gpio; i++) {
|
||||||
|
gpio_output_disable(bundle->gpio_array[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
free(bundle);
|
free(bundle);
|
||||||
|
|
||||||
if (recycle_all) {
|
if (recycle_all) {
|
||||||
|
@@ -70,16 +70,8 @@ static void test_dedic_gpio_on_specific_core(void *args)
|
|||||||
uint32_t value = 0;
|
uint32_t value = 0;
|
||||||
dedic_gpio_cpu_ll_write_all(0x0); // clear all out channels
|
dedic_gpio_cpu_ll_write_all(0x0); // clear all out channels
|
||||||
|
|
||||||
// configure a group of GPIOs, output only
|
|
||||||
const int bundleA_gpios[] = {ctx->gpios[0], ctx->gpios[1]};
|
|
||||||
gpio_config_t io_conf = {
|
|
||||||
.mode = GPIO_MODE_OUTPUT,
|
|
||||||
};
|
|
||||||
for (int i = 0; i < sizeof(bundleA_gpios) / sizeof(bundleA_gpios[0]); i++) {
|
|
||||||
io_conf.pin_bit_mask = 1ULL << bundleA_gpios[i];
|
|
||||||
gpio_config(&io_conf);
|
|
||||||
}
|
|
||||||
// Create bundleA, output only
|
// Create bundleA, output only
|
||||||
|
const int bundleA_gpios[] = {ctx->gpios[0], ctx->gpios[1]};
|
||||||
dedic_gpio_bundle_handle_t bundleA = NULL;
|
dedic_gpio_bundle_handle_t bundleA = NULL;
|
||||||
dedic_gpio_bundle_config_t bundleA_config = {
|
dedic_gpio_bundle_config_t bundleA_config = {
|
||||||
.gpio_array = bundleA_gpios,
|
.gpio_array = bundleA_gpios,
|
||||||
@@ -90,15 +82,8 @@ static void test_dedic_gpio_on_specific_core(void *args)
|
|||||||
};
|
};
|
||||||
TEST_ESP_OK(dedic_gpio_new_bundle(&bundleA_config, &bundleA));
|
TEST_ESP_OK(dedic_gpio_new_bundle(&bundleA_config, &bundleA));
|
||||||
|
|
||||||
// configure another group of GPIOs, input and output
|
|
||||||
const int bundleB_gpios[] = {ctx->gpios[2], ctx->gpios[3]};
|
|
||||||
io_conf.mode = GPIO_MODE_INPUT_OUTPUT;
|
|
||||||
for (int i = 0; i < sizeof(bundleB_gpios) / sizeof(bundleB_gpios[0]); i++) {
|
|
||||||
io_conf.pin_bit_mask = 1ULL << bundleB_gpios[i];
|
|
||||||
gpio_config(&io_conf);
|
|
||||||
}
|
|
||||||
|
|
||||||
// GPIO bundleB, input and output
|
// GPIO bundleB, input and output
|
||||||
|
const int bundleB_gpios[] = {ctx->gpios[2], ctx->gpios[3]};
|
||||||
dedic_gpio_bundle_handle_t bundleB = NULL;
|
dedic_gpio_bundle_handle_t bundleB = NULL;
|
||||||
dedic_gpio_bundle_config_t bundleB_config = {
|
dedic_gpio_bundle_config_t bundleB_config = {
|
||||||
.gpio_array = bundleB_gpios,
|
.gpio_array = bundleB_gpios,
|
||||||
@@ -192,13 +177,6 @@ TEST_CASE("Dedicated_GPIO_interrupt_and_callback", "[dedic_gpio]")
|
|||||||
#else
|
#else
|
||||||
const int bundle_gpios[] = {0, 1};
|
const int bundle_gpios[] = {0, 1};
|
||||||
#endif
|
#endif
|
||||||
gpio_config_t io_conf = {
|
|
||||||
.mode = GPIO_MODE_INPUT_OUTPUT,
|
|
||||||
};
|
|
||||||
for (int i = 0; i < sizeof(bundle_gpios) / sizeof(bundle_gpios[0]); i++) {
|
|
||||||
io_conf.pin_bit_mask = 1ULL << bundle_gpios[i];
|
|
||||||
gpio_config(&io_conf);
|
|
||||||
}
|
|
||||||
dedic_gpio_bundle_handle_t bundle = NULL;
|
dedic_gpio_bundle_handle_t bundle = NULL;
|
||||||
dedic_gpio_bundle_config_t bundle_config = {
|
dedic_gpio_bundle_config_t bundle_config = {
|
||||||
.gpio_array = bundle_gpios,
|
.gpio_array = bundle_gpios,
|
||||||
|
@@ -16,32 +16,21 @@ A GPIO bundle is a group of GPIOs, which can be manipulated at the same time in
|
|||||||
|
|
||||||
.. note::
|
.. note::
|
||||||
|
|
||||||
Dedicated GPIO is more of a CPU peripheral, so it has a strong relationship with CPU core. It's highly recommended to install and operate GPIO bundle in a pin-to-core task. For example, if GPIOA is connected to CPU0, and the dedicated GPIO instruction is issued from CPU1, then it's impossible to control GPIOA.
|
Dedicated GPIO is more like a CPU peripheral, it has a strong relationship with CPU core. It's highly recommended to install and operate GPIO bundle in the same task, and the task should be pined to a CPU core. For example, if GPIO_A is connected to CPU_0, but the dedicated GPIO instruction is issued from CPU_1, then it's impossible to control GPIO_A.
|
||||||
|
|
||||||
To install a GPIO bundle, one needs to call :cpp:func:`dedic_gpio_new_bundle` to allocate the software resources and connect the dedicated channels to user selected GPIOs. Configurations for a GPIO bundle are covered in :cpp:type:`dedic_gpio_bundle_config_t` structure:
|
To install a GPIO bundle, one needs to call :cpp:func:`dedic_gpio_new_bundle` to allocate the software resources and connect the dedicated channels to user selected GPIOs. Configurations for a GPIO bundle are covered in :cpp:type:`dedic_gpio_bundle_config_t` structure:
|
||||||
|
|
||||||
- :cpp:member:`gpio_array`: An array that contains GPIO number.
|
- :cpp:member:`dedic_gpio_bundle_config_t::gpio_array`: An array that contains GPIO number.
|
||||||
- :cpp:member:`array_size`: Element number of :cpp:member:`gpio_array`.
|
- :cpp:member:`dedic_gpio_bundle_config_t::array_size`: Element number of :cpp:member:`dedic_gpio_bundle_config_t::gpio_array`.
|
||||||
- :cpp:member:`flags`: Extra flags to control the behavior of GPIO Bundle.
|
- :cpp:member:`dedic_gpio_bundle_config_t::in_en` and :cpp:member:`dedic_gpio_bundle_config_t::out_en` are used to configure whether to enable the input and output ability of the GPIO(s).
|
||||||
|
- :cpp:member:`dedic_gpio_bundle_config_t::in_invert` and :cpp:member:`dedic_gpio_bundle_config_t::out_invert` are used to configure whether to invert the GPIO signal.
|
||||||
|
|
||||||
- :cpp:member:`in_en` and :cpp:member:`out_en` are used to select whether to enable the input and output function (note, they can be enabled together).
|
The following code shows how to install an output only GPIO bundle:
|
||||||
- :cpp:member:`in_invert` and :cpp:member:`out_invert` are used to select whether to invert the GPIO signal.
|
|
||||||
|
|
||||||
The following code shows how to install a output only GPIO bundle:
|
|
||||||
|
|
||||||
.. highlight:: c
|
.. highlight:: c
|
||||||
|
|
||||||
::
|
::
|
||||||
|
|
||||||
// configure GPIO
|
|
||||||
const int bundleA_gpios[] = {0, 1};
|
|
||||||
gpio_config_t io_conf = {
|
|
||||||
.mode = GPIO_MODE_OUTPUT,
|
|
||||||
};
|
|
||||||
for (int i = 0; i < sizeof(bundleA_gpios) / sizeof(bundleA_gpios[0]); i++) {
|
|
||||||
io_conf.pin_bit_mask = 1ULL << bundleA_gpios[i];
|
|
||||||
gpio_config(&io_conf);
|
|
||||||
}
|
|
||||||
// Create bundleA, output only
|
// Create bundleA, output only
|
||||||
dedic_gpio_bundle_handle_t bundleA = NULL;
|
dedic_gpio_bundle_handle_t bundleA = NULL;
|
||||||
dedic_gpio_bundle_config_t bundleA_config = {
|
dedic_gpio_bundle_config_t bundleA_config = {
|
||||||
@@ -53,11 +42,7 @@ The following code shows how to install a output only GPIO bundle:
|
|||||||
};
|
};
|
||||||
ESP_ERROR_CHECK(dedic_gpio_new_bundle(&bundleA_config, &bundleA));
|
ESP_ERROR_CHECK(dedic_gpio_new_bundle(&bundleA_config, &bundleA));
|
||||||
|
|
||||||
To uninstall the GPIO bundle, one needs to call :cpp:func:`dedic_gpio_del_bundle`.
|
To uninstall the GPIO bundle, you should call :cpp:func:`dedic_gpio_del_bundle`.
|
||||||
|
|
||||||
.. note::
|
|
||||||
|
|
||||||
:cpp:func:`dedic_gpio_new_bundle` doesn't cover any GPIO pad configuration (e.g., pull up/down, drive ability, output/input enable), so before installing a dedicated GPIO bundle, you have to configure the GPIO separately using GPIO driver API (e.g., :cpp:func:`gpio_config`). For more information about GPIO driver, please refer to :doc:`GPIO API Reference <gpio>`.
|
|
||||||
|
|
||||||
|
|
||||||
GPIO Bundle Operations
|
GPIO Bundle Operations
|
||||||
@@ -92,13 +77,13 @@ For advanced users, they can always manipulate the GPIOs by writing assembly cod
|
|||||||
3. Call CPU LL apis (e.g., `dedic_gpio_cpu_ll_write_mask`) or write assembly code with that mask
|
3. Call CPU LL apis (e.g., `dedic_gpio_cpu_ll_write_mask`) or write assembly code with that mask
|
||||||
4. The fastest way of toggling IO is to use the dedicated "set/clear" instructions:
|
4. The fastest way of toggling IO is to use the dedicated "set/clear" instructions:
|
||||||
|
|
||||||
.. only:: esp32s2 or esp32s3
|
.. only:: CONFIG_IDF_TARGET_ARCH_XTENSA
|
||||||
|
|
||||||
- Set bits of GPIO: ``set_bit_gpio_out imm[7:0]``
|
- Set bits of GPIO: ``set_bit_gpio_out imm[7:0]``
|
||||||
- Clear bits of GPIO: ``clr_bit_gpio_out imm[7:0]``
|
- Clear bits of GPIO: ``clr_bit_gpio_out imm[7:0]``
|
||||||
- Note: Immediate value width depends on the number of dedicated GPIO channels
|
- Note: Immediate value width depends on the number of dedicated GPIO channels
|
||||||
|
|
||||||
.. only:: esp32c2 or esp32c3 or esp32c6 or esp32h2
|
.. only:: CONFIG_IDF_TARGET_ARCH_RISCV
|
||||||
|
|
||||||
- Set bits of GPIO: ``csrrsi rd, csr, imm[4:0]``
|
- Set bits of GPIO: ``csrrsi rd, csr, imm[4:0]``
|
||||||
- Clear bits of GPIO: ``csrrci rd, csr, imm[4:0]``
|
- Clear bits of GPIO: ``csrrci rd, csr, imm[4:0]``
|
||||||
|
@@ -16,16 +16,14 @@ GPIO 捆绑包是一组 GPIO,该组 GPIO 可以在一个 CPU 周期内同时
|
|||||||
|
|
||||||
.. note::
|
.. note::
|
||||||
|
|
||||||
专用 GPIO 更像是 CPU 外设,因此与 CPU 内核关系密切。强烈建议在 pin-to-core 任务中安装和操作 GPIO 捆绑包。例如,如果 GPIOA 连接到了 CPU0,而专用的 GPIO 指令却是从 CPU1 发出的,那么就无法控制 GPIOA。
|
专用 GPIO 更像是 CPU 外设,因此与 CPU 内核关系密切。强烈建议在 pin-to-core 任务中安装和操作 GPIO 捆绑包。例如,如果 GPIO_A 连接到了 CPU_0,而专用的 GPIO 指令却是从 CPU_1 发出的,那么就无法控制 GPIO_A。
|
||||||
|
|
||||||
安装 GPIO 捆绑包需要调用 :cpp:func:`dedic_gpio_new_bundle` 来分配软件资源并将专用通道连接到用户选择的 GPIO。GPIO 捆绑包的配置在 :cpp:type:`dedic_gpio_bundle_config_t` 结构体中:
|
安装 GPIO 捆绑包需要调用 :cpp:func:`dedic_gpio_new_bundle` 来分配软件资源并将专用通道连接到用户选择的 GPIO。GPIO 捆绑包的配置在 :cpp:type:`dedic_gpio_bundle_config_t` 结构体中:
|
||||||
|
|
||||||
- :cpp:member:`gpio_array`:包含 GPIO 编号的数组。
|
- :cpp:member:`dedic_gpio_bundle_config_t::gpio_array`:包含 GPIO 编号的数组。
|
||||||
- :cpp:member:`array_size`::cpp:member:`gpio_array` 的元素个数。
|
- :cpp:member:`dedic_gpio_bundle_config_t::array_size`: :cpp:member:`dedic_gpio_bundle_config_t::gpio_array` 的元素个数。
|
||||||
- :cpp:member:`flags`:用于控制 GPIO 捆绑包行为的标志。
|
- :cpp:member:`dedic_gpio_bundle_config_t::in_en` 和 :cpp:member:`dedic_gpio_bundle_config_t::out_en` 用于选择是否开启输入输出功能(这两个功能可以同时开启)。
|
||||||
|
- :cpp:member:`dedic_gpio_bundle_config_t::in_invert` 和 :cpp:member:`dedic_gpio_bundle_config_t::out_invert` 用于选择是否反转 GPIO 信号。
|
||||||
- :cpp:member:`in_en` 和 :cpp:member:`out_en` 用于选择是否开启输入输出功能(这两个功能可以同时开启)。
|
|
||||||
- :cpp:member:`in_invert` 和 :cpp:member:`out_invert` 用于选择是否反转 GPIO 信号。
|
|
||||||
|
|
||||||
以下代码展示了如何安装只有输出功能的 GPIO 捆绑包:
|
以下代码展示了如何安装只有输出功能的 GPIO 捆绑包:
|
||||||
|
|
||||||
@@ -33,15 +31,6 @@ GPIO 捆绑包是一组 GPIO,该组 GPIO 可以在一个 CPU 周期内同时
|
|||||||
|
|
||||||
::
|
::
|
||||||
|
|
||||||
// 配置 GPIO
|
|
||||||
const int bundleA_gpios[] = {0, 1};
|
|
||||||
gpio_config_t io_conf = {
|
|
||||||
.mode = GPIO_MODE_OUTPUT,
|
|
||||||
};
|
|
||||||
for (int i = 0; i < sizeof(bundleA_gpios) / sizeof(bundleA_gpios[0]); i++) {
|
|
||||||
io_conf.pin_bit_mask = 1ULL << bundleA_gpios[i];
|
|
||||||
gpio_config(&io_conf);
|
|
||||||
}
|
|
||||||
// 创建 bundleA,仅输出
|
// 创建 bundleA,仅输出
|
||||||
dedic_gpio_bundle_handle_t bundleA = NULL;
|
dedic_gpio_bundle_handle_t bundleA = NULL;
|
||||||
dedic_gpio_bundle_config_t bundleA_config = {
|
dedic_gpio_bundle_config_t bundleA_config = {
|
||||||
@@ -55,10 +44,6 @@ GPIO 捆绑包是一组 GPIO,该组 GPIO 可以在一个 CPU 周期内同时
|
|||||||
|
|
||||||
如需卸载 GPIO 捆绑包,可调用 :cpp:func:`dedic_gpio_del_bundle`。
|
如需卸载 GPIO 捆绑包,可调用 :cpp:func:`dedic_gpio_del_bundle`。
|
||||||
|
|
||||||
.. note::
|
|
||||||
|
|
||||||
:cpp:func:`dedic_gpio_new_bundle` 不包含任何 GPIO pad 配置(例如上拉/下拉、驱动能力、输出/输入使能)。因此,在安装专用 GPIO 捆绑包之前,必须使用 GPIO 驱动程序 API(如 :cpp:func:`gpio_config`)单独配置 GPIO。更多关于 GPIO 驱动的信息,请参考 :doc:`GPIO API 参考 <gpio>`。
|
|
||||||
|
|
||||||
|
|
||||||
GPIO 捆绑包操作
|
GPIO 捆绑包操作
|
||||||
----------------------
|
----------------------
|
||||||
@@ -92,13 +77,13 @@ GPIO 捆绑包操作
|
|||||||
3. 调用 CPU LL apis(如 `cpu_ll_write_dedic_gpio_mask`)或使用该掩码编写汇编代码
|
3. 调用 CPU LL apis(如 `cpu_ll_write_dedic_gpio_mask`)或使用该掩码编写汇编代码
|
||||||
4. 切换 IO 的最快捷方式是使用专用的“设置/清除”指令:
|
4. 切换 IO 的最快捷方式是使用专用的“设置/清除”指令:
|
||||||
|
|
||||||
.. only:: esp32s2 or esp32s3
|
.. only:: CONFIG_IDF_TARGET_ARCH_XTENSA
|
||||||
|
|
||||||
- 设置 GPIO 位:``set_bit_gpio_out imm[7:0]``
|
- 设置 GPIO 位:``set_bit_gpio_out imm[7:0]``
|
||||||
- 清除 GPIO 位:``clr_bit_gpio_out imm[7:0]``
|
- 清除 GPIO 位:``clr_bit_gpio_out imm[7:0]``
|
||||||
- 注意:立即数宽度取决于专用 GPIO 通道的数量
|
- 注意:立即数宽度取决于专用 GPIO 通道的数量
|
||||||
|
|
||||||
.. only:: esp32c2 or esp32c3 or esp32c6 or esp32h2
|
.. only:: CONFIG_IDF_TARGET_ARCH_RISCV
|
||||||
|
|
||||||
- 设置 GPIO 位:``csrrsi rd, csr, imm[4:0]``
|
- 设置 GPIO 位:``csrrsi rd, csr, imm[4:0]``
|
||||||
- 清除 GPIO 位:``csrrci rd, csr, imm[4:0]``
|
- 清除 GPIO 位:``csrrci rd, csr, imm[4:0]``
|
||||||
|
@@ -1,11 +1,9 @@
|
|||||||
/* GPIO Example
|
/*
|
||||||
|
* SPDX-FileCopyrightText: 2020-2024 Espressif Systems (Shanghai) CO LTD
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
|
*/
|
||||||
|
|
||||||
This example code is in the Public Domain (or CC0 licensed, at your option.)
|
|
||||||
|
|
||||||
Unless required by applicable law or agreed to in writing, this
|
|
||||||
software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
|
|
||||||
CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
*/
|
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
|
@@ -23,7 +23,7 @@ This matrix keyboard driver is interrupt-driven, supports a configurable debounc
|
|||||||
|
|
||||||
This example can run on any target that has the dedicated feature (e.g. ESP32-S2). It's not necessary for your matrix board to have pull-up resisters on row/column lines. The driver has enabled internal pull-up resister by default. A typical matrix board should look as follows:
|
This example can run on any target that has the dedicated feature (e.g. ESP32-S2). It's not necessary for your matrix board to have pull-up resisters on row/column lines. The driver has enabled internal pull-up resister by default. A typical matrix board should look as follows:
|
||||||
|
|
||||||
```
|
```text
|
||||||
row_0 +--------+-------------------+------------------------------+-----------------+
|
row_0 +--------+-------------------+------------------------------+-----------------+
|
||||||
| | |
|
| | |
|
||||||
| + | + | +
|
| + | + | +
|
||||||
@@ -51,7 +51,7 @@ row_n +--------+-------------------+------------------------------+-----------
|
|||||||
|
|
||||||
Build the project and flash it to the board, then run monitor tool to view serial output:
|
Build the project and flash it to the board, then run monitor tool to view serial output:
|
||||||
|
|
||||||
```
|
```text
|
||||||
idf.py -p PORT flash monitor
|
idf.py -p PORT flash monitor
|
||||||
```
|
```
|
||||||
|
|
||||||
@@ -63,7 +63,7 @@ See the Getting Started Guide for full steps to configure and use ESP-IDF to bui
|
|||||||
|
|
||||||
## Example Output
|
## Example Output
|
||||||
|
|
||||||
```
|
```text
|
||||||
I (2883) example: press event, key code = 0002
|
I (2883) example: press event, key code = 0002
|
||||||
I (3003) example: release event, key code = 0002
|
I (3003) example: release event, key code = 0002
|
||||||
I (5053) example: press event, key code = 0001
|
I (5053) example: press event, key code = 0001
|
||||||
@@ -77,3 +77,7 @@ I (8923) example: release event, key code = 0103
|
|||||||
I (9543) example: press event, key code = 0203
|
I (9543) example: press event, key code = 0203
|
||||||
I (9683) example: release event, key code = 0203
|
I (9683) example: release event, key code = 0203
|
||||||
```
|
```
|
||||||
|
|
||||||
|
## Troubleshooting
|
||||||
|
|
||||||
|
For any technical queries, please open an [issue](https://github.com/espressif/esp-idf/issues) on GitHub. We will get back to you soon.
|
||||||
|
@@ -1,16 +1,8 @@
|
|||||||
// Copyright 2020 Espressif Systems (Shanghai) PTE LTD
|
/*
|
||||||
//
|
* SPDX-FileCopyrightText: 2020-2024 Espressif Systems (Shanghai) CO LTD
|
||||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
*
|
||||||
// you may not use this file except in compliance with the License.
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
// You may obtain a copy of the License at
|
*/
|
||||||
//
|
|
||||||
// http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
//
|
|
||||||
// Unless required by applicable law or agreed to in writing, software
|
|
||||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
// See the License for the specific language governing permissions and
|
|
||||||
// limitations under the License.
|
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* SPDX-FileCopyrightText: 2020-2023 Espressif Systems (Shanghai) CO LTD
|
* SPDX-FileCopyrightText: 2020-2024 Espressif Systems (Shanghai) CO LTD
|
||||||
*
|
*
|
||||||
* SPDX-License-Identifier: Apache-2.0
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
*/
|
*/
|
||||||
@@ -7,24 +7,15 @@
|
|||||||
#include "freertos/FreeRTOS.h"
|
#include "freertos/FreeRTOS.h"
|
||||||
#include "freertos/task.h"
|
#include "freertos/task.h"
|
||||||
#include "freertos/timers.h"
|
#include "freertos/timers.h"
|
||||||
#include "esp_compiler.h"
|
|
||||||
#include "esp_log.h"
|
#include "esp_log.h"
|
||||||
|
#include "esp_check.h"
|
||||||
#include "driver/dedic_gpio.h"
|
#include "driver/dedic_gpio.h"
|
||||||
#include "driver/gpio.h"
|
#include "driver/gpio.h"
|
||||||
|
#include "esp_private/gpio.h"
|
||||||
#include "matrix_keyboard.h"
|
#include "matrix_keyboard.h"
|
||||||
#include "esp_rom_sys.h"
|
|
||||||
|
|
||||||
static const char *TAG = "mkbd";
|
static const char *TAG = "mkbd";
|
||||||
|
|
||||||
#define MKBD_CHECK(a, msg, tag, ret, ...) \
|
|
||||||
do { \
|
|
||||||
if (unlikely(!(a))) { \
|
|
||||||
ESP_LOGE(TAG, "%s(%d): " msg, __FUNCTION__, __LINE__, ##__VA_ARGS__); \
|
|
||||||
ret_code = ret; \
|
|
||||||
goto tag; \
|
|
||||||
} \
|
|
||||||
} while (0)
|
|
||||||
|
|
||||||
typedef struct matrix_kbd_t matrix_kbd_t;
|
typedef struct matrix_kbd_t matrix_kbd_t;
|
||||||
|
|
||||||
struct matrix_kbd_t {
|
struct matrix_kbd_t {
|
||||||
@@ -91,45 +82,36 @@ static void matrix_kbd_debounce_timer_callback(TimerHandle_t xTimer)
|
|||||||
|
|
||||||
esp_err_t matrix_kbd_install(const matrix_kbd_config_t *config, matrix_kbd_handle_t *mkbd_handle)
|
esp_err_t matrix_kbd_install(const matrix_kbd_config_t *config, matrix_kbd_handle_t *mkbd_handle)
|
||||||
{
|
{
|
||||||
esp_err_t ret_code = ESP_OK;
|
esp_err_t ret = ESP_OK;
|
||||||
matrix_kbd_t *mkbd = NULL;
|
matrix_kbd_t *mkbd = NULL;
|
||||||
MKBD_CHECK(config, "matrix keyboard configuration can't be null", err, ESP_ERR_INVALID_ARG);
|
ESP_RETURN_ON_FALSE(config && mkbd_handle, ESP_ERR_INVALID_ARG, TAG, "invalid argument");
|
||||||
MKBD_CHECK(mkbd_handle, "matrix keyboard handle can't be null", err, ESP_ERR_INVALID_ARG);
|
|
||||||
|
|
||||||
mkbd = calloc(1, sizeof(matrix_kbd_t) + (config->nr_row_gpios) * sizeof(uint32_t));
|
mkbd = calloc(1, sizeof(matrix_kbd_t) + (config->nr_row_gpios) * sizeof(uint32_t));
|
||||||
MKBD_CHECK(mkbd, "allocate matrix keyboard context failed", err, ESP_ERR_NO_MEM);
|
ESP_RETURN_ON_FALSE(mkbd, ESP_ERR_NO_MEM, TAG, "no mem for matrix keyboard context");
|
||||||
|
|
||||||
|
// Create a ont-shot os timer, used for key debounce
|
||||||
|
mkbd->debounce_timer = xTimerCreate("kb_debounce", pdMS_TO_TICKS(config->debounce_ms), pdFALSE, mkbd, matrix_kbd_debounce_timer_callback);
|
||||||
|
ESP_GOTO_ON_FALSE(mkbd->debounce_timer, ESP_FAIL, err, TAG, "create debounce timer failed");
|
||||||
|
|
||||||
mkbd->nr_col_gpios = config->nr_col_gpios;
|
mkbd->nr_col_gpios = config->nr_col_gpios;
|
||||||
mkbd->nr_row_gpios = config->nr_row_gpios;
|
mkbd->nr_row_gpios = config->nr_row_gpios;
|
||||||
|
|
||||||
// GPIO pad configuration
|
|
||||||
// Each GPIO used in matrix key board should be able to input and output
|
|
||||||
// In case the keyboard doesn't design a resister to pull up row/col line
|
|
||||||
// We enable the internal pull up resister, enable Open Drain as well
|
|
||||||
gpio_config_t io_conf = {
|
|
||||||
.mode = GPIO_MODE_INPUT_OUTPUT_OD,
|
|
||||||
.pull_up_en = 1
|
|
||||||
};
|
|
||||||
|
|
||||||
for (int i = 0; i < config->nr_row_gpios; i++) {
|
|
||||||
io_conf.pin_bit_mask = 1ULL << config->row_gpios[i];
|
|
||||||
gpio_config(&io_conf);
|
|
||||||
}
|
|
||||||
|
|
||||||
dedic_gpio_bundle_config_t bundle_row_config = {
|
dedic_gpio_bundle_config_t bundle_row_config = {
|
||||||
.gpio_array = config->row_gpios,
|
.gpio_array = config->row_gpios,
|
||||||
.array_size = config->nr_row_gpios,
|
.array_size = config->nr_row_gpios,
|
||||||
|
// Each GPIO used in matrix key board should be able to input and output
|
||||||
.flags = {
|
.flags = {
|
||||||
.in_en = 1,
|
.in_en = 1,
|
||||||
.out_en = 1,
|
.out_en = 1,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
MKBD_CHECK(dedic_gpio_new_bundle(&bundle_row_config, &mkbd->row_bundle) == ESP_OK,
|
ESP_GOTO_ON_ERROR(dedic_gpio_new_bundle(&bundle_row_config, &mkbd->row_bundle), err, TAG, "create row bundle failed");
|
||||||
"create row bundle failed", err, ESP_FAIL);
|
|
||||||
|
|
||||||
for (int i = 0; i < config->nr_col_gpios; i++) {
|
// In case the keyboard doesn't design a resister to pull up row/col line
|
||||||
io_conf.pin_bit_mask = 1ULL << config->col_gpios[i];
|
// We enable the internal pull up resister, enable Open Drain as well
|
||||||
gpio_config(&io_conf);
|
for (int i = 0; i < config->nr_row_gpios; i++) {
|
||||||
|
gpio_pullup_en(config->row_gpios[i]);
|
||||||
|
gpio_od_enable(config->row_gpios[i]);
|
||||||
}
|
}
|
||||||
|
|
||||||
dedic_gpio_bundle_config_t bundle_col_config = {
|
dedic_gpio_bundle_config_t bundle_col_config = {
|
||||||
@@ -140,8 +122,12 @@ esp_err_t matrix_kbd_install(const matrix_kbd_config_t *config, matrix_kbd_handl
|
|||||||
.out_en = 1,
|
.out_en = 1,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
MKBD_CHECK(dedic_gpio_new_bundle(&bundle_col_config, &mkbd->col_bundle) == ESP_OK,
|
ESP_GOTO_ON_ERROR(dedic_gpio_new_bundle(&bundle_col_config, &mkbd->col_bundle), err, TAG, "create col bundle failed");
|
||||||
"create col bundle failed", err, ESP_FAIL);
|
|
||||||
|
for (int i = 0; i < config->nr_col_gpios; i++) {
|
||||||
|
gpio_pullup_en(config->col_gpios[i]);
|
||||||
|
gpio_od_enable(config->col_gpios[i]);
|
||||||
|
}
|
||||||
|
|
||||||
// Disable interrupt
|
// Disable interrupt
|
||||||
dedic_gpio_bundle_set_interrupt_and_callback(mkbd->row_bundle, (1 << config->nr_row_gpios) - 1,
|
dedic_gpio_bundle_set_interrupt_and_callback(mkbd->row_bundle, (1 << config->nr_row_gpios) - 1,
|
||||||
@@ -149,45 +135,35 @@ esp_err_t matrix_kbd_install(const matrix_kbd_config_t *config, matrix_kbd_handl
|
|||||||
dedic_gpio_bundle_set_interrupt_and_callback(mkbd->col_bundle, (1 << config->nr_col_gpios) - 1,
|
dedic_gpio_bundle_set_interrupt_and_callback(mkbd->col_bundle, (1 << config->nr_col_gpios) - 1,
|
||||||
DEDIC_GPIO_INTR_NONE, NULL, NULL);
|
DEDIC_GPIO_INTR_NONE, NULL, NULL);
|
||||||
|
|
||||||
// Create a ont-shot os timer, used for key debounce
|
|
||||||
mkbd->debounce_timer = xTimerCreate("kb_debounce", pdMS_TO_TICKS(config->debounce_ms), pdFALSE, mkbd, matrix_kbd_debounce_timer_callback);
|
|
||||||
MKBD_CHECK(mkbd->debounce_timer, "create debounce timer failed", err, ESP_FAIL);
|
|
||||||
|
|
||||||
* mkbd_handle = mkbd;
|
* mkbd_handle = mkbd;
|
||||||
return ESP_OK;
|
return ESP_OK;
|
||||||
err:
|
err:
|
||||||
if (mkbd) {
|
if (mkbd->debounce_timer) {
|
||||||
if (mkbd->debounce_timer) {
|
xTimerDelete(mkbd->debounce_timer, 0);
|
||||||
xTimerDelete(mkbd->debounce_timer, 0);
|
|
||||||
}
|
|
||||||
if (mkbd->col_bundle) {
|
|
||||||
dedic_gpio_del_bundle(mkbd->col_bundle);
|
|
||||||
}
|
|
||||||
if (mkbd->row_bundle) {
|
|
||||||
dedic_gpio_del_bundle(mkbd->row_bundle);
|
|
||||||
}
|
|
||||||
free(mkbd);
|
|
||||||
}
|
}
|
||||||
return ret_code;
|
if (mkbd->col_bundle) {
|
||||||
|
dedic_gpio_del_bundle(mkbd->col_bundle);
|
||||||
|
}
|
||||||
|
if (mkbd->row_bundle) {
|
||||||
|
dedic_gpio_del_bundle(mkbd->row_bundle);
|
||||||
|
}
|
||||||
|
free(mkbd);
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
esp_err_t matrix_kbd_uninstall(matrix_kbd_handle_t mkbd_handle)
|
esp_err_t matrix_kbd_uninstall(matrix_kbd_handle_t mkbd_handle)
|
||||||
{
|
{
|
||||||
esp_err_t ret_code = ESP_OK;
|
ESP_RETURN_ON_FALSE(mkbd_handle, ESP_ERR_INVALID_ARG, TAG, "invalid argument");
|
||||||
MKBD_CHECK(mkbd_handle, "matrix keyboard handle can't be null", err, ESP_ERR_INVALID_ARG);
|
|
||||||
xTimerDelete(mkbd_handle->debounce_timer, 0);
|
xTimerDelete(mkbd_handle->debounce_timer, 0);
|
||||||
dedic_gpio_del_bundle(mkbd_handle->col_bundle);
|
dedic_gpio_del_bundle(mkbd_handle->col_bundle);
|
||||||
dedic_gpio_del_bundle(mkbd_handle->row_bundle);
|
dedic_gpio_del_bundle(mkbd_handle->row_bundle);
|
||||||
free(mkbd_handle);
|
free(mkbd_handle);
|
||||||
return ESP_OK;
|
return ESP_OK;
|
||||||
err:
|
|
||||||
return ret_code;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
esp_err_t matrix_kbd_start(matrix_kbd_handle_t mkbd_handle)
|
esp_err_t matrix_kbd_start(matrix_kbd_handle_t mkbd_handle)
|
||||||
{
|
{
|
||||||
esp_err_t ret_code = ESP_OK;
|
ESP_RETURN_ON_FALSE(mkbd_handle, ESP_ERR_INVALID_ARG, TAG, "invalid argument");
|
||||||
MKBD_CHECK(mkbd_handle, "matrix keyboard handle can't be null", err, ESP_ERR_INVALID_ARG);
|
|
||||||
|
|
||||||
// row lines set to high level
|
// row lines set to high level
|
||||||
dedic_gpio_bundle_write(mkbd_handle->row_bundle, (1 << mkbd_handle->nr_row_gpios) - 1, (1 << mkbd_handle->nr_row_gpios) - 1);
|
dedic_gpio_bundle_write(mkbd_handle->row_bundle, (1 << mkbd_handle->nr_row_gpios) - 1, (1 << mkbd_handle->nr_row_gpios) - 1);
|
||||||
@@ -203,15 +179,11 @@ esp_err_t matrix_kbd_start(matrix_kbd_handle_t mkbd_handle)
|
|||||||
DEDIC_GPIO_INTR_BOTH_EDGE, matrix_kbd_row_isr_callback, mkbd_handle);
|
DEDIC_GPIO_INTR_BOTH_EDGE, matrix_kbd_row_isr_callback, mkbd_handle);
|
||||||
|
|
||||||
return ESP_OK;
|
return ESP_OK;
|
||||||
err:
|
|
||||||
return ret_code;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
esp_err_t matrix_kbd_stop(matrix_kbd_handle_t mkbd_handle)
|
esp_err_t matrix_kbd_stop(matrix_kbd_handle_t mkbd_handle)
|
||||||
{
|
{
|
||||||
esp_err_t ret_code = ESP_OK;
|
ESP_RETURN_ON_FALSE(mkbd_handle, ESP_ERR_INVALID_ARG, TAG, "invalid argument");
|
||||||
MKBD_CHECK(mkbd_handle, "matrix keyboard handle can't be null", err, ESP_ERR_INVALID_ARG);
|
|
||||||
|
|
||||||
xTimerStop(mkbd_handle->debounce_timer, 0);
|
xTimerStop(mkbd_handle->debounce_timer, 0);
|
||||||
|
|
||||||
// Disable interrupt
|
// Disable interrupt
|
||||||
@@ -221,17 +193,12 @@ esp_err_t matrix_kbd_stop(matrix_kbd_handle_t mkbd_handle)
|
|||||||
DEDIC_GPIO_INTR_NONE, NULL, NULL);
|
DEDIC_GPIO_INTR_NONE, NULL, NULL);
|
||||||
|
|
||||||
return ESP_OK;
|
return ESP_OK;
|
||||||
err:
|
|
||||||
return ret_code;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
esp_err_t matrix_kbd_register_event_handler(matrix_kbd_handle_t mkbd_handle, matrix_kbd_event_handler handler, void *args)
|
esp_err_t matrix_kbd_register_event_handler(matrix_kbd_handle_t mkbd_handle, matrix_kbd_event_handler handler, void *args)
|
||||||
{
|
{
|
||||||
esp_err_t ret_code = ESP_OK;
|
ESP_RETURN_ON_FALSE(mkbd_handle, ESP_ERR_INVALID_ARG, TAG, "invalid argument");
|
||||||
MKBD_CHECK(mkbd_handle, "matrix keyboard handle can't be null", err, ESP_ERR_INVALID_ARG);
|
|
||||||
mkbd_handle->event_handler = handler;
|
mkbd_handle->event_handler = handler;
|
||||||
mkbd_handle->event_handler_args = args;
|
mkbd_handle->event_handler_args = args;
|
||||||
return ESP_OK;
|
return ESP_OK;
|
||||||
err:
|
|
||||||
return ret_code;
|
|
||||||
}
|
}
|
||||||
|
@@ -1,11 +1,9 @@
|
|||||||
/* Matrix Keyboard (based on dedicated GPIO) example
|
/*
|
||||||
|
* SPDX-FileCopyrightText: 2020-2024 Espressif Systems (Shanghai) CO LTD
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
|
*/
|
||||||
|
|
||||||
This example code is in the Public Domain (or CC0 licensed, at your option.)
|
|
||||||
|
|
||||||
Unless required by applicable law or agreed to in writing, this
|
|
||||||
software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
|
|
||||||
CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
*/
|
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include "esp_log.h"
|
#include "esp_log.h"
|
||||||
#include "matrix_keyboard.h"
|
#include "matrix_keyboard.h"
|
||||||
|
@@ -876,9 +876,6 @@ examples/mesh/manual_networking/main/mesh_main.c
|
|||||||
examples/network/simple_sniffer/main/cmd_sniffer.c
|
examples/network/simple_sniffer/main/cmd_sniffer.c
|
||||||
examples/network/simple_sniffer/main/cmd_sniffer.h
|
examples/network/simple_sniffer/main/cmd_sniffer.h
|
||||||
examples/network/simple_sniffer/main/simple_sniffer_example_main.c
|
examples/network/simple_sniffer/main/simple_sniffer_example_main.c
|
||||||
examples/peripherals/gpio/generic_gpio/main/gpio_example_main.c
|
|
||||||
examples/peripherals/gpio/matrix_keyboard/components/matrix_keyboard/include/matrix_keyboard.h
|
|
||||||
examples/peripherals/gpio/matrix_keyboard/main/matrix_keyboard_example_main.c
|
|
||||||
examples/peripherals/ledc/ledc_basic/main/ledc_basic_example_main.c
|
examples/peripherals/ledc/ledc_basic/main/ledc_basic_example_main.c
|
||||||
examples/peripherals/ledc/ledc_fade/main/ledc_fade_example_main.c
|
examples/peripherals/ledc/ledc_fade/main/ledc_fade_example_main.c
|
||||||
examples/peripherals/sdio/host/main/app_main.c
|
examples/peripherals/sdio/host/main/app_main.c
|
||||||
|
Reference in New Issue
Block a user