ulp-lp-core.rst 8.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177
  1. ULP LP-Core 协处理器编程
  2. ===================================
  3. :link_to_translation:`en:[English]`
  4. ULP LP-Core(低功耗内核)协处理器是 {IDF_TARGET_NAME} 中 ULP 的一个变型。它具有超低功耗,同时还能在主 CPU 处于低功耗模式时保持运行。因此,LP-Core 协处理器能够在主 CPU 处于睡眠模式时处理 GPIO 或传感器读取等任务,从而显著降低整个系统的整体功耗。
  5. ULP LP-Core 协处理器具有以下功能:
  6. * 利用基于 RISC-V ISA 的 32 位处理器,包括标准扩展整数 (I)、乘法/除法 (M)、原子 (A) 和压缩 (C)。
  7. * 中断控制器。
  8. * 包含一个调试模块,支持通过 JTAG 进行外部调试。
  9. * 当整个系统处于 active 模式时,可以访问所有的高功耗 (HP) SRAM 和外设。
  10. * 当 HP 系统处于睡眠模式时,可以访问低功耗 (LP) SRAM 和外设。
  11. 编译 ULP LP-Core 代码
  12. ----------------------------------
  13. ULP LP-Core 代码会与 ESP-IDF 项目共同编译,生成一个单独的二进制文件,并自动嵌入到主项目的二进制文件中。编译操作如下:
  14. 1. 将用 C 语言或汇编语言编写的 ULP LP-Core 代码(带有 ``.S`` 扩展名)放在组件目录下的专用目录中,例如 ``ulp/``。
  15. 2. 在 CMakeLists.txt 文件中注册组件后,调用 ``ulp_embed_binary`` 函数。例如:
  16. idf_component_register()
  17. set(ulp_app_name ulp_${COMPONENT_NAME})
  18. set(ulp_sources "ulp/ulp_c_source_file.c" "ulp/ulp_assembly_source_file.S")
  19. set(ulp_exp_dep_srcs "ulp_c_source_file.c")
  20. ulp_embed_binary(${ulp_app_name} "${ulp_sources}" "${ulp_exp_dep_srcs}")
  21. ``ulp_embed_binary`` 的第一个参数为 ULP 二进制文件的文件名,该文件名也用于其他生成的文件,如 ELF 文件、映射文件、头文件和链接器导出文件。第二个参数为 ULP 源文件。第三个参数为组件源文件列表,用于包含要生成的头文件。要正确构建依赖关系、确保在编译这些文件前创建要生成的头文件,都需要此文件列表。有关 ULP 应用程序生成头文件的概念,请参阅本文档后续章节。
  22. 3. 在 menuconfig 中启用 :ref:`CONFIG_ULP_COPROC_ENABLED` 和 :ref:`CONFIG_ULP_COPROC_TYPE` 选项,并将后者设置为 ``CONFIG_ULP_COPROC_TYPE_LP_CORE``。:ref:`CONFIG_ULP_COPROC_RESERVE_MEM` 选项为 ULP 保留 RTC 内存,因此必须设置为一个足够大的值,以存储 ULP LP-Core 代码和数据。如果应用程序组件包含多个 ULP 程序,那么 RTC 内存的大小必须足够容纳其中最大的程序。
  23. 4. 按照常规步骤构建应用程序(例如 ``idf.py app``)。
  24. 在构建过程中,采取以下步骤来构建 ULP 程序:
  25. 1. **通过 C 编译器和汇编器运行每个源文件。** 此步骤会在组件构建目录中生成目标文件 ``.obj.c`` 或 ``.obj.S``,具体取决于处理的源文件。
  26. 2. **通过 C 预处理器运行链接器脚本模板。** 模板位于 ``components/ulp/ld`` 目录中。
  27. 3. **将对象文件链接到一个 ELF 输出文件中,** 即 ``ulp_app_name.elf``。在此阶段生成的映射文件 ``ulp_app_name.map`` 可用于调试。
  28. 4. **将 ELF 文件的内容转储到一个二进制文件中,** 即 ``ulp_app_name.bin``。此二进制文件接下来可以嵌入到应用程序中。
  29. 5. 使用 ``riscv32-esp-elf-nm`` 在 ELF 文件中 **生成全局符号列表,** 即 ``ulp_app_name.sym``。
  30. 6. **创建一个 LD 导出脚本和一个头文件,** 即 ``ulp_app_name.ld`` 和 ``ulp_app_name.h``,并在其中包含 ``ulp_app_name.sym`` 中的符号。此步骤可以通过 ``esp32ulp_mapgen.py`` 实现。
  31. 7. **将生成的二进制文件添加到要嵌入到应用程序中的二进制文件列表。**
  32. .. _ulp-lp-core-access-variables:
  33. 访问 ULP LP-Core 程序变量
  34. -------------------------------------------
  35. 在主程序中可以使用在 ULP LP-Core 程序中定义的全局符号。
  36. 例如,ULP LP-Core 程序定义了一个变量 ``measurement_count``,用来表示程序从深度睡眠中唤醒芯片前所需的 GPIO 测量次数。
  37. .. code-block:: c
  38. volatile int measurement_count;
  39. int some_function()
  40. {
  41. //读取测量次数以便后续使用。
  42. int temp = measurement_count;
  43. ...do something.
  44. }
  45. 主程序可以访问 ULP LP-Core 程序全局变量,这是因为构建系统生成了 ``${ULP_APP_NAME}.h`` 和 ``${ULP_APP_NAME}.ld`` 文件,文件中定义了 ULP LP-Core 程序中现有的的全局符号。在 ULP LP-Core 程序中定义的每个全局符号都包含在这两个文件中,并具有前缀 ``ulp_``。
  46. 头文件中包含符号的声明:
  47. .. code-block:: c
  48. extern uint32_t ulp_measurement_count;
  49. 注意,所有的符号(变量、数组、函数)都被声明为 ``uint32_t`` 类型。对于函数和数组,获取符号的地址并将其转换为合适的类型。
  50. 生成的链接器脚本文件定义了 LP_MEM 中符号的位置::
  51. PROVIDE ( ulp_measurement_count = 0x50000060 );
  52. 要从主程序访问 ULP LP-Core 程序变量,应使用 ``include`` 语句将生成的头文件包含在主程序中,这样就可以像访问常规变量一样访问 ULP LP-Core 程序变量。
  53. .. code-block:: c
  54. #include "ulp_app_name.h"
  55. void init_ulp_vars() {
  56. ulp_measurement_count = 64;
  57. }
  58. 启动 ULP LP-Core 程序
  59. --------------------------------
  60. 要运行 ULP LP-Core 程序,主应用程序需要先使用 :cpp:func:`ulp_lp_core_load_binary` 函数将 ULP 程序加载到 RTC 内存中,然后使用 :cpp:func:`ulp_lp_core_run` 函数进行启动。
  61. 每个 ULP LP-Core 程序以二进制 blob 的形式嵌入到 ESP-IDF 应用程序中。应用程序可以按照如下方式引用和加载该 blob(假设 ULP_APP_NAME 被定义为 ``ulp_app_name``):
  62. .. code-block:: c
  63. extern const uint8_t bin_start[] asm("_binary_ulp_app_name_bin_start");
  64. extern const uint8_t bin_end[] asm("_binary_ulp_app_name_bin_end");
  65. void start_ulp_program() {
  66. ESP_ERROR_CHECK( ulp_lp_core_load_binary( bin_start,
  67. (bin_end - bin_start)) );
  68. }
  69. 将程序加载到 LP 内存后,就可以调用 :cpp:func:`ulp_lp_core_run` 配置和启动应用程序:
  70. .. code-block:: c
  71. ulp_lp_core_cfg_t cfg = {
  72. .wakeup_source = ULP_LP_CORE_WAKEUP_SOURCE_LP_TIMER, // LP 内核会定期被 LP 定时器唤醒
  73. .lp_timer_sleep_duration_us = 10000,
  74. };
  75. ESP_ERROR_CHECK( ulp_lp_core_run(&cfg) );
  76. ULP LP-Core 程序流程
  77. ------------------------
  78. ULP LP-Core 协处理器如何启动取决于 :cpp:type:`ulp_lp_core_cfg_t` 中选择的唤醒源。最常见的用例是 ULP 定期唤醒,在进行一些测量后唤醒主 CPU,或者再次进入睡眠状态。
  79. ULP 有以下唤醒源:
  80. * :c:macro:`ULP_LP_CORE_WAKEUP_SOURCE_HP_CPU` - LP 内核可以被 HP CPU 唤醒。
  81. * :c:macro:`ULP_LP_CORE_WAKEUP_SOURCE_LP_TIMER` - LP 内核可以被 LP 定时器唤醒。
  82. * :c:macro:`ULP_LP_CORE_WAKEUP_SOURCE_ETM` - LP 内核可以被 ETM 事件唤醒。(暂不支持)
  83. * :c:macro:`ULP_LP_CORE_WAKEUP_SOURCE_LP_IO` - 当 LP IO 电平变化时,LP 内核会被唤醒。(暂不支持)
  84. * :c:macro:`ULP_LP_CORE_WAKEUP_SOURCE_LP_UART` - LP 内核在接收到一定数量的 UART RX 脉冲后会被唤醒。(暂不支持)
  85. ULP 被唤醒时会经历以下步骤:
  86. 1. 初始化系统功能,如中断
  87. 2. 调用用户代码 ``main()``
  88. 3. 从 ``main()`` 返回
  89. 4. 如果指定了 ``lp_timer_sleep_duration_us``,则配置下一个唤醒闹钟
  90. 5. 调用 :cpp:func:`ulp_lp_core_halt`
  91. ULP LP-Core 支持的外设
  92. ------------------------------
  93. 为了增强 ULP LP-Core 协处理器的功能,它可以访问在低功耗电源域运行的外设。ULP LP-Core 协处理器可以在主 CPU 处于睡眠模式时与这些外设进行交互,并在达到唤醒条件时唤醒主 CPU。以下为支持的外设:
  94. * LP IO
  95. * LP I2C
  96. 应用示例
  97. --------------------
  98. * 在示例 :example:`system/ulp/lp_core/gpio` 中,ULP LP-Core 协处理器在主 CPU 深度睡眠时轮询 GPIO。
  99. * 在示例 :example:`system/ulp/lp_core/lp_i2c` 中,ULP LP-Core 协处理器在主 CPU 深度睡眠时读取外部 I2C 环境光传感器 (BH1750),并在达到阈值时唤醒主 CPU。
  100. API 参考
  101. -------------
  102. 主 CPU API 参考
  103. ~~~~~~~~~~~~~~~~~~~~~~
  104. .. include-build-file:: inc/ulp_lp_core.inc
  105. .. include-build-file:: inc/lp_core_i2c.inc
  106. LP 内核 API 参考
  107. ~~~~~~~~~~~~~~~~~~~~~~
  108. .. include-build-file:: inc/ulp_lp_core_utils.inc
  109. .. include-build-file:: inc/ulp_lp_core_gpio.inc
  110. .. include-build-file:: inc/ulp_lp_core_i2c.inc