mirror of
https://github.com/espressif/esp-idf.git
synced 2025-08-10 04:43:33 +00:00
feat(uart): support uart module sleep retention on c6/h2/p4
This commit is contained in:
@@ -1,7 +1,19 @@
|
||||
set(srcs "test_app_main.c"
|
||||
"test_uart.c")
|
||||
|
||||
if(CONFIG_PM_ENABLE)
|
||||
list(APPEND srcs "test_uart_auto_lightsleep.c")
|
||||
endif()
|
||||
|
||||
# Only if the target supports uart retention and the sdkconfig.ci.xxx contains at least PM_ENABLE=y
|
||||
if(CONFIG_SOC_UART_SUPPORT_SLEEP_RETENTION AND CONFIG_PM_ENABLE)
|
||||
list(APPEND srcs "test_uart_retention.c")
|
||||
endif()
|
||||
|
||||
# In order for the cases defined by `TEST_CASE` to be linked into the final elf,
|
||||
# the component can be registered as WHOLE_ARCHIVE
|
||||
idf_component_register(
|
||||
SRCS "test_app_main.c" "test_uart.c" "test_uart_auto_lightsleep.c"
|
||||
SRCS ${srcs}
|
||||
REQUIRES esp_driver_uart unity esp_psram test_utils esp_driver_gpio esp_pm
|
||||
PRIV_INCLUDE_DIRS .
|
||||
WHOLE_ARCHIVE
|
||||
|
@@ -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
|
||||
*/
|
||||
@@ -27,15 +27,14 @@
|
||||
|
||||
#if CONFIG_XTAL_FREQ_40
|
||||
#define MIN_FREQ 10
|
||||
#elif CONFIG_XTAL_FREQ_48
|
||||
#define MIN_FREQ 12
|
||||
#elif CONFIG_XTAL_FREQ_32
|
||||
#define MIN_FREQ 8
|
||||
#elif CONFIG_XTAL_FREQ_26
|
||||
#define MIN_FREQ 13
|
||||
#endif
|
||||
|
||||
#if !TEMPORARY_DISABLED_FOR_TARGETS(ESP32P4)
|
||||
#if CONFIG_PM_ENABLE
|
||||
|
||||
TEST_CASE("uart tx won't be blocked by auto light sleep", "[uart]")
|
||||
{
|
||||
uart_port_param_t port_param = {};
|
||||
@@ -82,10 +81,8 @@ TEST_CASE("uart tx won't be blocked by auto light sleep", "[uart]")
|
||||
uart_driver_delete(port_num);
|
||||
free(data);
|
||||
|
||||
#if CONFIG_PM_POWER_DOWN_CPU_IN_LIGHT_SLEEP
|
||||
//When PD_CPU enabled, retention may cause 14K memory leak. Workaround to release the memory
|
||||
sleep_cpu_configure(false);
|
||||
#if CONFIG_FREERTOS_USE_TICKLESS_IDLE
|
||||
pm_config.light_sleep_enable = false;
|
||||
TEST_ESP_OK(esp_pm_configure(&pm_config));
|
||||
#endif
|
||||
}
|
||||
#endif // CONFIG_PM_ENABLE
|
||||
#endif //!TEMPORARY_DISABLED_FOR_TARGETS(ESP32P4)
|
||||
|
@@ -0,0 +1,148 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include <string.h>
|
||||
#include "sdkconfig.h"
|
||||
#include "unity.h"
|
||||
#include "driver/uart.h"
|
||||
#include "esp_pm.h"
|
||||
#include "esp_private/sleep_cpu.h"
|
||||
#include "esp_clk_tree.h"
|
||||
#include "esp_sleep.h"
|
||||
|
||||
// UART retention test only need to be done on HP UART
|
||||
|
||||
static const uart_port_t uart_num = UART_NUM_1;
|
||||
|
||||
static void uart_init(bool backup_before_sleep)
|
||||
{
|
||||
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,
|
||||
.flags.backup_before_sleep = backup_before_sleep,
|
||||
};
|
||||
|
||||
TEST_ESP_OK(uart_driver_install(uart_num, 256, 0, 20, NULL, 0));
|
||||
TEST_ESP_OK(uart_param_config(uart_num, &uart_config));
|
||||
TEST_ESP_OK(uart_set_loop_back(uart_num, true));
|
||||
}
|
||||
|
||||
TEST_CASE("uart restored correctly after auto light sleep", "[uart][hp-uart-only]")
|
||||
{
|
||||
// Configure dynamic frequency scaling:
|
||||
// maximum and minimum frequencies are set in sdkconfig,
|
||||
// automatic light sleep is enabled if tickless idle support is enabled.
|
||||
uint32_t xtal_hz = 0;
|
||||
esp_clk_tree_src_get_freq_hz(SOC_MOD_CLK_XTAL, ESP_CLK_TREE_SRC_FREQ_PRECISION_EXACT, &xtal_hz);
|
||||
esp_pm_config_t pm_config = {
|
||||
.max_freq_mhz = CONFIG_ESP_DEFAULT_CPU_FREQ_MHZ,
|
||||
.min_freq_mhz = xtal_hz / 1000000,
|
||||
#if CONFIG_FREERTOS_USE_TICKLESS_IDLE
|
||||
.light_sleep_enable = true,
|
||||
#endif
|
||||
};
|
||||
TEST_ESP_OK(esp_pm_configure(&pm_config));
|
||||
|
||||
uart_init(true);
|
||||
|
||||
// Ensure UART is fully idle before starting loopback RX/TX test
|
||||
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));
|
||||
|
||||
for (int i = 0; i < 5; i++) {
|
||||
char tx_data[20] = {0};
|
||||
char rx_data[20] = {0};
|
||||
int len = sprintf(tx_data, "Hello World %d!\n", i);
|
||||
uart_write_bytes(uart_num, tx_data, len);
|
||||
int size = 0;
|
||||
// Polling to read the data back to avoid getting into auto light sleep
|
||||
while (size < len) {
|
||||
int bytes = uart_read_bytes(uart_num, (void *)((uint32_t)rx_data + size), 1, 0);
|
||||
size += bytes;
|
||||
}
|
||||
rx_data[len] = '\0';
|
||||
printf("%s", rx_data);
|
||||
TEST_ASSERT_TRUE(strcmp(tx_data, rx_data) == 0);
|
||||
|
||||
vTaskDelay(pdMS_TO_TICKS(1000)); // auto light sleep
|
||||
}
|
||||
|
||||
TEST_ESP_OK(uart_driver_delete(uart_num));
|
||||
|
||||
pm_config.light_sleep_enable = false;
|
||||
TEST_ESP_OK(esp_pm_configure(&pm_config));
|
||||
}
|
||||
|
||||
TEST_CASE("uart restored correctly after manually enter light sleep", "[uart][hp-uart-only]")
|
||||
{
|
||||
// Prepare a TOP PD sleep
|
||||
TEST_ESP_OK(esp_sleep_enable_timer_wakeup(1 * 1000 * 1000));
|
||||
sleep_cpu_configure(true);
|
||||
|
||||
uart_init(true);
|
||||
|
||||
// Ensure UART is fully idle before starting loopback RX/TX test
|
||||
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));
|
||||
|
||||
for (int i = 0; i < 5; i++) {
|
||||
char tx_data[20] = {0};
|
||||
char rx_data[20] = {0};
|
||||
int len = sprintf(tx_data, "Hello World %d!\n", i);
|
||||
uart_write_bytes(uart_num, tx_data, len);
|
||||
int size = uart_read_bytes(uart_num, rx_data, len, pdMS_TO_TICKS(20));
|
||||
TEST_ASSERT_EQUAL(len, size);
|
||||
rx_data[len] = '\0';
|
||||
printf("%s", rx_data);
|
||||
TEST_ASSERT_TRUE(strcmp(tx_data, rx_data) == 0);
|
||||
|
||||
printf("Going into sleep...\n");
|
||||
TEST_ESP_OK(esp_light_sleep_start());
|
||||
printf("Waked up!\n");
|
||||
}
|
||||
|
||||
TEST_ESP_OK(uart_driver_delete(uart_num));
|
||||
TEST_ESP_OK(sleep_cpu_configure(false));
|
||||
}
|
||||
|
||||
TEST_CASE("uart won't be powered down in light sleep if retention not created", "[uart][hp-uart-only]")
|
||||
{
|
||||
// Prepare a TOP PD sleep
|
||||
TEST_ESP_OK(esp_sleep_enable_timer_wakeup(1 * 1000 * 1000));
|
||||
sleep_cpu_configure(true);
|
||||
|
||||
uart_init(false); // backup_before_sleep set to false, sleep retention module will be inited, but not created
|
||||
|
||||
// Ensure UART is fully idle before starting loopback RX/TX test
|
||||
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));
|
||||
|
||||
for (int i = 0; i < 3; i++) {
|
||||
char tx_data[20] = {0};
|
||||
char rx_data[20] = {0};
|
||||
int len = sprintf(tx_data, "Hello World %d!\n", i);
|
||||
uart_write_bytes(uart_num, tx_data, len);
|
||||
int size = uart_read_bytes(uart_num, rx_data, len, pdMS_TO_TICKS(20));
|
||||
TEST_ASSERT_EQUAL(len, size);
|
||||
rx_data[len] = '\0';
|
||||
printf("%s", rx_data);
|
||||
TEST_ASSERT_TRUE(strcmp(tx_data, rx_data) == 0);
|
||||
|
||||
printf("Going into sleep...\n");
|
||||
TEST_ESP_OK(esp_light_sleep_start()); // sleep without powering down TOP domain
|
||||
printf("Waked up!\n");
|
||||
}
|
||||
|
||||
TEST_ESP_OK(uart_driver_delete(uart_num));
|
||||
TEST_ESP_OK(sleep_cpu_configure(false));
|
||||
}
|
@@ -28,15 +28,18 @@ input_argv = {
|
||||
def test_uart_single_dev(case_tester) -> None: # type: ignore
|
||||
dut = case_tester.first_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}...')
|
||||
for case in case_tester.test_menu:
|
||||
if 'hp-uart-only' not in case.groups:
|
||||
for uart_port in input_argv.get(chip_type, []):
|
||||
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()
|
||||
dut.expect("select to test 'uart' or 'lp_uart' port", timeout=10)
|
||||
dut.write(f'{uart_port}')
|
||||
dut.expect_unity_test_output()
|
||||
else:
|
||||
dut._run_normal_case(case, reset=True)
|
||||
|
||||
|
||||
@pytest.mark.esp32s3
|
||||
|
@@ -1,5 +1,6 @@
|
||||
CONFIG_PM_ENABLE=y
|
||||
CONFIG_FREERTOS_USE_TICKLESS_IDLE=y
|
||||
CONFIG_PM_POWER_DOWN_PERIPHERAL_IN_LIGHT_SLEEP=y
|
||||
CONFIG_COMPILER_OPTIMIZATION_SIZE=y
|
||||
CONFIG_BOOTLOADER_COMPILER_OPTIMIZATION_SIZE=y
|
||||
CONFIG_COMPILER_OPTIMIZATION_ASSERTIONS_SILENT=y
|
||||
|
@@ -9,7 +9,7 @@
|
||||
#include "esp_heap_caps.h"
|
||||
|
||||
// Some resources are lazy allocated, the threadhold is left for that case
|
||||
#define TEST_MEMORY_LEAK_THRESHOLD (400)
|
||||
#define TEST_MEMORY_LEAK_THRESHOLD (500)
|
||||
|
||||
void setUp(void)
|
||||
{
|
||||
|
Reference in New Issue
Block a user