Use the target RC_FAST approximation for LP core delay conversion.
This prevents ESP32-S31 from under-delaying when running from RC_FAST.
Co-authored-by: Cursor <cursoragent@cursor.com>
Reset the LP SPI peripheral and GPIOs before and after every SPI case so
each test starts from a known-clean baseline, and gate the master on an
explicit slave-armed handshake so the master cannot clock the bus while
the slave is still in its arm prologue. Verify received data against the
expected pattern with bounded waits instead of merely logging it.
Add a dedicated LP SPI multi-device pytest for esp32p4 that runs the
retagged lp_core_spi cases, and tag the LP I2C case accordingly.
The LP SPI driver read and wrote the W0..W15 data buffer registers a
whole 32-bit word at a time, which overran the caller's buffer for
transfers whose length was not a multiple of four bytes and corrupted
the received data. Read and write the data buffer byte-granularly so
sub-word transfers no longer alias adjacent bytes.
The master transfer also programmed the shared bit-length register from
tx_length alone, truncating receive-longer-than-transmit transactions,
and always enabled MOSI even on read-only transfers, clocking out stale
buffer contents. Size each hardware transaction by max(tx_length,
rx_length) and gate MOSI/MISO on the corresponding buffer.
The slave path reused the master's single-shot flow, so it re-triggered
reg_update after preload (clocking out the previous transaction's data)
and offered no way for the caller to publish readiness before the master
started the clock. Split the slave transfer into an arm step that
preloads the buffer and starts the user phase, and a wait step that
blocks on TRANS_DONE and drains only the bytes the master actually
clocked in, tracked in software since reg_usr is not a reliable busy
indicator in slave mode.
Set the LP IO direction for the SPI pads, add
lp_core_lp_spi_bus_deinit() to release the LP GPIO pins, and reset the
LP SPI peripheral at bus initialization so a stale configuration from a
previous run cannot leak into the next.
The multi-device LP UART tests were failing on esp32p4 due to several
issues in the test harness:
- LP ROM boot banner: On chips with LP ROM (esp32p4), the LP core emits
a ROM banner on LP UART during startup, corrupting the first bytes of
test data. Set skip_lp_rom_boot=true in the ULP config for write, read
and mismatch tests to suppress this.
- Stale FIFO data: The HP UART RX FIFO could accumulate garbage during
pin mux setup. Add uart_flush_input() after HP UART driver installation
and before each read phase. Call lp_core_uart_clear_buf() before LP-side
read tests to flush the LP UART RX FIFO as well.
- Missing synchronization: The HP reader could start listening before
the LP transmitter was ready (or vice versa), causing data loss at
higher baud rates. Add signal exchange (unity_send_signal /
unity_wait_for_signal) to coordinate LP-to-HP data transfers.
- Short read timeout: The uart_read_bytes() timeout of 10 ms was too
aggressive for slower baud rates. Increase to 100 ms.
Made-with: Cursor
Several LP core pytest files were either hardcoded to specific chip lists
or using a less-precise SOC capability filter:
- test_lp_core_multi_device: was locked to ['esp32c6'] pending a workaround
for LP I2C on esp32p4; all three active LP core chips now have
SOC_LP_I2C_SUPPORTED=1, so switch to soc_filtered_targets.
- test_lp_uart_wakeup_modes: was using SOC_LP_CORE_SUPPORTED which is
semantically wrong for a UART test; change to SOC_ULP_LP_UART_SUPPORTED.
- LP core example pytests (build_system, interrupt, gpio_intr_pulse_counter,
lp_timer_interrupt): replace hardcoded ['esp32c5', 'esp32c6', 'esp32p4']
with soc_filtered_targets('SOC_LP_CORE_SUPPORTED == 1') so that new
chips automatically get coverage when their SOC cap is enabled.
Refactor the LP UART multi-device tests to use a single parameterised
helper pair (test_lp_uart_write_cfg / test_lp_uart_read_cfg) instead of
one-off functions per config, and extend coverage to:
- write and read tests for 5-, 6-, 7-bit and even-parity configurations
- negative tests: word-length mismatch (FRAM_ERR recovery on LP side,
garbled receive on HP side)
- LP GPIO Matrix routing tests (SOC_LP_GPIO_MATRIX_SUPPORTED chips only):
swaps the default TX/RX GPIO numbers so both pins go through the LP GPIO
Matrix, covering the lp_gpio_connect_in/out_signal() branch of
lp_uart_config_io() that was previously untested at the data-transfer
level; the same physical cross-wiring as all other LP UART tests is reused
Add rtc_gpio_deinit() cleanup at the end of single-board LP UART tests
so configured pins are returned to HP/digital mode and do not interfere
with subsequent tests that may reuse the same GPIOs.
lp_core_uart_set_pin() unconditionally configured the RTS and CTS GPIO
pins even when flow control was disabled. Only configure the RTS pin
when UART_HW_FLOWCTRL_RTS is set, and the CTS pin when
UART_HW_FLOWCTRL_CTS is set.
Use dual-path macros: C keeps fragment-style designated initializers;
C++ uses GNU statement expressions (ESP_LOG_CONFIG_INIT pattern).
Add compile-only C++ regression tests for LP UART/I2C and ULP RISC-V I2C.
Closes https://github.com/espressif/esp-idf/issues/18369
Co-authored-by: Cursor <cursoragent@cursor.com>
This allows rtc_gpio_deinit to always switch the pad back to GPIO,
regardless of lp io clock enabled or not, so that gpio_config can
always switch the IO back to GPIO use after wakeup from deep sleep.
The test was passing without real I2C communication due to a GPIO
mismatch (slave on GPIO 6/7 vs RTC I2C master on GPIO 2/3), single-byte
zero-coincidence, unchecked ULP return values, and an insufficient
RTC I2C timeout.
Fix slave GPIOs, increase test length, check I2C return values, add
proper assertions, and set an adequate RTC I2C timeout.
Co-authored-by: Cursor <cursoragent@cursor.com>
On SOC_LP_GPIO_MATRIX_SUPPORTED targets, route LP SPI, I2C, and remapped
LP UART pins through lp_gpio_connect_* (rtcio_hal_matrix_* on release
branches applies IOMUX and matrix routing).
Remove redundant rtc_gpio_set_direction and rtc_gpio_iomux_func_sel
before matrix connect for LP SPI and remapped LP UART pins.
Non-matrix LP I2C: use rtc_gpio_iomux_output instead of
rtc_gpio_iomux_func_sel. Non-matrix LP UART: use rtc_gpio_iomux_output
and rtc_gpio_iomux_input for func sel and direction.
When ulp_lp_core_wakeup_main_processor() is called, it sets the
PMU_SW_INT_RAW bit on the HP side. The normal sleep path clears this
bit before re-entering sleep, but esp_wake_stub_sleep() did not, leaving
the wakeup cause sticky. This caused the PMU to immediately re-trigger a
wakeup as soon as sleep was requested from the wake stub, producing a
rapid re-wakeup loop that eventually triggered LP_WDT_SYS resets.
Add a test case that verifies the wake stub can return to sleep correctly
across multiple LP core wakeup cycles without the re-wakeup bug.
Closing https://github.com/espressif/esp-idf/issues/18308
Made-with: Cursor
The existing spinlock mechanism possibly has an overlap of memory
operations during multi core execution, as visible in CI testing. When
running the example inter_cpu_critical_section, shared count increment
stops at 299999 instead of reaching 300000, but this only happens
randomly 1 out of 10 times. It is suspected that a memory operation
happens simultaneously from both core, even though spinlock protection
is in place.
To handle this problem, a memory barrier (fence instruction) is added
at critical places during spinlock acquire and release, to ensure that
all memory operations upto that point are completed and synchronised
before proceeding further.
This commit sets the calibration parameters for a a given LP ADC unit
and channel to improve the raw LP ADC reading when read from the LP
core. The calibration params are set from the HP core.