mirror of
https://github.com/espressif/esp-idf.git
synced 2026-04-27 19:13:21 +00:00
feat(uart): add glitch filter functionality for UART
Closes https://github.com/espressif/esp-idf/issues/17847
This commit is contained in:
@@ -198,10 +198,9 @@ TEST_CASE("I2C master clock frequency test", "[i2c]")
|
||||
|
||||
TEST_ESP_OK(i2c_master_transmit(dev_handle, data_wr, 500, 0));
|
||||
|
||||
uart_bitrate_detect_config_t conf = {
|
||||
.rx_io_num = I2C_MASTER_SCL_IO,
|
||||
.source_clk = UART_SCLK_DEFAULT,
|
||||
};
|
||||
uart_bitrate_detect_config_t conf = {};
|
||||
conf.rx_io_num = I2C_MASTER_SCL_IO;
|
||||
conf.source_clk = UART_SCLK_DEFAULT;
|
||||
uart_bitrate_res_t res = {};
|
||||
uart_detect_bitrate_start(UART_NUM_1, &conf);
|
||||
vTaskDelay(pdMS_TO_TICKS(50));
|
||||
|
||||
@@ -186,10 +186,9 @@ TEST_CASE("I3C master clock frequency test", "[i3c]")
|
||||
i3c_master_i2c_device_handle_t dev_1;
|
||||
TEST_ESP_OK(i3c_master_bus_add_i2c_device(bus_handle, &dev_cfg_1, &dev_1));
|
||||
|
||||
uart_bitrate_detect_config_t conf = {
|
||||
.rx_io_num = I3C_MASTER_SCL_IO,
|
||||
.source_clk = UART_SCLK_DEFAULT,
|
||||
};
|
||||
uart_bitrate_detect_config_t conf = {};
|
||||
conf.rx_io_num = I3C_MASTER_SCL_IO;
|
||||
conf.source_clk = UART_SCLK_DEFAULT;
|
||||
uart_bitrate_res_t res = {};
|
||||
uart_detect_bitrate_start(UART_NUM_1, &conf);
|
||||
|
||||
|
||||
@@ -50,10 +50,9 @@ TEST_CASE("ledc etm event and task", "[ledc]")
|
||||
TEST_ESP_OK(esp_etm_channel_enable(etm_channel_a));
|
||||
|
||||
// use UART auto baud rate detection feature to count the PWM pulse count
|
||||
uart_bitrate_detect_config_t conf = {
|
||||
.rx_io_num = PULSE_IO,
|
||||
.source_clk = UART_SCLK_DEFAULT,
|
||||
};
|
||||
uart_bitrate_detect_config_t conf = {};
|
||||
conf.rx_io_num = PULSE_IO;
|
||||
conf.source_clk = UART_SCLK_DEFAULT;
|
||||
uart_bitrate_res_t res = {};
|
||||
|
||||
uart_detect_bitrate_start(UART_NUM_1, &conf);
|
||||
|
||||
@@ -37,10 +37,9 @@ ledc_timer_config_t create_default_timer_config(void)
|
||||
// use UART auto baud rate detection feature to test the waveform of LEDC
|
||||
int wave_count(int last_time)
|
||||
{
|
||||
uart_bitrate_detect_config_t conf = {
|
||||
.rx_io_num = PULSE_IO,
|
||||
.source_clk = UART_SCLK_DEFAULT,
|
||||
};
|
||||
uart_bitrate_detect_config_t conf = {};
|
||||
conf.rx_io_num = PULSE_IO;
|
||||
conf.source_clk = UART_SCLK_DEFAULT;
|
||||
uart_bitrate_res_t res = {};
|
||||
uart_detect_bitrate_start(UART_NUM_1, &conf);
|
||||
vTaskDelay(pdMS_TO_TICKS(last_time));
|
||||
|
||||
@@ -34,12 +34,13 @@ extern "C" {
|
||||
*/
|
||||
typedef struct {
|
||||
int baud_rate; /*!< UART baud rate
|
||||
Note that the actual baud rate set could have a slight deviation from the user-configured value due to rounding error*/
|
||||
uart_word_length_t data_bits; /*!< UART byte size*/
|
||||
uart_parity_t parity; /*!< UART parity mode*/
|
||||
uart_stop_bits_t stop_bits; /*!< UART stop bits*/
|
||||
uart_hw_flowcontrol_t flow_ctrl; /*!< UART HW flow control mode (cts/rts)*/
|
||||
uint8_t rx_flow_ctrl_thresh; /*!< UART HW RTS threshold*/
|
||||
Note that the actual baud rate set could have a slight deviation from the user-configured value due to rounding error */
|
||||
uart_word_length_t data_bits; /*!< UART byte size */
|
||||
uart_parity_t parity; /*!< UART parity mode */
|
||||
uart_stop_bits_t stop_bits; /*!< UART stop bits */
|
||||
uart_hw_flowcontrol_t flow_ctrl; /*!< UART HW flow control mode (cts/rts) */
|
||||
uint8_t rx_flow_ctrl_thresh; /*!< UART HW RTS threshold */
|
||||
uint32_t rx_glitch_filt_thresh; /*!< The width of the glitch on the RX signal to be filtered (unit: ns). If set to 0, then RX signal filter is disabled. */
|
||||
union {
|
||||
uart_sclk_t source_clk; /*!< UART source clock selection */
|
||||
#if (SOC_UART_LP_NUM >= 1)
|
||||
@@ -896,6 +897,7 @@ typedef struct {
|
||||
int rx_io_num; /*!< GPIO pin number for the incoming signal */
|
||||
uart_sclk_t source_clk; /*!< The higher the frequency of the clock source, the more accurate the detected bitrate value;
|
||||
The slower the frequency of the clock source, the slower the bitrate can be measured */
|
||||
uint32_t rx_glitch_filt_thresh; /*!< The width of the glitch on the incoming signal to be filtered (unit: ns). If set to 0, then glitch filter is disabled. */
|
||||
} uart_bitrate_detect_config_t;
|
||||
|
||||
/**
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2015-2025 Espressif Systems (Shanghai) CO LTD
|
||||
* SPDX-FileCopyrightText: 2015-2026 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
@@ -1060,6 +1060,9 @@ esp_err_t uart_param_config(uart_port_t uart_num, const uart_config_t *uart_conf
|
||||
ESP_RETURN_ON_FALSE((uart_config->rx_flow_ctrl_thresh < UART_HW_FIFO_LEN(uart_num)), ESP_FAIL, UART_TAG, "rx flow thresh error");
|
||||
ESP_RETURN_ON_FALSE((uart_config->flow_ctrl < UART_HW_FLOWCTRL_MAX), ESP_FAIL, UART_TAG, "hw_flowctrl mode error");
|
||||
ESP_RETURN_ON_FALSE((uart_config->data_bits < UART_DATA_BITS_MAX), ESP_FAIL, UART_TAG, "data bit error");
|
||||
#if UART_LL_GLITCH_FILT_ONLY_ON_AUTOBAUD
|
||||
ESP_RETURN_ON_FALSE((uart_config->rx_glitch_filt_thresh == 0), ESP_FAIL, UART_TAG, "glitch filter on RX signal is not supported");
|
||||
#endif
|
||||
|
||||
bool allow_pd __attribute__((unused)) = (uart_config->flags.allow_pd || uart_config->flags.backup_before_sleep);
|
||||
#if !SOC_UART_SUPPORT_SLEEP_RETENTION
|
||||
@@ -1105,6 +1108,9 @@ esp_err_t uart_param_config(uart_port_t uart_num, const uart_config_t *uart_conf
|
||||
success = lp_uart_ll_set_baudrate(uart_context[uart_num].hal.dev, uart_config->baud_rate, sclk_freq);
|
||||
}
|
||||
#endif
|
||||
uart_hal_set_glitch_filt_thrd(&(uart_context[uart_num].hal), uart_config->rx_glitch_filt_thresh, sclk_freq);
|
||||
uart_hal_enable_glitch_filt(&(uart_context[uart_num].hal), uart_config->rx_glitch_filt_thresh > 0);
|
||||
|
||||
uart_hal_set_parity(&(uart_context[uart_num].hal), uart_config->parity);
|
||||
uart_hal_set_data_bit_num(&(uart_context[uart_num].hal), uart_config->data_bits);
|
||||
uart_hal_set_stop_bits(&(uart_context[uart_num].hal), uart_config->stop_bits);
|
||||
@@ -2345,14 +2351,37 @@ esp_err_t uart_detect_bitrate_start(uart_port_t uart_num, const uart_bitrate_det
|
||||
periph_rtc_dig_clk8m_enable();
|
||||
}
|
||||
#endif
|
||||
UART_ENTER_CRITICAL(&(uart_context[uart_num].spinlock));
|
||||
HP_UART_SRC_CLK_ATOMIC() {
|
||||
uart_hal_set_sclk(&(uart_context[uart_num].hal), uart_sclk_sel);
|
||||
uart_hal_set_baudrate(&(uart_context[uart_num].hal), 57600, sclk_freq); // set to any baudrate
|
||||
}
|
||||
uart_context[uart_num].sclk_sel = uart_sclk_sel;
|
||||
|
||||
#if CONFIG_IDF_TARGET_ESP32 || CONFIG_IDF_TARGET_ESP32S2
|
||||
// On such targets, the reference tick for filter is APB clock, regardless the UART func clock sel
|
||||
esp_clk_tree_src_get_freq_hz(SOC_MOD_CLK_APB, ESP_CLK_TREE_SRC_FREQ_PRECISION_CACHED, &sclk_freq);
|
||||
#endif
|
||||
uart_hal_set_glitch_filt_thrd(&(uart_context[uart_num].hal), config->rx_glitch_filt_thresh, sclk_freq);
|
||||
uart_hal_enable_glitch_filt(&(uart_context[uart_num].hal), config->rx_glitch_filt_thresh > 0);
|
||||
UART_EXIT_CRITICAL(&(uart_context[uart_num].spinlock));
|
||||
|
||||
_uart_set_pin6(uart_num, UART_PIN_NO_CHANGE, config->rx_io_num, UART_PIN_NO_CHANGE, UART_PIN_NO_CHANGE, UART_PIN_NO_CHANGE, UART_PIN_NO_CHANGE);
|
||||
} else if (config != NULL) {
|
||||
ESP_LOGW(UART_TAG, "unable to re-configure for an acquired port, ignoring the new config");
|
||||
#if UART_LL_GLITCH_FILT_ONLY_ON_AUTOBAUD
|
||||
if (config->rx_glitch_filt_thresh > 0) {
|
||||
// On ESP32 and ESP32S2, the reference tick for filter is APB clock, regardless the UART func clock sel
|
||||
UART_ENTER_CRITICAL(&(uart_context[uart_num].spinlock));
|
||||
soc_module_clk_t src_clk = SOC_MOD_CLK_APB;
|
||||
uint32_t sclk_freq = 0;
|
||||
esp_clk_tree_src_get_freq_hz(src_clk, ESP_CLK_TREE_SRC_FREQ_PRECISION_CACHED, &sclk_freq);
|
||||
uart_hal_set_glitch_filt_thrd(&(uart_context[uart_num].hal), config->rx_glitch_filt_thresh, sclk_freq);
|
||||
UART_EXIT_CRITICAL(&(uart_context[uart_num].spinlock));
|
||||
} else
|
||||
#endif
|
||||
{
|
||||
ESP_LOGW(UART_TAG, "unable to re-configure such parameters for an acquired port, ignoring the new config");
|
||||
}
|
||||
}
|
||||
|
||||
// start auto baud rate detection
|
||||
|
||||
@@ -1,9 +1,10 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD
|
||||
* SPDX-FileCopyrightText: 2024-2025 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Unlicense OR CC0-1.0
|
||||
*/
|
||||
#include "driver/uart.h"
|
||||
#include "sdkconfig.h"
|
||||
|
||||
typedef struct {
|
||||
uart_port_t port_num;
|
||||
@@ -14,3 +15,11 @@ typedef struct {
|
||||
} uart_port_param_t;
|
||||
|
||||
bool port_select(uart_port_param_t *port_param);
|
||||
|
||||
#if CONFIG_IDF_TARGET_ESP32H4
|
||||
#define TEST_UART_TX_PIN_NUM 2
|
||||
#define TEST_UART_RX_PIN_NUM 3
|
||||
#else
|
||||
#define TEST_UART_TX_PIN_NUM 4
|
||||
#define TEST_UART_RX_PIN_NUM 5
|
||||
#endif
|
||||
|
||||
@@ -7,20 +7,24 @@
|
||||
#include <sys/param.h>
|
||||
#include "unity.h"
|
||||
#include "test_utils.h"
|
||||
#include "unity_test_utils.h"
|
||||
#include "driver/uart.h"
|
||||
#include "esp_log.h"
|
||||
#include "esp_rom_gpio.h"
|
||||
#include "esp_private/gpio.h"
|
||||
#include "hal/gpio_ll.h"
|
||||
#if SOC_LP_GPIO_MATRIX_SUPPORTED
|
||||
#include "driver/lp_io.h"
|
||||
#include "driver/rtc_io.h"
|
||||
#include "hal/rtc_io_ll.h"
|
||||
#endif
|
||||
#include "hal/uart_ll.h"
|
||||
#include "hal/uart_periph.h"
|
||||
#include "soc/uart_pins.h"
|
||||
#include "soc/soc_caps.h"
|
||||
#include "soc/clk_tree_defs.h"
|
||||
#include "test_common.h"
|
||||
#include "esp_attr.h"
|
||||
|
||||
#define BUF_SIZE (100)
|
||||
#define UART_BAUD_11520 (11520)
|
||||
@@ -35,8 +39,8 @@ bool port_select(uart_port_param_t *port_param)
|
||||
if (strcmp(argv, "uart") == 0) {
|
||||
port_param->port_num = UART_NUM_1; // Test HP_UART with UART1 port
|
||||
port_param->default_src_clk = UART_SCLK_DEFAULT;
|
||||
port_param->tx_pin_num = 4;
|
||||
port_param->rx_pin_num = 5;
|
||||
port_param->tx_pin_num = TEST_UART_TX_PIN_NUM;
|
||||
port_param->rx_pin_num = TEST_UART_RX_PIN_NUM;
|
||||
port_param->rx_flow_ctrl_thresh = 120;
|
||||
return true;
|
||||
#if SOC_UART_LP_NUM > 0
|
||||
@@ -303,15 +307,21 @@ TEST_CASE("uart general API test", "[uart]")
|
||||
uart_wakeup_set_get_test(uart_num);
|
||||
}
|
||||
|
||||
typedef struct {
|
||||
uart_port_t port_num;
|
||||
int test_times;
|
||||
} uart_write_task_param_t;
|
||||
|
||||
static void uart_write_task(void *param)
|
||||
{
|
||||
uart_port_t uart_num = (uart_port_t)param;
|
||||
uart_write_task_param_t *task_param = (uart_write_task_param_t *)param;
|
||||
uart_port_t uart_num = task_param->port_num;
|
||||
uint8_t *tx_buf = (uint8_t *)malloc(1024);
|
||||
TEST_ASSERT_NOT_NULL(tx_buf);
|
||||
for (int i = 1; i < 1023; i++) {
|
||||
tx_buf[i] = (i & 0xff);
|
||||
}
|
||||
for (int i = 0; i < 1024; i++) {
|
||||
for (int i = 0; i < task_param->test_times; i++) {
|
||||
//d[0] and d[1023] are header
|
||||
tx_buf[0] = (i & 0xff);
|
||||
tx_buf[1023] = ((~i) & 0xff);
|
||||
@@ -322,33 +332,11 @@ static void uart_write_task(void *param)
|
||||
vTaskDelete(NULL);
|
||||
}
|
||||
|
||||
TEST_CASE("uart read write test", "[uart]")
|
||||
static void uart_read_data_with_check(uart_port_t uart_num, int test_times)
|
||||
{
|
||||
uart_port_param_t port_param = {};
|
||||
TEST_ASSERT(port_select(&port_param));
|
||||
|
||||
uart_port_t uart_num = port_param.port_num;
|
||||
uint8_t *rd_data = (uint8_t *)malloc(1024);
|
||||
TEST_ASSERT_NOT_NULL(rd_data);
|
||||
uart_config_t uart_config = {
|
||||
.baud_rate = 2000000,
|
||||
.data_bits = UART_DATA_8_BITS,
|
||||
.parity = UART_PARITY_DISABLE,
|
||||
.stop_bits = UART_STOP_BITS_1,
|
||||
.flow_ctrl = UART_HW_FLOWCTRL_CTS_RTS,
|
||||
.source_clk = port_param.default_src_clk,
|
||||
.rx_flow_ctrl_thresh = port_param.rx_flow_ctrl_thresh,
|
||||
};
|
||||
TEST_ESP_OK(uart_driver_install(uart_num, BUF_SIZE * 2, 0, 20, NULL, 0));
|
||||
TEST_ESP_OK(uart_param_config(uart_num, &uart_config));
|
||||
// Use loop back feature to connect TX signal to RX signal, CTS signal to RTS signal internally. Then no need to configure uart pins.
|
||||
TEST_ESP_OK(uart_set_loop_back(uart_num, true));
|
||||
|
||||
TEST_ESP_OK(uart_wait_tx_done(uart_num, portMAX_DELAY));
|
||||
vTaskDelay(pdMS_TO_TICKS(20)); // make sure last byte has flushed from TX FIFO
|
||||
TEST_ESP_OK(uart_flush_input(uart_num));
|
||||
xTaskCreate(uart_write_task, "uart_write_task", 8192, (void *)uart_num, 5, NULL);
|
||||
for (int i = 0; i < 1024; i++) {
|
||||
for (int i = 0; i < test_times; i++) {
|
||||
int bytes_remaining = 1024;
|
||||
memset(rd_data, 0, 1024);
|
||||
while (bytes_remaining) {
|
||||
@@ -382,9 +370,43 @@ TEST_CASE("uart read write test", "[uart]")
|
||||
TEST_FAIL();
|
||||
}
|
||||
}
|
||||
free(rd_data);
|
||||
}
|
||||
|
||||
TEST_CASE("uart read write test", "[uart]")
|
||||
{
|
||||
uart_port_param_t port_param = {};
|
||||
TEST_ASSERT(port_select(&port_param));
|
||||
|
||||
uart_port_t uart_num = port_param.port_num;
|
||||
uart_config_t uart_config = {
|
||||
.baud_rate = 2000000,
|
||||
.data_bits = UART_DATA_8_BITS,
|
||||
.parity = UART_PARITY_DISABLE,
|
||||
.stop_bits = UART_STOP_BITS_1,
|
||||
.flow_ctrl = UART_HW_FLOWCTRL_CTS_RTS,
|
||||
.source_clk = port_param.default_src_clk,
|
||||
.rx_flow_ctrl_thresh = port_param.rx_flow_ctrl_thresh,
|
||||
};
|
||||
TEST_ESP_OK(uart_driver_install(uart_num, BUF_SIZE * 2, 0, 20, NULL, 0));
|
||||
TEST_ESP_OK(uart_param_config(uart_num, &uart_config));
|
||||
// Use loop back feature to connect TX signal to RX signal, CTS signal to RTS signal internally. Then no need to configure uart pins.
|
||||
TEST_ESP_OK(uart_set_loop_back(uart_num, true));
|
||||
|
||||
TEST_ESP_OK(uart_wait_tx_done(uart_num, portMAX_DELAY));
|
||||
vTaskDelay(pdMS_TO_TICKS(20)); // make sure last byte has flushed from TX FIFO
|
||||
TEST_ESP_OK(uart_flush_input(uart_num));
|
||||
|
||||
uart_write_task_param_t task_param = {
|
||||
.port_num = uart_num,
|
||||
.test_times = 1024,
|
||||
};
|
||||
xTaskCreate(uart_write_task, "uart_write_task", 8192, (void *)&task_param, 5, NULL);
|
||||
|
||||
uart_read_data_with_check(uart_num, task_param.test_times);
|
||||
|
||||
uart_wait_tx_done(uart_num, portMAX_DELAY);
|
||||
uart_driver_delete(uart_num);
|
||||
free(rd_data);
|
||||
|
||||
vTaskDelay(2); // wait for uart_write_task to exit
|
||||
}
|
||||
@@ -695,3 +717,136 @@ TEST_CASE("uart auto baud rate detection", "[uart]")
|
||||
vTaskDelete(console_write_task);
|
||||
}
|
||||
}
|
||||
|
||||
IRAM_ATTR static void uart_signal_inject_glitch_task(void *param)
|
||||
{
|
||||
uart_port_param_t *port_param = (uart_port_param_t *)param;
|
||||
uart_port_t uart_num = port_param->port_num;
|
||||
uint32_t tx_pin = port_param->tx_pin_num;
|
||||
// while sending, frequently disconnect from UART TX signal and set level to high to create glitches
|
||||
gpio_ll_set_level(&GPIO, tx_pin, 1);
|
||||
#if SOC_UART_LP_NUM > 0 && SOC_LP_GPIO_MATRIX_SUPPORTED
|
||||
uint32_t rtc_gpio_num = rtc_io_number_get(tx_pin);
|
||||
rtcio_ll_set_level(rtc_gpio_num, 1);
|
||||
#endif
|
||||
|
||||
// esp_rom_delay_us(1000); // wait for uart write task to start sending data
|
||||
|
||||
while (1) {
|
||||
// make sure the glitch is always less than 5us
|
||||
portDISABLE_INTERRUPTS();
|
||||
if (uart_num < SOC_UART_HP_NUM) {
|
||||
esp_rom_gpio_connect_out_signal(tx_pin, SIG_GPIO_OUT_IDX, false, false);
|
||||
gpio_ll_set_output_enable_ctrl(&GPIO, tx_pin, false, false);
|
||||
esp_rom_gpio_connect_out_signal(tx_pin, UART_PERIPH_SIGNAL(uart_num, SOC_UART_PERIPH_SIGNAL_TX), false, false);
|
||||
#if SOC_UART_LP_NUM > 0 && SOC_LP_GPIO_MATRIX_SUPPORTED
|
||||
} else {
|
||||
rtcio_ll_matrix_out(rtc_gpio_num, SIG_LP_GPIO_OUT_IDX, false, false);
|
||||
LP_GPIO.func_out_sel_cfg[rtc_gpio_num].oe_sel = 1;
|
||||
rtcio_ll_matrix_out(rtc_gpio_num, UART_PERIPH_SIGNAL(uart_num, SOC_UART_PERIPH_SIGNAL_TX), false, false);
|
||||
#endif
|
||||
}
|
||||
portENABLE_INTERRUPTS();
|
||||
vTaskDelay(pdMS_TO_TICKS(1));
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE("uart rx glitch filter (read write test + auto baud rate detection test)", "[uart]")
|
||||
{
|
||||
// The test will be constructed as:
|
||||
// Configuring TX and RX signal on the same GPIO pad
|
||||
// And while the TX data is sending, the TX output configuration will be manipulated to generate glitches on the signal
|
||||
uart_port_param_t port_param = {};
|
||||
TEST_ASSERT(port_select(&port_param));
|
||||
port_param.tx_pin_num = port_param.rx_pin_num; // let tx and rx use the same pin
|
||||
|
||||
uart_port_t uart_num = port_param.port_num;
|
||||
// High speed clock source may not able to filter a 5us glitch, therefore, lower the source clock frequency
|
||||
if (uart_num < SOC_UART_HP_NUM) {
|
||||
#if SOC_UART_SUPPORT_XTAL_CLK
|
||||
port_param.default_src_clk = UART_SCLK_XTAL;
|
||||
#endif
|
||||
}
|
||||
uart_config_t uart_config = {
|
||||
.baud_rate = 50000,
|
||||
.data_bits = UART_DATA_8_BITS,
|
||||
.parity = UART_PARITY_DISABLE,
|
||||
.stop_bits = UART_STOP_BITS_1,
|
||||
.flow_ctrl = UART_HW_FLOWCTRL_DISABLE,
|
||||
.source_clk = port_param.default_src_clk,
|
||||
#if !UART_LL_GLITCH_FILT_ONLY_ON_AUTOBAUD
|
||||
.rx_glitch_filt_thresh = 5000, // filter all glitches with width less than 5us
|
||||
#endif
|
||||
};
|
||||
|
||||
TEST_ESP_OK(uart_driver_install(uart_num, BUF_SIZE * 2, 0, 20, NULL, 0));
|
||||
TEST_ESP_OK(uart_param_config(uart_num, &uart_config));
|
||||
esp_err_t err = uart_set_pin(uart_num, port_param.tx_pin_num, port_param.rx_pin_num, UART_PIN_NO_CHANGE, UART_PIN_NO_CHANGE);
|
||||
if (uart_num < SOC_UART_HP_NUM) {
|
||||
TEST_ESP_OK(err);
|
||||
#if SOC_UART_LP_NUM > 0
|
||||
} else {
|
||||
#if !SOC_LP_GPIO_MATRIX_SUPPORTED
|
||||
TEST_ESP_ERR(ESP_FAIL, err); // For LP UART port, if no LP GPIO Matrix, unable to be used in one-wire mode
|
||||
#else
|
||||
TEST_ESP_OK(err);
|
||||
#endif
|
||||
#endif // SOC_UART_LP_NUM > 0
|
||||
}
|
||||
|
||||
// If successfully route TX and RX on the same pad, then we can continue with the test
|
||||
if (err == ESP_OK) {
|
||||
TEST_ESP_OK(uart_wait_tx_done(uart_num, portMAX_DELAY));
|
||||
vTaskDelay(pdMS_TO_TICKS(20)); // make sure last byte has flushed from TX FIFO
|
||||
TEST_ESP_OK(uart_flush_input(uart_num));
|
||||
|
||||
uart_write_task_param_t task_param = {
|
||||
.port_num = uart_num,
|
||||
.test_times = 10,
|
||||
};
|
||||
TaskHandle_t inject_glitch_task_handle;
|
||||
xTaskCreate(uart_signal_inject_glitch_task, "uart_signal_inject_glitch_task", 1024, (void *)&port_param, 6, &inject_glitch_task_handle);
|
||||
|
||||
// 1. read write test
|
||||
#if !UART_LL_GLITCH_FILT_ONLY_ON_AUTOBAUD
|
||||
xTaskCreate(uart_write_task, "uart_write_task", 8192, (void *)&task_param, 5, NULL);
|
||||
uart_read_data_with_check(uart_num, task_param.test_times);
|
||||
uart_wait_tx_done(uart_num, portMAX_DELAY);
|
||||
#endif
|
||||
|
||||
// 2. auto baud rate detection test
|
||||
if (uart_num < SOC_UART_HP_NUM) {
|
||||
TaskHandle_t write_task_handle;
|
||||
task_param.test_times = 5;
|
||||
xTaskCreate(uart_write_task, "uart_write_task", 8192, (void *)&task_param, 5, &write_task_handle);
|
||||
uart_bitrate_res_t res = {};
|
||||
#if UART_LL_GLITCH_FILT_ONLY_ON_AUTOBAUD
|
||||
// Set the glitch filter threshold for auto baud rate detection on ESP32 and ESP32S2
|
||||
// And since the reference tick for filter is APB clock (80MHz) for the two targets, so set the threshold to 3us to avoid exceeding the register value limit
|
||||
// The glitch is much less than 3us
|
||||
uart_bitrate_detect_config_t conf = {
|
||||
.rx_glitch_filt_thresh = 3000,
|
||||
};
|
||||
TEST_ESP_OK(uart_detect_bitrate_start(uart_num, &conf));
|
||||
#else
|
||||
TEST_ESP_OK(uart_detect_bitrate_start(uart_num, NULL));
|
||||
#endif
|
||||
vTaskDelay(pdMS_TO_TICKS(10));
|
||||
TEST_ESP_OK(uart_detect_bitrate_stop(uart_num, false, &res));
|
||||
uint32_t detected_baudrate = res.clk_freq_hz * 2 / res.pos_period; // assume the wave has a slow falling slew rate
|
||||
uint32_t actual_baudrate = 0;
|
||||
uart_get_baudrate(uart_num, &actual_baudrate);
|
||||
TEST_ASSERT_INT32_WITHIN(actual_baudrate * 0.03, actual_baudrate, detected_baudrate);
|
||||
// wait for write task to finish and self deleted
|
||||
while (eTaskGetState(write_task_handle) != eDeleted) {
|
||||
vTaskDelay(1);
|
||||
}
|
||||
}
|
||||
|
||||
unity_utils_task_delete(inject_glitch_task_handle);
|
||||
}
|
||||
|
||||
uart_driver_delete(uart_num);
|
||||
|
||||
vTaskDelay(2); // wait for tasks to exit
|
||||
}
|
||||
|
||||
@@ -16,6 +16,9 @@
|
||||
#include "soc/uart_struct.h"
|
||||
#include "soc/dport_reg.h"
|
||||
#include "hal/uart_types.h"
|
||||
#include "hal/assert.h"
|
||||
|
||||
#define UART_LL_GLITCH_FILT_ONLY_ON_AUTOBAUD 1 // On ESP32, only autobaud can filter glitches. The data UART RX hardware processes is always the one without getting filtered.
|
||||
|
||||
// The default fifo depth
|
||||
#define UART_LL_FIFO_DEF_LEN (SOC_UART_FIFO_LEN)
|
||||
@@ -248,6 +251,24 @@ FORCE_INLINE_ATTR uint32_t uart_ll_get_baudrate(uart_dev_t *hw, uint32_t sclk_fr
|
||||
return ((sclk_freq << 4)) / ((div_reg.div_int << 4) | div_reg.div_frag);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Set the UART glitch filter threshold. Any high pulse lasting shorter than this value will be ignored when the filter is enabled.
|
||||
*
|
||||
* @param hw Beginning address of the peripheral registers.
|
||||
* @param glitch_filt_thrd The glitch filter threshold to be set (unit: ns)
|
||||
* @param sclk_freq Frequency of the clock source of UART, in Hz.
|
||||
*/
|
||||
FORCE_INLINE_ATTR void uart_ll_set_glitch_filt_thrd(uart_dev_t *hw, uint32_t glitch_filt_thrd, uint32_t sclk_freq)
|
||||
{
|
||||
uint32_t clk_cycles = 0;
|
||||
if (glitch_filt_thrd > 0) {
|
||||
uint32_t ref_clk_freq = sclk_freq; // no pre-divider
|
||||
clk_cycles = ((uint64_t)glitch_filt_thrd * ref_clk_freq + 1000000000 - 1) / 1000000000; // round up to always filter something
|
||||
HAL_ASSERT(clk_cycles <= UART_GLITCH_FILT_V);
|
||||
}
|
||||
HAL_FORCE_MODIFY_U32_REG_FIELD(hw->auto_baud, glitch_filt, clk_cycles);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Enable the UART interrupt based on the given mask.
|
||||
*
|
||||
@@ -1067,6 +1088,20 @@ FORCE_INLINE_ATTR void uart_ll_set_autobaud_en(uart_dev_t *hw, bool enable)
|
||||
hw->auto_baud.en = enable ? 1 : 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Enable or disable the UART glitch filter
|
||||
*
|
||||
* @param hw Beginning address of the peripheral registers.
|
||||
* @param enable True to enable the filter, False to disable the filter
|
||||
*/
|
||||
FORCE_INLINE_ATTR void uart_ll_enable_glitch_filt(uart_dev_t *hw, bool enable)
|
||||
{
|
||||
// No such register on ESP32 to independently enable or disable the glitch filter
|
||||
// Glitch filter is coupled with auto baudrate detection
|
||||
(void)hw;
|
||||
(void)enable;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get the RXD edge count.
|
||||
*
|
||||
|
||||
@@ -19,6 +19,7 @@
|
||||
#include "soc/system_reg.h"
|
||||
#include "soc/dport_access.h"
|
||||
#include "esp_attr.h"
|
||||
#include "hal/assert.h"
|
||||
|
||||
// The default fifo depth
|
||||
#define UART_LL_FIFO_DEF_LEN (SOC_UART_FIFO_LEN)
|
||||
@@ -259,6 +260,35 @@ FORCE_INLINE_ATTR uint32_t uart_ll_get_baudrate(uart_dev_t *hw, uint32_t sclk_fr
|
||||
(((div_reg.div_int << 4) | div_reg.div_frag) * (HAL_FORCE_READ_U32_REG_FIELD(hw->clk_conf, sclk_div_num) + 1));
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Set the UART glitch filter threshold. Any high pulse lasting shorter than this value will be ignored when the filter is enabled.
|
||||
*
|
||||
* @param hw Beginning address of the peripheral registers.
|
||||
* @param glitch_filt_thrd The glitch filter threshold to be set (unit: ns)
|
||||
* @param sclk_freq Frequency of the clock source of UART, in Hz.
|
||||
*/
|
||||
FORCE_INLINE_ATTR void uart_ll_set_glitch_filt_thrd(uart_dev_t *hw, uint32_t glitch_filt_thrd, uint32_t sclk_freq)
|
||||
{
|
||||
uint32_t clk_cycles = 0;
|
||||
if (glitch_filt_thrd > 0) {
|
||||
uint32_t ref_clk_freq = sclk_freq / (HAL_FORCE_READ_U32_REG_FIELD(hw->clk_conf, sclk_div_num) + 1);
|
||||
clk_cycles = ((uint64_t)glitch_filt_thrd * ref_clk_freq + 1000000000 - 1) / 1000000000; // round up to always filter something
|
||||
HAL_ASSERT(clk_cycles <= UART_GLITCH_FILT_V);
|
||||
}
|
||||
HAL_FORCE_MODIFY_U32_REG_FIELD(hw->rx_filt, glitch_filt, clk_cycles);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Enable or disable the UART glitch filter
|
||||
*
|
||||
* @param hw Beginning address of the peripheral registers.
|
||||
* @param enable True to enable the filter, False to disable the filter
|
||||
*/
|
||||
FORCE_INLINE_ATTR void uart_ll_enable_glitch_filt(uart_dev_t *hw, bool enable)
|
||||
{
|
||||
hw->rx_filt.glitch_filt_en = enable;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Enable the UART interrupt based on the given mask.
|
||||
*
|
||||
|
||||
@@ -18,6 +18,7 @@
|
||||
#include "soc/system_reg.h"
|
||||
#include "soc/dport_access.h"
|
||||
#include "esp_attr.h"
|
||||
#include "hal/assert.h"
|
||||
|
||||
// The default fifo depth
|
||||
#define UART_LL_FIFO_DEF_LEN (SOC_UART_FIFO_LEN)
|
||||
@@ -264,6 +265,35 @@ static inline uint32_t uart_ll_get_baudrate(uart_dev_t *hw, uint32_t sclk_freq)
|
||||
return ((sclk_freq << 4)) / (((div_reg.div_int << 4) | div_reg.div_frag) * (HAL_FORCE_READ_U32_REG_FIELD(hw->clk_conf, sclk_div_num) + 1));
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Set the UART glitch filter threshold. Any high pulse lasting shorter than this value will be ignored when the filter is enabled.
|
||||
*
|
||||
* @param hw Beginning address of the peripheral registers.
|
||||
* @param glitch_filt_thrd The glitch filter threshold to be set (unit: ns)
|
||||
* @param sclk_freq Frequency of the clock source of UART, in Hz.
|
||||
*/
|
||||
FORCE_INLINE_ATTR void uart_ll_set_glitch_filt_thrd(uart_dev_t *hw, uint32_t glitch_filt_thrd, uint32_t sclk_freq)
|
||||
{
|
||||
uint32_t clk_cycles = 0;
|
||||
if (glitch_filt_thrd > 0) {
|
||||
uint32_t ref_clk_freq = sclk_freq / (HAL_FORCE_READ_U32_REG_FIELD(hw->clk_conf, sclk_div_num) + 1);
|
||||
clk_cycles = ((uint64_t)glitch_filt_thrd * ref_clk_freq + 1000000000 - 1) / 1000000000; // round up to always filter something
|
||||
HAL_ASSERT(clk_cycles <= UART_GLITCH_FILT_V);
|
||||
}
|
||||
HAL_FORCE_MODIFY_U32_REG_FIELD(hw->rx_filt, glitch_filt, clk_cycles);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Enable or disable the UART glitch filter
|
||||
*
|
||||
* @param hw Beginning address of the peripheral registers.
|
||||
* @param enable True to enable the filter, False to disable the filter
|
||||
*/
|
||||
FORCE_INLINE_ATTR void uart_ll_enable_glitch_filt(uart_dev_t *hw, bool enable)
|
||||
{
|
||||
hw->rx_filt.glitch_filt_en = enable;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Enable the UART interrupt based on the given mask.
|
||||
*
|
||||
|
||||
@@ -478,7 +478,7 @@ FORCE_INLINE_ATTR uint32_t uart_ll_get_baudrate(uart_dev_t *hw, uint32_t sclk_fr
|
||||
{
|
||||
typeof(hw->clkdiv_sync) div_reg;
|
||||
div_reg.val = hw->clkdiv_sync.val;
|
||||
int sclk_div;
|
||||
int sclk_div = 1;
|
||||
if ((hw) == &LP_UART) {
|
||||
sclk_div = 1; // no pre-divider for LP UART clock source on the target
|
||||
} else {
|
||||
@@ -487,6 +487,41 @@ FORCE_INLINE_ATTR uint32_t uart_ll_get_baudrate(uart_dev_t *hw, uint32_t sclk_fr
|
||||
return ((sclk_freq << 4)) / (((div_reg.clkdiv_int << 4) | div_reg.clkdiv_frag) * sclk_div);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Set the UART glitch filter threshold. Any high pulse lasting shorter than this value will be ignored when the filter is enabled.
|
||||
*
|
||||
* @param hw Beginning address of the peripheral registers.
|
||||
* @param glitch_filt_thrd The glitch filter threshold to be set (unit: ns)
|
||||
* @param sclk_freq Frequency of the clock source of UART, in Hz.
|
||||
*/
|
||||
FORCE_INLINE_ATTR void uart_ll_set_glitch_filt_thrd(uart_dev_t *hw, uint32_t glitch_filt_thrd, uint32_t sclk_freq)
|
||||
{
|
||||
uint32_t clk_cycles = 0;
|
||||
if (glitch_filt_thrd > 0) {
|
||||
int sclk_div = 1;
|
||||
if ((hw) == &LP_UART) {
|
||||
sclk_div = 1; // no pre-divider for LP UART clock source on the target
|
||||
} else {
|
||||
sclk_div = UART_LL_PCR_REG_U32_GET(hw, sclk_conf, sclk_div_num) + 1;
|
||||
}
|
||||
uint32_t ref_clk_freq = sclk_freq / sclk_div;
|
||||
clk_cycles = ((uint64_t)glitch_filt_thrd * ref_clk_freq + 1000000000 - 1) / 1000000000; // round up to always filter something
|
||||
HAL_ASSERT(clk_cycles <= UART_GLITCH_FILT_V);
|
||||
}
|
||||
HAL_FORCE_MODIFY_U32_REG_FIELD(hw->rx_filt, glitch_filt, clk_cycles);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Enable or disable the UART glitch filter
|
||||
*
|
||||
* @param hw Beginning address of the peripheral registers.
|
||||
* @param enable True to enable the filter, False to disable the filter
|
||||
*/
|
||||
FORCE_INLINE_ATTR void uart_ll_enable_glitch_filt(uart_dev_t *hw, bool enable)
|
||||
{
|
||||
hw->rx_filt.glitch_filt_en = enable;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Enable the UART interrupt based on the given mask.
|
||||
*
|
||||
|
||||
@@ -459,7 +459,7 @@ FORCE_INLINE_ATTR uint32_t uart_ll_get_baudrate(uart_dev_t *hw, uint32_t sclk_fr
|
||||
{
|
||||
typeof(hw->clkdiv_sync) div_reg;
|
||||
div_reg.val = hw->clkdiv_sync.val;
|
||||
int sclk_div;
|
||||
int sclk_div = 1;
|
||||
if ((hw) == &LP_UART) {
|
||||
sclk_div = 1; // no pre-divider for LP UART clock source on the target
|
||||
} else {
|
||||
@@ -468,6 +468,41 @@ FORCE_INLINE_ATTR uint32_t uart_ll_get_baudrate(uart_dev_t *hw, uint32_t sclk_fr
|
||||
return ((sclk_freq << 4)) / (((div_reg.clkdiv_int << 4) | div_reg.clkdiv_frag) * sclk_div);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Set the UART glitch filter threshold. Any high pulse lasting shorter than this value will be ignored when the filter is enabled.
|
||||
*
|
||||
* @param hw Beginning address of the peripheral registers.
|
||||
* @param glitch_filt_thrd The glitch filter threshold to be set (unit: ns)
|
||||
* @param sclk_freq Frequency of the clock source of UART, in Hz.
|
||||
*/
|
||||
FORCE_INLINE_ATTR void uart_ll_set_glitch_filt_thrd(uart_dev_t *hw, uint32_t glitch_filt_thrd, uint32_t sclk_freq)
|
||||
{
|
||||
uint32_t clk_cycles = 0;
|
||||
if (glitch_filt_thrd > 0) {
|
||||
int sclk_div = 1;
|
||||
if ((hw) == &LP_UART) {
|
||||
sclk_div = 1; // no pre-divider for LP UART clock source on the target
|
||||
} else {
|
||||
sclk_div = UART_LL_PCR_REG_U32_GET(hw, sclk_conf, sclk_div_num) + 1;
|
||||
}
|
||||
uint32_t ref_clk_freq = sclk_freq / sclk_div;
|
||||
clk_cycles = ((uint64_t)glitch_filt_thrd * ref_clk_freq + 1000000000 - 1) / 1000000000; // round up to always filter something
|
||||
HAL_ASSERT(clk_cycles <= UART_GLITCH_FILT_V);
|
||||
}
|
||||
HAL_FORCE_MODIFY_U32_REG_FIELD(hw->rx_filt, glitch_filt, clk_cycles);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Enable or disable the UART glitch filter
|
||||
*
|
||||
* @param hw Beginning address of the peripheral registers.
|
||||
* @param enable True to enable the filter, False to disable the filter
|
||||
*/
|
||||
FORCE_INLINE_ATTR void uart_ll_enable_glitch_filt(uart_dev_t *hw, bool enable)
|
||||
{
|
||||
hw->rx_filt.glitch_filt_en = enable;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Enable the UART interrupt based on the given mask.
|
||||
*
|
||||
|
||||
@@ -305,6 +305,35 @@ FORCE_INLINE_ATTR uint32_t uart_ll_get_baudrate(uart_dev_t *hw, uint32_t sclk_fr
|
||||
return ((sclk_freq << 4)) / (((div_reg.clkdiv_int << 4) | div_reg.clkdiv_frag) * sclk_div);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Set the UART glitch filter threshold. Any high pulse lasting shorter than this value will be ignored when the filter is enabled.
|
||||
*
|
||||
* @param hw Beginning address of the peripheral registers.
|
||||
* @param glitch_filt_thrd The glitch filter threshold to be set (unit: ns)
|
||||
* @param sclk_freq Frequency of the clock source of UART, in Hz.
|
||||
*/
|
||||
FORCE_INLINE_ATTR void uart_ll_set_glitch_filt_thrd(uart_dev_t *hw, uint32_t glitch_filt_thrd, uint32_t sclk_freq)
|
||||
{
|
||||
uint32_t clk_cycles = 0;
|
||||
if (glitch_filt_thrd > 0) {
|
||||
uint32_t ref_clk_freq = sclk_freq / (UART_LL_PCR_REG_U32_GET(hw, sclk_conf, sclk_div_num) + 1);
|
||||
clk_cycles = ((uint64_t)glitch_filt_thrd * ref_clk_freq + 1000000000 - 1) / 1000000000; // round up to always filter something
|
||||
HAL_ASSERT(clk_cycles <= UART_GLITCH_FILT_V);
|
||||
}
|
||||
HAL_FORCE_MODIFY_U32_REG_FIELD(hw->rx_filt, glitch_filt, clk_cycles);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Enable or disable the UART glitch filter
|
||||
*
|
||||
* @param hw Beginning address of the peripheral registers.
|
||||
* @param enable True to enable the filter, False to disable the filter
|
||||
*/
|
||||
FORCE_INLINE_ATTR void uart_ll_enable_glitch_filt(uart_dev_t *hw, bool enable)
|
||||
{
|
||||
hw->rx_filt.glitch_filt_en = enable;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Enable the UART interrupt based on the given mask.
|
||||
*
|
||||
|
||||
@@ -18,6 +18,7 @@
|
||||
#include "soc/pcr_struct.h"
|
||||
#include "soc/pcr_reg.h"
|
||||
#include "esp_attr.h"
|
||||
#include "hal/assert.h"
|
||||
|
||||
// The default fifo depth
|
||||
#define UART_LL_FIFO_DEF_LEN (SOC_UART_FIFO_LEN)
|
||||
@@ -284,6 +285,35 @@ FORCE_INLINE_ATTR uint32_t uart_ll_get_baudrate(uart_dev_t *hw, uint32_t sclk_fr
|
||||
return ((sclk_freq << 4)) / (((div_reg.clkdiv_int << 4) | div_reg.clkdiv_frag) * (UART_LL_PCR_REG_U32_GET(hw, sclk_conf, sclk_div_num) + 1));
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Set the UART glitch filter threshold. Any high pulse lasting shorter than this value will be ignored when the filter is enabled.
|
||||
*
|
||||
* @param hw Beginning address of the peripheral registers.
|
||||
* @param glitch_filt_thrd The glitch filter threshold to be set (unit: ns)
|
||||
* @param sclk_freq Frequency of the clock source of UART, in Hz.
|
||||
*/
|
||||
FORCE_INLINE_ATTR void uart_ll_set_glitch_filt_thrd(uart_dev_t *hw, uint32_t glitch_filt_thrd, uint32_t sclk_freq)
|
||||
{
|
||||
uint32_t clk_cycles = 0;
|
||||
if (glitch_filt_thrd > 0) {
|
||||
uint32_t ref_clk_freq = sclk_freq / (UART_LL_PCR_REG_U32_GET(hw, sclk_conf, sclk_div_num) + 1);
|
||||
clk_cycles = ((uint64_t)glitch_filt_thrd * ref_clk_freq + 1000000000 - 1) / 1000000000; // round up to always filter something
|
||||
HAL_ASSERT(clk_cycles <= UART_GLITCH_FILT_V);
|
||||
}
|
||||
HAL_FORCE_MODIFY_U32_REG_FIELD(hw->rx_filt, glitch_filt, clk_cycles);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Enable or disable the UART glitch filter
|
||||
*
|
||||
* @param hw Beginning address of the peripheral registers.
|
||||
* @param enable True to enable the filter, False to disable the filter
|
||||
*/
|
||||
FORCE_INLINE_ATTR void uart_ll_enable_glitch_filt(uart_dev_t *hw, bool enable)
|
||||
{
|
||||
hw->rx_filt.glitch_filt_en = enable;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Enable the UART interrupt based on the given mask.
|
||||
*
|
||||
|
||||
@@ -18,6 +18,7 @@
|
||||
#include "soc/pcr_struct.h"
|
||||
#include "soc/pcr_reg.h"
|
||||
#include "esp_attr.h"
|
||||
#include "hal/assert.h"
|
||||
|
||||
// The default fifo depth
|
||||
#define UART_LL_FIFO_DEF_LEN (SOC_UART_FIFO_LEN)
|
||||
@@ -284,6 +285,35 @@ FORCE_INLINE_ATTR uint32_t uart_ll_get_baudrate(uart_dev_t *hw, uint32_t sclk_fr
|
||||
return ((sclk_freq << 4)) / (((div_reg.clkdiv << 4) | div_reg.clkdiv_frag) * (UART_LL_PCR_REG_U32_GET(hw, sclk_conf, sclk_div_num) + 1));
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Set the UART glitch filter threshold. Any high pulse lasting shorter than this value will be ignored when the filter is enabled.
|
||||
*
|
||||
* @param hw Beginning address of the peripheral registers.
|
||||
* @param glitch_filt_thrd The glitch filter threshold to be set (unit: ns)
|
||||
* @param sclk_freq Frequency of the clock source of UART, in Hz.
|
||||
*/
|
||||
FORCE_INLINE_ATTR void uart_ll_set_glitch_filt_thrd(uart_dev_t *hw, uint32_t glitch_filt_thrd, uint32_t sclk_freq)
|
||||
{
|
||||
uint32_t clk_cycles = 0;
|
||||
if (glitch_filt_thrd > 0) {
|
||||
uint32_t ref_clk_freq = sclk_freq / (UART_LL_PCR_REG_U32_GET(hw, sclk_conf, sclk_div_num) + 1);
|
||||
clk_cycles = ((uint64_t)glitch_filt_thrd * ref_clk_freq + 1000000000 - 1) / 1000000000; // round up to always filter something
|
||||
HAL_ASSERT(clk_cycles <= UART_GLITCH_FILT_V);
|
||||
}
|
||||
HAL_FORCE_MODIFY_U32_REG_FIELD(hw->rx_filt, glitch_filt, clk_cycles);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Enable or disable the UART glitch filter
|
||||
*
|
||||
* @param hw Beginning address of the peripheral registers.
|
||||
* @param enable True to enable the filter, False to disable the filter
|
||||
*/
|
||||
FORCE_INLINE_ATTR void uart_ll_enable_glitch_filt(uart_dev_t *hw, bool enable)
|
||||
{
|
||||
hw->rx_filt.glitch_filt_en = enable;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Enable the UART interrupt based on the given mask.
|
||||
*
|
||||
|
||||
@@ -297,11 +297,39 @@ FORCE_INLINE_ATTR uint32_t uart_ll_get_baudrate(uart_dev_t *hw, uint32_t sclk_fr
|
||||
{
|
||||
typeof(hw->clkdiv_sync) div_reg;
|
||||
div_reg.val = hw->clkdiv_sync.val;
|
||||
int sclk_div;
|
||||
sclk_div = UART_LL_PCR_REG_U32_GET(hw, sclk_conf, sclk_div_num) + 1;
|
||||
int sclk_div = UART_LL_PCR_REG_U32_GET(hw, sclk_conf, sclk_div_num) + 1;
|
||||
return ((sclk_freq << 4)) / (((div_reg.clkdiv << 4) | div_reg.clkdiv_frag) * sclk_div);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Set the UART glitch filter threshold. Any high pulse lasting shorter than this value will be ignored when the filter is enabled.
|
||||
*
|
||||
* @param hw Beginning address of the peripheral registers.
|
||||
* @param glitch_filt_thrd The glitch filter threshold to be set (unit: ns)
|
||||
* @param sclk_freq Frequency of the clock source of UART, in Hz.
|
||||
*/
|
||||
FORCE_INLINE_ATTR void uart_ll_set_glitch_filt_thrd(uart_dev_t *hw, uint32_t glitch_filt_thrd, uint32_t sclk_freq)
|
||||
{
|
||||
uint32_t clk_cycles = 0;
|
||||
if (glitch_filt_thrd > 0) {
|
||||
uint32_t ref_clk_freq = sclk_freq / (UART_LL_PCR_REG_U32_GET(hw, sclk_conf, sclk_div_num) + 1);
|
||||
clk_cycles = ((uint64_t)glitch_filt_thrd * ref_clk_freq + 1000000000 - 1) / 1000000000; // round up to always filter something
|
||||
HAL_ASSERT(clk_cycles <= UART_GLITCH_FILT_V);
|
||||
}
|
||||
HAL_FORCE_MODIFY_U32_REG_FIELD(hw->rx_filt, glitch_filt, clk_cycles);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Enable or disable the UART glitch filter
|
||||
*
|
||||
* @param hw Beginning address of the peripheral registers.
|
||||
* @param enable True to enable the filter, False to disable the filter
|
||||
*/
|
||||
FORCE_INLINE_ATTR void uart_ll_enable_glitch_filt(uart_dev_t *hw, bool enable)
|
||||
{
|
||||
hw->rx_filt.glitch_filt_en = enable;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Enable the UART interrupt based on the given mask.
|
||||
*
|
||||
|
||||
@@ -591,7 +591,7 @@ FORCE_INLINE_ATTR uint32_t uart_ll_get_baudrate(uart_dev_t *hw, uint32_t sclk_fr
|
||||
{
|
||||
typeof(hw->clkdiv_sync) div_reg;
|
||||
div_reg.val = hw->clkdiv_sync.val;
|
||||
int sclk_div = 0;
|
||||
int sclk_div = 1;
|
||||
if ((hw) == &UART0) {
|
||||
sclk_div = HAL_FORCE_READ_U32_REG_FIELD(HP_SYS_CLKRST.peri_clk_ctrl111, reg_uart0_sclk_div_num) + 1;
|
||||
} else if ((hw) == &UART1) {
|
||||
@@ -608,6 +608,49 @@ FORCE_INLINE_ATTR uint32_t uart_ll_get_baudrate(uart_dev_t *hw, uint32_t sclk_fr
|
||||
return ((sclk_freq << 4)) / (((div_reg.clkdiv << 4) | div_reg.clkdiv_frag) * sclk_div);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Set the UART glitch filter threshold. Any high pulse lasting shorter than this value will be ignored when the filter is enabled.
|
||||
*
|
||||
* @param hw Beginning address of the peripheral registers.
|
||||
* @param glitch_filt_thrd The glitch filter threshold to be set (unit: ns)
|
||||
* @param sclk_freq Frequency of the clock source of UART, in Hz.
|
||||
*/
|
||||
FORCE_INLINE_ATTR void uart_ll_set_glitch_filt_thrd(uart_dev_t *hw, uint32_t glitch_filt_thrd, uint32_t sclk_freq)
|
||||
{
|
||||
uint32_t clk_cycles = 0;
|
||||
if (glitch_filt_thrd > 0) {
|
||||
int sclk_div = 1;
|
||||
if ((hw) == &UART0) {
|
||||
sclk_div = HAL_FORCE_READ_U32_REG_FIELD(HP_SYS_CLKRST.peri_clk_ctrl111, reg_uart0_sclk_div_num) + 1;
|
||||
} else if ((hw) == &UART1) {
|
||||
sclk_div = HAL_FORCE_READ_U32_REG_FIELD(HP_SYS_CLKRST.peri_clk_ctrl112, reg_uart1_sclk_div_num) + 1;
|
||||
} else if ((hw) == &UART2) {
|
||||
sclk_div = HAL_FORCE_READ_U32_REG_FIELD(HP_SYS_CLKRST.peri_clk_ctrl113, reg_uart2_sclk_div_num) + 1;
|
||||
} else if ((hw) == &UART3) {
|
||||
sclk_div = HAL_FORCE_READ_U32_REG_FIELD(HP_SYS_CLKRST.peri_clk_ctrl114, reg_uart3_sclk_div_num) + 1;
|
||||
} else if ((hw) == &UART4) {
|
||||
sclk_div = HAL_FORCE_READ_U32_REG_FIELD(HP_SYS_CLKRST.peri_clk_ctrl115, reg_uart4_sclk_div_num) + 1;
|
||||
} else if ((hw) == &LP_UART) {
|
||||
sclk_div = 1; // no pre-divider for LP UART clock source on the target
|
||||
}
|
||||
uint32_t ref_clk_freq = sclk_freq / sclk_div;
|
||||
clk_cycles = ((uint64_t)glitch_filt_thrd * ref_clk_freq + 1000000000 - 1) / 1000000000; // round up to always filter something
|
||||
HAL_ASSERT(clk_cycles <= UART_GLITCH_FILT_V);
|
||||
}
|
||||
HAL_FORCE_MODIFY_U32_REG_FIELD(hw->rx_filt, glitch_filt, clk_cycles);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Enable or disable the UART glitch filter
|
||||
*
|
||||
* @param hw Beginning address of the peripheral registers.
|
||||
* @param enable True to enable the filter, False to disable the filter
|
||||
*/
|
||||
FORCE_INLINE_ATTR void uart_ll_enable_glitch_filt(uart_dev_t *hw, bool enable)
|
||||
{
|
||||
hw->rx_filt.glitch_filt_en = enable;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Enable the UART interrupt based on the given mask.
|
||||
*
|
||||
|
||||
@@ -17,6 +17,9 @@
|
||||
#include "soc/system_reg.h"
|
||||
#include "soc/dport_reg.h"
|
||||
#include "esp_attr.h"
|
||||
#include "hal/assert.h"
|
||||
|
||||
#define UART_LL_GLITCH_FILT_ONLY_ON_AUTOBAUD 1 // On ESP32-S2, only autobaud can filter glitches. The data UART RX hardware processes is always the one without getting filtered.
|
||||
|
||||
// The default fifo depth
|
||||
#define UART_LL_FIFO_DEF_LEN (SOC_UART_FIFO_LEN)
|
||||
@@ -237,6 +240,24 @@ FORCE_INLINE_ATTR uint32_t uart_ll_get_baudrate(uart_dev_t *hw, uint32_t sclk_fr
|
||||
return ((sclk_freq << 4)) / ((div_reg.div_int << 4) | div_reg.div_frag);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Set the UART glitch filter threshold. Any high pulse lasting shorter than this value will be ignored when the filter is enabled.
|
||||
*
|
||||
* @param hw Beginning address of the peripheral registers.
|
||||
* @param glitch_filt_thrd The glitch filter threshold to be set (unit: ns)
|
||||
* @param sclk_freq Frequency of the clock source of UART, in Hz.
|
||||
*/
|
||||
FORCE_INLINE_ATTR void uart_ll_set_glitch_filt_thrd(uart_dev_t *hw, uint32_t glitch_filt_thrd, uint32_t sclk_freq)
|
||||
{
|
||||
uint32_t clk_cycles = 0;
|
||||
if (glitch_filt_thrd > 0) {
|
||||
uint32_t ref_clk_freq = sclk_freq; // no pre-divider
|
||||
clk_cycles = ((uint64_t)glitch_filt_thrd * ref_clk_freq + 1000000000 - 1) / 1000000000; // round up to always filter something
|
||||
HAL_ASSERT(clk_cycles <= UART_GLITCH_FILT_V);
|
||||
}
|
||||
HAL_FORCE_MODIFY_U32_REG_FIELD(hw->auto_baud, glitch_filt, clk_cycles);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Enable the UART interrupt based on the given mask.
|
||||
*
|
||||
@@ -987,6 +1008,20 @@ FORCE_INLINE_ATTR void uart_ll_set_autobaud_en(uart_dev_t *hw, bool enable)
|
||||
hw->auto_baud.en = enable ? 1 : 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Enable or disable the UART glitch filter
|
||||
*
|
||||
* @param hw Beginning address of the peripheral registers.
|
||||
* @param enable True to enable the filter, False to disable the filter
|
||||
*/
|
||||
FORCE_INLINE_ATTR void uart_ll_enable_glitch_filt(uart_dev_t *hw, bool enable)
|
||||
{
|
||||
// No such register on ESP32-S2 to independently enable or disable the glitch filter
|
||||
// Glitch filter is coupled with auto baudrate detection
|
||||
(void)hw;
|
||||
(void)enable;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get the RXD edge count.
|
||||
*
|
||||
|
||||
@@ -18,6 +18,7 @@
|
||||
#include "soc/system_reg.h"
|
||||
#include "soc/dport_access.h"
|
||||
#include "esp_attr.h"
|
||||
#include "hal/assert.h"
|
||||
|
||||
// The default fifo depth
|
||||
#define UART_LL_FIFO_DEF_LEN (SOC_UART_FIFO_LEN)
|
||||
@@ -269,6 +270,35 @@ FORCE_INLINE_ATTR uint32_t uart_ll_get_baudrate(uart_dev_t *hw, uint32_t sclk_fr
|
||||
(((div_reg.clkdiv << 4) | div_reg.clkdiv_frag) * (HAL_FORCE_READ_U32_REG_FIELD(hw->clk_conf, sclk_div_num) + 1));
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Set the UART glitch filter threshold. Any high pulse lasting shorter than this value will be ignored when the filter is enabled.
|
||||
*
|
||||
* @param hw Beginning address of the peripheral registers.
|
||||
* @param glitch_filt_thrd The glitch filter threshold to be set (unit: ns)
|
||||
* @param sclk_freq Frequency of the clock source of UART, in Hz.
|
||||
*/
|
||||
FORCE_INLINE_ATTR void uart_ll_set_glitch_filt_thrd(uart_dev_t *hw, uint32_t glitch_filt_thrd, uint32_t sclk_freq)
|
||||
{
|
||||
uint32_t clk_cycles = 0;
|
||||
if (glitch_filt_thrd > 0) {
|
||||
uint32_t ref_clk_freq = sclk_freq / (HAL_FORCE_READ_U32_REG_FIELD(hw->clk_conf, sclk_div_num) + 1);
|
||||
clk_cycles = ((uint64_t)glitch_filt_thrd * ref_clk_freq + 1000000000 - 1) / 1000000000; // round up to always filter something
|
||||
HAL_ASSERT(clk_cycles <= UART_GLITCH_FILT_V);
|
||||
}
|
||||
HAL_FORCE_MODIFY_U32_REG_FIELD(hw->rx_filt, glitch_filt, clk_cycles);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Enable or disable the UART glitch filter
|
||||
*
|
||||
* @param hw Beginning address of the peripheral registers.
|
||||
* @param enable True to enable the filter, False to disable the filter
|
||||
*/
|
||||
FORCE_INLINE_ATTR void uart_ll_enable_glitch_filt(uart_dev_t *hw, bool enable)
|
||||
{
|
||||
hw->rx_filt.glitch_filt_en = enable;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Enable the UART interrupt based on the given mask.
|
||||
*
|
||||
|
||||
@@ -468,7 +468,7 @@ FORCE_INLINE_ATTR uint32_t uart_ll_get_baudrate(uart_dev_t *hw, uint32_t sclk_fr
|
||||
{
|
||||
typeof(hw->clkdiv_sync) div_reg;
|
||||
div_reg.val = hw->clkdiv_sync.val;
|
||||
int sclk_div = 0;
|
||||
int sclk_div = 1;
|
||||
if ((hw) == &UART0) {
|
||||
sclk_div = HAL_FORCE_READ_U32_REG_FIELD(HP_SYS_CLKRST.uart0_ctrl0, reg_uart0_sclk_div_num) + 1;
|
||||
} else if ((hw) == &UART1) {
|
||||
@@ -483,6 +483,47 @@ FORCE_INLINE_ATTR uint32_t uart_ll_get_baudrate(uart_dev_t *hw, uint32_t sclk_fr
|
||||
return ((sclk_freq << 4)) / (((div_reg.clkdiv << 4) | div_reg.clkdiv_frag) * sclk_div);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Set the UART glitch filter threshold. Any high pulse lasting shorter than this value will be ignored when the filter is enabled.
|
||||
*
|
||||
* @param hw Beginning address of the peripheral registers.
|
||||
* @param glitch_filt_thrd The glitch filter threshold to be set (unit: ns)
|
||||
* @param sclk_freq Frequency of the clock source of UART, in Hz.
|
||||
*/
|
||||
FORCE_INLINE_ATTR void uart_ll_set_glitch_filt_thrd(uart_dev_t *hw, uint32_t glitch_filt_thrd, uint32_t sclk_freq)
|
||||
{
|
||||
uint32_t clk_cycles = 0;
|
||||
if (glitch_filt_thrd > 0) {
|
||||
int sclk_div = 1;
|
||||
if ((hw) == &UART0) {
|
||||
sclk_div = HAL_FORCE_READ_U32_REG_FIELD(HP_SYS_CLKRST.uart0_ctrl0, reg_uart0_sclk_div_num) + 1;
|
||||
} else if ((hw) == &UART1) {
|
||||
sclk_div = HAL_FORCE_READ_U32_REG_FIELD(HP_SYS_CLKRST.uart1_ctrl0, reg_uart1_sclk_div_num) + 1;
|
||||
} else if ((hw) == &UART2) {
|
||||
sclk_div = HAL_FORCE_READ_U32_REG_FIELD(HP_SYS_CLKRST.uart2_ctrl0, reg_uart2_sclk_div_num) + 1;
|
||||
} else if ((hw) == &UART3) {
|
||||
sclk_div = HAL_FORCE_READ_U32_REG_FIELD(HP_SYS_CLKRST.uart3_ctrl0, reg_uart3_sclk_div_num) + 1;
|
||||
// } else if ((hw) == &LP_UART) {
|
||||
// sclk_div = HAL_FORCE_READ_U32_REG_FIELD(hw->clk_conf, sclk_div_num) + 1;
|
||||
}
|
||||
uint32_t ref_clk_freq = sclk_freq / sclk_div;
|
||||
clk_cycles = ((uint64_t)glitch_filt_thrd * ref_clk_freq + 1000000000 - 1) / 1000000000; // round up to always filter something
|
||||
HAL_ASSERT(clk_cycles <= UART_GLITCH_FILT_V);
|
||||
}
|
||||
HAL_FORCE_MODIFY_U32_REG_FIELD(hw->rx_filt, glitch_filt, clk_cycles);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Enable or disable the UART glitch filter
|
||||
*
|
||||
* @param hw Beginning address of the peripheral registers.
|
||||
* @param enable True to enable the filter, False to disable the filter
|
||||
*/
|
||||
FORCE_INLINE_ATTR void uart_ll_enable_glitch_filt(uart_dev_t *hw, bool enable)
|
||||
{
|
||||
hw->rx_filt.glitch_filt_en = enable;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Enable the UART interrupt based on the given mask.
|
||||
*
|
||||
|
||||
@@ -488,6 +488,23 @@ uint16_t uart_hal_get_max_rx_timeout_thrd(uart_hal_context_t *hal);
|
||||
*/
|
||||
#define uart_hal_get_rxfifo_len(hal) uart_ll_get_rxfifo_len((hal)->dev)
|
||||
|
||||
/**
|
||||
* @brief Set the UART glitch filter threshold. Any high pulse lasting shorter than this value will be ignored when the filter is enabled.
|
||||
*
|
||||
* @param hal Context of the HAL layer
|
||||
* @param glitch_filt_thrd The glitch filter threshold to be set (unit: ns)
|
||||
* @param sclk_freq Frequency of the clock source of UART, in Hz.
|
||||
*/
|
||||
#define uart_hal_set_glitch_filt_thrd(hal, glitch_filt_thrd, sclk_freq) uart_ll_set_glitch_filt_thrd((hal)->dev, glitch_filt_thrd, sclk_freq)
|
||||
|
||||
/**
|
||||
* @brief Enable or disable the UART glitch filter
|
||||
*
|
||||
* @param hal Context of the HAL layer
|
||||
* @param enable True to enable the filter, False to disable the filter
|
||||
*/
|
||||
#define uart_hal_enable_glitch_filt(hal, enable) uart_ll_enable_glitch_filt((hal)->dev, enable)
|
||||
|
||||
/**
|
||||
* @brief Enable or disable the auto baudrate detection
|
||||
*
|
||||
|
||||
@@ -107,6 +107,8 @@ For more information on how to configure the hardware flow control options, plea
|
||||
|
||||
Additionally, :cpp:member:`uart_config_t::allow_pd` can be set to enable the backup of the UART configuration registers before entering sleep and restore these registers after exiting sleep. This allows the UART to continue working properly after waking up even when the UART module power domain is entirely off during sleep. This option implies an balance between power consumption and memory usage. If the power consumption is not a concern, you can disable this option to save memory.
|
||||
|
||||
If glitches may occur on the RX signal, :cpp:member:`uart_config_t::rx_glitch_filt_thresh` can be set to filter the glitches to ensure the correct data is received (note that this feature is not supported on ESP32 and ESP32-S2). The unit of the :cpp:member:`uart_config_t::rx_glitch_filt_thresh` is nanoseconds. The default value is 0, which means no filtering.
|
||||
|
||||
Multiple Steps
|
||||
""""""""""""""
|
||||
|
||||
|
||||
@@ -107,6 +107,8 @@ UART 驱动程序函数通过 :cpp:type:`uart_port_t` 识别不同的 UART 控
|
||||
|
||||
此外,置位 :cpp:member:`uart_config_t::allow_pd` 会使能在进入睡眠模式前备份 UART 配置寄存器并在退出睡眠后恢复这些寄存器。这个功能使 UART 能够在系统唤醒后继续正常工作,即使其电源域在睡眠过程中被完全关闭。此选项需要用户在功耗和内存使用之间取得平衡。如果功耗不是一个问题,可以禁用这个选项来节省内存。
|
||||
|
||||
如果 RX 信号可能出现抖动,可以设置 :cpp:member:`uart_config_t::rx_glitch_filt_thresh` 来过滤抖动以确保接收到正确的数据(注意:该功能在 ESP32 和 ESP32-S2 上不支持)。:cpp:member:`uart_config_t::rx_glitch_filt_thresh` 的单位是纳秒。默认值为 0,即表示不进行过滤。
|
||||
|
||||
分步依次配置每个参数
|
||||
"""""""""""""""""""""""""""""""
|
||||
|
||||
|
||||
Reference in New Issue
Block a user