Merge branch 'bugfix/improve_lp_uart_test_docs' into 'release/v5.2'

refactor(uart): add support to be able to test LP_UART port (v5.2)

See merge request espressif/esp-idf!30175
This commit is contained in:
morris 2024-04-17 17:46:48 +08:00
commit 61210271a8
22 changed files with 372 additions and 164 deletions

View File

@ -2,6 +2,6 @@
# the component can be registered as WHOLE_ARCHIVE
idf_component_register(
SRCS "test_app_main.c" "test_uart.c"
REQUIRES driver unity
REQUIRES driver unity test_utils
WHOLE_ARCHIVE
)

View File

@ -1,29 +1,61 @@
/*
* SPDX-FileCopyrightText: 2021-2022 Espressif Systems (Shanghai) CO LTD
* SPDX-FileCopyrightText: 2021-2024 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <string.h>
#include <sys/param.h>
#include "unity.h"
#include "driver/uart.h" // for the uart driver access
#include "test_utils.h"
#include "driver/uart.h"
#include "esp_log.h"
#include "esp_system.h" // for uint32_t esp_random()
#include "esp_rom_gpio.h"
#include "driver/lp_io.h"
#include "soc/uart_periph.h"
#include "soc/uart_pins.h"
#include "soc/soc_caps.h"
#include "soc/clk_tree_defs.h"
#define UART_TAG "Uart"
#define UART_NUM1 (UART_NUM_1)
#define BUF_SIZE (100)
#define UART1_RX_PIN (5)
#define UART1_TX_PIN (4)
#define UART_BAUD_11520 (11520)
#define UART_BAUD_115200 (115200)
#define TOLERANCE (0.02) //baud rate error tolerance 2%.
#define UART1_CTS_PIN (13)
typedef struct {
uart_port_t port_num;
soc_module_clk_t default_src_clk;
int tx_pin_num;
int rx_pin_num;
uint32_t rx_flow_ctrl_thresh;
} uart_port_param_t;
static void uart_config(uint32_t baud_rate, uart_sclk_t source_clk)
static bool port_select(uart_port_param_t *port_param)
{
char argv[10];
unity_wait_for_signal_param("select to test 'uart' or 'lp_uart' port", argv, sizeof(argv));
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->rx_flow_ctrl_thresh = 120;
return true;
#if SOC_UART_LP_NUM > 0
} else if (strcmp(argv, "lp_uart") == 0) {
port_param->port_num = LP_UART_NUM_0;
port_param->default_src_clk = LP_UART_SCLK_DEFAULT;
port_param->tx_pin_num = LP_U0TXD_GPIO_NUM;
port_param->rx_pin_num = LP_U0RXD_GPIO_NUM;
port_param->rx_flow_ctrl_thresh = 12;
return true;
#endif
} else {
return false;
}
}
static void uart_config(uart_port_t uart_num, uint32_t baud_rate, uart_sclk_t source_clk)
{
uart_config_t uart_config = {
.baud_rate = baud_rate,
@ -34,49 +66,63 @@ static void uart_config(uint32_t baud_rate, uart_sclk_t source_clk)
.flow_ctrl = UART_HW_FLOWCTRL_DISABLE,
};
uart_driver_install(UART_NUM1, BUF_SIZE * 2, BUF_SIZE * 2, 20, NULL, 0);
uart_param_config(UART_NUM1, &uart_config);
TEST_ESP_OK(uart_set_loop_back(UART_NUM1, true));
TEST_ESP_OK(uart_driver_install(uart_num, BUF_SIZE * 2, BUF_SIZE * 2, 20, NULL, 0));
TEST_ESP_OK(uart_param_config(uart_num, &uart_config));
TEST_ESP_OK(uart_set_loop_back(uart_num, true));
}
static volatile bool exit_flag, case_end;
typedef struct {
uart_port_t port_num;
SemaphoreHandle_t exit_sem;
} uart_task1_param_t;
static void test_task1(void *pvParameters)
{
SemaphoreHandle_t *sema = (SemaphoreHandle_t *) pvParameters;
uart_task1_param_t *param = (uart_task1_param_t *)pvParameters;
char* data = (char *) malloc(256);
while (exit_flag == false) {
uart_tx_chars(UART_NUM1, data, 256);
uart_tx_chars(param->port_num, data, 256);
// The uart_wait_tx_done() function does not block anything if ticks_to_wait = 0.
uart_wait_tx_done(UART_NUM1, 0);
uart_wait_tx_done(param->port_num, 0);
}
free(data);
xSemaphoreGive(*sema);
xSemaphoreGive(param->exit_sem);
vTaskDelete(NULL);
}
static void test_task2(void *pvParameters)
{
uart_port_t uart_num = (uart_port_t)pvParameters;
while (exit_flag == false) {
// This task obstruct a setting tx_done_sem semaphore in the UART interrupt.
// It leads to waiting the ticks_to_wait time in uart_wait_tx_done() function.
uart_disable_tx_intr(UART_NUM1);
uart_disable_tx_intr(uart_num);
}
vTaskDelete(NULL);
}
static void test_task3(void *pvParameters)
{
uart_config(UART_BAUD_11520, UART_SCLK_DEFAULT);
uart_port_param_t port_param = {};
TEST_ASSERT(port_select(&port_param));
uart_port_t uart_num = port_param.port_num;
uart_config(uart_num, UART_BAUD_11520, port_param.default_src_clk);
SemaphoreHandle_t exit_sema = xSemaphoreCreateBinary();
uart_task1_param_t task1_param = {
.port_num = uart_num,
.exit_sem = exit_sema,
};
exit_flag = false;
case_end = false;
xTaskCreate(test_task1, "tsk1", 2048, &exit_sema, 5, NULL);
xTaskCreate(test_task2, "tsk2", 2048, NULL, 5, NULL);
xTaskCreate(test_task1, "tsk1", 2048, (void *)&task1_param, 5, NULL);
xTaskCreate(test_task2, "tsk2", 2048, (void *)uart_num, 5, NULL);
printf("Waiting for 5 sec\n");
vTaskDelay(pdMS_TO_TICKS(5000));
@ -87,7 +133,7 @@ static void test_task3(void *pvParameters)
} else {
TEST_FAIL_MESSAGE("uart_wait_tx_done is blocked");
}
TEST_ESP_OK(uart_driver_delete(UART_NUM1));
TEST_ESP_OK(uart_driver_delete(uart_num));
vTaskDelay(2); // wait for test_task1 to exit
@ -104,41 +150,70 @@ TEST_CASE("test uart_wait_tx_done is not blocked when ticks_to_wait=0", "[uart]"
TEST_CASE("test uart get baud-rate", "[uart]")
{
#if SOC_UART_SUPPORT_REF_TICK
uint32_t baud_rate1 = 0;
printf("init uart%d, use reftick, baud rate : %d\n", (int)UART_NUM1, (int)UART_BAUD_11520);
uart_config(UART_BAUD_11520, UART_SCLK_REF_TICK);
uart_get_baudrate(UART_NUM1, &baud_rate1);
printf("get baud rate when use reftick: %d\n", (int)baud_rate1);
TEST_ASSERT_UINT32_WITHIN(UART_BAUD_11520 * TOLERANCE, UART_BAUD_11520, baud_rate1);
#endif
uint32_t baud_rate2 = 0;
printf("init uart%d, unuse reftick, baud rate : %d\n", (int)UART_NUM1, (int)UART_BAUD_115200);
uart_config(UART_BAUD_115200, UART_SCLK_DEFAULT);
uart_get_baudrate(UART_NUM1, &baud_rate2);
printf("get baud rate when don't use reftick: %d\n", (int)baud_rate2);
TEST_ASSERT_UINT32_WITHIN(UART_BAUD_115200 * TOLERANCE, UART_BAUD_115200, baud_rate2);
uart_port_param_t port_param = {};
TEST_ASSERT(port_select(&port_param));
uart_driver_delete(UART_NUM1);
ESP_LOGI(UART_TAG, "get baud-rate test passed ....");
uart_port_t uart_num = port_param.port_num;
soc_module_clk_t uart_clk_srcs[] = SOC_UART_CLKS;
uint32_t uart_clk_srcs_num = sizeof(uart_clk_srcs) / sizeof(uart_clk_srcs[0]);
soc_module_clk_t *clk_srcs = uart_clk_srcs;
uint32_t clk_srcs_num = uart_clk_srcs_num;
#if SOC_UART_LP_NUM > 0
soc_module_clk_t lp_uart_clk_srcs[] = SOC_LP_UART_CLKS;
uint32_t lp_uart_clk_srcs_num = sizeof(lp_uart_clk_srcs) / sizeof(lp_uart_clk_srcs[0]);
if (uart_num >= SOC_UART_HP_NUM) {
clk_srcs = lp_uart_clk_srcs;
clk_srcs_num = lp_uart_clk_srcs_num;
}
#endif
uart_config(uart_num, UART_BAUD_115200, port_param.default_src_clk);
const uint32_t test_baudrate_vals[] = {UART_BAUD_11520, UART_BAUD_115200};
for (size_t i = 0; i < sizeof(test_baudrate_vals) / sizeof(test_baudrate_vals[0]); i++) {
for (size_t j = 0; j < clk_srcs_num; j++) {
uart_config_t uart_config = {
.baud_rate = test_baudrate_vals[i],
.source_clk = clk_srcs[j],
.data_bits = UART_DATA_8_BITS,
.parity = UART_PARITY_DISABLE,
.stop_bits = UART_STOP_BITS_1,
.flow_ctrl = UART_HW_FLOWCTRL_DISABLE,
};
TEST_ESP_OK(uart_param_config(uart_num, &uart_config));
uint32_t actual_baudrate = 0;
uart_get_baudrate(uart_num, &actual_baudrate);
TEST_ASSERT_UINT32_WITHIN(test_baudrate_vals[i] * TOLERANCE, test_baudrate_vals[i], actual_baudrate);
}
}
uart_driver_delete(uart_num);
}
TEST_CASE("test uart tx data with break", "[uart]")
{
uart_port_param_t port_param = {};
TEST_ASSERT(port_select(&port_param));
uart_port_t uart_num = port_param.port_num;
const int buf_len = 200;
const int send_len = 128;
const int brk_len = 10;
char *psend = (char *)malloc(buf_len);
TEST_ASSERT_NOT_NULL(psend);
memset(psend, '0', buf_len);
uart_config(UART_BAUD_115200, UART_SCLK_DEFAULT);
printf("Uart%d send %d bytes with break\n", UART_NUM1, send_len);
uart_write_bytes_with_break(UART_NUM1, (const char *)psend, send_len, brk_len);
uart_wait_tx_done(UART_NUM1, portMAX_DELAY);
uart_config(uart_num, UART_BAUD_115200, port_param.default_src_clk);
printf("Uart%d send %d bytes with break\n", uart_num, send_len);
uart_write_bytes_with_break(uart_num, (const char *)psend, send_len, brk_len);
uart_wait_tx_done(uart_num, portMAX_DELAY);
//If the code is running here, it means the test passed, otherwise it will crash due to the interrupt wdt timeout.
printf("Send data with break test passed\n");
free(psend);
uart_driver_delete(UART_NUM1);
uart_driver_delete(uart_num);
}
static void uart_word_len_set_get_test(int uart_num)
@ -210,14 +285,17 @@ static void uart_wakeup_set_get_test(int uart_num)
TEST_CASE("uart general API test", "[uart]")
{
const int uart_num = UART_NUM1;
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 = 115200,
.data_bits = UART_DATA_8_BITS,
.parity = UART_PARITY_DISABLE,
.stop_bits = UART_STOP_BITS_1,
.flow_ctrl = UART_HW_FLOWCTRL_DISABLE,
.source_clk = UART_SCLK_DEFAULT,
.source_clk = port_param.default_src_clk,
};
uart_param_config(uart_num, &uart_config);
uart_word_len_set_get_test(uart_num);
@ -229,7 +307,7 @@ TEST_CASE("uart general API test", "[uart]")
static void uart_write_task(void *param)
{
int uart_num = (int)param;
uart_port_t uart_num = (uart_port_t)param;
uint8_t *tx_buf = (uint8_t *)malloc(1024);
if(tx_buf == NULL) {
TEST_FAIL_MESSAGE("tx buffer malloc fail");
@ -241,25 +319,19 @@ static void uart_write_task(void *param)
//d[0] and d[1023] are header
tx_buf[0] = (i & 0xff);
tx_buf[1023] = ((~i) & 0xff);
uart_write_bytes(uart_num, (const char*)tx_buf, 1024);
uart_write_bytes(uart_num, (const char *)tx_buf, 1024);
uart_wait_tx_done(uart_num, portMAX_DELAY);
}
free(tx_buf);
vTaskDelete(NULL);
}
/**
* The following tests use loop back
*
* NOTE: In the following tests, because the internal loopback is enabled, the CTS signal is connected to
* the RTS signal internally. However, On ESP32S3, they are not, and the CTS keeps the default level (which
* is a high level). So the workaround is to map the CTS in_signal to a GPIO pin (here IO13 is used) and connect
* the RTS output_signal to this IO.
*/
TEST_CASE("uart read write test", "[uart]")
{
const int uart_num = UART_NUM1;
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);
if(rd_data == NULL) {
TEST_FAIL_MESSAGE("rx buffer malloc fail");
@ -270,15 +342,13 @@ TEST_CASE("uart read write test", "[uart]")
.parity = UART_PARITY_DISABLE,
.stop_bits = UART_STOP_BITS_1,
.flow_ctrl = UART_HW_FLOWCTRL_CTS_RTS,
.source_clk = UART_SCLK_DEFAULT,
.rx_flow_ctrl_thresh = 120
.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_set_pin(uart_num, UART_PIN_NO_CHANGE, UART_PIN_NO_CHANGE, UART_PIN_NO_CHANGE, UART1_CTS_PIN));
//Connect the RTS out_signal to the CTS pin (which is mapped to CTS in_signal)
esp_rom_gpio_connect_out_signal(UART1_CTS_PIN, UART_PERIPH_SIGNAL(uart_num, SOC_UART_RTS_PIN_IDX), 0, 0);
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
@ -322,12 +392,15 @@ TEST_CASE("uart read write test", "[uart]")
uart_driver_delete(uart_num);
free(rd_data);
vTaskDelay(pdMS_TO_TICKS(100)); // wait for uart_write_task to exit
vTaskDelay(2); // wait for uart_write_task to exit
}
TEST_CASE("uart tx with ringbuffer test", "[uart]")
{
const int uart_num = UART_NUM1;
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);
uint8_t *wr_data = (uint8_t *)malloc(1024);
if(rd_data == NULL || wr_data == NULL) {
@ -339,16 +412,14 @@ TEST_CASE("uart tx with ringbuffer test", "[uart]")
.parity = UART_PARITY_DISABLE,
.stop_bits = UART_STOP_BITS_1,
.flow_ctrl = UART_HW_FLOWCTRL_CTS_RTS,
.rx_flow_ctrl_thresh = 120,
.source_clk = UART_SCLK_DEFAULT,
.rx_flow_ctrl_thresh = port_param.rx_flow_ctrl_thresh,
.source_clk = port_param.default_src_clk,
};
uart_wait_tx_idle_polling(uart_num);
TEST_ESP_OK(uart_param_config(uart_num, &uart_config));
TEST_ESP_OK(uart_driver_install(uart_num, 1024 * 2, 1024 *2, 20, NULL, 0));
TEST_ESP_OK(uart_driver_install(uart_num, 1024 * 2, 1024 * 2, 20, NULL, 0));
// 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_set_pin(uart_num, UART_PIN_NO_CHANGE, UART_PIN_NO_CHANGE, UART_PIN_NO_CHANGE, UART1_CTS_PIN));
//Connect the RTS out_signal to the CTS pin (which is mapped to CTS in_signal)
esp_rom_gpio_connect_out_signal(UART1_CTS_PIN, UART_PERIPH_SIGNAL(uart_num, SOC_UART_RTS_PIN_IDX), 0, 0);
for (int i = 0; i < 1024; i++) {
wr_data[i] = i;
@ -358,7 +429,7 @@ TEST_CASE("uart tx with ringbuffer test", "[uart]")
size_t tx_buffer_free_space;
uart_get_tx_buffer_free_size(uart_num, &tx_buffer_free_space);
TEST_ASSERT_EQUAL_INT(2048, tx_buffer_free_space); // full tx buffer space is free
uart_write_bytes(uart_num, (const char*)wr_data, 1024);
uart_write_bytes(uart_num, (const char *)wr_data, 1024);
uart_get_tx_buffer_free_size(uart_num, &tx_buffer_free_space);
TEST_ASSERT_LESS_THAN(2048, tx_buffer_free_space); // tx transmit in progress: tx buffer has content
TEST_ASSERT_GREATER_OR_EQUAL(1024, tx_buffer_free_space);
@ -374,56 +445,72 @@ TEST_CASE("uart tx with ringbuffer test", "[uart]")
TEST_CASE("uart int state restored after flush", "[uart]")
{
/**
* The first goal of this test is to make sure that when our RX FIFO is full,
* we can continue receiving back data after flushing
* For more details, check IDF-4374
*/
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 = 115200,
.data_bits = UART_DATA_8_BITS,
.parity = UART_PARITY_DISABLE,
.stop_bits = UART_STOP_BITS_1,
.flow_ctrl = UART_HW_FLOWCTRL_DISABLE,
.source_clk = UART_SCLK_DEFAULT,
.source_clk = port_param.default_src_clk,
};
const uart_port_t uart_echo = UART_NUM_1;
const int uart_tx_signal = uart_periph_signal[uart_echo].pins[SOC_UART_TX_PIN_IDX].signal;
const int uart_tx = UART1_TX_PIN;
const int uart_rx = UART1_RX_PIN;
const int uart_tx_signal = uart_periph_signal[uart_num].pins[SOC_UART_TX_PIN_IDX].signal;
const int uart_tx = port_param.tx_pin_num;
const int uart_rx = port_param.rx_pin_num;
const int buf_size = 256;
const int intr_alloc_flags = 0;
TEST_ESP_OK(uart_driver_install(uart_echo, buf_size * 2, 0, 0, NULL, intr_alloc_flags));
TEST_ESP_OK(uart_param_config(uart_echo, &uart_config));
TEST_ESP_OK(uart_set_pin(uart_echo, uart_tx, uart_rx, UART_PIN_NO_CHANGE, UART_PIN_NO_CHANGE));
TEST_ESP_OK(uart_driver_install(uart_num, buf_size * 2, 0, 0, NULL, intr_alloc_flags));
TEST_ESP_OK(uart_param_config(uart_num, &uart_config));
TEST_ESP_OK(uart_set_pin(uart_num, uart_tx, uart_rx, UART_PIN_NO_CHANGE, UART_PIN_NO_CHANGE));
/* Make sure UART2's RX signal is connected to TX pin
/* Make sure UART's TX signal is connected to RX pin
* This creates a loop that lets us receive anything we send on the UART */
esp_rom_gpio_connect_out_signal(uart_rx, uart_tx_signal, false, false);
if (uart_num < SOC_UART_HP_NUM) {
esp_rom_gpio_connect_out_signal(uart_rx, uart_tx_signal, false, false);
#if SOC_UART_LP_NUM > 0
} else {
// LP_UART
#if SOC_LP_GPIO_MATRIX_SUPPORTED
TEST_ESP_OK(lp_gpio_connect_out_signal(uart_rx, uart_tx_signal, false, false));
#else
// The only way is to use loop back feature
TEST_ESP_OK(uart_set_loop_back(uart_num, true));
#endif
#endif // SOC_UART_LP_NUM > 0
}
uint8_t *data = (uint8_t *) malloc(buf_size);
uint8_t *data = (uint8_t *)malloc(buf_size);
TEST_ASSERT_NOT_NULL(data);
uart_write_bytes(uart_echo, (const char *) data, buf_size);
uart_write_bytes(uart_num, (const char *)data, buf_size);
/* As we set up a loopback, we can read them back on RX */
int len = uart_read_bytes(uart_echo, data, buf_size, pdMS_TO_TICKS(1000));
int len = uart_read_bytes(uart_num, data, buf_size, pdMS_TO_TICKS(1000));
printf("len is %d\n", len);
TEST_ASSERT_EQUAL(len, buf_size);
/**
* The first goal of this test is to make sure that when our RX FIFO is full,
* we can continue receiving back data after flushing
* For more details, check IDF-4374 */
/* Fill the RX buffer, this should disable the RX interrupts */
int written = uart_write_bytes(uart_echo, (const char *) data, buf_size);
int written = uart_write_bytes(uart_num, (const char *)data, buf_size);
TEST_ASSERT_NOT_EQUAL(-1, written);
written = uart_write_bytes(uart_echo, (const char *) data, buf_size);
written = uart_write_bytes(uart_num, (const char *)data, buf_size);
TEST_ASSERT_NOT_EQUAL(-1, written);
written = uart_write_bytes(uart_echo, (const char *) data, buf_size);
written = uart_write_bytes(uart_num, (const char *)data, buf_size);
TEST_ASSERT_NOT_EQUAL(-1, written);
/* Flush the input buffer, RX interrupts should be re-enabled */
uart_flush_input(uart_echo);
written = uart_write_bytes(uart_echo, (const char *) data, buf_size);
uart_flush_input(uart_num);
written = uart_write_bytes(uart_num, (const char *)data, buf_size);
TEST_ASSERT_NOT_EQUAL(-1, written);
len = uart_read_bytes(uart_echo, data, buf_size, pdMS_TO_TICKS(1000));
len = uart_read_bytes(uart_num, data, buf_size, pdMS_TO_TICKS(1000));
/* len equals buf_size bytes if interrupts were indeed re-enabled */
TEST_ASSERT_EQUAL(len, buf_size);
@ -433,14 +520,15 @@ TEST_CASE("uart int state restored after flush", "[uart]")
* To do so, start by cleaning the RX FIFO, disable the RX interrupts,
* flush again, send data to the UART and check that we haven't received
* any of the bytes */
uart_flush_input(uart_echo);
uart_disable_rx_intr(uart_echo);
uart_flush_input(uart_echo);
written = uart_write_bytes(uart_echo, (const char *) data, buf_size);
uart_flush_input(uart_num);
uart_disable_rx_intr(uart_num);
uart_flush_input(uart_num);
written = uart_write_bytes(uart_num, (const char *)data, buf_size);
TEST_ASSERT_NOT_EQUAL(-1, written);
len = uart_read_bytes(uart_echo, data, buf_size, pdMS_TO_TICKS(250));
len = uart_read_bytes(uart_num, data, buf_size, pdMS_TO_TICKS(250));
TEST_ASSERT_EQUAL(len, 0);
TEST_ESP_OK(uart_driver_delete(uart_echo));
TEST_ESP_OK(uart_driver_delete(uart_num));
free(data);
}

View File

@ -1,8 +1,17 @@
# SPDX-FileCopyrightText: 2021-2023 Espressif Systems (Shanghai) CO LTD
# SPDX-FileCopyrightText: 2021-2024 Espressif Systems (Shanghai) CO LTD
# SPDX-License-Identifier: CC0-1.0
import pytest
input_argv = {
'esp32': ['uart'],
'esp32s2': ['uart'],
'esp32s3': ['uart'],
'esp32c3': ['uart'],
'esp32c2': ['uart'],
'esp32c6': ['uart', 'lp_uart'],
'esp32h2': ['uart'],
}
@pytest.mark.supported_targets
@pytest.mark.generic
@ -15,4 +24,14 @@ import pytest
indirect=True,
)
def test_uart_single_dev(case_tester) -> None: # type: ignore
case_tester.run_all_normal_cases(reset=True)
dut = case_tester.dut
chip_type = dut.app.target
for uart_port in input_argv.get(chip_type, []):
for case in case_tester.test_menu:
dut.serial.hard_reset()
dut._get_ready()
dut.confirm_write(case.index, expect_str=f'Running {case.name}...')
dut.expect("select to test 'uart' or 'lp_uart' port", timeout=10)
dut.write(f'{uart_port}')
dut.expect_unity_test_output()

View File

@ -1,15 +1,11 @@
/*
* SPDX-FileCopyrightText: 2015-2022 Espressif Systems (Shanghai) CO LTD
* SPDX-FileCopyrightText: 2015-2024 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#pragma once
#ifdef __cplusplus
extern "C" {
#endif
#include "esp_err.h"
#include "esp_intr_alloc.h"
#include "soc/soc_caps.h"
@ -20,6 +16,10 @@ extern "C" {
#include "freertos/ringbuf.h"
#include "hal/uart_types.h"
#ifdef __cplusplus
extern "C" {
#endif
/* @brief When calling `uart_set_pin`, instead of GPIO number, `UART_PIN_NO_CHANGE`
* can be provided to keep the currently allocated pin.
*/

View File

@ -48,7 +48,7 @@
static const char *UART_TAG = "uart";
#define UART_EMPTY_THRESH_DEFAULT (10)
#define LP_UART_EMPTY_THRESH_DEFAULT (2)
#define LP_UART_EMPTY_THRESH_DEFAULT (4)
#define UART_FULL_THRESH_DEFAULT (120)
#define LP_UART_FULL_THRESH_DEFAULT (10)
#define UART_TOUT_THRESH_DEFAULT (10)

View File

@ -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
*/
@ -211,15 +211,18 @@ static inline void lp_uart_ll_reset_register(int hw_id)
*/
FORCE_INLINE_ATTR bool uart_ll_is_enabled(uint32_t uart_num)
{
HAL_ASSERT(uart_num < SOC_UART_HP_NUM);
uint32_t uart_clk_config_reg = ((uart_num == 0) ? PCR_UART0_CONF_REG :
(uart_num == 1) ? PCR_UART1_CONF_REG : 0);
uint32_t uart_rst_bit = ((uart_num == 0) ? PCR_UART0_RST_EN :
(uart_num == 1) ? PCR_UART1_RST_EN : 0);
uint32_t uart_en_bit = ((uart_num == 0) ? PCR_UART0_CLK_EN :
(uart_num == 1) ? PCR_UART1_CLK_EN : 0);
return REG_GET_BIT(uart_clk_config_reg, uart_rst_bit) == 0 &&
REG_GET_BIT(uart_clk_config_reg, uart_en_bit) != 0;
switch (uart_num) {
case 0:
return PCR.uart0_conf.uart0_clk_en && !PCR.uart0_conf.uart0_rst_en;
case 1:
return PCR.uart1_conf.uart1_clk_en && !PCR.uart1_conf.uart1_rst_en;
case 2: // LP_UART
return LPPERI.clk_en.lp_uart_ck_en && !LPPERI.reset_en.lp_uart_reset_en;
default:
// Unknown uart port number
HAL_ASSERT(false);
return false;
}
}
/**

View File

@ -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
*/
@ -100,9 +100,9 @@ FORCE_INLINE_ATTR void lp_uart_ll_get_sclk(uart_dev_t *hw, soc_module_clk_t *sou
case 1:
*source_clk = (soc_module_clk_t)LP_UART_SCLK_XTAL_D2;
break;
case 2:
*source_clk = (soc_module_clk_t)LP_UART_SCLK_LP_PLL;
break;
// case 2:
// *source_clk = (soc_module_clk_t)LP_UART_SCLK_LP_PLL;
// break;
}
}
@ -122,9 +122,9 @@ static inline void lp_uart_ll_set_source_clk(uart_dev_t *hw, soc_periph_lp_uart_
case LP_UART_SCLK_XTAL_D2:
LPPERI.core_clk_sel.lp_uart_clk_sel = 1;
break;
case LP_UART_SCLK_LP_PLL:
LPPERI.core_clk_sel.lp_uart_clk_sel = 2;
break;
// case LP_UART_SCLK_LP_PLL: // TODO: LP_PLL clock requires extra support
// LPPERI.core_clk_sel.lp_uart_clk_sel = 2;
// break;
default:
// Invalid LP_UART clock source
HAL_ASSERT(false);
@ -202,8 +202,7 @@ static inline void lp_uart_ll_reset_register(int hw_id)
*/
FORCE_INLINE_ATTR bool uart_ll_is_enabled(uint32_t uart_num)
{
HAL_ASSERT(uart_num < SOC_UART_HP_NUM);
bool uart_rst_en = false;
bool uart_rst_en = true;
bool uart_apb_en = false;
bool uart_sys_en = false;
switch (uart_num) {
@ -232,7 +231,14 @@ FORCE_INLINE_ATTR bool uart_ll_is_enabled(uint32_t uart_num)
uart_apb_en = HP_SYS_CLKRST.soc_clk_ctrl2.reg_uart4_apb_clk_en;
uart_sys_en = HP_SYS_CLKRST.soc_clk_ctrl1.reg_uart4_sys_clk_en;
break;
case 5:
uart_rst_en = LPPERI.reset_en.rst_en_lp_uart;
uart_apb_en = LPPERI.clk_en.ck_en_lp_uart;
uart_sys_en = true;
break;
default:
// Unknown uart port number
HAL_ASSERT(false);
break;
}
return (!uart_rst_en && uart_apb_en && uart_sys_en);

View File

@ -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
*/
@ -202,6 +202,11 @@ typedef enum {
///////////////////////////////////////////////////UART/////////////////////////////////////////////////////////////////
/**
* @brief Array initializer for all supported clock sources of UART
*/
#define SOC_UART_CLKS {SOC_MOD_CLK_APB, SOC_MOD_CLK_REF_TICK}
/**
* @brief Type of UART clock source, reserved for the legacy UART driver
*/

View File

@ -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
*/
@ -175,6 +175,11 @@ typedef enum {
///////////////////////////////////////////////////UART/////////////////////////////////////////////////////////////////
/**
* @brief Array initializer for all supported clock sources of UART
*/
#define SOC_UART_CLKS {SOC_MOD_CLK_PLL_F40M, SOC_MOD_CLK_XTAL, SOC_MOD_CLK_RC_FAST}
/**
* @brief Type of UART clock source, reserved for the legacy UART driver
*/

View File

@ -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
*/
@ -201,6 +201,11 @@ typedef enum {
///////////////////////////////////////////////////UART/////////////////////////////////////////////////////////////////
/**
* @brief Array initializer for all supported clock sources of UART
*/
#define SOC_UART_CLKS {SOC_MOD_CLK_APB, SOC_MOD_CLK_XTAL, SOC_MOD_CLK_RC_FAST}
/**
* @brief Type of UART clock source, reserved for the legacy UART driver
*/

View File

@ -1179,6 +1179,10 @@ config SOC_UART_SUPPORT_WAKEUP_INT
bool
default y
config SOC_UART_HAS_LP_UART
bool
default y
config SOC_UART_SUPPORT_FSM_TX_WAIT_SEND
bool
default y

View File

@ -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
*/
@ -217,6 +217,11 @@ typedef enum {
///////////////////////////////////////////////////UART/////////////////////////////////////////////////////////////////
/**
* @brief Array initializer for all supported clock sources of UART
*/
#define SOC_UART_CLKS {SOC_MOD_CLK_PLL_F80M, SOC_MOD_CLK_XTAL, SOC_MOD_CLK_RC_FAST}
/**
* @brief Type of UART clock source, reserved for the legacy UART driver
*/
@ -227,6 +232,11 @@ typedef enum {
UART_SCLK_DEFAULT = SOC_MOD_CLK_PLL_F80M, /*!< UART source clock default choice is PLL_F80M */
} soc_periph_uart_clk_src_legacy_t;
/**
* @brief Array initializer for all supported clock sources of LP_UART
*/
#define SOC_LP_UART_CLKS {SOC_MOD_CLK_RTC_FAST, SOC_MOD_CLK_XTAL_D2}
/**
* @brief Type of LP_UART clock source
*/

View File

@ -477,6 +477,7 @@
#define SOC_UART_SUPPORT_RTC_CLK (1) /*!< Support RTC clock as the clock source */
#define SOC_UART_SUPPORT_XTAL_CLK (1) /*!< Support XTAL clock as the clock source */
#define SOC_UART_SUPPORT_WAKEUP_INT (1) /*!< Support UART wakeup interrupt */
#define SOC_UART_HAS_LP_UART (1) /*!< Support LP UART */
// UART has an extra TX_WAIT_SEND state when the FIFO is not empty and XOFF is enabled
#define SOC_UART_SUPPORT_FSM_TX_WAIT_SEND (1)

View File

@ -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
*/
@ -224,6 +224,11 @@ typedef enum {
///////////////////////////////////////////////////UART/////////////////////////////////////////////////////////////////
/**
* @brief Array initializer for all supported clock sources of UART
*/
#define SOC_UART_CLKS {SOC_MOD_CLK_PLL_F48M, SOC_MOD_CLK_XTAL, SOC_MOD_CLK_RC_FAST}
/**
* @brief Type of UART clock source, reserved for the legacy UART driver
*/

View File

@ -1139,6 +1139,10 @@ config SOC_UART_SUPPORT_WAKEUP_INT
bool
default y
config SOC_UART_HAS_LP_UART
bool
default y
config SOC_UART_SUPPORT_FSM_TX_WAIT_SEND
bool
default y

View File

@ -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
*/
@ -258,6 +258,11 @@ typedef enum {
///////////////////////////////////////////////////UART/////////////////////////////////////////////////////////////////
/**
* @brief Array initializer for all supported clock sources of UART
*/
#define SOC_UART_CLKS {SOC_MOD_CLK_PLL_F80M, SOC_MOD_CLK_XTAL, SOC_MOD_CLK_RC_FAST}
/**
* @brief Type of UART clock source, reserved for the legacy UART driver
*/
@ -265,26 +270,22 @@ typedef enum {
UART_SCLK_PLL_F80M = SOC_MOD_CLK_PLL_F80M, /*!< UART source clock is PLL_F80M */
UART_SCLK_RTC = SOC_MOD_CLK_RC_FAST, /*!< UART source clock is RC_FAST */
UART_SCLK_XTAL = SOC_MOD_CLK_XTAL, /*!< UART source clock is XTAL */
#if SOC_CLK_TREE_SUPPORTED
UART_SCLK_DEFAULT = SOC_MOD_CLK_PLL_F80M, /*!< UART source clock default choice is PLL_F80M */
#else
UART_SCLK_DEFAULT = SOC_MOD_CLK_XTAL, /*!< UART source clock default choice is XTAL for FPGA environment */
#endif
} soc_periph_uart_clk_src_legacy_t;
/**
* @brief Array initializer for all supported clock sources of LP_UART
*/
#define SOC_LP_UART_CLKS {SOC_MOD_CLK_RTC_FAST, SOC_MOD_CLK_XTAL_D2}
/**
* @brief Type of LP_UART clock source
*/
typedef enum {
LP_UART_SCLK_LP_FAST = SOC_MOD_CLK_RTC_FAST, /*!< LP_UART source clock is LP(RTC)_FAST */
LP_UART_SCLK_XTAL_D2 = SOC_MOD_CLK_XTAL_D2, /*!< LP_UART source clock is XTAL_D2 */
LP_UART_SCLK_LP_PLL = SOC_MOD_CLK_LP_PLL, /*!< LP_UART source clock is LP_PLL (8M PLL) */
#if SOC_CLK_TREE_SUPPORTED
LP_UART_SCLK_DEFAULT = SOC_MOD_CLK_RTC_FAST,
#else
LP_UART_SCLK_DEFAULT = SOC_MOD_CLK_XTAL_D2, /*!< LP_UART source clock default choice is XTAL_D2 */
#endif
// LP_UART_SCLK_LP_PLL = SOC_MOD_CLK_LP_PLL, /*!< LP_UART source clock is LP_PLL (8M PLL) */ TODO: LP_PLL clock requires extra support
LP_UART_SCLK_DEFAULT = SOC_MOD_CLK_RTC_FAST, /*!< LP_UART source clock default choice is LP(RTC)_FAST */
} soc_periph_lp_uart_clk_src_t;
//////////////////////////////////////////////////MCPWM/////////////////////////////////////////////////////////////////

View File

@ -503,6 +503,7 @@
#define SOC_UART_SUPPORT_RTC_CLK (1) /*!< Support RTC clock as the clock source */
#define SOC_UART_SUPPORT_XTAL_CLK (1) /*!< Support XTAL clock as the clock source */
#define SOC_UART_SUPPORT_WAKEUP_INT (1) /*!< Support UART wakeup interrupt */
#define SOC_UART_HAS_LP_UART (1) /*!< Support LP UART */
// UART has an extra TX_WAIT_SEND state when the FIFO is not empty and XOFF is enabled
#define SOC_UART_SUPPORT_FSM_TX_WAIT_SEND (1)

View File

@ -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
*/
@ -217,6 +217,11 @@ typedef enum {
///////////////////////////////////////////////////UART/////////////////////////////////////////////////////////////////
/**
* @brief Array initializer for all supported clock sources of UART
*/
#define SOC_UART_CLKS {SOC_MOD_CLK_APB, SOC_MOD_CLK_REF_TICK}
/**
* @brief Type of UART clock source, reserved for the legacy UART driver
*/

View File

@ -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
*/
@ -219,6 +219,11 @@ typedef enum {
///////////////////////////////////////////////////UART/////////////////////////////////////////////////////////////////
/**
* @brief Array initializer for all supported clock sources of UART
*/
#define SOC_UART_CLKS {SOC_MOD_CLK_APB, SOC_MOD_CLK_XTAL, SOC_MOD_CLK_RC_FAST}
/**
* @brief Type of UART clock source, reserved for the legacy UART driver
*/

View File

@ -97,7 +97,6 @@ api-reference/peripherals/dedic_gpio.rst
api-reference/peripherals/sd_pullup_requirements.rst
api-reference/peripherals/index.rst
api-reference/peripherals/sdmmc_host.rst
api-reference/peripherals/uart.rst
api-reference/network/esp_openthread.rst
api-reference/network/esp_eth.rst
api-reference/network/esp_netif_driver.rst

View File

@ -12,7 +12,7 @@ The {IDF_TARGET_NAME} chip has {IDF_TARGET_SOC_UART_HP_NUM} UART controllers (al
Each UART controller is independently configurable with parameters such as baud rate, data bit length, bit ordering, number of stop bits, parity bit, etc. All the regular UART controllers are compatible with UART-enabled devices from various manufacturers and can also support Infrared Data Association (IrDA) protocols.
.. only:: SOC_UART_LP_NUM
.. only:: SOC_UART_HAS_LP_UART
Additionally, the {IDF_TARGET_NAME} chip has one low-power (LP) UART controller. It is the cut-down version of regular UART. Usually, the LP UART controller only support basic UART functionality with a much smaller RAM size, and does not support IrDA or RS485 protocols. For a full list of difference between UART and LP UART, please refer to the **{IDF_TARGET_NAME} Technical Reference Manual** > **UART Controller (UART)** > **Features** [`PDF <{IDF_TARGET_TRM_EN_URL}#uart>`__]).
@ -30,6 +30,10 @@ The overview describes how to establish communication between an {IDF_TARGET_NAM
Steps 1 to 3 comprise the configuration stage. Step 4 is where the UART starts operating. Steps 5 and 6 are optional.
.. only:: SOC_UART_HAS_LP_UART
Additionally, when using the LP UART Controller you need to pay attention to :ref:`uart-api-lp-uart-driver`.
The UART driver's functions identify each of the UART controllers using :cpp:type:`uart_port_t`. This identification is needed for all the following function calls.
@ -239,12 +243,6 @@ The API provides a convenient way to handle specific interrupts discussed in thi
- Disable the interrupt using :cpp:func:`uart_disable_pattern_det_intr`
Macros
^^^^^^
The API also defines several macros. For example, :c:macro:`UART_HW_FIFO_LEN` defines the length of hardware FIFO buffers; :c:macro:`UART_BITRATE_MAX` gives the maximum baud rate supported by the UART controllers, etc.
.. _uart-api-deleting-driver:
Deleting a Driver
@ -253,6 +251,29 @@ Deleting a Driver
If the communication established with :cpp:func:`uart_driver_install` is no longer required, the driver can be removed to free allocated resources by calling :cpp:func:`uart_driver_delete`.
Macros
^^^^^^
The API also defines several macros. For example, :c:macro:`UART_HW_FIFO_LEN` defines the length of hardware FIFO buffers; :c:macro:`UART_BITRATE_MAX` gives the maximum baud rate supported by the UART controllers, etc.
.. only:: SOC_UART_HAS_LP_UART
.. _uart-api-lp-uart-driver:
Use LP UART Controller with HP Core
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
The UART driver also supports to control the LP UART controller when the chip is in active mode. The configuration steps for the LP UART are the same as the steps for a normal UART controller, except:
.. list::
- The port number for the LP UART controller is defined by :c:macro:`LP_UART_NUM_0`.
- The available clock sources for the LP UART controller can be found in :cpp:type:`lp_uart_sclk_t`.
- The size of the hardware FIFO for the LP UART controller is much smaller, which is defined in :c:macro:`SOC_LP_UART_FIFO_LEN`.
:SOC_LP_GPIO_MATRIX_SUPPORTED: - The GPIO pins for the LP UART controller can only be selected from the LP GPIO pins.
:not SOC_LP_GPIO_MATRIX_SUPPORTED: - The GPIO pins for the LP UART controller are unalterable, because there is no LP GPIO matrix on the target. Please see **{IDF_TARGET_NAME} Technical Reference Manual** > **IO MUX and GPIO Matrix (GPIO, IO MUX)** > **LP IO MUX Functions List** [`PDF <{IDF_TARGET_TRM_EN_URL}#lp-io-mux-func-list>`__] for the specific pin numbers.
Overview of RS485 Specific Communication 0ptions
------------------------------------------------

View File

@ -12,7 +12,7 @@
每个 UART 控制器可以独立配置波特率、数据位长度、位顺序、停止位位数、奇偶校验位等参数。所有具备完整功能的 UART 控制器都能与不同制造商的 UART 设备兼容,并且支持红外数据协会 (IrDA) 定义的标准协议。
.. only:: SOC_UART_LP_NUM
.. only:: SOC_UART_HAS_LP_UART
此外,{IDF_TARGET_NAME} 芯片还有一个满足低功耗需求的 LP UART 控制器。LP UART 是原 UART 的功能剪裁版本。它只支持基础 UART 功能,不支持 IrDA 或 RS485 协议,并且只有一块较小的 RAM 存储空间。想要全面了解的 UART 及 LP UART 功能区别,请参考 **{IDF_TARGET_NAME} 技术参考手册** > UART 控制器 (UART) > 主要特性 [`PDF <{IDF_TARGET_TRM_EN_URL}#uart>`__]。
@ -30,6 +30,10 @@
步骤 1 到 3 为配置阶段,步骤 4 为 UART 运行阶段,步骤 5 和 6 为可选步骤。
.. only:: SOC_UART_HAS_LP_UART
此外LP UART 控制器的编程需要注意 :ref:`uart-api-lp-uart-driver`
UART 驱动程序函数通过 :cpp:type:`uart_port_t` 识别不同的 UART 控制器。调用以下所有函数均需此标识。
@ -239,12 +243,6 @@ API 提供了一种便利的方法来处理本文所讨论的特定中断,即
- 禁用中断:调用 :cpp:func:`uart_disable_pattern_det_intr`
宏指令
^^^^^^^^^^^^
API 还定义了一些宏指令。例如,:c:macro:`UART_HW_FIFO_LEN` 定义了硬件 FIFO 缓冲区的长度,:c:macro:`UART_BITRATE_MAX` 定义了 UART 控制器支持的最大波特率。
.. _uart-api-deleting-driver:
删除驱动程序
@ -253,12 +251,35 @@ API 还定义了一些宏指令。例如,:c:macro:`UART_HW_FIFO_LEN` 定义了
如不再需要与 :cpp:func:`uart_driver_install` 建立通信,则可调用 :cpp:func:`uart_driver_delete` 删除驱动程序,释放已分配的资源。
宏指令
^^^^^^^^^^^^
API 还定义了一些宏指令。例如,:c:macro:`UART_HW_FIFO_LEN` 定义了硬件 FIFO 缓冲区的长度,:c:macro:`UART_BITRATE_MAX` 定义了 UART 控制器支持的最大波特率。
.. only:: SOC_UART_HAS_LP_UART
.. _uart-api-lp-uart-driver:
使用主核驱动 LP UART 控制器
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
UART 驱动程序还适配了在 Active 模式下对 LP UART 控制器的驱动。LP UART 的配置流程和普通 UART 没有本质上的差别,除了有以下几点需要注意:
.. list::
- LP UART 控制器的端口号为 :c:macro:`LP_UART_NUM_0`
- LP UART 控制器的可选时钟源可以在 :cpp:type:`lp_uart_sclk_t` 中找到。
- LP UART 控制器的硬件 FIFO 大小要远小于普通 UART 控制器的硬件 FIFO 大小,其值为 :c:macro:`SOC_LP_UART_FIFO_LEN`
:SOC_LP_GPIO_MATRIX_SUPPORTED: - LP UART 控制器的 GPIO 引脚只能从 LP GPIO 引脚中选择。
:not SOC_LP_GPIO_MATRIX_SUPPORTED: - 由于该芯片没有 LP GPIO 交换矩阵LP UART 控制器的 GPIO 引脚不可改变。具体的引脚号请查看 **{IDF_TARGET_NAME} 技术参考手册** > **IO MUX 和 GPIO 交换矩阵 (GPIO, IO MUX)** > **LP IO MUX 管脚功能列表** [`PDF <{IDF_TARGET_TRM_CN_URL}#lp-io-mux-func-list>`__]。
RS485 特定通信模式简介
----------------------------------------------
.. note::
下文将使用 ``[UART_REGISTER_NAME].[UART_FIELD_BIT]`` 指代 UART 寄存器字段/位。了解特定模式位的更多信息,请参考 **{IDF_TARGET_NAME} 技术参考手册** > UART 控制器 (UART) > 寄存器摘要 [`PDF <{IDF_TARGET_TRM_EN_URL}#uart-reg-summ>`__]。请搜索寄存器名称导航至寄存器描述,找到相应字段/位。
下文将使用 ``[UART_REGISTER_NAME].[UART_FIELD_BIT]`` 指代 UART 寄存器字段/位。了解特定模式位的更多信息,请参考 **{IDF_TARGET_NAME} 技术参考手册** > UART 控制器 (UART) > 寄存器摘要 [`PDF <{IDF_TARGET_TRM_CN_URL}#uart-reg-summ>`__]。请搜索寄存器名称导航至寄存器描述,找到相应字段/位。
- ``UART_RS485_CONF_REG.UART_RS485_EN``:设置此位将启用 RS485 通信模式支持。
- ``UART_RS485_CONF_REG.UART_RS485TX_RX_EN``:设置此位,发送器的输出信号将环回到接收器的输入信号。