Files
esp-idf/examples/system/ulp/ulp_riscv/gpio_pulse_counter
Meet Patel af895be8f6 feat(ulp_riscv): Add pulse counter example code for ulp riscv
Added a pulse counter example code for ulp riscv chips. The example
works by HP core generating high frequency pulses on a GPIO, which
are counted by ULP core to find out the highest possible frequency
of pulses that can be achieved without missing any edges.
2025-09-26 15:59:07 +05:30
..

Supported Targets ESP32-S2 ESP32-S3

ULP-RISC-V pulse counter example with GPIO Polling:

This example demonstrates how to program the ULP-RISC-V coprocessor to count the number of pulses being applied on a GPIO pin, and fastest possible frequency that can be counted.

For the demonstration purpose, HP core is used to generate square wave pulses which are counted by ULP core.

ULP program written in C can be found in ulp/main.c. The build system compiles and links this program, converts it into binary format, and embeds it into the .rodata section of the ESP-IDF application.

At runtime, the application running inside the main CPU loads ULP program into the RTC_SLOW_MEM memory region using ulp_riscv_load_binary function. The main code then configures the ULP wakeup period and starts the coprocessor by using ulp_riscv_run.

After the ULP program has started, main program running on HP core starts generating pulses on a GPIO pin.

ULP program checks for the pulses by continuously polling the GPIO status to determine any state change from LOW to HIGH or vice versa to determine an edge, and increments the count to track how many number of edges have passed so far.

To speed up execution, the critical part of ULP program is written in an inline assembly format with optimization for speed and lowest possible number of instructions in loop (users can unroll a few iterations of the loop to further improve speed, but that is beyond the scope and simplicity intended for this example code, and hence not shown in assembly code)

After the pulses have been generated and edges have been counted by ULP core, HP core checks the number of edges counted and stored in ULP memory, divides it by 2, and prints on console whether the count matched as expected or missed any edges.

Hardware setup

Only one ESP devkit having ULP riscv core is needed to run this example

Pin Assignment:

The following pin assignment is used by default

ESP variant GPIO pin for Pulse Input/Output
ESP32-S2 GPIO1
ESP32-S3 GPIO1

Note: If modifying pulse GPIO to another pin, please ensure it is a valid RTC GPIO and supported for usage by ULP core. Also update assembly code in ulp/main.c to read correct register for that GPIO.

Connections:

  • No specific wire connections are required to run this example, as the same GPIO pin is used to generate and detect pulses
  • Optionally, user can connect an oscilloscope positive probe to GPIO1 and negative probe to GND pin to check the frequency of pulses that was measured by ULP core

Example output

SUCCESS case:

Start generating pulses
Stop generating pulses
Number of pulses generated by HP Core: 500000
SUCCESS: ULP core was able to count all the pulses correctly, try reducing HP_CORE_PULSE_DELAY to generate pulses faster and see if ULP core can still count the pulses at that speed.

FAILURE case:

Start generating pulses
Stop generating pulses
Number of pulses generated by HP Core: 500000
FAILURE: ULP core couldn't count all the pulses correctly, try increasing HP_CORE_PULSE_DELAY to generate slower pulses and see if ULP core can still count the pulses at that speed.