mirror of
https://github.com/espressif/esp-idf
synced 2025-03-09 17:19:09 -04:00
feat(gptimer): make start and stop function idempotent
Closes https://github.com/espressif/esp-idf/issues/12325 Closes https://github.com/espressif/esp-idf/issues/13486
This commit is contained in:
parent
5f2a7f4d29
commit
9822433957
@ -43,7 +43,7 @@ extern void spi_flash_enable_interrupts_caches_and_other_cpu(void);
|
|||||||
__attribute__((unused))
|
__attribute__((unused))
|
||||||
static void s_test_cache_disable_period_us(test_adc_iram_ctx_t *ctx, uint32_t period_us);
|
static void s_test_cache_disable_period_us(test_adc_iram_ctx_t *ctx, uint32_t period_us);
|
||||||
|
|
||||||
#if CONFIG_ADC_ONESHOT_CTRL_FUNC_IN_IRAM && CONFIG_GPTIMER_ISR_IRAM_SAFE
|
#if CONFIG_ADC_ONESHOT_CTRL_FUNC_IN_IRAM && CONFIG_GPTIMER_ISR_CACHE_SAFE
|
||||||
/*---------------------------------------------------------------
|
/*---------------------------------------------------------------
|
||||||
ADC oneshot work with cache safe ISR
|
ADC oneshot work with cache safe ISR
|
||||||
---------------------------------------------------------------*/
|
---------------------------------------------------------------*/
|
||||||
@ -140,7 +140,7 @@ TEST_CASE("ADC oneshot fast work with ISR and Flash", "[adc_oneshot]")
|
|||||||
TEST_ESP_OK(gptimer_del_timer(timer));
|
TEST_ESP_OK(gptimer_del_timer(timer));
|
||||||
TEST_ESP_OK(adc_oneshot_del_unit(oneshot_handle));
|
TEST_ESP_OK(adc_oneshot_del_unit(oneshot_handle));
|
||||||
}
|
}
|
||||||
#endif //#if CONFIG_ADC_ONESHOT_CTRL_FUNC_IN_IRAM && CONFIG_GPTIMER_ISR_IRAM_SAFE
|
#endif //#if CONFIG_ADC_ONESHOT_CTRL_FUNC_IN_IRAM && CONFIG_GPTIMER_ISR_CACHE_SAFE
|
||||||
|
|
||||||
#if CONFIG_ADC_CONTINUOUS_ISR_IRAM_SAFE || CONFIG_GDMA_ISR_IRAM_SAFE
|
#if CONFIG_ADC_CONTINUOUS_ISR_IRAM_SAFE || CONFIG_GDMA_ISR_IRAM_SAFE
|
||||||
#include "esp_adc/adc_continuous.h"
|
#include "esp_adc/adc_continuous.h"
|
||||||
|
@ -3,7 +3,7 @@ CONFIG_XTAL_FREQ_26=y
|
|||||||
|
|
||||||
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_CACHE_SAFE=y
|
||||||
CONFIG_GPTIMER_CTRL_FUNC_IN_IRAM=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_SIZE=y
|
CONFIG_COMPILER_OPTIMIZATION_SIZE=y
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
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_CACHE_SAFE=y
|
||||||
CONFIG_GPTIMER_CTRL_FUNC_IN_IRAM=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_SIZE=y
|
CONFIG_COMPILER_OPTIMIZATION_SIZE=y
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
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_CACHE_SAFE=y
|
||||||
CONFIG_GPTIMER_CTRL_FUNC_IN_IRAM=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_SIZE=y
|
CONFIG_COMPILER_OPTIMIZATION_SIZE=y
|
||||||
|
@ -1,31 +1,45 @@
|
|||||||
menu "ESP-Driver:GPTimer Configurations"
|
menu "ESP-Driver:GPTimer Configurations"
|
||||||
depends on SOC_GPTIMER_SUPPORTED
|
depends on SOC_GPTIMER_SUPPORTED
|
||||||
|
|
||||||
config GPTIMER_ISR_HANDLER_IN_IRAM
|
config GPTIMER_ISR_HANDLER_IN_IRAM
|
||||||
bool "Place GPTimer ISR handler into IRAM"
|
bool "Place GPTimer ISR handler in IRAM to reduce latency"
|
||||||
default y
|
default y
|
||||||
|
select GPTIMER_OBJ_CACHE_SAFE
|
||||||
help
|
help
|
||||||
Place GPTimer ISR handler into IRAM for better performance and fewer cache misses.
|
Place GPTimer ISR handler in IRAM to reduce latency caused by cache miss.
|
||||||
|
|
||||||
config GPTIMER_CTRL_FUNC_IN_IRAM
|
config GPTIMER_CTRL_FUNC_IN_IRAM
|
||||||
bool "Place GPTimer control functions into IRAM"
|
bool "Place GPTimer control functions in IRAM"
|
||||||
default n
|
default n
|
||||||
|
select GPTIMER_OBJ_CACHE_SAFE
|
||||||
help
|
help
|
||||||
Place GPTimer control functions (like start/stop) into IRAM,
|
Place GPTimer control functions (like start/stop) in IRAM, to reduce latency caused by cache miss.
|
||||||
so that these functions can be IRAM-safe and able to be called in the other IRAM interrupt context.
|
If enabled, these functions can also be called when cache is disabled.
|
||||||
Enabling this option can improve driver performance as well.
|
|
||||||
|
|
||||||
config GPTIMER_ISR_IRAM_SAFE
|
config GPTIMER_ISR_CACHE_SAFE
|
||||||
bool "GPTimer ISR IRAM-Safe"
|
bool "Allow GPTimer ISR to execute when cache is disabled"
|
||||||
select GPTIMER_ISR_HANDLER_IN_IRAM
|
select GPTIMER_ISR_HANDLER_IN_IRAM
|
||||||
default n
|
default n
|
||||||
help
|
help
|
||||||
Ensure the GPTimer interrupt is IRAM-Safe by allowing the interrupt handler to be
|
Enable this option to allow the GPTimer Interrupt Service Routine (ISR)
|
||||||
executable when the cache is disabled (e.g. SPI Flash write).
|
to execute even when the cache is disabled. This can be useful in scenarios where the cache
|
||||||
|
might be turned off, but the GPTimer functionality is still required to operate correctly.
|
||||||
|
|
||||||
config GPTIMER_ENABLE_DEBUG_LOG
|
config GPTIMER_OBJ_CACHE_SAFE
|
||||||
bool "Enable debug log"
|
bool
|
||||||
default n
|
default n
|
||||||
help
|
help
|
||||||
whether to enable the debug log message for GPTimer driver.
|
This will ensure the GPTimer object will not be allocated from a memory region
|
||||||
Note that, this option only controls the GPTimer driver log, won't affect other drivers.
|
where its cache can be disabled.
|
||||||
|
|
||||||
|
config GPTIMER_ENABLE_DEBUG_LOG
|
||||||
|
bool "Force enable debug log"
|
||||||
|
default n
|
||||||
|
help
|
||||||
|
If enabled, GPTimer component will:
|
||||||
|
1. ignore the global logging settings
|
||||||
|
2. compile all log messages into the binary
|
||||||
|
3. set the runtime log level to VERBOSE
|
||||||
|
Please enable this option by caution, as it will increase the binary size.
|
||||||
|
|
||||||
endmenu
|
endmenu
|
||||||
|
@ -135,7 +135,7 @@ esp_err_t gptimer_get_captured_count(gptimer_handle_t timer, uint64_t *value);
|
|||||||
/**
|
/**
|
||||||
* @brief Group of supported GPTimer callbacks
|
* @brief Group of supported GPTimer callbacks
|
||||||
* @note The callbacks are all running under ISR environment
|
* @note The callbacks are all running under ISR environment
|
||||||
* @note When CONFIG_GPTIMER_ISR_IRAM_SAFE is enabled, the callback itself and functions called by it should be placed in IRAM.
|
* @note When CONFIG_GPTIMER_ISR_CACHE_SAFE is enabled, the callback itself and functions called by it should be placed in IRAM.
|
||||||
*/
|
*/
|
||||||
typedef struct {
|
typedef struct {
|
||||||
gptimer_alarm_cb_t on_alarm; /*!< Timer alarm callback */
|
gptimer_alarm_cb_t on_alarm; /*!< Timer alarm callback */
|
||||||
|
4
components/esp_driver_gptimer/sdkconfig.rename
Normal file
4
components/esp_driver_gptimer/sdkconfig.rename
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
# sdkconfig replacement configurations for deprecated options formatted as
|
||||||
|
# CONFIG_DEPRECATED_OPTION CONFIG_NEW_OPTION
|
||||||
|
|
||||||
|
CONFIG_GPTIMER_ISR_IRAM_SAFE CONFIG_GPTIMER_ISR_CACHE_SAFE
|
@ -1,27 +1,14 @@
|
|||||||
/*
|
/*
|
||||||
* SPDX-FileCopyrightText: 2022-2024 Espressif Systems (Shanghai) CO LTD
|
* SPDX-FileCopyrightText: 2022-2025 Espressif Systems (Shanghai) CO LTD
|
||||||
*
|
*
|
||||||
* SPDX-License-Identifier: Apache-2.0
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <sys/lock.h>
|
#include <sys/lock.h>
|
||||||
#include "sdkconfig.h"
|
|
||||||
#if CONFIG_GPTIMER_ENABLE_DEBUG_LOG
|
|
||||||
// The local log level must be defined before including esp_log.h
|
|
||||||
// Set the maximum log level for this source file
|
|
||||||
#define LOG_LOCAL_LEVEL ESP_LOG_DEBUG
|
|
||||||
#endif
|
|
||||||
#include "freertos/FreeRTOS.h"
|
|
||||||
#include "esp_attr.h"
|
|
||||||
#include "esp_err.h"
|
|
||||||
#include "esp_log.h"
|
|
||||||
#include "esp_check.h"
|
|
||||||
#include "driver/gptimer.h"
|
#include "driver/gptimer.h"
|
||||||
#include "esp_memory_utils.h"
|
|
||||||
#include "gptimer_priv.h"
|
#include "gptimer_priv.h"
|
||||||
|
#include "esp_memory_utils.h"
|
||||||
static const char *TAG = "gptimer";
|
|
||||||
|
|
||||||
static void gptimer_default_isr(void *args);
|
static void gptimer_default_isr(void *args);
|
||||||
|
|
||||||
@ -136,9 +123,6 @@ static esp_err_t gptimer_destroy(gptimer_t *timer)
|
|||||||
|
|
||||||
esp_err_t gptimer_new_timer(const gptimer_config_t *config, gptimer_handle_t *ret_timer)
|
esp_err_t gptimer_new_timer(const gptimer_config_t *config, gptimer_handle_t *ret_timer)
|
||||||
{
|
{
|
||||||
#if CONFIG_GPTIMER_ENABLE_DEBUG_LOG
|
|
||||||
esp_log_level_set(TAG, ESP_LOG_DEBUG);
|
|
||||||
#endif
|
|
||||||
esp_err_t ret = ESP_OK;
|
esp_err_t ret = ESP_OK;
|
||||||
gptimer_t *timer = NULL;
|
gptimer_t *timer = NULL;
|
||||||
ESP_RETURN_ON_FALSE(config && ret_timer, ESP_ERR_INVALID_ARG, TAG, "invalid argument");
|
ESP_RETURN_ON_FALSE(config && ret_timer, ESP_ERR_INVALID_ARG, TAG, "invalid argument");
|
||||||
@ -188,7 +172,7 @@ esp_err_t gptimer_new_timer(const gptimer_config_t *config, gptimer_handle_t *re
|
|||||||
timer->direction = config->direction;
|
timer->direction = config->direction;
|
||||||
timer->intr_priority = config->intr_priority;
|
timer->intr_priority = config->intr_priority;
|
||||||
timer->flags.intr_shared = config->flags.intr_shared;
|
timer->flags.intr_shared = config->flags.intr_shared;
|
||||||
ESP_LOGD(TAG, "new gptimer (%d,%d) at %p, resolution=%"PRIu32"Hz", group_id, timer_id, timer, timer->resolution_hz);
|
ESP_LOGD(TAG, "new gptimer (%d,%d) at %p, %zu bytes used", group_id, timer_id, timer, heap_caps_get_allocated_size(timer));
|
||||||
*ret_timer = timer;
|
*ret_timer = timer;
|
||||||
return ESP_OK;
|
return ESP_OK;
|
||||||
|
|
||||||
@ -231,7 +215,9 @@ esp_err_t gptimer_del_timer(gptimer_handle_t timer)
|
|||||||
|
|
||||||
esp_err_t gptimer_set_raw_count(gptimer_handle_t timer, unsigned long long value)
|
esp_err_t gptimer_set_raw_count(gptimer_handle_t timer, unsigned long long value)
|
||||||
{
|
{
|
||||||
ESP_RETURN_ON_FALSE_ISR(timer, ESP_ERR_INVALID_ARG, TAG, "invalid argument");
|
if (timer == NULL) {
|
||||||
|
return ESP_ERR_INVALID_ARG;
|
||||||
|
}
|
||||||
|
|
||||||
portENTER_CRITICAL_SAFE(&timer->spinlock);
|
portENTER_CRITICAL_SAFE(&timer->spinlock);
|
||||||
timer_hal_set_counter_value(&timer->hal, value);
|
timer_hal_set_counter_value(&timer->hal, value);
|
||||||
@ -241,7 +227,9 @@ esp_err_t gptimer_set_raw_count(gptimer_handle_t timer, unsigned long long value
|
|||||||
|
|
||||||
esp_err_t gptimer_get_raw_count(gptimer_handle_t timer, unsigned long long *value)
|
esp_err_t gptimer_get_raw_count(gptimer_handle_t timer, unsigned long long *value)
|
||||||
{
|
{
|
||||||
ESP_RETURN_ON_FALSE_ISR(timer && value, ESP_ERR_INVALID_ARG, TAG, "invalid argument");
|
if (timer == NULL || value == NULL) {
|
||||||
|
return ESP_ERR_INVALID_ARG;
|
||||||
|
}
|
||||||
|
|
||||||
portENTER_CRITICAL_SAFE(&timer->spinlock);
|
portENTER_CRITICAL_SAFE(&timer->spinlock);
|
||||||
*value = timer_hal_capture_and_get_counter_value(&timer->hal);
|
*value = timer_hal_capture_and_get_counter_value(&timer->hal);
|
||||||
@ -258,7 +246,9 @@ esp_err_t gptimer_get_resolution(gptimer_handle_t timer, uint32_t *out_resolutio
|
|||||||
|
|
||||||
esp_err_t gptimer_get_captured_count(gptimer_handle_t timer, uint64_t *value)
|
esp_err_t gptimer_get_captured_count(gptimer_handle_t timer, uint64_t *value)
|
||||||
{
|
{
|
||||||
ESP_RETURN_ON_FALSE_ISR(timer && value, ESP_ERR_INVALID_ARG, TAG, "invalid argument");
|
if (timer == NULL || value == NULL) {
|
||||||
|
return ESP_ERR_INVALID_ARG;
|
||||||
|
}
|
||||||
|
|
||||||
portENTER_CRITICAL_SAFE(&timer->spinlock);
|
portENTER_CRITICAL_SAFE(&timer->spinlock);
|
||||||
*value = timer_ll_get_counter_value(timer->hal.dev, timer->timer_id);
|
*value = timer_ll_get_counter_value(timer->hal.dev, timer->timer_id);
|
||||||
@ -274,7 +264,7 @@ esp_err_t gptimer_register_event_callbacks(gptimer_handle_t timer, const gptimer
|
|||||||
int group_id = group->group_id;
|
int group_id = group->group_id;
|
||||||
int timer_id = timer->timer_id;
|
int timer_id = timer->timer_id;
|
||||||
|
|
||||||
#if CONFIG_GPTIMER_ISR_IRAM_SAFE
|
#if CONFIG_GPTIMER_ISR_CACHE_SAFE
|
||||||
if (cbs->on_alarm) {
|
if (cbs->on_alarm) {
|
||||||
ESP_RETURN_ON_FALSE(esp_ptr_in_iram(cbs->on_alarm), ESP_ERR_INVALID_ARG, TAG, "on_alarm callback not in IRAM");
|
ESP_RETURN_ON_FALSE(esp_ptr_in_iram(cbs->on_alarm), ESP_ERR_INVALID_ARG, TAG, "on_alarm callback not in IRAM");
|
||||||
}
|
}
|
||||||
@ -308,14 +298,22 @@ esp_err_t gptimer_register_event_callbacks(gptimer_handle_t timer, const gptimer
|
|||||||
|
|
||||||
esp_err_t gptimer_set_alarm_action(gptimer_handle_t timer, const gptimer_alarm_config_t *config)
|
esp_err_t gptimer_set_alarm_action(gptimer_handle_t timer, const gptimer_alarm_config_t *config)
|
||||||
{
|
{
|
||||||
ESP_RETURN_ON_FALSE_ISR(timer, ESP_ERR_INVALID_ARG, TAG, "invalid argument");
|
if (timer == NULL) {
|
||||||
|
return ESP_ERR_INVALID_ARG;
|
||||||
|
}
|
||||||
if (config) {
|
if (config) {
|
||||||
#if CONFIG_GPTIMER_CTRL_FUNC_IN_IRAM
|
#if CONFIG_GPTIMER_CTRL_FUNC_IN_IRAM
|
||||||
ESP_RETURN_ON_FALSE_ISR(esp_ptr_internal(config), ESP_ERR_INVALID_ARG, TAG, "alarm config struct not in internal RAM");
|
// when the function is placed in IRAM, we expect the config struct is also placed in internal RAM
|
||||||
|
// if the cache is disabled, the function can still access the config struct
|
||||||
|
if (esp_ptr_internal(config) == false) {
|
||||||
|
return ESP_ERR_INVALID_ARG;
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
// When auto_reload is enabled, alarm_count should not be equal to reload_count
|
// When auto_reload is enabled, alarm_count should not be equal to reload_count
|
||||||
bool valid_auto_reload = !config->flags.auto_reload_on_alarm || config->alarm_count != config->reload_count;
|
bool valid_auto_reload = !config->flags.auto_reload_on_alarm || config->alarm_count != config->reload_count;
|
||||||
ESP_RETURN_ON_FALSE_ISR(valid_auto_reload, ESP_ERR_INVALID_ARG, TAG, "reload count can't equal to alarm count");
|
if (valid_auto_reload == false) {
|
||||||
|
return ESP_ERR_INVALID_ARG;
|
||||||
|
}
|
||||||
|
|
||||||
portENTER_CRITICAL_SAFE(&timer->spinlock);
|
portENTER_CRITICAL_SAFE(&timer->spinlock);
|
||||||
timer->reload_count = config->reload_count;
|
timer->reload_count = config->reload_count;
|
||||||
@ -343,6 +341,7 @@ esp_err_t gptimer_set_alarm_action(gptimer_handle_t timer, const gptimer_alarm_c
|
|||||||
esp_err_t gptimer_enable(gptimer_handle_t timer)
|
esp_err_t gptimer_enable(gptimer_handle_t timer)
|
||||||
{
|
{
|
||||||
ESP_RETURN_ON_FALSE(timer, ESP_ERR_INVALID_ARG, TAG, "invalid argument");
|
ESP_RETURN_ON_FALSE(timer, ESP_ERR_INVALID_ARG, TAG, "invalid argument");
|
||||||
|
// the only acceptable FSM change: init->enable
|
||||||
gptimer_fsm_t expected_fsm = GPTIMER_FSM_INIT;
|
gptimer_fsm_t expected_fsm = GPTIMER_FSM_INIT;
|
||||||
ESP_RETURN_ON_FALSE(atomic_compare_exchange_strong(&timer->fsm, &expected_fsm, GPTIMER_FSM_ENABLE),
|
ESP_RETURN_ON_FALSE(atomic_compare_exchange_strong(&timer->fsm, &expected_fsm, GPTIMER_FSM_ENABLE),
|
||||||
ESP_ERR_INVALID_STATE, TAG, "timer not in init state");
|
ESP_ERR_INVALID_STATE, TAG, "timer not in init state");
|
||||||
@ -363,6 +362,7 @@ esp_err_t gptimer_enable(gptimer_handle_t timer)
|
|||||||
esp_err_t gptimer_disable(gptimer_handle_t timer)
|
esp_err_t gptimer_disable(gptimer_handle_t timer)
|
||||||
{
|
{
|
||||||
ESP_RETURN_ON_FALSE(timer, ESP_ERR_INVALID_ARG, TAG, "invalid argument");
|
ESP_RETURN_ON_FALSE(timer, ESP_ERR_INVALID_ARG, TAG, "invalid argument");
|
||||||
|
// the only acceptable FSM change: enable->init
|
||||||
gptimer_fsm_t expected_fsm = GPTIMER_FSM_ENABLE;
|
gptimer_fsm_t expected_fsm = GPTIMER_FSM_ENABLE;
|
||||||
ESP_RETURN_ON_FALSE(atomic_compare_exchange_strong(&timer->fsm, &expected_fsm, GPTIMER_FSM_INIT),
|
ESP_RETURN_ON_FALSE(atomic_compare_exchange_strong(&timer->fsm, &expected_fsm, GPTIMER_FSM_INIT),
|
||||||
ESP_ERR_INVALID_STATE, TAG, "timer not in enable state");
|
ESP_ERR_INVALID_STATE, TAG, "timer not in enable state");
|
||||||
@ -382,7 +382,14 @@ esp_err_t gptimer_disable(gptimer_handle_t timer)
|
|||||||
|
|
||||||
esp_err_t gptimer_start(gptimer_handle_t timer)
|
esp_err_t gptimer_start(gptimer_handle_t timer)
|
||||||
{
|
{
|
||||||
ESP_RETURN_ON_FALSE_ISR(timer, ESP_ERR_INVALID_ARG, TAG, "invalid argument");
|
if (timer == NULL) {
|
||||||
|
return ESP_ERR_INVALID_ARG;
|
||||||
|
}
|
||||||
|
|
||||||
|
// if the timer is already started, do nothing
|
||||||
|
if (atomic_load(&timer->fsm) == GPTIMER_FSM_RUN) {
|
||||||
|
return ESP_OK;
|
||||||
|
}
|
||||||
|
|
||||||
gptimer_fsm_t expected_fsm = GPTIMER_FSM_ENABLE;
|
gptimer_fsm_t expected_fsm = GPTIMER_FSM_ENABLE;
|
||||||
if (atomic_compare_exchange_strong(&timer->fsm, &expected_fsm, GPTIMER_FSM_RUN_WAIT)) {
|
if (atomic_compare_exchange_strong(&timer->fsm, &expected_fsm, GPTIMER_FSM_RUN_WAIT)) {
|
||||||
@ -396,7 +403,8 @@ esp_err_t gptimer_start(gptimer_handle_t timer)
|
|||||||
atomic_store(&timer->fsm, GPTIMER_FSM_RUN);
|
atomic_store(&timer->fsm, GPTIMER_FSM_RUN);
|
||||||
portEXIT_CRITICAL_SAFE(&timer->spinlock);
|
portEXIT_CRITICAL_SAFE(&timer->spinlock);
|
||||||
} else {
|
} else {
|
||||||
ESP_RETURN_ON_FALSE_ISR(false, ESP_ERR_INVALID_STATE, TAG, "timer is not ready for a new start");
|
// return error if the timer is not in the expected state
|
||||||
|
return ESP_ERR_INVALID_STATE;
|
||||||
}
|
}
|
||||||
|
|
||||||
return ESP_OK;
|
return ESP_OK;
|
||||||
@ -404,7 +412,15 @@ esp_err_t gptimer_start(gptimer_handle_t timer)
|
|||||||
|
|
||||||
esp_err_t gptimer_stop(gptimer_handle_t timer)
|
esp_err_t gptimer_stop(gptimer_handle_t timer)
|
||||||
{
|
{
|
||||||
ESP_RETURN_ON_FALSE_ISR(timer, ESP_ERR_INVALID_ARG, TAG, "invalid argument");
|
if (timer == NULL) {
|
||||||
|
// not printing error message here because the return value already indicates the error well
|
||||||
|
return ESP_ERR_INVALID_ARG;
|
||||||
|
}
|
||||||
|
|
||||||
|
// if the timer is not started, do nothing
|
||||||
|
if (atomic_load(&timer->fsm) == GPTIMER_FSM_ENABLE) {
|
||||||
|
return ESP_OK;
|
||||||
|
}
|
||||||
|
|
||||||
gptimer_fsm_t expected_fsm = GPTIMER_FSM_RUN;
|
gptimer_fsm_t expected_fsm = GPTIMER_FSM_RUN;
|
||||||
if (atomic_compare_exchange_strong(&timer->fsm, &expected_fsm, GPTIMER_FSM_ENABLE_WAIT)) {
|
if (atomic_compare_exchange_strong(&timer->fsm, &expected_fsm, GPTIMER_FSM_ENABLE_WAIT)) {
|
||||||
@ -415,7 +431,8 @@ esp_err_t gptimer_stop(gptimer_handle_t timer)
|
|||||||
atomic_store(&timer->fsm, GPTIMER_FSM_ENABLE);
|
atomic_store(&timer->fsm, GPTIMER_FSM_ENABLE);
|
||||||
portEXIT_CRITICAL_SAFE(&timer->spinlock);
|
portEXIT_CRITICAL_SAFE(&timer->spinlock);
|
||||||
} else {
|
} else {
|
||||||
ESP_RETURN_ON_FALSE_ISR(false, ESP_ERR_INVALID_STATE, TAG, "timer is not running");
|
// return error if the timer is not in the expected state
|
||||||
|
return ESP_ERR_INVALID_STATE;
|
||||||
}
|
}
|
||||||
|
|
||||||
return ESP_OK;
|
return ESP_OK;
|
||||||
|
@ -1,18 +1,14 @@
|
|||||||
/*
|
/*
|
||||||
* SPDX-FileCopyrightText: 2022-2024 Espressif Systems (Shanghai) CO LTD
|
* SPDX-FileCopyrightText: 2022-2025 Espressif Systems (Shanghai) CO LTD
|
||||||
*
|
*
|
||||||
* SPDX-License-Identifier: Apache-2.0
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <sys/lock.h>
|
#include <sys/lock.h>
|
||||||
#include "esp_check.h"
|
|
||||||
#include "esp_clk_tree.h"
|
#include "esp_clk_tree.h"
|
||||||
#include "esp_private/esp_clk_tree_common.h"
|
|
||||||
#include "esp_private/gptimer.h"
|
#include "esp_private/gptimer.h"
|
||||||
#include "gptimer_priv.h"
|
#include "gptimer_priv.h"
|
||||||
#include "soc/soc_caps.h"
|
#include "esp_private/esp_clk_tree_common.h"
|
||||||
|
|
||||||
static const char *TAG = "gptimer";
|
|
||||||
|
|
||||||
typedef struct gptimer_platform_t {
|
typedef struct gptimer_platform_t {
|
||||||
_lock_t mutex; // platform level mutex lock
|
_lock_t mutex; // platform level mutex lock
|
||||||
@ -182,3 +178,11 @@ int gptimer_get_group_id(gptimer_handle_t timer, int *group_id)
|
|||||||
*group_id = timer->group->group_id;
|
*group_id = timer->group->group_id;
|
||||||
return ESP_OK;
|
return ESP_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if CONFIG_GPTIMER_ENABLE_DEBUG_LOG
|
||||||
|
__attribute__((constructor))
|
||||||
|
static void gptimer_override_default_log_level(void)
|
||||||
|
{
|
||||||
|
esp_log_level_set(TAG, ESP_LOG_VERBOSE);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
@ -1,26 +1,17 @@
|
|||||||
/*
|
/*
|
||||||
* SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD
|
* SPDX-FileCopyrightText: 2022-2025 Espressif Systems (Shanghai) CO LTD
|
||||||
*
|
*
|
||||||
* SPDX-License-Identifier: Apache-2.0
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <sys/lock.h>
|
#include <sys/lock.h>
|
||||||
#include "sdkconfig.h"
|
|
||||||
#include "freertos/FreeRTOS.h"
|
|
||||||
#include "esp_err.h"
|
|
||||||
#include "esp_log.h"
|
|
||||||
#include "esp_check.h"
|
|
||||||
#include "esp_heap_caps.h"
|
|
||||||
#include "driver/gptimer.h"
|
#include "driver/gptimer.h"
|
||||||
#include "gptimer_priv.h"
|
#include "gptimer_priv.h"
|
||||||
#include "hal/timer_ll.h"
|
|
||||||
#include "esp_private/etm_interface.h"
|
#include "esp_private/etm_interface.h"
|
||||||
|
|
||||||
#define ETM_MEM_ALLOC_CAPS MALLOC_CAP_DEFAULT
|
#define ETM_MEM_ALLOC_CAPS MALLOC_CAP_DEFAULT
|
||||||
|
|
||||||
static const char *TAG = "gptimer-etm";
|
|
||||||
|
|
||||||
static esp_err_t gptimer_del_etm_event(esp_etm_event_t *event)
|
static esp_err_t gptimer_del_etm_event(esp_etm_event_t *event)
|
||||||
{
|
{
|
||||||
free(event);
|
free(event);
|
||||||
@ -36,17 +27,16 @@ static esp_err_t gptimer_del_etm_task(esp_etm_task_t *task)
|
|||||||
esp_err_t gptimer_new_etm_event(gptimer_handle_t timer, const gptimer_etm_event_config_t *config, esp_etm_event_handle_t *out_event)
|
esp_err_t gptimer_new_etm_event(gptimer_handle_t timer, const gptimer_etm_event_config_t *config, esp_etm_event_handle_t *out_event)
|
||||||
{
|
{
|
||||||
esp_etm_event_t *event = NULL;
|
esp_etm_event_t *event = NULL;
|
||||||
esp_err_t ret = ESP_OK;
|
ESP_RETURN_ON_FALSE(timer && config && out_event, ESP_ERR_INVALID_ARG, TAG, "invalid argument");
|
||||||
ESP_GOTO_ON_FALSE(timer && config && out_event, ESP_ERR_INVALID_ARG, err, TAG, "invalid argument");
|
ESP_RETURN_ON_FALSE(config->event_type < GPTIMER_ETM_EVENT_MAX, ESP_ERR_INVALID_ARG, TAG, "invalid event type");
|
||||||
ESP_GOTO_ON_FALSE(config->event_type < GPTIMER_ETM_EVENT_MAX, ESP_ERR_INVALID_ARG, err, TAG, "invalid event type");
|
|
||||||
event = heap_caps_calloc(1, sizeof(esp_etm_event_t), ETM_MEM_ALLOC_CAPS);
|
event = heap_caps_calloc(1, sizeof(esp_etm_event_t), ETM_MEM_ALLOC_CAPS);
|
||||||
ESP_GOTO_ON_FALSE(event, ESP_ERR_NO_MEM, err, TAG, "no memory for ETM event");
|
ESP_RETURN_ON_FALSE(event, ESP_ERR_NO_MEM, TAG, "no memory for ETM event");
|
||||||
|
|
||||||
|
// get the event ID that can be recognized by ETM hardware
|
||||||
gptimer_group_t *group = timer->group;
|
gptimer_group_t *group = timer->group;
|
||||||
int group_id = group->group_id;
|
int group_id = group->group_id;
|
||||||
int timer_id = timer->timer_id;
|
int timer_id = timer->timer_id;
|
||||||
uint32_t event_id = TIMER_LL_ETM_EVENT_TABLE(group_id, timer_id, config->event_type);
|
uint32_t event_id = TIMER_LL_ETM_EVENT_TABLE(group_id, timer_id, config->event_type);
|
||||||
ESP_GOTO_ON_FALSE(event_id != 0, ESP_ERR_NOT_SUPPORTED, err, TAG, "not supported event type");
|
|
||||||
|
|
||||||
// fill the ETM event object
|
// fill the ETM event object
|
||||||
event->event_id = event_id;
|
event->event_id = event_id;
|
||||||
@ -54,28 +44,21 @@ esp_err_t gptimer_new_etm_event(gptimer_handle_t timer, const gptimer_etm_event_
|
|||||||
event->del = gptimer_del_etm_event;
|
event->del = gptimer_del_etm_event;
|
||||||
*out_event = event;
|
*out_event = event;
|
||||||
return ESP_OK;
|
return ESP_OK;
|
||||||
|
|
||||||
err:
|
|
||||||
if (event) {
|
|
||||||
gptimer_del_etm_event(event);
|
|
||||||
}
|
|
||||||
return ret;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
esp_err_t gptimer_new_etm_task(gptimer_handle_t timer, const gptimer_etm_task_config_t *config, esp_etm_task_handle_t *out_task)
|
esp_err_t gptimer_new_etm_task(gptimer_handle_t timer, const gptimer_etm_task_config_t *config, esp_etm_task_handle_t *out_task)
|
||||||
{
|
{
|
||||||
esp_etm_task_t *task = NULL;
|
esp_etm_task_t *task = NULL;
|
||||||
esp_err_t ret = ESP_OK;
|
ESP_RETURN_ON_FALSE(timer && config && out_task, ESP_ERR_INVALID_ARG, TAG, "invalid argument");
|
||||||
ESP_GOTO_ON_FALSE(timer && config && out_task, ESP_ERR_INVALID_ARG, err, TAG, "invalid argument");
|
ESP_RETURN_ON_FALSE(config->task_type < GPTIMER_ETM_TASK_MAX, ESP_ERR_INVALID_ARG, TAG, "invalid task type");
|
||||||
ESP_GOTO_ON_FALSE(config->task_type < GPTIMER_ETM_TASK_MAX, ESP_ERR_INVALID_ARG, err, TAG, "invalid task type");
|
|
||||||
task = heap_caps_calloc(1, sizeof(esp_etm_task_t), ETM_MEM_ALLOC_CAPS);
|
task = heap_caps_calloc(1, sizeof(esp_etm_task_t), ETM_MEM_ALLOC_CAPS);
|
||||||
ESP_GOTO_ON_FALSE(task, ESP_ERR_NO_MEM, err, TAG, "no memory for ETM task");
|
ESP_RETURN_ON_FALSE(task, ESP_ERR_NO_MEM, TAG, "no memory for ETM task");
|
||||||
|
|
||||||
|
// get the task ID that can be recognized by ETM hardware
|
||||||
gptimer_group_t *group = timer->group;
|
gptimer_group_t *group = timer->group;
|
||||||
int group_id = group->group_id;
|
int group_id = group->group_id;
|
||||||
int timer_id = timer->timer_id;
|
int timer_id = timer->timer_id;
|
||||||
uint32_t task_id = TIMER_LL_ETM_TASK_TABLE(group_id, timer_id, config->task_type);
|
uint32_t task_id = TIMER_LL_ETM_TASK_TABLE(group_id, timer_id, config->task_type);
|
||||||
ESP_GOTO_ON_FALSE(task_id != 0, ESP_ERR_NOT_SUPPORTED, err, TAG, "not supported task type");
|
|
||||||
|
|
||||||
// fill the ETM task object
|
// fill the ETM task object
|
||||||
task->task_id = task_id;
|
task->task_id = task_id;
|
||||||
@ -83,10 +66,4 @@ esp_err_t gptimer_new_etm_task(gptimer_handle_t timer, const gptimer_etm_task_co
|
|||||||
task->del = gptimer_del_etm_task;
|
task->del = gptimer_del_etm_task;
|
||||||
*out_task = task;
|
*out_task = task;
|
||||||
return ESP_OK;
|
return ESP_OK;
|
||||||
|
|
||||||
err:
|
|
||||||
if (task) {
|
|
||||||
gptimer_del_etm_task(task);
|
|
||||||
}
|
|
||||||
return ret;
|
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* SPDX-FileCopyrightText: 2022-2024 Espressif Systems (Shanghai) CO LTD
|
* SPDX-FileCopyrightText: 2022-2025 Espressif Systems (Shanghai) CO LTD
|
||||||
*
|
*
|
||||||
* SPDX-License-Identifier: Apache-2.0
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
*/
|
*/
|
||||||
@ -9,17 +9,25 @@
|
|||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include <stdatomic.h>
|
#include <stdatomic.h>
|
||||||
#include "sdkconfig.h"
|
#include "sdkconfig.h"
|
||||||
|
#if CONFIG_GPTIMER_ENABLE_DEBUG_LOG
|
||||||
|
// The local log level must be defined before including esp_log.h
|
||||||
|
// Set the maximum log level for gptimer driver
|
||||||
|
#define LOG_LOCAL_LEVEL ESP_LOG_VERBOSE
|
||||||
|
#endif
|
||||||
#include "soc/soc_caps.h"
|
#include "soc/soc_caps.h"
|
||||||
#include "freertos/FreeRTOS.h"
|
#include "freertos/FreeRTOS.h"
|
||||||
#include "esp_err.h"
|
#include "esp_err.h"
|
||||||
|
#include "esp_log.h"
|
||||||
|
#include "esp_check.h"
|
||||||
|
#include "esp_attr.h"
|
||||||
#include "esp_intr_alloc.h"
|
#include "esp_intr_alloc.h"
|
||||||
#include "esp_heap_caps.h"
|
#include "esp_heap_caps.h"
|
||||||
#include "clk_ctrl_os.h"
|
|
||||||
#include "esp_pm.h"
|
#include "esp_pm.h"
|
||||||
#include "soc/timer_periph.h"
|
#include "soc/timer_periph.h"
|
||||||
#include "hal/timer_types.h"
|
#include "hal/timer_types.h"
|
||||||
#include "hal/timer_hal.h"
|
#include "hal/timer_hal.h"
|
||||||
#include "hal/timer_ll.h"
|
#include "hal/timer_ll.h"
|
||||||
|
#include "clk_ctrl_os.h"
|
||||||
#include "esp_private/sleep_retention.h"
|
#include "esp_private/sleep_retention.h"
|
||||||
#include "esp_private/periph_ctrl.h"
|
#include "esp_private/periph_ctrl.h"
|
||||||
|
|
||||||
@ -29,13 +37,13 @@ extern "C" {
|
|||||||
|
|
||||||
// If ISR handler is allowed to run whilst cache is disabled,
|
// If ISR handler is allowed to run whilst cache is disabled,
|
||||||
// Make sure all the code and related variables used by the handler are in the SRAM
|
// Make sure all the code and related variables used by the handler are in the SRAM
|
||||||
#if CONFIG_GPTIMER_ISR_IRAM_SAFE || CONFIG_GPTIMER_CTRL_FUNC_IN_IRAM
|
#if CONFIG_GPTIMER_OBJ_CACHE_SAFE
|
||||||
#define GPTIMER_MEM_ALLOC_CAPS (MALLOC_CAP_INTERNAL | MALLOC_CAP_8BIT)
|
#define GPTIMER_MEM_ALLOC_CAPS (MALLOC_CAP_INTERNAL | MALLOC_CAP_8BIT)
|
||||||
#else
|
#else
|
||||||
#define GPTIMER_MEM_ALLOC_CAPS MALLOC_CAP_DEFAULT
|
#define GPTIMER_MEM_ALLOC_CAPS MALLOC_CAP_DEFAULT
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if CONFIG_GPTIMER_ISR_IRAM_SAFE
|
#if CONFIG_GPTIMER_ISR_CACHE_SAFE
|
||||||
#define GPTIMER_INTR_ALLOC_FLAGS (ESP_INTR_FLAG_IRAM | ESP_INTR_FLAG_INTRDISABLED)
|
#define GPTIMER_INTR_ALLOC_FLAGS (ESP_INTR_FLAG_IRAM | ESP_INTR_FLAG_INTRDISABLED)
|
||||||
#else
|
#else
|
||||||
#define GPTIMER_INTR_ALLOC_FLAGS ESP_INTR_FLAG_INTRDISABLED
|
#define GPTIMER_INTR_ALLOC_FLAGS ESP_INTR_FLAG_INTRDISABLED
|
||||||
@ -53,6 +61,10 @@ extern "C" {
|
|||||||
#define GPTIMER_CLOCK_SRC_ATOMIC()
|
#define GPTIMER_CLOCK_SRC_ATOMIC()
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
///!< Logging settings
|
||||||
|
#define TAG "gptimer"
|
||||||
|
|
||||||
|
///!< Forward declaration
|
||||||
typedef struct gptimer_t gptimer_t;
|
typedef struct gptimer_t gptimer_t;
|
||||||
|
|
||||||
typedef struct gptimer_group_t {
|
typedef struct gptimer_group_t {
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
set(srcs "test_app_main.c"
|
set(srcs "test_app_main.c"
|
||||||
"test_gptimer.c")
|
"test_gptimer.c")
|
||||||
|
|
||||||
if(CONFIG_GPTIMER_ISR_IRAM_SAFE)
|
if(CONFIG_GPTIMER_ISR_CACHE_SAFE)
|
||||||
list(APPEND srcs "test_gptimer_iram.c")
|
list(APPEND srcs "test_gptimer_iram.c")
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
@ -13,11 +13,11 @@
|
|||||||
#include "soc/soc_caps.h"
|
#include "soc/soc_caps.h"
|
||||||
#include "esp_attr.h"
|
#include "esp_attr.h"
|
||||||
|
|
||||||
#if CONFIG_GPTIMER_ISR_IRAM_SAFE
|
#if CONFIG_GPTIMER_ISR_CACHE_SAFE
|
||||||
#define TEST_ALARM_CALLBACK_ATTR IRAM_ATTR
|
#define TEST_ALARM_CALLBACK_ATTR IRAM_ATTR
|
||||||
#else
|
#else
|
||||||
#define TEST_ALARM_CALLBACK_ATTR
|
#define TEST_ALARM_CALLBACK_ATTR
|
||||||
#endif // CONFIG_GPTIMER_ISR_IRAM_SAFE
|
#endif // CONFIG_GPTIMER_ISR_CACHE_SAFE
|
||||||
|
|
||||||
TEST_CASE("gptimer_set_get_raw_count", "[gptimer]")
|
TEST_CASE("gptimer_set_get_raw_count", "[gptimer]")
|
||||||
{
|
{
|
||||||
@ -299,7 +299,7 @@ TEST_ALARM_CALLBACK_ATTR static bool test_gptimer_alarm_normal_callback(gptimer_
|
|||||||
* Also should account for the inaccuracy of the systick during DFS.
|
* Also should account for the inaccuracy of the systick during DFS.
|
||||||
*/
|
*/
|
||||||
#if CONFIG_PM_ENABLE
|
#if CONFIG_PM_ENABLE
|
||||||
#define GPTIMER_ONE_SHOT_ALARM_COUNT_DELTA 15000
|
#define GPTIMER_ONE_SHOT_ALARM_COUNT_DELTA 50000
|
||||||
#else
|
#else
|
||||||
#define GPTIMER_ONE_SHOT_ALARM_COUNT_DELTA 1000
|
#define GPTIMER_ONE_SHOT_ALARM_COUNT_DELTA 1000
|
||||||
#endif // CONFIG_PM_ENABLE
|
#endif // CONFIG_PM_ENABLE
|
||||||
|
@ -13,11 +13,11 @@
|
|||||||
#include "driver/gpio_etm.h"
|
#include "driver/gpio_etm.h"
|
||||||
#include "driver/gpio.h"
|
#include "driver/gpio.h"
|
||||||
|
|
||||||
#if CONFIG_GPTIMER_ISR_IRAM_SAFE
|
#if CONFIG_GPTIMER_ISR_CACHE_SAFE
|
||||||
#define TEST_ALARM_CALLBACK_ATTR IRAM_ATTR
|
#define TEST_ALARM_CALLBACK_ATTR IRAM_ATTR
|
||||||
#else
|
#else
|
||||||
#define TEST_ALARM_CALLBACK_ATTR
|
#define TEST_ALARM_CALLBACK_ATTR
|
||||||
#endif // CONFIG_GPTIMER_ISR_IRAM_SAFE
|
#endif // CONFIG_GPTIMER_ISR_CACHE_SAFE
|
||||||
|
|
||||||
TEST_ALARM_CALLBACK_ATTR
|
TEST_ALARM_CALLBACK_ATTR
|
||||||
static bool on_gptimer_alarm_cb(gptimer_handle_t timer, const gptimer_alarm_event_data_t *edata, void *user_ctx)
|
static bool on_gptimer_alarm_cb(gptimer_handle_t timer, const gptimer_alarm_event_data_t *edata, void *user_ctx)
|
||||||
|
@ -23,7 +23,7 @@ static void IRAM_ATTR test_delay_post_cache_disable(void *args)
|
|||||||
esp_rom_delay_us(1000);
|
esp_rom_delay_us(1000);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_CASE("gptimer_interrupt_iram_safe", "[gptimer]")
|
TEST_CASE("gptimer works with cache disabled", "[gptimer]")
|
||||||
{
|
{
|
||||||
gptimer_handle_t gptimer = NULL;
|
gptimer_handle_t gptimer = NULL;
|
||||||
gptimer_config_t timer_config = {
|
gptimer_config_t timer_config = {
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
CONFIG_COMPILER_DUMP_RTL_FILES=y
|
CONFIG_COMPILER_DUMP_RTL_FILES=y
|
||||||
CONFIG_GPTIMER_CTRL_FUNC_IN_IRAM=y
|
CONFIG_GPTIMER_CTRL_FUNC_IN_IRAM=y
|
||||||
CONFIG_GPTIMER_ISR_IRAM_SAFE=y
|
CONFIG_GPTIMER_ISR_CACHE_SAFE=y
|
||||||
CONFIG_COMPILER_OPTIMIZATION_NONE=y
|
CONFIG_COMPILER_OPTIMIZATION_NONE=y
|
||||||
# place non-ISR FreeRTOS functions in Flash
|
# place non-ISR FreeRTOS functions in Flash
|
||||||
CONFIG_FREERTOS_PLACE_FUNCTIONS_INTO_FLASH=y
|
CONFIG_FREERTOS_PLACE_FUNCTIONS_INTO_FLASH=y
|
Loading…
x
Reference in New Issue
Block a user