mirror of
https://github.com/espressif/esp-idf.git
synced 2025-09-30 19:19:21 +00:00
Merge branch 'docs/update_ulp_lp_core_cn' into 'master'
docs: Update CN translation for ulp-lp-core.rst Closes DOC-8773 See merge request espressif/esp-idf!33352
This commit is contained in:
@@ -1,11 +1,11 @@
|
||||
ULP LP-Core 协处理器编程
|
||||
===================================
|
||||
ULP LP 内核协处理器编程
|
||||
=======================
|
||||
|
||||
:link_to_translation:`en:[English]`
|
||||
|
||||
ULP LP-Core(低功耗内核)协处理器是 {IDF_TARGET_NAME} 中 ULP 的一个变型。它具有超低功耗,同时还能在主 CPU 处于低功耗模式时保持运行。因此,LP-Core 协处理器能够在主 CPU 处于睡眠模式时处理 GPIO 或传感器读取等任务,从而显著降低整个系统的整体功耗。
|
||||
ULP LP 内核 (Low-power core) 协处理器是 {IDF_TARGET_NAME} 中 ULP 的一个变型。它具有超低功耗,同时还能在主 CPU 处于低功耗模式时保持运行。因此,LP 内核协处理器能够在主 CPU 处于睡眠模式时处理 GPIO 或传感器读取等任务,从而显著降低整个系统的整体功耗。
|
||||
|
||||
ULP LP-Core 协处理器具有以下功能:
|
||||
ULP LP 内核协处理器具有以下功能:
|
||||
|
||||
* RV32I 处理器(32 位 RISC-V ISA),支持乘法/除法 (M)、原子 (A) 和压缩 (C) 扩展。
|
||||
* 中断控制器。
|
||||
@@ -13,17 +13,17 @@ ULP LP-Core 协处理器具有以下功能:
|
||||
* 当整个系统处于 active 模式时,可以访问所有的高功耗 (HP) SRAM 和外设。
|
||||
* 当 HP 系统处于睡眠模式时,可以访问低功耗 (LP) SRAM 和外设。
|
||||
|
||||
编译 ULP LP-Core 代码
|
||||
----------------------------------
|
||||
编译 ULP LP 内核代码
|
||||
--------------------
|
||||
|
||||
ULP LP-Core 代码会与 ESP-IDF 项目共同编译,生成一个单独的二进制文件,并自动嵌入到主项目的二进制文件中。编译可通过以下两种方式实现:
|
||||
ULP LP 内核代码会与 ESP-IDF 项目共同编译,生成一个单独的二进制文件,并自动嵌入到主项目的二进制文件中。编译可通过以下两种方式实现:
|
||||
|
||||
使用 ``ulp_embed_binary``
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
1. 将用 C 语言或汇编语言编写的 ULP LP-Core 代码(带有 ``.S`` 扩展名)放在组件目录下的专用目录中,例如 ``ulp/``。
|
||||
1. 将用 C 语言或汇编语言编写的 ULP LP 内核代码(带有 ``.S`` 扩展名)放在组件目录下的专用目录中,例如 ``ulp/``。
|
||||
|
||||
2. 在 CMakeLists.txt 文件中注册组件后,调用 ``ulp_embed_binary`` 函数。例如:
|
||||
2. 在 ``CMakeLists.txt`` 文件中注册组件后,调用 ``ulp_embed_binary`` 函数。例如:
|
||||
|
||||
.. code-block:: cmake
|
||||
|
||||
@@ -41,7 +41,7 @@ ULP LP-Core 代码会与 ESP-IDF 项目共同编译,生成一个单独的二
|
||||
使用自定义的 CMake 项目
|
||||
~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
也可以为 LP-Core 创建自定义的 CMake 项目,从而更好地控制构建过程,并实现常规 CMake 项目的操作,例如设置编译选项、链接外部库等。
|
||||
也可以为 LP 内核创建自定义的 CMake 项目,从而更好地控制构建过程,并实现常规 CMake 项目的操作,例如设置编译选项、链接外部库等。
|
||||
|
||||
请在组件的 ``CMakeLists.txt`` 文件中将 ULP 项目添加为外部项目:
|
||||
|
||||
@@ -90,7 +90,7 @@ ULP LP-Core 代码会与 ESP-IDF 项目共同编译,生成一个单独的二
|
||||
|
||||
若想编译和构建项目,请执行以下操作:
|
||||
|
||||
1. 在 menuconfig 中启用 :ref:`CONFIG_ULP_COPROC_ENABLED` 和 :ref:`CONFIG_ULP_COPROC_TYPE` 选项,并将 :ref:`CONFIG_ULP_COPROC_TYPE` 设置为 ``CONFIG_ULP_COPROC_TYPE_LP_CORE``。:ref:`CONFIG_ULP_COPROC_RESERVE_MEM` 选项为 ULP 保留 RTC 内存,因此必须设置为一个足够大的值,以存储 ULP LP-Core 代码和数据。如果应用程序组件包含多个 ULP 程序,那么 RTC 内存的大小必须足够容纳其中最大的程序。
|
||||
1. 在 menuconfig 中启用 :ref:`CONFIG_ULP_COPROC_ENABLED` 和 :ref:`CONFIG_ULP_COPROC_TYPE` 选项,并将 :ref:`CONFIG_ULP_COPROC_TYPE` 设置为 ``CONFIG_ULP_COPROC_TYPE_LP_CORE``。:ref:`CONFIG_ULP_COPROC_RESERVE_MEM` 选项为 ULP 保留 RTC 内存,因此必须设置为一个足够大的值,以存储 ULP LP 内核代码和数据。如果应用程序组件包含多个 ULP 程序,那么 RTC 内存的大小必须足够容纳其中最大的程序。
|
||||
|
||||
2. 按照常规步骤构建应用程序(例如 ``idf.py app``)。
|
||||
|
||||
@@ -113,12 +113,12 @@ ULP LP-Core 代码会与 ESP-IDF 项目共同编译,生成一个单独的二
|
||||
|
||||
.. _ulp-lp-core-access-variables:
|
||||
|
||||
访问 ULP LP-Core 程序变量
|
||||
-------------------------------------------
|
||||
访问 ULP LP 内核程序变量
|
||||
------------------------
|
||||
|
||||
在主程序中可以使用在 ULP LP-Core 程序中定义的全局符号。
|
||||
在主程序中可以使用在 ULP LP 内核程序中定义的全局符号。
|
||||
|
||||
例如,ULP LP-Core 程序定义了一个变量 ``measurement_count``,用来表示程序从深度睡眠中唤醒芯片前所需的 GPIO 测量次数。
|
||||
例如,ULP LP 内核程序定义了一个变量 ``measurement_count``,用来表示程序从深度睡眠中唤醒芯片前所需的 GPIO 测量次数。
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
@@ -132,7 +132,7 @@ ULP LP-Core 代码会与 ESP-IDF 项目共同编译,生成一个单独的二
|
||||
...do something.
|
||||
}
|
||||
|
||||
主程序可以访问 ULP LP-Core 程序全局变量,这是因为构建系统生成了 ``${ULP_APP_NAME}.h`` 和 ``${ULP_APP_NAME}.ld`` 文件,文件中定义了 ULP LP-Core 程序中现有的的全局符号。在 ULP LP-Core 程序中定义的每个全局符号都包含在这两个文件中,并具有前缀 ``ulp_``。
|
||||
主程序可以访问 ULP LP 内核程序全局变量,这是因为构建系统生成了 ``${ULP_APP_NAME}.h`` 和 ``${ULP_APP_NAME}.ld`` 文件,文件中定义了 ULP LP 内核程序中现有的的全局符号。在 ULP LP 内核程序中定义的每个全局符号都包含在这两个文件中,并具有前缀 ``ulp_``。
|
||||
|
||||
头文件中包含符号的声明:
|
||||
|
||||
@@ -148,7 +148,7 @@ ULP LP-Core 代码会与 ESP-IDF 项目共同编译,生成一个单独的二
|
||||
|
||||
PROVIDE ( ulp_measurement_count = 0x50000060 );
|
||||
|
||||
要从主程序访问 ULP LP-Core 程序变量,应使用 ``include`` 语句将生成的头文件包含在主程序中,这样就可以像访问常规变量一样访问 ULP LP-Core 程序变量。
|
||||
要从主程序访问 ULP LP 内核程序变量,应使用 ``include`` 语句将生成的头文件包含在主程序中,这样就可以像访问常规变量一样访问 ULP LP 内核程序变量。
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
@@ -160,15 +160,15 @@ ULP LP-Core 代码会与 ESP-IDF 项目共同编译,生成一个单独的二
|
||||
|
||||
.. note::
|
||||
|
||||
LP-Core 程序全局变量存储在二进制文件的 ``.bss`` 或者 ``.data`` 部分。这些部分在加载和执行 LP-Core 二进制文件时被初始化。在首次运行 LP-Core 之前,从 HP-Core 主程序访问这些变量可能会导致未定义行为。
|
||||
LP 内核程序全局变量存储在二进制文件的 ``.bss`` 或者 ``.data`` 部分。这些部分在加载和执行 LP 内核二进制文件时被初始化。在首次运行 LP 内核之前,从 HP-Core 主程序访问这些变量可能会导致未定义行为。
|
||||
|
||||
|
||||
启动 ULP LP-Core 程序
|
||||
--------------------------------
|
||||
启动 ULP LP 内核程序
|
||||
--------------------
|
||||
|
||||
要运行 ULP LP-Core 程序,主应用程序需要先使用 :cpp:func:`ulp_lp_core_load_binary` 函数将 ULP 程序加载到 RTC 内存中,然后使用 :cpp:func:`ulp_lp_core_run` 函数进行启动。
|
||||
要运行 ULP LP 内核程序,主应用程序需要先使用 :cpp:func:`ulp_lp_core_load_binary` 函数将 ULP 程序加载到 RTC 内存中,然后使用 :cpp:func:`ulp_lp_core_run` 函数进行启动。
|
||||
|
||||
每个 ULP LP-Core 程序以二进制 blob 的形式嵌入到 ESP-IDF 应用程序中。应用程序可以按照如下方式引用和加载该 blob(假设 ULP_APP_NAME 被定义为 ``ulp_app_name``):
|
||||
每个 ULP LP 内核程序以二进制 blob 的形式嵌入到 ESP-IDF 应用程序中。应用程序可以按照如下方式引用和加载该 blob(假设 ULP_APP_NAME 被定义为 ``ulp_app_name``):
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
@@ -191,10 +191,10 @@ ULP LP-Core 代码会与 ESP-IDF 项目共同编译,生成一个单独的二
|
||||
|
||||
ESP_ERROR_CHECK( ulp_lp_core_run(&cfg) );
|
||||
|
||||
ULP LP-Core 程序流程
|
||||
------------------------
|
||||
ULP LP 内核程序流程
|
||||
-------------------
|
||||
|
||||
ULP LP-Core 协处理器如何启动取决于 :cpp:type:`ulp_lp_core_cfg_t` 中选择的唤醒源。最常见的用例是 ULP 定期唤醒,在进行一些测量后唤醒主 CPU,或者再次进入睡眠状态。
|
||||
ULP LP 内核协处理器如何启动取决于 :cpp:type:`ulp_lp_core_cfg_t` 中选择的唤醒源。最常见的用例是 ULP 定期唤醒,在进行一些测量后唤醒主 CPU,或者再次进入睡眠状态。
|
||||
|
||||
ULP 有以下唤醒源:
|
||||
* :c:macro:`ULP_LP_CORE_WAKEUP_SOURCE_HP_CPU` - LP 内核可以被 HP CPU 唤醒。
|
||||
@@ -215,10 +215,10 @@ ULP 被唤醒时会经历以下步骤:
|
||||
#. 调用 :cpp:func:`ulp_lp_core_halt`
|
||||
|
||||
|
||||
ULP LP-Core 支持的外设
|
||||
------------------------------
|
||||
ULP LP 内核支持的外设
|
||||
---------------------
|
||||
|
||||
为了增强 ULP LP-Core 协处理器的功能,它可以访问在低功耗电源域运行的外设。ULP LP-Core 协处理器可以在主 CPU 处于睡眠模式时与这些外设进行交互,并在达到唤醒条件时唤醒主 CPU。以下为支持的外设:
|
||||
为了增强 ULP LP 内核协处理器的功能,它可以访问在低功耗电源域运行的外设。ULP LP 内核协处理器可以在主 CPU 处于睡眠模式时与这些外设进行交互,并在达到唤醒条件时唤醒主 CPU。以下为支持的外设:
|
||||
|
||||
.. list::
|
||||
|
||||
@@ -229,14 +229,14 @@ ULP LP-Core 支持的外设
|
||||
|
||||
.. only:: CONFIG_ESP_ROM_HAS_LP_ROM
|
||||
|
||||
ULP LP-Core ROM
|
||||
ULP LP 内核 ROM
|
||||
---------------
|
||||
|
||||
ULP LP-Core ROM 是位于 LP-ROM 中的一小段预编译代码,用户无法修改。与主 CPU 运行的引导加载程序 ROM 代码类似,ULP LP-Core ROM 也在 ULP LP-Core 协处理器启动时执行。该 ROM 代码会初始化 ULP LP-Core 协处理器,随后跳转到用户程序。如果已初始化 LP UART,该 ROM 代码还会打印启动信息。
|
||||
ULP LP 内核 ROM 是位于 LP-ROM 中的一小段预编译代码,用户无法修改。与主 CPU 运行的引导加载程序 ROM 代码类似,ULP LP 内核 ROM 也在 ULP LP 内核协处理器启动时执行。该 ROM 代码会初始化 ULP LP 内核协处理器,随后跳转到用户程序。如果已初始化 LP UART,该 ROM 代码还会打印启动信息。
|
||||
|
||||
如果已将 :cpp:member:`ulp_lp_core_cfg_t::skip_lp_rom_boot` 设置为真,则不会执行 ULP LP-Core ROM 代码。如需尽快唤醒 ULP,同时避免初始化和信息打印产生额外开销,则可使用这一功能。
|
||||
如果已将 :cpp:member:`ulp_lp_core_cfg_t::skip_lp_rom_boot` 设置为真,则不会执行 ULP LP 内核 ROM 代码。如需尽快唤醒 ULP,同时避免初始化和信息打印产生额外开销,则可使用这一功能。
|
||||
|
||||
除上述启动代码,ULP LP-Core ROM 代码还提供以下功能和接口:
|
||||
除上述启动代码,ULP LP 内核 ROM 代码还提供以下功能和接口:
|
||||
|
||||
* :component_file:`ROM.ld 接口 <esp_rom/{IDF_TARGET_PATH_NAME}/ld/{IDF_TARGET_PATH_NAME}lp.rom.ld>`
|
||||
* :component_file:`newlib.ld 接口 <esp_rom/{IDF_TARGET_PATH_NAME}/ld/{IDF_TARGET_PATH_NAME}lp.rom.newlib.ld>`
|
||||
@@ -244,12 +244,12 @@ ULP LP-Core 支持的外设
|
||||
在任何情况下,这些函数都存在于 LP-ROM 中,因此在程序中使用这些函数可以减少 ULP 应用程序的 RAM 占用。
|
||||
|
||||
|
||||
ULP LP-Core 中断
|
||||
----------------
|
||||
ULP LP 内核中断
|
||||
---------------
|
||||
|
||||
配置 LP-Core 协处理器,可以处理各种类型的中断,例如 LP IO 低/高电平中断或是 LP 定时器中断。只需重写 IDF 提供的任何一个弱处理函数,就可以注册一个中断处理程序。所有处理程序可见 :component_file:`ulp_lp_core_interrupts.h <ulp/lp_core/lp_core/include/ulp_lp_core_interrupts.h>`。有关特定目标可使用的中断的详细信息,请参阅 **{IDF_TARGET_NAME} 技术参考手册** [`PDF <{IDF_TARGET_TRM_CN_URL}#ulp>`__]。
|
||||
配置 LP 内核协处理器,可以处理各种类型的中断,例如 LP IO 低/高电平中断或是 LP 定时器中断。只需重写 IDF 提供的任何一个弱处理函数,就可以注册一个中断处理程序。所有处理程序可见 :component_file:`ulp_lp_core_interrupts.h <ulp/lp_core/lp_core/include/ulp_lp_core_interrupts.h>`。有关特定目标可使用的中断的详细信息,请参阅 **{IDF_TARGET_NAME} 技术参考手册** [`PDF <{IDF_TARGET_TRM_CN_URL}#ulp>`__]。
|
||||
|
||||
例如,要重写 LP IO 中断的处理程序,可以在 ULP LP-Core 代码中定义以下函数:
|
||||
例如,要重写 LP IO 中断的处理程序,可以在 ULP LP 内核代码中定义以下函数:
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
@@ -260,50 +260,130 @@ ULP LP-Core 中断
|
||||
|
||||
:c:macro:`LP_CORE_ISR_ATTR` 宏用于定义中断处理函数,可确保调用中断处理程序时妥善保存并恢复寄存器。
|
||||
|
||||
除了为需要处理的中断源配置相关的中断寄存器外,还要调用 :cpp:func:`ulp_lp_core_intr_enable` 函数,在 LP-Core 中断控制器中使能全局中断。
|
||||
除了为需要处理的中断源配置相关的中断寄存器外,还要调用 :cpp:func:`ulp_lp_core_intr_enable` 函数,在 LP 内核中断控制器中使能全局中断。
|
||||
|
||||
调试 ULP LP-Core 应用程序
|
||||
-------------------------
|
||||
ULP LP 内核时钟配置
|
||||
-------------------
|
||||
|
||||
在编程 LP-Core 时,有时很难弄清楚程序未按预期运行的原因。请参考以下策略,调试 LP-Core 程序:
|
||||
{IDF_TARGET_XTAL_FREQ:default="未更新", esp32c5="48 MHz", esp32p4="40 MHz"}
|
||||
|
||||
* 使用 LP-UART 打印:LP-Core 可以访问 LP-UART 外设,在主 CPU 处于睡眠状态时独立打印信息。有关使用此驱动程序的示例,请参阅 :example:`system/ulp/lp_core/lp_uart/lp_uart_print`。
|
||||
ULP LP 内核的时钟源来自系统时钟 ``LP_FAST_CLK``,详情请参见 `技术参考手册 <{IDF_TARGET_TRM_CN_URL}>`__ > ``复位和时钟``。
|
||||
|
||||
* 通过 :ref:`CONFIG_ULP_HP_UART_CONSOLE_PRINT`,将 :cpp:func:`lp_core_printf` 路由到 HP-Core 控制台 UART,可以轻松地将 LP-Core 信息打印到已经连接的 HP-Core 控制台 UART。此方法的缺点是需要主 CPU 处于唤醒状态,并且由于 LP 核与 HP 核未同步,输出可能会交错。
|
||||
.. only:: SOC_CLK_LP_FAST_SUPPORT_XTAL
|
||||
|
||||
在 {IDF_TARGET_NAME} 上,``LP_FAST_CLK`` 支持使用外部 {IDF_TARGET_XTAL_FREQ} 晶振 (XTAL) 作为其时钟源。默认时钟源 ``RTC_FAST_CLOCK`` 的运行频率约为 20 MHz,使用外部晶振时钟后,ULP LP 内核将以更高的频率运行。缺点在于,``LP_FAST_CLK`` 在休眠期间通常会断电以减少功耗,而选择 XTAL 作为时钟源后,休眠期间时钟仍将保持通电,造成功耗增加。因此,如果仅希望在 HP 内核活动时将 LP 内核用作协处理器,则可以使用 XTAL 以提高 LP 内核的性能和频率稳定性。
|
||||
|
||||
要启用此功能,请将 :ref:`CONFIG_RTC_FAST_CLK_SRC` 设置为 ``CONFIG_RTC_FAST_CLK_SRC_XTAL``。
|
||||
|
||||
|
||||
调试 ULP LP 内核应用程序
|
||||
------------------------
|
||||
|
||||
在编程 LP 内核时,有时很难弄清楚程序未按预期运行的原因。请参考以下策略,调试 LP 内核程序:
|
||||
|
||||
* 使用 LP-UART 打印:LP 内核可以访问 LP-UART 外设,在主 CPU 处于睡眠状态时独立打印信息。有关使用此驱动程序的示例,请参阅 :example:`system/ulp/lp_core/lp_uart/lp_uart_print`。
|
||||
|
||||
* 通过 :ref:`CONFIG_ULP_HP_UART_CONSOLE_PRINT`,将 :cpp:func:`lp_core_printf` 路由到 HP-Core 控制台 UART,可以轻松地将 LP 内核信息打印到已经连接的 HP-Core 控制台 UART。此方法的缺点是需要主 CPU 处于唤醒状态,并且由于 LP 内核与 HP 内未同步,输出可能会交错。
|
||||
|
||||
* 通过共享变量共享程序状态:如 :ref:`ulp-lp-core-access-variables` 所述,主 CPU 和 ULP 内核都可以轻松访问 RTC 内存中的全局变量。若想了解 ULP 内核的运行状态,可以将状态信息从 ULP 写入变量中,并通过主 CPU 读取信息。这种方法的缺点在于它需要主 CPU 一直处于唤醒状态,而这通常很难实现。另外,若主 CPU 一直处于唤醒状态,可能会掩盖某些问题,因为部分问题只会在特定电源域断电时发生。
|
||||
|
||||
* 紧急处理程序:当检测到异常时,LP-Core 的紧急处理程序会把 LP-Core 寄存器的状态通过 LP-UART 发送出去。将 :ref:`CONFIG_ULP_PANIC_OUTPUT_ENABLE` 选项设置为 ``y``,可以启用紧急处理程序。禁用此选项将减少 LP-Core 应用程序的 LP-RAM 使用量。若想从紧急转储中解析栈回溯,可以使用 esp-idf-monitor_,例如:
|
||||
* 紧急处理程序:当检测到异常时,LP 内核的紧急处理程序会把 LP 内核寄存器的状态通过 LP-UART 发送出去。将 :ref:`CONFIG_ULP_PANIC_OUTPUT_ENABLE` 选项设置为 ``y``,可以启用紧急处理程序。禁用此选项将减少 LP 内核应用程序的 LP-RAM 使用量。若想从紧急转储中解析栈回溯,可以使用 esp-idf-monitor_,例如:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
python -m esp_idf_monitor --toolchain-prefix riscv32-esp-elf- --target {IDF_TARGET_NAME} --decode-panic backtrace PATH_TO_ULP_ELF_FILE
|
||||
|
||||
调试 ULP LP 内核应用程序:使用 GDB 和 OpenOCD
|
||||
----------------------------------------------
|
||||
|
||||
与调试 HP 内核类似,也可以用 GDB 和 OpenOCD 来调试 LP 内核上的代码,但要注意其特殊之处和限制条件。
|
||||
|
||||
调试会话
|
||||
~~~~~~~~
|
||||
|
||||
使用支持 LP 内核调试的特殊配置文件来运行 OpenOCD,然后用特殊的 ``gdbinit`` 文件运行 GDB。
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
openocd -f board/{IDF_TARGET_PATH_NAME}-lpcore-builtin.cfg
|
||||
riscv32-esp-elf-gdb -x gdbinit <path to main program ELF>
|
||||
|
||||
以下是带有内联注释的 ``gdbinit`` 文件内容,详细信息请参考下一章节。
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
# 连接到目标
|
||||
target extended-remote :3333
|
||||
# 重置芯片
|
||||
mon reset halt
|
||||
maintenance flush register-cache
|
||||
# 添加 ULP 程序的符号和调试信息
|
||||
add-symbol <ULP 程序 ELF 文件路径>
|
||||
# 设置临时硬件断点
|
||||
# 如果需要的断点数量超过硬件支持的数量
|
||||
thb main
|
||||
commands
|
||||
# 在这里设置断点
|
||||
# 此时 ULP 程序已加载到 RAM 中
|
||||
# 若无可用的硬件断点插槽,GDB 将设置软件断点
|
||||
b func1
|
||||
b func2
|
||||
b func3
|
||||
# 恢复执行
|
||||
c
|
||||
end
|
||||
# 重置后启动主程序
|
||||
c
|
||||
|
||||
LP 内核调试特性
|
||||
~~~~~~~~~~~~~~~
|
||||
|
||||
.. list::
|
||||
|
||||
#. 为了方便调试,请在 ULP 应用的 ``CMakeLists.txt`` 文件中添加 ``-O0`` 编译选项。具体操作步骤请参见 :example:`system/ulp/lp_core/debugging/`。
|
||||
:not esp32p4: #. LP 内核支持的硬件异常类型有限,例如,写入地址 `0x0` 不会像在 HP 内核上一样造成系统崩溃。启用 LP 内核应用程序的未定义行为检测器 (`ubsan`) 可以捕捉一些错误,从而在一定程度上弥补这一限制。但请注意,这将显著增加代码量,可能会导致应用程序超出 RTC RAM 的容量限制。要启用 `ubsan`,请在 ``CMakeLists.txt`` 文件中添加 ``-fsanitize=undefined -fno-sanitize=shift-base`` 编译选项。具体操作步骤请参见 :example:`system/ulp/lp_core/debugging/`。
|
||||
#. 为了调试运行在 LP 内核上的程序,需要先将调试信息和符号加载到 GDB 中。这可以通过 GDB 命令行或在 ``gdbinit`` 文件中完成。具体操作步骤请参见上文。
|
||||
#. LP 内核应用程序会在启时会加载到 RAM 中,在此之前设置的所有软件断点都会被覆盖。设置 LP 内核应用断点的最佳时机是在 LP 内核程序运行至 ``main`` 函数之时。
|
||||
#. 使用 IDE 时,可能无法配置上述 ``gdbinit`` 文件中的断点操作或命令。因此,请在调试会话开始前预设并禁用所有断点,只保留 ``main`` 函数处的断点。当程序在 ``main`` 处停止时,手动启用其余断点并恢复执行。
|
||||
|
||||
限制
|
||||
~~~~
|
||||
|
||||
#. 调试场景有限制:目前,当 HP 内核或 LP 内核进入睡眠模式时,将无法调适。
|
||||
#. 调试 内核时,OpenOCD 不支持 FreeRTOS,因此无法看到系统中正在运行的任务,但会有几个线程代表 HP 和 LP 内核:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
(gdb) info thread
|
||||
Id Target Id Frame
|
||||
1 Thread 1 "{IDF_TARGET_PATH_NAME}.cpu0" (Name: {IDF_TARGET_PATH_NAME}.cpu0, state: debug-request) 0x40803772 in esp_cpu_wait_for_intr ()
|
||||
at /home/user/projects/esp/esp-idf/components/esp_hw_support/cpu.c:64
|
||||
* 2 Thread 2 "{IDF_TARGET_PATH_NAME}.cpu1" (Name: {IDF_TARGET_PATH_NAME}.cpu1, state: breakpoint) do_things (max=1000000000)
|
||||
at /home/user/projects/esp/esp-idf/examples/system/ulp/lp_core/debugging/main/lp_core/main.c:21
|
||||
|
||||
#. 在 GDB 中设置硬件断点时,这些断点会同时应用到两个内核上,因此可用的硬件断点数量受 LP 内核支持数量({IDF_TARGET_NAME} 有 {IDF_TARGET_SOC_CPU_BREAKPOINTS_NUM} 个)所限。
|
||||
#. OpenOCD 的 flash 支持被禁用。LP 内核应用程序完全在 RAM 中运行,且 GDB 可以为其使用软件断点,因而该限制无关紧要。但若想在 HP 内核运行的代码中调用的 flash 函数(例如 `app_main`)上设置断点,则需要通过 ``hb`` 和 ``thb`` GDB 命令显式请求设置硬件断点。
|
||||
#. 由于主程序和 ULP 程序被链接为独立的二进制文件,它们可能会拥有相同名称的全局符号(如函数或变量)。若通过函数名称设置断点,则 GDB 将为所有同名函数设置断点。在调试 LP 内核时,OpenOCD 不支持 flash,因此如果上述函数位于 flash 中,可能会引发问题。此时建议通过源代码行号或函数的内存地址来设置断点。
|
||||
|
||||
应用示例
|
||||
--------
|
||||
|
||||
* :example:`system/ulp/lp_core/gpio` 展示了 ULP LP-Core 协处理器在主 CPU 深度睡眠时轮询 GPIO。
|
||||
.. list::
|
||||
|
||||
.. only:: esp32c6
|
||||
|
||||
* :example:`system/ulp/lp_core/lp_i2c` 展示了 ULP LP-Core 协处理器在主 CPU 深度睡眠时读取外部 I2C 环境光传感器 (BH1750),并在达到阈值时唤醒主 CPU。
|
||||
|
||||
* :example:`system/ulp/lp_core/lp_uart/lp_uart_echo` 展示了低功耗内核上运行的 LP UART 驱动程序如何读取并回显写入串行控制台的数据。
|
||||
|
||||
* :example:`system/ulp/lp_core/lp_uart/lp_uart_print` 展示了如何在低功耗内核上使用串口打印功能。
|
||||
|
||||
* :example:`system/ulp/lp_core/interrupt` 展示了如何在 LP 内核上注册中断处理程序,接收由主 CPU 触发的中断。
|
||||
|
||||
* :example:`system/ulp/lp_core/gpio_intr_pulse_counter` 展示了如何在主 CPU 处于 Deep-sleep 模式时,使用 GPIO 中断为脉冲计数。
|
||||
|
||||
* :example:`system/ulp/lp_core/build_system/` 演示了如何为 ULP 应用程序添加自定义的 ``CMakeLists.txt`` 文件。
|
||||
- :example:`system/ulp/lp_core/gpio` 展示了 ULP LP 内核协处理器在主 CPU 深度睡眠时轮询 GPIO。
|
||||
:esp32c6: - :example:`system/ulp/lp_core/lp_i2c` 展示了 ULP LP 内核协处理器在主 CPU 深度睡眠时读取外部 I2C 环境光传感器 (BH1750),并在达到阈值时唤醒主 CPU。
|
||||
- :example:`system/ulp/lp_core/lp_uart/lp_uart_echo` 展示了低功耗内核上运行的 LP UART 驱动程序如何读取并回显写入串行控制台的数据。
|
||||
- :example:`system/ulp/lp_core/lp_uart/lp_uart_print` 展示了如何在低功耗内核上使用串口打印功能。
|
||||
- :example:`system/ulp/lp_core/interrupt` 展示了如何在 LP 内核上注册中断处理程序,接收由主 CPU 触发的中断。
|
||||
- :example:`system/ulp/lp_core/gpio_intr_pulse_counter` 展示了如何在主 CPU 处于 Deep-sleep 模式时,使用 GPIO 中断为脉冲计数。
|
||||
- :example:`system/ulp/lp_core/build_system/` 演示了如何为 ULP 应用程序添加自定义的 ``CMakeLists.txt`` 文件。
|
||||
- :example:`system/ulp/lp_core/debugging` 演示了如何使用 GDB 和 OpenOCD 来调试运行在 LP 内核上的代码。
|
||||
|
||||
API 参考
|
||||
-------------
|
||||
--------
|
||||
|
||||
主 CPU API 参考
|
||||
~~~~~~~~~~~~~~~~~~~~~~
|
||||
~~~~~~~~~~~~~~~
|
||||
|
||||
.. include-build-file:: inc/ulp_lp_core.inc
|
||||
.. include-build-file:: inc/lp_core_i2c.inc
|
||||
@@ -320,7 +400,7 @@ API 参考
|
||||
.. include-build-file:: inc/lp_core_types.inc
|
||||
|
||||
LP 内核 API 参考
|
||||
~~~~~~~~~~~~~~~~~~~~~~
|
||||
~~~~~~~~~~~~~~~~
|
||||
|
||||
.. include-build-file:: inc/ulp_lp_core_utils.inc
|
||||
.. include-build-file:: inc/ulp_lp_core_gpio.inc
|
||||
|
Reference in New Issue
Block a user