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) {
|
||||
for (size_t i = 0; i < config->array_size; i++) {
|
||||
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);
|
||||
}
|
||||
}
|
||||
@@ -325,6 +326,17 @@ esp_err_t dedic_gpio_del_bundle(dedic_gpio_bundle_handle_t bundle)
|
||||
}
|
||||
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);
|
||||
|
||||
if (recycle_all) {
|
||||
|
@@ -70,16 +70,8 @@ static void test_dedic_gpio_on_specific_core(void *args)
|
||||
uint32_t value = 0;
|
||||
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
|
||||
const int bundleA_gpios[] = {ctx->gpios[0], ctx->gpios[1]};
|
||||
dedic_gpio_bundle_handle_t bundleA = NULL;
|
||||
dedic_gpio_bundle_config_t bundleA_config = {
|
||||
.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));
|
||||
|
||||
// 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
|
||||
const int bundleB_gpios[] = {ctx->gpios[2], ctx->gpios[3]};
|
||||
dedic_gpio_bundle_handle_t bundleB = NULL;
|
||||
dedic_gpio_bundle_config_t bundleB_config = {
|
||||
.gpio_array = bundleB_gpios,
|
||||
@@ -192,13 +177,6 @@ TEST_CASE("Dedicated_GPIO_interrupt_and_callback", "[dedic_gpio]")
|
||||
#else
|
||||
const int bundle_gpios[] = {0, 1};
|
||||
#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_config_t bundle_config = {
|
||||
.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::
|
||||
|
||||
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:
|
||||
|
||||
- :cpp:member:`gpio_array`: An array that contains GPIO number.
|
||||
- :cpp:member:`array_size`: Element number of :cpp:member:`gpio_array`.
|
||||
- :cpp:member:`flags`: Extra flags to control the behavior of GPIO Bundle.
|
||||
- :cpp:member:`dedic_gpio_bundle_config_t::gpio_array`: An array that contains GPIO number.
|
||||
- :cpp:member:`dedic_gpio_bundle_config_t::array_size`: Element number of :cpp:member:`dedic_gpio_bundle_config_t::gpio_array`.
|
||||
- :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).
|
||||
- :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:
|
||||
The following code shows how to install an output only GPIO bundle:
|
||||
|
||||
.. 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
|
||||
dedic_gpio_bundle_handle_t bundleA = NULL;
|
||||
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));
|
||||
|
||||
To uninstall the GPIO bundle, one needs to 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>`.
|
||||
To uninstall the GPIO bundle, you should call :cpp:func:`dedic_gpio_del_bundle`.
|
||||
|
||||
|
||||
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
|
||||
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]``
|
||||
- Clear bits of GPIO: ``clr_bit_gpio_out imm[7:0]``
|
||||
- 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]``
|
||||
- Clear bits of GPIO: ``csrrci rd, csr, imm[4:0]``
|
||||
|
@@ -16,16 +16,14 @@ GPIO 捆绑包是一组 GPIO,该组 GPIO 可以在一个 CPU 周期内同时
|
||||
|
||||
.. 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` 结构体中:
|
||||
|
||||
- :cpp:member:`gpio_array`:包含 GPIO 编号的数组。
|
||||
- :cpp:member:`array_size`::cpp:member:`gpio_array` 的元素个数。
|
||||
- :cpp:member:`flags`:用于控制 GPIO 捆绑包行为的标志。
|
||||
|
||||
- :cpp:member:`in_en` 和 :cpp:member:`out_en` 用于选择是否开启输入输出功能(这两个功能可以同时开启)。
|
||||
- :cpp:member:`in_invert` 和 :cpp:member:`out_invert` 用于选择是否反转 GPIO 信号。
|
||||
- :cpp:member:`dedic_gpio_bundle_config_t::gpio_array`:包含 GPIO 编号的数组。
|
||||
- :cpp:member:`dedic_gpio_bundle_config_t::array_size`: :cpp:member:`dedic_gpio_bundle_config_t::gpio_array` 的元素个数。
|
||||
- :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 信号。
|
||||
|
||||
以下代码展示了如何安装只有输出功能的 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,仅输出
|
||||
dedic_gpio_bundle_handle_t bundleA = NULL;
|
||||
dedic_gpio_bundle_config_t bundleA_config = {
|
||||
@@ -55,10 +44,6 @@ GPIO 捆绑包是一组 GPIO,该组 GPIO 可以在一个 CPU 周期内同时
|
||||
|
||||
如需卸载 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 捆绑包操作
|
||||
----------------------
|
||||
@@ -92,13 +77,13 @@ GPIO 捆绑包操作
|
||||
3. 调用 CPU LL apis(如 `cpu_ll_write_dedic_gpio_mask`)或使用该掩码编写汇编代码
|
||||
4. 切换 IO 的最快捷方式是使用专用的“设置/清除”指令:
|
||||
|
||||
.. only:: esp32s2 or esp32s3
|
||||
.. only:: CONFIG_IDF_TARGET_ARCH_XTENSA
|
||||
|
||||
- 设置 GPIO 位:``set_bit_gpio_out imm[7:0]``
|
||||
- 清除 GPIO 位:``clr_bit_gpio_out imm[7:0]``
|
||||
- 注意:立即数宽度取决于专用 GPIO 通道的数量
|
||||
|
||||
.. only:: esp32c2 or esp32c3 or esp32c6 or esp32h2
|
||||
.. only:: CONFIG_IDF_TARGET_ARCH_RISCV
|
||||
|
||||
- 设置 GPIO 位:``csrrsi 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 <string.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:
|
||||
|
||||
```
|
||||
```text
|
||||
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:
|
||||
|
||||
```
|
||||
```text
|
||||
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
|
||||
|
||||
```
|
||||
```text
|
||||
I (2883) example: press event, key code = 0002
|
||||
I (3003) example: release event, key code = 0002
|
||||
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 (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
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// 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.
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2020-2024 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#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
|
||||
*/
|
||||
@@ -7,24 +7,15 @@
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/task.h"
|
||||
#include "freertos/timers.h"
|
||||
#include "esp_compiler.h"
|
||||
#include "esp_log.h"
|
||||
#include "esp_check.h"
|
||||
#include "driver/dedic_gpio.h"
|
||||
#include "driver/gpio.h"
|
||||
#include "esp_private/gpio.h"
|
||||
#include "matrix_keyboard.h"
|
||||
#include "esp_rom_sys.h"
|
||||
|
||||
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;
|
||||
|
||||
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 ret_code = ESP_OK;
|
||||
esp_err_t ret = ESP_OK;
|
||||
matrix_kbd_t *mkbd = NULL;
|
||||
MKBD_CHECK(config, "matrix keyboard configuration can't be null", err, ESP_ERR_INVALID_ARG);
|
||||
MKBD_CHECK(mkbd_handle, "matrix keyboard handle can't be null", err, ESP_ERR_INVALID_ARG);
|
||||
ESP_RETURN_ON_FALSE(config && mkbd_handle, ESP_ERR_INVALID_ARG, TAG, "invalid argument");
|
||||
|
||||
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_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 = {
|
||||
.gpio_array = config->row_gpios,
|
||||
.array_size = config->nr_row_gpios,
|
||||
// Each GPIO used in matrix key board should be able to input and output
|
||||
.flags = {
|
||||
.in_en = 1,
|
||||
.out_en = 1,
|
||||
},
|
||||
};
|
||||
MKBD_CHECK(dedic_gpio_new_bundle(&bundle_row_config, &mkbd->row_bundle) == ESP_OK,
|
||||
"create row bundle failed", err, ESP_FAIL);
|
||||
ESP_GOTO_ON_ERROR(dedic_gpio_new_bundle(&bundle_row_config, &mkbd->row_bundle), err, TAG, "create row bundle failed");
|
||||
|
||||
for (int i = 0; i < config->nr_col_gpios; i++) {
|
||||
io_conf.pin_bit_mask = 1ULL << config->col_gpios[i];
|
||||
gpio_config(&io_conf);
|
||||
// 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
|
||||
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 = {
|
||||
@@ -140,8 +122,12 @@ esp_err_t matrix_kbd_install(const matrix_kbd_config_t *config, matrix_kbd_handl
|
||||
.out_en = 1,
|
||||
},
|
||||
};
|
||||
MKBD_CHECK(dedic_gpio_new_bundle(&bundle_col_config, &mkbd->col_bundle) == ESP_OK,
|
||||
"create col bundle failed", err, ESP_FAIL);
|
||||
ESP_GOTO_ON_ERROR(dedic_gpio_new_bundle(&bundle_col_config, &mkbd->col_bundle), err, TAG, "create col bundle failed");
|
||||
|
||||
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
|
||||
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_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;
|
||||
return ESP_OK;
|
||||
err:
|
||||
if (mkbd) {
|
||||
if (mkbd->debounce_timer) {
|
||||
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);
|
||||
if (mkbd->debounce_timer) {
|
||||
xTimerDelete(mkbd->debounce_timer, 0);
|
||||
}
|
||||
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 ret_code = ESP_OK;
|
||||
MKBD_CHECK(mkbd_handle, "matrix keyboard handle can't be null", err, ESP_ERR_INVALID_ARG);
|
||||
ESP_RETURN_ON_FALSE(mkbd_handle, ESP_ERR_INVALID_ARG, TAG, "invalid argument");
|
||||
xTimerDelete(mkbd_handle->debounce_timer, 0);
|
||||
dedic_gpio_del_bundle(mkbd_handle->col_bundle);
|
||||
dedic_gpio_del_bundle(mkbd_handle->row_bundle);
|
||||
free(mkbd_handle);
|
||||
return ESP_OK;
|
||||
err:
|
||||
return ret_code;
|
||||
}
|
||||
|
||||
esp_err_t matrix_kbd_start(matrix_kbd_handle_t mkbd_handle)
|
||||
{
|
||||
esp_err_t ret_code = ESP_OK;
|
||||
MKBD_CHECK(mkbd_handle, "matrix keyboard handle can't be null", err, ESP_ERR_INVALID_ARG);
|
||||
ESP_RETURN_ON_FALSE(mkbd_handle, ESP_ERR_INVALID_ARG, TAG, "invalid argument");
|
||||
|
||||
// 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);
|
||||
@@ -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);
|
||||
|
||||
return ESP_OK;
|
||||
err:
|
||||
return ret_code;
|
||||
}
|
||||
|
||||
esp_err_t matrix_kbd_stop(matrix_kbd_handle_t mkbd_handle)
|
||||
{
|
||||
esp_err_t ret_code = ESP_OK;
|
||||
MKBD_CHECK(mkbd_handle, "matrix keyboard handle can't be null", err, ESP_ERR_INVALID_ARG);
|
||||
|
||||
ESP_RETURN_ON_FALSE(mkbd_handle, ESP_ERR_INVALID_ARG, TAG, "invalid argument");
|
||||
xTimerStop(mkbd_handle->debounce_timer, 0);
|
||||
|
||||
// Disable interrupt
|
||||
@@ -221,17 +193,12 @@ esp_err_t matrix_kbd_stop(matrix_kbd_handle_t mkbd_handle)
|
||||
DEDIC_GPIO_INTR_NONE, NULL, NULL);
|
||||
|
||||
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 ret_code = ESP_OK;
|
||||
MKBD_CHECK(mkbd_handle, "matrix keyboard handle can't be null", err, ESP_ERR_INVALID_ARG);
|
||||
ESP_RETURN_ON_FALSE(mkbd_handle, ESP_ERR_INVALID_ARG, TAG, "invalid argument");
|
||||
mkbd_handle->event_handler = handler;
|
||||
mkbd_handle->event_handler_args = args;
|
||||
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 "esp_log.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.h
|
||||
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_fade/main/ledc_fade_example_main.c
|
||||
examples/peripherals/sdio/host/main/app_main.c
|
||||
|
Reference in New Issue
Block a user