feat(freertos): base support on p4

This commit is contained in:
Armando
2023-07-18 16:21:15 +08:00
committed by Armando (Dou Yiwen)
parent e11b154c99
commit 48ee1ba36e
7 changed files with 279 additions and 11 deletions

View File

@@ -3,7 +3,7 @@
*
* SPDX-License-Identifier: MIT
*
* SPDX-FileContributor: 2016-2022 Espressif Systems (Shanghai) CO LTD
* SPDX-FileContributor: 2016-2023 Espressif Systems (Shanghai) CO LTD
*/
/*
* FreeRTOS Kernel V10.4.3
@@ -160,6 +160,8 @@ BaseType_t xPortInterruptedFromISRContext(void);
* @note [refactor-todo] Refactor critical section API so that this is no longer required
* ------------------------------------------------------ */
//TODO: IDF-7566
#if !CONFIG_IDF_TARGET_ESP32P4
/**
* @brief Spinlock object
* Owner:
@@ -178,6 +180,11 @@ typedef struct {
uint32_t owner;
uint32_t count;
} portMUX_TYPE;
#else
typedef spinlock_t portMUX_TYPE; /**< Spinlock type used by FreeRTOS critical sections */
#endif
/**< Spinlock initializer */
#define portMUX_INITIALIZER_UNLOCKED { \
.owner = portMUX_FREE_VAL, \
@@ -199,7 +206,12 @@ typedef struct {
* - Simply disable interrupts
* - Can be nested
*/
//TODO: IDF-7566
#if !CONFIG_IDF_TARGET_ESP32P4
void vPortEnterCritical(void);
#else
void vPortEnterCritical(portMUX_TYPE *mux);
#endif
/**
* @brief Exit a critical section
@@ -207,7 +219,12 @@ void vPortEnterCritical(void);
* - Reenables interrupts
* - Can be nested
*/
//TODO: IDF-7566
#if !CONFIG_IDF_TARGET_ESP32P4
void vPortExitCritical(void);
#else
void vPortExitCritical(portMUX_TYPE *mux);
#endif
// ---------------------- Yielding -------------------------
@@ -320,6 +337,8 @@ FORCE_INLINE_ATTR BaseType_t xPortGetCoreID(void)
// ------------------ Critical Sections --------------------
//TODO: IDF-7566
#if !CONFIG_IDF_TARGET_ESP32P4
#define portENTER_CRITICAL(mux) {(void)mux; vPortEnterCritical();}
#define portEXIT_CRITICAL(mux) {(void)mux; vPortExitCritical();}
#define portTRY_ENTER_CRITICAL(mux, timeout) ({ \
@@ -328,6 +347,17 @@ FORCE_INLINE_ATTR BaseType_t xPortGetCoreID(void)
BaseType_t ret = pdPASS; \
ret; \
})
#else
#define portENTER_CRITICAL(mux) {vPortEnterCritical(mux);}
#define portEXIT_CRITICAL(mux) {vPortExitCritical(mux);}
#define portTRY_ENTER_CRITICAL(mux, timeout) ({ \
(void)timeout; \
vPortEnterCritical(mux); \
BaseType_t ret = pdPASS; \
ret; \
})
#endif
//In single-core RISC-V, we can use the same critical section API
#define portENTER_CRITICAL_ISR(mux) portENTER_CRITICAL(mux)
#define portEXIT_CRITICAL_ISR(mux) portEXIT_CRITICAL(mux)
@@ -350,6 +380,10 @@ FORCE_INLINE_ATTR BaseType_t xPortGetCoreID(void)
})
#define portTRY_ENTER_CRITICAL_SAFE(mux, timeout) portENTER_CRITICAL_SAFE(mux, timeout)
//TODO: IDF-7566
#if CONFIG_IDF_TARGET_ESP32P4
#define portCHECK_IF_IN_ISR() xPortInIsrContext()
#endif
// ---------------------- Yielding -------------------------
#define portYIELD() vPortYield()
@@ -428,7 +462,13 @@ extern void vPortCleanUpTCB ( void *pxTCB );
FORCE_INLINE_ATTR bool xPortCanYield(void)
{
//TODO: IDF-7566
#if SOC_INT_CLIC_SUPPORTED
uint32_t threshold = REG_READ(INTERRUPT_CORE0_CPU_INT_THRESH_REG + 0x10000 * xPortGetCoreID());
threshold = threshold >> (24 + (8 - NLBITS));
#else
uint32_t threshold = REG_READ(INTERRUPT_CORE0_CPU_INT_THRESH_REG);
#endif
/* 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

View File

@@ -3,7 +3,7 @@
*
* SPDX-License-Identifier: MIT
*
* SPDX-FileContributor: 2016-2022 Espressif Systems (Shanghai) CO LTD
* SPDX-FileContributor: 2016-2023 Espressif Systems (Shanghai) CO LTD
*/
/*
* FreeRTOS Kernel V10.4.3
@@ -56,6 +56,10 @@
#include "portmacro.h"
#include "port_systick.h"
#include "esp_memory_utils.h"
#if CONFIG_IDF_TARGET_ESP32P4
//TODO: IDF-7566
#include "soc/hp_system_reg.h"
#endif
_Static_assert(portBYTE_ALIGNMENT == 16, "portBYTE_ALIGNMENT must be set to 16");
#if CONFIG_ESP_SYSTEM_HW_STACK_GUARD
@@ -74,6 +78,8 @@ _Static_assert(offsetof( StaticTask_t, pxDummy8 ) == PORT_OFFSET_PX_END_OF_STACK
*
* ------------------------------------------------------------------------------------------------------------------ */
//TODO: IDF-7566
#if !CONFIG_IDF_TARGET_ESP32P4
/**
* @brief A variable is used to keep track of the critical section nesting.
* @note This variable has to be stored as part of the task context and must be initialized to a non zero value
@@ -88,6 +94,25 @@ BaseType_t xPortSwitchFlag = 0;
__attribute__((aligned(16))) StackType_t xIsrStack[configISR_STACK_SIZE];
StackType_t *xIsrStackTop = &xIsrStack[0] + (configISR_STACK_SIZE & (~((portPOINTER_SIZE_TYPE)portBYTE_ALIGNMENT_MASK)));
#else
/* uxCriticalNesting will be increased by 1 each time one processor is entering a critical section
* and will be decreased by 1 each time one processor is exiting a critical section
*/
volatile UBaseType_t uxCriticalNesting[portNUM_PROCESSORS] = {0};
volatile UBaseType_t uxSavedInterruptState[portNUM_PROCESSORS] = {0};
volatile BaseType_t uxSchedulerRunning[portNUM_PROCESSORS] = {0};
volatile UBaseType_t uxInterruptNesting[portNUM_PROCESSORS] = {0};
volatile BaseType_t xPortSwitchFlag[portNUM_PROCESSORS] = {0};
/* core0 interrupt stack space */
__attribute__((aligned(16))) static StackType_t xIsrStack[configISR_STACK_SIZE];
/* core1 interrupt stack space */
__attribute__((aligned(16))) static StackType_t xIsrStack1[configISR_STACK_SIZE];
/* core0 interrupt stack top, passed to sp */
StackType_t *xIsrStackTop = &xIsrStack[0] + (configISR_STACK_SIZE & (~((portPOINTER_SIZE_TYPE)portBYTE_ALIGNMENT_MASK)));
/* core1 interrupt stack top, passed to sp */
StackType_t *xIsrStackTop1 = &xIsrStack1[0] + (configISR_STACK_SIZE & (~((portPOINTER_SIZE_TYPE)portBYTE_ALIGNMENT_MASK)));
#endif
/* ------------------------------------------------ FreeRTOS Portable --------------------------------------------------
@@ -97,11 +122,19 @@ StackType_t *xIsrStackTop = &xIsrStack[0] + (configISR_STACK_SIZE & (~((portPOIN
// ----------------- Scheduler Start/End -------------------
//TODO: IDF-7566
BaseType_t xPortStartScheduler(void)
{
#if !CONFIG_IDF_TARGET_ESP32P4
uxInterruptNesting = 0;
uxCriticalNesting = 0;
uxSchedulerRunning = 0;
#else
BaseType_t coreID = xPortGetCoreID();
uxInterruptNesting[coreID] = 0;
uxCriticalNesting[coreID] = 0;
uxSchedulerRunning[coreID] = 0;
#endif
/* Setup the hardware to generate the tick. */
vPortSetupTimer();
@@ -312,15 +345,26 @@ StackType_t *pxPortInitialiseStack(StackType_t *pxTopOfStack, TaskFunction_t pxC
// --------------------- Interrupts ------------------------
//TODO: IDF-7566
BaseType_t xPortInIsrContext(void)
{
#if !CONFIG_IDF_TARGET_ESP32P4
return uxInterruptNesting;
#else
BaseType_t coreID = xPortGetCoreID();
return uxInterruptNesting[coreID];
#endif
}
BaseType_t IRAM_ATTR xPortInterruptedFromISRContext(void)
{
/* For single core, this can be the same as xPortInIsrContext() because reading it is atomic */
#if !CONFIG_IDF_TARGET_ESP32P4
return uxInterruptNesting;
#else
BaseType_t coreID = xPortGetCoreID();
return uxInterruptNesting[coreID];
#endif
}
// ---------------------- Spinlocks ------------------------
@@ -329,6 +373,8 @@ BaseType_t IRAM_ATTR xPortInterruptedFromISRContext(void)
// ------------------ Critical Sections --------------------
//TODO: IDF-7566
#if !CONFIG_IDF_TARGET_ESP32P4
void vPortEnterCritical(void)
{
BaseType_t state = portSET_INTERRUPT_MASK_FROM_ISR();
@@ -349,15 +395,52 @@ void vPortExitCritical(void)
}
}
#else
void vPortEnterCritical(portMUX_TYPE *mux)
{
BaseType_t coreID = xPortGetCoreID();
BaseType_t state = portSET_INTERRUPT_MASK_FROM_ISR();
spinlock_acquire((spinlock_t *)mux, SPINLOCK_WAIT_FOREVER);
uxCriticalNesting[coreID]++;
if (uxCriticalNesting[coreID] == 1) {
uxSavedInterruptState[coreID] = state;
}
}
void vPortExitCritical(portMUX_TYPE *mux)
{
spinlock_release((spinlock_t *)mux);
BaseType_t coreID = xPortGetCoreID();
if (uxCriticalNesting[coreID] > 0) {
uxCriticalNesting[coreID]--;
if (uxCriticalNesting[coreID] == 0) {
portCLEAR_INTERRUPT_MASK_FROM_ISR(uxSavedInterruptState[coreID]);
}
}
}
#endif
// ---------------------- Yielding -------------------------
//TODO: IDF-7566
int vPortSetInterruptMask(void)
{
int ret;
unsigned old_mstatus = RV_CLEAR_CSR(mstatus, MSTATUS_MIE);
ret = REG_READ(INTERRUPT_CORE0_CPU_INT_THRESH_REG);
#if !CONFIG_IDF_TARGET_ESP32P4
REG_WRITE(INTERRUPT_CORE0_CPU_INT_THRESH_REG, RVHAL_EXCM_LEVEL);
RV_SET_CSR(mstatus, old_mstatus & MSTATUS_MIE);
#else
#define RVHAL_EXCM_THRESHOLD_VALUE (((RVHAL_EXCM_LEVEL << (8 - NLBITS)) | 0x1f) << CLIC_CPU_INT_THRESH_S)
REG_WRITE(INTERRUPT_CORE0_CPU_INT_THRESH_REG, RVHAL_EXCM_THRESHOLD_VALUE);
RV_SET_CSR(mstatus, old_mstatus & MSTATUS_MIE);
#endif
/**
* In theory, this function should not return immediately as there is a
* delay between the moment we mask the interrupt threshold register and
@@ -395,6 +478,8 @@ void vPortClearInterruptMask(int mask)
asm volatile ( "nop" );
}
//TODO: IDF-7566
#if !CONFIG_IDF_TARGET_ESP32P4
void vPortYield(void)
{
if (uxInterruptNesting) {
@@ -423,6 +508,37 @@ void vPortYieldFromISR( void )
xPortSwitchFlag = 1;
}
#else
void vPortYield(void)
{
BaseType_t coreID = xPortGetCoreID();
if (uxInterruptNesting[coreID]) {
vPortYieldFromISR();
} else {
esp_crosscore_int_send_yield(coreID);
/* 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[coreID] && uxCriticalNesting[coreID] == 0 && REG_READ(HP_SYSTEM_CPU_INT_FROM_CPU_0_REG + 4*coreID) != 0) {}
}
}
void vPortYieldFromISR( void )
{
traceISR_EXIT_TO_SCHEDULER();
BaseType_t coreID = xPortGetCoreID();
uxSchedulerRunning[coreID] = 1;
xPortSwitchFlag[coreID] = 1;
}
#endif
void vPortYieldOtherCore(BaseType_t coreid)
{
esp_crosscore_int_send_yield(coreid);

View File

@@ -1,5 +1,5 @@
/*
* SPDX-FileCopyrightText: 2015-2022 Espressif Systems (Shanghai) CO LTD
* SPDX-FileCopyrightText: 2015-2023 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
@@ -12,6 +12,10 @@
.global uxInterruptNesting
.global uxSchedulerRunning
.global xIsrStackTop
#if CONFIG_IDF_TARGET_ESP32P4
//TODO: IDF-7566
.global xIsrStackTop1
#endif
.global pxCurrentTCB
.global vTaskSwitchContext
.global xPortSwitchFlag
@@ -35,18 +39,40 @@
.global rtos_int_enter
.type rtos_int_enter, @function
rtos_int_enter:
#if CONFIG_IDF_TARGET_ESP32P4
/* needs jira for p4 */
/* preserve the return address */
mv t1, ra
mv t2, a0
#endif
//TODO: IDF-7566
#if !CONFIG_IDF_TARGET_ESP32P4
/* scheduler not enabled, jump directly to ISR handler */
lw t0, uxSchedulerRunning
beq t0,zero, rtos_enter_end
#else
/* scheduler not enabled, jump directly to ISR handler */
csrr t6, mhartid /* t6 = coreID */
slli t6, t6, 2 /* t6 = coreID * 4 */
la t0, uxSchedulerRunning /* t0 = &uxSchedulerRunning */
add t0, t0, t6 /* t0 = &uxSchedulerRunning[coreID] */
lw t0, (t0) /* t0 = uxSchedulerRunning[coreID] */
beq t0,zero, rtos_enter_end
#endif
/* increments the ISR nesting count */
la t3, uxInterruptNesting
lw t4, 0x0(t3)
addi t5,t4,1
sw t5, 0x0(t3)
la t3, uxInterruptNesting
#if CONFIG_IDF_TARGET_ESP32P4
//TODO: IDF-7566
add t3, t3, t6
#endif
lw t4, 0x0(t3)
addi t5,t4,1
sw t5, 0x0(t3)
/* If reached here from another low-prio ISR, skip stack pushing to TCB */
bne t4,zero, rtos_enter_end
bne t4,zero, rtos_enter_end
#if CONFIG_ESP_SYSTEM_HW_STACK_GUARD
/* esp_hw_stack_guard_monitor_stop(); */
@@ -54,9 +80,21 @@ rtos_int_enter:
#endif /* CONFIG_ESP_SYSTEM_HW_STACK_GUARD */
/* Save current TCB and load the ISR stack */
//TODO: IDF-7566
#if !CONFIG_IDF_TARGET_ESP32P4
lw t0, pxCurrentTCB
sw sp, 0x0(t0)
lw sp, xIsrStackTop
#else
la t0, pxCurrentTCB /* t0 = &pxCurrentTCB */
add t0, t0, t6 /* t0 = &pxCurrentTCB[coreID] */
lw t0, (t0) /* t0 = pxCurrentTCB[coreID] */
sw t2, 0x0(t0)
lw sp, xIsrStackTop
csrr t6, mhartid
beq t6, zero, rtos_enter_end
lw sp, xIsrStackTop1
#endif
#if CONFIG_ESP_SYSTEM_HW_STACK_GUARD
/* esp_hw_stack_guard_set_bounds(xIsrStack, xIsrStackTop); */
@@ -67,6 +105,10 @@ rtos_int_enter:
#endif /* CONFIG_ESP_SYSTEM_HW_STACK_GUARD */
rtos_enter_end:
#if CONFIG_IDF_TARGET_ESP32P4
/* needs jira for p4 */
mv ra, t1
#endif
ret
/**
@@ -76,11 +118,25 @@ rtos_enter_end:
.type rtos_int_exit, @function
rtos_int_exit:
/* may skip RTOS aware interrupt since scheduler was not started */
//TODO: IDF-7566
#if !CONFIG_IDF_TARGET_ESP32P4
lw t0, uxSchedulerRunning
#else
csrr t1, mhartid
slli t1, t1, 2
la t0, uxSchedulerRunning /* t0 = &uxSchedulerRunning */
add t0, t0, t1 /* t0 = &uxSchedulerRunning[coreID] */
lw t0, (t0)
#endif
beq t0,zero, rtos_exit_end
/* update nesting interrupts counter */
la t2, uxInterruptNesting
#if CONFIG_IDF_TARGET_ESP32P4
//TODO: IDF-7566
add t2, t2, t1
#endif
lw t3, 0x0(t2)
/* Already zero, protect against underflow */
@@ -95,6 +151,10 @@ isr_skip_decrement:
/* Schedule the next task if a yield is pending */
la t0, xPortSwitchFlag
#if CONFIG_IDF_TARGET_ESP32P4
//TODO: IDF-7566
add t0, t0, t1
#endif
lw t2, 0x0(t0)
beq t2, zero, no_switch
@@ -108,11 +168,19 @@ isr_skip_decrement:
/* Clears the switch pending flag */
la t0, xPortSwitchFlag
#if CONFIG_IDF_TARGET_ESP32P4
//TODO: IDF-7566
/* c routine vTaskSwitchContext may change the temp registers, so we read again */
csrr t3, mhartid
slli t3, t3, 2
add t0, t0, t3
#endif
mv t2, zero
sw t2, 0x0(t0)
no_switch:
#if !CONFIG_IDF_TARGET_ESP32P4 //TODO: IDF-7566
#if CONFIG_ESP_SYSTEM_HW_STACK_GUARD
/* esp_hw_stack_guard_monitor_stop(); */
ESP_HW_STACK_GUARD_MONITOR_STOP_CPU0
@@ -133,5 +201,16 @@ no_switch:
ESP_HW_STACK_GUARD_MONITOR_START_CPU0
#endif /* CONFIG_ESP_SYSTEM_HW_STACK_GUARD */
#else
/* Recover the stack of next task and prepare to exit : */
la a0, pxCurrentTCB
/* We may come here from a branch, so we re-cal here */
csrr t3, mhartid
slli t3, t3, 2
add a0, a0, t3 /* a0 = &pxCurrentTCB[coreID] */
lw a0, (a0) /* a0 = pxCurrentTCB[coreID] */
lw a0, 0x0(a0) /* a0 = previous sp */
#endif //#if !CONFIG_IDF_TARGET_ESP32P4
rtos_exit_end:
ret

View File

@@ -3,7 +3,7 @@
*
* SPDX-License-Identifier: MIT
*
* SPDX-FileContributor: 2016-2022 Espressif Systems (Shanghai) CO LTD
* SPDX-FileContributor: 2016-2023 Espressif Systems (Shanghai) CO LTD
*/
/*
@@ -185,6 +185,8 @@
/*-----------------------------------------------------------*/
//TODO: IDF-7566
#if !CONFIG_IDF_TARGET_ESP32P4
#define taskSELECT_HIGHEST_PRIORITY_TASK() \
{ \
UBaseType_t uxTopPriority; \
@@ -194,6 +196,17 @@
configASSERT( listCURRENT_LIST_LENGTH( &( pxReadyTasksLists[ uxTopPriority ] ) ) > 0 ); \
listGET_OWNER_OF_NEXT_ENTRY( pxCurrentTCB[ 0 ], &( pxReadyTasksLists[ uxTopPriority ] ) ); \
} /* taskSELECT_HIGHEST_PRIORITY_TASK() */
#else
#define taskSELECT_HIGHEST_PRIORITY_TASK() \
{ \
UBaseType_t uxTopPriority; \
\
/* Find the highest priority list that contains ready tasks. */ \
portGET_HIGHEST_PRIORITY( uxTopPriority, uxTopReadyPriority ); \
configASSERT( listCURRENT_LIST_LENGTH( &( pxReadyTasksLists[ uxTopPriority ] ) ) > 0 ); \
listGET_OWNER_OF_NEXT_ENTRY( pxCurrentTCB[ xPortGetCoreID() ], &( pxReadyTasksLists[ uxTopPriority ] ) ); \
} /* taskSELECT_HIGHEST_PRIORITY_TASK() */
#endif
/*-----------------------------------------------------------*/

View File

@@ -30,6 +30,7 @@ menu "FreeRTOS"
# Todo: Replace with CONFIG_NUM_CORES (IDF-4986)
bool "Run FreeRTOS only on first core"
default "y" if IDF_TARGET_ESP32S2 || IDF_TARGET_LINUX
default "y" if IDF_TARGET_ESP32P4 #TODO: IDF-7566
select ESP_SYSTEM_SINGLE_CORE_MODE
help
This version of FreeRTOS normally takes control of all cores of the CPU. Select this if you only want

View File

@@ -1,5 +1,5 @@
/*
* SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD
* SPDX-FileCopyrightText: 2022-2023 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
@@ -111,10 +111,19 @@ void esp_startup_start_app_other_cores(void)
}
// Wait for CPU0 to start FreeRTOS before progressing
//TODO: IDF-7566
#if !CONFIG_IDF_TARGET_ESP32P4
extern volatile unsigned port_xSchedulerRunning[portNUM_PROCESSORS];
while (port_xSchedulerRunning[0] == 0) {
;
}
#else
extern volatile unsigned uxSchedulerRunning[portNUM_PROCESSORS];
while (uxSchedulerRunning[0] == 0) {
;
}
#endif
#if CONFIG_APPTRACE_ENABLE
// [refactor-todo] move to esp_system initialization

View File

@@ -1,5 +1,5 @@
/*
* SPDX-FileCopyrightText: 2017-2021 Espressif Systems (Shanghai) CO LTD
* SPDX-FileCopyrightText: 2017-2023 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
@@ -64,7 +64,17 @@ void vSystimerSetup(void)
/* Systimer HAL layer object */
static systimer_hal_context_t systimer_hal;
/* set system timer interrupt vector */
/**
* TODO: IDF-7487
* ETS_SYSTIMER_TARGET0_EDGE_INTR_SOURCE is renamed to ETS_SYSTIMER_TARGET0_INTR_SOURCE.
* It's said that this interrupt is never an edge type, for previous all chips. You may need to check this and unify the name.
*/
#if !CONFIG_IDF_TARGET_ESP32P4
ESP_ERROR_CHECK(esp_intr_alloc(ETS_SYSTIMER_TARGET0_EDGE_INTR_SOURCE + cpuid, ESP_INTR_FLAG_IRAM | level, SysTickIsrHandler, &systimer_hal, NULL));
#else
ESP_ERROR_CHECK(esp_intr_alloc(ETS_SYSTIMER_TARGET0_INTR_SOURCE + cpuid, ESP_INTR_FLAG_IRAM | level, SysTickIsrHandler, &systimer_hal, NULL));
#endif
if (cpuid == 0) {
periph_module_enable(PERIPH_SYSTIMER_MODULE);