mirror of
https://github.com/espressif/esp-idf.git
synced 2024-10-05 20:47:46 -04:00
Merge branch 'feature/glitch_filter_h2' into 'master'
gpio: support glitch filter on esp32h2 Closes IDF-6286 See merge request espressif/esp-idf!22273
This commit is contained in:
commit
e0c98da169
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD
|
||||
* SPDX-FileCopyrightText: 2022-2023 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
@ -8,11 +8,11 @@
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "esp_check.h"
|
||||
#include "glitch_filter_priv.h"
|
||||
#include "esp_private/esp_clk.h"
|
||||
#include "esp_private/io_mux.h"
|
||||
#include "soc/soc_caps.h"
|
||||
#include "hal/gpio_glitch_filter_ll.h"
|
||||
#include "esp_pm.h"
|
||||
#include "clk_tree.h"
|
||||
|
||||
static const char *TAG = "gpio-filter";
|
||||
|
||||
@ -136,31 +136,20 @@ esp_err_t gpio_new_flex_glitch_filter(const gpio_flex_glitch_filter_config_t *co
|
||||
int filter_id = filter->filter_id;
|
||||
|
||||
// set clock source
|
||||
uint32_t clk_freq_mhz = 0;
|
||||
switch (config->clk_src) {
|
||||
#if SOC_GPIO_FILTER_CLK_SUPPORT_XTAL
|
||||
case GLITCH_FILTER_CLK_SRC_XTAL:
|
||||
clk_freq_mhz = esp_clk_xtal_freq() / 1000000;
|
||||
break;
|
||||
#endif // SOC_GPIO_FILTER_CLK_SUPPORT_XTAL
|
||||
uint32_t clk_freq_hz = 0;
|
||||
ESP_GOTO_ON_ERROR(clk_tree_src_get_freq_hz((soc_module_clk_t)config->clk_src, CLK_TREE_SRC_FREQ_PRECISION_CACHED, &clk_freq_hz),
|
||||
err, TAG, "get clock source frequency failed");
|
||||
|
||||
#if SOC_GPIO_FILTER_CLK_SUPPORT_PLL_F80M
|
||||
case GLITCH_FILTER_CLK_SRC_PLL_F80M:
|
||||
clk_freq_mhz = 80;
|
||||
// create pm_lock according to different clock source
|
||||
#if CONFIG_PM_ENABLE
|
||||
sprintf(filter->pm_lock_name, "filter_%d", filter_id); // e.g. filter_0
|
||||
ret = esp_pm_lock_create(ESP_PM_NO_LIGHT_SLEEP, 0, filter->pm_lock_name, &filter->pm_lock);
|
||||
ESP_RETURN_ON_ERROR(ret, TAG, "create NO_LIGHT_SLEEP lock failed");
|
||||
esp_pm_lock_type_t lock_type = ESP_PM_NO_LIGHT_SLEEP;
|
||||
sprintf(filter->pm_lock_name, "filter_%d", filter_id); // e.g. filter_0
|
||||
ESP_GOTO_ON_ERROR(esp_pm_lock_create(lock_type, 0, filter->pm_lock_name, &filter->pm_lock),
|
||||
err, TAG, "create pm_lock failed");
|
||||
#endif
|
||||
break;
|
||||
#endif // SOC_GPIO_FILTER_CLK_SUPPORT_PLL_F80M
|
||||
default:
|
||||
ESP_GOTO_ON_FALSE(false, ESP_ERR_INVALID_ARG, err, TAG, "invalid clock source");
|
||||
break;
|
||||
}
|
||||
|
||||
uint32_t window_thres_ticks = clk_freq_mhz * config->window_thres_ns / 1000;
|
||||
uint32_t window_width_ticks = clk_freq_mhz * config->window_width_ns / 1000;
|
||||
uint32_t window_thres_ticks = clk_freq_hz / 1000000 * config->window_thres_ns / 1000;
|
||||
uint32_t window_width_ticks = clk_freq_hz / 1000000 * config->window_width_ns / 1000;
|
||||
ESP_GOTO_ON_FALSE(window_thres_ticks && window_thres_ticks <= window_width_ticks && window_width_ticks <= GPIO_LL_GLITCH_FILTER_MAX_WINDOW,
|
||||
ESP_ERR_INVALID_ARG, err, TAG, "invalid or out of range window width/threshold");
|
||||
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD
|
||||
* SPDX-FileCopyrightText: 2022-2023 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
@ -10,7 +10,7 @@
|
||||
#include "esp_pm.h"
|
||||
#include "glitch_filter_priv.h"
|
||||
#include "hal/gpio_ll.h"
|
||||
#include "esp_private/esp_clk.h"
|
||||
#include "clk_tree.h"
|
||||
#include "esp_private/io_mux.h"
|
||||
|
||||
static const char *TAG = "gpio-filter";
|
||||
@ -84,36 +84,18 @@ esp_err_t gpio_new_pin_glitch_filter(const gpio_pin_glitch_filter_config_t *conf
|
||||
filter = heap_caps_calloc(1, sizeof(gpio_pin_glitch_filter_t), FILTER_MEM_ALLOC_CAPS);
|
||||
ESP_GOTO_ON_FALSE(filter, ESP_ERR_NO_MEM, err, TAG, "no memory for pin glitch filter");
|
||||
|
||||
// set clock source
|
||||
switch (config->clk_src) {
|
||||
#if SOC_GPIO_FILTER_CLK_SUPPORT_XTAL
|
||||
case GLITCH_FILTER_CLK_SRC_XTAL:
|
||||
break;
|
||||
#endif // SOC_GPIO_FILTER_CLK_SUPPORT_XTAL
|
||||
|
||||
#if SOC_GPIO_FILTER_CLK_SUPPORT_PLL_F80M
|
||||
case GLITCH_FILTER_CLK_SRC_PLL_F80M:
|
||||
// create pm lock according to different clock source
|
||||
#if CONFIG_PM_ENABLE
|
||||
sprintf(filter->pm_lock_name, "filter_io_%d", config->gpio_num); // e.g. filter_io_0
|
||||
ret = esp_pm_lock_create(ESP_PM_NO_LIGHT_SLEEP, 0, filter->pm_lock_name, &filter->pm_lock);
|
||||
ESP_RETURN_ON_ERROR(ret, TAG, "create NO_LIGHT_SLEEP lock failed");
|
||||
#endif
|
||||
break;
|
||||
#endif // SOC_GPIO_FILTER_CLK_SUPPORT_PLL_F80M
|
||||
|
||||
esp_pm_lock_type_t lock_type = ESP_PM_NO_LIGHT_SLEEP;
|
||||
#if SOC_GPIO_FILTER_CLK_SUPPORT_APB
|
||||
case GLITCH_FILTER_CLK_SRC_APB:
|
||||
#if CONFIG_PM_ENABLE
|
||||
sprintf(filter->pm_lock_name, "filter_io_%d", config->gpio_num); // e.g. filter_io_0
|
||||
ret = esp_pm_lock_create(ESP_PM_APB_FREQ_MAX, 0, filter->pm_lock_name, &filter->pm_lock);
|
||||
ESP_RETURN_ON_ERROR(ret, TAG, "create APB_FREQ_MAX lock failed");
|
||||
#endif
|
||||
break;
|
||||
#endif // SOC_GPIO_FILTER_CLK_SUPPORT_APB
|
||||
default:
|
||||
ESP_GOTO_ON_FALSE(false, ESP_ERR_INVALID_ARG, err, TAG, "invalid clock source");
|
||||
break;
|
||||
if (config->clk_src == GLITCH_FILTER_CLK_SRC_APB) {
|
||||
lock_type = ESP_PM_APB_FREQ_MAX;
|
||||
}
|
||||
#endif // SOC_GPIO_FILTER_CLK_SUPPORT_APB
|
||||
sprintf(filter->pm_lock_name, "filter_io_%d", config->gpio_num); // e.g. filter_io_0
|
||||
ESP_GOTO_ON_ERROR(esp_pm_lock_create(lock_type, 0, filter->pm_lock_name, &filter->pm_lock),
|
||||
err, TAG, "create pm_lock failed");
|
||||
#endif // CONFIG_PM_ENABLE
|
||||
|
||||
// Glitch filter's clock source is same to the IOMUX clock
|
||||
ESP_GOTO_ON_ERROR(io_mux_set_clock_source((soc_module_clk_t)(config->clk_src)), err, TAG, "set IO MUX clock source failed");
|
||||
|
@ -1,13 +1,32 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD
|
||||
* SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "esp_private/io_mux.h"
|
||||
#include "hal/gpio_ll.h"
|
||||
|
||||
static portMUX_TYPE s_io_mux_spinlock = portMUX_INITIALIZER_UNLOCKED;
|
||||
static soc_module_clk_t s_io_mux_clk_src = 0; // by default, the clock source is not set explicitly by any consumer (e.g. SDM, Filter)
|
||||
|
||||
esp_err_t io_mux_set_clock_source(soc_module_clk_t clk_src)
|
||||
{
|
||||
// TODO: IDF-6286
|
||||
bool clk_conflict = false;
|
||||
// check is the IO MUX has been set to another clock source
|
||||
portENTER_CRITICAL(&s_io_mux_spinlock);
|
||||
if (s_io_mux_clk_src != 0 && s_io_mux_clk_src != clk_src) {
|
||||
clk_conflict = true;
|
||||
} else {
|
||||
s_io_mux_clk_src = clk_src;
|
||||
}
|
||||
portEXIT_CRITICAL(&s_io_mux_spinlock);
|
||||
|
||||
if (clk_conflict) {
|
||||
return ESP_ERR_INVALID_STATE;
|
||||
}
|
||||
|
||||
gpio_ll_iomux_set_clk_src(clk_src);
|
||||
return ESP_OK;
|
||||
}
|
||||
|
55
components/hal/esp32h2/include/hal/dedic_gpio_cpu_ll.h
Normal file
55
components/hal/esp32h2/include/hal/dedic_gpio_cpu_ll.h
Normal file
@ -0,0 +1,55 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <stdint.h>
|
||||
#include "riscv/csr.h"
|
||||
|
||||
/*fast gpio*/
|
||||
#define CSR_GPIO_OEN_USER 0x803
|
||||
#define CSR_GPIO_IN_USER 0x804
|
||||
#define CSR_GPIO_OUT_USER 0x805
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
__attribute__((always_inline))
|
||||
static inline void dedic_gpio_cpu_ll_enable_output(uint32_t mask)
|
||||
{
|
||||
RV_WRITE_CSR(CSR_GPIO_OEN_USER, mask);
|
||||
}
|
||||
|
||||
static inline void dedic_gpio_cpu_ll_write_all(uint32_t value)
|
||||
{
|
||||
RV_WRITE_CSR(CSR_GPIO_OUT_USER, value);
|
||||
}
|
||||
|
||||
__attribute__((always_inline))
|
||||
static inline uint32_t dedic_gpio_cpu_ll_read_in(void)
|
||||
{
|
||||
uint32_t value = RV_READ_CSR(CSR_GPIO_IN_USER);
|
||||
return value;
|
||||
}
|
||||
|
||||
__attribute__((always_inline))
|
||||
static inline uint32_t dedic_gpio_cpu_ll_read_out(void)
|
||||
{
|
||||
uint32_t value = RV_READ_CSR(CSR_GPIO_OUT_USER);
|
||||
return value;
|
||||
}
|
||||
|
||||
__attribute__((always_inline))
|
||||
static inline void dedic_gpio_cpu_ll_write_mask(uint32_t mask, uint32_t value)
|
||||
{
|
||||
RV_SET_CSR(CSR_GPIO_OUT_USER, mask & value);
|
||||
RV_CLEAR_CSR(CSR_GPIO_OUT_USER, mask & ~(value));
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
66
components/hal/esp32h2/include/hal/gpio_glitch_filter_ll.h
Normal file
66
components/hal/esp32h2/include/hal/gpio_glitch_filter_ll.h
Normal file
@ -0,0 +1,66 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
/*******************************************************************************
|
||||
* NOTICE
|
||||
* The hal is not public api, don't use in application code.
|
||||
* See readme.md in hal/include/hal/readme.md
|
||||
******************************************************************************/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <stdbool.h>
|
||||
#include "hal/assert.h"
|
||||
#include "soc/gpio_ext_struct.h"
|
||||
|
||||
#define GPIO_LL_GLITCH_FILTER_MAX_WINDOW 64
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Enable GPIO glitch filter
|
||||
*
|
||||
* @param hw Glitch filter register base address
|
||||
* @param filter_idx Glitch filter index
|
||||
* @param enable True to enable, false to disable
|
||||
*/
|
||||
static inline void gpio_ll_glitch_filter_enable(gpio_glitch_filter_dev_t *hw, uint32_t filter_idx, bool enable)
|
||||
{
|
||||
hw->glitch_filter_chn[filter_idx].filter_chn_en = enable;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Set the input GPIO for the glitch filter
|
||||
*
|
||||
* @param hw Glitch filter register base address
|
||||
* @param filter_idx Glitch filter index
|
||||
* @param gpio_num GPIO number
|
||||
*/
|
||||
static inline void gpio_ll_glitch_filter_set_gpio(gpio_glitch_filter_dev_t *hw, uint32_t filter_idx, uint32_t gpio_num)
|
||||
{
|
||||
hw->glitch_filter_chn[filter_idx].filter_chn_input_io_num = gpio_num;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Set the coefficient of the glitch filter window
|
||||
*
|
||||
* @param hw Glitch filter register base address
|
||||
* @param filter_idx Glitch filter index
|
||||
* @param window_width Window width, in IOMUX clock ticks
|
||||
* @param window_threshold Window threshold, in IOMUX clock ticks
|
||||
*/
|
||||
static inline void gpio_ll_glitch_filter_set_window_coeff(gpio_glitch_filter_dev_t *hw, uint32_t filter_idx, uint32_t window_width, uint32_t window_thres)
|
||||
{
|
||||
HAL_ASSERT(window_thres <= window_width);
|
||||
hw->glitch_filter_chn[filter_idx].filter_chn_window_width = window_width - 1;
|
||||
hw->glitch_filter_chn[filter_idx].filter_chn_window_thres = window_thres - 1;
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
@ -359,14 +359,6 @@ config SOC_GPIO_FLEX_GLITCH_FILTER_NUM
|
||||
int
|
||||
default 8
|
||||
|
||||
config SOC_GPIO_FILTER_CLK_SUPPORT_XTAL
|
||||
bool
|
||||
default y
|
||||
|
||||
config SOC_GPIO_FILTER_CLK_SUPPORT_PLL_F80M
|
||||
bool
|
||||
default y
|
||||
|
||||
config SOC_GPIO_SUPPORT_ETM
|
||||
bool
|
||||
default y
|
||||
|
@ -161,8 +161,6 @@
|
||||
#define SOC_GPIO_PIN_COUNT 31
|
||||
#define SOC_GPIO_SUPPORT_PIN_GLITCH_FILTER 1
|
||||
#define SOC_GPIO_FLEX_GLITCH_FILTER_NUM 8
|
||||
#define SOC_GPIO_FILTER_CLK_SUPPORT_XTAL 1
|
||||
#define SOC_GPIO_FILTER_CLK_SUPPORT_PLL_F80M 1
|
||||
|
||||
// GPIO peripheral has the ETM extension
|
||||
#define SOC_GPIO_SUPPORT_ETM 1
|
||||
|
@ -3,6 +3,10 @@
|
||||
# using gen_soc_caps_kconfig.py, do not edit manually
|
||||
#####################################################
|
||||
|
||||
config SOC_DEDICATED_GPIO_SUPPORTED
|
||||
bool
|
||||
default y
|
||||
|
||||
config SOC_UART_SUPPORTED
|
||||
bool
|
||||
default y
|
||||
@ -291,6 +295,14 @@ config SOC_GPIO_PIN_COUNT
|
||||
int
|
||||
default 28
|
||||
|
||||
config SOC_GPIO_SUPPORT_PIN_GLITCH_FILTER
|
||||
bool
|
||||
default y
|
||||
|
||||
config SOC_GPIO_FLEX_GLITCH_FILTER_NUM
|
||||
int
|
||||
default 8
|
||||
|
||||
config SOC_GPIO_SUPPORT_ETM
|
||||
bool
|
||||
default y
|
||||
|
@ -371,7 +371,11 @@ typedef enum {
|
||||
typedef enum {
|
||||
GLITCH_FILTER_CLK_SRC_XTAL = SOC_MOD_CLK_XTAL, /*!< Select XTAL clock as the source clock */
|
||||
GLITCH_FILTER_CLK_SRC_PLL_F48M = SOC_MOD_CLK_PLL_F48M, /*!< Select PLL_F48M clock as the source clock */
|
||||
#if CONFIG_IDF_ENV_FPGA
|
||||
GLITCH_FILTER_CLK_SRC_DEFAULT = SOC_MOD_CLK_XTAL, /*!< Select XTAL as the default clock choice */
|
||||
#else
|
||||
GLITCH_FILTER_CLK_SRC_DEFAULT = SOC_MOD_CLK_PLL_F48M, /*!< Select PLL_F48M clock as the default clock choice */
|
||||
#endif
|
||||
} soc_periph_glitch_filter_clk_src_t;
|
||||
|
||||
//////////////////////////////////////////////////TWAI/////////////////////////////////////////////////////////////////
|
||||
|
@ -112,22 +112,22 @@ typedef union {
|
||||
*/
|
||||
typedef union {
|
||||
struct {
|
||||
/** filter_ch0_en : R/W; bitpos: [0]; default: 0;
|
||||
/** filter_chn_en : R/W; bitpos: [0]; default: 0;
|
||||
* Glitch Filter channel enable bit.
|
||||
*/
|
||||
uint32_t filter_ch0_en:1;
|
||||
/** filter_ch0_input_io_num : R/W; bitpos: [6:1]; default: 0;
|
||||
uint32_t filter_chn_en:1;
|
||||
/** filter_chn_input_io_num : R/W; bitpos: [6:1]; default: 0;
|
||||
* Glitch Filter input io number.
|
||||
*/
|
||||
uint32_t filter_ch0_input_io_num:6;
|
||||
/** filter_ch0_window_thres : R/W; bitpos: [12:7]; default: 0;
|
||||
uint32_t filter_chn_input_io_num:6;
|
||||
/** filter_chn_window_thres : R/W; bitpos: [12:7]; default: 0;
|
||||
* Glitch Filter window threshold.
|
||||
*/
|
||||
uint32_t filter_ch0_window_thres:6;
|
||||
/** filter_ch0_window_width : R/W; bitpos: [18:13]; default: 0;
|
||||
uint32_t filter_chn_window_thres:6;
|
||||
/** filter_chn_window_width : R/W; bitpos: [18:13]; default: 0;
|
||||
* Glitch Filter window width.
|
||||
*/
|
||||
uint32_t filter_ch0_window_width:6;
|
||||
uint32_t filter_chn_window_width:6;
|
||||
uint32_t reserved_19:13;
|
||||
};
|
||||
uint32_t val;
|
||||
|
@ -26,7 +26,7 @@
|
||||
|
||||
/*-------------------------- COMMON CAPS ---------------------------------------*/
|
||||
// #define SOC_ADC_SUPPORTED 1 // TODO: IDF-6214
|
||||
// #define SOC_DEDICATED_GPIO_SUPPORTED 1 // TODO: IDF-6241
|
||||
#define SOC_DEDICATED_GPIO_SUPPORTED 1
|
||||
#define SOC_UART_SUPPORTED 1
|
||||
#define SOC_GDMA_SUPPORTED 1
|
||||
#define SOC_ASYNC_MEMCPY_SUPPORTED 1
|
||||
@ -153,8 +153,10 @@
|
||||
|
||||
/*-------------------------- GPIO CAPS ---------------------------------------*/
|
||||
// ESP32-H2 has 1 GPIO peripheral
|
||||
#define SOC_GPIO_PORT (1U)
|
||||
#define SOC_GPIO_PIN_COUNT (28)
|
||||
#define SOC_GPIO_PORT 1U
|
||||
#define SOC_GPIO_PIN_COUNT 28
|
||||
#define SOC_GPIO_SUPPORT_PIN_GLITCH_FILTER 1
|
||||
#define SOC_GPIO_FLEX_GLITCH_FILTER_NUM 8
|
||||
|
||||
// GPIO peripheral has the ETM extension
|
||||
#define SOC_GPIO_SUPPORT_ETM 1
|
||||
@ -173,7 +175,6 @@
|
||||
// digital I/O pad powered by VDD3P3_CPU or VDD_SPI(GPIO_NUM_0~6. GPIO_NUM_15~27)
|
||||
#define SOC_GPIO_VALID_DIGITAL_IO_PAD_MASK 0x000000000FFF807FULL
|
||||
|
||||
// TODO: IDF-6241
|
||||
/*-------------------------- Dedicated GPIO CAPS -----------------------------*/
|
||||
#define SOC_DEDIC_GPIO_OUT_CHANNELS_NUM (8) /*!< 8 outward channels on each CPU core */
|
||||
#define SOC_DEDIC_GPIO_IN_CHANNELS_NUM (8) /*!< 8 inward channels on each CPU core */
|
||||
|
@ -1,5 +1,5 @@
|
||||
| Supported Targets | ESP32-C2 | ESP32-C3 | ESP32-C6 | ESP32-S2 | ESP32-S3 |
|
||||
| ----------------- | -------- | -------- | -------- | -------- | -------- |
|
||||
| Supported Targets | ESP32-C2 | ESP32-C3 | ESP32-C6 | ESP32-H2 | ESP32-S2 | ESP32-S3 |
|
||||
| ----------------- | -------- | -------- | -------- | -------- | -------- | -------- |
|
||||
|
||||
# Example: Software I2C Master via Dedicated/Fast GPIOs
|
||||
|
||||
|
@ -1,5 +1,5 @@
|
||||
| Supported Targets | ESP32-C2 | ESP32-C3 | ESP32-C6 |
|
||||
| ----------------- | -------- | -------- | -------- |
|
||||
| Supported Targets | ESP32-C2 | ESP32-C3 | ESP32-C6 | ESP32-H2 |
|
||||
| ----------------- | -------- | -------- | -------- | -------- |
|
||||
|
||||
# Example: SPI software emulation using dedicated/fast GPIOs
|
||||
|
||||
|
@ -1,5 +1,5 @@
|
||||
| Supported Targets | ESP32-C2 | ESP32-C3 | ESP32-C6 |
|
||||
| ----------------- | -------- | -------- | -------- |
|
||||
| Supported Targets | ESP32-C2 | ESP32-C3 | ESP32-C6 | ESP32-H2 |
|
||||
| ----------------- | -------- | -------- | -------- | -------- |
|
||||
|
||||
# Example: UART software emulation using dedicated/fast GPIOs
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user