mirror of
https://github.com/espressif/esp-idf
synced 2025-03-10 09:39:10 -04:00
Merge branch 'feature/fast_gpio_esp32p4' into 'master'
feat(fast_gpio): support fast GPIO and glitch filter on esp32p4 Closes IDF-7552, IDF-8974, IDF-7721, and IDF-7481 See merge request espressif/esp-idf!28642
This commit is contained in:
commit
79897ccd10
@ -1,2 +1,2 @@
|
|||||||
| Supported Targets | ESP32-C2 | ESP32-C3 | ESP32-C6 | ESP32-H2 | ESP32-S2 | ESP32-S3 |
|
| Supported Targets | ESP32-C2 | ESP32-C3 | ESP32-C6 | ESP32-H2 | ESP32-P4 | ESP32-S2 | ESP32-S3 |
|
||||||
| ----------------- | -------- | -------- | -------- | -------- | -------- | -------- |
|
| ----------------- | -------- | -------- | -------- | -------- | -------- | -------- | -------- |
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* SPDX-FileCopyrightText: 2021-2022 Espressif Systems (Shanghai) CO LTD
|
* SPDX-FileCopyrightText: 2021-2024 Espressif Systems (Shanghai) CO LTD
|
||||||
*
|
*
|
||||||
* SPDX-License-Identifier: Apache-2.0
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
*/
|
*/
|
||||||
@ -146,7 +146,11 @@ TEST_CASE("Dedicated_GPIO_run_on_multiple_CPU_cores", "[dedic_gpio]")
|
|||||||
TaskHandle_t task_handle[SOC_CPU_CORES_NUM];
|
TaskHandle_t task_handle[SOC_CPU_CORES_NUM];
|
||||||
|
|
||||||
for (int i = 0; i < SOC_CPU_CORES_NUM; i++) {
|
for (int i = 0; i < SOC_CPU_CORES_NUM; i++) {
|
||||||
|
#if CONFIG_IDF_TARGET_ESP32P4
|
||||||
|
int start_gpio = i * TEST_GPIO_GROUP_SIZE + 20;
|
||||||
|
#else
|
||||||
int start_gpio = i * TEST_GPIO_GROUP_SIZE;
|
int start_gpio = i * TEST_GPIO_GROUP_SIZE;
|
||||||
|
#endif
|
||||||
test_dedic_task_context_t isr_ctx = {
|
test_dedic_task_context_t isr_ctx = {
|
||||||
.sem = sem,
|
.sem = sem,
|
||||||
.gpios = {start_gpio, start_gpio + 1, start_gpio + 2, start_gpio + 3}
|
.gpios = {start_gpio, start_gpio + 1, start_gpio + 2, start_gpio + 3}
|
||||||
@ -181,7 +185,11 @@ TEST_CASE("Dedicated_GPIO_interrupt_and_callback", "[dedic_gpio]")
|
|||||||
SemaphoreHandle_t sem = xSemaphoreCreateBinary();
|
SemaphoreHandle_t sem = xSemaphoreCreateBinary();
|
||||||
|
|
||||||
// configure GPIO
|
// configure GPIO
|
||||||
|
#if CONFIG_IDF_TARGET_ESP32P4
|
||||||
|
const int bundle_gpios[] = {20, 21};
|
||||||
|
#else
|
||||||
const int bundle_gpios[] = {0, 1};
|
const int bundle_gpios[] = {0, 1};
|
||||||
|
#endif
|
||||||
gpio_config_t io_conf = {
|
gpio_config_t io_conf = {
|
||||||
.mode = GPIO_MODE_INPUT_OUTPUT,
|
.mode = GPIO_MODE_INPUT_OUTPUT,
|
||||||
};
|
};
|
||||||
@ -200,12 +208,12 @@ TEST_CASE("Dedicated_GPIO_interrupt_and_callback", "[dedic_gpio]")
|
|||||||
};
|
};
|
||||||
TEST_ESP_OK(dedic_gpio_new_bundle(&bundle_config, &bundle));
|
TEST_ESP_OK(dedic_gpio_new_bundle(&bundle_config, &bundle));
|
||||||
|
|
||||||
// enable interrupt on GPIO1
|
// enable interrupt
|
||||||
TEST_ESP_OK(gpio_set_intr_type(1, GPIO_INTR_POSEDGE));
|
TEST_ESP_OK(gpio_set_intr_type(bundle_gpios[1], GPIO_INTR_POSEDGE));
|
||||||
// install gpio isr service
|
// install gpio isr service
|
||||||
TEST_ESP_OK(gpio_install_isr_service(0));
|
TEST_ESP_OK(gpio_install_isr_service(0));
|
||||||
// hook isr handler for specific gpio pin
|
// hook isr handler for specific gpio pin
|
||||||
TEST_ESP_OK(gpio_isr_handler_add(1, test_dedic_gpio_isr_callback, sem));
|
TEST_ESP_OK(gpio_isr_handler_add(bundle_gpios[1], test_dedic_gpio_isr_callback, sem));
|
||||||
|
|
||||||
// trigger a posedge on GPIO1
|
// trigger a posedge on GPIO1
|
||||||
dedic_gpio_bundle_write(bundle, BIT(1), 0x00);
|
dedic_gpio_bundle_write(bundle, BIT(1), 0x00);
|
||||||
@ -214,7 +222,7 @@ TEST_CASE("Dedicated_GPIO_interrupt_and_callback", "[dedic_gpio]")
|
|||||||
TEST_ASSERT_EQUAL(pdTRUE, xSemaphoreTake(sem, pdMS_TO_TICKS(1000)));
|
TEST_ASSERT_EQUAL(pdTRUE, xSemaphoreTake(sem, pdMS_TO_TICKS(1000)));
|
||||||
|
|
||||||
// remove isr handler for gpio number
|
// remove isr handler for gpio number
|
||||||
TEST_ESP_OK(gpio_isr_handler_remove(1));
|
TEST_ESP_OK(gpio_isr_handler_remove(bundle_gpios[1]));
|
||||||
// uninstall GPIO interrupt service
|
// uninstall GPIO interrupt service
|
||||||
gpio_uninstall_isr_service();
|
gpio_uninstall_isr_service();
|
||||||
|
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* SPDX-FileCopyrightText: 2022-2023 Espressif Systems (Shanghai) CO LTD
|
* SPDX-FileCopyrightText: 2022-2024 Espressif Systems (Shanghai) CO LTD
|
||||||
*
|
*
|
||||||
* SPDX-License-Identifier: Apache-2.0
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
*/
|
*/
|
||||||
@ -14,6 +14,12 @@
|
|||||||
#include "driver/dedic_gpio.h"
|
#include "driver/dedic_gpio.h"
|
||||||
#include "soc/soc_caps.h"
|
#include "soc/soc_caps.h"
|
||||||
|
|
||||||
|
#if CONFIG_IDF_TARGET_ESP32P4
|
||||||
|
#define TEST_FILTER_GPIO 20
|
||||||
|
#else
|
||||||
|
#define TEST_FILTER_GPIO 2
|
||||||
|
#endif
|
||||||
|
|
||||||
#if SOC_GPIO_SUPPORT_PIN_GLITCH_FILTER
|
#if SOC_GPIO_SUPPORT_PIN_GLITCH_FILTER
|
||||||
|
|
||||||
TEST_CASE("GPIO pin glitch filter life cycle", "[gpio_filter]")
|
TEST_CASE("GPIO pin glitch filter life cycle", "[gpio_filter]")
|
||||||
@ -108,7 +114,7 @@ NOINLINE_ATTR IRAM_ATTR static void test_gpio_simulate_glitch_pulse(void)
|
|||||||
|
|
||||||
TEST_CASE("GPIO flex glitch filter enable/disable", "[gpio_filter]")
|
TEST_CASE("GPIO flex glitch filter enable/disable", "[gpio_filter]")
|
||||||
{
|
{
|
||||||
const gpio_num_t test_gpio = 2;
|
const gpio_num_t test_gpio = TEST_FILTER_GPIO;
|
||||||
|
|
||||||
printf("initialize GPIO for input and out\r\n");
|
printf("initialize GPIO for input and out\r\n");
|
||||||
gpio_config_t gpio_cfg = {
|
gpio_config_t gpio_cfg = {
|
||||||
|
@ -1,6 +1,5 @@
|
|||||||
# SPDX-FileCopyrightText: 2022-2023 Espressif Systems (Shanghai) CO LTD
|
# SPDX-FileCopyrightText: 2022-2023 Espressif Systems (Shanghai) CO LTD
|
||||||
# SPDX-License-Identifier: CC0-1.0
|
# SPDX-License-Identifier: CC0-1.0
|
||||||
|
|
||||||
import pytest
|
import pytest
|
||||||
from pytest_embedded_idf import IdfDut
|
from pytest_embedded_idf import IdfDut
|
||||||
|
|
||||||
@ -16,6 +15,7 @@ CONFIGS = [
|
|||||||
@pytest.mark.esp32h2
|
@pytest.mark.esp32h2
|
||||||
@pytest.mark.esp32s2
|
@pytest.mark.esp32s2
|
||||||
@pytest.mark.esp32s3
|
@pytest.mark.esp32s3
|
||||||
|
@pytest.mark.esp32p4
|
||||||
@pytest.mark.generic
|
@pytest.mark.generic
|
||||||
@pytest.mark.parametrize('config', CONFIGS, indirect=True)
|
@pytest.mark.parametrize('config', CONFIGS, indirect=True)
|
||||||
def test_gpio_filter(dut: IdfDut) -> None:
|
def test_gpio_filter(dut: IdfDut) -> None:
|
||||||
@ -28,6 +28,7 @@ def test_gpio_filter(dut: IdfDut) -> None:
|
|||||||
@pytest.mark.esp32h2
|
@pytest.mark.esp32h2
|
||||||
@pytest.mark.esp32s2
|
@pytest.mark.esp32s2
|
||||||
@pytest.mark.esp32s3
|
@pytest.mark.esp32s3
|
||||||
|
@pytest.mark.esp32p4
|
||||||
@pytest.mark.generic
|
@pytest.mark.generic
|
||||||
@pytest.mark.parametrize('config', CONFIGS, indirect=True)
|
@pytest.mark.parametrize('config', CONFIGS, indirect=True)
|
||||||
def test_dedic_gpio(dut: IdfDut) -> None:
|
def test_dedic_gpio(dut: IdfDut) -> None:
|
||||||
|
@ -25,10 +25,6 @@ components/esp_hw_support/test_apps/esp_hw_support_unity_tests:
|
|||||||
components/esp_hw_support/test_apps/etm:
|
components/esp_hw_support/test_apps/etm:
|
||||||
disable:
|
disable:
|
||||||
- if: SOC_ETM_SUPPORTED != 1
|
- if: SOC_ETM_SUPPORTED != 1
|
||||||
disable_test:
|
|
||||||
- if: IDF_TARGET == "esp32p4"
|
|
||||||
temporary: true
|
|
||||||
reason: test not pass, should be re-enable # TODO: IDF-8974
|
|
||||||
depends_components:
|
depends_components:
|
||||||
- esp_driver_gptimer
|
- esp_driver_gptimer
|
||||||
- esp_driver_gpio
|
- esp_driver_gpio
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD
|
* SPDX-FileCopyrightText: 2023-2024 Espressif Systems (Shanghai) CO LTD
|
||||||
*
|
*
|
||||||
* SPDX-License-Identifier: Apache-2.0
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
*/
|
*/
|
||||||
@ -19,7 +19,7 @@
|
|||||||
#define TEST_ANA_CMPR_UNIT 0
|
#define TEST_ANA_CMPR_UNIT 0
|
||||||
#define TEST_TIME_US 5000
|
#define TEST_TIME_US 5000
|
||||||
|
|
||||||
static gptimer_handle_t s_test_ana_cmpr_gptimer_init(void)
|
static gptimer_handle_t test_ana_cmpr_gptimer_init(void)
|
||||||
{
|
{
|
||||||
gptimer_handle_t gptimer = NULL;
|
gptimer_handle_t gptimer = NULL;
|
||||||
gptimer_config_t timer_config = {
|
gptimer_config_t timer_config = {
|
||||||
@ -33,13 +33,13 @@ static gptimer_handle_t s_test_ana_cmpr_gptimer_init(void)
|
|||||||
return gptimer;
|
return gptimer;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void s_test_ana_cmpr_gptimer_deinit(gptimer_handle_t gptimer)
|
static void test_ana_cmpr_gptimer_deinit(gptimer_handle_t gptimer)
|
||||||
{
|
{
|
||||||
TEST_ESP_OK(gptimer_disable(gptimer));
|
TEST_ESP_OK(gptimer_disable(gptimer));
|
||||||
TEST_ESP_OK(gptimer_del_timer(gptimer));
|
TEST_ESP_OK(gptimer_del_timer(gptimer));
|
||||||
}
|
}
|
||||||
|
|
||||||
static ana_cmpr_handle_t s_test_ana_cmpr_init(void)
|
static ana_cmpr_handle_t test_ana_cmpr_init(void)
|
||||||
{
|
{
|
||||||
ana_cmpr_handle_t cmpr = NULL;
|
ana_cmpr_handle_t cmpr = NULL;
|
||||||
|
|
||||||
@ -65,13 +65,13 @@ static ana_cmpr_handle_t s_test_ana_cmpr_init(void)
|
|||||||
return cmpr;
|
return cmpr;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void s_test_ana_cmpr_deinit(ana_cmpr_handle_t cmpr)
|
static void test_ana_cmpr_deinit(ana_cmpr_handle_t cmpr)
|
||||||
{
|
{
|
||||||
TEST_ESP_OK(ana_cmpr_disable(cmpr));
|
TEST_ESP_OK(ana_cmpr_disable(cmpr));
|
||||||
TEST_ESP_OK(ana_cmpr_del_unit(cmpr));
|
TEST_ESP_OK(ana_cmpr_del_unit(cmpr));
|
||||||
}
|
}
|
||||||
|
|
||||||
static int s_test_ana_cmpr_src_gpio_init(void)
|
static int test_ana_cmpr_src_gpio_init(void)
|
||||||
{
|
{
|
||||||
int gpio_num = -1;
|
int gpio_num = -1;
|
||||||
TEST_ESP_OK(ana_cmpr_get_gpio(TEST_ANA_CMPR_UNIT, ANA_CMPR_SOURCE_CHAN, &gpio_num));
|
TEST_ESP_OK(ana_cmpr_get_gpio(TEST_ANA_CMPR_UNIT, ANA_CMPR_SOURCE_CHAN, &gpio_num));
|
||||||
@ -96,7 +96,7 @@ typedef struct {
|
|||||||
esp_etm_channel_handle_t etm_neg_handle;
|
esp_etm_channel_handle_t etm_neg_handle;
|
||||||
} test_ana_cmpr_etm_handles_t;
|
} test_ana_cmpr_etm_handles_t;
|
||||||
|
|
||||||
static test_ana_cmpr_etm_handles_t s_test_ana_cmpr_init_etm(ana_cmpr_handle_t cmpr, gptimer_handle_t gptimer)
|
static test_ana_cmpr_etm_handles_t test_ana_cmpr_init_etm(ana_cmpr_handle_t cmpr, gptimer_handle_t gptimer)
|
||||||
{
|
{
|
||||||
test_ana_cmpr_etm_handles_t etm_handles = {};
|
test_ana_cmpr_etm_handles_t etm_handles = {};
|
||||||
|
|
||||||
@ -105,7 +105,7 @@ static test_ana_cmpr_etm_handles_t s_test_ana_cmpr_init_etm(ana_cmpr_handle_t cm
|
|||||||
.event_type = ANA_CMPR_EVENT_POS_CROSS,
|
.event_type = ANA_CMPR_EVENT_POS_CROSS,
|
||||||
};
|
};
|
||||||
TEST_ESP_OK(ana_cmpr_new_etm_event(cmpr, &evt_cfg, &etm_handles.cmpr_pos_evt));
|
TEST_ESP_OK(ana_cmpr_new_etm_event(cmpr, &evt_cfg, &etm_handles.cmpr_pos_evt));
|
||||||
evt_cfg.event_type = GPIO_ETM_EVENT_EDGE_NEG;
|
evt_cfg.event_type = ANA_CMPR_EVENT_NEG_CROSS;
|
||||||
TEST_ESP_OK(ana_cmpr_new_etm_event(cmpr, &evt_cfg, &etm_handles.cmpr_neg_evt));
|
TEST_ESP_OK(ana_cmpr_new_etm_event(cmpr, &evt_cfg, &etm_handles.cmpr_neg_evt));
|
||||||
|
|
||||||
/* Allocate the GPTimer tasks */
|
/* Allocate the GPTimer tasks */
|
||||||
@ -121,8 +121,8 @@ static test_ana_cmpr_etm_handles_t s_test_ana_cmpr_init_etm(ana_cmpr_handle_t cm
|
|||||||
TEST_ESP_OK(esp_etm_new_channel(&etm_cfg, &etm_handles.etm_pos_handle));
|
TEST_ESP_OK(esp_etm_new_channel(&etm_cfg, &etm_handles.etm_pos_handle));
|
||||||
TEST_ESP_OK(esp_etm_new_channel(&etm_cfg, &etm_handles.etm_neg_handle));
|
TEST_ESP_OK(esp_etm_new_channel(&etm_cfg, &etm_handles.etm_neg_handle));
|
||||||
/* Bind the events and tasks */
|
/* Bind the events and tasks */
|
||||||
TEST_ESP_OK(esp_etm_channel_connect(etm_handles.etm_pos_handle, etm_handles.cmpr_pos_evt, etm_handles.gptimer_start_task));
|
TEST_ESP_OK(esp_etm_channel_connect(etm_handles.etm_neg_handle, etm_handles.cmpr_neg_evt, etm_handles.gptimer_start_task));
|
||||||
TEST_ESP_OK(esp_etm_channel_connect(etm_handles.etm_neg_handle, etm_handles.cmpr_neg_evt, etm_handles.gptimer_stop_task));
|
TEST_ESP_OK(esp_etm_channel_connect(etm_handles.etm_pos_handle, etm_handles.cmpr_pos_evt, etm_handles.gptimer_stop_task));
|
||||||
/* Enable the ETM channels */
|
/* Enable the ETM channels */
|
||||||
TEST_ESP_OK(esp_etm_channel_enable(etm_handles.etm_pos_handle));
|
TEST_ESP_OK(esp_etm_channel_enable(etm_handles.etm_pos_handle));
|
||||||
TEST_ESP_OK(esp_etm_channel_enable(etm_handles.etm_neg_handle));
|
TEST_ESP_OK(esp_etm_channel_enable(etm_handles.etm_neg_handle));
|
||||||
@ -130,10 +130,10 @@ static test_ana_cmpr_etm_handles_t s_test_ana_cmpr_init_etm(ana_cmpr_handle_t cm
|
|||||||
return etm_handles;
|
return etm_handles;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void s_test_ana_cmpr_deinit_etm(test_ana_cmpr_etm_handles_t handles)
|
static void test_ana_cmpr_deinit_etm(test_ana_cmpr_etm_handles_t handles)
|
||||||
{
|
{
|
||||||
TEST_ESP_OK(esp_etm_channel_disable(handles.etm_pos_handle));
|
TEST_ESP_OK(esp_etm_channel_disable(handles.etm_pos_handle));
|
||||||
TEST_ESP_OK(esp_etm_channel_disable(handles.etm_pos_handle));
|
TEST_ESP_OK(esp_etm_channel_disable(handles.etm_neg_handle));
|
||||||
|
|
||||||
TEST_ESP_OK(esp_etm_del_task(handles.gptimer_start_task));
|
TEST_ESP_OK(esp_etm_del_task(handles.gptimer_start_task));
|
||||||
TEST_ESP_OK(esp_etm_del_task(handles.gptimer_stop_task));
|
TEST_ESP_OK(esp_etm_del_task(handles.gptimer_stop_task));
|
||||||
@ -147,21 +147,27 @@ static void s_test_ana_cmpr_deinit_etm(test_ana_cmpr_etm_handles_t handles)
|
|||||||
|
|
||||||
TEST_CASE("analog_comparator_etm_event", "[etm]")
|
TEST_CASE("analog_comparator_etm_event", "[etm]")
|
||||||
{
|
{
|
||||||
gptimer_handle_t gptimer = s_test_ana_cmpr_gptimer_init();
|
gptimer_handle_t gptimer = test_ana_cmpr_gptimer_init();
|
||||||
ana_cmpr_handle_t cmpr = s_test_ana_cmpr_init();
|
ana_cmpr_handle_t cmpr = test_ana_cmpr_init();
|
||||||
int src_gpio = s_test_ana_cmpr_src_gpio_init();
|
int src_gpio = test_ana_cmpr_src_gpio_init();
|
||||||
test_ana_cmpr_etm_handles_t handles = s_test_ana_cmpr_init_etm(cmpr, gptimer);
|
test_ana_cmpr_etm_handles_t handles = test_ana_cmpr_init_etm(cmpr, gptimer);
|
||||||
|
|
||||||
|
// triggers a negative pulse, whose duration is ~TEST_TIME_US
|
||||||
gpio_set_level(src_gpio, 0);
|
gpio_set_level(src_gpio, 0);
|
||||||
esp_rom_delay_us(TEST_TIME_US);
|
esp_rom_delay_us(TEST_TIME_US);
|
||||||
gpio_set_level(src_gpio, 1);
|
gpio_set_level(src_gpio, 1);
|
||||||
|
|
||||||
uint64_t cnt_us = 0;
|
uint64_t cnt_us = 0;
|
||||||
TEST_ESP_OK(gptimer_get_raw_count(gptimer, &cnt_us));
|
TEST_ESP_OK(gptimer_get_raw_count(gptimer, &cnt_us));
|
||||||
|
printf("Count: %" PRIu64 "\n", cnt_us);
|
||||||
|
// gptimer timer should stopped
|
||||||
|
uint64_t cnt_us_again = 0;
|
||||||
|
TEST_ESP_OK(gptimer_get_raw_count(gptimer, &cnt_us_again));
|
||||||
|
TEST_ASSERT(cnt_us_again == cnt_us);
|
||||||
|
|
||||||
s_test_ana_cmpr_deinit_etm(handles);
|
test_ana_cmpr_deinit_etm(handles);
|
||||||
s_test_ana_cmpr_deinit(cmpr);
|
test_ana_cmpr_deinit(cmpr);
|
||||||
s_test_ana_cmpr_gptimer_deinit(gptimer);
|
test_ana_cmpr_gptimer_deinit(gptimer);
|
||||||
|
|
||||||
TEST_ASSERT_UINT64_WITHIN(TEST_TIME_US * 0.1, 5000, cnt_us);
|
TEST_ASSERT_UINT_WITHIN(TEST_TIME_US * 0.1, TEST_TIME_US, cnt_us);
|
||||||
}
|
}
|
||||||
|
@ -1,12 +1,12 @@
|
|||||||
# SPDX-FileCopyrightText: 2022-2023 Espressif Systems (Shanghai) CO LTD
|
# SPDX-FileCopyrightText: 2022-2023 Espressif Systems (Shanghai) CO LTD
|
||||||
# SPDX-License-Identifier: CC0-1.0
|
# SPDX-License-Identifier: CC0-1.0
|
||||||
|
|
||||||
import pytest
|
import pytest
|
||||||
from pytest_embedded import Dut
|
from pytest_embedded import Dut
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.esp32c6
|
@pytest.mark.esp32c6
|
||||||
@pytest.mark.esp32h2
|
@pytest.mark.esp32h2
|
||||||
|
@pytest.mark.esp32p4
|
||||||
@pytest.mark.generic
|
@pytest.mark.generic
|
||||||
@pytest.mark.parametrize(
|
@pytest.mark.parametrize(
|
||||||
'config',
|
'config',
|
||||||
|
57
components/hal/esp32p4/include/hal/dedic_gpio_cpu_ll.h
Normal file
57
components/hal/esp32p4/include/hal/dedic_gpio_cpu_ll.h
Normal file
@ -0,0 +1,57 @@
|
|||||||
|
/*
|
||||||
|
* SPDX-FileCopyrightText: 2024 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)
|
||||||
|
{
|
||||||
|
// the OEN register is active low
|
||||||
|
RV_CLEAR_CSR(CSR_GPIO_OEN_USER, mask);
|
||||||
|
}
|
||||||
|
|
||||||
|
__attribute__((always_inline))
|
||||||
|
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
|
60
components/hal/esp32p4/include/hal/gpio_glitch_filter_ll.h
Normal file
60
components/hal/esp32p4/include/hal/gpio_glitch_filter_ll.h
Normal file
@ -0,0 +1,60 @@
|
|||||||
|
/*
|
||||||
|
* SPDX-FileCopyrightText: 2023-2024 Espressif Systems (Shanghai) CO LTD
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
|
*/
|
||||||
|
|
||||||
|
#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
|
58
components/soc/esp32p4/dedic_gpio_periph.c
Normal file
58
components/soc/esp32p4/dedic_gpio_periph.c
Normal file
@ -0,0 +1,58 @@
|
|||||||
|
/*
|
||||||
|
* SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "soc/gpio_sig_map.h"
|
||||||
|
#include "soc/dedic_gpio_periph.h"
|
||||||
|
|
||||||
|
const dedic_gpio_signal_conn_t dedic_gpio_periph_signals = {
|
||||||
|
.irq = -1,
|
||||||
|
.cores = {
|
||||||
|
[0] = {
|
||||||
|
.in_sig_per_channel = {
|
||||||
|
[0] = CORE_GPIO_IN_PAD_IN0_IDX,
|
||||||
|
[1] = CORE_GPIO_IN_PAD_IN1_IDX,
|
||||||
|
[2] = CORE_GPIO_IN_PAD_IN2_IDX,
|
||||||
|
[3] = CORE_GPIO_IN_PAD_IN3_IDX,
|
||||||
|
[4] = CORE_GPIO_IN_PAD_IN4_IDX,
|
||||||
|
[5] = CORE_GPIO_IN_PAD_IN5_IDX,
|
||||||
|
[6] = CORE_GPIO_IN_PAD_IN6_IDX,
|
||||||
|
[7] = CORE_GPIO_IN_PAD_IN7_IDX,
|
||||||
|
},
|
||||||
|
.out_sig_per_channel = {
|
||||||
|
[0] = CORE_GPIO_OUT_PAD_OUT0_IDX,
|
||||||
|
[1] = CORE_GPIO_OUT_PAD_OUT1_IDX,
|
||||||
|
[2] = CORE_GPIO_OUT_PAD_OUT2_IDX,
|
||||||
|
[3] = CORE_GPIO_OUT_PAD_OUT3_IDX,
|
||||||
|
[4] = CORE_GPIO_OUT_PAD_OUT4_IDX,
|
||||||
|
[5] = CORE_GPIO_OUT_PAD_OUT5_IDX,
|
||||||
|
[6] = CORE_GPIO_OUT_PAD_OUT6_IDX,
|
||||||
|
[7] = CORE_GPIO_OUT_PAD_OUT7_IDX,
|
||||||
|
}
|
||||||
|
},
|
||||||
|
[1] = {
|
||||||
|
.in_sig_per_channel = {
|
||||||
|
[0] = CORE_GPIO_IN_PAD_IN8_IDX,
|
||||||
|
[1] = CORE_GPIO_IN_PAD_IN9_IDX,
|
||||||
|
[2] = CORE_GPIO_IN_PAD_IN10_IDX,
|
||||||
|
[3] = CORE_GPIO_IN_PAD_IN11_IDX,
|
||||||
|
[4] = CORE_GPIO_IN_PAD_IN12_IDX,
|
||||||
|
[5] = CORE_GPIO_IN_PAD_IN13_IDX,
|
||||||
|
[6] = CORE_GPIO_IN_PAD_IN14_IDX,
|
||||||
|
[7] = CORE_GPIO_IN_PAD_IN15_IDX,
|
||||||
|
},
|
||||||
|
.out_sig_per_channel = {
|
||||||
|
[0] = CORE_GPIO_OUT_PAD_OUT8_IDX,
|
||||||
|
[1] = CORE_GPIO_OUT_PAD_OUT9_IDX,
|
||||||
|
[2] = CORE_GPIO_OUT_PAD_OUT10_IDX,
|
||||||
|
[3] = CORE_GPIO_OUT_PAD_OUT11_IDX,
|
||||||
|
[4] = CORE_GPIO_OUT_PAD_OUT12_IDX,
|
||||||
|
[5] = CORE_GPIO_OUT_PAD_OUT13_IDX,
|
||||||
|
[6] = CORE_GPIO_OUT_PAD_OUT14_IDX,
|
||||||
|
[7] = CORE_GPIO_OUT_PAD_OUT15_IDX,
|
||||||
|
}
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
@ -7,6 +7,10 @@ config SOC_ANA_CMPR_SUPPORTED
|
|||||||
bool
|
bool
|
||||||
default y
|
default y
|
||||||
|
|
||||||
|
config SOC_DEDICATED_GPIO_SUPPORTED
|
||||||
|
bool
|
||||||
|
default y
|
||||||
|
|
||||||
config SOC_UART_SUPPORTED
|
config SOC_UART_SUPPORTED
|
||||||
bool
|
bool
|
||||||
default y
|
default y
|
||||||
@ -463,6 +467,14 @@ config SOC_GPIO_PIN_COUNT
|
|||||||
int
|
int
|
||||||
default 55
|
default 55
|
||||||
|
|
||||||
|
config SOC_GPIO_SUPPORT_PIN_GLITCH_FILTER
|
||||||
|
bool
|
||||||
|
default y
|
||||||
|
|
||||||
|
config SOC_GPIO_FLEX_GLITCH_FILTER_NUM
|
||||||
|
int
|
||||||
|
default 8
|
||||||
|
|
||||||
config SOC_GPIO_SUPPORT_PIN_HYS_FILTER
|
config SOC_GPIO_SUPPORT_PIN_HYS_FILTER
|
||||||
bool
|
bool
|
||||||
default y
|
default y
|
||||||
|
@ -249,8 +249,6 @@ typedef enum {
|
|||||||
RMT_BASECLK_DEFAULT = SOC_MOD_CLK_PLL_F80M, /*!< RMT source clock default choice is PLL_F80M */
|
RMT_BASECLK_DEFAULT = SOC_MOD_CLK_PLL_F80M, /*!< RMT source clock default choice is PLL_F80M */
|
||||||
} soc_periph_rmt_clk_src_legacy_t;
|
} soc_periph_rmt_clk_src_legacy_t;
|
||||||
|
|
||||||
//////////////////////////////////////////////////Temp Sensor///////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
///////////////////////////////////////////////////UART/////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////UART/////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -509,6 +507,21 @@ typedef enum {
|
|||||||
|
|
||||||
//////////////////////////////////////////////////GPIO Glitch Filter////////////////////////////////////////////////////
|
//////////////////////////////////////////////////GPIO Glitch Filter////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Array initializer for all supported clock sources of Glitch Filter
|
||||||
|
*/
|
||||||
|
#define SOC_GLITCH_FILTER_CLKS {SOC_MOD_CLK_PLL_F80M, SOC_MOD_CLK_XTAL}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Glitch filter clock source
|
||||||
|
*/
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
GLITCH_FILTER_CLK_SRC_XTAL = SOC_MOD_CLK_XTAL, /*!< Select XTAL clock as the source clock */
|
||||||
|
GLITCH_FILTER_CLK_SRC_PLL_F80M = SOC_MOD_CLK_PLL_F80M, /*!< Select PLL_F80M clock as the source clock */
|
||||||
|
GLITCH_FILTER_CLK_SRC_DEFAULT = SOC_MOD_CLK_PLL_F80M, /*!< Select PLL_F80M clock as the default clock choice */
|
||||||
|
} soc_periph_glitch_filter_clk_src_t;
|
||||||
|
|
||||||
///////////////////////////////////////////////////Analog Comparator////////////////////////////////////////////////////
|
///////////////////////////////////////////////////Analog Comparator////////////////////////////////////////////////////
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -19,7 +19,7 @@
|
|||||||
/*-------------------------- COMMON CAPS ---------------------------------------*/
|
/*-------------------------- COMMON CAPS ---------------------------------------*/
|
||||||
// #define SOC_ADC_SUPPORTED 1 //TODO: IDF-6496
|
// #define SOC_ADC_SUPPORTED 1 //TODO: IDF-6496
|
||||||
#define SOC_ANA_CMPR_SUPPORTED 1
|
#define SOC_ANA_CMPR_SUPPORTED 1
|
||||||
// #define SOC_DEDICATED_GPIO_SUPPORTED 1 //TODO: IDF-7552
|
#define SOC_DEDICATED_GPIO_SUPPORTED 1
|
||||||
#define SOC_UART_SUPPORTED 1
|
#define SOC_UART_SUPPORTED 1
|
||||||
#define SOC_GDMA_SUPPORTED 1
|
#define SOC_GDMA_SUPPORTED 1
|
||||||
#define SOC_AHB_GDMA_SUPPORTED 1
|
#define SOC_AHB_GDMA_SUPPORTED 1
|
||||||
@ -200,8 +200,8 @@
|
|||||||
// ESP32-P4 has 1 GPIO peripheral
|
// ESP32-P4 has 1 GPIO peripheral
|
||||||
#define SOC_GPIO_PORT 1U
|
#define SOC_GPIO_PORT 1U
|
||||||
#define SOC_GPIO_PIN_COUNT 55
|
#define SOC_GPIO_PIN_COUNT 55
|
||||||
// #define SOC_GPIO_SUPPORT_PIN_GLITCH_FILTER 1 //TODO: IDF-7481
|
#define SOC_GPIO_SUPPORT_PIN_GLITCH_FILTER 1
|
||||||
// #define SOC_GPIO_FLEX_GLITCH_FILTER_NUM 8 //TODO: IDF-7481
|
#define SOC_GPIO_FLEX_GLITCH_FILTER_NUM 8
|
||||||
#define SOC_GPIO_SUPPORT_PIN_HYS_FILTER 1
|
#define SOC_GPIO_SUPPORT_PIN_HYS_FILTER 1
|
||||||
|
|
||||||
// GPIO peripheral has the ETM extension
|
// GPIO peripheral has the ETM extension
|
||||||
|
@ -77,7 +77,6 @@ api-reference/peripherals/touch_pad.rst
|
|||||||
api-reference/peripherals/adc_calibration.rst
|
api-reference/peripherals/adc_calibration.rst
|
||||||
api-reference/peripherals/parlio.rst
|
api-reference/peripherals/parlio.rst
|
||||||
api-reference/peripherals/i2c.rst
|
api-reference/peripherals/i2c.rst
|
||||||
api-reference/peripherals/dedic_gpio.rst
|
|
||||||
api-reference/peripherals/sd_pullup_requirements.rst
|
api-reference/peripherals/sd_pullup_requirements.rst
|
||||||
api-reference/peripherals/index.rst
|
api-reference/peripherals/index.rst
|
||||||
api-reference/network/esp_openthread.rst
|
api-reference/network/esp_openthread.rst
|
||||||
|
@ -112,9 +112,7 @@ For advanced users, they can always manipulate the GPIOs by writing assembly cod
|
|||||||
|
|
||||||
For details of supported dedicated GPIO instructions, please refer to **{IDF_TARGET_NAME} Technical Reference Manual** > **Processor Instruction Extensions (PIE) (to be added later)** [`PDF <{IDF_TARGET_TRM_EN_URL}#pie>`__].
|
For details of supported dedicated GPIO instructions, please refer to **{IDF_TARGET_NAME} Technical Reference Manual** > **Processor Instruction Extensions (PIE) (to be added later)** [`PDF <{IDF_TARGET_TRM_EN_URL}#pie>`__].
|
||||||
|
|
||||||
.. only:: esp32c2 or esp32c3 or esp32c6 or esp32h2
|
.. only:: not (esp32s2 or esp32s3)
|
||||||
|
|
||||||
Code examples for manipulating dedicated GPIOs from assembly are provided in the :example:`peripherals/dedicated_gpio` directory of ESP-IDF examples. These examples show how to emulate a UART, an I2C and an SPI bus in assembly thanks to dedicated GPIOs.
|
|
||||||
|
|
||||||
For details of supported dedicated GPIO instructions, please refer to **{IDF_TARGET_NAME} Technical Reference Manual** > **ESP-RISC-V CPU** [`PDF <{IDF_TARGET_TRM_EN_URL}#riscvcpu>`__].
|
For details of supported dedicated GPIO instructions, please refer to **{IDF_TARGET_NAME} Technical Reference Manual** > **ESP-RISC-V CPU** [`PDF <{IDF_TARGET_TRM_EN_URL}#riscvcpu>`__].
|
||||||
|
|
||||||
@ -152,12 +150,14 @@ Some of the dedicated CPU instructions are also wrapped inside ``hal/dedic_gpio_
|
|||||||
// wait for done semaphore
|
// wait for done semaphore
|
||||||
xSemaphoreTake(sem, portMAX_DELAY);
|
xSemaphoreTake(sem, portMAX_DELAY);
|
||||||
|
|
||||||
.. only:: SOC_DEDIC_GPIO_HAS_INTERRUPT
|
|
||||||
|
|
||||||
Application Example
|
Application Example
|
||||||
-------------------
|
-------------------
|
||||||
|
|
||||||
Matrix keyboard example based on dedicated GPIO: :example:`peripherals/gpio/matrix_keyboard`.
|
.. list::
|
||||||
|
|
||||||
|
* Emulate UART/I2C/SPI peripherals in assembly with dedicate CPU instructions designed for manipulating the GPIOs: :example:`peripherals/dedicated_gpio`.
|
||||||
|
:SOC_DEDIC_GPIO_HAS_INTERRUPT: * Matrix keyboard example based on dedicated GPIO: :example:`peripherals/gpio/matrix_keyboard`.
|
||||||
|
|
||||||
|
|
||||||
API Reference
|
API Reference
|
||||||
|
@ -112,9 +112,7 @@ GPIO 捆绑包操作
|
|||||||
|
|
||||||
有关支持的专用 GPIO 指令的详细信息,请参考 **{IDF_TARGET_NAME} 技术参考手册** > **处理器指令拓展 (PIE)(稍后发布)** [`PDF <{IDF_TARGET_TRM_CN_URL}#pie>`__].
|
有关支持的专用 GPIO 指令的详细信息,请参考 **{IDF_TARGET_NAME} 技术参考手册** > **处理器指令拓展 (PIE)(稍后发布)** [`PDF <{IDF_TARGET_TRM_CN_URL}#pie>`__].
|
||||||
|
|
||||||
.. only:: esp32c2 or esp32c3 or esp32c6 or esp32h2
|
.. only:: not (esp32s2 or esp32s3)
|
||||||
|
|
||||||
通过汇编操作专用 GPIO 的示例代码存放在 ESP-IDF 示例项目的 :example:`peripherals/dedicated_gpio` 目录下。示例演示了如何通过汇编操作专用 GPIO 来模拟 UART、I2C 和 SPI 总线。
|
|
||||||
|
|
||||||
有关支持的专用 GPIO 指令的详细信息,请参考 **{IDF_TARGET_NAME} 技术参考手册** > **ESP-RISC-V CPU** [`PDF <{IDF_TARGET_TRM_CN_URL}#riscvcpu>`__]。
|
有关支持的专用 GPIO 指令的详细信息,请参考 **{IDF_TARGET_NAME} 技术参考手册** > **ESP-RISC-V CPU** [`PDF <{IDF_TARGET_TRM_CN_URL}#riscvcpu>`__]。
|
||||||
|
|
||||||
@ -152,12 +150,14 @@ GPIO 捆绑包操作
|
|||||||
// 等待完成信号量
|
// 等待完成信号量
|
||||||
xSemaphoreTake(sem, portMAX_DELAY);
|
xSemaphoreTake(sem, portMAX_DELAY);
|
||||||
|
|
||||||
.. only:: SOC_DEDIC_GPIO_HAS_INTERRUPT
|
|
||||||
|
|
||||||
应用示例
|
应用示例
|
||||||
-------------------
|
-------------------
|
||||||
|
|
||||||
基于专用 GPIO 的矩阵键盘示例::example:`peripherals/gpio/matrix_keyboard`.
|
.. list::
|
||||||
|
|
||||||
|
* 通过汇编代码使用专用的 CPU 指令来操作 GPIO 以模拟 UART/I2C/SPI 外设 :example:`peripherals/dedicated_gpio`.
|
||||||
|
:SOC_DEDIC_GPIO_HAS_INTERRUPT: * 基于专用 GPIO 驱动的矩阵键盘::example:`peripherals/gpio/matrix_keyboard`.
|
||||||
|
|
||||||
|
|
||||||
API 参考
|
API 参考
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
| Supported Targets | ESP32-C2 | ESP32-C3 | ESP32-C6 | ESP32-H2 | ESP32-S2 | ESP32-S3 |
|
| Supported Targets | ESP32-C2 | ESP32-C3 | ESP32-C6 | ESP32-H2 | ESP32-P4 | ESP32-S2 | ESP32-S3 |
|
||||||
| ----------------- | -------- | -------- | -------- | -------- | -------- | -------- |
|
| ----------------- | -------- | -------- | -------- | -------- | -------- | -------- | -------- |
|
||||||
|
|
||||||
# Example: Software I2C Master via Dedicated/Fast GPIOs
|
# Example: Software I2C Master via Dedicated/Fast GPIOs
|
||||||
|
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
| Supported Targets | ESP32-C2 | ESP32-C3 | ESP32-C6 | ESP32-H2 |
|
| Supported Targets | ESP32-C2 | ESP32-C3 | ESP32-C6 | ESP32-H2 | ESP32-P4 |
|
||||||
| ----------------- | -------- | -------- | -------- | -------- |
|
| ----------------- | -------- | -------- | -------- | -------- | -------- |
|
||||||
|
|
||||||
# Example: SPI software emulation using dedicated/fast GPIOs
|
# Example: SPI software emulation using dedicated/fast GPIOs
|
||||||
|
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
| Supported Targets | ESP32-C2 | ESP32-C3 | ESP32-C6 | ESP32-H2 | ESP32-S2 | ESP32-S3 |
|
| Supported Targets | ESP32-C2 | ESP32-C3 | ESP32-C6 | ESP32-H2 | ESP32-P4 | ESP32-S2 | ESP32-S3 |
|
||||||
| ----------------- | -------- | -------- | -------- | -------- | -------- | -------- |
|
| ----------------- | -------- | -------- | -------- | -------- | -------- | -------- | -------- |
|
||||||
|
|
||||||
# Example: UART software emulation using dedicated/fast GPIOs
|
# Example: UART software emulation using dedicated/fast GPIOs
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user