From eaaeed2236e18dec7e1f857e2b72fc7110e9a1a7 Mon Sep 17 00:00:00 2001 From: Eren Terzioglu Date: Wed, 30 Jul 2025 17:35:59 +0200 Subject: [PATCH] Docs/risc-v/esp32c6: Add lpcore docs Add lpcore board docs for esp32c6 Signed-off-by: Eren Terzioglu --- .../esp32c6/boards/esp32c6-devkitc/index.rst | 38 ++++ .../boards/esp32c6-devkitc/ulp_blink.bin | Bin 0 -> 4096 bytes .../platforms/risc-v/esp32c6/index.rst | 178 +++++++++++++++++- 3 files changed, 215 insertions(+), 1 deletion(-) create mode 100755 Documentation/platforms/risc-v/esp32c6/boards/esp32c6-devkitc/ulp_blink.bin diff --git a/Documentation/platforms/risc-v/esp32c6/boards/esp32c6-devkitc/index.rst b/Documentation/platforms/risc-v/esp32c6/boards/esp32c6-devkitc/index.rst index 4d458ccf69f..38fcc81a4c3 100644 --- a/Documentation/platforms/risc-v/esp32c6/boards/esp32c6-devkitc/index.rst +++ b/Documentation/platforms/risc-v/esp32c6/boards/esp32c6-devkitc/index.rst @@ -538,6 +538,44 @@ and running the ``can`` example:: SJW: 3 ID: 1 DLC: 1 +ulp +--- + +This configuration enables the support for the ULP LP core (Low-power core) coprocessor. +To get more information about LP Core please check :ref:`ULP LP Core Coprocessor docs. ` + +Configuration uses a pre-built binary in ``Documentation/platforms/risc-v/esp32c6/boards/esp32c6-devkitc/ulp_blink.bin`` +which is a blink example for GPIO0. After flashing operation, GPIO0 pin will blink. + +Prebuild binary runs this code: + +.. code-block:: C + + #include + #include + #include "ulp_lp_core_gpio.h" + + #define GPIO_PIN 0 + + #define nop() __asm__ __volatile__ ("nop") + + bool gpio_level_previous = true; + + int main (void) + { + while (1) + { + ulp_lp_core_gpio_set_level(GPIO_PIN, gpio_level_previous); + gpio_level_previous = !gpio_level_previous; + for (int i = 0; i < 10000; i++) + { + nop(); + } + } + + return 0; + } + usbconsole ---------- diff --git a/Documentation/platforms/risc-v/esp32c6/boards/esp32c6-devkitc/ulp_blink.bin b/Documentation/platforms/risc-v/esp32c6/boards/esp32c6-devkitc/ulp_blink.bin new file mode 100755 index 0000000000000000000000000000000000000000..f2817d108119752d93fb205dd35f0f943683e631 GIT binary patch literal 4096 zcmeH_Z)h839LIl`O&P3|0>p-T{3ScANY7JsVu zpDce8`09hxr9>n~keA|Ek1aTIli0kipg{1VI4I2%PnqDI+e8p7N%EheXJG!3zG!l5yv_b5n;-11#f zpPhUAE|VCb?O#k^%gGF8PEta}m+nwu^gapZ>yl&}a{#xji9FQ?siGb`JDpW!M=KUm zXS`N-!7RqWTHcQqThXbrZuRp4j>>{tOjY%)uU~Y4l@J*xr@M;#8I!Gym5^9K_jNm7uDkh9b>mTdC*8v-8qD9& zcHO1O443)UPGtT%=Tfx&?|1sEQR;1;$msho@9W=PUgq0}2`g5LhStsB(k8aVTOjNx zo>8f??bGLGo23wl`ImxggG)m4N=$oQn9au*k`}Aw;euyxTNv?I{l4I8aR0BsNy75c z_F+;?Xp@p{iiB(VzFud6vt)q{^ySl9CvaajMOk_ku;*L5ox6Jk{CulTa;mMD2()QW zZyo=b${k*3im#R4D67*K5U%(pLFFK-zQGDlnI9Xh%fo1mquri^$tS0X zOxJ(z_tB}iZz6TrGbi|bRo_VOcCYE&+&MO~8u1NO2Sx_B2dTcReU9MGpctx!#`>H6 z)cLFD9T#q15HHp)jtw=34qTdmZWn-Jg7C`#E?w)pu?z uname -a NuttX 12.8.0 759d37b97c-dirty Mar 5 2025 19:42:41 risc-v esp32c6-devkitc +.. _esp32c6_debug: + Debugging ========= @@ -200,7 +202,7 @@ USB-to-JTAG adapter. OpenOCD can then be used:: - openocd -s -c 'set ESP_RTOS hwthread' -f board/esp32c3-builtin.cfg -c 'init; reset halt; esp appimage_offset 0x0' + openocd -s -c 'set ESP_RTOS hwthread' -f board/esp32c6-builtin.cfg -c 'init; reset halt; esp appimage_offset 0x0' .. note:: - ``appimage_offset`` should be set to ``0x0`` when ``Simple Boot`` is used. For MCUboot, this value should be set to @@ -594,6 +596,180 @@ For MCUBoot operation: - The **Scratch Partition** is used by MCUBoot for image swapping during updates - MCUBoot manages image validation, confirmation, and rollback functionality +.. _esp32c6_ulp: + +ULP LP Core Coprocessor +======================= + +The ULP LP core (Low-power core) is a 32-bit RISC-V coprocessor integrated into the ESP32-C6 SoC. +It is designed to run independently of the main high-performance (HP) core and is capable of executing lightweight tasks +such as GPIO polling, simple peripheral control and I/O interactions. + +This coprocessor benefits to offload simple tasks from HP core (e.g., GPIO polling , I2C operations, basic control logic) and +frees the main CPU for higher-level processing + +For more information about ULP LP Core Coprocessor `check here `__. + +Features of the ULP LP-Core +--------------------------- + +* Processor Architecture + - RV32I RISC-V core with IMAC extensions—Integer (I), Multiplication/Division (M), Atomic (A), and Compressed (C) instructions + - Runs at 20 MHz +* Memory + - Access to 16 KB of low-power memory (LP-RAM) and LP-domain peripherals any time + - Full access to all of the chip's memory and peripherals when when the HP core is active +* Debugging + - Built-in JTAG debug module for external debugging + - Supports LP UART for logging from the ULP itself + - Includes a panic handler capable of dumping register state via LP UART on exceptions +* Peripheral support + - LP domain peripherals (LP GPIO, LP I2C, LP UART and LP Timer) + - Full access HP domain peripherals when when the HP core is active + +Loading Binary into ULP LP-Core +------------------------------- + +There are two ways to load a binary into LP-Core: + - Using a prebuilt binary + - Using NuttX internal build system to build your own (bare-metal) application + +When using a prebuilt binary, the already compiled output for the ULP system whether built from NuttX +or the ESP-IDF environment can be leveraged. However, whenever the ULP code needs to be modified, it must be rebuilt separately, +and the resulting .bin file has to be integrated into NuttX. This workflow, while compatible, can become tedious. + +With NuttX internal build system, the ULP binary code can be built and flashed from a single location. It is more convenient but +using build system has some dependencies on example side. + +Both methods requires `CONFIG_ESPRESSIF_USE_LP_CORE` variable to enable ULP core and +`CONFIG_ESPRESSIF_ULP_PROJECT_PATH` variable to set the path to the ULP project or prebuilt binary file +relative to NuttX root folder. +These variables can be set using `make menuconfig` or `kconfig-tweak` commands. + +Here is an example for enabling ULP and using a prebuilt binary for ULP core:: + + make distclean + ./tools/configure.sh esp32c6-devkitc:nsh + kconfig-tweak -e CONFIG_ESPRESSIF_USE_LP_CORE + kconfig-tweak --set-str CONFIG_ESPRESSIF_ULP_PROJECT_PATH "Documentation/platforms/risc-v/esp32c6/boards/esp32c6-devkitc/ulp_blink.bin" + make olddefconfig + make -j + +Creating an ULP LP-Core Application +----------------------------------- + +To use NuttX's internal build system to compile the bare-metal LP binary, check the following instructions. + +First, create a folder for the ULP source and header files. This folder is just for ULP project and it is +an independent project. Therefore, the NuttX example guide should not be followed, and no Makefile or similar +build files should be added. Also folder location could be anywhere. To include ULP folder into build +system don't forget to set `CONFIG_ESPRESSIF_ULP_PROJECT_PATH` variable with path of the ULP project folder relative to +NuttX root folder. Instructions for setting up can be found above. + +NuttX's internal functions or POSIX calls are not supported. + +Here is an example: + +- ULP UART Snippet: + +.. code-block:: C + + #include + #include "ulp_lp_core_print.h" + #include "ulp_lp_core_utils.h" + #include "ulp_lp_core_uart.h" + #include "ulp_lp_core_gpio.h" + + #define nop() __asm__ __volatile__ ("nop") + + int main (void) + { + while(1) + { + + lp_core_printf("Hello from the LP core!!\r\n"); + for (int i = 0; i < 10000; i++) + { + nop(); + } + } + + return 0; + } + +For more information about ULP Core Coprocessor examples `check here `__. +After these settings follow the same steps as for any other configuration to build NuttX. Build system checks ULP project path, +adds every source and header file into project and builds it. + +To sum up, here is an complete example. `ulp_example/ulp (../ulp_example/ulp)` folder selected as example +to create a subfolder for ULP but folder that includes ULP source code can be anywhere: + +- Tree view: + +.. code-block:: text + + nuttxspace/ + ├── nuttx/ + └── apps/ + └── ulp_example/ + └── ulp/ + └── ulp_main.c + +- Contents in ulp_main.c: + +.. code-block:: C + + #include + #include + #include "ulp_lp_core_gpio.h" + + #define GPIO_PIN 0 + + #define nop() __asm__ __volatile__ ("nop") + + bool gpio_level_previous = true; + + int main (void) + { + while (1) + { + ulp_lp_core_gpio_set_level(GPIO_PIN, gpio_level_previous); + gpio_level_previous = !gpio_level_previous; + for (int i = 0; i < 10000; i++) + { + nop(); + } + } + + return 0; + } + +- Command to build:: + + make distclean + ./tools/configure.sh esp32c6-devkitc:nsh + kconfig-tweak -e CONFIG_ESPRESSIF_GPIO_IRQ + kconfig-tweak -e CONFIG_DEV_GPIO + kconfig-tweak -e CONFIG_ESPRESSIF_USE_LP_CORE + kconfig-tweak --set-str CONFIG_ESPRESSIF_ULP_PROJECT_PATH "../ulp_example/ulp" + make olddefconfig + make -j + +Debugging ULP LP-Core +--------------------- + +To debug ULP LP-Core please first refer to :ref:`Debugging section. ` +Debugging ULP core consist same steps with some small differences. First of all, configuration file +needs to be changed from `board/esp32c6-builtin.cfg` or `board/esp32c6-ftdi.cfg` to +`board/esp32c6-lpcore-builtin.cfg` or `board/esp32c6-lpcore-ftdi.cfg` depending on preferred debug adapter. + +LP core supports limited set of HW exceptions, so, for example, writing at address +0x0 will not cause a panic as it would be for the code running on HP core. +This can be overcome to some extent by enabling undefined behavior sanitizer for LP core application, +so ubsan can help to catch some errors. But note that it will increase code size significantly and +it can happen that application won't fit into RTC RAM. +To enable ubsan for ULP please add `CONFIG_ESPRESSIF_ULP_ENABLE_UBSAN` in menuconfig. + _`Managing esptool on virtual environment` ==========================================