diff --git a/components/ulp/ld/lp_core_riscv.ld b/components/ulp/ld/lp_core_riscv.ld index 4ecab5b34a..0f2da81c3e 100644 --- a/components/ulp/ld/lp_core_riscv.ld +++ b/components/ulp/ld/lp_core_riscv.ld @@ -14,13 +14,20 @@ #define ULP_MEM_START_ADDRESS (SOC_RTC_DRAM_LOW) #endif +#define ALIGN_DOWN(SIZE, AL) (SIZE & ~(AL - 1)) +/* Ensure the end where the shared memory starts is aligned to 8 bytes + if updating this also update the same in ulp_lp_core_memory_shared.c + */ +#define ALIGNED_COPROC_MEM ALIGN_DOWN(CONFIG_ULP_COPROC_RESERVE_MEM, 0x8) + ENTRY(reset_vector) MEMORY { /*first 128byte for exception/interrupt vectors*/ vector_table(RX) : ORIGIN = ULP_MEM_START_ADDRESS , LENGTH = 0x80 - ram(RWX) : ORIGIN = ULP_MEM_START_ADDRESS + 0x80, LENGTH = CONFIG_ULP_COPROC_RESERVE_MEM - 0x80 - CONFIG_ULP_SHARED_MEM + ram(RWX) : ORIGIN = ULP_MEM_START_ADDRESS + 0x80, LENGTH = ALIGNED_COPROC_MEM - 0x80 - CONFIG_ULP_SHARED_MEM + shared_mem_ram(RW) : ORIGIN = ULP_MEM_START_ADDRESS + ALIGNED_COPROC_MEM - CONFIG_ULP_SHARED_MEM, LENGTH = CONFIG_ULP_SHARED_MEM } SECTIONS @@ -65,4 +72,10 @@ SECTIONS } >ram __stack_top = ORIGIN(ram) + LENGTH(ram); + + . = ORIGIN(shared_mem_ram); + .shared_mem (ALIGN(4)) : + { + KEEP(*(.shared_mem)) + } > shared_mem_ram } diff --git a/components/ulp/lp_core/shared/ulp_lp_core_memory_shared.c b/components/ulp/lp_core/shared/ulp_lp_core_memory_shared.c index e36c4b56dd..c3779b5020 100644 --- a/components/ulp/lp_core/shared/ulp_lp_core_memory_shared.c +++ b/components/ulp/lp_core/shared/ulp_lp_core_memory_shared.c @@ -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 */ @@ -7,21 +7,37 @@ #include "sdkconfig.h" #include "soc/soc.h" +#include "esp_rom_caps.h" #include "esp_assert.h" +#define ALIGN_DOWN(SIZE, AL) (SIZE & ~(AL - 1)) + /* The last CONFIG_ULP_SHARED_MEM bytes of the reserved memory are reserved for a shared cfg struct The main cpu app and the ulp binary can share variables automatically through the linkerscript generated from esp32ulp_mapgen.py, but this is not available when compiling the ULP library. For those special cases, e.g. config settings. We can use this shared area. */ -#define LP_CORE_SHARED_MEM_ADDR (SOC_RTC_DRAM_LOW + CONFIG_ULP_COPROC_RESERVE_MEM - CONFIG_ULP_SHARED_MEM) - -static ulp_lp_core_memory_shared_cfg_t *const s_shared_mem = (ulp_lp_core_memory_shared_cfg_t *)LP_CORE_SHARED_MEM_ADDR; +#if IS_ULP_COCPU +static ulp_lp_core_memory_shared_cfg_t __attribute__((section(".shared_mem"))) s_shared_mem = {}; ESP_STATIC_ASSERT(CONFIG_ULP_SHARED_MEM == sizeof(ulp_lp_core_memory_shared_cfg_t)); +#endif ulp_lp_core_memory_shared_cfg_t* ulp_lp_core_memory_shared_cfg_get(void) { - return s_shared_mem; +#if IS_ULP_COCPU + return &s_shared_mem; +#else +#if ESP_ROM_HAS_LP_ROM + extern uint32_t _rtc_ulp_memory_start; + uint32_t ulp_base_addr = (uint32_t)&_rtc_ulp_memory_start; +#else + uint32_t ulp_base_addr = SOC_RTC_DRAM_LOW; +#endif + /* Ensure the end where the shared memory starts is aligned to 8 bytes + if updating this also update the same in ulp_lp_core_riscv.ld + */ + return (ulp_lp_core_memory_shared_cfg_t *)(ulp_base_addr + ALIGN_DOWN(CONFIG_ULP_COPROC_RESERVE_MEM, 0x8) - CONFIG_ULP_SHARED_MEM); +#endif } diff --git a/components/ulp/test_apps/lp_core/lp_core_hp_uart/main/CMakeLists.txt b/components/ulp/test_apps/lp_core/lp_core_hp_uart/main/CMakeLists.txt index 87918dae18..9e6a9d16bb 100644 --- a/components/ulp/test_apps/lp_core/lp_core_hp_uart/main/CMakeLists.txt +++ b/components/ulp/test_apps/lp_core/lp_core_hp_uart/main/CMakeLists.txt @@ -1,6 +1,7 @@ set(app_sources "test_app_main.c" "test_lp_core.c") set(lp_core_sources "lp_core/test_hello_main.c") set(lp_core_sources_panic "lp_core/test_panic_main.c") +set(lp_core_sources_shared_mem "lp_core/test_shared_mem_main.c") idf_component_register(SRCS ${app_sources} INCLUDE_DIRS "lp_core" @@ -11,3 +12,4 @@ set(lp_core_exp_dep_srcs ${app_sources}) ulp_embed_binary(lp_core_test_app "${lp_core_sources}" "${lp_core_exp_dep_srcs}") ulp_embed_binary(lp_core_test_app_panic "${lp_core_sources_panic}" "${lp_core_exp_dep_srcs}") +ulp_embed_binary(lp_core_test_app_shared_mem "${lp_core_sources_shared_mem}" "${lp_core_exp_dep_srcs}") diff --git a/components/ulp/test_apps/lp_core/lp_core_hp_uart/main/lp_core/test_shared.h b/components/ulp/test_apps/lp_core/lp_core_hp_uart/main/lp_core/test_shared.h new file mode 100644 index 0000000000..17571e195c --- /dev/null +++ b/components/ulp/test_apps/lp_core/lp_core_hp_uart/main/lp_core/test_shared.h @@ -0,0 +1,9 @@ +/* + * SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Unlicense OR CC0-1.0 + */ +#pragma once + +#define SHARED_MEM_INIT_VALUE 0xEE +#define SHARED_MEM_END_VALUE 0xAA diff --git a/components/ulp/test_apps/lp_core/lp_core_hp_uart/main/lp_core/test_shared_mem_main.c b/components/ulp/test_apps/lp_core/lp_core_hp_uart/main/lp_core/test_shared_mem_main.c new file mode 100644 index 0000000000..c37c83962c --- /dev/null +++ b/components/ulp/test_apps/lp_core/lp_core_hp_uart/main/lp_core/test_shared_mem_main.c @@ -0,0 +1,34 @@ +/* + * SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include +#include "ulp_lp_core_print.h" +#include "ulp_lp_core_memory_shared.h" +#include "test_shared.h" + +int main(void) +{ + ulp_lp_core_memory_shared_cfg_t *shared_cfg = ulp_lp_core_memory_shared_cfg_get(); + lp_core_printf("ULP shared memory address: %p\n", shared_cfg); + + volatile uint8_t* shared_mem = (uint8_t*)shared_cfg; + for (int i = 0; i < sizeof(ulp_lp_core_memory_shared_cfg_t); i++) { + if (shared_mem[i] != SHARED_MEM_INIT_VALUE) { + lp_core_printf("Test failed: expected %X, got %X at %d\n", SHARED_MEM_INIT_VALUE, shared_mem[i], i); + return 0; + } + } + + for (int i = 0; i < sizeof(ulp_lp_core_memory_shared_cfg_t); i++) { + shared_mem[i] = SHARED_MEM_END_VALUE; + } + + lp_core_printf("ULP shared memory test passed\n"); + + return 0; +} diff --git a/components/ulp/test_apps/lp_core/lp_core_hp_uart/main/test_lp_core.c b/components/ulp/test_apps/lp_core/lp_core_hp_uart/main/test_lp_core.c index bdd1e863c7..e21d52afbd 100644 --- a/components/ulp/test_apps/lp_core/lp_core_hp_uart/main/test_lp_core.c +++ b/components/ulp/test_apps/lp_core/lp_core_hp_uart/main/test_lp_core.c @@ -7,6 +7,7 @@ #include #include #include +#include #include "freertos/FreeRTOS.h" #include "freertos/task.h" #include "sdkconfig.h" @@ -15,6 +16,8 @@ #include "esp_rom_caps.h" #include "lp_core_test_app.h" #include "ulp_lp_core.h" +#include "ulp_lp_core_memory_shared.h" +#include "test_shared.h" extern const uint8_t lp_core_main_bin_start[] asm("_binary_lp_core_test_app_bin_start"); extern const uint8_t lp_core_main_bin_end[] asm("_binary_lp_core_test_app_bin_end"); @@ -22,6 +25,9 @@ extern const uint8_t lp_core_main_bin_end[] asm("_binary_lp_core_test_app_bin_ extern const uint8_t lp_core_panic_bin_start[] asm("_binary_lp_core_test_app_panic_bin_start"); extern const uint8_t lp_core_panic_bin_end[] asm("_binary_lp_core_test_app_panic_bin_end"); +extern const uint8_t lp_core_shared_mem_bin_start[] asm("_binary_lp_core_test_app_shared_mem_bin_start"); +extern const uint8_t lp_core_shared_mem_bin_end[] asm("_binary_lp_core_test_app_shared_mem_bin_end"); + static void load_and_start_lp_core_firmware(ulp_lp_core_cfg_t* cfg, const uint8_t* firmware_start, const uint8_t* firmware_end) { TEST_ASSERT(ulp_lp_core_load_binary(firmware_start, @@ -58,3 +64,32 @@ TEST_CASE("LP-Core panic", "[lp_core]") // We simply wait to allow the lp-core to run once vTaskDelay(1000 / portTICK_PERIOD_MS); } + +TEST_CASE("LP-Core Shared-mem", "[lp_core]") +{ + /* Load ULP firmware and start the coprocessor */ + ulp_lp_core_cfg_t cfg = { + .wakeup_source = ULP_LP_CORE_WAKEUP_SOURCE_HP_CPU, + }; + + TEST_ASSERT(ulp_lp_core_load_binary(lp_core_shared_mem_bin_start, (lp_core_shared_mem_bin_end - lp_core_shared_mem_bin_start)) == ESP_OK); + + printf("HP shared memory address: %p\n", ulp_lp_core_memory_shared_cfg_get()); + + volatile uint8_t* shared_mem = (uint8_t*)ulp_lp_core_memory_shared_cfg_get(); + for (int i = 0; i < sizeof(ulp_lp_core_memory_shared_cfg_t); i++) { + shared_mem[i] = SHARED_MEM_INIT_VALUE; + } + + TEST_ASSERT(ulp_lp_core_run(&cfg) == ESP_OK); + // Actual test output on UART is checked by pytest, not unity test-case + // We simply wait to allow the lp-core to run once + vTaskDelay(1000 / portTICK_PERIOD_MS); + + // Check that ULP set the shared memory to 0xAA, and it did not get overwritten by anything + for (int i = 0; i < sizeof(ulp_lp_core_memory_shared_cfg_t); i++) { + TEST_ASSERT_EQUAL(SHARED_MEM_END_VALUE, shared_mem[i]); + } + + printf("HP shared memory test passed\n"); +} diff --git a/components/ulp/test_apps/lp_core/lp_core_hp_uart/pytest_lp_core_hp_uart.py b/components/ulp/test_apps/lp_core/lp_core_hp_uart/pytest_lp_core_hp_uart.py index 974a9d108a..b21e6e3e35 100644 --- a/components/ulp/test_apps/lp_core/lp_core_hp_uart/pytest_lp_core_hp_uart.py +++ b/components/ulp/test_apps/lp_core/lp_core_hp_uart/pytest_lp_core_hp_uart.py @@ -27,3 +27,23 @@ def test_lp_core_panic(dut: Dut) -> None: dut.expect_exact("Guru Meditation Error: LP Core panic'ed Breakpoint") dut.expect_exact('Core 0 register dump:') dut.expect_exact('ELF file SHA256:') + + +@pytest.mark.esp32c5 +@pytest.mark.esp32c6 +@pytest.mark.esp32p4 +@pytest.mark.generic +def test_lp_core_shared_mem(dut: Dut) -> None: + dut.expect_exact('Press ENTER to see the list of tests') + dut.write('"LP-Core Shared-mem"') + + result = dut.expect(r'HP shared memory address: (0x[0-9a-fA-F]+)') + hp_addr = result[1] + + result = dut.expect(r'ULP shared memory address: (0x[0-9a-fA-F]+)') + ulp_addr = result[1] + + assert ulp_addr == hp_addr + + dut.expect_exact('ULP shared memory test passed') + dut.expect_exact('HP shared memory test passed')