mirror of
https://github.com/espressif/esp-idf.git
synced 2026-10-01 18:50:34 +03:00
feat(ulp): Improved ULP delay API accuracy and removed floating point operations
Closes https://github.com/espressif/esp-idf/issues/17494 Closes https://github.com/espressif/esp-idf/issues/16891
This commit is contained in:
committed by
BOT
parent
329ed7ddce
commit
6fe2cf575f
@@ -53,14 +53,50 @@ static inline uint32_t ulp_lp_core_get_cpu_cycles(void)
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Makes the co-processor busy wait for a certain number of microseconds
|
||||
* @brief Check whether an mcycle-based timeout has elapsed.
|
||||
*
|
||||
* @note A timeout value of -1 means "wait forever".
|
||||
* Other values are interpreted as unsigned cycle counts.
|
||||
*
|
||||
* @param start_cycle_count Cycle counter value captured at timeout start.
|
||||
* @param cycles_to_wait Timeout in CPU cycles, or -1 to disable timeout.
|
||||
*
|
||||
* @return true if timeout elapsed, false otherwise.
|
||||
*/
|
||||
static inline bool ulp_lp_core_is_timeout_elapsed(uint32_t start_cycle_count, int32_t cycles_to_wait)
|
||||
{
|
||||
if (cycles_to_wait == -1) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return (ulp_lp_core_get_cpu_cycles() - start_cycle_count) >= (uint32_t)cycles_to_wait;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Makes the co-processor busy-wait for a certain number of microseconds.
|
||||
*
|
||||
* @note The maximum supported delay depends on the LP core clock source and frequency.
|
||||
* For values above the limits below, the computed delay may overflow and the result
|
||||
* is undefined.
|
||||
* - LP core @ 16 MHz (RC_FAST / default): us must be <= 134217727 (about 134.2 s)
|
||||
* - LP core @ 40 MHz (XTAL 40 MHz): us must be <= 53687091 (about 53.7 s)
|
||||
* - LP core @ 48 MHz (XTAL 48 MHz): us must be <= 44739242 (about 44.7 s)
|
||||
*
|
||||
* @param us Number of microseconds to busy-wait for
|
||||
*/
|
||||
void ulp_lp_core_delay_us(uint32_t us);
|
||||
|
||||
/**
|
||||
* @brief Makes the co-processor busy wait for a certain number of cycles
|
||||
* @brief Makes the co-processor busy-wait for a certain number of cycles.
|
||||
*
|
||||
* @note The maximum supported delay is 0x7FFFFFFF cycles.
|
||||
* For larger values, the behavior is undefined. Split longer delays into smaller
|
||||
* chunks if needed.
|
||||
*
|
||||
* For reference, this corresponds approximately to:
|
||||
* - LP core @ 16 MHz (RC_FAST / default): 0x7FFFFFFF cycles ≈ 134.2 s
|
||||
* - LP core @ 40 MHz (XTAL 40 MHz): 0x7FFFFFFF cycles ≈ 53.7 s
|
||||
* - LP core @ 48 MHz (XTAL 48 MHz): 0x7FFFFFFF cycles ≈ 44.7 s
|
||||
*
|
||||
* @param cycles Number of cycles to busy-wait for
|
||||
*/
|
||||
|
||||
@@ -24,19 +24,7 @@
|
||||
#endif
|
||||
|
||||
#include "esp_cpu.h"
|
||||
|
||||
/* LP_FAST_CLK is not very accurate, for now use a rough estimate */
|
||||
#if CONFIG_RTC_FAST_CLK_SRC_RC_FAST
|
||||
#define LP_CORE_CPU_FREQUENCY_HZ 16000000 // For P4 TRM says 20 MHz by default, but we tune it closer to 16 MHz
|
||||
#elif CONFIG_RTC_FAST_CLK_SRC_XTAL
|
||||
#if SOC_XTAL_SUPPORT_48M
|
||||
#define LP_CORE_CPU_FREQUENCY_HZ 48000000
|
||||
#else
|
||||
#define LP_CORE_CPU_FREQUENCY_HZ 40000000
|
||||
#endif
|
||||
#else // Default value in chip without rtc fast clock sel option
|
||||
#define LP_CORE_CPU_FREQUENCY_HZ 16000000
|
||||
#endif
|
||||
#include "ulp_lp_core_cpu_freq_shared.h"
|
||||
|
||||
static uint32_t lp_wakeup_cause = 0;
|
||||
|
||||
@@ -117,11 +105,14 @@ void ulp_lp_core_wakeup_main_processor(void)
|
||||
*/
|
||||
void ulp_lp_core_delay_us(uint32_t us)
|
||||
{
|
||||
uint32_t start = RV_READ_CSR(mcycle);
|
||||
uint32_t end = us * (LP_CORE_CPU_FREQUENCY_HZ / 1000000);
|
||||
if (us == 0) {
|
||||
return;
|
||||
}
|
||||
uint32_t start = RV_READ_CSR(mcycle) - ULP_LP_CORE_DELAY_CALL_OVERHEAD_IN_CYCLES;
|
||||
uint32_t req_delay = us * LP_CORE_CYCLES_PER_US_NUM / LP_CORE_CYCLES_PER_US_DENOM;
|
||||
|
||||
while ((RV_READ_CSR(mcycle) - start) < end) {
|
||||
/* nothing to do */
|
||||
while ((uint32_t)(RV_READ_CSR(mcycle) - start) < req_delay) {
|
||||
/* busy wait */
|
||||
}
|
||||
}
|
||||
|
||||
@@ -132,11 +123,13 @@ void ulp_lp_core_delay_us(uint32_t us)
|
||||
*/
|
||||
void ulp_lp_core_delay_cycles(uint32_t cycles)
|
||||
{
|
||||
uint32_t start = RV_READ_CSR(mcycle);
|
||||
uint32_t end = cycles;
|
||||
if (cycles <= ULP_LP_CORE_DELAY_CALL_OVERHEAD_IN_CYCLES) {
|
||||
return;
|
||||
}
|
||||
|
||||
while ((RV_READ_CSR(mcycle) - start) < end) {
|
||||
/* nothing to do */
|
||||
uint32_t start = RV_READ_CSR(mcycle) - ULP_LP_CORE_DELAY_CALL_OVERHEAD_IN_CYCLES;
|
||||
while ((uint32_t)(RV_READ_CSR(mcycle) - start) < cycles) {
|
||||
/* busy wait */
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,41 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2026 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include "sdkconfig.h"
|
||||
#include "soc/soc_caps.h"
|
||||
|
||||
/* LP_FAST_CLK is not very accurate, for now use a rough estimate */
|
||||
#if CONFIG_RTC_FAST_CLK_SRC_RC_FAST
|
||||
#define LP_CORE_CPU_FREQUENCY_HZ 16000000U /* For P4 TRM says 20 MHz by default, but we tune it closer to 16 MHz */
|
||||
#define LP_CORE_CYCLES_PER_US_NUM 16U
|
||||
#define LP_CORE_CYCLES_PER_US_DENOM 1U
|
||||
#elif CONFIG_RTC_FAST_CLK_SRC_XTAL
|
||||
#if SOC_XTAL_SUPPORT_48M
|
||||
#define LP_CORE_CPU_FREQUENCY_HZ 48000000U
|
||||
#define LP_CORE_CYCLES_PER_US_NUM 48U
|
||||
#define LP_CORE_CYCLES_PER_US_DENOM 1U
|
||||
#else
|
||||
#define LP_CORE_CPU_FREQUENCY_HZ 40000000U
|
||||
#define LP_CORE_CYCLES_PER_US_NUM 40U
|
||||
#define LP_CORE_CYCLES_PER_US_DENOM 1U
|
||||
#endif
|
||||
#else // Default value in chip without rtc fast clock sel option
|
||||
#define LP_CORE_CPU_FREQUENCY_HZ 16000000U
|
||||
#define LP_CORE_CYCLES_PER_US_NUM 16U
|
||||
#define LP_CORE_CYCLES_PER_US_DENOM 1U
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Compensation for LP core delay function overhead in CPU cycles.
|
||||
*
|
||||
* @details Estimated cycles consumed by delay loop function call and measurement
|
||||
* overhead. Derived from empirical "LP core delay calibration" test measurements.
|
||||
* Used by delay functions to improve accuracy for short durations.
|
||||
*
|
||||
* @note Value is calibration-specific and may vary with compiler optimization.
|
||||
*/
|
||||
#define ULP_LP_CORE_DELAY_CALL_OVERHEAD_IN_CYCLES 11U
|
||||
Reference in New Issue
Block a user