mirror of
https://github.com/espressif/esp-idf.git
synced 2025-08-08 07:04:32 +02:00
freertos: FreeRTOS SMP RISC-V port cleanup and enable esp32c3 in KConfig
This commit does general cleanup of the risc-v port files and restricts FreeRTOS SMP config option to only esp32 and esp32c3.
This commit is contained in:
@@ -17,54 +17,14 @@ This file get's pulled into assembly sources. Therefore, some includes need to b
|
|||||||
#include <assert.h> //For configASSERT()
|
#include <assert.h> //For configASSERT()
|
||||||
#endif /* def __ASSEMBLER__ */
|
#endif /* def __ASSEMBLER__ */
|
||||||
|
|
||||||
#if __XTENSA__
|
|
||||||
/* Required for configuration-dependent settings. */
|
|
||||||
#include "xtensa_config.h"
|
|
||||||
|
|
||||||
/* -------------------------------------------- Xtensa Additional Config ----------------------------------------------
|
|
||||||
* - Provide Xtensa definitions usually given by -D option when building with xt-make (see readme_xtensa.txt)
|
|
||||||
* - xtensa_rtos.h and xtensa_timer.h will default some of these values
|
|
||||||
* - XT_SIMULATOR configXT_SIMULATOR
|
|
||||||
* - XT_BOARD configXT_BOARD
|
|
||||||
* - XT_CLOCK_FREQ Should not be defined as we are using XT_BOARD mode
|
|
||||||
* - XT_TICK_PER_SEC Defaults to configTICK_RATE_HZ
|
|
||||||
* - XT_TIMER_INDEX Defaults to configXT_TIMER_INDEX
|
|
||||||
* - XT_INTEXC_HOOKS Defaults to configXT_INTEXC_HOOKS
|
|
||||||
* - XT_USE_OVLY We don't define this (unused)
|
|
||||||
* - XT_USE_SWPRI We don't define this (unused)
|
|
||||||
* ------------------------------------------------------------------------------------------------------------------ */
|
|
||||||
|
|
||||||
#define configXT_SIMULATOR 0
|
|
||||||
#define configXT_BOARD 1 /* Board mode */
|
|
||||||
#if CONFIG_FREERTOS_CORETIMER_0
|
|
||||||
#define configXT_TIMER_INDEX 0
|
|
||||||
#elif CONFIG_FREERTOS_CORETIMER_1
|
|
||||||
#define configXT_TIMER_INDEX 1
|
|
||||||
#endif
|
|
||||||
#define configXT_INTEXC_HOOKS 0
|
|
||||||
|
|
||||||
#define configBENCHMARK 0
|
|
||||||
#endif // __XTENSA__
|
|
||||||
|
|
||||||
/* ------------------------------------------------ ESP-IDF Additions --------------------------------------------------
|
/* ------------------------------------------------ ESP-IDF Additions --------------------------------------------------
|
||||||
*
|
*
|
||||||
* ------------------------------------------------------------------------------------------------------------------ */
|
* ------------------------------------------------------------------------------------------------------------------ */
|
||||||
|
|
||||||
#if __XTENSA__
|
|
||||||
/* The Xtensa port uses a separate interrupt stack. Adjust the stack size
|
|
||||||
* to suit the needs of your specific application.
|
|
||||||
* Size needs to be aligned to the stack increment, since the location of
|
|
||||||
* the stack for the 2nd CPU will be calculated using configISR_STACK_SIZE.
|
|
||||||
*/
|
|
||||||
#define configSTACK_ALIGNMENT 16
|
|
||||||
#ifndef configISR_STACK_SIZE
|
|
||||||
#define configISR_STACK_SIZE ((CONFIG_FREERTOS_ISR_STACKSIZE + configSTACK_ALIGNMENT - 1) & (~(configSTACK_ALIGNMENT - 1)))
|
|
||||||
#endif
|
|
||||||
#else // RISC-V
|
|
||||||
#ifndef configISR_STACK_SIZE
|
#ifndef configISR_STACK_SIZE
|
||||||
#define configISR_STACK_SIZE (CONFIG_FREERTOS_ISR_STACKSIZE)
|
#define configISR_STACK_SIZE (CONFIG_FREERTOS_ISR_STACKSIZE)
|
||||||
#endif
|
#endif
|
||||||
#endif // __XTENSA__
|
|
||||||
/* ----------------------------------------------------- Helpers -------------------------------------------------------
|
/* ----------------------------------------------------- Helpers -------------------------------------------------------
|
||||||
* - Macros that the FreeRTOS configuration macros depend on
|
* - Macros that the FreeRTOS configuration macros depend on
|
||||||
* ------------------------------------------------------------------------------------------------------------------ */
|
* ------------------------------------------------------------------------------------------------------------------ */
|
||||||
@@ -188,6 +148,8 @@ This file get's pulled into assembly sources. Therefore, some includes need to b
|
|||||||
#endif // CONFIG_FREERTOS_TLSP_DELETION_CALLBACKS
|
#endif // CONFIG_FREERTOS_TLSP_DELETION_CALLBACKS
|
||||||
#define configSTACK_DEPTH_TYPE uint32_t
|
#define configSTACK_DEPTH_TYPE uint32_t
|
||||||
#define configUSE_NEWLIB_REENTRANT 1
|
#define configUSE_NEWLIB_REENTRANT 1
|
||||||
|
#define configNEWLIB_REENTRANT_IS_DYNAMIC 1 // IDF Newlib supports dynamic reentrancy.
|
||||||
|
// We provide our own __getreent() function
|
||||||
#define configENABLE_BACKWARD_COMPATIBILITY 0
|
#define configENABLE_BACKWARD_COMPATIBILITY 0
|
||||||
#define configASSERT(a) assert(a)
|
#define configASSERT(a) assert(a)
|
||||||
#define configINCLUDE_FREERTOS_TASK_C_ADDITIONS_H 1
|
#define configINCLUDE_FREERTOS_TASK_C_ADDITIONS_H 1
|
||||||
|
@@ -49,11 +49,8 @@ typedef uint32_t TickType_t;
|
|||||||
#define portTASK_FUNCTION_PROTO( vFunction, pvParameters ) void vFunction( void *pvParameters )
|
#define portTASK_FUNCTION_PROTO( vFunction, pvParameters ) void vFunction( void *pvParameters )
|
||||||
#define portTASK_FUNCTION( vFunction, pvParameters ) void vFunction( void *pvParameters )
|
#define portTASK_FUNCTION( vFunction, pvParameters ) void vFunction( void *pvParameters )
|
||||||
|
|
||||||
//TODO: Check this
|
|
||||||
// interrupt module will mask interrupt with priority less than threshold
|
// interrupt module will mask interrupt with priority less than threshold
|
||||||
#define RVHAL_EXCM_LEVEL 4
|
#define RVHAL_EXCM_LEVEL 4
|
||||||
// TODO: Check this end
|
|
||||||
|
|
||||||
|
|
||||||
/* ----------------------------------------------- Port Configurations -------------------------------------------------
|
/* ----------------------------------------------- Port Configurations -------------------------------------------------
|
||||||
* - Configurations values supplied by each port
|
* - Configurations values supplied by each port
|
||||||
@@ -67,127 +64,28 @@ typedef uint32_t TickType_t;
|
|||||||
#define portNOP() __asm volatile (" nop ")
|
#define portNOP() __asm volatile (" nop ")
|
||||||
|
|
||||||
/* ---------------------------------------------- Forward Declarations -------------------------------------------------
|
/* ---------------------------------------------- Forward Declarations -------------------------------------------------
|
||||||
* - Forward declarations of all the port functions and macros need to implement the FreeRTOS porting interface
|
* - Forward declarations of all the port functions and macros needed to implement the FreeRTOS porting interface
|
||||||
* - These must come before definition/declaration of the FreeRTOS porting interface
|
* - These must come before definition/declaration of the FreeRTOS porting interface
|
||||||
* ------------------------------------------------------------------------------------------------------------------ */
|
* ------------------------------------------------------------------------------------------------------------------ */
|
||||||
|
|
||||||
/* ---------------------- Spinlocks ------------------------
|
/* ---------------------- Spinlocks ------------------------
|
||||||
- Spinlocks added to match API with SMP FreeRTOS. Single core RISC-V does not need spin locks
|
- Spinlocks added to match API with SMP FreeRTOS. Single core RISC-V does not need spin locks
|
||||||
- Because single core does not have a primitive spinlock data type, we have to implement one here
|
|
||||||
* @note [refactor-todo] Refactor critical section API so that this is no longer required
|
|
||||||
* ------------------------------------------------------ */
|
* ------------------------------------------------------ */
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Spinlock object
|
|
||||||
* Owner:
|
|
||||||
* - Set to 0 if uninitialized
|
|
||||||
* - Set to portMUX_FREE_VAL when free
|
|
||||||
* - Set to CORE_ID_REGVAL_PRO or CORE_ID_REGVAL_AP when locked
|
|
||||||
* - Any other value indicates corruption
|
|
||||||
* Count:
|
|
||||||
* - 0 if unlocked
|
|
||||||
* - Recursive count if locked
|
|
||||||
*
|
|
||||||
* @note Not a true spinlock as single core RISC-V does not have atomic compare and set instruction
|
|
||||||
* @note Keep portMUX_INITIALIZER_UNLOCKED in sync with this struct
|
|
||||||
*/
|
|
||||||
//typedef struct {
|
|
||||||
// uint32_t owner;
|
|
||||||
// uint32_t count;
|
|
||||||
//} portMUX_TYPE;
|
|
||||||
typedef spinlock_t portMUX_TYPE; /**< Spinlock type used by FreeRTOS critical sections */
|
typedef spinlock_t portMUX_TYPE; /**< Spinlock type used by FreeRTOS critical sections */
|
||||||
#if 0
|
|
||||||
#define portMUX_INITIALIZER_UNLOCKED { \
|
|
||||||
.owner = portMUX_FREE_VAL, \
|
|
||||||
.count = 0, \
|
|
||||||
}
|
|
||||||
#define portMUX_FREE_VAL SPINLOCK_FREE /**< Spinlock is free. [refactor-todo] check if this is still required */
|
|
||||||
#define portMUX_NO_TIMEOUT SPINLOCK_WAIT_FOREVER /**< When passed for 'timeout_cycles', spin forever if necessary. [refactor-todo] check if this is still required */
|
|
||||||
#define portMUX_TRY_LOCK SPINLOCK_NO_WAIT /**< Try to acquire the spinlock a single time only. [refactor-todo] check if this is still required */
|
|
||||||
#define portMUX_INITIALIZE(mux) ({ \
|
|
||||||
(mux)->owner = portMUX_FREE_VAL; \
|
|
||||||
(mux)->count = 0; \
|
|
||||||
})
|
|
||||||
#endif
|
|
||||||
#define portMUX_INITIALIZER_UNLOCKED SPINLOCK_INITIALIZER /**< Spinlock initializer */
|
#define portMUX_INITIALIZER_UNLOCKED SPINLOCK_INITIALIZER /**< Spinlock initializer */
|
||||||
#define portMUX_FREE_VAL SPINLOCK_FREE /**< Spinlock is free. [refactor-todo] check if this is still required */
|
#define portMUX_FREE_VAL SPINLOCK_FREE /**< Spinlock is free. [refactor-todo] check if this is still required */
|
||||||
#define portMUX_NO_TIMEOUT SPINLOCK_WAIT_FOREVER /**< When passed for 'timeout_cycles', spin forever if necessary. [refactor-todo] check if this is still required */
|
#define portMUX_NO_TIMEOUT SPINLOCK_WAIT_FOREVER /**< When passed for 'timeout_cycles', spin forever if necessary. [refactor-todo] check if this is still required */
|
||||||
#define portMUX_TRY_LOCK SPINLOCK_NO_WAIT /**< Try to acquire the spinlock a single time only. [refactor-todo] check if this is still required */
|
#define portMUX_TRY_LOCK SPINLOCK_NO_WAIT /**< Try to acquire the spinlock a single time only. [refactor-todo] check if this is still required */
|
||||||
#define portMUX_INITIALIZE(mux) spinlock_initialize(mux) /*< Initialize a spinlock to its unlocked state */
|
#define portMUX_INITIALIZE(mux) spinlock_initialize(mux) /*< Initialize a spinlock to its unlocked state */
|
||||||
|
|
||||||
|
|
||||||
// ----------------------- Memory --------------------------
|
|
||||||
|
|
||||||
// --------------------- Interrupts ------------------------
|
// --------------------- Interrupts ------------------------
|
||||||
|
|
||||||
BaseType_t xPortCheckIfInISR(void);
|
BaseType_t xPortCheckIfInISR(void);
|
||||||
|
|
||||||
// TODO: Check this
|
|
||||||
#if 0
|
|
||||||
/**
|
|
||||||
* @brief Checks if the current core is in an ISR context
|
|
||||||
*
|
|
||||||
* - ISR context consist of Low/Mid priority ISR, or time tick ISR
|
|
||||||
* - High priority ISRs aren't detected here, but they normally cannot call C code, so that should not be an issue anyway.
|
|
||||||
*
|
|
||||||
* @note [refactor-todo] Check if this should be inlined
|
|
||||||
* @return
|
|
||||||
* - pdTRUE if in ISR
|
|
||||||
* - pdFALSE otherwise
|
|
||||||
*/
|
|
||||||
BaseType_t xPortInIsrContext(void);
|
|
||||||
#endif
|
|
||||||
// TODO: Check this end
|
|
||||||
|
|
||||||
// TODO: Check this
|
|
||||||
/**
|
|
||||||
* @brief Check if in ISR context from High priority ISRs
|
|
||||||
*
|
|
||||||
* - Called from High priority ISR
|
|
||||||
* - Checks if the previous context (before high priority interrupt) was in ISR context (meaning low/med priority)
|
|
||||||
*
|
|
||||||
* @note [refactor-todo] Check if this should be inlined
|
|
||||||
* @return
|
|
||||||
* - pdTRUE if in previous in ISR context
|
|
||||||
* - pdFALSE otherwise
|
|
||||||
*/
|
|
||||||
BaseType_t xPortInterruptedFromISRContext(void);
|
|
||||||
// TODO: Check this end
|
|
||||||
|
|
||||||
// TODO: Check this
|
|
||||||
/* ---------------------- Spinlocks ------------------------*/
|
|
||||||
/**
|
|
||||||
* @brief Wrapper for atomic compare-and-set instruction
|
|
||||||
*
|
|
||||||
* @note Isn't a real atomic CAS.
|
|
||||||
* @note [refactor-todo] check if we still need this
|
|
||||||
* @note [refactor-todo] Check if this function should be renamed (due to void return type)
|
|
||||||
*
|
|
||||||
* @param[inout] addr Pointer to target address
|
|
||||||
* @param[in] compare Compare value
|
|
||||||
* @param[inout] set Pointer to set value
|
|
||||||
*/
|
|
||||||
static inline void __attribute__((always_inline)) uxPortCompareSet(volatile uint32_t *addr, uint32_t compare, uint32_t *set);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Wrapper for atomic compare-and-set instruction in external RAM
|
|
||||||
*
|
|
||||||
* @note Isn't a real atomic CAS.
|
|
||||||
* @note [refactor-todo] check if we still need this
|
|
||||||
* @note [refactor-todo] Check if this function should be renamed (due to void return type)
|
|
||||||
*
|
|
||||||
* @param[inout] addr Pointer to target address
|
|
||||||
* @param[in] compare Compare value
|
|
||||||
* @param[inout] set Pointer to set value
|
|
||||||
*/
|
|
||||||
static inline void uxPortCompareSetExtram(volatile uint32_t *addr, uint32_t compare, uint32_t *set);
|
|
||||||
// TODO: Check this end
|
|
||||||
|
|
||||||
// ------------------ Critical Sections --------------------
|
// ------------------ Critical Sections --------------------
|
||||||
|
|
||||||
UBaseType_t uxPortEnterCriticalFromISR( void );
|
|
||||||
void vPortExitCriticalFromISR( UBaseType_t level );
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
These are always called with interrupts already disabled. We simply need to get/release the spinlocks
|
These are always called with interrupts already disabled. We simply need to get/release the spinlocks
|
||||||
*/
|
*/
|
||||||
@@ -198,55 +96,24 @@ extern portMUX_TYPE port_xISRLock;
|
|||||||
void vPortTakeLock( portMUX_TYPE *lock );
|
void vPortTakeLock( portMUX_TYPE *lock );
|
||||||
void vPortReleaseLock( portMUX_TYPE *lock );
|
void vPortReleaseLock( portMUX_TYPE *lock );
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Enter a critical section
|
|
||||||
*
|
|
||||||
* - Simply disable interrupts
|
|
||||||
* - Can be nested
|
|
||||||
*/
|
|
||||||
void vPortEnterCritical(void);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Exit a critical section
|
|
||||||
*
|
|
||||||
* - Reenables interrupts
|
|
||||||
* - Can be nested
|
|
||||||
*/
|
|
||||||
void vPortExitCritical(void);
|
|
||||||
|
|
||||||
// ---------------------- Yielding -------------------------
|
// ---------------------- Yielding -------------------------
|
||||||
|
|
||||||
void vPortYield( void );
|
void vPortYield( void );
|
||||||
static inline void __attribute__((always_inline)) vPortYieldCore( BaseType_t xCoreID );
|
static inline void __attribute__((always_inline)) vPortYieldCore( BaseType_t xCoreID );
|
||||||
// TODO: Check this
|
|
||||||
//static inline void __attribute__((always_inline)) vPortYieldFromISR( void );
|
|
||||||
// TODO: Check this end
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Set interrupt mask and return current interrupt enable register
|
* @brief Set interrupt mask and return current interrupt enable register
|
||||||
*
|
*
|
||||||
* @note [refactor-todo] Check if this function should be renamed (due to int return type)
|
* @return UBaseType_t Current interrupt enable register before set
|
||||||
* @return int Current interrupt enable register before set
|
|
||||||
*/
|
*/
|
||||||
int vPortSetInterruptMask(void);
|
UBaseType_t ulPortSetInterruptMask(void);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Clear current interrupt mask and set given mask
|
* @brief Clear current interrupt mask and set given mask
|
||||||
*
|
*
|
||||||
* @param mask Interrupt mask
|
* @param mask Interrupt mask
|
||||||
*/
|
*/
|
||||||
void vPortClearInterruptMask(int mask);
|
void vPortClearInterruptMask(UBaseType_t mask);
|
||||||
|
|
||||||
// TODO: Check this
|
|
||||||
#if 0
|
|
||||||
/**
|
|
||||||
* @brief Perform a context switch from a task
|
|
||||||
*
|
|
||||||
* @note [refactor-todo] The rest of ESP-IDF should call taskYield() instead
|
|
||||||
*/
|
|
||||||
void vPortYield(void);
|
|
||||||
#endif
|
|
||||||
// TODO: Check this end
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Perform a context switch from an ISR
|
* @brief Perform a context switch from an ISR
|
||||||
@@ -260,31 +127,6 @@ void vPortYieldFromISR(void);
|
|||||||
})
|
})
|
||||||
#define portYIELD_FROM_ISR_NO_CHECK() vPortYieldFromISR()
|
#define portYIELD_FROM_ISR_NO_CHECK() vPortYieldFromISR()
|
||||||
|
|
||||||
// TODO: Check this
|
|
||||||
#if 0
|
|
||||||
/**
|
|
||||||
* @brief Yields the other core
|
|
||||||
*
|
|
||||||
* @note Added to be compatible with SMP API
|
|
||||||
* @note [refactor-todo] Put this into private macros as its only called from task.c and is not public API
|
|
||||||
* @param coreid ID of core to yield
|
|
||||||
*/
|
|
||||||
void vPortYieldOtherCore(BaseType_t coreid);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Checks if the current core can yield
|
|
||||||
*
|
|
||||||
* - A core cannot yield if its in an ISR or in a critical section
|
|
||||||
*
|
|
||||||
* @note [refactor-todo] See if this can be separated from port macro
|
|
||||||
* @note [refactor-todo] Check if this function should be renamed (due to bool return type)
|
|
||||||
* @return true Core can yield
|
|
||||||
* @return false Core cannot yield
|
|
||||||
*/
|
|
||||||
static inline bool xPortCanYield(void);
|
|
||||||
#endif
|
|
||||||
// TODO: Check this end
|
|
||||||
|
|
||||||
// ----------------------- System --------------------------
|
// ----------------------- System --------------------------
|
||||||
|
|
||||||
static inline BaseType_t __attribute__((always_inline)) xPortGetCoreID( void );
|
static inline BaseType_t __attribute__((always_inline)) xPortGetCoreID( void );
|
||||||
@@ -293,87 +135,15 @@ static inline BaseType_t __attribute__((always_inline)) xPortGetCoreID( void );
|
|||||||
|
|
||||||
void vPortCleanUpTCB ( void *pxTCB );
|
void vPortCleanUpTCB ( void *pxTCB );
|
||||||
|
|
||||||
// TODO: Check this
|
|
||||||
#if 0
|
|
||||||
// ------------------- Hook Functions ----------------------
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Hook function called on entry to tickless idle
|
|
||||||
*
|
|
||||||
* - Implemented in pm_impl.c
|
|
||||||
*
|
|
||||||
* @param xExpectedIdleTime Expected idle time
|
|
||||||
*/
|
|
||||||
void vApplicationSleep(TickType_t xExpectedIdleTime);
|
|
||||||
#endif
|
|
||||||
// TODO: Check this end
|
|
||||||
|
|
||||||
// TODO: Check this
|
|
||||||
#if 0
|
|
||||||
// ----------------------- System --------------------------
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Get the tick rate per second
|
|
||||||
*
|
|
||||||
* @note [refactor-todo] make this inline
|
|
||||||
* @note [refactor-todo] Check if this function should be renamed (due to uint return type)
|
|
||||||
* @return uint32_t Tick rate in Hz
|
|
||||||
*/
|
|
||||||
uint32_t xPortGetTickRateHz(void);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Set a watchpoint to watch the last 32 bytes of the stack
|
|
||||||
*
|
|
||||||
* Callback to set a watchpoint on the end of the stack. Called every context switch to change the stack watchpoint
|
|
||||||
* around.
|
|
||||||
*
|
|
||||||
* @param pxStackStart Pointer to the start of the stack
|
|
||||||
*/
|
|
||||||
void vPortSetStackWatchpoint(void *pxStackStart);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Get the current core's ID
|
|
||||||
*
|
|
||||||
* @note Added to be compatible with SMP API
|
|
||||||
* @note [refactor-todo] IDF should call a FreeRTOS like macro instead of port function directly
|
|
||||||
* @return BaseType_t Core ID
|
|
||||||
*/
|
|
||||||
static inline BaseType_t IRAM_ATTR xPortGetCoreID(void)
|
|
||||||
{
|
|
||||||
return (BaseType_t) cpu_hal_get_core_id();
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
// TODO: Check this end
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/* ------------------------------------------- FreeRTOS Porting Interface ----------------------------------------------
|
/* ------------------------------------------- FreeRTOS Porting Interface ----------------------------------------------
|
||||||
* - Contains all the mappings of the macros required by FreeRTOS
|
* - Contains all the mappings of the macros required by FreeRTOS
|
||||||
* - Most come after forward declare as porting macros map to declared functions
|
* - Most come after forward declare as porting macros map to declared functions
|
||||||
* - Maps to forward declared functions
|
* - Maps to forward declared functions
|
||||||
* ------------------------------------------------------------------------------------------------------------------ */
|
* ------------------------------------------------------------------------------------------------------------------ */
|
||||||
|
|
||||||
// ----------------------- Memory --------------------------
|
|
||||||
|
|
||||||
// TODO: Check this
|
|
||||||
#if 0
|
|
||||||
/**
|
|
||||||
* @brief Task memory allocation macros
|
|
||||||
*
|
|
||||||
* @note Because the ROM routines don't necessarily handle a stack in external RAM correctly, we force the stack
|
|
||||||
* memory to always be internal.
|
|
||||||
* @note [refactor-todo] Update portable.h to match v10.4.3 to use new malloc prototypes
|
|
||||||
*/
|
|
||||||
#define portTcbMemoryCaps (MALLOC_CAP_INTERNAL|MALLOC_CAP_8BIT)
|
|
||||||
#define portStackMemoryCaps (MALLOC_CAP_INTERNAL|MALLOC_CAP_8BIT)
|
|
||||||
#define pvPortMallocTcbMem(size) pvPortMalloc(size)
|
|
||||||
#define pvPortMallocStackMem(size) pvPortMalloc(size)
|
|
||||||
#endif
|
|
||||||
// TODO: Check this end
|
|
||||||
|
|
||||||
// --------------------- Interrupts ------------------------
|
// --------------------- Interrupts ------------------------
|
||||||
|
|
||||||
#define portDISABLE_INTERRUPTS() vPortSetInterruptMask()
|
#define portDISABLE_INTERRUPTS() ulPortSetInterruptMask()
|
||||||
#define portENABLE_INTERRUPTS() vPortClearInterruptMask(1)
|
#define portENABLE_INTERRUPTS() vPortClearInterruptMask(1)
|
||||||
#define portRESTORE_INTERRUPTS(x) vPortClearInterruptMask(x)
|
#define portRESTORE_INTERRUPTS(x) vPortClearInterruptMask(x)
|
||||||
|
|
||||||
@@ -420,51 +190,11 @@ extern void vTaskExitCritical( void );
|
|||||||
#endif
|
#endif
|
||||||
#define portYIELD_CORE(x) vPortYieldCore(x)
|
#define portYIELD_CORE(x) vPortYieldCore(x)
|
||||||
|
|
||||||
// TODO: Check this
|
|
||||||
#if 0
|
|
||||||
#define portYIELD_FROM_ISR_NO_ARG() vPortYieldFromISR()
|
|
||||||
#define portYIELD_FROM_ISR_ARG(xHigherPriorityTaskWoken) ({ \
|
|
||||||
if (xHigherPriorityTaskWoken == pdTRUE) { \
|
|
||||||
vPortYieldFromISR(); \
|
|
||||||
} \
|
|
||||||
})
|
|
||||||
/**
|
|
||||||
* @note The macro below could be used when passing a single argument, or without any argument,
|
|
||||||
* it was developed to support both usages of portYIELD inside of an ISR. Any other usage form
|
|
||||||
* might result in undesired behavior
|
|
||||||
*/
|
|
||||||
#if defined(__cplusplus) && (__cplusplus > 201703L)
|
|
||||||
#define portYIELD_FROM_ISR(...) CHOOSE_MACRO_VA_ARG(portYIELD_FROM_ISR_ARG, portYIELD_FROM_ISR_NO_ARG __VA_OPT__(,) __VA_ARGS__)(__VA_ARGS__)
|
|
||||||
#else
|
|
||||||
#define portYIELD_FROM_ISR(...) CHOOSE_MACRO_VA_ARG(portYIELD_FROM_ISR_ARG, portYIELD_FROM_ISR_NO_ARG, ##__VA_ARGS__)(__VA_ARGS__)
|
|
||||||
#endif
|
|
||||||
|
|
||||||
|
|
||||||
#define portEND_SWITCHING_ISR(xSwitchRequired) if(xSwitchRequired) vPortYield()
|
|
||||||
/* Yielding within an API call (when interrupts are off), means the yield should be delayed
|
|
||||||
until interrupts are re-enabled.
|
|
||||||
To do this, we use the "cross-core" interrupt as a trigger to yield on this core when interrupts are re-enabled.This
|
|
||||||
is the same interrupt & code path which is used to trigger a yield between CPUs, although in this case the yield is
|
|
||||||
happening on the same CPU.
|
|
||||||
*/
|
|
||||||
#define portYIELD_WITHIN_API() portYIELD()
|
|
||||||
#endif
|
|
||||||
// TODO: Check this end
|
|
||||||
|
|
||||||
//
|
|
||||||
// ----------------------- System --------------------------
|
// ----------------------- System --------------------------
|
||||||
|
|
||||||
#define portGET_CORE_ID() xPortGetCoreID()
|
#define portGET_CORE_ID() xPortGetCoreID()
|
||||||
#define portCHECK_IF_IN_ISR() xPortCheckIfInISR()
|
#define portCHECK_IF_IN_ISR() xPortCheckIfInISR()
|
||||||
|
|
||||||
// TODO: Check this
|
|
||||||
#if 0
|
|
||||||
// ------------------- Hook Functions ----------------------
|
|
||||||
|
|
||||||
#define portSUPPRESS_TICKS_AND_SLEEP(idleTime) vApplicationSleep(idleTime)
|
|
||||||
#endif
|
|
||||||
// TODO: Check this end
|
|
||||||
|
|
||||||
// ------------------- Run Time Stats ----------------------
|
// ------------------- Run Time Stats ----------------------
|
||||||
|
|
||||||
#define portCONFIGURE_TIMER_FOR_RUN_TIME_STATS()
|
#define portCONFIGURE_TIMER_FOR_RUN_TIME_STATS()
|
||||||
@@ -484,10 +214,6 @@ extern void vTaskExitCritical( void );
|
|||||||
* - For implementation of non-inlined functions, see port.c, port_common.c, or other assembly files
|
* - For implementation of non-inlined functions, see port.c, port_common.c, or other assembly files
|
||||||
* ------------------------------------------------------------------------------------------------------------------ */
|
* ------------------------------------------------------------------------------------------------------------------ */
|
||||||
|
|
||||||
// --------------------- Interrupts ------------------------
|
|
||||||
|
|
||||||
// ------------------ Critical Sections --------------------
|
|
||||||
|
|
||||||
// ---------------------- Yielding -------------------------
|
// ---------------------- Yielding -------------------------
|
||||||
|
|
||||||
static inline void __attribute__((always_inline)) vPortYieldCore( BaseType_t xCoreID )
|
static inline void __attribute__((always_inline)) vPortYieldCore( BaseType_t xCoreID )
|
||||||
@@ -495,20 +221,6 @@ static inline void __attribute__((always_inline)) vPortYieldCore( BaseType_t xCo
|
|||||||
esp_crosscore_int_send_yield( xCoreID );
|
esp_crosscore_int_send_yield( xCoreID );
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: Check this
|
|
||||||
#if 0
|
|
||||||
static inline bool IRAM_ATTR xPortCanYield(void)
|
|
||||||
{
|
|
||||||
uint32_t threshold = REG_READ(INTERRUPT_CORE0_CPU_INT_THRESH_REG);
|
|
||||||
/* when enter critical code, FreeRTOS will mask threshold to RVHAL_EXCM_LEVEL
|
|
||||||
* and exit critical code, will recover threshold value (1). so threshold <= 1
|
|
||||||
* means not in critical code
|
|
||||||
*/
|
|
||||||
return (threshold <= 1);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
// TODO: Check this end
|
|
||||||
|
|
||||||
// ----------------------- System --------------------------
|
// ----------------------- System --------------------------
|
||||||
|
|
||||||
static inline BaseType_t __attribute__((always_inline)) xPortGetCoreID( void )
|
static inline BaseType_t __attribute__((always_inline)) xPortGetCoreID( void )
|
||||||
@@ -520,8 +232,6 @@ static inline BaseType_t __attribute__((always_inline)) xPortGetCoreID( void )
|
|||||||
* - These macros and functions need to be defined for IDF to compile
|
* - These macros and functions need to be defined for IDF to compile
|
||||||
* ------------------------------------------------------------------------------------------------------------------ */
|
* ------------------------------------------------------------------------------------------------------------------ */
|
||||||
|
|
||||||
// --------------------- Interrupts ------------------------
|
|
||||||
|
|
||||||
static inline BaseType_t xPortInIsrContext(void)
|
static inline BaseType_t xPortInIsrContext(void)
|
||||||
{
|
{
|
||||||
//Just call the FreeRTOS port interface version
|
//Just call the FreeRTOS port interface version
|
||||||
@@ -530,11 +240,33 @@ static inline BaseType_t xPortInIsrContext(void)
|
|||||||
|
|
||||||
// ---------------------- Spinlocks ------------------------
|
// ---------------------- Spinlocks ------------------------
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Wrapper for atomic compare-and-set instruction
|
||||||
|
*
|
||||||
|
* @note Isn't a real atomic CAS.
|
||||||
|
* @note [refactor-todo] check if we still need this
|
||||||
|
* @note [refactor-todo] Check if this function should be renamed (due to void return type)
|
||||||
|
*
|
||||||
|
* @param[inout] addr Pointer to target address
|
||||||
|
* @param[in] compare Compare value
|
||||||
|
* @param[inout] set Pointer to set value
|
||||||
|
*/
|
||||||
static inline void __attribute__((always_inline)) uxPortCompareSet(volatile uint32_t *addr, uint32_t compare, uint32_t *set)
|
static inline void __attribute__((always_inline)) uxPortCompareSet(volatile uint32_t *addr, uint32_t compare, uint32_t *set)
|
||||||
{
|
{
|
||||||
compare_and_set_native(addr, compare, set);
|
compare_and_set_native(addr, compare, set);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Wrapper for atomic compare-and-set instruction in external RAM
|
||||||
|
*
|
||||||
|
* @note Isn't a real atomic CAS.
|
||||||
|
* @note [refactor-todo] check if we still need this
|
||||||
|
* @note [refactor-todo] Check if this function should be renamed (due to void return type)
|
||||||
|
*
|
||||||
|
* @param[inout] addr Pointer to target address
|
||||||
|
* @param[in] compare Compare value
|
||||||
|
* @param[inout] set Pointer to set value
|
||||||
|
*/
|
||||||
static inline void uxPortCompareSetExtram(volatile uint32_t *addr, uint32_t compare, uint32_t *set)
|
static inline void uxPortCompareSetExtram(volatile uint32_t *addr, uint32_t compare, uint32_t *set)
|
||||||
{
|
{
|
||||||
#if defined(CONFIG_SPIRAM)
|
#if defined(CONFIG_SPIRAM)
|
||||||
@@ -606,7 +338,7 @@ extern int xPortSwitchFlag;
|
|||||||
// --------------------- Debugging -------------------------
|
// --------------------- Debugging -------------------------
|
||||||
|
|
||||||
#if CONFIG_FREERTOS_ASSERT_ON_UNTESTED_FUNCTION
|
#if CONFIG_FREERTOS_ASSERT_ON_UNTESTED_FUNCTION
|
||||||
#define UNTESTED_FUNCTION() { esp_rom_printf("Untested FreeRTOS function %s\r\n", __FUNCTION__); configASSERT(false); } while(0)
|
#define UNTESTED_FUNCTION() do{ esp_rom_printf("Untested FreeRTOS function %s\r\n", __FUNCTION__); configASSERT(false); } while(0)
|
||||||
#else
|
#else
|
||||||
#define UNTESTED_FUNCTION()
|
#define UNTESTED_FUNCTION()
|
||||||
#endif
|
#endif
|
||||||
|
@@ -46,10 +46,10 @@
|
|||||||
static const char *TAG = "cpu_start"; // [refactor-todo]: might be appropriate to change in the future, but
|
static const char *TAG = "cpu_start"; // [refactor-todo]: might be appropriate to change in the future, but
|
||||||
|
|
||||||
BaseType_t uxSchedulerRunning = 0;
|
BaseType_t uxSchedulerRunning = 0;
|
||||||
UBaseType_t uxInterruptNesting = 0;
|
volatile UBaseType_t uxInterruptNesting = 0;
|
||||||
portMUX_TYPE port_xTaskLock = portMUX_INITIALIZER_UNLOCKED;
|
portMUX_TYPE port_xTaskLock = portMUX_INITIALIZER_UNLOCKED;
|
||||||
portMUX_TYPE port_xISRLock = portMUX_INITIALIZER_UNLOCKED;
|
portMUX_TYPE port_xISRLock = portMUX_INITIALIZER_UNLOCKED;
|
||||||
BaseType_t xPortSwitchFlag = 0;
|
volatile BaseType_t xPortSwitchFlag = 0;
|
||||||
__attribute__((aligned(16))) static StackType_t xIsrStack[configISR_STACK_SIZE];
|
__attribute__((aligned(16))) static StackType_t xIsrStack[configISR_STACK_SIZE];
|
||||||
StackType_t *xIsrStackTop = &xIsrStack[0] + (configISR_STACK_SIZE & (~((portPOINTER_SIZE_TYPE)portBYTE_ALIGNMENT_MASK)));
|
StackType_t *xIsrStackTop = &xIsrStack[0] + (configISR_STACK_SIZE & (~((portPOINTER_SIZE_TYPE)portBYTE_ALIGNMENT_MASK)));
|
||||||
|
|
||||||
@@ -61,26 +61,32 @@ static UBaseType_t port_uxCriticalOldInterruptStateIDF = 0;
|
|||||||
* - These need to be defined for IDF to compile
|
* - These need to be defined for IDF to compile
|
||||||
* ------------------------------------------------------------------------------------------------------------------ */
|
* ------------------------------------------------------------------------------------------------------------------ */
|
||||||
|
|
||||||
// --------------------- Interrupts ------------------------
|
|
||||||
|
|
||||||
BaseType_t IRAM_ATTR xPortInterruptedFromISRContext(void)
|
|
||||||
{
|
|
||||||
/* For single core, this can be the same as xPortCheckIfInISR() because reading it is atomic */
|
|
||||||
return uxInterruptNesting;
|
|
||||||
}
|
|
||||||
|
|
||||||
// ------------------ Critical Sections --------------------
|
// ------------------ Critical Sections --------------------
|
||||||
|
|
||||||
// ----------------------- System --------------------------
|
void vPortEnterCriticalIDF(void)
|
||||||
|
|
||||||
// TODO: Check this
|
|
||||||
#if 0
|
|
||||||
uint32_t xPortGetTickRateHz(void)
|
|
||||||
{
|
{
|
||||||
return (uint32_t)configTICK_RATE_HZ;
|
// Save current interrupt threshold and disable interrupts
|
||||||
|
UBaseType_t old_thresh = ulPortSetInterruptMask();
|
||||||
|
// Update the IDF critical nesting count
|
||||||
|
port_uxCriticalNestingIDF++;
|
||||||
|
if (port_uxCriticalNestingIDF == 1) {
|
||||||
|
// Save a copy of the old interrupt threshold
|
||||||
|
port_uxCriticalOldInterruptStateIDF = (UBaseType_t) old_thresh;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
// TODO: Check this end
|
void vPortExitCriticalIDF(void)
|
||||||
|
{
|
||||||
|
if (port_uxCriticalNestingIDF > 0) {
|
||||||
|
port_uxCriticalNestingIDF--;
|
||||||
|
if (port_uxCriticalNestingIDF == 0) {
|
||||||
|
// Restore the saved interrupt threshold
|
||||||
|
vPortClearInterruptMask((int)port_uxCriticalOldInterruptStateIDF);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ----------------------- System --------------------------
|
||||||
|
|
||||||
#define STACK_WATCH_AREA_SIZE 32
|
#define STACK_WATCH_AREA_SIZE 32
|
||||||
#define STACK_WATCH_POINT_NUMBER (SOC_CPU_WATCHPOINTS_NUM - 1)
|
#define STACK_WATCH_POINT_NUMBER (SOC_CPU_WATCHPOINTS_NUM - 1)
|
||||||
@@ -282,6 +288,50 @@ void esp_startup_start_app(void)
|
|||||||
|
|
||||||
// --------------------- Interrupts ------------------------
|
// --------------------- Interrupts ------------------------
|
||||||
|
|
||||||
|
UBaseType_t ulPortSetInterruptMask(void)
|
||||||
|
{
|
||||||
|
int ret;
|
||||||
|
unsigned old_mstatus = RV_CLEAR_CSR(mstatus, MSTATUS_MIE);
|
||||||
|
ret = REG_READ(INTERRUPT_CORE0_CPU_INT_THRESH_REG);
|
||||||
|
REG_WRITE(INTERRUPT_CORE0_CPU_INT_THRESH_REG, RVHAL_EXCM_LEVEL);
|
||||||
|
RV_SET_CSR(mstatus, old_mstatus & MSTATUS_MIE);
|
||||||
|
/**
|
||||||
|
* In theory, this function should not return immediately as there is a
|
||||||
|
* delay between the moment we mask the interrupt threshold register and
|
||||||
|
* the moment a potential lower-priority interrupt is triggered (as said
|
||||||
|
* above), it should have a delay of 2 machine cycles/instructions.
|
||||||
|
*
|
||||||
|
* However, in practice, this function has an epilogue of one instruction,
|
||||||
|
* thus the instruction masking the interrupt threshold register is
|
||||||
|
* followed by two instructions: `ret` and `csrrs` (RV_SET_CSR).
|
||||||
|
* That's why we don't need any additional nop instructions here.
|
||||||
|
*/
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
void vPortClearInterruptMask(UBaseType_t mask)
|
||||||
|
{
|
||||||
|
REG_WRITE(INTERRUPT_CORE0_CPU_INT_THRESH_REG, mask);
|
||||||
|
/**
|
||||||
|
* The delay between the moment we unmask the interrupt threshold register
|
||||||
|
* and the moment the potential requested interrupt is triggered is not
|
||||||
|
* null: up to three machine cycles/instructions can be executed.
|
||||||
|
*
|
||||||
|
* When compilation size optimization is enabled, this function and its
|
||||||
|
* callers returning void will have NO epilogue, thus the instruction
|
||||||
|
* following these calls will be executed.
|
||||||
|
*
|
||||||
|
* If the requested interrupt is a context switch to a higher priority
|
||||||
|
* task then the one currently running, we MUST NOT execute any instruction
|
||||||
|
* before the interrupt effectively happens.
|
||||||
|
* In order to prevent this, force this routine to have a 3-instruction
|
||||||
|
* delay before exiting.
|
||||||
|
*/
|
||||||
|
asm volatile ( "nop" );
|
||||||
|
asm volatile ( "nop" );
|
||||||
|
asm volatile ( "nop" );
|
||||||
|
}
|
||||||
|
|
||||||
BaseType_t xPortCheckIfInISR(void)
|
BaseType_t xPortCheckIfInISR(void)
|
||||||
{
|
{
|
||||||
return uxInterruptNesting;
|
return uxInterruptNesting;
|
||||||
@@ -289,19 +339,45 @@ BaseType_t xPortCheckIfInISR(void)
|
|||||||
|
|
||||||
// ------------------ Critical Sections --------------------
|
// ------------------ Critical Sections --------------------
|
||||||
|
|
||||||
void vPortTakeLock( portMUX_TYPE *lock )
|
void IRAM_ATTR vPortTakeLock( portMUX_TYPE *lock )
|
||||||
{
|
{
|
||||||
spinlock_acquire( lock, portMUX_NO_TIMEOUT);
|
spinlock_acquire( lock, portMUX_NO_TIMEOUT);
|
||||||
}
|
}
|
||||||
|
|
||||||
void vPortReleaseLock( portMUX_TYPE *lock )
|
void IRAM_ATTR vPortReleaseLock( portMUX_TYPE *lock )
|
||||||
{
|
{
|
||||||
spinlock_release( lock );
|
spinlock_release( lock );
|
||||||
}
|
}
|
||||||
|
|
||||||
// ---------------------- Yielding -------------------------
|
// ---------------------- Yielding -------------------------
|
||||||
|
|
||||||
// ----------------------- System --------------------------
|
void vPortYield(void)
|
||||||
|
{
|
||||||
|
if (uxInterruptNesting) {
|
||||||
|
vPortYieldFromISR();
|
||||||
|
} else {
|
||||||
|
|
||||||
|
esp_crosscore_int_send_yield(0);
|
||||||
|
/* There are 3-4 instructions of latency between triggering the software
|
||||||
|
interrupt and the CPU interrupt happening. Make sure it happened before
|
||||||
|
we return, otherwise vTaskDelay() may return and execute 1-2
|
||||||
|
instructions before the delay actually happens.
|
||||||
|
|
||||||
|
(We could use the WFI instruction here, but there is a chance that
|
||||||
|
the interrupt will happen while evaluating the other two conditions
|
||||||
|
for an instant yield, and if that happens then the WFI would be
|
||||||
|
waiting for the next interrupt to occur...)
|
||||||
|
*/
|
||||||
|
while (uxSchedulerRunning && REG_READ(SYSTEM_CPU_INTR_FROM_CPU_0_REG) != 0) {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void vPortYieldFromISR( void )
|
||||||
|
{
|
||||||
|
//traceISR_EXIT_TO_SCHEDULER();
|
||||||
|
uxSchedulerRunning = 1;
|
||||||
|
xPortSwitchFlag = 1;
|
||||||
|
}
|
||||||
|
|
||||||
/* ------------------------------------------------ FreeRTOS Portable --------------------------------------------------
|
/* ------------------------------------------------ FreeRTOS Portable --------------------------------------------------
|
||||||
* - Provides implementation for functions required by FreeRTOS
|
* - Provides implementation for functions required by FreeRTOS
|
||||||
@@ -507,8 +583,6 @@ StackType_t *pxPortInitialiseStack(StackType_t *pxTopOfStack, TaskFunction_t pxC
|
|||||||
return (StackType_t *)frame;
|
return (StackType_t *)frame;
|
||||||
}
|
}
|
||||||
|
|
||||||
// -------------------- Co-Processor -----------------------
|
|
||||||
|
|
||||||
// ------- Thread Local Storage Pointers Deletion Callbacks -------
|
// ------- Thread Local Storage Pointers Deletion Callbacks -------
|
||||||
|
|
||||||
#if ( CONFIG_FREERTOS_TLSP_DELETION_CALLBACKS )
|
#if ( CONFIG_FREERTOS_TLSP_DELETION_CALLBACKS )
|
||||||
@@ -617,111 +691,3 @@ void vPortCleanUpTCB ( void *pxTCB )
|
|||||||
vPortTLSPointersDelCb( pxTCB );
|
vPortTLSPointersDelCb( pxTCB );
|
||||||
#endif /* CONFIG_FREERTOS_TLSP_DELETION_CALLBACKS */
|
#endif /* CONFIG_FREERTOS_TLSP_DELETION_CALLBACKS */
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ---------------------------------------------- Port Implementations -------------------------------------------------
|
|
||||||
*
|
|
||||||
* ------------------------------------------------------------------------------------------------------------------ */
|
|
||||||
|
|
||||||
// ------------------ Critical Sections --------------------
|
|
||||||
|
|
||||||
void vPortEnterCriticalIDF(void)
|
|
||||||
{
|
|
||||||
// Save current interrupt threshold and disable interrupts
|
|
||||||
int old_thresh = vPortSetInterruptMask();
|
|
||||||
// Update the IDF critical nesting count
|
|
||||||
port_uxCriticalNestingIDF++;
|
|
||||||
if (port_uxCriticalNestingIDF == 1) {
|
|
||||||
// Save a copy of the old interrupt threshold
|
|
||||||
port_uxCriticalOldInterruptStateIDF = (UBaseType_t) old_thresh;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void vPortExitCriticalIDF(void)
|
|
||||||
{
|
|
||||||
if (port_uxCriticalNestingIDF > 0) {
|
|
||||||
port_uxCriticalNestingIDF--;
|
|
||||||
if (port_uxCriticalNestingIDF == 0) {
|
|
||||||
// Restore the saved interrupt threshold
|
|
||||||
vPortClearInterruptMask((int)port_uxCriticalOldInterruptStateIDF);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// ---------------------- Yielding -------------------------
|
|
||||||
|
|
||||||
int vPortSetInterruptMask(void)
|
|
||||||
{
|
|
||||||
int ret;
|
|
||||||
unsigned old_mstatus = RV_CLEAR_CSR(mstatus, MSTATUS_MIE);
|
|
||||||
ret = REG_READ(INTERRUPT_CORE0_CPU_INT_THRESH_REG);
|
|
||||||
REG_WRITE(INTERRUPT_CORE0_CPU_INT_THRESH_REG, RVHAL_EXCM_LEVEL);
|
|
||||||
RV_SET_CSR(mstatus, old_mstatus & MSTATUS_MIE);
|
|
||||||
/**
|
|
||||||
* In theory, this function should not return immediately as there is a
|
|
||||||
* delay between the moment we mask the interrupt threshold register and
|
|
||||||
* the moment a potential lower-priority interrupt is triggered (as said
|
|
||||||
* above), it should have a delay of 2 machine cycles/instructions.
|
|
||||||
*
|
|
||||||
* However, in practice, this function has an epilogue of one instruction,
|
|
||||||
* thus the instruction masking the interrupt threshold register is
|
|
||||||
* followed by two instructions: `ret` and `csrrs` (RV_SET_CSR).
|
|
||||||
* That's why we don't need any additional nop instructions here.
|
|
||||||
*/
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
void vPortClearInterruptMask(int mask)
|
|
||||||
{
|
|
||||||
REG_WRITE(INTERRUPT_CORE0_CPU_INT_THRESH_REG, mask);
|
|
||||||
/**
|
|
||||||
* The delay between the moment we unmask the interrupt threshold register
|
|
||||||
* and the moment the potential requested interrupt is triggered is not
|
|
||||||
* null: up to three machine cycles/instructions can be executed.
|
|
||||||
*
|
|
||||||
* When compilation size optimization is enabled, this function and its
|
|
||||||
* callers returning void will have NO epilogue, thus the instruction
|
|
||||||
* following these calls will be executed.
|
|
||||||
*
|
|
||||||
* If the requested interrupt is a context switch to a higher priority
|
|
||||||
* task then the one currently running, we MUST NOT execute any instruction
|
|
||||||
* before the interrupt effectively happens.
|
|
||||||
* In order to prevent this, force this routine to have a 3-instruction
|
|
||||||
* delay before exiting.
|
|
||||||
*/
|
|
||||||
asm volatile ( "nop" );
|
|
||||||
asm volatile ( "nop" );
|
|
||||||
asm volatile ( "nop" );
|
|
||||||
}
|
|
||||||
|
|
||||||
void vPortYield(void)
|
|
||||||
{
|
|
||||||
if (uxInterruptNesting) {
|
|
||||||
vPortYieldFromISR();
|
|
||||||
} else {
|
|
||||||
|
|
||||||
esp_crosscore_int_send_yield(0);
|
|
||||||
/* There are 3-4 instructions of latency between triggering the software
|
|
||||||
interrupt and the CPU interrupt happening. Make sure it happened before
|
|
||||||
we return, otherwise vTaskDelay() may return and execute 1-2
|
|
||||||
instructions before the delay actually happens.
|
|
||||||
|
|
||||||
(We could use the WFI instruction here, but there is a chance that
|
|
||||||
the interrupt will happen while evaluating the other two conditions
|
|
||||||
for an instant yield, and if that happens then the WFI would be
|
|
||||||
waiting for the next interrupt to occur...)
|
|
||||||
*/
|
|
||||||
while (uxSchedulerRunning && REG_READ(SYSTEM_CPU_INTR_FROM_CPU_0_REG) != 0) {}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void vPortYieldFromISR( void )
|
|
||||||
{
|
|
||||||
//traceISR_EXIT_TO_SCHEDULER();
|
|
||||||
uxSchedulerRunning = 1;
|
|
||||||
xPortSwitchFlag = 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
void vPortYieldOtherCore(BaseType_t coreid)
|
|
||||||
{
|
|
||||||
esp_crosscore_int_send_yield(coreid);
|
|
||||||
}
|
|
||||||
|
@@ -507,7 +507,7 @@ extern int xPortSwitchFlag;
|
|||||||
// --------------------- Debugging -------------------------
|
// --------------------- Debugging -------------------------
|
||||||
|
|
||||||
#if CONFIG_FREERTOS_ASSERT_ON_UNTESTED_FUNCTION
|
#if CONFIG_FREERTOS_ASSERT_ON_UNTESTED_FUNCTION
|
||||||
#define UNTESTED_FUNCTION() { esp_rom_printf("Untested FreeRTOS function %s\r\n", __FUNCTION__); configASSERT(false); } while(0)
|
#define UNTESTED_FUNCTION() do{ esp_rom_printf("Untested FreeRTOS function %s\r\n", __FUNCTION__); configASSERT(false); } while(0)
|
||||||
#else
|
#else
|
||||||
#define UNTESTED_FUNCTION()
|
#define UNTESTED_FUNCTION()
|
||||||
#endif
|
#endif
|
||||||
|
@@ -760,7 +760,7 @@ extern uint32_t port_switch_flag[];
|
|||||||
// --------------------- Debugging -------------------------
|
// --------------------- Debugging -------------------------
|
||||||
|
|
||||||
#if CONFIG_FREERTOS_ASSERT_ON_UNTESTED_FUNCTION
|
#if CONFIG_FREERTOS_ASSERT_ON_UNTESTED_FUNCTION
|
||||||
#define UNTESTED_FUNCTION() { esp_rom_printf("Untested FreeRTOS function %s\r\n", __FUNCTION__); configASSERT(false); } while(0)
|
#define UNTESTED_FUNCTION() do{ esp_rom_printf("Untested FreeRTOS function %s\r\n", __FUNCTION__); configASSERT(false); } while(0)
|
||||||
#else
|
#else
|
||||||
#define UNTESTED_FUNCTION()
|
#define UNTESTED_FUNCTION()
|
||||||
#endif
|
#endif
|
||||||
|
@@ -5,6 +5,7 @@ menu "FreeRTOS"
|
|||||||
|
|
||||||
config FREERTOS_SMP
|
config FREERTOS_SMP
|
||||||
bool "Run the SMP FreeRTOS kernel instead (FEATURE UNDER DEVELOPMENT)"
|
bool "Run the SMP FreeRTOS kernel instead (FEATURE UNDER DEVELOPMENT)"
|
||||||
|
depends on IDF_TARGET_ESP32 || IDF_TARGET_ESP32C3
|
||||||
default "n"
|
default "n"
|
||||||
help
|
help
|
||||||
This will cause the FreeRTOS component to compile with the SMP FreeRTOS kernel instead.
|
This will cause the FreeRTOS component to compile with the SMP FreeRTOS kernel instead.
|
||||||
|
Reference in New Issue
Block a user