Merge branch 'docs/ulp_lp_core' into 'master'

ulp: add lp core docs

Closes IDF-5816

See merge request espressif/esp-idf!24013
This commit is contained in:
Marius Vikhammer 2023-06-07 10:43:23 +08:00
commit ccda256058
9 changed files with 228 additions and 28 deletions

View File

@ -16,21 +16,32 @@ extern "C" {
#include "hal/gpio_types.h"
#include "esp_err.h"
/**
* @brief LP Core I2C pin config parameters
*/
typedef struct {
gpio_num_t sda_io_num; // GPIO pin for SDA signal. Only GPIO#6 can be used as the SDA pin.
gpio_num_t scl_io_num; // GPIO pin for SCL signal. Only GPIO#7 can be used as the SCL pin.
bool sda_pullup_en; // SDA line enable internal pullup. Can be configured if external pullup is not used.
bool scl_pullup_en; // SCL line enable internal pullup. Can be configured if external pullup is not used.
gpio_num_t sda_io_num; /*!< GPIO pin for SDA signal. Only GPIO#6 can be used as the SDA pin. */
gpio_num_t scl_io_num; /*!< GPIO pin for SCL signal. Only GPIO#7 can be used as the SCL pin. */
bool sda_pullup_en; /*!< SDA line enable internal pullup. Can be configured if external pullup is not used. */
bool scl_pullup_en; /*!< SCL line enable internal pullup. Can be configured if external pullup is not used. */
} lp_core_i2c_pin_cfg_t;
/**
* @brief LP Core I2C timing config parameters
*/
typedef struct {
uint32_t clk_speed_hz; // LP I2C clock speed for master mode
uint32_t clk_speed_hz; /*!< LP I2C clock speed for master mode */
} lp_core_i2c_timing_cfg_t;
/**
* @brief LP Core I2C config parameters
*/
typedef struct {
lp_core_i2c_pin_cfg_t i2c_pin_cfg; // LP I2C pin configuration
lp_core_i2c_timing_cfg_t i2c_timing_cfg; // LP I2C timing configuration
soc_periph_lp_i2c_clk_src_t i2c_src_clk; // LP I2C source clock type
lp_core_i2c_pin_cfg_t i2c_pin_cfg; /*!< LP I2C pin configuration */
lp_core_i2c_timing_cfg_t i2c_timing_cfg; /*!< LP I2C timing configuration */
soc_periph_lp_i2c_clk_src_t i2c_src_clk; /*!< LP I2C source clock type */
} lp_core_i2c_cfg_t;
/* Default LP I2C GPIO settings */
@ -63,6 +74,7 @@ typedef struct {
* @brief Initialize and configure the LP I2C for use by the LP core
* Currently LP I2C can only be used in master mode
*
* @param lp_i2c_num LP I2C port number
* @param cfg Configuration parameters
* @return esp_err_t ESP_OK when successful
*

View File

@ -27,8 +27,8 @@ extern "C" {
*
*/
typedef struct {
uint32_t wakeup_source; // Wakeup source flags
uint32_t lp_timer_sleep_duration_us; // Sleep duration when ULP_LP_CORE_WAKEUP_SOURCE_LP_TIMER is specified.
uint32_t wakeup_source; /*!< Wakeup source flags */
uint32_t lp_timer_sleep_duration_us; /*!< Sleep duration when ULP_LP_CORE_WAKEUP_SOURCE_LP_TIMER is specified. Measurement unit: us */
} ulp_lp_core_cfg_t;
/**

View File

@ -21,11 +21,11 @@ extern "C" {
* @note The LP I2C must have been initialized from the HP core using the lp_core_i2c_master_init() API
* before invoking this API.
*
* @param lp_i2c_num LP I2C port number
* @param device_addr I2C device address (7-bit)
* @param data_rd Buffer to hold data to be read
* @param size Size of data to be read in bytes
* @param timeout Operation timeout in CPU cycles. Set to -1 to wait forever.
* @param lp_i2c_num LP I2C port number
* @param device_addr I2C device address (7-bit)
* @param data_rd Buffer to hold data to be read
* @param size Size of data to be read in bytes
* @param ticks_to_wait Operation timeout in CPU cycles. Set to -1 to wait forever.
*
* @return esp_err_t ESP_OK when successful
*
@ -33,7 +33,7 @@ extern "C" {
* @note the LP I2C port number is ignored at the moment.
*/
esp_err_t lp_core_i2c_master_read_from_device(i2c_port_t lp_i2c_num, uint16_t device_addr,
uint8_t *data_rs, size_t size,
uint8_t *data_rd, size_t size,
int32_t ticks_to_wait);
/**
@ -42,11 +42,11 @@ esp_err_t lp_core_i2c_master_read_from_device(i2c_port_t lp_i2c_num, uint16_t de
* @note The LP I2C must have been initialized from the HP core using the lp_core_i2c_master_init() API
* before invoking this API.
*
* @param lp_i2c_num LP I2C port number
* @param device_addr I2C device address (7-bit)
* @param data_wr Buffer which holds the data to be written
* @param size Size of data to be written in bytes
* @param timeout Operation timeout in CPU cycles. Set to -1 to wait forever.
* @param lp_i2c_num LP I2C port number
* @param device_addr I2C device address (7-bit)
* @param data_wr Buffer which holds the data to be written
* @param size Size of data to be written in bytes
* @param ticks_to_wait Operation timeout in CPU cycles. Set to -1 to wait forever.
*
* @return esp_err_t ESP_OK when successful
*
@ -63,13 +63,13 @@ esp_err_t lp_core_i2c_master_write_to_device(i2c_port_t lp_i2c_num, uint16_t dev
* @note The LP I2C must have been initialized from the HP core using the lp_core_i2c_master_init() API
* before invoking this API.
*
* @param lp_i2c_num LP I2C port number
* @param device_addr I2C device address (7-bit)
* @param data_wr Buffer which holds the data to be written
* @param write_size Size of data to be written in bytes
* @param data_rd Buffer to hold data to be read
* @param read_size Size of data to be read in bytes
* @param timeout Operation timeout in CPU cycles. Set to -1 to wait forever.
* @param lp_i2c_num LP I2C port number
* @param device_addr I2C device address (7-bit)
* @param data_wr Buffer which holds the data to be written
* @param write_size Size of data to be written in bytes
* @param data_rd Buffer to hold data to be read
* @param read_size Size of data to be read in bytes
* @param ticks_to_wait Operation timeout in CPU cycles. Set to -1 to wait forever.
*
* @return esp_err_t ESP_OK when successful
*

View File

@ -111,6 +111,8 @@ ULP_FSM_DOCS = ['api-reference/system/ulp.rst',
RISCV_COPROC_DOCS = ['api-reference/system/ulp-risc-v.rst',]
LP_CORE_DOCS = ['api-reference/system/ulp-lp-core.rst']
XTENSA_DOCS = ['api-guides/hlinterrupts.rst',
'api-reference/system/perfmon.rst']
@ -188,6 +190,7 @@ conditional_include_dict = {'SOC_BT_SUPPORTED':BT_DOCS,
'SOC_TOUCH_SENSOR_SUPPORTED':TOUCH_SENSOR_DOCS,
'SOC_ULP_FSM_SUPPORTED':ULP_FSM_DOCS,
'SOC_RISCV_COPROC_SUPPORTED':RISCV_COPROC_DOCS,
'SOC_LP_CORE_SUPPORTED':LP_CORE_DOCS,
'SOC_DIG_SIGN_SUPPORTED':['api-reference/peripherals/ds.rst'],
'SOC_HMAC_SUPPORTED':['api-reference/peripherals/hmac.rst'],
'SOC_ASYNC_MEMCPY_SUPPORTED':['api-reference/system/async_memcpy.rst'],

View File

@ -271,6 +271,11 @@ INPUT = \
$(PROJECT_PATH)/components/ulp/ulp_riscv/include/ulp_riscv.h \
$(PROJECT_PATH)/components/ulp/ulp_riscv/include/ulp_riscv_i2c.h \
$(PROJECT_PATH)/components/ulp/ulp_riscv/shared/include/ulp_riscv_lock_shared.h \
$(PROJECT_PATH)/components/ulp/lp_core/include/lp_core_i2c.h \
$(PROJECT_PATH)/components/ulp/lp_core/include/ulp_lp_core.h \
$(PROJECT_PATH)/components/ulp/lp_core/lp_core/include/ulp_lp_core_gpio.h \
$(PROJECT_PATH)/components/ulp/lp_core/lp_core/include/ulp_lp_core_i2c.h \
$(PROJECT_PATH)/components/ulp/lp_core/lp_core/include/ulp_lp_core_utils.h \
$(PROJECT_PATH)/components/usb/include/usb/usb_helpers.h \
$(PROJECT_PATH)/components/usb/include/usb/usb_host.h \
$(PROJECT_PATH)/components/usb/include/usb/usb_types_ch9.h \

View File

@ -40,6 +40,7 @@ System API
:esp32: himem
:SOC_ULP_FSM_SUPPORTED: ulp
:SOC_RISCV_COPROC_SUPPORTED: ulp-risc-v
:SOC_LP_CORE_SUPPORTED: ulp-lp-core
wdts

View File

@ -0,0 +1,177 @@
ULP LP-Core Coprocessor Programming
===================================
:link_to_translation:`zh_CN:[中文]`
The ULP LP-Core (Low-power core) coprocessor is a variant of the ULP present in {IDF_TARGET_NAME}. It features ultra-low power consumption while also being able to stay powered on while the main CPU stays in low-power modes. This enables the LP-Core coprocessor to handle tasks like GPIO or sensor readings while the main CPU is in sleep mode, resulting in significant overall power savings for the entire system.
The ULP LP-Core coprocessor has the following features:
* Utilizes a 32-bit processor based on the RISC-V ISA, encompassing the standard extensions integer (I), multiplication/division (M), atomic (A), and compressed (C).
* Interrupt controller
* Includes a debug module that supports external debugging via JTAG.
* Can access all of the High-power (HP) SRAM and peripherals when the entire system is active.
* Can access the Low-power (LP) SRAM and peripherals when the HP system is in sleep mode.
Compiling Code for the ULP LP-Core
----------------------------------
The ULP LP-Core code is compiled together with your IDF project as a separate binary and automatically embedded into the main project binary. To acheive this do the following:
1. Place the ULP LP-Core code, written in C or assembly (with the ``.S`` extension), in a dedicated directory within the component directory, such as ``ulp/``.
2. After registering the component in the CMakeLists.txt file, call the ``ulp_embed_binary`` function. Here's an example:
idf_component_register()
set(ulp_app_name ulp_${COMPONENT_NAME})
set(ulp_sources "ulp/ulp_c_source_file.c" "ulp/ulp_assembly_source_file.S")
set(ulp_exp_dep_srcs "ulp_c_source_file.c")
ulp_embed_binary(${ulp_app_name} "${ulp_sources}" "${ulp_exp_dep_srcs}")
The first argument to ``ulp_embed_binary`` specifies the ULP binary name. The name specified here will also be used by other generated artifacts such as the ELF file, map file, header file, and linker export file. The second argument specifies the ULP source files. Finally, the third argument specifies the list of component source files which include the header file to be generated. This list is needed to build the dependencies correctly and ensure that the generated header file will be created before any of these files are compiled. See the section below for the concept of generated header files for ULP applications.
3. Enable both :ref:`CONFIG_ULP_COPROC_ENABLED` and :ref:`CONFIG_ULP_COPROC_TYPE` to ``CONFIG_ULP_COPROC_TYPE_LP_CORE`` options in menuconfig. The :ref:`CONFIG_ULP_COPROC_RESERVE_MEM` option will reserve RTC memory for the ULP and must be set to a value big enough to store both the ULP LP-Core code and data. If the application components contain multiple ULP programs, then the size of the RTC memory must be sufficient to hold the largest one.
4. Build the application as usual (e.g., `idf.py app`).
During the build process, the following steps are taken to build ULP program:
1. **Run each source file through the C compiler and assembler.** This step generates the object files (.obj.c or .obj.S depending of source file processed) in the component build directory.
2. **Run the linker script template through the C preprocessor.** The template is located in ``components/ulp/ld`` directory.
3. **Link the object files into an output ELF file** (``ulp_app_name.elf``). The Map file (``ulp_app_name.map``) generated at this stage may be useful for debugging purposes.
4. **Dump the contents of the ELF file into a binary** (``ulp_app_name.bin``) which can then be embedded into the application.
5. **Generate a list of global symbols** (``ulp_app_name.sym``) in the ELF file using ``riscv32-esp-elf-nm``.
6. **Create an LD export script and a header file** (``ulp_app_name.ld`` and ``ulp_app_name.h``) containing the symbols from ``ulp_app_name.sym``. This is done using the ``esp32ulp_mapgen.py`` utility.
7. **Add the generated binary to the list of binary files** to be embedded into the application.
.. _ulp-lp-core-access-variables:
Accessing the ULP LP-Core Program Variables
-------------------------------------------
Global symbols defined in the ULP LP-Core program may be used inside the main program.
For example, the ULP LP-Core program may define a variable ``measurement_count`` which will define the number of GPIO measurements the program needs to make before waking up the chip from deep sleep.
.. code-block:: c
volatile int measurement_count;
int some_function()
{
//read the measurement count for later use.
int temp = measurement_count;
...do something.
}
The main program can access the global ULP LP-Core program variables as the build system makes this possible by generating the ``${ULP_APP_NAME}.h`` and ``${ULP_APP_NAME}.ld`` files which define the global symbols present in the ULP LP-Core program. Each global symbol defined in the ULP LP-Core program is included in these files and are prefixed with ``ulp_``.
The header file contains the declaration of the symbol:
.. code-block:: c
extern uint32_t ulp_measurement_count;
Note that all symbols (variables, arrays, functions) are declared as ``uint32_t``. For functions and arrays, take the address of the symbol and cast it to the appropriate type.
The generated linker script file defines the locations of symbols in LP_MEM::
PROVIDE ( ulp_measurement_count = 0x50000060 );
To access the ULP LP-Core program variables from the main program, the generated header file should be included using an ``include`` statement. This will allow the ULP LP-Core program variables to be accessed as regular variables.
.. code-block:: c
#include "ulp_app_name.h"
void init_ulp_vars() {
ulp_measurement_count = 64;
}
Starting the ULP LP-Core Program
--------------------------------
To run a ULP LP-Core program, the main application needs to load the ULP program into RTC memory using the :cpp:func:`ulp_lp_core_load_binary` function, and then start it using the :cpp:func:`ulp_lp_core_run` function.
Each ULP LP-Core program is embedded into the ESP-IDF application as a binary blob. The application can reference this blob and load it in the following way (supposed ULP_APP_NAME was defined to ``ulp_app_name``):
.. code-block:: c
extern const uint8_t bin_start[] asm("_binary_ulp_app_name_bin_start");
extern const uint8_t bin_end[] asm("_binary_ulp_app_name_bin_end");
void start_ulp_program() {
ESP_ERROR_CHECK( ulp_lp_core_load_binary( bin_start,
(bin_end - bin_start)) );
}
Once the program is loaded into LP memory, the application can be configured and started by calling :cpp:func:`ulp_lp_core_run`:
.. code-block:: c
ulp_lp_core_cfg_t cfg = {
.wakeup_source = ULP_LP_CORE_WAKEUP_SOURCE_LP_TIMER, // LP core will be woken up periodically by LP timer
.lp_timer_sleep_duration_us = 10000,
};
ESP_ERROR_CHECK( ulp_lp_core_run(&cfg) );
ULP LP-Core Program Flow
------------------------
How the ULP LP-Core coprocessor is started depends on the wakeup source selected in :cpp:type:`ulp_lp_core_cfg_t`. The most common use-case will be for the ULP to periodically wake-up, do some measurements before either waking up the main CPU or going back to sleep again.
The ULP has the following wake-up sources:
* :c:macro:`ULP_LP_CORE_WAKEUP_SOURCE_HP_CPU` - LP Core can be woken up by the HP CPU.
* :c:macro:`ULP_LP_CORE_WAKEUP_SOURCE_LP_TIMER` - LP Core can be woken up by the LP timer.
* :c:macro:`ULP_LP_CORE_WAKEUP_SOURCE_ETM` - LP Core can be woken up by a ETM event. (Not yet supported)
* :c:macro:`ULP_LP_CORE_WAKEUP_SOURCE_LP_IO` - LP Core can be woken up when LP IO level changes. (Not yet supported)
* :c:macro:`ULP_LP_CORE_WAKEUP_SOURCE_LP_UART` - LP Core can be woken up after receiving a certain number of UART RX pulses. (Not yet supported)
When the ULP is woken up it will go through the following steps:
1. Initialize system feature, e.g. interrupts
2. Call user code: ``main()``
3. Return from ``main()``
4. If ``lp_timer_sleep_duration_us`` is specified then configure the next wake-up alarm
5. Call :cpp:func:`ulp_lp_core_halt`
ULP LP-Core Peripheral Support
------------------------------
To enhance the capabilities of the ULP LP-Core coprocessor, it has access to peripherals which operate in the low-power domain. The ULP LP-Core coprocessor can interact with these peripherals when the main CPU is in sleep mode, and can wake up the main CPU once a wakeup condition is reached. The following peripherals are supported:
* LP IO
* LP I2C
Application Examples
--------------------
* ULP LP-Core Coprocessor polls GPIO while main CPU is in deep sleep: :example:`system/ulp/lp_core/gpio`.
* ULP LP-Core Coprocessor reads external I2C ambient light sensor (BH1750) while the main CPU is in Deep-sleep and wakes up the main CPU once a threshold is met: :example:`system/ulp/lp_core/lp_i2c`.
API Reference
-------------
Main CPU API Reference
~~~~~~~~~~~~~~~~~~~~~~
.. include-build-file:: inc/ulp_lp_core.inc
.. include-build-file:: inc/lp_core_i2c.inc
LP Core API Reference
~~~~~~~~~~~~~~~~~~~~~~
.. include-build-file:: inc/ulp_lp_core_utils.inc
.. include-build-file:: inc/ulp_lp_core_gpio.inc
.. include-build-file:: inc/ulp_lp_core_i2c.inc

View File

@ -40,6 +40,7 @@ System API
:esp32: himem
:SOC_ULP_FSM_SUPPORTED: ulp
:SOC_RISCV_COPROC_SUPPORTED: ulp-risc-v
:SOC_LP_CORE_SUPPORTED: ulp-lp-core
wdts

View File

@ -0,0 +1 @@
.. include:: ../../../en/api-reference/system/ulp-lp-core.rst