Merge branch 'refactor/gptimer_software_capture' into 'master'

split gptimer software capture in hal driver

See merge request espressif/esp-idf!19749
This commit is contained in:
morris 2022-08-26 13:25:25 +08:00
commit 060f3a3b13
16 changed files with 171 additions and 190 deletions

View File

@ -63,7 +63,7 @@ esp_err_t timer_get_counter_value(timer_group_t group_num, timer_idx_t timer_num
ESP_RETURN_ON_FALSE(timer_val != NULL, ESP_ERR_INVALID_ARG, TIMER_TAG, TIMER_PARAM_ADDR_ERROR); ESP_RETURN_ON_FALSE(timer_val != NULL, ESP_ERR_INVALID_ARG, TIMER_TAG, TIMER_PARAM_ADDR_ERROR);
ESP_RETURN_ON_FALSE(p_timer_obj[group_num][timer_num] != NULL, ESP_ERR_INVALID_ARG, TIMER_TAG, TIMER_NEVER_INIT_ERROR); ESP_RETURN_ON_FALSE(p_timer_obj[group_num][timer_num] != NULL, ESP_ERR_INVALID_ARG, TIMER_TAG, TIMER_NEVER_INIT_ERROR);
TIMER_ENTER_CRITICAL(&timer_spinlock[group_num]); TIMER_ENTER_CRITICAL(&timer_spinlock[group_num]);
*timer_val = timer_ll_get_counter_value(p_timer_obj[group_num][timer_num]->hal.dev, timer_num); *timer_val = timer_hal_capture_and_get_counter_value(&p_timer_obj[group_num][timer_num]->hal);
TIMER_EXIT_CRITICAL(&timer_spinlock[group_num]); TIMER_EXIT_CRITICAL(&timer_spinlock[group_num]);
return ESP_OK; return ESP_OK;
} }
@ -74,7 +74,7 @@ esp_err_t timer_get_counter_time_sec(timer_group_t group_num, timer_idx_t timer_
ESP_RETURN_ON_FALSE(timer_num < TIMER_MAX, ESP_ERR_INVALID_ARG, TIMER_TAG, TIMER_NUM_ERROR); ESP_RETURN_ON_FALSE(timer_num < TIMER_MAX, ESP_ERR_INVALID_ARG, TIMER_TAG, TIMER_NUM_ERROR);
ESP_RETURN_ON_FALSE(time != NULL, ESP_ERR_INVALID_ARG, TIMER_TAG, TIMER_PARAM_ADDR_ERROR); ESP_RETURN_ON_FALSE(time != NULL, ESP_ERR_INVALID_ARG, TIMER_TAG, TIMER_PARAM_ADDR_ERROR);
ESP_RETURN_ON_FALSE(p_timer_obj[group_num][timer_num] != NULL, ESP_ERR_INVALID_ARG, TIMER_TAG, TIMER_NEVER_INIT_ERROR); ESP_RETURN_ON_FALSE(p_timer_obj[group_num][timer_num] != NULL, ESP_ERR_INVALID_ARG, TIMER_TAG, TIMER_NEVER_INIT_ERROR);
uint64_t timer_val = timer_ll_get_counter_value(p_timer_obj[group_num][timer_num]->hal.dev, timer_num); uint64_t timer_val = timer_hal_capture_and_get_counter_value(&p_timer_obj[group_num][timer_num]->hal);
uint32_t div = p_timer_obj[group_num][timer_num]->divider; uint32_t div = p_timer_obj[group_num][timer_num]->divider;
// [clk_tree] TODO: replace the following switch table by clk_tree API // [clk_tree] TODO: replace the following switch table by clk_tree API
switch (p_timer_obj[group_num][timer_num]->clk_src) { switch (p_timer_obj[group_num][timer_num]->clk_src) {
@ -432,6 +432,7 @@ void IRAM_ATTR timer_group_enable_alarm_in_isr(timer_group_t group_num, timer_id
uint64_t IRAM_ATTR timer_group_get_counter_value_in_isr(timer_group_t group_num, timer_idx_t timer_num) uint64_t IRAM_ATTR timer_group_get_counter_value_in_isr(timer_group_t group_num, timer_idx_t timer_num)
{ {
timer_ll_trigger_soft_capture(p_timer_obj[group_num][timer_num]->hal.dev, timer_num);
uint64_t val = timer_ll_get_counter_value(p_timer_obj[group_num][timer_num]->hal.dev, timer_num); uint64_t val = timer_ll_get_counter_value(p_timer_obj[group_num][timer_num]->hal.dev, timer_num);
return val; return val;
} }

View File

@ -236,7 +236,7 @@ esp_err_t gptimer_get_raw_count(gptimer_handle_t timer, unsigned long long *valu
ESP_RETURN_ON_FALSE_ISR(timer && value, ESP_ERR_INVALID_ARG, TAG, "invalid argument"); ESP_RETURN_ON_FALSE_ISR(timer && value, ESP_ERR_INVALID_ARG, TAG, "invalid argument");
portENTER_CRITICAL_SAFE(&timer->spinlock); portENTER_CRITICAL_SAFE(&timer->spinlock);
*value = timer_ll_get_counter_value(timer->hal.dev, timer->timer_id); *value = timer_hal_capture_and_get_counter_value(&timer->hal);
portEXIT_CRITICAL_SAFE(&timer->spinlock); portEXIT_CRITICAL_SAFE(&timer->spinlock);
return ESP_OK; return ESP_OK;
} }
@ -497,7 +497,7 @@ IRAM_ATTR static void gptimer_default_isr(void *args)
if (intr_status & TIMER_LL_EVENT_ALARM(timer->timer_id)) { if (intr_status & TIMER_LL_EVENT_ALARM(timer->timer_id)) {
// Note: when alarm event happens, the alarm will be disabled automatically by hardware // Note: when alarm event happens, the alarm will be disabled automatically by hardware
gptimer_alarm_event_data_t edata = { gptimer_alarm_event_data_t edata = {
.count_value = timer_ll_get_counter_value(timer->hal.dev, timer->timer_id), .count_value = timer_hal_capture_and_get_counter_value(&timer->hal),
.alarm_value = timer->alarm_count, .alarm_value = timer->alarm_count,
}; };

View File

@ -31,9 +31,9 @@ typedef struct {
/** /**
* @brief Timer alarm callback prototype * @brief Timer alarm callback prototype
* *
* @param[in] timer Timer handle created by `gptimer_new_timer()` * @param[in] timer Timer handle created by `gptimer_new_timer`
* @param[in] edata Alarm event data, fed by driver * @param[in] edata Alarm event data, fed by driver
* @param[in] user_ctx User data, passed from `gptimer_register_event_callbacks()` * @param[in] user_ctx User data, passed from `gptimer_register_event_callbacks`
* @return Whether a high priority task has been waken up by this function * @return Whether a high priority task has been waken up by this function
*/ */
typedef bool (*gptimer_alarm_cb_t) (gptimer_handle_t timer, const gptimer_alarm_event_data_t *edata, void *user_ctx); typedef bool (*gptimer_alarm_cb_t) (gptimer_handle_t timer, const gptimer_alarm_event_data_t *edata, void *user_ctx);
@ -91,9 +91,9 @@ esp_err_t gptimer_new_timer(const gptimer_config_t *config, gptimer_handle_t *re
* @brief Delete the GPTimer handle * @brief Delete the GPTimer handle
* *
* @note A timer can't be in the enable state when this function is invoked. * @note A timer can't be in the enable state when this function is invoked.
* See also `gptimer_disable()` for how to disable a timer. * See also `gptimer_disable` for how to disable a timer.
* *
* @param[in] timer Timer handle created by `gptimer_new_timer()` * @param[in] timer Timer handle created by `gptimer_new_timer`
* @return * @return
* - ESP_OK: Delete GPTimer successfully * - ESP_OK: Delete GPTimer successfully
* - ESP_ERR_INVALID_ARG: Delete GPTimer failed because of invalid argument * - ESP_ERR_INVALID_ARG: Delete GPTimer failed because of invalid argument
@ -109,7 +109,7 @@ esp_err_t gptimer_del_timer(gptimer_handle_t timer);
* @note This function is allowed to run within ISR context * @note This function is allowed to run within ISR context
* @note This function is allowed to be executed when Cache is disabled, by enabling `CONFIG_GPTIMER_CTRL_FUNC_IN_IRAM` * @note This function is allowed to be executed when Cache is disabled, by enabling `CONFIG_GPTIMER_CTRL_FUNC_IN_IRAM`
* *
* @param[in] timer Timer handle created by `gptimer_new_timer()` * @param[in] timer Timer handle created by `gptimer_new_timer`
* @param[in] value Count value to be set * @param[in] value Count value to be set
* @return * @return
* - ESP_OK: Set GPTimer raw count value successfully * - ESP_OK: Set GPTimer raw count value successfully
@ -121,11 +121,12 @@ esp_err_t gptimer_set_raw_count(gptimer_handle_t timer, uint64_t value);
/** /**
* @brief Get GPTimer raw count value * @brief Get GPTimer raw count value
* *
* @note This function will trigger a software capture event and then return the captured count value.
* @note With the raw count value and the resolution set in the `gptimer_config_t`, you can convert the count value into seconds. * @note With the raw count value and the resolution set in the `gptimer_config_t`, you can convert the count value into seconds.
* @note This function is allowed to run within ISR context * @note This function is allowed to run within ISR context
* @note This function is allowed to be executed when Cache is disabled, by enabling `CONFIG_GPTIMER_CTRL_FUNC_IN_IRAM` * @note This function is allowed to be executed when Cache is disabled, by enabling `CONFIG_GPTIMER_CTRL_FUNC_IN_IRAM`
* *
* @param[in] timer Timer handle created by `gptimer_new_timer()` * @param[in] timer Timer handle created by `gptimer_new_timer`
* @param[out] value Returned GPTimer count value * @param[out] value Returned GPTimer count value
* @return * @return
* - ESP_OK: Get GPTimer raw count value successfully * - ESP_OK: Get GPTimer raw count value successfully
@ -141,7 +142,7 @@ esp_err_t gptimer_get_raw_count(gptimer_handle_t timer, uint64_t *value);
* @note The first call to this function needs to be before the call to `gptimer_enable` * @note The first call to this function needs to be before the call to `gptimer_enable`
* @note User can deregister a previously registered callback by calling this function and setting the callback member in the `cbs` structure to NULL. * @note User can deregister a previously registered callback by calling this function and setting the callback member in the `cbs` structure to NULL.
* *
* @param[in] timer Timer handle created by `gptimer_new_timer()` * @param[in] timer Timer handle created by `gptimer_new_timer`
* @param[in] cbs Group of callback functions * @param[in] cbs Group of callback functions
* @param[in] user_data User data, which will be passed to callback functions directly * @param[in] user_data User data, which will be passed to callback functions directly
* @return * @return
@ -158,7 +159,7 @@ esp_err_t gptimer_register_event_callbacks(gptimer_handle_t timer, const gptimer
* @note This function is allowed to run within ISR context, so that user can set new alarm action immediately in the ISR callback. * @note This function is allowed to run within ISR context, so that user can set new alarm action immediately in the ISR callback.
* @note This function is allowed to be executed when Cache is disabled, by enabling `CONFIG_GPTIMER_CTRL_FUNC_IN_IRAM` * @note This function is allowed to be executed when Cache is disabled, by enabling `CONFIG_GPTIMER_CTRL_FUNC_IN_IRAM`
* *
* @param[in] timer Timer handle created by `gptimer_new_timer()` * @param[in] timer Timer handle created by `gptimer_new_timer`
* @param[in] config Alarm configuration, especially, set config to NULL means disabling the alarm function * @param[in] config Alarm configuration, especially, set config to NULL means disabling the alarm function
* @return * @return
* - ESP_OK: Set alarm action for GPTimer successfully * - ESP_OK: Set alarm action for GPTimer successfully
@ -171,11 +172,11 @@ esp_err_t gptimer_set_alarm_action(gptimer_handle_t timer, const gptimer_alarm_c
* @brief Enable GPTimer * @brief Enable GPTimer
* *
* @note This function will transit the timer state from init to enable. * @note This function will transit the timer state from init to enable.
* @note This function will enable the interrupt service, if it's lazy installed in `gptimer_register_event_callbacks()`. * @note This function will enable the interrupt service, if it's lazy installed in `gptimer_register_event_callbacks`.
* @note This function will acquire a PM lock, if a specific source clock (e.g. APB) is selected in the `gptimer_config_t`, while `CONFIG_PM_ENABLE` is enabled. * @note This function will acquire a PM lock, if a specific source clock (e.g. APB) is selected in the `gptimer_config_t`, while `CONFIG_PM_ENABLE` is enabled.
* @note Enable a timer doesn't mean to start it. See also `gptimer_start()` for how to make the timer start counting. * @note Enable a timer doesn't mean to start it. See also `gptimer_start` for how to make the timer start counting.
* *
* @param[in] timer Timer handle created by `gptimer_new_timer()` * @param[in] timer Timer handle created by `gptimer_new_timer`
* @return * @return
* - ESP_OK: Enable GPTimer successfully * - ESP_OK: Enable GPTimer successfully
* - ESP_ERR_INVALID_ARG: Enable GPTimer failed because of invalid argument * - ESP_ERR_INVALID_ARG: Enable GPTimer failed because of invalid argument
@ -187,10 +188,10 @@ esp_err_t gptimer_enable(gptimer_handle_t timer);
/** /**
* @brief Disable GPTimer * @brief Disable GPTimer
* *
* @note This function will do the opposite work to the `gptimer_enable()` * @note This function will do the opposite work to the `gptimer_enable`
* @note Disable a timer doesn't mean to stop it. See also `gptimer_stop()` for how to make the timer stop counting. * @note Disable a timer doesn't mean to stop it. See also `gptimer_stop` for how to make the timer stop counting.
* *
* @param[in] timer Timer handle created by `gptimer_new_timer()` * @param[in] timer Timer handle created by `gptimer_new_timer`
* @return * @return
* - ESP_OK: Disable GPTimer successfully * - ESP_OK: Disable GPTimer successfully
* - ESP_ERR_INVALID_ARG: Disable GPTimer failed because of invalid argument * - ESP_ERR_INVALID_ARG: Disable GPTimer failed because of invalid argument
@ -202,11 +203,11 @@ esp_err_t gptimer_disable(gptimer_handle_t timer);
/** /**
* @brief Start GPTimer (internal counter starts counting) * @brief Start GPTimer (internal counter starts counting)
* *
* @note This function should be called when the timer is in the enable state (i.e. after calling `gptimer_enable()`) * @note This function should be called when the timer is in the enable state (i.e. after calling `gptimer_enable`)
* @note This function is allowed to run within ISR context * @note This function is allowed to run within ISR context
* @note This function will be placed into IRAM if `CONFIG_GPTIMER_CTRL_FUNC_IN_IRAM` is on, so that it's allowed to be executed when Cache is disabled * @note This function will be placed into IRAM if `CONFIG_GPTIMER_CTRL_FUNC_IN_IRAM` is on, so that it's allowed to be executed when Cache is disabled
* *
* @param[in] timer Timer handle created by `gptimer_new_timer()` * @param[in] timer Timer handle created by `gptimer_new_timer`
* @return * @return
* - ESP_OK: Start GPTimer successfully * - ESP_OK: Start GPTimer successfully
* - ESP_ERR_INVALID_ARG: Start GPTimer failed because of invalid argument * - ESP_ERR_INVALID_ARG: Start GPTimer failed because of invalid argument
@ -218,11 +219,11 @@ esp_err_t gptimer_start(gptimer_handle_t timer);
/** /**
* @brief Stop GPTimer (internal counter stops counting) * @brief Stop GPTimer (internal counter stops counting)
* *
* @note This function should be called when the timer is in the enable state (i.e. after calling `gptimer_enable()`) * @note This function should be called when the timer is in the enable state (i.e. after calling `gptimer_enable`)
* @note This function is allowed to run within ISR context * @note This function is allowed to run within ISR context
* @note This function will be placed into IRAM if `CONFIG_GPTIMER_CTRL_FUNC_IN_IRAM` is on, so that it's allowed to be executed when Cache is disabled * @note This function will be placed into IRAM if `CONFIG_GPTIMER_CTRL_FUNC_IN_IRAM` is on, so that it's allowed to be executed when Cache is disabled
* *
* @param[in] timer Timer handle created by `gptimer_new_timer()` * @param[in] timer Timer handle created by `gptimer_new_timer`
* @return * @return
* - ESP_OK: Stop GPTimer successfully * - ESP_OK: Stop GPTimer successfully
* - ESP_ERR_INVALID_ARG: Stop GPTimer failed because of invalid argument * - ESP_ERR_INVALID_ARG: Stop GPTimer failed because of invalid argument

View File

@ -1,2 +1,4 @@
CONFIG_FREERTOS_HZ=1000 CONFIG_FREERTOS_HZ=1000
CONFIG_ESP_TASK_WDT=n CONFIG_ESP_TASK_WDT=n
# Disable nano printf, because we need to print the timer count in %llu format
CONFIG_NEWLIB_NANO_FORMAT=n

View File

@ -1,8 +1,9 @@
CONFIG_COMPILER_DUMP_RTL_FILES=y CONFIG_COMPILER_DUMP_RTL_FILES=y
CONFIG_ADC_ONESHOT_CTRL_FUNC_IN_IRAM=y CONFIG_ADC_ONESHOT_CTRL_FUNC_IN_IRAM=y
CONFIG_GPTIMER_ISR_IRAM_SAFE=y CONFIG_GPTIMER_ISR_IRAM_SAFE=y
CONFIG_GPTIMER_CTRL_FUNC_IN_IRAM=y
CONFIG_ADC_CONTINUOUS_ISR_IRAM_SAFE=y CONFIG_ADC_CONTINUOUS_ISR_IRAM_SAFE=y
CONFIG_COMPILER_OPTIMIZATION_NONE=y CONFIG_COMPILER_OPTIMIZATION_SIZE=y
# silent the error check, as the error string are stored in rodata, causing RTL check failure # silent the error check, as the error string are stored in rodata, causing RTL check failure
CONFIG_COMPILER_OPTIMIZATION_CHECKS_SILENT=y CONFIG_COMPILER_OPTIMIZATION_CHECKS_SILENT=y
CONFIG_COMPILER_OPTIMIZATION_ASSERTIONS_SILENT=y CONFIG_COMPILER_OPTIMIZATION_ASSERTIONS_SILENT=y

View File

@ -1,104 +0,0 @@
/*
* SPDX-FileCopyrightText: 2021-2022 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
/*----------------------------------------------------------------------------/
/ TJpgDec - Tiny JPEG Decompressor include file (C)ChaN, 2012
/----------------------------------------------------------------------------*/
#ifndef _TJPGDEC
#define _TJPGDEC
/*---------------------------------------------------------------------------*/
/* System Configurations */
#define JD_SZBUF 512 /* Size of stream input buffer */
#define JD_FORMAT 0 /* Output pixel format 0:RGB888 (3 BYTE/pix), 1:RGB565 (1 WORD/pix) */
#define JD_USE_SCALE 1 /* Use descaling feature for output */
#define JD_TBLCLIP 1 /* Use table for saturation (might be a bit faster but increases 1K bytes of code size) */
/*---------------------------------------------------------------------------*/
#ifdef __cplusplus
extern "C" {
#endif
/* These types must be 16-bit, 32-bit or larger integer */
typedef int INT;
typedef unsigned int UINT;
/* These types must be 8-bit integer */
typedef char CHAR;
typedef unsigned char UCHAR;
typedef unsigned char BYTE;
/* These types must be 16-bit integer */
typedef short SHORT;
typedef unsigned short USHORT;
typedef unsigned short WORD;
typedef unsigned short WCHAR;
/* These types must be 32-bit integer */
typedef long LONG;
typedef unsigned long ULONG;
typedef unsigned long DWORD;
/* Error code */
typedef enum {
JDR_OK = 0, /* 0: Succeeded */
JDR_INTR, /* 1: Interrupted by output function */
JDR_INP, /* 2: Device error or wrong termination of input stream */
JDR_MEM1, /* 3: Insufficient memory pool for the image */
JDR_MEM2, /* 4: Insufficient stream input buffer */
JDR_PAR, /* 5: Parameter error */
JDR_FMT1, /* 6: Data format error (may be damaged data) */
JDR_FMT2, /* 7: Right format but not supported */
JDR_FMT3 /* 8: Not supported JPEG standard */
} JRESULT;
/* Rectangular structure */
typedef struct {
WORD left, right, top, bottom;
} JRECT;
/* Decompressor object structure */
typedef struct JDEC JDEC;
struct JDEC {
UINT dctr; /* Number of bytes available in the input buffer */
BYTE *dptr; /* Current data read ptr */
BYTE *inbuf; /* Bit stream input buffer */
BYTE dmsk; /* Current bit in the current read byte */
BYTE scale; /* Output scaling ratio */
BYTE msx, msy; /* MCU size in unit of block (width, height) */
BYTE qtid[3]; /* Quantization table ID of each component */
SHORT dcv[3]; /* Previous DC element of each component */
WORD nrst; /* Restart inverval */
UINT width, height; /* Size of the input image (pixel) */
BYTE *huffbits[2][2]; /* Huffman bit distribution tables [id][dcac] */
WORD *huffcode[2][2]; /* Huffman code word tables [id][dcac] */
BYTE *huffdata[2][2]; /* Huffman decoded data tables [id][dcac] */
LONG *qttbl[4]; /* Dequaitizer tables [id] */
void *workbuf; /* Working buffer for IDCT and RGB output */
BYTE *mcubuf; /* Working buffer for the MCU */
void *pool; /* Pointer to available memory pool */
UINT sz_pool; /* Size of momory pool (bytes available) */
UINT (*infunc)(JDEC *, BYTE *, UINT); /* Pointer to jpeg stream input function */
void *device; /* Pointer to I/O device identifiler for the session */
};
/* TJpgDec API functions */
JRESULT jd_prepare (JDEC *, UINT(*)(JDEC *, BYTE *, UINT), void *, UINT, void *);
JRESULT jd_decomp (JDEC *, UINT(*)(JDEC *, void *, JRECT *), BYTE);
#ifdef __cplusplus
}
#endif
#endif /* _TJPGDEC */

View File

@ -112,6 +112,22 @@ static inline void timer_ll_enable_counter(timg_dev_t *hw, uint32_t timer_num, b
hw->hw_timer[timer_num].config.tx_en = en; hw->hw_timer[timer_num].config.tx_en = en;
} }
/**
* @brief Trigger software capture event
*
* @param hw Timer Group register base address
* @param timer_num Timer number in the group
*/
__attribute__((always_inline))
static inline void timer_ll_trigger_soft_capture(timg_dev_t *hw, uint32_t timer_num)
{
hw->hw_timer[timer_num].update.tx_update = 1;
// Timer register is in a different clock domain from Timer hardware logic
// We need to wait for the update to take effect before fetching the count value
while (hw->hw_timer[timer_num].update.tx_update) {
}
}
/** /**
* @brief Get counter value * @brief Get counter value
* *
@ -123,11 +139,6 @@ static inline void timer_ll_enable_counter(timg_dev_t *hw, uint32_t timer_num, b
__attribute__((always_inline)) __attribute__((always_inline))
static inline uint64_t timer_ll_get_counter_value(timg_dev_t *hw, uint32_t timer_num) static inline uint64_t timer_ll_get_counter_value(timg_dev_t *hw, uint32_t timer_num)
{ {
hw->hw_timer[timer_num].update.tx_update = 1;
// Timer register is in a different clock domain from Timer hardware logic
// We need to wait for the update to take effect before fetching the count value
while (hw->hw_timer[timer_num].update.tx_update) {
}
return ((uint64_t) hw->hw_timer[timer_num].hi.tx_hi << 32) | (hw->hw_timer[timer_num].lo.tx_lo); return ((uint64_t) hw->hw_timer[timer_num].hi.tx_hi << 32) | (hw->hw_timer[timer_num].lo.tx_lo);
} }

View File

@ -115,6 +115,22 @@ static inline void timer_ll_enable_counter(timg_dev_t *hw, uint32_t timer_num, b
hw->hw_timer[timer_num].config.tx_en = en; hw->hw_timer[timer_num].config.tx_en = en;
} }
/**
* @brief Trigger software capture event
*
* @param hw Timer Group register base address
* @param timer_num Timer number in the group
*/
__attribute__((always_inline))
static inline void timer_ll_trigger_soft_capture(timg_dev_t *hw, uint32_t timer_num)
{
hw->hw_timer[timer_num].update.tx_update = 1;
// Timer register is in a different clock domain from Timer hardware logic
// We need to wait for the update to take effect before fetching the count value
while (hw->hw_timer[timer_num].update.tx_update) {
}
}
/** /**
* @brief Get counter value * @brief Get counter value
* *
@ -126,11 +142,6 @@ static inline void timer_ll_enable_counter(timg_dev_t *hw, uint32_t timer_num, b
__attribute__((always_inline)) __attribute__((always_inline))
static inline uint64_t timer_ll_get_counter_value(timg_dev_t *hw, uint32_t timer_num) static inline uint64_t timer_ll_get_counter_value(timg_dev_t *hw, uint32_t timer_num)
{ {
hw->hw_timer[timer_num].update.tx_update = 1;
// Timer register is in a different clock domain from Timer hardware logic
// We need to wait for the update to take effect before fetching the count value
while (hw->hw_timer[timer_num].update.tx_update) {
}
return ((uint64_t) hw->hw_timer[timer_num].hi.tx_hi << 32) | (hw->hw_timer[timer_num].lo.tx_lo); return ((uint64_t) hw->hw_timer[timer_num].hi.tx_hi << 32) | (hw->hw_timer[timer_num].lo.tx_lo);
} }

View File

@ -115,6 +115,22 @@ static inline void timer_ll_enable_counter(timg_dev_t *hw, uint32_t timer_num, b
hw->hw_timer[timer_num].config.tx_en = en; hw->hw_timer[timer_num].config.tx_en = en;
} }
/**
* @brief Trigger software capture event
*
* @param hw Timer Group register base address
* @param timer_num Timer number in the group
*/
__attribute__((always_inline))
static inline void timer_ll_trigger_soft_capture(timg_dev_t *hw, uint32_t timer_num)
{
hw->hw_timer[timer_num].update.tx_update = 1;
// Timer register is in a different clock domain from Timer hardware logic
// We need to wait for the update to take effect before fetching the count value
while (hw->hw_timer[timer_num].update.tx_update) {
}
}
/** /**
* @brief Get counter value * @brief Get counter value
* *
@ -126,11 +142,6 @@ static inline void timer_ll_enable_counter(timg_dev_t *hw, uint32_t timer_num, b
__attribute__((always_inline)) __attribute__((always_inline))
static inline uint64_t timer_ll_get_counter_value(timg_dev_t *hw, uint32_t timer_num) static inline uint64_t timer_ll_get_counter_value(timg_dev_t *hw, uint32_t timer_num)
{ {
hw->hw_timer[timer_num].update.tx_update = 1;
// Timer register is in a different clock domain from Timer hardware logic
// We need to wait for the update to take effect before fetching the count value
while (hw->hw_timer[timer_num].update.tx_update) {
}
return ((uint64_t) hw->hw_timer[timer_num].hi.tx_hi << 32) | (hw->hw_timer[timer_num].lo.tx_lo); return ((uint64_t) hw->hw_timer[timer_num].hi.tx_hi << 32) | (hw->hw_timer[timer_num].lo.tx_lo);
} }

View File

@ -115,6 +115,22 @@ static inline void timer_ll_enable_counter(timg_dev_t *hw, uint32_t timer_num, b
hw->hw_timer[timer_num].config.tx_en = en; hw->hw_timer[timer_num].config.tx_en = en;
} }
/**
* @brief Trigger software capture event
*
* @param hw Timer Group register base address
* @param timer_num Timer number in the group
*/
__attribute__((always_inline))
static inline void timer_ll_trigger_soft_capture(timg_dev_t *hw, uint32_t timer_num)
{
hw->hw_timer[timer_num].update.tx_update = 1;
// Timer register is in a different clock domain from Timer hardware logic
// We need to wait for the update to take effect before fetching the count value
while (hw->hw_timer[timer_num].update.tx_update) {
}
}
/** /**
* @brief Get counter value * @brief Get counter value
* *
@ -126,11 +142,6 @@ static inline void timer_ll_enable_counter(timg_dev_t *hw, uint32_t timer_num, b
__attribute__((always_inline)) __attribute__((always_inline))
static inline uint64_t timer_ll_get_counter_value(timg_dev_t *hw, uint32_t timer_num) static inline uint64_t timer_ll_get_counter_value(timg_dev_t *hw, uint32_t timer_num)
{ {
hw->hw_timer[timer_num].update.tx_update = 1;
// Timer register is in a different clock domain from Timer hardware logic
// We need to wait for the update to take effect before fetching the count value
while (hw->hw_timer[timer_num].update.tx_update) {
}
return ((uint64_t) hw->hw_timer[timer_num].hi.tx_hi << 32) | (hw->hw_timer[timer_num].lo.tx_lo); return ((uint64_t) hw->hw_timer[timer_num].hi.tx_hi << 32) | (hw->hw_timer[timer_num].lo.tx_lo);
} }

View File

@ -116,6 +116,22 @@ static inline void timer_ll_enable_counter(timg_dev_t *hw, uint32_t timer_num, b
hw->hw_timer[timer_num].config.tx_en = en; hw->hw_timer[timer_num].config.tx_en = en;
} }
/**
* @brief Trigger software capture event
*
* @param hw Timer Group register base address
* @param timer_num Timer number in the group
*/
__attribute__((always_inline))
static inline void timer_ll_trigger_soft_capture(timg_dev_t *hw, uint32_t timer_num)
{
hw->hw_timer[timer_num].update.tx_update = 1;
// Timer register is in a different clock domain from Timer hardware logic
// We need to wait for the update to take effect before fetching the count value
while (hw->hw_timer[timer_num].update.tx_update) {
}
}
/** /**
* @brief Get counter value * @brief Get counter value
* *
@ -127,11 +143,6 @@ static inline void timer_ll_enable_counter(timg_dev_t *hw, uint32_t timer_num, b
__attribute__((always_inline)) __attribute__((always_inline))
static inline uint64_t timer_ll_get_counter_value(timg_dev_t *hw, uint32_t timer_num) static inline uint64_t timer_ll_get_counter_value(timg_dev_t *hw, uint32_t timer_num)
{ {
hw->hw_timer[timer_num].update.tx_update = 1;
// Timer register is in a different clock domain from Timer hardware logic
// We need to wait for the update to take effect before fetching the count value
while (hw->hw_timer[timer_num].update.tx_update) {
}
return ((uint64_t) hw->hw_timer[timer_num].hi.tx_hi << 32) | (hw->hw_timer[timer_num].lo.tx_lo); return ((uint64_t) hw->hw_timer[timer_num].hi.tx_hi << 32) | (hw->hw_timer[timer_num].lo.tx_lo);
} }

View File

@ -115,6 +115,22 @@ static inline void timer_ll_enable_counter(timg_dev_t *hw, uint32_t timer_num, b
hw->hw_timer[timer_num].config.tn_en = en; hw->hw_timer[timer_num].config.tn_en = en;
} }
/**
* @brief Trigger software capture event
*
* @param hw Timer Group register base address
* @param timer_num Timer number in the group
*/
__attribute__((always_inline))
static inline void timer_ll_trigger_soft_capture(timg_dev_t *hw, uint32_t timer_num)
{
hw->hw_timer[timer_num].update.tn_update = 1;
// Timer register is in a different clock domain from Timer hardware logic
// We need to wait for the update to take effect before fetching the count value
while (hw->hw_timer[timer_num].update.tn_update) {
}
}
/** /**
* @brief Get counter value * @brief Get counter value
* *
@ -126,11 +142,6 @@ static inline void timer_ll_enable_counter(timg_dev_t *hw, uint32_t timer_num, b
__attribute__((always_inline)) __attribute__((always_inline))
static inline uint64_t timer_ll_get_counter_value(timg_dev_t *hw, uint32_t timer_num) static inline uint64_t timer_ll_get_counter_value(timg_dev_t *hw, uint32_t timer_num)
{ {
hw->hw_timer[timer_num].update.tn_update = 1;
// Timer register is in a different clock domain from Timer hardware logic
// We need to wait for the update to take effect before fetching the count value
while (hw->hw_timer[timer_num].update.tn_update) {
}
return ((uint64_t)hw->hw_timer[timer_num].hi.tn_hi << 32) | (hw->hw_timer[timer_num].lo.tn_lo); return ((uint64_t)hw->hw_timer[timer_num].hi.tn_hi << 32) | (hw->hw_timer[timer_num].lo.tn_lo);
} }

View File

@ -1,5 +1,5 @@
/* /*
* SPDX-FileCopyrightText: 2021 Espressif Systems (Shanghai) CO LTD * SPDX-FileCopyrightText: 2021-2022 Espressif Systems (Shanghai) CO LTD
* *
* SPDX-License-Identifier: Apache-2.0 * SPDX-License-Identifier: Apache-2.0
*/ */
@ -45,6 +45,14 @@ void timer_hal_init(timer_hal_context_t *hal, uint32_t group_num, uint32_t timer
*/ */
void timer_hal_set_counter_value(timer_hal_context_t *hal, uint64_t load_val); void timer_hal_set_counter_value(timer_hal_context_t *hal, uint64_t load_val);
/**
* @brief Trigger a software capture event and then return the captured count value
*
* @param hal Context of the HAL layer
* @return Counter value
*/
uint64_t timer_hal_capture_and_get_counter_value(timer_hal_context_t *hal);
#ifdef __cplusplus #ifdef __cplusplus
} }
#endif #endif

View File

@ -22,3 +22,9 @@ void timer_hal_set_counter_value(timer_hal_context_t *hal, uint64_t load_val)
// restore the previous reload value // restore the previous reload value
timer_ll_set_reload_value(hal->dev, hal->timer_id, old_reload); timer_ll_set_reload_value(hal->dev, hal->timer_id, old_reload);
} }
uint64_t timer_hal_capture_and_get_counter_value(timer_hal_context_t *hal)
{
timer_ll_trigger_soft_capture(hal->dev, hal->timer_id);
return timer_ll_get_counter_value(hal->dev, hal->timer_id);
}

View File

@ -17,18 +17,18 @@ Functional Overview
The following sections of this document cover the typical steps to install and operate a timer: The following sections of this document cover the typical steps to install and operate a timer:
- :ref:`resource-allocation` - covers which parameters should be set up to get a timer handle and how to recycle the resources when GPTimer finishes working. - :ref:`gptimer-resource-allocation` - covers which parameters should be set up to get a timer handle and how to recycle the resources when GPTimer finishes working.
- :ref:`set-and-get-count-value` - covers how to force the timer counting from a start point and how to get the count value at anytime. - :ref:`set-and-get-count-value` - covers how to force the timer counting from a start point and how to get the count value at anytime.
- :ref:`set-up-alarm-action` - covers the parameters that should be set up to enable the alarm event. - :ref:`set-up-alarm-action` - covers the parameters that should be set up to enable the alarm event.
- :ref:`register-event-callbacks` - covers how to hook user specific code to the alarm event callback function. - :ref:`gptimer-register-event-callbacks` - covers how to hook user specific code to the alarm event callback function.
- :ref:`enable-and-disable-timer` - covers how to enable and disable the timer. - :ref:`enable-and-disable-timer` - covers how to enable and disable the timer.
- :ref:`start-and-stop-timer` - shows some typical use cases that start the timer with different alarm behavior. - :ref:`start-and-stop-timer` - shows some typical use cases that start the timer with different alarm behavior.
- :ref:`power-management` - describes how different source clock selections can affect power consumption. - :ref:`gptimer-power-management` - describes how different source clock selections can affect power consumption.
- :ref:`iram-safe` - describes tips on how to make the timer interrupt and IO control functions work better along with a disabled cache. - :ref:`gptimer-iram-safe` - describes tips on how to make the timer interrupt and IO control functions work better along with a disabled cache.
- :ref:`thread-safety` - lists which APIs are guaranteed to be thread safe by the driver. - :ref:`gptimer-thread-safety` - lists which APIs are guaranteed to be thread safe by the driver.
- :ref:`kconfig-options` - lists the supported Kconfig options that can be used to make a different effect on driver behavior. - :ref:`gptimer-kconfig-options` - lists the supported Kconfig options that can be used to make a different effect on driver behavior.
.. _resource-allocation: .. _gptimer-resource-allocation:
Resource Allocation Resource Allocation
^^^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^
@ -39,7 +39,7 @@ A GPTimer instance is represented by :cpp:type:`gptimer_handle_t`. The driver be
To install a timer instance, there is a configuration structure that needs to be given in advance: :cpp:type:`gptimer_config_t`: To install a timer instance, there is a configuration structure that needs to be given in advance: :cpp:type:`gptimer_config_t`:
- :cpp:member:`gptimer_config_t::clk_src` selects the source clock for the timer. The available clocks are listed in :cpp:type:`gptimer_clock_source_t`, you can only pick one of them. For the effect on power consumption of different clock source, please refer to Section :ref:`power-management`. - :cpp:member:`gptimer_config_t::clk_src` selects the source clock for the timer. The available clocks are listed in :cpp:type:`gptimer_clock_source_t`, you can only pick one of them. For the effect on power consumption of different clock source, please refer to Section :ref:`gptimer-power-management`.
- :cpp:member:`gptimer_config_t::direction` sets the counting direction of the timer, supported directions are listed in :cpp:type:`gptimer_count_direction_t`, you can only pick one of them. - :cpp:member:`gptimer_config_t::direction` sets the counting direction of the timer, supported directions are listed in :cpp:type:`gptimer_count_direction_t`, you can only pick one of them.
@ -94,7 +94,7 @@ To make the alarm configurations take effect, you should call :cpp:func:`gptimer
If an alarm value is set and the timer has already exceeded this value, the alarm will be triggered immediately. If an alarm value is set and the timer has already exceeded this value, the alarm will be triggered immediately.
.. _register-event-callbacks: .. _gptimer-register-event-callbacks:
Register Event Callbacks Register Event Callbacks
^^^^^^^^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^^^^^^
@ -116,7 +116,7 @@ Before doing IO control to the timer, you needs to enable the timer first, by ca
* Switch the timer driver state from **init** to **enable**. * Switch the timer driver state from **init** to **enable**.
* Enable the interrupt service if it has been lazy installed by :cpp:func:`gptimer_register_event_callbacks`. * Enable the interrupt service if it has been lazy installed by :cpp:func:`gptimer_register_event_callbacks`.
* Acquire a proper power management lock if a specific clock source (e.g. APB clock) is selected. See Section :ref:`power-management` for more information. * Acquire a proper power management lock if a specific clock source (e.g. APB clock) is selected. See Section :ref:`gptimer-power-management` for more information.
Calling :cpp:func:`gptimer_disable` will do the opposite, that is, put the timer driver back to the **init** state, disable the interrupts service and release the power management lock. Calling :cpp:func:`gptimer_disable` will do the opposite, that is, put the timer driver back to the **init** state, disable the interrupts service and release the power management lock.
@ -256,7 +256,7 @@ Alarm value can be updated dynamically inside the ISR handler callback, by chang
ESP_ERROR_CHECK(gptimer_enable(gptimer)); ESP_ERROR_CHECK(gptimer_enable(gptimer));
ESP_ERROR_CHECK(gptimer_start(gptimer, &alarm_config)); ESP_ERROR_CHECK(gptimer_start(gptimer, &alarm_config));
.. _power-management: .. _gptimer-power-management:
Power Management Power Management
^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^
@ -267,7 +267,7 @@ However, the driver can prevent the system from changing APB frequency by acquir
If other gptimer clock sources are selected such as :cpp:enumerator:`GPTIMER_CLK_SRC_XTAL`, then the driver will not install power management lock. The XTAL clock source is more suitable for a low power application as long as the source clock can still provide sufficient resolution. If other gptimer clock sources are selected such as :cpp:enumerator:`GPTIMER_CLK_SRC_XTAL`, then the driver will not install power management lock. The XTAL clock source is more suitable for a low power application as long as the source clock can still provide sufficient resolution.
.. _iram-safe: .. _gptimer-iram-safe:
IRAM Safe IRAM Safe
^^^^^^^^^ ^^^^^^^^^
@ -290,7 +290,7 @@ There is another Kconfig option :ref:`CONFIG_GPTIMER_CTRL_FUNC_IN_IRAM` that can
- :cpp:func:`gptimer_set_raw_count` - :cpp:func:`gptimer_set_raw_count`
- :cpp:func:`gptimer_set_alarm_action` - :cpp:func:`gptimer_set_alarm_action`
.. _thread-safety: .. _gptimer-thread-safety:
Thread Safety Thread Safety
^^^^^^^^^^^^^ ^^^^^^^^^^^^^
@ -307,13 +307,13 @@ The following functions are allowed to run under ISR context, as the driver uses
Other functions that take :cpp:type:`gptimer_handle_t` as the first positional parameter, are not treated as thread safe, which means you should avoid calling them from multiple tasks. Other functions that take :cpp:type:`gptimer_handle_t` as the first positional parameter, are not treated as thread safe, which means you should avoid calling them from multiple tasks.
.. _kconfig-options: .. _gptimer-kconfig-options:
Kconfig Options Kconfig Options
^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^
- :ref:`CONFIG_GPTIMER_CTRL_FUNC_IN_IRAM` controls where to place the GPTimer control functions (IRAM or flash), see Section :ref:`iram-safe` for more information. - :ref:`CONFIG_GPTIMER_CTRL_FUNC_IN_IRAM` controls where to place the GPTimer control functions (IRAM or flash), see Section :ref:`gptimer-iram-safe` for more information.
- :ref:`CONFIG_GPTIMER_ISR_IRAM_SAFE` controls whether the default ISR handler can work when the cache is disabled, see Section :ref:`iram-safe` for more information. - :ref:`CONFIG_GPTIMER_ISR_IRAM_SAFE` controls whether the default ISR handler can work when the cache is disabled, see Section :ref:`gptimer-iram-safe` for more information.
- :ref:`CONFIG_GPTIMER_ENABLE_DEBUG_LOG` is used to enabled the debug log output. Enable this option will increase the firmware binary size. - :ref:`CONFIG_GPTIMER_ENABLE_DEBUG_LOG` is used to enabled the debug log output. Enable this option will increase the firmware binary size.
Application Examples Application Examples

View File

@ -17,18 +17,18 @@
下文介绍了配置和操作定时器的常规步骤: 下文介绍了配置和操作定时器的常规步骤:
- :ref:`resource-allocation` - 获取定时器句柄应设置的参数,以及如何在通用定时器完成工作时回收资源。 - :ref:`gptimer-resource-allocation` - 获取定时器句柄应设置的参数,以及如何在通用定时器完成工作时回收资源。
- :ref:`set-and-get-count-value` - 如何强制定时器从起点开始计数,以及如何随时获取计数值。 - :ref:`set-and-get-count-value` - 如何强制定时器从起点开始计数,以及如何随时获取计数值。
- :ref:`set-up-alarm-action` - 启动警报事件应设置的参数。 - :ref:`set-up-alarm-action` - 启动警报事件应设置的参数。
- :ref:`register-event-callbacks` - 如何将用户的特定代码挂载到警报事件回调函数。 - :ref:`gptimer-register-event-callbacks` - 如何将用户的特定代码挂载到警报事件回调函数。
- :ref:`enable-and-disable-timer` - 如何使能和禁用定时器。 - :ref:`enable-and-disable-timer` - 如何使能和禁用定时器。
- :ref:`start-and-stop-timer` - 通过不同报警行为启动定时器的典型使用场景。 - :ref:`start-and-stop-timer` - 通过不同报警行为启动定时器的典型使用场景。
- :ref:`power-management` - 选择不同的时钟源将会如何影响功耗。 - :ref:`gptimer-power-management` - 选择不同的时钟源将会如何影响功耗。
- :ref:`iram-safe` - 在 cache 禁用的情况下,如何更好地让定时器处理中断事务以及实现 IO 控制功能。 - :ref:`gptimer-iram-safe` - 在 cache 禁用的情况下,如何更好地让定时器处理中断事务以及实现 IO 控制功能。
- :ref:`thread-safety` - 驱动程序保证哪些 API 线程安全。 - :ref:`gptimer-thread-safety` - 驱动程序保证哪些 API 线程安全。
- :ref:`kconfig-options` - 支持的 Kconfig 选项,这些选项会对驱动程序行为产生不同影响。 - :ref:`gptimer-kconfig-options` - 支持的 Kconfig 选项,这些选项会对驱动程序行为产生不同影响。
.. _resource-allocation: .. _gptimer-resource-allocation:
资源分配 资源分配
^^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^
@ -39,7 +39,7 @@
要安装一个定时器实例,需要提前提供配置结构体 :cpp:type:`gptimer_config_t` 要安装一个定时器实例,需要提前提供配置结构体 :cpp:type:`gptimer_config_t`
- :cpp:member:`gptimer_config_t::clk_src` 选择定时器的时钟源。:cpp:type:`gptimer_clock_source_t` 中列出多个可用时钟,仅可选择其中一个时钟。了解不同时钟源对功耗的影响,请查看章节 :ref:`power-management`。 - :cpp:member:`gptimer_config_t::clk_src` 选择定时器的时钟源。:cpp:type:`gptimer_clock_source_t` 中列出多个可用时钟,仅可选择其中一个时钟。了解不同时钟源对功耗的影响,请查看章节 :ref:`gptimer-power-management`。
- :cpp:member:`gptimer_config_t::direction` 设置定时器的计数方向,:cpp:type:`gptimer_count_direction_t` 中列出多个支持的方向,仅可选择其中一个方向。 - :cpp:member:`gptimer_config_t::direction` 设置定时器的计数方向,:cpp:type:`gptimer_count_direction_t` 中列出多个支持的方向,仅可选择其中一个方向。
@ -94,7 +94,7 @@
如果警报值已设置且定时器超过该值,则会立即触发警报。 如果警报值已设置且定时器超过该值,则会立即触发警报。
.. _register-event-callbacks: .. _gptimer-register-event-callbacks:
注册事件回调函数 注册事件回调函数
^^^^^^^^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^^^^^^
@ -116,7 +116,7 @@
* 此函数将把定时器驱动程序的状态从 **init** 切换为 **enable**。 * 此函数将把定时器驱动程序的状态从 **init** 切换为 **enable**。
* 如果 :cpp:func:`gptimer_register_event_callbacks` 已经延迟安装中断服务,此函数将使能中断服务。 * 如果 :cpp:func:`gptimer_register_event_callbacks` 已经延迟安装中断服务,此函数将使能中断服务。
* 如果选择了特定的时钟源(例如 APB 时钟),此函数将获取适当的电源管理锁。了解更多信息,请查看章节 :ref:`power-management`。 * 如果选择了特定的时钟源(例如 APB 时钟),此函数将获取适当的电源管理锁。了解更多信息,请查看章节 :ref:`gptimer-power-management`。
调用 :cpp:func:`gptimer_disable` 会进行相反的操作,即将定时器驱动程序恢复到 **init** 状态,禁用中断服务并释放电源管理锁。 调用 :cpp:func:`gptimer_disable` 会进行相反的操作,即将定时器驱动程序恢复到 **init** 状态,禁用中断服务并释放电源管理锁。
@ -256,7 +256,7 @@
ESP_ERROR_CHECK(gptimer_enable(gptimer)); ESP_ERROR_CHECK(gptimer_enable(gptimer));
ESP_ERROR_CHECK(gptimer_start(gptimer, &alarm_config)); ESP_ERROR_CHECK(gptimer_start(gptimer, &alarm_config));
.. _power-management: .. _gptimer-power-management:
电源管理 电源管理
^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^
@ -267,7 +267,7 @@
如果选择 :cpp:enumerator:`GPTIMER_CLK_SRC_XTAL` 等其他时钟源那么驱动程序不会安装电源管理锁。只要时钟源仍可提供足够的分辨率XTAL 时钟源就更适合低功耗应用。 如果选择 :cpp:enumerator:`GPTIMER_CLK_SRC_XTAL` 等其他时钟源那么驱动程序不会安装电源管理锁。只要时钟源仍可提供足够的分辨率XTAL 时钟源就更适合低功耗应用。
.. _iram-safe: .. _gptimer-iram-safe:
IRAM 安全 IRAM 安全
^^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^
@ -290,7 +290,7 @@ IRAM 安全
- :cpp:func:`gptimer_set_raw_count` - :cpp:func:`gptimer_set_raw_count`
- :cpp:func:`gptimer_set_alarm_action` - :cpp:func:`gptimer_set_alarm_action`
.. _thread-safety: .. _gptimer-thread-safety:
线程安全 线程安全
^^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^
@ -307,13 +307,13 @@ IRAM 安全
:cpp:type:`gptimer_handle_t` 作为第一个位置参数的其他函数不被视作线程安全,也就是说应该避免从多个任务中调用这些函数。 :cpp:type:`gptimer_handle_t` 作为第一个位置参数的其他函数不被视作线程安全,也就是说应该避免从多个任务中调用这些函数。
.. _kconfig-options: .. _gptimer-kconfig-options:
Kconfig 选项 Kconfig 选项
^^^^^^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^^^^
- :ref:`CONFIG_GPTIMER_CTRL_FUNC_IN_IRAM` 控制放置通用定时器控制函数IRAM 或 flash的位置。了解更多信息请参考章节 :ref:`iram-safe`。 - :ref:`CONFIG_GPTIMER_CTRL_FUNC_IN_IRAM` 控制放置通用定时器控制函数IRAM 或 flash的位置。了解更多信息请参考章节 :ref:`gptimer-iram-safe`。
- :ref:`CONFIG_GPTIMER_ISR_IRAM_SAFE` 控制默认 ISR 程序在 cache 禁用时是否可以运行。了解更多信息,请参考章节 :ref:`iram-safe`。 - :ref:`CONFIG_GPTIMER_ISR_IRAM_SAFE` 控制默认 ISR 程序在 cache 禁用时是否可以运行。了解更多信息,请参考章节 :ref:`gptimer-iram-safe`。
- :ref:`CONFIG_GPTIMER_ENABLE_DEBUG_LOG` 用于启用调试日志输出。启用这一选项将增加固件二进制文件大小。 - :ref:`CONFIG_GPTIMER_ENABLE_DEBUG_LOG` 用于启用调试日志输出。启用这一选项将增加固件二进制文件大小。
应用示例 应用示例