feat(ulp): support interrupts for C6/P4 LP core

Closes https://github.com/espressif/esp-idf/issues/13059
This commit is contained in:
Marius Vikhammer
2024-04-19 14:03:29 +08:00
parent 73190dd04e
commit c5a513cf49
34 changed files with 796 additions and 32 deletions

View File

@@ -0,0 +1,8 @@
# For more information about build system see
# https://docs.espressif.com/projects/esp-idf/en/latest/api-guides/build-system.html
# The following five lines of boilerplate have to be in your project's
# CMakeLists in this exact order for cmake to work correctly
cmake_minimum_required(VERSION 3.16)
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
project(interrupts)

View File

@@ -0,0 +1,19 @@
| Supported Targets | ESP32-C6 | ESP32-P4 |
| ----------------- | -------- | -------- |
# LP-Core example with interrupt triggered from HP-Core:
This example demonstrates how to program the ULP coprocessor to receive an interrupt triggered by the HP-Core
ULP program written in C can be found across `lp_core/main.c`. The build system compiles and links this program, converts it into binary format, and embeds it into the .rodata section of the ESP-IDF application.
At runtime, the application running inside the main CPU loads ULP program into the `RTC_SLOW_MEM` memory region using `ulp_lp_core_load_binary` function. The main code then configures the ULP and starts the coprocessor by using `ulp_lp_core_run`. Once the ULP program is started, it runs continuously, waiting for interrupts. The main program will periodically trigger interrupts on the LP-Core.
After triggering a certain amount of interrupts, the main core will read and print the number of interrupts received as reported by the LP-Core.
## Example output
```
LP core loaded with firmware and running successfully
Triggered 10 interrupts on the LP-Core, LP-Core received 10 interrupts
```

View File

@@ -0,0 +1,25 @@
# Register the component
idf_component_register(SRCS "lp_interrupts_main.c"
INCLUDE_DIRS ""
REQUIRES ulp)
#
# ULP support additions to component CMakeLists.txt.
#
# 1. The LP Core app name must be unique (if multiple components use LP Core).
set(ulp_app_name lp_core_${COMPONENT_NAME})
#
# 2. Specify all C files.
# Files should be placed into a separate directory (in this case, lp_core/),
# which should not be added to COMPONENT_SRCS.
set(ulp_lp_core_sources "lp_core/main.c")
#
# 3. List all the component source files which include automatically
# generated LP Core export file, ${ulp_app_name}.h:
set(ulp_exp_dep_srcs "lp_interrupts_main.c")
#
# 4. Call function to build ULP binary and embed in project using the argument
# values above.
ulp_embed_binary(${ulp_app_name} "${ulp_lp_core_sources}" "${ulp_exp_dep_srcs}")

View File

@@ -0,0 +1,30 @@
/*
* SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <stdint.h>
#include "ulp_lp_core_utils.h"
#include "ulp_lp_core_interrupts.h"
uint32_t lp_core_pmu_intr_count = 0;
/* Add LP_CORE_ISR_ATTR to ensure registers are saved and restored */
void LP_CORE_ISR_ATTR ulp_lp_core_lp_pmu_intr_handler(void)
{
ulp_lp_core_sw_intr_clear();
lp_core_pmu_intr_count++;
}
int main (void)
{
ulp_lp_core_intr_enable();
ulp_lp_core_sw_intr_enable(true);
while(1) {
/* Wait forever, handling interrupts */
asm volatile("wfi");
}
return 0;
}

View File

@@ -0,0 +1,53 @@
/*
* SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <stdio.h>
#include "esp_sleep.h"
#include "esp_err.h"
#include "lp_core_main.h"
#include "ulp_lp_core.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
extern const uint8_t lp_core_main_bin_start[] asm("_binary_lp_core_main_bin_start");
extern const uint8_t lp_core_main_bin_end[] asm("_binary_lp_core_main_bin_end");
static void lp_core_init(void)
{
/* Set LP core wakeup source as the HP CPU */
ulp_lp_core_cfg_t cfg = {
.wakeup_source = ULP_LP_CORE_WAKEUP_SOURCE_HP_CPU,
};
/* Load LP core firmware */
ESP_ERROR_CHECK(ulp_lp_core_load_binary(lp_core_main_bin_start, (lp_core_main_bin_end - lp_core_main_bin_start)));
/* Run LP core */
ESP_ERROR_CHECK(ulp_lp_core_run(&cfg));
// Give the LP core time to start up
vTaskDelay(pdMS_TO_TICKS(100));
printf("LP core loaded with firmware and running successfully\n");
}
#define INTERRUPT_COUNT 10
void app_main(void)
{
/* Load LP Core binary and start the coprocessor */
lp_core_init();
for (int i = 0; i < INTERRUPT_COUNT; i++) {
/* In addition to waking the LP source up, the HP-LP communication bit can also be used to trigger a PMU interrupt on the LP Core */
ulp_lp_core_sw_intr_trigger();
vTaskDelay(pdMS_TO_TICKS(100));
}
printf("Triggered %d interrupts on the LP-Core, LP-Core received %"PRIu32" interrupts\n", INTERRUPT_COUNT, ulp_lp_core_pmu_intr_count);
}

View File

@@ -0,0 +1,11 @@
# SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD
# SPDX-License-Identifier: CC0-1.0
import pytest
from pytest_embedded import Dut
@pytest.mark.esp32c6
@pytest.mark.esp32p4
@pytest.mark.generic
def test_lp_core_intr(dut: Dut) -> None:
dut.expect('Triggered 10 interrupts on the LP-Core, LP-Core received 10 interrupts')

View File

@@ -0,0 +1,4 @@
# Enable ULP
CONFIG_ULP_COPROC_ENABLED=y
CONFIG_ULP_COPROC_TYPE_LP_CORE=y
CONFIG_ULP_COPROC_RESERVE_MEM=4096