first commit

This commit is contained in:
2026-05-22 22:05:03 +03:00
commit 43393d2692
33463 changed files with 9249702 additions and 0 deletions
@@ -0,0 +1,153 @@
/*
* SPDX-FileCopyrightText: 2015-2023 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#pragma once
#ifdef __cplusplus
extern "C" {
#endif
#ifndef __ASSEMBLER__
#include <stdbool.h>
#include "sdkconfig.h"
#include "soc/soc.h" // [refactor-todo] IDF-2297
#include "esp_err.h"
#include "esp_cpu.h"
/*
* @brief Structure used for backtracing
*
* This structure stores the backtrace information of a particular stack frame
* (i.e. the PC and SP). This structure is used iteratively with the
* esp_cpu_get_next_backtrace_frame() function to traverse each frame within a
* single stack. The next_pc represents the PC of the current frame's caller, thus
* a next_pc of 0 indicates that the current frame is the last frame on the stack.
*
* @note Call esp_backtrace_get_start() to obtain initialization values for
* this structure
*/
typedef struct {
uint32_t pc; /* PC of the current frame */
uint32_t sp; /* SP of the current frame */
uint32_t next_pc; /* PC of the current frame's caller */
const void *exc_frame; /* Pointer to the full frame data structure, if applicable */
} esp_backtrace_frame_t;
/**
* @brief If an OCD is connected over JTAG. set breakpoint 0 to the given function
* address. Do nothing otherwise.
* @param fn Pointer to the target breakpoint position
*/
void esp_set_breakpoint_if_jtag(void *fn);
/**
* Get the first frame of the current stack's backtrace
*
* Given the following function call flow (B -> A -> X -> esp_backtrace_get_start),
* this function will do the following.
* - Flush CPU registers and window frames onto the current stack
* - Return PC and SP of function A (i.e. start of the stack's backtrace)
* - Return PC of function B (i.e. next_pc)
*
* @note This function is implemented in assembly
*
* @param[out] pc PC of the first frame in the backtrace
* @param[out] sp SP of the first frame in the backtrace
* @param[out] next_pc PC of the first frame's caller
*/
extern void esp_backtrace_get_start(uint32_t *pc, uint32_t *sp, uint32_t *next_pc);
/**
* Get the next frame on a stack for backtracing
*
* Given a stack frame(i), this function will obtain the next stack frame(i-1)
* on the same call stack (i.e. the caller of frame(i)). This function is meant to be
* called iteratively when doing a backtrace.
*
* Entry Conditions: Frame structure containing valid SP and next_pc
* Exit Conditions:
* - Frame structure updated with SP and PC of frame(i-1). next_pc now points to frame(i-2).
* - If a next_pc of 0 is returned, it indicates that frame(i-1) is last frame on the stack
*
* @param[inout] frame Pointer to frame structure
*
* @return
* - True if the SP and PC of the next frame(i-1) are sane
* - False otherwise
*/
bool esp_backtrace_get_next_frame(esp_backtrace_frame_t *frame);
/**
* @brief Print the backtrace from specified frame.
*
* @param depth The maximum number of stack frames to print (should be > 0)
* @param frame Starting frame to print from
* @param panic Indicator if backtrace print is during a system panic
*
* @note On the ESP32, users must call esp_backtrace_get_start() first to flush the stack.
* @note If a esp_backtrace_frame_t* frame is obtained though a call to esp_backtrace_get_start()
* from some example function func_a(), then frame is only valid within the frame/scope of func_a().
* Users should not attempt to pass/use frame other frames within the same stack of different stacks.
*
* @return
* - ESP_OK Backtrace successfully printed to completion or to depth limit
* - ESP_FAIL Backtrace is corrupted
*/
esp_err_t esp_backtrace_print_from_frame(int depth, const esp_backtrace_frame_t* frame, bool panic);
/**
* @brief Print the backtrace of the current stack
*
* @param depth The maximum number of stack frames to print (should be > 0)
*
* @note On RISC-V targets printing backtrace at run-time is only available if
* CONFIG_ESP_SYSTEM_USE_EH_FRAME is selected. Otherwise we simply print
* a register dump. Function assumes it is called in a context where the
* calling task will not migrate to another core, e.g. interrupts disabled/panic handler.
*
* @return
* - ESP_OK Backtrace successfully printed to completion or to depth limit
* - ESP_FAIL Backtrace is corrupted
*/
esp_err_t esp_backtrace_print(int depth);
/**
* @brief Print the backtrace of all tasks
*
* @param depth The maximum number of stack frames to print (must be > 0)
*
* @note Users must ensure that no tasks are created or deleted while this function is running.
* @note This function must be called from a task context.
*
* @return
* - ESP_OK All backtraces successfully printed to completion or to depth limit
* - ESP_FAIL One or more backtraces are corrupt
*/
esp_err_t esp_backtrace_print_all_tasks(int depth);
/**
* @brief Set a watchpoint to break/panic when a certain memory range is accessed.
* Superseded by esp_cpu_set_watchpoint in esp_cpu.h.
*/
static inline __attribute__((deprecated)) esp_err_t esp_set_watchpoint(int no, void *adr, int size, int flags)
{
return esp_cpu_set_watchpoint(no, adr, size, (esp_cpu_watchpoint_trigger_t)flags);
}
/**
* @brief Set a watchpoint to break/panic when a certain memory range is accessed.
* Superseded by esp_cpu_clear_watchpoint in esp_cpu.h.
*/
static inline __attribute__((deprecated)) void esp_clear_watchpoint(int no)
{
esp_cpu_clear_watchpoint(no);
}
#endif
#ifdef __cplusplus
}
#endif
@@ -0,0 +1,54 @@
/*
* SPDX-FileCopyrightText: 2015-2024 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#pragma once
#include <stdbool.h>
#include "freertos/FreeRTOS.h"
#include "freertos/semphr.h"
#include "freertos/task.h"
#include "esp_debug_helpers.h"
#include "esp_log.h"
#ifdef __cplusplus
extern "C" {
#endif
typedef void (*shared_stack_function)(void);
#define ESP_EXECUTE_EXPRESSION_WITH_STACK(lock, stack, stack_size, expression) \
esp_execute_shared_stack_function(lock, stack, stack_size, expression)
/**
* @brief Calls function on user defined shared stack space
*
* After returning, the original stack is used again.
*
* @warning This function does minimal preparation of the provided piece of memory (\c stack).
* DO NOT do any of the following in \c function or any of its callees:
* * Use Thread-local storage
* * Use the Floating-point unit on ESP32-P4
* * Use the AI co-processor on ESP32-P4
* * Call vTaskDelete(NULL) (deleting the currently running task)
* Furthermore, backtraces will be wrong when called from \c function or any of its callees.
* The limitations are quite sever, so that we might deprecate this function in the future.
* If you have any use case which can only be implemented using this function, please open
* an issue on github.
*
* @param lock Mutex object to protect in case of shared stack
* @param stack Pointer to user allocated stack
* @param stack_size Size of current stack in bytes
* @param function pointer to the shared stack function to be executed
* @note if either lock, stack or stack size is invalid, the expression will
* be called using the current stack.
*/
void esp_execute_shared_stack_function(SemaphoreHandle_t lock,
void *stack,
size_t stack_size,
shared_stack_function function);
#ifdef __cplusplus
}
#endif
@@ -0,0 +1,125 @@
/*
* SPDX-FileCopyrightText: 2015-2024 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#ifndef __ESP_FREERTOS_HOOKS_H__
#define __ESP_FREERTOS_HOOKS_H__
#include <stdbool.h>
#include "freertos/portmacro.h"
#include "esp_err.h"
#ifdef __cplusplus
extern "C"
{
#endif
/*
Definitions for the tickhook and idlehook callbacks
*/
typedef bool (*esp_freertos_idle_cb_t)(void);
typedef void (*esp_freertos_tick_cb_t)(void);
/**
* @brief Register a callback to be called from the specified core's idle hook.
* The callback should return true if it should be called by the idle hook
* once per interrupt (or FreeRTOS tick), and return false if it should
* be called repeatedly as fast as possible by the idle hook.
*
* @warning Idle callbacks MUST NOT, UNDER ANY CIRCUMSTANCES, CALL
* A FUNCTION THAT MIGHT BLOCK.
*
* @param[in] new_idle_cb Callback to be called
* @param[in] cpuid id of the core
*
* @return
* - ESP_OK: Callback registered to the specified core's idle hook
* - ESP_ERR_NO_MEM: No more space on the specified core's idle hook to register callback
* - ESP_ERR_INVALID_ARG: cpuid is invalid
*/
esp_err_t esp_register_freertos_idle_hook_for_cpu(esp_freertos_idle_cb_t new_idle_cb, UBaseType_t cpuid);
/**
* @brief Register a callback to the idle hook of the core that calls this function.
* The callback should return true if it should be called by the idle hook
* once per interrupt (or FreeRTOS tick), and return false if it should
* be called repeatedly as fast as possible by the idle hook.
*
* @warning Idle callbacks MUST NOT, UNDER ANY CIRCUMSTANCES, CALL
* A FUNCTION THAT MIGHT BLOCK.
*
* @param[in] new_idle_cb Callback to be called
*
* @return
* - ESP_OK: Callback registered to the calling core's idle hook
* - ESP_ERR_NO_MEM: No more space on the calling core's idle hook to register callback
*/
esp_err_t esp_register_freertos_idle_hook(esp_freertos_idle_cb_t new_idle_cb);
/**
* @brief Register a callback to be called from the specified core's tick hook.
*
* @param[in] new_tick_cb Callback to be called
* @param[in] cpuid id of the core
*
* @return
* - ESP_OK: Callback registered to specified core's tick hook
* - ESP_ERR_NO_MEM: No more space on the specified core's tick hook to register the callback
* - ESP_ERR_INVALID_ARG: cpuid is invalid
*/
esp_err_t esp_register_freertos_tick_hook_for_cpu(esp_freertos_tick_cb_t new_tick_cb, UBaseType_t cpuid);
/**
* @brief Register a callback to be called from the calling core's tick hook.
*
* @param[in] new_tick_cb Callback to be called
*
* @return
* - ESP_OK: Callback registered to the calling core's tick hook
* - ESP_ERR_NO_MEM: No more space on the calling core's tick hook to register the callback
*/
esp_err_t esp_register_freertos_tick_hook(esp_freertos_tick_cb_t new_tick_cb);
/**
* @brief Unregister an idle callback from the idle hook of the specified core
*
* @param[in] old_idle_cb Callback to be unregistered
* @param[in] cpuid id of the core
*/
void esp_deregister_freertos_idle_hook_for_cpu(esp_freertos_idle_cb_t old_idle_cb, UBaseType_t cpuid);
/**
* @brief Unregister an idle callback. If the idle callback is registered to
* the idle hooks of both cores, the idle hook will be unregistered from
* both cores
*
* @param[in] old_idle_cb Callback to be unregistered
*/
void esp_deregister_freertos_idle_hook(esp_freertos_idle_cb_t old_idle_cb);
/**
* @brief Unregister a tick callback from the tick hook of the specified core
*
* @param[in] old_tick_cb Callback to be unregistered
* @param[in] cpuid id of the core
*/
void esp_deregister_freertos_tick_hook_for_cpu(esp_freertos_tick_cb_t old_tick_cb, UBaseType_t cpuid);
/**
* @brief Unregister a tick callback. If the tick callback is registered to the
* tick hooks of both cores, the tick hook will be unregistered from
* both cores
*
* @param[in] old_tick_cb Callback to be unregistered
*/
void esp_deregister_freertos_tick_hook(esp_freertos_tick_cb_t old_tick_cb);
#ifdef __cplusplus
}
#endif
#endif // __ESP_FREERTOS_HOOKS_H__
@@ -0,0 +1,78 @@
/*
* SPDX-FileCopyrightText: 2015-2024 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#pragma once
#include <esp_err.h>
#ifdef __cplusplus
extern "C" {
#endif
#if !defined(CONFIG_FREERTOS_UNICORE) || defined(CONFIG_APPTRACE_GCOV_ENABLE)
/*
* Inter-processor call APIs
*
* FreeRTOS provides several APIs which can be used to communicate between different tasks, including tasks running on
* different CPUs. This module provides additional APIs to run some code on the other CPU. These APIs can only be used
* when FreeRTOS scheduler is running.
*/
/**
* @brief IPC Callback
*
* A callback of this type should be provided as an argument when calling esp_ipc_call() or esp_ipc_call_blocking().
*/
typedef void (*esp_ipc_func_t)(void* arg);
/**
* @brief Execute a callback on a given CPU
*
* Execute a given callback on a particular CPU. The callback must be of type "esp_ipc_func_t" and will be invoked in
* the context of the target CPU's IPC task.
*
* - This function will block the target CPU's IPC task has begun execution of the callback
* - If another IPC call is ongoing, this function will block until the ongoing IPC call completes
* - The stack size of the IPC task can be configured via the CONFIG_ESP_IPC_TASK_STACK_SIZE option
*
* @note In single-core mode, returns ESP_ERR_INVALID_ARG for cpu_id 1.
*
* @param[in] cpu_id CPU where the given function should be executed (0 or 1)
* @param[in] func Pointer to a function of type void func(void* arg) to be executed
* @param[in] arg Arbitrary argument of type void* to be passed into the function
*
* @return
* - ESP_ERR_INVALID_ARG if cpu_id is invalid
* - ESP_ERR_INVALID_STATE if the FreeRTOS scheduler is not running
* - ESP_OK otherwise
*/
esp_err_t esp_ipc_call(uint32_t cpu_id, esp_ipc_func_t func, void* arg);
/**
* @brief Execute a callback on a given CPU until and block until it completes
*
* This function is identical to esp_ipc_call() except that this function will block until the execution of the callback
* completes.
*
* @note In single-core mode, returns ESP_ERR_INVALID_ARG for cpu_id 1.
*
* @param[in] cpu_id CPU where the given function should be executed (0 or 1)
* @param[in] func Pointer to a function of type void func(void* arg) to be executed
* @param[in] arg Arbitrary argument of type void* to be passed into the function
*
* @return
* - ESP_ERR_INVALID_ARG if cpu_id is invalid
* - ESP_ERR_INVALID_STATE if the FreeRTOS scheduler is not running
* - ESP_OK otherwise
*/
esp_err_t esp_ipc_call_blocking(uint32_t cpu_id, esp_ipc_func_t func, void* arg);
#endif // !defined(CONFIG_FREERTOS_UNICORE) || defined(CONFIG_APPTRACE_GCOV_ENABLE)
#ifdef __cplusplus
}
#endif
@@ -0,0 +1,140 @@
/*
* SPDX-FileCopyrightText: 2015-2023 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#pragma once
#include "sdkconfig.h"
#ifdef __cplusplus
extern "C" {
#endif
#ifdef CONFIG_ESP_IPC_ISR_ENABLE
/**
* @brief IPC ISR Callback
*
* The callback must be written:
* - in assembly for XTENSA chips (such as ESP32, ESP32S3).
* - in C or assembly for RISCV chips (such as ESP32P4).
*
* A callback of this type should be provided as an argument when calling esp_ipc_isr_call() or
* esp_ipc_isr_call_blocking().
*/
typedef void (*esp_ipc_isr_func_t)(void* arg);
/**
* @brief Execute an ISR callback on the other CPU
*
* Execute a given callback on the other CPU in the context of a High Priority Interrupt.
*
* - This function will busy-wait in a critical section until the other CPU has started execution of the callback
* - The callback must be written:
* - in assembly for XTENSA chips (such as ESP32, ESP32S3).
* The function is invoked using a CALLX0 instruction and can use only a2, a3, a4 registers.
* See :doc:`IPC in Interrupt Context </api-reference/system/ipc>` doc for more details.
* - in C or assembly for RISCV chips (such as ESP32P4).
*
* @note This function is not available in single-core mode.
*
* @param[in] func Pointer to a function of type void func(void* arg) to be executed
* @param[in] arg Arbitrary argument of type void* to be passed into the function
*/
void esp_ipc_isr_call(esp_ipc_isr_func_t func, void* arg) ;
/**
* @brief Execute an ISR callback on the other CPU
* See esp_ipc_isr_call().
*/
#define esp_ipc_isr_asm_call(func, arg) esp_ipc_isr_call(func, arg)
/**
* @brief Execute an ISR callback on the other CPU and busy-wait until it completes
*
* This function is identical to esp_ipc_isr_call() except that this function will busy-wait until the execution of
* the callback completes.
*
* @note This function is not available in single-core mode.
*
* @param[in] func Pointer to a function of type void func(void* arg) to be executed
* @param[in] arg Arbitrary argument of type void* to be passed into the function
*/
void esp_ipc_isr_call_blocking(esp_ipc_isr_func_t func, void* arg);
/**
* @brief Execute an ISR callback on the other CPU and busy-wait until it completes
* See esp_ipc_isr_call_blocking().
*/
#define esp_ipc_isr_asm_call_blocking(func, arg) esp_ipc_isr_call_blocking(func, arg)
/**
* @brief Stall the other CPU
*
* This function will stall the other CPU. The other CPU is stalled by busy-waiting in the context of a High Priority
* Interrupt. The other CPU will not be resumed until esp_ipc_isr_release_other_cpu() is called.
*
* - This function is internally implemented using IPC ISR
* - This function is used for DPORT workaround.
* - If the stall feature is paused using esp_ipc_isr_stall_pause(), this function will have no effect
*
* @note This function is not available in single-core mode.
* @note It is the caller's responsibility to avoid deadlocking on spinlocks
*/
void esp_ipc_isr_stall_other_cpu(void);
/**
* @brief Release the other CPU
*
* This function will release the other CPU that was previously stalled from calling esp_ipc_isr_stall_other_cpu()
*
* - This function is used for DPORT workaround.
* - If the stall feature is paused using esp_ipc_isr_stall_pause(), this function will have no effect
*
* @note This function is not available in single-core mode.
*/
void esp_ipc_isr_release_other_cpu(void);
/**
* @brief Puase the CPU stall feature
*
* This function will pause the CPU stall feature. Once paused, calls to esp_ipc_isr_stall_other_cpu() and
* esp_ipc_isr_release_other_cpu() will have no effect. If a IPC ISR call is already in progress, this function will
* busy-wait until the call completes before pausing the CPU stall feature.
*/
void esp_ipc_isr_stall_pause(void);
/**
* @brief Abort a CPU stall
*
* This function will abort any stalling routine of the other CPU due to a pervious call to
* esp_ipc_isr_stall_other_cpu(). This function aborts the stall in a non-recoverable manner, thus should only be called
* in case of a panic().
*
* - This function is used in panic handling code
*/
void esp_ipc_isr_stall_abort(void);
/**
* @brief Resume the CPU stall feature
*
* This function will resume the CPU stall feature that was previously paused by calling esp_ipc_isr_stall_pause(). Once
* resumed, calls to esp_ipc_isr_stall_other_cpu() and esp_ipc_isr_release_other_cpu() will have effect again.
*/
void esp_ipc_isr_stall_resume(void);
#else // CONFIG_ESP_IPC_ISR_ENABLE
#define esp_ipc_isr_stall_other_cpu()
#define esp_ipc_isr_release_other_cpu()
#define esp_ipc_isr_stall_pause()
#define esp_ipc_isr_stall_abort()
#define esp_ipc_isr_stall_resume()
#endif // CONFIG_ESP_IPC_ISR_ENABLE
#ifdef __cplusplus
}
#endif
@@ -0,0 +1,383 @@
/*
* SPDX-FileCopyrightText: 2022-2024 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
/**
* This file provides an abstract OS API for entering and exiting critical sections.
* It furthermore provides macros to define and initialize an optional spinlock
* if the used chip is a multi-core chip. If a single-core chip is used, just disabling interrupts
* is sufficient to guarantee consecutive, non-interrupted execution of a critical section.
* Hence, the spinlock is unneccessary and will be automatically ommitted by the macros.
*/
#pragma once
#include "freertos/FreeRTOS.h"
#include "spinlock.h"
#ifdef __cplusplus
extern "C" {
#endif
#if CONFIG_IDF_TARGET_ESP32 || CONFIG_IDF_TARGET_ESP32S3 || CONFIG_IDF_TARGET_ESP32S2 || CONFIG_IDF_TARGET_ESP32P4
/**
* This macro also helps users switching between spinlock declarations/definitions for multi-/single core environments
* if the macros below aren't sufficient.
*/
#define OS_SPINLOCK 1
#else
#define OS_SPINLOCK 0
#endif
#if OS_SPINLOCK == 1
typedef spinlock_t esp_os_spinlock_t;
#endif
/**
* Define and initialize a static (internal linking) lock for entering critical sections.
*
* Use this when all the critical sections are local inside a file.
* The lock will only be defined if built for a multi-core system, otherwise it is unnecessary.
*
* @note When using this macro, the critical section macros esp_os_enter_critical* and esp_os_exit_critical*
* MUST be used, otherwise normal functions would be passed an undefined variable when build for single-core systems.
*
* @param lock_name Variable name of the lock. This will later be used to reference the declared lock.
* @param optional_qualifiers Qualifiers such as DRAM_ATTR and other attributes. Can be omitted if no qualifiers are
* required.
*
* Example usage:
* @code{c}
* ...
* #include "os/critical_section.h"
* ...
* DEFINE_CRIT_SECTION_LOCK_STATIC(my_lock); // will have internal linking (static)
* ...
* esp_os_enter_critical(&my_lock);
* ...
* esp_os_exit_critical(&my_lock);
* @endcode
*/
#if OS_SPINLOCK == 1
#define DEFINE_CRIT_SECTION_LOCK_STATIC(lock_name, optional_qualifiers...) static optional_qualifiers esp_os_spinlock_t lock_name = SPINLOCK_INITIALIZER
#else
#define DEFINE_CRIT_SECTION_LOCK_STATIC(lock_name, optional_qualifiers...)
#endif
/**
* Define and initialize a non-static (external linking) lock for entering critical sections.
*
* Locks defined by this macro can be linked among object files but this rather exceptional.
* Prefer the static lock definition whenever possible.
* The lock will only be defined if built for a multi-core system, otherwise it is unnecessary.
*
* @note When using this macro, the critical section macros esp_os_enter_critical* and esp_os_exit_critical*
* MUST be used, otherwise normal functions would be passed an undefined variable when build for single-core systems.
*
* @param lock_name Variable name of the lock. This will later be used to reference the declared lock.
* @param optional_qualifiers Qualifiers such as DRAM_ATTR and other attributes. Can be omitted if no qualifiers are
* required.
*
* Example usage:
* @code{c}
* ...
* #include "os/critical_section.h"
* ...
* DEFINE_CRIT_SECTION_LOCK(my_lock); // will have external linking (non-static)
* ...
* esp_os_enter_critical(&my_lock);
* ...
* esp_os_exit_critical(&my_lock);
* @endcode
*/
#if OS_SPINLOCK == 1
#define DEFINE_CRIT_SECTION_LOCK(lock_name, optional_qualifiers...) optional_qualifiers esp_os_spinlock_t lock_name = SPINLOCK_INITIALIZER
#else
#define DEFINE_CRIT_SECTION_LOCK(lock_name, optional_qualifiers...)
#endif
/**
* @brief This macro initializes a critical section lock at runtime.
*
* This macro basically creates a member of the initialization list, including the trailing comma.
* If the lock is unnecessary because the architecture is single-core, this macro will not do anything.
* This is incompatible with a lock created by DEFINE_CRIT_SECTION_LOCK_STATIC from above.
*
* @param lock_name Pointer to the lock.
*
* @note When using this macro, the critical section macros esp_os_enter_critical* and esp_os_exit_critical*
* MUST be used, otherwise normal functions would be passed an undefined variable when build for single-core
* systems.
*
* Example usage:
* @code{c}
* ...
* #include "os/critical_section.h"
* ...
* typedef struct protected_struct_t {
* int member1;
* DECLARE_CRIT_SECTION_LOCK_IN_STRUCT(my_lock)
* int another_member;
* };
* ...
* protected_struct_t my_protected;
* INIT_CRIT_SECTION_LOCK_IN_STRUCT(&(my_protected.my_lock));
* };
* @endcode
*/
#if OS_SPINLOCK == 1
#define INIT_CRIT_SECTION_LOCK_RUNTIME(lock_name) spinlock_initialize(lock_name)
#else
#define INIT_CRIT_SECTION_LOCK_RUNTIME(lock_name)
#endif
/**
* @brief This macro declares a critical section lock as a member of a struct.
*
* The critical section lock member is only declared if built for multi-core systems, otherwise it is omitted.
*
* @note When using this macro, the critical section macros esp_os_enter_critical* and esp_os_exit_critical*
* MUST be used, otherwise normal functions would be passed an undefined variable when build for single-core
* systems.
* @note Do NOT add any semicolon after declaring the member with this macro.
* The trailing semicolon is included in the macro, otherwise -Wpedantic would complain about
* superfluous ";" if OS_SPINLOCK == 0.
*
* Example usage:
* @code{c}
* ...
* #include "os/critical_section.h"
* ...
* typedef struct protected_struct_t {
* int member1;
* DECLARE_CRIT_SECTION_LOCK_IN_STRUCT(my_lock) // no semicolon!
* int another_member;
* };
* @endcode
*/
#if OS_SPINLOCK == 1
#define DECLARE_CRIT_SECTION_LOCK_IN_STRUCT(lock_name) esp_os_spinlock_t lock_name;
#else
#define DECLARE_CRIT_SECTION_LOCK_IN_STRUCT(lock_name)
#endif
/**
* @brief This macro initializes a critical section lock as a member of a struct when using an list initialization.
* It has to be used together with \c DECLARE_CRIT_SECTION_LOCK_IN_STRUCT() to work.
*
* This macro basically creates a member of the initialization list, including the trailing comma.
* If the lock is unnecessary because the architecture is single-core, this macro will not do anything.
* This means that if \c lock_name is still a member of the struct, \c lock_name will be uninitialized.
* Hence, this macro has to be used together with \c DECLARE_CRIT_SECTION_LOCK_IN_STRUCT() to correctly to declare
* or omit the struct member \c lock_name.
*
* @param lock_name The field name of the lock inside the struct.
*
* @note When using this macro, the critical section macros esp_os_enter_critical* and esp_os_exit_critical*
* MUST be used, otherwise normal functions would be passed an undefined variable when build for single-core
* systems.
* @note Do NOT add any comma in the initializer list after using this macro.
*
* Example usage:
* @code{c}
* ...
* #include "os/critical_section.h"
* ...
* typedef struct protected_struct_t {
* int member1;
* DECLARE_CRIT_SECTION_LOCK_IN_STRUCT(my_lock)
* int another_member;
* };
* ...
* protected_struct_t my_protected = {
* .member1 = 0,
* INIT_CRIT_SECTION_LOCK_IN_STRUCT(my_lock) // no comma!
* another_member = 47,
* };
* @endcode
*/
#if OS_SPINLOCK == 1
#define INIT_CRIT_SECTION_LOCK_IN_STRUCT(lock_name) .lock_name = portMUX_INITIALIZER_UNLOCKED,
#else
#define INIT_CRIT_SECTION_LOCK_IN_STRUCT(lock_name)
#endif
/**
* @brief Enter a critical section, i.e., a section that will not be interrupted by any other task or interrupt.
*
* On multi-core systems, this will disable interrupts and take the spinlock \c lock. On single core systems, a
* spinlock is unncessary, hence \c lock is ignored and interrupts are disabled only.
*
* @note This macro MUST be used together with any of the initialization macros, e.g.
* DEFINE_CRIT_SECTION_LOCK_STATIC. If not, there may be unused variables.
*
* @param lock Pointer to the critical section lock. Ignored if build for single core system.
*
* Example usage with static locks:
* @code{c}
* ...
* #include "os/critical_section.h"
* ...
* DEFINE_CRIT_SECTION_LOCK_STATIC(my_lock); // will have internal linking (static)
* ...
* esp_os_enter_critical(&my_lock);
* // code inside critical section
* esp_os_exit_critical(&my_lock);
* @endcode
*/
#if OS_SPINLOCK == 1
#define esp_os_enter_critical(lock) portENTER_CRITICAL(lock)
#else
#define esp_os_enter_critical(lock) vPortEnterCritical()
#endif
/**
* @brief Exit a critical section.
*
* On multi-core systems, this will enable interrupts and release the spinlock \c lock. On single core systems, a
* spinlock is unncessary, hence \c lock is ignored and interrupts are enabled only.
*
* @note This macro MUST be used together with any of the initialization macros, e.g.
* DEFINE_CRIT_SECTION_LOCK_STATIC. If not, there may be unused variables.
*
* @param lock Pointer to the critical section lock. Ignored if build for single core system.
*
* Example usage with static locks:
* @code{c}
* ...
* #include "os/critical_section.h"
* ...
* DEFINE_CRIT_SECTION_LOCK_STATIC(my_lock); // will have internal linking (static)
* ...
* esp_os_enter_critical(&my_lock);
* // code inside critical section
* esp_os_exit_critical(&my_lock);
* @endcode
*/
#if OS_SPINLOCK == 1
#define esp_os_exit_critical(lock) portEXIT_CRITICAL(lock)
#else
#define esp_os_exit_critical(lock) vPortExitCritical()
#endif
/**
* @brief Enter a critical section while from ISR.
*
* On multi-core systems, this will disable interrupts and take the spinlock \c lock. On single core systems, a
* spinlock is unncessary, hence \c lock is ignored and interrupts are disabled only.
*
* @note This macro MUST be used together with any of the initialization macros, e.g.
* DEFINE_CRIT_SECTION_LOCK_STATIC. If not, there may be unused variables.
*
* @param lock Pointer to the critical section lock. Ignored if build for single core system.
*
* Example usage with static locks:
* @code{c}
* ...
* #include "os/critical_section.h"
* ...
* DEFINE_CRIT_SECTION_LOCK_STATIC(my_lock); // will have internal linking (static)
* ...
* esp_os_enter_critical(&my_lock);
* // code inside critical section
* esp_os_exit_critical(&my_lock);
* @endcode
*/
#if OS_SPINLOCK == 1
#define esp_os_enter_critical_isr(lock) portENTER_CRITICAL_ISR(lock)
#else
#define esp_os_enter_critical_isr(lock) vPortEnterCritical()
#endif
/**
* @brief Exit a critical section after entering from ISR.
*
* On multi-core systems, this will enable interrupts and release the spinlock \c lock. On single core systems, a
* spinlock is unncessary, hence \c lock is ignored and interrupts are enabled only.
*
* @note This macro MUST be used together with any of the initialization macros, e.g.
* DEFINE_CRIT_SECTION_LOCK_STATIC. If not, there may be unused variables.
*
* @param lock Pointer to the critical section lock. Ignored if build for single core system.
*
* Example usage with static locks:
* @code{c}
* ...
* #include "os/critical_section.h"
* ...
* DEFINE_CRIT_SECTION_LOCK_STATIC(my_lock); // will have internal linking (static)
* ...
* esp_os_enter_critical(&my_lock);
* // code inside critical section
* esp_os_exit_critical(&my_lock);
* @endcode
*/
#if OS_SPINLOCK == 1
#define esp_os_exit_critical_isr(lock) portEXIT_CRITICAL_ISR(lock)
#else
#define esp_os_exit_critical_isr(lock) vPortExitCritical()
#endif
/**
* @brief Enter a critical section from normal task or ISR. This macro will check if the current CPU is processing
* an ISR or not and enter the critical section accordingly.
*
* On multi-core systems, this will disable interrupts and take the spinlock \c lock. On single core systems, a
* spinlock is unncessary, hence \c lock is ignored and interrupts are disabled only.
*
* @note This macro MUST be used together with any of the initialization macros, e.g.
* DEFINE_CRIT_SECTION_LOCK_STATIC. If not, there may be unused variables.
*
* @param lock Pointer to the critical section lock. Ignored if build for single core system.
*
* Example usage with static locks:
* @code{c}
* ...
* #include "os/critical_section.h"
* ...
* DEFINE_CRIT_SECTION_LOCK_STATIC(my_lock); // will have internal linking (static)
* ...
* esp_os_enter_critical(&my_lock);
* // code inside critical section
* esp_os_exit_critical(&my_lock);
* @endcode
*/
#if OS_SPINLOCK == 1
#define esp_os_enter_critical_safe(lock) portENTER_CRITICAL_SAFE(lock)
#else
#define esp_os_enter_critical_safe(lock) vPortEnterCritical()
#endif
/**
* @brief Exit a critical section after entering via esp_os_enter_critical_safe.
*
* On multi-core systems, this will enable interrupts and release the spinlock \c lock. On single core systems, a
* spinlock is unncessary, hence \c lock is ignored and interrupts are enabled only.
*
* @note This macro MUST be used together with any of the initialization macros, e.g.
* DEFINE_CRIT_SECTION_LOCK_STATIC. If not, there may be unused variables.
*
* @param lock Pointer to the critical section lock. Ignored if build for single core system.
*
* Example usage with static locks:
* @code{c}
* ...
* #include "os/critical_section.h"
* ...
* DEFINE_CRIT_SECTION_LOCK_STATIC(my_lock); // will have internal linking (static)
* ...
* esp_os_enter_critical(&my_lock);
* // code inside critical section
* esp_os_exit_critical(&my_lock);
* @endcode
*/
#if OS_SPINLOCK == 1
#define esp_os_exit_critical_safe(lock) portEXIT_CRITICAL_SAFE(lock)
#else
#define esp_os_exit_critical_safe(lock) vPortExitCritical()
#endif
#ifdef __cplusplus
}
#endif
@@ -0,0 +1,82 @@
/*
* SPDX-FileCopyrightText: 2015-2022 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#ifndef __ESP_CROSSCORE_INT_H
#define __ESP_CROSSCORE_INT_H
#include "sdkconfig.h"
#ifdef __cplusplus
extern "C" {
#endif
/**
* Initialize the crosscore interrupt system for this CPU.
* This needs to be called once on every CPU that is used
* by FreeRTOS.
*
* If multicore FreeRTOS support is enabled, this will be
* called automatically by the startup code and should not
* be called manually.
*/
void esp_crosscore_int_init(void);
/**
* Send an interrupt to a CPU indicating it should yield its
* currently running task in favour of a higher-priority task
* that presumably just woke up.
*
* This is used internally by FreeRTOS in multicore mode
* and should not be called by the user.
*
* @param core_id Core that should do the yielding
*/
void esp_crosscore_int_send_yield(int core_id);
/**
* Send an interrupt to a CPU indicating it should update its
* CCOMPARE1 value due to a frequency switch.
*
* This is used internally when dynamic frequency switching is
* enabled, and should not be called from application code.
*
* @param core_id Core that should update its CCOMPARE1 value
*/
void esp_crosscore_int_send_freq_switch(int core_id);
void esp_crosscore_int_send_gdb_call(int core_id);
#if !CONFIG_ESP_SYSTEM_SINGLE_CORE_MODE
/**
* Send an interrupt to a CPU indicating it should print its current backtrace
*
* This is used internally by the Task Watchdog to dump the backtrace of the
* opposite core and should not be called from application code.
*
* @param core_id Core that should print its backtrace
*/
void esp_crosscore_int_send_print_backtrace(int core_id);
#if CONFIG_ESP_TASK_WDT_EN
/**
* Send an interrupt to a CPU indicating it call `task_wdt_timeout_abort_xtensa`.
* This will make the CPU abort, using the interrupted task frame.
*
* This is used internally by the Task Watchdog when it should abort after a task,
* running on the other core than the one running the TWDT ISR, failed to reset
* its timer.
*
* @param core_id Core that should abort
*/
void esp_crosscore_int_send_twdt_abort(int core_id);
#endif // CONFIG_ESP_TASK_WDT_EN
#endif // !CONFIG_ESP_SYSTEM_SINGLE_CORE_MODE
#ifdef __cplusplus
}
#endif
#endif
@@ -0,0 +1,27 @@
/*
* SPDX-FileCopyrightText: 2020-2022 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#ifndef EH_FRAME_PARSER_H
#define EH_FRAME_PARSER_H
#ifdef __cplusplus
extern "C" {
#endif
/**
* @brief Print backtrace for the given execution frame.
*
* @param frame_or Snapshot of the CPU registers when the program stopped its
* normal execution. This frame is usually generated on the
* stack when an exception or an interrupt occurs.
*/
void esp_eh_frame_print_backtrace(const void *frame_or);
#ifdef __cplusplus
}
#endif
#endif // EH_FRAME_PARSER_H
@@ -0,0 +1,33 @@
/*
* SPDX-FileCopyrightText: 2015-2022 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#pragma once
#ifdef __cplusplus
extern "C" {
#endif
/**
* @brief Initialize the non-CPU-specific parts of interrupt watchdog.
*
* This function is automatically called during application startup if the
* interrupt watchdog is enabled in menuconfig.
*/
void esp_int_wdt_init(void);
/**
* @brief Enable the interrupt watchdog on the current CPU.
*
* This function is automatically called during application startup for each CPU
* that has enabled the interrupt watchdog in menuconfig.
*
* @note esp_int_wdt_init() must be called first before calling this function
*/
void esp_int_wdt_cpu_init(void);
#ifdef __cplusplus
}
#endif
@@ -0,0 +1,47 @@
/*
* SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#pragma once
#include "../esp_ipc.h"
#include "sdkconfig.h"
#ifdef __cplusplus
extern "C" {
#endif
#if !defined(CONFIG_FREERTOS_UNICORE) || defined(CONFIG_APPTRACE_GCOV_ENABLE)
/**
* @brief Execute a callback on a given CPU without any blocking operations for the caller
*
* Since it does not have any blocking operations it is suitable to be run from interrupts
* or even when the Scheduler on the current core is suspended.
*
* The function:
* - does not wait for the callback to begin or complete execution,
* - does not change the IPC priority.
* The function returns after sending a notification to the IPC task to execute the callback.
*
* @param[in] cpu_id CPU where the given function should be executed (0 or 1)
* @param[in] func Pointer to a function of type void func(void* arg) to be executed
* @param[in] arg Arbitrary argument of type void* to be passed into the function
*
* @return
* - ESP_ERR_INVALID_ARG if cpu_id is invalid
* - ESP_ERR_INVALID_STATE 1. IPC tasks have not been initialized yet,
* 2. cpu_id requests IPC on the current core, but the FreeRTOS scheduler is not running on it
* (the IPC task cannot be executed).
* - ESP_FAIL IPC is busy due to a previous call was not completed.
* - ESP_OK otherwise
*/
esp_err_t esp_ipc_call_nonblocking(uint32_t cpu_id, esp_ipc_func_t func, void* arg);
#endif // !defined(CONFIG_FREERTOS_UNICORE) || defined(CONFIG_APPTRACE_GCOV_ENABLE)
#ifdef __cplusplus
}
#endif
@@ -0,0 +1,37 @@
/*
* SPDX-FileCopyrightText: 2015-2022 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#pragma once
#include "sdkconfig.h"
#ifdef __cplusplus
extern "C" {
#endif
#ifdef CONFIG_ESP_IPC_ISR_ENABLE
/**
* @brief Initialize the IPC ISR feature, must be called for each CPU
*
* @note This function is called from ipc_task().
*
* This function initializes the IPC ISR feature and must be called before any other esp_ipc_isr...() functions.
* The IPC ISR feature allows for callbacks (written in assembly) to be run on a particular CPU in the context of a
* High Priority Interrupt.
*
* - This function will register a High Priority Interrupt for a CPU where it is called. The priority of the interrupts is dependent on
* the CONFIG_ESP_SYSTEM_CHECK_INT_LEVEL option.
* - Callbacks written in assembly can then run in context of the registered High Priority Interrupts
* - Callbacks can be executed by calling esp_ipc_isr_call() or esp_ipc_isr_call_blocking()
*/
void esp_ipc_isr_init(void);
#endif // CONFIG_ESP_IPC_ISR_ENABLE
#ifdef __cplusplus
}
#endif
@@ -0,0 +1,24 @@
/*
* SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#pragma once
#include "esp_attr.h"
#include "sdkconfig.h"
#ifdef __cplusplus
extern "C" {
#endif
#if CONFIG_ESP_SYSTEM_IN_IRAM
#define ESP_SYSTEM_IRAM_ATTR IRAM_ATTR
#else
#define ESP_SYSTEM_IRAM_ATTR
#endif
#ifdef __cplusplus
}
#endif
@@ -0,0 +1,57 @@
/*
* SPDX-FileCopyrightText: 2015-2022 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#pragma once
#include "sdkconfig.h"
#include "esp_err.h"
#if CONFIG_ESP_TASK_WDT_EN
#ifdef __cplusplus
extern "C" {
#endif
/**
* @brief Type used to define the context of a Task WatchDog Timer implementation.
* This is used internally in the TWDT driver, it is implementation specific.
*/
typedef void* twdt_ctx_t;
/**
* @brief Type of the function used as an ISR callback.
*/
typedef void (*twdt_isr_callback)(void*);
/**
* @brief Stop the Task Watchdog Timer (TWDT)
*
* This function will temporarily stop the timer until it is restarted by a call to esp_task_wdt_restart().
* @note esp_task_wdt_stop() must not be called by multiple tasks simultaneously.
* @return
* - ESP_OK: TWDT successfully stopped
* - Other: Failed to stop the TWDT
*/
esp_err_t esp_task_wdt_stop(void);
/**
* @brief Restart the Task Watchdog Timer (TWDT)
*
* This function will restart the timer after it has been stopped by esp_task_wdt_stop().
* @note esp_task_wdt_restart() must not be called by multiple tasks simultaneously.
* @return
* - ESP_OK: TWDT successfully stopped
* - Other: Failed to stop the TWDT
*/
esp_err_t esp_task_wdt_restart(void);
#ifdef __cplusplus
}
#endif
#endif // CONFIG_ESP_TASK_WDT_EN
@@ -0,0 +1,94 @@
/*
* SPDX-FileCopyrightText: 2015-2024 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#pragma once
#include "esp_err.h"
#include "../esp_task_wdt.h"
#include "esp_private/esp_task_wdt.h"
#ifdef __cplusplus
extern "C" {
#endif
/**
* @brief Allocate and initialize the Task Watchdog Timer (TWDT) with the given configuration.
*
* @param[in] config Pointer to the configuration structure
* @param[out] obj Abstract context for the current timer, this will be passed to all the other functions
*
* @return
* - ESP_OK: Successfully initialized and configured the timer
* - Other: Failed to initialize the timer
*/
esp_err_t esp_task_wdt_impl_timer_allocate(const esp_task_wdt_config_t *config,
twdt_isr_callback callback,
twdt_ctx_t *obj);
/**
* @brief Reconfigure a timer.
*
* The timer must be stopped when calling this function. The timer will not be restarted at the end of this
* function.
*
* @param[in] config Pointer to the configuration structure
*
* @return
* - ESP_OK: Successfully reconfigured the timer
* - Other: Failed to reconfigure the timer
*/
esp_err_t esp_task_wdt_impl_timer_reconfigure(twdt_ctx_t obj, const esp_task_wdt_config_t *config);
/**
* @brief Free the Task Watchdog Timer (TWDT).
*
* @param[in] obj Abstract implementation context
*
*/
void esp_task_wdt_impl_timer_free(twdt_ctx_t obj);
/**
* @brief Feed the Task Watchdog Timer (TWDT)
*
* Feed the timer underneath to prevent it from triggering for the next period (configured at initialization).
*
* @param[in] obj Abstract implementation context
* @return
* - ESP_OK: timer successfully feeded
* - Other: failed to feed the timer
*/
esp_err_t esp_task_wdt_impl_timer_feed(twdt_ctx_t obj);
/**
* @brief Function invoked as soon as the Task Watchdog Timer (TWDT) ISR callback is called.
*
* @param[in] obj Abstract implementation context
*/
void esp_task_wdt_impl_timeout_triggered(twdt_ctx_t obj);
/**
* @brief Stop the Task Watchdog Timer (TWDT).
*
* @param[in] obj Abstract implementation context
*
*/
esp_err_t esp_task_wdt_impl_timer_stop(twdt_ctx_t obj);
/**
* @brief Restart the Task Watchdog Timer (TWDT)
*
* This function will restart/resume the timer after it has been stopped.
*
* @param[in] obj Abstract implementation context
* @return
* - ESP_OK: timer successfully stopped
* - Other: failed to stop the timer
*/
esp_err_t esp_task_wdt_impl_timer_restart(twdt_ctx_t obj);
#ifdef __cplusplus
}
#endif
@@ -0,0 +1,31 @@
/*
* SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#pragma once
#include "freertos/FreeRTOS.h"
#ifdef __cplusplus
extern "C" {
#endif
typedef enum {
CDCACM_SELECT_READ_NOTIF,
CDCACM_SELECT_WRITE_NOTIF,
CDCACM_SELECT_ERROR_NOTIF,
} cdcacm_select_notif_t;
typedef void (*cdcacm_select_notif_callback_t)(cdcacm_select_notif_t cdcacm_select_notif, BaseType_t *task_woken);
/**
* @brief Set notification callback function for select() events
* @param cdcacm_select_notif_callback callback function
*/
void cdcacm_set_select_notif_callback(cdcacm_select_notif_callback_t cdcacm_select_notif_callback);
#ifdef __cplusplus
}
#endif
@@ -0,0 +1,27 @@
/*
* SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#ifndef FP_UNWIND_H
#define FP_UNWIND_H
#ifdef __cplusplus
extern "C" {
#endif
/**
* @brief Print backtrace for the given execution frame thanks to the frame pointers.
*
* @param frame_or Snapshot of the CPU registers when the program stopped its
* normal execution. This frame is usually generated on the
* stack when an exception or an interrupt occurs.
*/
void esp_fp_print_backtrace(const void *frame_or);
#ifdef __cplusplus
}
#endif
#endif // FP_UNWIND_H
@@ -0,0 +1,93 @@
/*
* SPDX-FileCopyrightText: 2015-2023 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#pragma once
#include <stdint.h>
#include <stdbool.h>
#include "esp_macros.h"
#include "soc/soc_caps.h"
#include "sdkconfig.h"
#ifdef __cplusplus
extern "C" {
#endif
extern bool g_panic_abort;
extern char *g_panic_abort_details;
extern void *g_exc_frames[SOC_CPU_CORES_NUM];
// Function to print longer amounts of information such as the details
// and backtrace field of panic_info_t. These functions should limit themselves
// to printing to the console and should do other more involved processing,
// and must be aware that the main logic in panic.c has a watchdog timer active.
typedef void (*panic_info_dump_fn_t)(const void* frame);
// Non architecture specific exceptions (generally valid for all targets).
// Can be used to convey to the main logic what exception is being
// dealt with to perform some actions, without knowing the underlying
// architecture/chip-specific exception.
typedef enum {
PANIC_EXCEPTION_DEBUG,
PANIC_EXCEPTION_IWDT,
PANIC_EXCEPTION_TWDT,
PANIC_EXCEPTION_ABORT,
PANIC_EXCEPTION_FAULT, // catch-all for all types of faults
} panic_exception_t;
typedef struct {
int core; // core which triggered panic
panic_exception_t exception; // non-architecture-specific exception code
const char* reason; // exception string
const char* description; // short description of the exception
panic_info_dump_fn_t details; // more details on the exception
panic_info_dump_fn_t state; // processor state, usually the contents of the registers
const void* addr; // instruction address that triggered the exception
const void* frame; // reference to the frame
bool pseudo_excause; // flag indicating that exception cause has special meaning
} panic_info_t;
#define PANIC_INFO_DUMP(info, dump_fn) {if ((info)->dump_fn) (*(info)->dump_fn)((info->frame));}
// Create own print functions, since printf might be broken, and can be silenced
// when CONFIG_ESP_SYSTEM_PANIC_SILENT_REBOOT
#if !CONFIG_ESP_SYSTEM_PANIC_SILENT_REBOOT
void panic_print_char(char c);
void panic_print_str(const char *str);
void panic_print_dec(int d);
void panic_print_hex(int h);
#else
#define panic_print_char(c) ESP_UNUSED(c)
#define panic_print_str(str) ESP_UNUSED(str)
#define panic_print_dec(d) ESP_UNUSED(d)
#define panic_print_hex(h) ESP_UNUSED(h)
#endif
void __attribute__((__noreturn__)) panic_abort(const char *details);
void panic_arch_fill_info(void *frame, panic_info_t *info);
void panic_soc_fill_info(void *frame, panic_info_t *info);
bool panic_soc_check_pseudo_cause(void *f, panic_info_t *info);
void panic_print_registers(const void *frame, int core);
void panic_print_backtrace(const void *frame, int core);
uint32_t panic_get_address(const void* frame);
void panic_set_address(void *frame, uint32_t addr);
uint32_t panic_get_cause(const void* frame);
void panic_prepare_frame_from_ctx(void* frame);
#ifdef __cplusplus
}
#endif
@@ -0,0 +1,96 @@
/*
* SPDX-FileCopyrightText: 2015-2024 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#pragma once
#include "esp_attr.h"
#include "esp_err.h"
#include "esp_bit_defs.h"
#if !CONFIG_IDF_TARGET_LINUX
#include "esp_cpu.h"
#endif
#include "soc/soc_caps.h"
#include "sdkconfig.h"
#ifdef __cplusplus
extern "C" {
#endif
// Port layer defines the entry point. It then transfer control to a `sys_startup_fn_t`, stored in this
// array, one per core.
typedef void (*sys_startup_fn_t)(void);
/* This array of per-CPU system layer startup functions is initialized in the non-port part of esp_system */
#if !CONFIG_ESP_SYSTEM_SINGLE_CORE_MODE
extern sys_startup_fn_t const g_startup_fn[SOC_CPU_CORES_NUM];
#else
extern sys_startup_fn_t const g_startup_fn[1];
#endif
// Utility to execute `sys_startup_fn_t` for the current core.
#define SYS_STARTUP_FN() ((*g_startup_fn[(esp_cpu_get_core_id())])())
#if !CONFIG_ESP_SYSTEM_SINGLE_CORE_MODE
void startup_resume_other_cores(void);
#endif
/**
* Internal structure describing ESP_SYSTEM_INIT_FN startup functions
*/
typedef struct {
esp_err_t (*fn)(void); /*!< Pointer to the startup function */
uint16_t cores; /*!< Bit mask of cores where the function has to be called */
uint16_t stage; /*!< Init stage number (0 or 1) */
} esp_system_init_fn_t;
#define ESP_SYSTEM_INIT_STAGE_CORE 0
#define ESP_SYSTEM_INIT_STAGE_SECONDARY 1
/**
* @brief Define a system initialization function which will be executed on the specified cores
*
* @param f function name (identifier)
* @param stage_ init stage name (CORE or SECONDARY)
* @param c bit mask of cores to execute the function on (ex. if BIT0 is set, the function
* will be executed on CPU 0, if BIT1 is set - on CPU 1, and so on)
* @param priority integer, priority of the initialization function. Higher values mean that
* the function will be executed later in the process.
* @param (varargs) optional, additional attributes for the function declaration (such as IRAM_ATTR)
*
* The function defined using this macro must return ESP_OK on success. Any other value will be
* logged and the startup process will abort.
*
* Initialization functions should be placed in a compilation unit where at least one other
* symbol is referenced in another compilation unit. This means that the reference should not itself
* get optimized out by the compiler or discarded by the linker if the related feature is used.
* It is, on the other hand, a good practice to make sure the initialization function does get
* discarded if the related feature is not used.
*/
#define ESP_SYSTEM_INIT_FN(f, stage_, c, priority, ...) \
static esp_err_t __VA_ARGS__ __esp_system_init_fn_##f(void); \
static __attribute__((used)) _SECTION_ATTR_IMPL(".esp_system_init_fn", priority) \
esp_system_init_fn_t esp_system_init_fn_##f = { \
.fn = ( __esp_system_init_fn_##f), \
.cores = (c), \
.stage = ESP_SYSTEM_INIT_STAGE_##stage_ \
}; \
static esp_err_t __esp_system_init_fn_##f(void)
#ifdef CONFIG_ESP_SYSTEM_SINGLE_CORE_MODE
#define ESP_SYSTEM_INIT_ALL_CORES BIT(0)
#else
#define ESP_SYSTEM_INIT_ALL_CORES (BIT(SOC_CPU_CORES_NUM) - 1)
#endif
extern uint64_t g_startup_time; // Startup time that serves as the point of origin for system time. Should be set by the entry
// function in the port layer. May be 0 as well if this is not backed by a persistent counter, in which case
// startup time = system time = 0 at the point the entry function sets this variable.
#ifdef __cplusplus
}
#endif
@@ -0,0 +1,81 @@
/*
* SPDX-FileCopyrightText: 2018-2022 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#pragma once
#ifdef __cplusplus
extern "C" {
#endif
#include "esp_system.h"
/**
* @brief Internal function to restart PRO and APP CPUs.
*
* @note This function should not be called from FreeRTOS applications.
* Use esp_restart instead.
*
* This function executes a CPU reset (see TRM).
*
* CPU resets do not reset digital peripherals, but this function will
* manually reset a subset of digital peripherals (depending on target) before
* carrying out the CPU reset.
*
* Memory protection is also cleared by a CPU reset.
*
* This is an internal function called by esp_restart. It is called directly
* by the panic handler and brownout detector interrupt.
*/
void esp_restart_noos(void) __attribute__((noreturn));
/**
* @brief Similar to esp_restart_noos, but resets all the digital peripherals.
*/
void esp_restart_noos_dig(void) __attribute__((noreturn));
/**
* @brief Internal function to set reset reason hint
*
* The hint is used do distinguish different reset reasons when software reset
* is performed.
*
* The hint is stored in RTC store register, RTC_RESET_CAUSE_REG.
*
* @param hint Desired esp_reset_reason_t value for the real reset reason
*/
void esp_reset_reason_set_hint(esp_reset_reason_t hint);
/**
* @brief Internal function to get the reset hint value
* @return - Reset hint value previously stored into RTC_RESET_CAUSE_REG using
* esp_reset_reason_set_hint function
* - ESP_RST_UNKNOWN if the value in RTC_RESET_CAUSE_REG is invalid
*/
esp_reset_reason_t esp_reset_reason_get_hint(void);
/**
* @brief Get the time in microseconds since startup
*
* @returns time since g_startup_time; definition should be fixed by system time provider
* no matter the underlying timer used.
*/
int64_t esp_system_get_time(void);
/**
* @brief Get the resolution of the time returned by `esp_system_get_time`.
*
* @returns the resolution in nanoseconds
*/
uint32_t esp_system_get_time_resolution(void);
/**
* @brief Before the system exit (e.g. panic, brownout, restart, etc.), this function is to be called to reset all necessary peripherals.
*/
void esp_system_reset_modules_on_exit(void);
#ifdef __cplusplus
}
#endif
@@ -0,0 +1,114 @@
/*
* SPDX-FileCopyrightText: 2019-2025 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#pragma once
#include <stdbool.h>
#include <stddef.h>
#include <stdint.h>
#include "esp_err.h"
#ifdef __cplusplus
extern "C" {
#endif
/**
* @file usb_console.h
* This file contains definitions of low-level USB console functions.
* These functions are not considered to be a public interface and
* should not be called by applications directly.
* Application interface to the USB console is provided either by
* "cdcacm" VFS driver, or by the USB CDC driver in TinyUSB.
*/
/**
* RX/TX callback function type
* @param arg callback-specific context pointer
*/
typedef void (*esp_usb_console_cb_t)(void* arg);
/**
* Initialize USB console output using ROM USB CDC driver.
* This function is called by the early startup code if USB CDC is
* selected as the console output option.
* @return
* - ESP_OK on success
* - ESP_ERR_NO_MEM
* - other error codes from the interrupt allocator
*/
esp_err_t esp_usb_console_init(void);
/**
* Write a buffer to USB CDC
* @param buf data to write
* @param size size of the data, in bytes
* @return -1 on error, otherwise the number of bytes
*/
ssize_t esp_usb_console_write_buf(const char* buf, size_t size);
/**
* @brief Wait until all buffered USB CDC output is written
*
* @return ssize_t Number of bytes written, or -1 if the driver is not initialized
*/
ssize_t esp_usb_console_flush(void);
/**
* @brief Read data from USB CDC
*
* May read less data than requested.
*
* @param buf Buffer to read data into
* @param buf_size Size of the buffer
* @return ssize_t Number of bytes written into the buffer, or -1 if the driver is not initialized
*/
ssize_t esp_usb_console_read_buf(char* buf, size_t buf_size);
/**
* @brief Get the number of bytes available for reading from USB CDC
*
* @return ssize_t Number of bytes available, or -1 if the driver is not initialized
*/
ssize_t esp_usb_console_available_for_read(void);
/**
* @brief Check if data can be written into USB CDC
*
* @return true if data can be written now without blocking
*/
bool esp_usb_console_write_available(void);
/**
* @brief Set RX/TX callback functions to be called from ISR
*
* @param rx_cb RX callback function
* @param tx_cb TX callback function
* @param arg callback-specific context pointer
* @return ESP_OK if the callbacks were set, ESP_ERR_INVALID_STATE if the driver is not initialized
*/
esp_err_t esp_usb_console_set_cb(esp_usb_console_cb_t rx_cb, esp_usb_console_cb_t tx_cb, void* arg);
/**
* @brief Checks whether the USB console is installed or not
*
* @return
* - true USB console is installed
* - false USB console is not installed
*/
bool esp_usb_console_is_installed(void);
/**
* @brief Call the USB interrupt handler while any interrupts
* are pending, but not more than a few times. Non-static to
* allow placement into IRAM by ldgen.
*
*/
void esp_usb_console_poll_interrupts(void); // [refactor-todo] Remove when implementing IDF-12175
#ifdef __cplusplus
}
#endif
@@ -0,0 +1,125 @@
/*
* SPDX-FileCopyrightText: 2015-2024 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#ifndef __ESP_SYSTEM_H__
#define __ESP_SYSTEM_H__
#include <stdint.h>
#include <stdbool.h>
#include "esp_err.h"
#include "esp_attr.h"
#include "esp_bit_defs.h"
#include "esp_idf_version.h"
#ifdef __cplusplus
extern "C" {
#endif
/**
* @brief Reset reasons
*/
typedef enum {
ESP_RST_UNKNOWN, //!< Reset reason can not be determined
ESP_RST_POWERON, //!< Reset due to power-on event
ESP_RST_EXT, //!< Reset by external pin (not applicable for ESP32)
ESP_RST_SW, //!< Software reset via esp_restart
ESP_RST_PANIC, //!< Software reset due to exception/panic
ESP_RST_INT_WDT, //!< Reset (software or hardware) due to interrupt watchdog
ESP_RST_TASK_WDT, //!< Reset due to task watchdog
ESP_RST_WDT, //!< Reset due to other watchdogs
ESP_RST_DEEPSLEEP, //!< Reset after exiting deep sleep mode
ESP_RST_BROWNOUT, //!< Brownout reset (software or hardware)
ESP_RST_SDIO, //!< Reset over SDIO
ESP_RST_USB, //!< Reset by USB peripheral
ESP_RST_JTAG, //!< Reset by JTAG
ESP_RST_EFUSE, //!< Reset due to efuse error
ESP_RST_PWR_GLITCH, //!< Reset due to power glitch detected
ESP_RST_CPU_LOCKUP, //!< Reset due to CPU lock up (double exception)
} esp_reset_reason_t;
/**
* Shutdown handler type
*/
typedef void (*shutdown_handler_t)(void);
/**
* @brief Register shutdown handler
*
* This function allows you to register a handler that gets invoked before
* the application is restarted using esp_restart function.
* @param handle function to execute on restart
* @return
* - ESP_OK on success
* - ESP_ERR_INVALID_STATE if the handler has already been registered
* - ESP_ERR_NO_MEM if no more shutdown handler slots are available
*/
esp_err_t esp_register_shutdown_handler(shutdown_handler_t handle);
/**
* @brief Unregister shutdown handler
*
* This function allows you to unregister a handler which was previously
* registered using esp_register_shutdown_handler function.
* - ESP_OK on success
* - ESP_ERR_INVALID_STATE if the given handler hasn't been registered before
*/
esp_err_t esp_unregister_shutdown_handler(shutdown_handler_t handle);
/**
* @brief Restart PRO and APP CPUs.
*
* This function can be called both from PRO and APP CPUs.
* After successful restart, CPU reset reason will be SW_CPU_RESET.
* Peripherals (except for Wi-Fi, BT, UART0, SPI1, and legacy timers) are not reset.
* This function does not return.
*/
void esp_restart(void) __attribute__((__noreturn__));
/**
* @brief Get reason of last reset
* @return See description of esp_reset_reason_t for explanation of each value.
*/
esp_reset_reason_t esp_reset_reason(void);
/**
* @brief Get the size of available heap.
*
* @note Note that the returned value may be larger than the maximum contiguous block
* which can be allocated.
*
* @return Available heap size, in bytes.
*/
uint32_t esp_get_free_heap_size(void);
/**
* @brief Get the size of available internal heap.
*
* @note Note that the returned value may be larger than the maximum contiguous block
* which can be allocated.
*
* @return Available internal heap size, in bytes.
*/
uint32_t esp_get_free_internal_heap_size(void);
/**
* @brief Get the minimum heap that has ever been available
*
* @return Minimum free heap ever available
*/
uint32_t esp_get_minimum_free_heap_size(void);
/**
* @brief Trigger a software abort
*
* @param details Details that will be displayed during panic handling.
*/
void __attribute__((__noreturn__)) esp_system_abort(const char* details);
#ifdef __cplusplus
}
#endif
#endif /* __ESP_SYSTEM_H__ */
@@ -0,0 +1,21 @@
/*
* SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#pragma once
#ifdef __cplusplus
extern "C" {
#endif
/**
* @brief Outputs a char to the configured primary and secondary console
*
* @param c char to output
*/
void esp_system_console_put_char(char c);
#ifdef __cplusplus
}
#endif
@@ -0,0 +1,31 @@
/*
* SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#pragma once
#include "esp_err.h"
#include "esp_etm.h"
#ifdef __cplusplus
extern "C" {
#endif
/**
* @brief Get the ETM event handle of systick hardware's alarm/heartbeat event
*
* @note The created ETM event object can be deleted later by calling `esp_etm_del_event`
*
* @param[in] core_id CPU core ID
* @param[out] out_event Returned ETM event handle
* @return
* - ESP_OK Success
* - ESP_ERR_INVALID_ARG Parameter error
*/
esp_err_t esp_systick_new_etm_alarm_event(int core_id, esp_etm_event_handle_t *out_event);
#ifdef __cplusplus
}
#endif
@@ -0,0 +1,60 @@
/*
* SPDX-FileCopyrightText: 2019-2022 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
/* Notes:
* 1. Put all task priority and stack size definition in this file
* 2. If the task priority is less than 10, use ESP_TASK_PRIO_MIN + X style,
* otherwise use ESP_TASK_PRIO_MAX - X style
* 3. If this is a daemon task, the macro prefix is ESP_TASKD_, otherwise
* it's ESP_TASK_
* 4. If the configMAX_PRIORITIES is modified, please make all priority are
* greater than 0
* 5. Make sure esp_task.h is consistent between wifi lib and idf
* 6. If changing system task priorities, please check the values documented in /api-guides/performance/speed.rst
* are up to date
*/
#ifndef _ESP_TASK_H_
#define _ESP_TASK_H_
#include "sdkconfig.h"
#include "freertos/FreeRTOS.h"
#include "freertos/FreeRTOSConfig.h"
#define ESP_TASK_PRIO_MAX (configMAX_PRIORITIES)
#define ESP_TASK_PRIO_MIN (0)
/* Bt contoller Task */
/* controller */
#define ESP_TASK_BT_CONTROLLER_PRIO (ESP_TASK_PRIO_MAX - 2)
#ifdef CONFIG_NEWLIB_NANO_FORMAT
#define TASK_EXTRA_STACK_SIZE (0)
#else
#define TASK_EXTRA_STACK_SIZE (512)
#endif
#define BT_TASK_EXTRA_STACK_SIZE TASK_EXTRA_STACK_SIZE
#define ESP_TASK_BT_CONTROLLER_STACK (3584 + TASK_EXTRA_STACK_SIZE)
/* Ping Task */
#define ESP_TASK_PING_STACK (2048 + TASK_EXTRA_STACK_SIZE)
/* idf task */
#define ESP_TASK_TIMER_PRIO (ESP_TASK_PRIO_MAX - 3)
#define ESP_TASK_TIMER_STACK (CONFIG_ESP_TIMER_TASK_STACK_SIZE + TASK_EXTRA_STACK_SIZE)
#define ESP_TASKD_EVENT_PRIO (ESP_TASK_PRIO_MAX - 5)
#if CONFIG_LWIP_TCPIP_CORE_LOCKING
#define ESP_TASKD_EVENT_STACK (CONFIG_ESP_SYSTEM_EVENT_TASK_STACK_SIZE + TASK_EXTRA_STACK_SIZE + 2048)
#else
#define ESP_TASKD_EVENT_STACK (CONFIG_ESP_SYSTEM_EVENT_TASK_STACK_SIZE + TASK_EXTRA_STACK_SIZE)
#endif /* CONFIG_LWIP_TCPIP_CORE_LOCKING */
#define ESP_TASK_TCPIP_PRIO (CONFIG_LWIP_TCPIP_TASK_PRIO)
#define ESP_TASK_TCPIP_STACK (CONFIG_LWIP_TCPIP_TASK_STACK_SIZE + TASK_EXTRA_STACK_SIZE)
#define ESP_TASK_MAIN_PRIO (ESP_TASK_PRIO_MIN + 1)
#define ESP_TASK_MAIN_STACK (CONFIG_ESP_MAIN_TASK_STACK_SIZE + TASK_EXTRA_STACK_SIZE)
#define ESP_TASK_MAIN_CORE CONFIG_ESP_MAIN_TASK_AFFINITY
#endif
@@ -0,0 +1,209 @@
/*
* SPDX-FileCopyrightText: 2015-2023 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#pragma once
#include <stdbool.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "esp_err.h"
#ifdef __cplusplus
extern "C" {
#endif
/**
* @brief Task Watchdog Timer (TWDT) configuration structure
*/
typedef struct {
uint32_t timeout_ms; /**< TWDT timeout duration in milliseconds */
uint32_t idle_core_mask; /**< Bitmask of the core whose idle task should be subscribed on initialization where 1 << i means that core i's idle task will be monitored by the TWDT */
bool trigger_panic; /**< Trigger panic when timeout occurs */
} esp_task_wdt_config_t;
/**
* @brief Task Watchdog Timer (TWDT) user handle
*/
typedef struct esp_task_wdt_user_handle_s * esp_task_wdt_user_handle_t;
/**
* @brief Initialize the Task Watchdog Timer (TWDT)
*
* This function configures and initializes the TWDT. This function will subscribe the idle tasks if
* configured to do so. For other tasks, users can subscribe them using esp_task_wdt_add() or esp_task_wdt_add_user().
* This function won't start the timer if no task have been registered yet.
*
* @note esp_task_wdt_init() must only be called after the scheduler is started. Moreover, it must not be called by
* multiple tasks simultaneously.
* @param[in] config Configuration structure
* @return
* - ESP_OK: Initialization was successful
* - ESP_ERR_INVALID_STATE: Already initialized
* - Other: Failed to initialize TWDT
*/
esp_err_t esp_task_wdt_init(const esp_task_wdt_config_t *config);
/**
* @brief Reconfigure the Task Watchdog Timer (TWDT)
*
* The function reconfigures the running TWDT. It must already be initialized when this function is called.
*
* @note esp_task_wdt_reconfigure() must not be called by multiple tasks simultaneously.
*
* @param[in] config Configuration structure
*
* @return
* - ESP_OK: Reconfiguring was successful
* - ESP_ERR_INVALID_STATE: TWDT not initialized yet
* - Other: Failed to initialize TWDT
*/
esp_err_t esp_task_wdt_reconfigure(const esp_task_wdt_config_t *config);
/**
* @brief Deinitialize the Task Watchdog Timer (TWDT)
*
* This function will deinitialize the TWDT, and unsubscribe any idle tasks. Calling this function whilst other tasks
* are still subscribed to the TWDT, or when the TWDT is already deinitialized, will result in an error code being
* returned.
*
* @note esp_task_wdt_deinit() must not be called by multiple tasks simultaneously.
* @return
* - ESP_OK: TWDT successfully deinitialized
* - Other: Failed to deinitialize TWDT
*/
esp_err_t esp_task_wdt_deinit(void);
/**
* @brief Subscribe a task to the Task Watchdog Timer (TWDT)
*
* This function subscribes a task to the TWDT. Each subscribed task must periodically call esp_task_wdt_reset() to
* prevent the TWDT from elapsing its timeout period. Failure to do so will result in a TWDT timeout.
*
* @param task_handle Handle of the task. Input NULL to subscribe the current running task to the TWDT
* @return
* - ESP_OK: Successfully subscribed the task to the TWDT
* - Other: Failed to subscribe task
*/
esp_err_t esp_task_wdt_add(TaskHandle_t task_handle);
/**
* @brief Subscribe a user to the Task Watchdog Timer (TWDT)
*
* This function subscribes a user to the TWDT. A user of the TWDT is usually a function that needs to run
* periodically. Each subscribed user must periodically call esp_task_wdt_reset_user() to prevent the TWDT from elapsing
* its timeout period. Failure to do so will result in a TWDT timeout.
*
* @param[in] user_name String to identify the user
* @param[out] user_handle_ret Handle of the user
* @return
* - ESP_OK: Successfully subscribed the user to the TWDT
* - Other: Failed to subscribe user
*/
esp_err_t esp_task_wdt_add_user(const char *user_name, esp_task_wdt_user_handle_t *user_handle_ret);
/**
* @brief Reset the Task Watchdog Timer (TWDT) on behalf of the currently running task
*
* This function will reset the TWDT on behalf of the currently running task. Each subscribed task must periodically
* call this function to prevent the TWDT from timing out. If one or more subscribed tasks fail to reset the TWDT on
* their own behalf, a TWDT timeout will occur.
*
* @return
* - ESP_OK: Successfully reset the TWDT on behalf of the currently running task
* - Other: Failed to reset
*/
esp_err_t esp_task_wdt_reset(void);
/**
* @brief Reset the Task Watchdog Timer (TWDT) on behalf of a user
*
* This function will reset the TWDT on behalf of a user. Each subscribed user must periodically call this function to
* prevent the TWDT from timing out. If one or more subscribed users fail to reset the TWDT on their own behalf, a TWDT
* timeout will occur.
*
* @param[in] user_handle User handle
* - ESP_OK: Successfully reset the TWDT on behalf of the user
* - Other: Failed to reset
*/
esp_err_t esp_task_wdt_reset_user(esp_task_wdt_user_handle_t user_handle);
/**
* @brief Unsubscribes a task from the Task Watchdog Timer (TWDT)
*
* This function will unsubscribe a task from the TWDT. After being unsubscribed, the task should no longer call
* esp_task_wdt_reset().
*
* @param[in] task_handle Handle of the task. Input NULL to unsubscribe the current running task.
* @return
* - ESP_OK: Successfully unsubscribed the task from the TWDT
* - Other: Failed to unsubscribe task
*/
esp_err_t esp_task_wdt_delete(TaskHandle_t task_handle);
/**
* @brief Unsubscribes a user from the Task Watchdog Timer (TWDT)
*
* This function will unsubscribe a user from the TWDT. After being unsubscribed, the user should no longer call
* esp_task_wdt_reset_user().
*
* @param[in] user_handle User handle
* @return
* - ESP_OK: Successfully unsubscribed the user from the TWDT
* - Other: Failed to unsubscribe user
*/
esp_err_t esp_task_wdt_delete_user(esp_task_wdt_user_handle_t user_handle);
/**
* @brief Query whether a task is subscribed to the Task Watchdog Timer (TWDT)
*
* This function will query whether a task is currently subscribed to the TWDT, or whether the TWDT is initialized.
*
* @param[in] task_handle Handle of the task. Input NULL to query the current running task.
* @return:
* - ESP_OK: The task is currently subscribed to the TWDT
* - ESP_ERR_NOT_FOUND: The task is not subscribed
* - ESP_ERR_INVALID_STATE: TWDT was never initialized
*/
esp_err_t esp_task_wdt_status(TaskHandle_t task_handle);
/**
* @brief User ISR callback placeholder
*
* This function is called by task_wdt_isr function (ISR for when TWDT times out). It can be defined in user code to
* handle TWDT events.
*
* @note It has the same limitations as the interrupt function. Do not use ESP_LOGx functions inside.
*/
void __attribute__((weak)) esp_task_wdt_isr_user_handler(void);
typedef void (*task_wdt_msg_handler)(void *opaque, const char *msg);
/**
* @brief Prints or retrieves information about tasks/users that triggered the Task Watchdog Timeout.
*
* This function provides various operations to handle tasks/users that did not reset the Task Watchdog in time.
* It can print detailed information about these tasks/users, such as their names, associated CPUs, and whether they have been reset.
* Additionally, it can retrieve the total length of the printed information or the CPU affinity of the failing tasks.
*
* @param[in] msg_handler Optional message handler function that will be called for each printed line.
* @param[in] opaque Optional pointer to opaque data that will be passed to the message handler function.
* @param[out] cpus_fail Optional pointer to an integer where the CPU affinity of the failing tasks will be stored.
*
* @return
* - ESP_OK: The function executed successfully.
* - ESP_FAIL: No triggered tasks were found, and thus no information was printed or retrieved.
*
* @note
* - If `msg_handler` is not provided, the information will be printed to console using ESP_EARLY_LOGE.
* - If `msg_handler` is provided, the function will send the printed information to the provided message handler function.
* - If `cpus_fail` is provided, the function will store the CPU affinity of the failing tasks in the provided integer.
* - During the execution of this function, logging is allowed in critical sections, as TWDT timeouts are considered fatal errors.
*/
esp_err_t esp_task_wdt_print_triggered_tasks(task_wdt_msg_handler msg_handler, void *opaque, int *cpus_fail);
#ifdef __cplusplus
}
#endif
@@ -0,0 +1,63 @@
/*
* SPDX-FileCopyrightText: 2021 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#pragma once
#include <stdint.h>
#include "esp_err.h"
#include "esp_intr_alloc.h"
#ifdef __cplusplus
extern "C" {
#endif
/**
* @brief esp_xt_wdt configuration struct
*
*/
typedef struct {
uint8_t timeout; /*!< Watchdog timeout */
bool auto_backup_clk_enable; /*!< Enable automatic switch to backup clock at timeout */
} esp_xt_wdt_config_t;
/* Callback function for WDT interrupt*/
typedef void (*esp_xt_callback_t)(void *arg);
/**
* @brief Initializes the xtal32k watchdog timer
*
* @param cfg Pointer to configuration struct
* @return esp_err_t
* - ESP_OK: XTWDT was successfully enabled
* - ESP_ERR_NO_MEM: Failed to allocate ISR
*/
esp_err_t esp_xt_wdt_init(const esp_xt_wdt_config_t *cfg);
/**
* @brief Register a callback function that will be called when the watchdog
* times out.
*
* @note This function will be called from an interrupt context where the cache might be disabled.
* Thus the function should be placed in IRAM and must not perform any blocking operations.
*
* Only one callback function can be registered, any call to esp_xt_wdt_register_callback
* will override the previous callback function.
*
* @param func The callback function to register
* @param arg Pointer to argument that will be passed to the callback function
*/
void esp_xt_wdt_register_callback(esp_xt_callback_t func, void *arg);
/**
* @brief Restores the xtal32k clock and re-enables the WDT
*
*/
void esp_xt_wdt_restore_clk(void);
#ifdef __cplusplus
}
#endif
@@ -0,0 +1,136 @@
/*
* SPDX-FileCopyrightText: 2020-2024 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#pragma once
#include "sdkconfig.h"
#include <stddef.h>
#include <stdint.h>
#if CONFIG_IDF_TARGET_ARCH_RISCV
#include "libunwind-riscv.h"
#elif CONFIG_IDF_TARGET_X86
#include "libunwind-x86.h"
#else
/* This header must be a standalone one, so, it shall not trigger an error when
* pre-processed without including any of the architecture header above.
* The implementation can trigger a compile error if UNW_UNKNOWN_TARGET
* macro is defined. */
#define UNW_UNKNOWN_TARGET 1
typedef void* ExecutionFrame;
#endif
#ifdef __cplusplus
extern "C" {
#endif
/* Error codes returned by the functions defined below */
#define UNW_ESUCCESS 0
#define UNW_EUNSPEC 1 /* General failure */
#define UNW_EBADREG 3 /* Register given is wrong */
#define UNW_ESTOPUNWIND 5
#define UNW_EINVAL 8 /* Bad parameter or unimplemented operation */
#define UNW_EBADVERSION 9
#define UNW_ENOINFO 10
/* A libunwind context is the equivalent of an ESP-IDF ExecutionFrame */
typedef ExecutionFrame unw_context_t;
/* A register number is an unsigned word in our case */
typedef uint32_t unw_regnum_t;
/* In our current implementation, a cursor is the same as a context */
typedef unw_context_t unw_cursor_t;
/* long should represent the size of a CPU register */
typedef unsigned long unw_word_t;
/* At the moment, we don't support the operations using the following types,
* so just set them to void* */
typedef void* unw_addr_space_t;
typedef void* unw_fpreg_t;
/**
* @brief Get the current CPU context.
*
* @param[out] ctx Pointer to `unw_context_t` structure. It must not be NULL
* as it will be filled with the CPU registers value
*
* @return UNW_ESUCCESS on success, -UNW_EUNSPEC if ctx is NULL
*
* @note This function MUST be inlined. Marking it as "static inline" or
* __attribute__((always_inline)) does not guarantee that it will inlined by
* the compiler for all the architectures. Thus, define this function as a macro.
* @note If the caller of this function returns, all the pointers, contexts, cursors
* generated out of the initial returned context shall be considered invalid and
* thus, must **not** be used.
*/
#define unw_getcontext(ctx) ({ int retval; \
if (ctx == NULL) { \
retval = -UNW_EUNSPEC; \
} else { \
UNW_GET_CONTEXT(ctx); \
retval = UNW_ESUCCESS; \
} \
retval; \
})
/**
* @brief Initialize a cursor on a local context. Multiple cursor can be initialized on
* a given CPU context, they can then be manipulated independently.
*
* @param[out] c Pointer on cursor to be returned. Must not be NULL
* @param[in] ctx Pointer on the context returned by the function `unw_getcontext`
*
* @return UNW_ESUCCESS on success, -UNW_EUNSPEC if one of the parameter is NULL.
*/
int unw_init_local(unw_cursor_t* c, unw_context_t* ctx);
/**
* @brief Perform a step "up" on the given cursor. After calling this function, the
* cursor will point to the caller's CPU context. Thus, it is then possible
* to retrieve the caller's address by getting the PC register out of the cursor.
* Check `unw_get_reg` function for this.
*
* @param[in] cp Current cursor
*
* @returns 0 if the previous frame was the last one
* @returns Positive value on success
* @returns -UNW_EBADVERSION if the DWARF information's version is not compatible with the eh_frame_parser implementation
* @returns -UNW_ENOINFO if the caller information are not present in the binary. (if the caller is in ROM for example)
* @returns -UNW_ESTOPUNWIND if unwinding is terminated
*/
int unw_step(unw_cursor_t* cp);
/**
* @brief Get the value of a CPU register from a given cursor.
*
* @param[in] cp Pointer to the cursor
* @param reg Register number to retrieve the value of
* @param[out] valp Pointer that will be filled with the register value
*
* @returns UNW_ESUCCESS on success
* @returns -UNW_EUNSPEC if any pointer passed is NULL
* @returns -UNW_EBADREG if the register number is invalid
*/
int unw_get_reg(unw_cursor_t* cp, unw_regnum_t reg, unw_word_t* valp);
/**
* @brief Set the value of a CPU register in a given cursor.
*
* @param[in]cp Pointer to the cursor
* @param reg Register number to set the value of
* @param val New register value
*
* @returns UNW_ESUCCESS on success
* @returns -UNW_EUNSPEC if the pointer passed is NULL
* @returns -UNW_EBADREG if the register number is invalid
*/
int unw_set_reg(unw_cursor_t* cp, unw_regnum_t reg, unw_word_t val);
#ifdef __cplusplus
}
#endif
@@ -0,0 +1,75 @@
/*
* SPDX-FileCopyrightText: 2015-2024 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#pragma once
#include <stdbool.h>
#include <stdint.h>
#ifdef __cplusplus
extern "C" {
#endif
/**
* @brief Cache error information
*/
typedef struct {
const char* err_str; /*!< Error message for the current panic */
uint32_t vaddr; /*!< Virtual address that caused the error */
uint32_t size; /*!< Size of the access which caused the error */
} esp_cache_err_info_t;
/**
* @brief initialize cache invalid access interrupt
*
* This function enables cache invalid access interrupt source and connects it
* to interrupt input number. It is called from the startup code.
*
* On ESP32, the interrupt input number is ETS_MEMACCESS_ERR_INUM. On other targets
* it is ETS_CACHEERR_INUM. See soc/soc.h for more information.
*/
void esp_cache_err_int_init(void);
/**
* @brief get the CPU which caused cache invalid access interrupt. Helper function in
* panic handling.
* @return
* - PRO_CPU_NUM, if PRO_CPU has caused cache IA interrupt
* - APP_CPU_NUM, if APP_CPU has caused cache IA interrupt
* - (-1) otherwise
*/
int esp_cache_err_get_cpuid(void);
/**
* @brief Get error info for the current cache exception
*
* @err_info struct containing the information of the current error
*/
void esp_cache_err_get_panic_info(esp_cache_err_info_t *err_info);
/**
* @brief Checks if any cache errors are active
*
* @return true
* @return false
*/
bool esp_cache_err_has_active_err(void);
#if SOC_CACHE_ACS_INVALID_STATE_ON_PANIC
/**
* @brief Saves and clears active access errors
*
* @note Some access errors needs to be cleared to allow the cache to operate again,
* otherwise accessing e.g rodata from flash might give invalid data
*
*/
void esp_cache_err_acs_save_and_clr(void);
#endif //SOC_CACHE_ACS_INVALID_STATE_ON_PANIC
#ifdef __cplusplus
}
#endif
@@ -0,0 +1,39 @@
/*
* SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#pragma once
#include "sdkconfig.h"
#ifdef __cplusplus
extern "C" {
#endif
#ifdef CONFIG_ESP_IPC_ISR_ENABLE
/**
* @brief Initialize the IPC ISR interrupt for a specific CPU.
*
* This function initializes the IPC ISR (Inter-Processor Communication Interrupt)
* for a specific CPU core. It configures the interrupt source and enables the
* IPC ISR interrupt for the specified CPU.
*
* @param[in] cpuid The ID of the CPU core to initialize IPC ISR for.
*/
void esp_ipc_isr_port_init(const int cpuid);
/**
* @brief Trigger an interrupt on a specific CPU core.
*
* @param[in] cpuid The ID of the CPU core to trigger the interrupt on (0 or 1).
*/
void esp_ipc_isr_port_int_trigger(const int cpuid);
#endif // CONFIG_ESP_IPC_ISR_ENABLE
#ifdef __cplusplus
}
#endif
@@ -0,0 +1,136 @@
/*
* SPDX-FileCopyrightText: 2023-2024 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#pragma once
#ifndef __ASSEMBLER__
#include "sdkconfig.h"
#include <stdbool.h>
#include <stdint.h>
#ifdef __cplusplus
extern "C" {
#endif
#define ESP_HW_STACK_GUARD_NOT_FIRED UINT32_MAX
/* The functions below are designed to be used in interrupt/panic handler
* In case using them in user's code put them into critical section.*/
void esp_hw_stack_guard_monitor_start(void);
void esp_hw_stack_guard_monitor_stop(void);
void esp_hw_stack_guard_set_bounds(uint32_t sp_min, uint32_t sp_max);
void esp_hw_stack_guard_get_bounds(uint32_t core_id, uint32_t *sp_min, uint32_t *sp_max);
uint32_t esp_hw_stack_guard_get_fired_cpu(void);
uint32_t esp_hw_stack_guard_get_pc(uint32_t core_id);
#ifdef __cplusplus
};
#endif
#else // __ASSEMBLER__
#include "hal/assist_debug_ll.h"
#define ASSIST_DEBUG_CORE_0_MONITOR_REG_IMM (ASSIST_DEBUG_CORE_0_MONITOR_REG >> 12)
#define ASSIST_DEBUG_CORE_0_SP_MIN_OFFSET (ASSIST_DEBUG_CORE_0_SP_MIN_REG - DR_REG_ASSIST_DEBUG_BASE)
#define ASSIST_DEBUG_CORE_0_SP_MAX_OFFSET (ASSIST_DEBUG_CORE_0_SP_MAX_REG - DR_REG_ASSIST_DEBUG_BASE)
#define ASSIST_DEBUG_CORE_0_SP_SPILL_OFFSET (ASSIST_DEBUG_CORE_0_MONITOR_REG - DR_REG_ASSIST_DEBUG_BASE)
.macro ESP_HW_STACK_GUARD_SET_BOUNDS_CPU0 reg1
lui \reg1, ASSIST_DEBUG_CORE_0_MONITOR_REG_IMM
sw a0, ASSIST_DEBUG_CORE_0_SP_MIN_OFFSET(\reg1)
sw a1, ASSIST_DEBUG_CORE_0_SP_MAX_OFFSET(\reg1)
.endm
.macro ESP_HW_STACK_GUARD_MONITOR_STOP_CPU0 reg1 reg2
lui \reg1, ASSIST_DEBUG_CORE_0_MONITOR_REG_IMM
lw \reg2, ASSIST_DEBUG_CORE_0_SP_SPILL_OFFSET(\reg1)
andi \reg2, \reg2, ~ASSIST_DEBUG_SP_SPILL_BITS
sw \reg2, ASSIST_DEBUG_CORE_0_SP_SPILL_OFFSET(\reg1)
.endm
.macro ESP_HW_STACK_GUARD_MONITOR_START_CPU0 reg1 reg2
lui \reg1, ASSIST_DEBUG_CORE_0_MONITOR_REG_IMM
lw \reg2, ASSIST_DEBUG_CORE_0_SP_SPILL_OFFSET(\reg1)
ori \reg2, \reg2, ASSIST_DEBUG_SP_SPILL_BITS
sw \reg2, ASSIST_DEBUG_CORE_0_SP_SPILL_OFFSET(\reg1)
.endm
#if SOC_CPU_CORES_NUM > 1
#define ASSIST_DEBUG_CORE_1_MONITOR_REG_IMM (ASSIST_DEBUG_CORE_1_MONITOR_REG >> 12)
#define ASSIST_DEBUG_CORE_1_SP_MIN_OFFSET (ASSIST_DEBUG_CORE_1_SP_MIN_REG - DR_REG_ASSIST_DEBUG_BASE)
#define ASSIST_DEBUG_CORE_1_SP_MAX_OFFSET (ASSIST_DEBUG_CORE_1_SP_MAX_REG - DR_REG_ASSIST_DEBUG_BASE)
#define ASSIST_DEBUG_CORE_1_SP_SPILL_OFFSET (ASSIST_DEBUG_CORE_1_MONITOR_REG - DR_REG_ASSIST_DEBUG_BASE)
.macro ESP_HW_STACK_GUARD_SET_BOUNDS_CPU1 reg1
lui \reg1, ASSIST_DEBUG_CORE_1_MONITOR_REG_IMM
sw a0, ASSIST_DEBUG_CORE_1_SP_MIN_OFFSET(\reg1)
sw a1, ASSIST_DEBUG_CORE_1_SP_MAX_OFFSET(\reg1)
.endm
.macro ESP_HW_STACK_GUARD_MONITOR_STOP_CPU1 reg1 reg2
lui \reg1, ASSIST_DEBUG_CORE_1_MONITOR_REG_IMM
lw \reg2, ASSIST_DEBUG_CORE_1_SP_SPILL_OFFSET(\reg1)
andi \reg2, \reg2, ~ASSIST_DEBUG_SP_SPILL_BITS
sw \reg2, ASSIST_DEBUG_CORE_1_SP_SPILL_OFFSET(\reg1)
.endm
.macro ESP_HW_STACK_GUARD_MONITOR_START_CPU1 reg1 reg2
lui \reg1, ASSIST_DEBUG_CORE_1_MONITOR_REG_IMM
lw \reg2, ASSIST_DEBUG_CORE_1_SP_SPILL_OFFSET(\reg1)
ori \reg2, \reg2, ASSIST_DEBUG_SP_SPILL_BITS
sw \reg2, ASSIST_DEBUG_CORE_1_SP_SPILL_OFFSET(\reg1)
.endm
.macro ESP_HW_STACK_GUARD_SET_BOUNDS_CUR_CORE reg1
/* Check the current core ID */
csrr \reg1, mhartid
beqz \reg1, 1f
/* Core 1 */
ESP_HW_STACK_GUARD_SET_BOUNDS_CPU1 \reg1
j 2f
1:
/* Core 0 */
ESP_HW_STACK_GUARD_SET_BOUNDS_CPU0 \reg1
2:
.endm
.macro ESP_HW_STACK_GUARD_MONITOR_START_CUR_CORE reg1 reg2
/* Check the current core ID */
csrr \reg1, mhartid
beqz \reg1, 1f
/* Core 1 */
ESP_HW_STACK_GUARD_MONITOR_START_CPU1 \reg1 \reg2
j 2f
1:
/* Core 0 */
ESP_HW_STACK_GUARD_MONITOR_START_CPU0 \reg1 \reg2
2:
.endm
.macro ESP_HW_STACK_GUARD_MONITOR_STOP_CUR_CORE reg1 reg2
/* Check the current core ID */
csrr \reg1, mhartid
beqz \reg1, 1f
/* Core 1 */
ESP_HW_STACK_GUARD_MONITOR_STOP_CPU1 \reg1 \reg2
j 2f
1:
/* Core 0 */
ESP_HW_STACK_GUARD_MONITOR_STOP_CPU0 \reg1 \reg2
2:
.endm
#else // SOC_CPU_CORES_NUM <= 1
#define ESP_HW_STACK_GUARD_SET_BOUNDS_CUR_CORE ESP_HW_STACK_GUARD_SET_BOUNDS_CPU0
#define ESP_HW_STACK_GUARD_MONITOR_START_CUR_CORE ESP_HW_STACK_GUARD_MONITOR_START_CPU0
#define ESP_HW_STACK_GUARD_MONITOR_STOP_CUR_CORE ESP_HW_STACK_GUARD_MONITOR_STOP_CPU0
#endif // SOC_CPU_CORES_NUM > 1
#endif // __ASSEMBLER__
@@ -0,0 +1,45 @@
/*
* SPDX-FileCopyrightText: 2023-2024 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#pragma once
#include <stdint.h>
#include <stddef.h>
#include <string.h>
#include "esp_err.h"
#ifdef __cplusplus
extern "C" {
#endif
/**
* @brief Image process driver
*/
typedef struct image_process_driver_s image_process_driver_t;
/**
* @brief Image process flow
* @note This API first reads the image header, then process the segments from the image header.
* This API can be further inserted with more steps about the image processing by registering
* more function pointer in `image_process_driver_t`.
*
* @return
* - ESP_OK
* - ESP_FAIL: image process flow fails
*/
esp_err_t image_process(void);
/**
* @brief get flash segments info, only available after image_process() has been called
*
* @param[out] out_drom_paddr_start drom paddr start
* @param[out] out_irom_paddr_start irom paddr start
*/
void image_process_get_flash_segments_info(uint32_t *out_drom_paddr_start, uint32_t *out_irom_paddr_start);
#ifdef __cplusplus
}
#endif
@@ -0,0 +1,71 @@
/*
* SPDX-FileCopyrightText: 2015-2021 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#include "sdkconfig.h"
#include "esp_err.h"
#include "eri.h"
#include "xtensa-debug-module.h"
#include "xt_trax.h"
#ifdef __cplusplus
extern "C" {
#endif
typedef enum {
TRAX_DOWNCOUNT_WORDS,
TRAX_DOWNCOUNT_INSTRUCTIONS
} trax_downcount_unit_t;
typedef enum {
TRAX_ENA_NONE = 0,
TRAX_ENA_PRO,
TRAX_ENA_APP,
TRAX_ENA_PRO_APP,
TRAX_ENA_PRO_APP_SWAP
} trax_ena_select_t;
/**
* @brief Enable the trax memory blocks to be used as Trax memory.
*
* @param pro_cpu_enable : true if Trax needs to be enabled for the pro CPU
* @param app_cpu_enable : true if Trax needs to be enabled for the pro CPU
* @param swap_regions : Normally, the pro CPU writes to Trax mem block 0 while
* the app cpu writes to block 1. Setting this to true
* inverts this.
*
* @return esp_err_t. Fails with ESP_ERR_NO_MEM if Trax enable is requested for 2 CPUs
* but memmap only has room for 1, or if Trax memmap is disabled
* entirely.
*/
int trax_enable(trax_ena_select_t ena);
/**
* @brief Start a Trax trace on the current CPU
*
* @param units_until_stop : Set the units of the delay that gets passed to
* trax_trigger_traceend_after_delay. One of TRAX_DOWNCOUNT_WORDS
* or TRAX_DOWNCOUNT_INSTRUCTIONS.
*
* @return esp_err_t. Fails with ESP_ERR_NO_MEM if Trax is disabled.
*/
int trax_start_trace(trax_downcount_unit_t units_until_stop);
/**
* @brief Trigger a Trax trace stop after the indicated delay. If this is called
* before and the previous delay hasn't ended yet, this will overwrite
* that delay with the new value. The delay will always start at the time
* the function is called.
*
* @param delay : The delay to stop the trace in, in the unit indicated to
* trax_start_trace. Note: the trace memory has 4K words available.
*
* @return esp_err_t
*/
int trax_trigger_traceend_after_delay(int delay);
#ifdef __cplusplus
}
#endif