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:
morris
2024-10-15 11:32:07 +08:00
10 changed files with 89 additions and 173 deletions

View File

@@ -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) {

View File

@@ -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,

View File

@@ -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]``

View File

@@ -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]``

View File

@@ -1,11 +1,9 @@
/* GPIO Example /*
* SPDX-FileCopyrightText: 2020-2024 Espressif Systems (Shanghai) CO LTD
This example code is in the Public Domain (or CC0 licensed, at your option.) *
* SPDX-License-Identifier: Apache-2.0
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>

View File

@@ -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.

View File

@@ -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

View File

@@ -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,14 +135,9 @@ 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);
} }
@@ -167,27 +148,22 @@ err:
dedic_gpio_del_bundle(mkbd->row_bundle); dedic_gpio_del_bundle(mkbd->row_bundle);
} }
free(mkbd); free(mkbd);
} return ret;
return ret_code;
} }
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;
} }

View File

@@ -1,11 +1,9 @@
/* Matrix Keyboard (based on dedicated GPIO) example /*
* SPDX-FileCopyrightText: 2020-2024 Espressif Systems (Shanghai) CO LTD
This example code is in the Public Domain (or CC0 licensed, at your option.) *
* SPDX-License-Identifier: Apache-2.0
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"

View File

@@ -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