mirror of
https://github.com/espressif/esp-idf.git
synced 2024-10-05 20:47:46 -04: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:
parent
71eef9a9b0
commit
12e2312aaa
@ -17,54 +17,14 @@ This file get's pulled into assembly sources. Therefore, some includes need to b
|
||||
#include <assert.h> //For configASSERT()
|
||||
#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 --------------------------------------------------
|
||||
*
|
||||
* ------------------------------------------------------------------------------------------------------------------ */
|
||||
|
||||
#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
|
||||
#define configISR_STACK_SIZE (CONFIG_FREERTOS_ISR_STACKSIZE)
|
||||
#endif
|
||||
#endif // __XTENSA__
|
||||
|
||||
/* ----------------------------------------------------- Helpers -------------------------------------------------------
|
||||
* - 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
|
||||
#define configSTACK_DEPTH_TYPE uint32_t
|
||||
#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 configASSERT(a) assert(a)
|
||||
#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( vFunction, pvParameters ) void vFunction( void *pvParameters )
|
||||
|
||||
//TODO: Check this
|
||||
// interrupt module will mask interrupt with priority less than threshold
|
||||
#define RVHAL_EXCM_LEVEL 4
|
||||
// TODO: Check this end
|
||||
|
||||
|
||||
/* ----------------------------------------------- Port Configurations -------------------------------------------------
|
||||
* - Configurations values supplied by each port
|
||||
@ -67,127 +64,28 @@ typedef uint32_t TickType_t;
|
||||
#define portNOP() __asm volatile (" nop ")
|
||||
|
||||
/* ---------------------------------------------- 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
|
||||
* ------------------------------------------------------------------------------------------------------------------ */
|
||||
|
||||
/* ---------------------- Spinlocks ------------------------
|
||||
- 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 */
|
||||
#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_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) spinlock_initialize(mux) /*< Initialize a spinlock to its unlocked state */
|
||||
|
||||
|
||||
// ----------------------- Memory --------------------------
|
||||
|
||||
// --------------------- Interrupts ------------------------
|
||||
|
||||
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 --------------------
|
||||
|
||||
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
|
||||
*/
|
||||
@ -198,55 +96,24 @@ extern portMUX_TYPE port_xISRLock;
|
||||
void vPortTakeLock( 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 -------------------------
|
||||
|
||||
void vPortYield( void );
|
||||
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
|
||||
*
|
||||
* @note [refactor-todo] Check if this function should be renamed (due to int return type)
|
||||
* @return int Current interrupt enable register before set
|
||||
* @return UBaseType_t Current interrupt enable register before set
|
||||
*/
|
||||
int vPortSetInterruptMask(void);
|
||||
UBaseType_t ulPortSetInterruptMask(void);
|
||||
|
||||
/**
|
||||
* @brief Clear current interrupt mask and set given mask
|
||||
*
|
||||
* @param mask Interrupt mask
|
||||
*/
|
||||
void vPortClearInterruptMask(int 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
|
||||
void vPortClearInterruptMask(UBaseType_t mask);
|
||||
|
||||
/**
|
||||
* @brief Perform a context switch from an ISR
|
||||
@ -260,31 +127,6 @@ void vPortYieldFromISR(void);
|
||||
})
|
||||
#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 --------------------------
|
||||
|
||||
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 );
|
||||
|
||||
// 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 ----------------------------------------------
|
||||
* - Contains all the mappings of the macros required by FreeRTOS
|
||||
* - Most come after forward declare as porting macros map to 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 ------------------------
|
||||
|
||||
#define portDISABLE_INTERRUPTS() vPortSetInterruptMask()
|
||||
#define portDISABLE_INTERRUPTS() ulPortSetInterruptMask()
|
||||
#define portENABLE_INTERRUPTS() vPortClearInterruptMask(1)
|
||||
#define portRESTORE_INTERRUPTS(x) vPortClearInterruptMask(x)
|
||||
|
||||
@ -420,51 +190,11 @@ extern void vTaskExitCritical( void );
|
||||
#endif
|
||||
#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 --------------------------
|
||||
|
||||
#define portGET_CORE_ID() xPortGetCoreID()
|
||||
#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 ----------------------
|
||||
|
||||
#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
|
||||
* ------------------------------------------------------------------------------------------------------------------ */
|
||||
|
||||
// --------------------- Interrupts ------------------------
|
||||
|
||||
// ------------------ Critical Sections --------------------
|
||||
|
||||
// ---------------------- Yielding -------------------------
|
||||
|
||||
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 );
|
||||
}
|
||||
|
||||
// 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 --------------------------
|
||||
|
||||
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
|
||||
* ------------------------------------------------------------------------------------------------------------------ */
|
||||
|
||||
// --------------------- Interrupts ------------------------
|
||||
|
||||
static inline BaseType_t xPortInIsrContext(void)
|
||||
{
|
||||
//Just call the FreeRTOS port interface version
|
||||
@ -530,11 +240,33 @@ static inline BaseType_t xPortInIsrContext(void)
|
||||
|
||||
// ---------------------- 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)
|
||||
{
|
||||
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)
|
||||
{
|
||||
#if defined(CONFIG_SPIRAM)
|
||||
@ -606,7 +338,7 @@ extern int xPortSwitchFlag;
|
||||
// --------------------- Debugging -------------------------
|
||||
|
||||
#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
|
||||
#define UNTESTED_FUNCTION()
|
||||
#endif
|
||||
|
@ -46,10 +46,10 @@
|
||||
static const char *TAG = "cpu_start"; // [refactor-todo]: might be appropriate to change in the future, but
|
||||
|
||||
BaseType_t uxSchedulerRunning = 0;
|
||||
UBaseType_t uxInterruptNesting = 0;
|
||||
volatile UBaseType_t uxInterruptNesting = 0;
|
||||
portMUX_TYPE port_xTaskLock = 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];
|
||||
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
|
||||
* ------------------------------------------------------------------------------------------------------------------ */
|
||||
|
||||
// --------------------- 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 --------------------
|
||||
|
||||
// ----------------------- System --------------------------
|
||||
|
||||
// TODO: Check this
|
||||
#if 0
|
||||
uint32_t xPortGetTickRateHz(void)
|
||||
void vPortEnterCriticalIDF(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_POINT_NUMBER (SOC_CPU_WATCHPOINTS_NUM - 1)
|
||||
@ -282,6 +288,50 @@ void esp_startup_start_app(void)
|
||||
|
||||
// --------------------- 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)
|
||||
{
|
||||
return uxInterruptNesting;
|
||||
@ -289,19 +339,45 @@ BaseType_t xPortCheckIfInISR(void)
|
||||
|
||||
// ------------------ Critical Sections --------------------
|
||||
|
||||
void vPortTakeLock( portMUX_TYPE *lock )
|
||||
void IRAM_ATTR vPortTakeLock( portMUX_TYPE *lock )
|
||||
{
|
||||
spinlock_acquire( lock, portMUX_NO_TIMEOUT);
|
||||
}
|
||||
|
||||
void vPortReleaseLock( portMUX_TYPE *lock )
|
||||
void IRAM_ATTR vPortReleaseLock( portMUX_TYPE *lock )
|
||||
{
|
||||
spinlock_release( lock );
|
||||
}
|
||||
|
||||
// ---------------------- 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 --------------------------------------------------
|
||||
* - Provides implementation for functions required by FreeRTOS
|
||||
@ -507,8 +583,6 @@ StackType_t *pxPortInitialiseStack(StackType_t *pxTopOfStack, TaskFunction_t pxC
|
||||
return (StackType_t *)frame;
|
||||
}
|
||||
|
||||
// -------------------- Co-Processor -----------------------
|
||||
|
||||
// ------- Thread Local Storage Pointers Deletion Callbacks -------
|
||||
|
||||
#if ( CONFIG_FREERTOS_TLSP_DELETION_CALLBACKS )
|
||||
@ -617,111 +691,3 @@ void vPortCleanUpTCB ( void *pxTCB )
|
||||
vPortTLSPointersDelCb( pxTCB );
|
||||
#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 -------------------------
|
||||
|
||||
#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
|
||||
#define UNTESTED_FUNCTION()
|
||||
#endif
|
||||
|
@ -760,7 +760,7 @@ extern uint32_t port_switch_flag[];
|
||||
// --------------------- Debugging -------------------------
|
||||
|
||||
#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
|
||||
#define UNTESTED_FUNCTION()
|
||||
#endif
|
||||
|
@ -5,6 +5,7 @@ menu "FreeRTOS"
|
||||
|
||||
config FREERTOS_SMP
|
||||
bool "Run the SMP FreeRTOS kernel instead (FEATURE UNDER DEVELOPMENT)"
|
||||
depends on IDF_TARGET_ESP32 || IDF_TARGET_ESP32C3
|
||||
default "n"
|
||||
help
|
||||
This will cause the FreeRTOS component to compile with the SMP FreeRTOS kernel instead.
|
||||
|
Loading…
x
Reference in New Issue
Block a user