Merge branch 'feature/s3_ulp_fsm' into 'master'

ulp-fsm: support ulp-fsm example on S3

See merge request espressif/esp-idf!18473
This commit is contained in:
Marius Vikhammer
2022-06-16 10:30:42 +08:00
4 changed files with 25 additions and 11 deletions

View File

@@ -72,7 +72,7 @@ def test_deep_sleep(dut: Dut) -> None:
CONFIGS_S2_S3 = [
pytest.param('basic', marks=[pytest.mark.esp32s2, pytest.mark.esp32s3]), # S2/S3 runner on isolated runners for now, IDF-XX
pytest.param('basic', marks=[pytest.mark.esp32s2, pytest.mark.esp32s3]), # S2/S3 runner on isolated runners for now, IDF-5213
]

View File

@@ -1,19 +1,19 @@
| Supported Targets | ESP32 | ESP32-S2 |
| ----------------- | ----- | -------- |
| Supported Targets | ESP32 | ESP32-S2 | ESP32-S3 |
| ----------------- | ----- | -------- | -------- |
# ULP Pulse Counting Example
This example demonstrates how to program the ULP FSM coprocessor to count pulses on an IO while the main CPUs are either running some other code or are in deep sleep. See the README.md file in the upper level 'examples' directory for more information about examples.
ULP program written in assembly can be found across `ulp/pulse_cnt.S` and `ulp/wake_up.S` (demonstrating multiple ULP source files). The build system assembles and links this program, converts it into binary format, and embeds it into the .rodata section of the ESP-IDF application.
At runtime, the main code running on the ESP32 (found in main.c) loads ULP program into the `RTC_SLOW_MEM` memory region using `ulp_load_binary` function. Main code configures the ULP program by setting up values of some variables and then starts it using `ulp_run`. Once the ULP program is started, it runs periodically, with the period set by the main program. The main program enables ULP wakeup source and puts the chip into deep sleep mode.
At runtime, the main code running on the ESP (found in main.c) loads ULP program into the `RTC_SLOW_MEM` memory region using `ulp_load_binary` function. Main code configures the ULP program by setting up values of some variables and then starts it using `ulp_run`. Once the ULP program is started, it runs periodically, with the period set by the main program. The main program enables ULP wakeup source and puts the chip into deep sleep mode.
When the ULP program finds an edge in the input signal, it performs debouncing and increments the variable maintaining the total edge count. Once the edge count reaches certain value (set by the main program), ULP triggers wake up from deep sleep. Note that the ULP program keeps running and monitoring the input signal even when the SoC is woken up.
Upon wakeup, the main program saves total edge count into NVS and returns to deep sleep.
In this example the input signal is connected to GPIO0. Note that this pin was chosen because most development boards have a button connected to it, so the pulses to be counted can be generated by pressing the button. For real world applications this is not a good choice of a pin, because GPIO0 also acts as a bootstrapping pin. To change the pin number, check the ESP32 Chip Pin List document and adjust `gpio_num` and `ulp_io_number` variables in main.c.
In this example the input signal is connected to GPIO0. Note that this pin was chosen because most development boards have a button connected to it, so the pulses to be counted can be generated by pressing the button. For real world applications this is not a good choice of a pin, because GPIO0 also acts as a bootstrapping pin. To change the pin number, check the ESP Chip Pin List document and adjust `gpio_num` and `ulp_io_number` variables in main.c.
In this example, the `CONFIG_BOOTLOADER_SKIP_VALIDATE_IN_DEEP_SLEEP` Kconfig option is used, which allows you to reduce the boot time of the bootloader during waking up from deep sleep. The bootloader stores in rtc memory the address of a running partition and uses it when it wakes up. This example allows you to skip all image checks and speed up the boot.
@@ -50,8 +50,8 @@ Entering deep sleep
Note that in one case the pulse count captured by the ULP program is 6, even though the `edge_count_to_wake_up` variable is set to 10 by the main program. This shows that the ULP program keeps track of pulses while the main CPUs are starting up, so when pulses are sent rapidly it is possible to register more pulses between wake up and entry into app_main.
With the default configuration (20ms ULP wakeup period), average current consumption in deep sleep mode is 16uA.
With the default configuration (20ms ULP wakeup period), average current consumption in deep sleep mode on ESP32 is 16uA.
## Typical current consumption
## Typical current consumption on ESP32
![CurrentConsumption](image/ulp_power_graph.png)

View File

@@ -80,6 +80,9 @@ entry:
#if CONFIG_IDF_TARGET_ESP32S2
/* ESP32S2 powers down RTC periph when entering deep sleep and thus by association SENS_SAR_IO_MUX_CONF_REG */
WRITE_RTC_FIELD(SENS_SAR_IO_MUX_CONF_REG, SENS_IOMUX_CLK_GATE_EN, 1)
#elif CONFIG_IDF_TARGET_ESP32S3
/* ESP32S3 powers down RTC periph when entering deep sleep and thus by association SENS_SAR_PERI_CLK_GATE_CONF_REG */
WRITE_RTC_FIELD(SENS_SAR_PERI_CLK_GATE_CONF_REG, SENS_IOMUX_CLK_EN, 1);
#endif
/* Lower 16 IOs and higher need to be handled separately,

View File

@@ -8,9 +8,7 @@ import pytest
from pytest_embedded import Dut
@pytest.mark.esp32
@pytest.mark.generic
def test_ulp_fsm(dut: Dut) -> None:
def ulp_fsm_test_function(dut: Dut) -> None:
dut.expect_exact('Not ULP wakeup')
dut.expect_exact('Entering deep sleep')
@@ -41,3 +39,16 @@ def test_ulp_fsm(dut: Dut) -> None:
nvs_value = new_count
logging.info('Pulse count written to NVS: {}. Entering deep sleep...'.format(nvs_value))
dut.expect_exact('Entering deep sleep', timeout=5)
@pytest.mark.esp32
@pytest.mark.generic
def test_ulp_fsm(dut: Dut) -> None:
ulp_fsm_test_function(dut)
@pytest.mark.esp32s2
@pytest.mark.esp32s3
@pytest.mark.deepsleep_temp_tag # S2/S3 runner on isolated runners for now, IDF-5213
def test_ulp_fsm_s2_s3(dut: Dut) -> None:
ulp_fsm_test_function(dut)