forked from espressif/esp-idf
Merge branch 'refactor/freertos_port_files' into 'master'
FreeRTOS: Tidy up existing port files Closes IDF-3919 See merge request espressif/esp-idf!15199
This commit is contained in:
@@ -90,7 +90,6 @@
|
|||||||
#define portNUM_PROCESSORS 1
|
#define portNUM_PROCESSORS 1
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#define configASSERT_2 0
|
|
||||||
#define portUSING_MPU_WRAPPERS 0
|
#define portUSING_MPU_WRAPPERS 0
|
||||||
#define configUSE_MUTEX 1
|
#define configUSE_MUTEX 1
|
||||||
|
|
||||||
@@ -206,7 +205,6 @@
|
|||||||
#define configGENERATE_RUN_TIME_STATS 1 /* Used by vTaskGetRunTimeStats() */
|
#define configGENERATE_RUN_TIME_STATS 1 /* Used by vTaskGetRunTimeStats() */
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#define configUSE_TRACE_FACILITY_2 0
|
|
||||||
#define configBENCHMARK 0
|
#define configBENCHMARK 0
|
||||||
#define configUSE_16_BIT_TICKS 0
|
#define configUSE_16_BIT_TICKS 0
|
||||||
#define configIDLE_SHOULD_YIELD 0
|
#define configIDLE_SHOULD_YIELD 0
|
||||||
|
@@ -1,16 +1,8 @@
|
|||||||
// Copyright 2015-2020 Espressif Systems (Shanghai) PTE LTD
|
/*
|
||||||
//
|
* SPDX-FileCopyrightText: 2021 Espressif Systems (Shanghai) CO LTD
|
||||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
*
|
||||||
// you may not use this file except in compliance with the License.
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
// You may obtain a copy of the License at
|
*/
|
||||||
//
|
|
||||||
// http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
//
|
|
||||||
// Unless required by applicable law or agreed to in writing, software
|
|
||||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
// See the License for the specific language governing permissions and
|
|
||||||
// limitations under the License.
|
|
||||||
|
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include "FreeRTOS.h"
|
#include "FreeRTOS.h"
|
||||||
@@ -22,8 +14,9 @@
|
|||||||
#include "esp_task_wdt.h"
|
#include "esp_task_wdt.h"
|
||||||
#include "esp_task.h"
|
#include "esp_task.h"
|
||||||
#include "esp_private/crosscore_int.h"
|
#include "esp_private/crosscore_int.h"
|
||||||
#include "esp_private/startup_internal.h"
|
#include "esp_private/startup_internal.h" /* Required by g_spiram_ok. [refactor-todo] for g_spiram_ok */
|
||||||
#include "esp_log.h"
|
#include "esp_log.h"
|
||||||
|
#include "soc/soc_memory_types.h"
|
||||||
#include "soc/dport_access.h"
|
#include "soc/dport_access.h"
|
||||||
#include "sdkconfig.h"
|
#include "sdkconfig.h"
|
||||||
|
|
||||||
@@ -136,3 +129,19 @@ static void main_task(void* args)
|
|||||||
app_main();
|
app_main();
|
||||||
vTaskDelete(NULL);
|
vTaskDelete(NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// -------------------- Heap Related -----------------------
|
||||||
|
|
||||||
|
bool xPortCheckValidTCBMem(const void *ptr)
|
||||||
|
{
|
||||||
|
return esp_ptr_internal(ptr) && esp_ptr_byte_accessible(ptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool xPortcheckValidStackMem(const void *ptr)
|
||||||
|
{
|
||||||
|
#ifdef CONFIG_SPIRAM_ALLOW_STACK_EXTERNAL_MEMORY
|
||||||
|
return esp_ptr_byte_accessible(ptr);
|
||||||
|
#else
|
||||||
|
return esp_ptr_internal(ptr) && esp_ptr_byte_accessible(ptr);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
@@ -24,46 +24,47 @@
|
|||||||
*
|
*
|
||||||
* 1 tab == 4 spaces!
|
* 1 tab == 4 spaces!
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef PORTMACRO_H
|
#ifndef PORTMACRO_H
|
||||||
#define PORTMACRO_H
|
#define PORTMACRO_H
|
||||||
|
|
||||||
|
#ifndef __ASSEMBLER__
|
||||||
|
|
||||||
|
#include "sdkconfig.h"
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include "soc/spinlock.h"
|
||||||
|
#include "soc/interrupt_core0_reg.h"
|
||||||
|
#include "soc/cpu.h"
|
||||||
|
#include "esp_attr.h"
|
||||||
|
#include "esp_rom_sys.h"
|
||||||
|
#include "esp_timer.h" /* required for FreeRTOS run time stats */
|
||||||
|
#include "esp_heap_caps.h"
|
||||||
|
#include "esp_system.h" /* required by esp_get_...() functions in portable.h. [refactor-todo] Update portable.h */
|
||||||
|
#include "esp_newlib.h"
|
||||||
|
#include "portbenchmark.h"
|
||||||
|
|
||||||
|
/* [refactor-todo] These includes are not directly used in this file. They are kept into to prevent a breaking change. Remove these. */
|
||||||
|
#include <limits.h>
|
||||||
|
#ifdef CONFIG_LEGACY_INCLUDE_COMMON_HEADERS
|
||||||
|
#include "soc/soc_memory_layout.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
extern "C" {
|
extern "C" {
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifndef __ASSEMBLER__
|
|
||||||
|
|
||||||
#include <stdint.h>
|
|
||||||
#include <stdlib.h>
|
|
||||||
#include <stdbool.h>
|
|
||||||
#include <stdio.h>
|
|
||||||
#include <limits.h>
|
|
||||||
#include "esp_timer.h" /* required for FreeRTOS run time stats */
|
|
||||||
|
|
||||||
#include "sdkconfig.h"
|
/* --------------------------------------------------- Port Types ------------------------------------------------------
|
||||||
#include "esp_attr.h"
|
* - Port specific types.
|
||||||
#include "esp_heap_caps.h"
|
* - The settings in this file configure FreeRTOS correctly for the given hardware and compiler.
|
||||||
#ifdef CONFIG_LEGACY_INCLUDE_COMMON_HEADERS
|
* - These settings should not be altered.
|
||||||
#include "soc/soc_memory_layout.h"
|
* - The port types must come first as they are used further down in this file
|
||||||
#endif
|
* ------------------------------------------------------------------------------------------------------------------ */
|
||||||
#include "soc/spinlock.h"
|
|
||||||
#include "soc/interrupt_core0_reg.h"
|
|
||||||
#include "esp_rom_sys.h"
|
|
||||||
#include "soc/cpu.h"
|
|
||||||
#include "esp_system.h"
|
|
||||||
#include "esp_newlib.h"
|
|
||||||
|
|
||||||
/*-----------------------------------------------------------
|
|
||||||
* Port specific definitions.
|
|
||||||
*
|
|
||||||
* The settings in this file configure FreeRTOS correctly for the
|
|
||||||
* given hardware and compiler.
|
|
||||||
*
|
|
||||||
* These settings should not be altered.
|
|
||||||
*-----------------------------------------------------------
|
|
||||||
*/
|
|
||||||
|
|
||||||
/* Type definitions. */
|
|
||||||
#define portCHAR uint8_t
|
#define portCHAR uint8_t
|
||||||
#define portFLOAT float
|
#define portFLOAT float
|
||||||
#define portDOUBLE double
|
#define portDOUBLE double
|
||||||
@@ -71,8 +72,6 @@ extern "C" {
|
|||||||
#define portSHORT int16_t
|
#define portSHORT int16_t
|
||||||
#define portSTACK_TYPE uint8_t
|
#define portSTACK_TYPE uint8_t
|
||||||
#define portBASE_TYPE int
|
#define portBASE_TYPE int
|
||||||
// interrupt module will mask interrupt with priority less than threshold
|
|
||||||
#define RVHAL_EXCM_LEVEL 4
|
|
||||||
|
|
||||||
typedef portSTACK_TYPE StackType_t;
|
typedef portSTACK_TYPE StackType_t;
|
||||||
typedef portBASE_TYPE BaseType_t;
|
typedef portBASE_TYPE BaseType_t;
|
||||||
@@ -85,96 +84,103 @@ typedef unsigned portBASE_TYPE UBaseType_t;
|
|||||||
typedef uint32_t TickType_t;
|
typedef uint32_t TickType_t;
|
||||||
#define portMAX_DELAY (TickType_t) 0xffffffffUL
|
#define portMAX_DELAY (TickType_t) 0xffffffffUL
|
||||||
#endif
|
#endif
|
||||||
/*------------------------------------------------------*/
|
|
||||||
|
|
||||||
/* Architecture specifics. */
|
/* Task function macros as described on the FreeRTOS.org WEB site. */
|
||||||
|
#define portTASK_FUNCTION_PROTO(vFunction, pvParameters) void vFunction(void *pvParameters)
|
||||||
|
#define portTASK_FUNCTION(vFunction, pvParameters) void vFunction(void *pvParameters)
|
||||||
|
|
||||||
|
// interrupt module will mask interrupt with priority less than threshold
|
||||||
|
#define RVHAL_EXCM_LEVEL 4
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/* ----------------------------------------------- Port Configurations -------------------------------------------------
|
||||||
|
* - Configurations values supplied by each port
|
||||||
|
* - Required by FreeRTOS
|
||||||
|
* ------------------------------------------------------------------------------------------------------------------ */
|
||||||
|
|
||||||
|
#define portCRITICAL_NESTING_IN_TCB 0
|
||||||
#define portSTACK_GROWTH (-1)
|
#define portSTACK_GROWTH (-1)
|
||||||
#define portTICK_PERIOD_MS ((TickType_t) (1000 / configTICK_RATE_HZ))
|
#define portTICK_PERIOD_MS ((TickType_t) (1000 / configTICK_RATE_HZ))
|
||||||
#define portBYTE_ALIGNMENT 16
|
#define portBYTE_ALIGNMENT 16
|
||||||
/*-----------------------------------------------------------*/
|
#define portNOP() __asm volatile (" nop ")
|
||||||
#include "portbenchmark.h"
|
|
||||||
|
|
||||||
static inline BaseType_t IRAM_ATTR xPortGetCoreID(void) {
|
|
||||||
return cpu_hal_get_core_id();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline void uxPortCompareSetExtram(volatile uint32_t *addr, uint32_t compare, uint32_t *set)
|
/* ---------------------------------------------- Forward Declarations -------------------------------------------------
|
||||||
{
|
* - Forward declarations of all the port functions and macros need to implement the FreeRTOS porting interface
|
||||||
#if defined(CONFIG_SPIRAM)
|
* - These must come before definition/declaration of the FreeRTOS porting interface
|
||||||
compare_and_set_extram(addr, compare, set);
|
* ------------------------------------------------------------------------------------------------------------------ */
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline void __attribute__((always_inline)) uxPortCompareSet(volatile uint32_t *addr, uint32_t compare, uint32_t *set) {
|
// --------------------- Interrupts ------------------------
|
||||||
compare_and_set_native(addr, compare, set);
|
|
||||||
}
|
|
||||||
|
|
||||||
#define portCRITICAL_NESTING_IN_TCB 0
|
/**
|
||||||
|
* @brief Checks if the current core is in an ISR context
|
||||||
/*
|
*
|
||||||
* Send an interrupt to another core in order to make the task running
|
* - ISR context consist of Low/Mid priority ISR, or time tick ISR
|
||||||
* on it yield for a higher-priority task.
|
* - High priority ISRs aren't detected here, but they normally cannot call C code, so that should not be an issue anyway.
|
||||||
*/
|
*
|
||||||
void vPortYieldOtherCore( BaseType_t coreid);
|
* @note [refactor-todo] Check if this should be inlined
|
||||||
|
* @return
|
||||||
/*
|
* - pdTRUE if in ISR
|
||||||
Callback to set a watchpoint on the end of the stack. Called every context switch to change the stack
|
* - pdFALSE otherwise
|
||||||
watchpoint around.
|
|
||||||
*/
|
|
||||||
void vPortSetStackWatchpoint( void* pxStackStart );
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Returns true if the current core is in ISR context; low prio ISR, med prio ISR or timer tick ISR. High prio ISRs
|
|
||||||
* aren't detected here, but they normally cannot call C code, so that should not be an issue anyway.
|
|
||||||
*/
|
*/
|
||||||
BaseType_t xPortInIsrContext(void);
|
BaseType_t xPortInIsrContext(void);
|
||||||
|
|
||||||
/*
|
/**
|
||||||
* This function will be called in High prio ISRs. Returns true if the current core was in ISR context
|
* @brief Check if in ISR context from High priority ISRs
|
||||||
* before calling into high prio ISR context.
|
*
|
||||||
|
* - 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);
|
BaseType_t xPortInterruptedFromISRContext(void);
|
||||||
|
|
||||||
/* "mux" data structure (spinlock) */
|
/**
|
||||||
|
* @brief Disable interrupts in a nested manner
|
||||||
|
*
|
||||||
|
* - Cleaner solution allows nested interrupts disabling and restoring via local registers or stack.
|
||||||
|
* - They can be called from interrupts too.
|
||||||
|
* - WARNING Only applies to current CPU.
|
||||||
|
*
|
||||||
|
* @note [refactor-todo] Define this as portSET_INTERRUPT_MASK_FROM_ISR() instead
|
||||||
|
* @return unsigned Previous interrupt state
|
||||||
|
*/
|
||||||
|
static inline unsigned portENTER_CRITICAL_NESTED(void);
|
||||||
|
|
||||||
|
/* ---------------------- 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 {
|
typedef struct {
|
||||||
/* owner field values:
|
|
||||||
* 0 - Uninitialized (invalid)
|
|
||||||
* portMUX_FREE_VAL - Mux is free, can be locked by either CPU
|
|
||||||
* CORE_ID_REGVAL_PRO / CORE_ID_REGVAL_APP - Mux is locked to the particular core
|
|
||||||
*
|
|
||||||
*
|
|
||||||
* Any value other than portMUX_FREE_VAL, CORE_ID_REGVAL_PRO, CORE_ID_REGVAL_APP indicates corruption
|
|
||||||
*/
|
|
||||||
uint32_t owner;
|
uint32_t owner;
|
||||||
/* count field:
|
|
||||||
* If mux is unlocked, count should be zero.
|
|
||||||
* If mux is locked, count is non-zero & represents the number of recursive locks on the mux.
|
|
||||||
*/
|
|
||||||
uint32_t count;
|
uint32_t count;
|
||||||
#ifdef CONFIG_FREERTOS_PORTMUX_DEBUG
|
#ifdef CONFIG_FREERTOS_PORTMUX_DEBUG
|
||||||
const char *lastLockedFn;
|
const char *lastLockedFn;
|
||||||
int lastLockedLine;
|
int lastLockedLine;
|
||||||
#endif
|
#endif
|
||||||
} portMUX_TYPE;
|
} portMUX_TYPE;
|
||||||
|
/**< Spinlock initializer */
|
||||||
#define portMUX_FREE_VAL SPINLOCK_FREE
|
|
||||||
|
|
||||||
/* Special constants for vPortCPUAcquireMutexTimeout() */
|
|
||||||
#define portMUX_NO_TIMEOUT SPINLOCK_WAIT_FOREVER /* When passed for 'timeout_cycles', spin forever if necessary */
|
|
||||||
#define portMUX_TRY_LOCK SPINLOCK_NO_WAIT /* Try to acquire the spinlock a single time only */
|
|
||||||
|
|
||||||
// Keep this in sync with the portMUX_TYPE struct definition please.
|
|
||||||
#ifndef CONFIG_FREERTOS_PORTMUX_DEBUG
|
#ifndef CONFIG_FREERTOS_PORTMUX_DEBUG
|
||||||
#define portMUX_INITIALIZER_UNLOCKED { \
|
#define portMUX_INITIALIZER_UNLOCKED { \
|
||||||
.owner = portMUX_FREE_VAL, \
|
.owner = portMUX_FREE_VAL, \
|
||||||
@@ -187,15 +193,251 @@ typedef struct {
|
|||||||
.lastLockedFn = "(never locked)", \
|
.lastLockedFn = "(never locked)", \
|
||||||
.lastLockedLine = -1 \
|
.lastLockedLine = -1 \
|
||||||
}
|
}
|
||||||
#endif
|
#endif /* CONFIG_FREERTOS_PORTMUX_DEBUG */
|
||||||
|
#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 */
|
||||||
|
|
||||||
/* Scheduler utilities. */
|
/**
|
||||||
extern void vPortYield( void );
|
* @brief Initialize a spinlock
|
||||||
extern void vPortYieldFromISR( void );
|
*
|
||||||
|
* - Initializes a spinlock that is used by FreeRTOS SMP critical sections
|
||||||
|
*
|
||||||
|
* @note [refactor-todo] We can make this inline or consider making it a macro
|
||||||
|
* @param[in] mux Spinlock
|
||||||
|
*/
|
||||||
|
void vPortCPUInitializeMutex(portMUX_TYPE *mux);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Acquire a spinlock
|
||||||
|
*
|
||||||
|
* @note [refactor-todo] check if we still need this
|
||||||
|
* @note [refactor-todo] Check if this should be inlined
|
||||||
|
* @param[in] mux Spinlock
|
||||||
|
*/
|
||||||
|
void vPortCPUAcquireMutex(portMUX_TYPE *mux);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Acquire a spinlock but with a specified timeout
|
||||||
|
*
|
||||||
|
* @note [refactor-todo] Check if we still need this
|
||||||
|
* @note [refactor-todo] Check if this should be inlined
|
||||||
|
* @note [refactor-todo] Check if this function should be renamed (due to bool return type)
|
||||||
|
* @param[in] mux Spinlock
|
||||||
|
* @param[in] timeout Timeout in number of CPU cycles
|
||||||
|
* @return true Spinlock acquired
|
||||||
|
* @return false Timed out
|
||||||
|
*/
|
||||||
|
bool vPortCPUAcquireMutexTimeout(portMUX_TYPE *mux, int timeout_cycles);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Release a spinlock
|
||||||
|
*
|
||||||
|
* @note [refactor-todo] check if we still need this
|
||||||
|
* @note [refactor-todo] Check if this should be inlined
|
||||||
|
* @param[in] mux Spinlock
|
||||||
|
*/
|
||||||
|
void vPortCPUReleaseMutex(portMUX_TYPE *mux);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @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);
|
||||||
|
|
||||||
|
// ------------------ Critical Sections --------------------
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @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 -------------------------
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @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
|
||||||
|
*/
|
||||||
|
int vPortSetInterruptMask(void);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Clear current interrupt mask and set given mask
|
||||||
|
*
|
||||||
|
* @param mask Interrupt mask
|
||||||
|
*/
|
||||||
|
void vPortClearInterruptMask(int mask);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Perform a context switch from a task
|
||||||
|
*
|
||||||
|
* @note [refactor-todo] The rest of ESP-IDF should call taskYield() instead
|
||||||
|
*/
|
||||||
|
void vPortYield(void);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Perform a context switch from an ISR
|
||||||
|
*/
|
||||||
|
void vPortYieldFromISR(void);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @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 IRAM_ATTR xPortCanYield(void);
|
||||||
|
|
||||||
|
// ------------------- Hook Functions ----------------------
|
||||||
|
|
||||||
|
extern void esp_vApplicationIdleHook(void);
|
||||||
|
extern void esp_vApplicationTickHook(void);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Hook function called on entry to tickless idle
|
||||||
|
*
|
||||||
|
* - Implemented in pm_impl.c
|
||||||
|
*
|
||||||
|
* @param xExpectedIdleTime Expected idle time
|
||||||
|
*/
|
||||||
|
void vApplicationSleep(TickType_t xExpectedIdleTime);
|
||||||
|
|
||||||
|
// ----------------------- 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 cpu_hal_get_core_id();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/* ------------------------------------------- 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 --------------------------
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @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)
|
||||||
|
|
||||||
|
// --------------------- Interrupts ------------------------
|
||||||
|
|
||||||
|
#define portEXIT_CRITICAL_NESTED(state) do { portCLEAR_INTERRUPT_MASK_FROM_ISR(state);} while(0);
|
||||||
|
#define portDISABLE_INTERRUPTS() portSET_INTERRUPT_MASK_FROM_ISR()
|
||||||
|
#define portENABLE_INTERRUPTS() portCLEAR_INTERRUPT_MASK_FROM_ISR(1)
|
||||||
|
#define portSET_INTERRUPT_MASK_FROM_ISR() vPortSetInterruptMask()
|
||||||
|
#define portCLEAR_INTERRUPT_MASK_FROM_ISR(uxSavedStatusValue) vPortClearInterruptMask(uxSavedStatusValue)
|
||||||
|
|
||||||
|
// ------------------ Critical Sections --------------------
|
||||||
|
|
||||||
|
#define portENTER_CRITICAL(mux) {(void)mux; vPortEnterCritical();}
|
||||||
|
#define portEXIT_CRITICAL(mux) {(void)mux; vPortExitCritical();}
|
||||||
|
//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)
|
||||||
|
/* [refactor-todo] on RISC-V, both ISR and non-ISR cases result in the same call. We can redefine this macro */
|
||||||
|
#define portENTER_CRITICAL_SAFE(mux) ({ \
|
||||||
|
if (xPortInIsrContext()) { \
|
||||||
|
portENTER_CRITICAL_ISR(mux); \
|
||||||
|
} else { \
|
||||||
|
portENTER_CRITICAL(mux); \
|
||||||
|
} \
|
||||||
|
})
|
||||||
|
#define portEXIT_CRITICAL_SAFE(mux) ({ \
|
||||||
|
if (xPortInIsrContext()) { \
|
||||||
|
portEXIT_CRITICAL_ISR(mux); \
|
||||||
|
} else { \
|
||||||
|
portEXIT_CRITICAL(mux); \
|
||||||
|
} \
|
||||||
|
})
|
||||||
|
|
||||||
|
// ---------------------- Yielding -------------------------
|
||||||
|
|
||||||
#define portYIELD() vPortYield()
|
#define portYIELD() vPortYield()
|
||||||
#define portYIELD_FROM_ISR() vPortYieldFromISR()
|
#define portYIELD_FROM_ISR() vPortYieldFromISR()
|
||||||
|
#define portEND_SWITCHING_ISR(xSwitchRequired) if(xSwitchRequired) vPortYield()
|
||||||
/* Yielding within an API call (when interrupts are off), means the yield should be delayed
|
/* Yielding within an API call (when interrupts are off), means the yield should be delayed
|
||||||
until interrupts are re-enabled.
|
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
|
To do this, we use the "cross-core" interrupt as a trigger to yield on this core when interrupts are re-enabled.This
|
||||||
@@ -203,112 +445,104 @@ extern void vPortYieldFromISR( void );
|
|||||||
happening on the same CPU.
|
happening on the same CPU.
|
||||||
*/
|
*/
|
||||||
#define portYIELD_WITHIN_API() portYIELD()
|
#define portYIELD_WITHIN_API() portYIELD()
|
||||||
/*-----------------------------------------------------------*/
|
|
||||||
|
|
||||||
/* Critical section management. */
|
// ------------------- Hook Functions ----------------------
|
||||||
extern int vPortSetInterruptMask(void);
|
|
||||||
extern void vPortClearInterruptMask( int );
|
|
||||||
|
|
||||||
void vPortCPUInitializeMutex(portMUX_TYPE *mux);
|
|
||||||
void vPortCPUAcquireMutex(portMUX_TYPE *mux);
|
|
||||||
bool vPortCPUAcquireMutexTimeout(portMUX_TYPE *mux, int timeout_cycles);
|
|
||||||
void vPortCPUReleaseMutex(portMUX_TYPE *mux);
|
|
||||||
|
|
||||||
extern void vPortEnterCritical( void );
|
|
||||||
extern void vPortExitCritical( void );
|
|
||||||
|
|
||||||
#define portDISABLE_INTERRUPTS() portSET_INTERRUPT_MASK_FROM_ISR()
|
|
||||||
#define portENABLE_INTERRUPTS() portCLEAR_INTERRUPT_MASK_FROM_ISR(1)
|
|
||||||
|
|
||||||
#define portENTER_CRITICAL(mux) {(void)mux; vPortEnterCritical();}
|
|
||||||
#define portEXIT_CRITICAL(mux) {(void)mux; vPortExitCritical();}
|
|
||||||
|
|
||||||
#define portENTER_CRITICAL_ISR(mux) portENTER_CRITICAL(mux)
|
|
||||||
#define portEXIT_CRITICAL_ISR(mux) portEXIT_CRITICAL(mux)
|
|
||||||
|
|
||||||
#define portENTER_CRITICAL_SAFE(mux) do { \
|
|
||||||
if (xPortInIsrContext()) { \
|
|
||||||
portENTER_CRITICAL_ISR(mux); \
|
|
||||||
} else { \
|
|
||||||
portENTER_CRITICAL(mux); \
|
|
||||||
} \
|
|
||||||
} while(0)
|
|
||||||
|
|
||||||
#define portEXIT_CRITICAL_SAFE(mux) do { \
|
|
||||||
if (xPortInIsrContext()) { \
|
|
||||||
portEXIT_CRITICAL_ISR(mux); \
|
|
||||||
} else { \
|
|
||||||
portEXIT_CRITICAL(mux); \
|
|
||||||
} \
|
|
||||||
} while(0)
|
|
||||||
|
|
||||||
/*------------------------------------------------------------*/
|
|
||||||
#define portSET_INTERRUPT_MASK_FROM_ISR() vPortSetInterruptMask()
|
|
||||||
#define portCLEAR_INTERRUPT_MASK_FROM_ISR( uxSavedStatusValue ) vPortClearInterruptMask( uxSavedStatusValue )
|
|
||||||
#define portEND_SWITCHING_ISR( xSwitchRequired ) if( xSwitchRequired ) vPortYield()
|
|
||||||
|
|
||||||
// Cleaner solution allows nested interrupts disabling and restoring via local registers or stack.
|
|
||||||
// They can be called from interrupts too.
|
|
||||||
static inline unsigned portENTER_CRITICAL_NESTED(void) {
|
|
||||||
unsigned state = portSET_INTERRUPT_MASK_FROM_ISR();
|
|
||||||
return state;
|
|
||||||
}
|
|
||||||
|
|
||||||
#define portEXIT_CRITICAL_NESTED(state) do { portCLEAR_INTERRUPT_MASK_FROM_ISR( state );} while(0);
|
|
||||||
/*-----------------------------------------------------------*/
|
|
||||||
|
|
||||||
//Because the ROM routines don't necessarily handle a stack in external RAM correctly, we force
|
|
||||||
//the stack memory to always be internal.
|
|
||||||
#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)
|
|
||||||
|
|
||||||
/* Fine resolution time */
|
|
||||||
#define portGET_RUN_TIME_COUNTER_VALUE() 0
|
|
||||||
#define portCONFIGURE_TIMER_FOR_RUN_TIME_STATS()
|
|
||||||
|
|
||||||
#ifdef CONFIG_FREERTOS_RUN_TIME_STATS_USING_ESP_TIMER
|
|
||||||
/* Coarse resolution time (us) */
|
|
||||||
#define portALT_GET_RUN_TIME_COUNTER_VALUE(x) do {x = (uint32_t)esp_timer_get_time();} while(0)
|
|
||||||
#endif
|
|
||||||
|
|
||||||
extern void esp_vApplicationIdleHook( void );
|
|
||||||
extern void esp_vApplicationTickHook( void );
|
|
||||||
|
|
||||||
#ifndef CONFIG_FREERTOS_LEGACY_HOOKS
|
#ifndef CONFIG_FREERTOS_LEGACY_HOOKS
|
||||||
#define vApplicationIdleHook esp_vApplicationIdleHook
|
#define vApplicationIdleHook esp_vApplicationIdleHook
|
||||||
#define vApplicationTickHook esp_vApplicationTickHook
|
#define vApplicationTickHook esp_vApplicationTickHook
|
||||||
#endif /* !CONFIG_FREERTOS_LEGACY_HOOKS */
|
#endif /* !CONFIG_FREERTOS_LEGACY_HOOKS */
|
||||||
|
|
||||||
/* Task function macros as described on the FreeRTOS.org WEB site. */
|
|
||||||
#define portTASK_FUNCTION_PROTO( vFunction, pvParameters ) void vFunction( void *pvParameters )
|
|
||||||
#define portTASK_FUNCTION( vFunction, pvParameters ) void vFunction( void *pvParameters )
|
|
||||||
|
|
||||||
void vApplicationSleep( TickType_t xExpectedIdleTime );
|
|
||||||
#define portSUPPRESS_TICKS_AND_SLEEP(idleTime) vApplicationSleep(idleTime)
|
#define portSUPPRESS_TICKS_AND_SLEEP(idleTime) vApplicationSleep(idleTime)
|
||||||
|
|
||||||
#define portNOP() __asm volatile ( " nop " )
|
// ------------------- Run Time Stats ----------------------
|
||||||
|
|
||||||
#define portVALID_TCB_MEM(ptr) esp_ptr_byte_accessible(ptr)
|
#define portCONFIGURE_TIMER_FOR_RUN_TIME_STATS()
|
||||||
#define portVALID_STACK_MEM(ptr) esp_ptr_byte_accessible(ptr)
|
#define portGET_RUN_TIME_COUNTER_VALUE() 0
|
||||||
|
#ifdef CONFIG_FREERTOS_RUN_TIME_STATS_USING_ESP_TIMER
|
||||||
/* Get tick rate per second */
|
/* Coarse resolution time (us) */
|
||||||
uint32_t xPortGetTickRateHz(void);
|
#define portALT_GET_RUN_TIME_COUNTER_VALUE(x) do {x = (uint32_t)esp_timer_get_time();} while(0)
|
||||||
|
|
||||||
// configASSERT_2 if requested
|
|
||||||
#if configASSERT_2
|
|
||||||
#include <stdio.h>
|
|
||||||
void exit(int);
|
|
||||||
#define configASSERT( x ) if (!(x)) { porttracePrint(-1); printf("\nAssertion failed in %s:%d\n", __FILE__, __LINE__); exit(-1); }
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
#endif //__ASSEMBLER__
|
|
||||||
|
/* --------------------------------------------- Inline Implementations ------------------------------------------------
|
||||||
|
* - Implementation of inline functions of the forward declares
|
||||||
|
* - Should come after forward declare and FreeRTOS Porting interface, as implementation may use both.
|
||||||
|
* - For implementation of non-inlined functions, see port.c, port_common.c, or other assembly files
|
||||||
|
* ------------------------------------------------------------------------------------------------------------------ */
|
||||||
|
|
||||||
|
// --------------------- Interrupts ------------------------
|
||||||
|
|
||||||
|
static inline unsigned portENTER_CRITICAL_NESTED(void)
|
||||||
|
{
|
||||||
|
unsigned state = portSET_INTERRUPT_MASK_FROM_ISR();
|
||||||
|
return state;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ---------------------- Spinlocks ------------------------
|
||||||
|
|
||||||
|
static inline void __attribute__((always_inline)) uxPortCompareSet(volatile uint32_t *addr, uint32_t compare, uint32_t *set)
|
||||||
|
{
|
||||||
|
compare_and_set_native(addr, compare, set);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void uxPortCompareSetExtram(volatile uint32_t *addr, uint32_t compare, uint32_t *set)
|
||||||
|
{
|
||||||
|
#if defined(CONFIG_SPIRAM)
|
||||||
|
compare_and_set_extram(addr, compare, set);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
// ---------------------- Yielding -------------------------
|
||||||
|
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/* ------------------------------------------------------ Misc ---------------------------------------------------------
|
||||||
|
* - Miscellaneous porting macros
|
||||||
|
* - These are not port of the FreeRTOS porting interface, but are used by other FreeRTOS dependent components
|
||||||
|
* ------------------------------------------------------------------------------------------------------------------ */
|
||||||
|
|
||||||
|
// -------------------- Heap Related -----------------------
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Checks if a given piece of memory can be used to store a task's TCB
|
||||||
|
*
|
||||||
|
* - Defined in port_common.c
|
||||||
|
*
|
||||||
|
* @param ptr Pointer to memory
|
||||||
|
* @return true Memory can be used to store a TCB
|
||||||
|
* @return false Otherwise
|
||||||
|
*/
|
||||||
|
bool xPortCheckValidTCBMem(const void *ptr);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Checks if a given piece of memory can be used to store a task's stack
|
||||||
|
*
|
||||||
|
* - Defined in port_common.c
|
||||||
|
*
|
||||||
|
* @param ptr Pointer to memory
|
||||||
|
* @return true Memory can be used to store a task stack
|
||||||
|
* @return false Otherwise
|
||||||
|
*/
|
||||||
|
bool xPortcheckValidStackMem(const void *ptr);
|
||||||
|
|
||||||
|
#define portVALID_TCB_MEM(ptr) xPortCheckValidTCBMem(ptr)
|
||||||
|
#define portVALID_STACK_MEM(ptr) xPortcheckValidStackMem(ptr)
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#endif //__ASSEMBLER__
|
||||||
|
|
||||||
#endif /* PORTMACRO_H */
|
#endif /* PORTMACRO_H */
|
||||||
|
@@ -74,31 +74,35 @@
|
|||||||
* Implementation of functions defined in portable.h for the RISC-V port.
|
* Implementation of functions defined in portable.h for the RISC-V port.
|
||||||
*----------------------------------------------------------------------*/
|
*----------------------------------------------------------------------*/
|
||||||
|
|
||||||
#include <string.h>
|
|
||||||
#include "FreeRTOS.h"
|
|
||||||
#include "task.h"
|
|
||||||
#include "portmacro.h"
|
|
||||||
|
|
||||||
#include "sdkconfig.h"
|
#include "sdkconfig.h"
|
||||||
|
#include <string.h>
|
||||||
#include "soc/soc_caps.h"
|
#include "soc/soc_caps.h"
|
||||||
#include "soc/periph_defs.h"
|
#include "soc/periph_defs.h"
|
||||||
#include "soc/system_reg.h"
|
#include "soc/system_reg.h"
|
||||||
#include "hal/systimer_hal.h"
|
#include "hal/systimer_hal.h"
|
||||||
#include "hal/systimer_ll.h"
|
#include "hal/systimer_ll.h"
|
||||||
|
|
||||||
#include "riscv/rvruntime-frames.h"
|
#include "riscv/rvruntime-frames.h"
|
||||||
#include "riscv/riscv_interrupts.h"
|
#include "riscv/riscv_interrupts.h"
|
||||||
#include "riscv/interrupt.h"
|
#include "riscv/interrupt.h"
|
||||||
|
#include "esp_private/crosscore_int.h"
|
||||||
#include "port_systick.h"
|
#include "esp_private/pm_trace.h"
|
||||||
|
#include "esp_attr.h"
|
||||||
#include "esp_system.h"
|
#include "esp_system.h"
|
||||||
#include "esp_intr_alloc.h"
|
#include "esp_intr_alloc.h"
|
||||||
#include "esp_private/crosscore_int.h"
|
|
||||||
#include "esp_attr.h"
|
|
||||||
#include "esp_debug_helpers.h"
|
#include "esp_debug_helpers.h"
|
||||||
#include "esp_log.h"
|
#include "esp_log.h"
|
||||||
#include "esp_private/pm_trace.h"
|
#include "FreeRTOS.h" /* This pulls in portmacro.h */
|
||||||
|
#include "task.h"
|
||||||
|
#include "portmacro.h"
|
||||||
|
#include "port_systick.h"
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/* ---------------------------------------------------- Variables ------------------------------------------------------
|
||||||
|
*
|
||||||
|
* ------------------------------------------------------------------------------------------------------------------ */
|
||||||
|
|
||||||
|
static const char *TAG = "cpu_start"; // [refactor-todo]: might be appropriate to change in the future, but
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief A variable is used to keep track of the critical section nesting.
|
* @brief A variable is used to keep track of the critical section nesting.
|
||||||
@@ -114,33 +118,43 @@ 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)));
|
||||||
|
|
||||||
static const char *TAG = "cpu_start"; // [refactor-todo]: might be appropriate to change in the future, but
|
|
||||||
|
|
||||||
static void prvTaskExitError(void);
|
|
||||||
|
/* ------------------------------------------------ FreeRTOS Portable --------------------------------------------------
|
||||||
|
* - Provides implementation for functions required by FreeRTOS
|
||||||
|
* - Declared in portable.h
|
||||||
|
* ------------------------------------------------------------------------------------------------------------------ */
|
||||||
|
|
||||||
|
// ----------------- Scheduler Start/End -------------------
|
||||||
|
|
||||||
extern void esprv_intc_int_set_threshold(int); // FIXME, this function is in ROM only
|
extern void esprv_intc_int_set_threshold(int); // FIXME, this function is in ROM only
|
||||||
|
BaseType_t xPortStartScheduler(void)
|
||||||
void vPortEnterCritical(void)
|
|
||||||
{
|
{
|
||||||
BaseType_t state = portENTER_CRITICAL_NESTED();
|
uxInterruptNesting = 0;
|
||||||
uxCriticalNesting++;
|
uxCriticalNesting = 0;
|
||||||
|
uxSchedulerRunning = 0;
|
||||||
|
|
||||||
if (uxCriticalNesting == 1) {
|
/* Setup the hardware to generate the tick. */
|
||||||
uxSavedInterruptState = state;
|
vPortSetupTimer();
|
||||||
}
|
|
||||||
|
esprv_intc_int_set_threshold(1); /* set global INTC masking level */
|
||||||
|
riscv_global_interrupts_enable();
|
||||||
|
|
||||||
|
vPortYield();
|
||||||
|
|
||||||
|
/*Should not get here*/
|
||||||
|
return pdFALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
void vPortExitCritical(void)
|
void vPortEndScheduler(void)
|
||||||
{
|
{
|
||||||
if (uxCriticalNesting > 0) {
|
/* very unlikely this function will be called, so just trap here */
|
||||||
uxCriticalNesting--;
|
abort();
|
||||||
if (uxCriticalNesting == 0) {
|
|
||||||
portEXIT_CRITICAL_NESTED(uxSavedInterruptState);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void prvTaskExitError(void)
|
// ------------------------ Stack --------------------------
|
||||||
|
|
||||||
|
static void prvTaskExitError(void)
|
||||||
{
|
{
|
||||||
/* A function that implements a task must not exit or attempt to return to
|
/* A function that implements a task must not exit or attempt to return to
|
||||||
its caller as there is nothing to return to. If a task wants to exit it
|
its caller as there is nothing to return to. If a task wants to exit it
|
||||||
@@ -153,52 +167,6 @@ void prvTaskExitError(void)
|
|||||||
abort();
|
abort();
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Clear current interrupt mask and set given mask */
|
|
||||||
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" );
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Set interrupt mask and return current interrupt enable register */
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
StackType_t *pxPortInitialiseStack(StackType_t *pxTopOfStack, TaskFunction_t pxCode, void *pvParameters)
|
StackType_t *pxPortInitialiseStack(StackType_t *pxTopOfStack, TaskFunction_t pxCode, void *pvParameters)
|
||||||
{
|
{
|
||||||
extern uint32_t __global_pointer$;
|
extern uint32_t __global_pointer$;
|
||||||
@@ -271,78 +239,13 @@ StackType_t *pxPortInitialiseStack(StackType_t *pxTopOfStack, TaskFunction_t pxC
|
|||||||
return (StackType_t *)frame;
|
return (StackType_t *)frame;
|
||||||
}
|
}
|
||||||
|
|
||||||
BaseType_t xPortStartScheduler(void)
|
|
||||||
{
|
|
||||||
uxInterruptNesting = 0;
|
|
||||||
uxCriticalNesting = 0;
|
|
||||||
uxSchedulerRunning = 0;
|
|
||||||
|
|
||||||
/* Setup the hardware to generate the tick. */
|
|
||||||
vPortSetupTimer();
|
|
||||||
|
|
||||||
esprv_intc_int_set_threshold(1); /* set global INTC masking level */
|
/* ---------------------------------------------- Port Implementations -------------------------------------------------
|
||||||
riscv_global_interrupts_enable();
|
*
|
||||||
|
* ------------------------------------------------------------------------------------------------------------------ */
|
||||||
|
|
||||||
vPortYield();
|
// --------------------- Interrupts ------------------------
|
||||||
|
|
||||||
/*Should not get here*/
|
|
||||||
return pdFALSE;
|
|
||||||
}
|
|
||||||
|
|
||||||
void vPortEndScheduler(void)
|
|
||||||
{
|
|
||||||
/* very unlikely this function will be called, so just trap here */
|
|
||||||
abort();
|
|
||||||
}
|
|
||||||
|
|
||||||
void vPortYieldOtherCore(BaseType_t coreid)
|
|
||||||
{
|
|
||||||
esp_crosscore_int_send_yield(coreid);
|
|
||||||
}
|
|
||||||
|
|
||||||
void vPortYieldFromISR( void )
|
|
||||||
{
|
|
||||||
traceISR_EXIT_TO_SCHEDULER();
|
|
||||||
uxSchedulerRunning = 1;
|
|
||||||
xPortSwitchFlag = 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
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 && uxCriticalNesting == 0 && REG_READ(SYSTEM_CPU_INTR_FROM_CPU_0_REG) != 0) {}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
#define STACK_WATCH_AREA_SIZE 32
|
|
||||||
#define STACK_WATCH_POINT_NUMBER (SOC_CPU_WATCHPOINTS_NUM - 1)
|
|
||||||
|
|
||||||
void vPortSetStackWatchpoint(void *pxStackStart)
|
|
||||||
{
|
|
||||||
uint32_t addr = (uint32_t)pxStackStart;
|
|
||||||
addr = (addr + (STACK_WATCH_AREA_SIZE - 1)) & (~(STACK_WATCH_AREA_SIZE - 1));
|
|
||||||
esp_cpu_set_watchpoint(STACK_WATCH_POINT_NUMBER, (char *)addr, STACK_WATCH_AREA_SIZE, ESP_WATCHPOINT_STORE);
|
|
||||||
}
|
|
||||||
|
|
||||||
uint32_t xPortGetTickRateHz(void)
|
|
||||||
{
|
|
||||||
return (uint32_t)configTICK_RATE_HZ;
|
|
||||||
}
|
|
||||||
|
|
||||||
BaseType_t xPortInIsrContext(void)
|
BaseType_t xPortInIsrContext(void)
|
||||||
{
|
{
|
||||||
@@ -355,6 +258,7 @@ BaseType_t IRAM_ATTR xPortInterruptedFromISRContext(void)
|
|||||||
return uxInterruptNesting;
|
return uxInterruptNesting;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ---------------------- Spinlocks ------------------------
|
||||||
|
|
||||||
void vPortCPUInitializeMutex(portMUX_TYPE *mux)
|
void vPortCPUInitializeMutex(portMUX_TYPE *mux)
|
||||||
{
|
{
|
||||||
@@ -378,6 +282,109 @@ void vPortCPUReleaseMutex(portMUX_TYPE *mux)
|
|||||||
(void)mux; //TODO: IDF-2393
|
(void)mux; //TODO: IDF-2393
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ------------------ Critical Sections --------------------
|
||||||
|
|
||||||
|
void vPortEnterCritical(void)
|
||||||
|
{
|
||||||
|
BaseType_t state = portENTER_CRITICAL_NESTED();
|
||||||
|
uxCriticalNesting++;
|
||||||
|
|
||||||
|
if (uxCriticalNesting == 1) {
|
||||||
|
uxSavedInterruptState = state;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void vPortExitCritical(void)
|
||||||
|
{
|
||||||
|
if (uxCriticalNesting > 0) {
|
||||||
|
uxCriticalNesting--;
|
||||||
|
if (uxCriticalNesting == 0) {
|
||||||
|
portEXIT_CRITICAL_NESTED(uxSavedInterruptState);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ---------------------- 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 && uxCriticalNesting == 0 && 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);
|
||||||
|
}
|
||||||
|
|
||||||
|
// ------------------- Hook Functions ----------------------
|
||||||
|
|
||||||
void __attribute__((weak)) vApplicationStackOverflowHook(TaskHandle_t xTask, char *pcTaskName)
|
void __attribute__((weak)) vApplicationStackOverflowHook(TaskHandle_t xTask, char *pcTaskName)
|
||||||
{
|
{
|
||||||
#define ERR_STR1 "***ERROR*** A stack overflow in task "
|
#define ERR_STR1 "***ERROR*** A stack overflow in task "
|
||||||
@@ -393,6 +400,32 @@ void __attribute__((weak)) vApplicationStackOverflowHook(TaskHandle_t xTask, cha
|
|||||||
esp_system_abort(buf);
|
esp_system_abort(buf);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ----------------------- System --------------------------
|
||||||
|
|
||||||
|
uint32_t xPortGetTickRateHz(void)
|
||||||
|
{
|
||||||
|
return (uint32_t)configTICK_RATE_HZ;
|
||||||
|
}
|
||||||
|
|
||||||
|
#define STACK_WATCH_AREA_SIZE 32
|
||||||
|
#define STACK_WATCH_POINT_NUMBER (SOC_CPU_WATCHPOINTS_NUM - 1)
|
||||||
|
|
||||||
|
void vPortSetStackWatchpoint(void *pxStackStart)
|
||||||
|
{
|
||||||
|
uint32_t addr = (uint32_t)pxStackStart;
|
||||||
|
addr = (addr + (STACK_WATCH_AREA_SIZE - 1)) & (~(STACK_WATCH_AREA_SIZE - 1));
|
||||||
|
esp_cpu_set_watchpoint(STACK_WATCH_POINT_NUMBER, (char *)addr, STACK_WATCH_AREA_SIZE, ESP_WATCHPOINT_STORE);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/* ---------------------------------------------- Misc Implementations -------------------------------------------------
|
||||||
|
*
|
||||||
|
* ------------------------------------------------------------------------------------------------------------------ */
|
||||||
|
|
||||||
|
// --------------------- App Start-up ----------------------
|
||||||
|
|
||||||
|
/* [refactor-todo]: See if we can include this through a header */
|
||||||
extern void esp_startup_start_app_common(void);
|
extern void esp_startup_start_app_common(void);
|
||||||
|
|
||||||
void esp_startup_start_app(void)
|
void esp_startup_start_app(void)
|
||||||
|
@@ -24,56 +24,54 @@
|
|||||||
*
|
*
|
||||||
* 1 tab == 4 spaces!
|
* 1 tab == 4 spaces!
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef PORTMACRO_H
|
#ifndef PORTMACRO_H
|
||||||
#define PORTMACRO_H
|
#define PORTMACRO_H
|
||||||
|
|
||||||
|
#ifndef __ASSEMBLER__
|
||||||
|
|
||||||
|
#include "sdkconfig.h"
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include <stdarg.h>
|
||||||
|
#include <xtensa/config/core.h>
|
||||||
|
#include <xtensa/hal.h> /* required for xthal_get_ccount. [refactor-todo] use cpu_hal instead */
|
||||||
|
#include <xtensa/xtruntime.h> /* required for XTOS_SET_INTLEVEL. [refactor-todo] add common intr functions to esp_hw_support */
|
||||||
|
#include "xt_instr_macros.h"
|
||||||
|
#include "soc/spinlock.h"
|
||||||
|
#include "hal/cpu_hal.h"
|
||||||
|
#include "esp_private/crosscore_int.h"
|
||||||
|
#include "esp_attr.h"
|
||||||
|
#include "esp_timer.h" /* required for esp_timer_get_time. [refactor-todo] make this common between archs */
|
||||||
|
#include "esp_newlib.h" /* required for esp_reent_init() in tasks.c */
|
||||||
|
#include "esp_heap_caps.h"
|
||||||
|
#include "esp_rom_sys.h"
|
||||||
|
#include "esp_system.h" /* required by esp_get_...() functions in portable.h. [refactor-todo] Update portable.h */
|
||||||
|
#include "portbenchmark.h"
|
||||||
|
|
||||||
|
/* [refactor-todo] These includes are not directly used in this file. They are kept into to prevent a breaking change. Remove these. */
|
||||||
|
#include <limits.h>
|
||||||
|
#include <xtensa/config/system.h>
|
||||||
|
#include <xtensa/xtensa_api.h>
|
||||||
|
#include "soc/cpu.h"
|
||||||
|
#ifdef CONFIG_LEGACY_INCLUDE_COMMON_HEADERS
|
||||||
|
#include "soc/soc_memory_layout.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
extern "C" {
|
extern "C" {
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifndef __ASSEMBLER__
|
|
||||||
|
|
||||||
#include <sdkconfig.h>
|
|
||||||
#include <stdint.h>
|
|
||||||
#include <stdlib.h>
|
|
||||||
#include <stdbool.h>
|
|
||||||
#include <stdarg.h>
|
|
||||||
#include <xtensa/hal.h>
|
|
||||||
#include <xtensa/config/core.h>
|
|
||||||
#include <xtensa/config/system.h> /* required for XSHAL_CLIB */
|
|
||||||
#include <xtensa/xtruntime.h>
|
|
||||||
#include "esp_private/crosscore_int.h"
|
|
||||||
#include "esp_timer.h" /* required for FreeRTOS run time stats */
|
|
||||||
#include "esp_system.h"
|
|
||||||
#include "esp_newlib.h"
|
|
||||||
#include "soc/spinlock.h"
|
|
||||||
#include <esp_heap_caps.h>
|
|
||||||
#include "esp_rom_sys.h"
|
|
||||||
#include "sdkconfig.h"
|
|
||||||
#include "freertos/xtensa_api.h"
|
|
||||||
#include "esp_system.h"
|
|
||||||
#include "soc/cpu.h"
|
|
||||||
#include <limits.h>
|
|
||||||
|
|
||||||
#ifdef CONFIG_LEGACY_INCLUDE_COMMON_HEADERS
|
/* --------------------------------------------------- Port Types ------------------------------------------------------
|
||||||
#include "soc/soc_memory_layout.h"
|
* - Port specific types.
|
||||||
#endif
|
* - The settings in this file configure FreeRTOS correctly for the given hardware and compiler.
|
||||||
|
* - These settings should not be altered.
|
||||||
|
* - The port types must come before first as they are used further down the file
|
||||||
|
* ------------------------------------------------------------------------------------------------------------------ */
|
||||||
|
|
||||||
/*-----------------------------------------------------------
|
|
||||||
* Port specific definitions.
|
|
||||||
*
|
|
||||||
* The settings in this file configure FreeRTOS correctly for the
|
|
||||||
* given hardware and compiler.
|
|
||||||
*
|
|
||||||
* These settings should not be altered.
|
|
||||||
*-----------------------------------------------------------
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include "esp_system.h"
|
|
||||||
#include "hal/cpu_hal.h"
|
|
||||||
#include "xt_instr_macros.h"
|
|
||||||
|
|
||||||
/* Type definitions. */
|
|
||||||
#define portCHAR int8_t
|
#define portCHAR int8_t
|
||||||
#define portFLOAT float
|
#define portFLOAT float
|
||||||
#define portDOUBLE double
|
#define portDOUBLE double
|
||||||
@@ -93,60 +91,453 @@ typedef unsigned portBASE_TYPE UBaseType_t;
|
|||||||
typedef uint32_t TickType_t;
|
typedef uint32_t TickType_t;
|
||||||
#define portMAX_DELAY ( TickType_t ) 0xffffffffUL
|
#define portMAX_DELAY ( TickType_t ) 0xffffffffUL
|
||||||
#endif
|
#endif
|
||||||
/*-----------------------------------------------------------*/
|
|
||||||
|
|
||||||
// portbenchmark
|
/* Task function macros as described on the FreeRTOS.org WEB site. */
|
||||||
#include "portbenchmark.h"
|
#define portTASK_FUNCTION_PROTO( vFunction, pvParameters ) void vFunction( void *pvParameters )
|
||||||
|
#define portTASK_FUNCTION( vFunction, pvParameters ) void vFunction( void *pvParameters )
|
||||||
|
|
||||||
#include "sdkconfig.h"
|
|
||||||
#include "esp_attr.h"
|
|
||||||
#include "portmacro_priv.h"
|
|
||||||
|
|
||||||
// Cleaner solution allows nested interrupts disabling and restoring via local registers or stack.
|
|
||||||
// They can be called from interrupts too.
|
/* ----------------------------------------------- Port Configurations -------------------------------------------------
|
||||||
// WARNING: Only applies to current CPU. See notes above.
|
* - Configurations values supplied by each port
|
||||||
static inline unsigned portENTER_CRITICAL_NESTED(void) {
|
* - Required by FreeRTOS
|
||||||
|
* ------------------------------------------------------------------------------------------------------------------ */
|
||||||
|
|
||||||
|
#define portCRITICAL_NESTING_IN_TCB 0
|
||||||
|
#define portSTACK_GROWTH ( -1 )
|
||||||
|
#define portTICK_PERIOD_MS ( ( TickType_t ) 1000 / configTICK_RATE_HZ )
|
||||||
|
#define portBYTE_ALIGNMENT 4
|
||||||
|
#define portNOP() XT_NOP()
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/* ---------------------------------------------- Forward Declarations -------------------------------------------------
|
||||||
|
* - Forward declarations of all the port functions and macros need to implement the FreeRTOS porting interface
|
||||||
|
* - These must come before definition/declaration of the FreeRTOS porting interface
|
||||||
|
* ------------------------------------------------------------------------------------------------------------------ */
|
||||||
|
|
||||||
|
// --------------------- Interrupts ------------------------
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @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);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Asserts if in ISR context
|
||||||
|
*
|
||||||
|
* - Asserts on xPortInIsrContext() internally
|
||||||
|
*
|
||||||
|
* @note [refactor-todo] Check if this API is still required
|
||||||
|
* @note [refactor-todo] Check if this should be inlined
|
||||||
|
*/
|
||||||
|
void vPortAssertIfInISR(void);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @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);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Disable interrupts in a nested manner
|
||||||
|
*
|
||||||
|
* - Cleaner solution allows nested interrupts disabling and restoring via local registers or stack.
|
||||||
|
* - They can be called from interrupts too.
|
||||||
|
* - WARNING Only applies to current CPU.
|
||||||
|
* @note [refactor-todo] Define this as portSET_INTERRUPT_MASK_FROM_ISR() instead
|
||||||
|
* @return unsigned Previous interrupt state
|
||||||
|
*/
|
||||||
|
static inline unsigned __attribute__((always_inline)) portENTER_CRITICAL_NESTED(void);
|
||||||
|
|
||||||
|
/* ---------------------- Spinlocks ------------------------
|
||||||
|
* - Modifications made to critical sections to support SMP
|
||||||
|
* - See "Critical Sections & Disabling Interrupts" in docs/api-guides/freertos-smp.rst for more details
|
||||||
|
* - Remark: For the ESP32, portENTER_CRITICAL and portENTER_CRITICAL_ISR both alias vPortEnterCritical, meaning that
|
||||||
|
* either function can be called both from ISR as well as task context. This is not standard FreeRTOS
|
||||||
|
* behaviorr; please keep this in mind if you need any compatibility with other FreeRTOS implementations.
|
||||||
|
* @note [refactor-todo] Check if these comments are still true
|
||||||
|
* ------------------------------------------------------ */
|
||||||
|
|
||||||
|
typedef spinlock_t portMUX_TYPE; /**< Spinlock type used by FreeRTOS critical sections */
|
||||||
|
#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 */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Initialize a spinlock
|
||||||
|
*
|
||||||
|
* - Initializes a spinlock that is used by FreeRTOS SMP critical sections
|
||||||
|
*
|
||||||
|
* @param[in] mux Spinlock
|
||||||
|
*/
|
||||||
|
static inline void __attribute__((always_inline)) vPortCPUInitializeMutex(portMUX_TYPE *mux);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Acquire a spinlock
|
||||||
|
*
|
||||||
|
* @note [refactor-todo] check if we still need this
|
||||||
|
*
|
||||||
|
* @param[in] mux Spinlock
|
||||||
|
*/
|
||||||
|
static inline void __attribute__((always_inline)) vPortCPUAcquireMutex(portMUX_TYPE *mux);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Acquire a spinlock but with a specified timeout
|
||||||
|
*
|
||||||
|
* @note [refactor-todo] check if we still need this
|
||||||
|
* @note [refactor-todo] Check if this function should be renamed (due to bool return type)
|
||||||
|
*
|
||||||
|
* @param[in] mux Spinlock
|
||||||
|
* @param timeout
|
||||||
|
* @return true Spinlock acquired
|
||||||
|
* @return false Timed out
|
||||||
|
*/
|
||||||
|
static inline bool __attribute__((always_inline)) vPortCPUAcquireMutexTimeout(portMUX_TYPE *mux, int timeout);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Release a spinlock
|
||||||
|
*
|
||||||
|
* @note [refactor-todo] check if we still need this
|
||||||
|
*
|
||||||
|
* @param[in] mux Spinlock
|
||||||
|
*/
|
||||||
|
static inline void __attribute__((always_inline)) vPortCPUReleaseMutex(portMUX_TYPE *mux);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Wrapper for atomic compare-and-set instruction
|
||||||
|
*
|
||||||
|
* This subroutine will atomically compare *addr to 'compare'. If *addr == compare, *addr is set to *set. *set is
|
||||||
|
* updated with the previous value of *addr (either 'compare' or some other value.)
|
||||||
|
*
|
||||||
|
* @warning From the ISA docs: in some (unspecified) cases, the s32c1i instruction may return the "bitwise inverse" of
|
||||||
|
* the old mem if the mem wasn't written. This doesn't seem to happen on the ESP32 (portMUX assertions would
|
||||||
|
* fail).
|
||||||
|
*
|
||||||
|
* @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
|
||||||
|
*
|
||||||
|
* Atomic compare-and-set but the target address is placed in external RAM
|
||||||
|
*
|
||||||
|
* @note [refactor-todo] check if we still need this
|
||||||
|
*
|
||||||
|
* @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);
|
||||||
|
|
||||||
|
// ------------------ Critical Sections --------------------
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Enter a SMP critical section
|
||||||
|
*
|
||||||
|
* - Disable interrupts
|
||||||
|
* - Takes spinlock
|
||||||
|
* - Can be nested
|
||||||
|
*
|
||||||
|
* @param[in] mux Spinlock
|
||||||
|
*/
|
||||||
|
void vPortEnterCritical(portMUX_TYPE *mux);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Exit a SMP critical section
|
||||||
|
*
|
||||||
|
* - Releases spinlock
|
||||||
|
* - Reenables interrupts
|
||||||
|
* - Can be nested
|
||||||
|
*
|
||||||
|
* @param[in] mux Spinlock
|
||||||
|
*/
|
||||||
|
void vPortExitCritical(portMUX_TYPE *mux);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief FreeRTOS compliant version of enter critical
|
||||||
|
*
|
||||||
|
* - Ensures that critical section is only entered from task context
|
||||||
|
*
|
||||||
|
* @param[in] mux Spinlock
|
||||||
|
*/
|
||||||
|
static inline void __attribute__((always_inline)) vPortEnterCriticalCompliance(portMUX_TYPE *mux);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief FreeRTOS compliant version of exit critical
|
||||||
|
*
|
||||||
|
* @param[in] mux Spinlock
|
||||||
|
*/
|
||||||
|
static inline void __attribute__((always_inline)) vPortExitCriticalCompliance(portMUX_TYPE *mux);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Safe version of enter critical
|
||||||
|
*
|
||||||
|
* - This function can be used to enter a critical section from both task and ISR contexts
|
||||||
|
*
|
||||||
|
* @param[in] mux Spinlock
|
||||||
|
*/
|
||||||
|
static inline void __attribute__((always_inline)) vPortEnterCriticalSafe(portMUX_TYPE *mux);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Safe version of exit critical
|
||||||
|
*
|
||||||
|
* @param[in] mux Spinlock
|
||||||
|
*/
|
||||||
|
static inline void __attribute__((always_inline)) vPortExitCriticalSafe(portMUX_TYPE *mux);
|
||||||
|
|
||||||
|
// ---------------------- Yielding -------------------------
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Perform a solicited context switch
|
||||||
|
*
|
||||||
|
* - Defined in portasm.S
|
||||||
|
*
|
||||||
|
* @note [refactor-todo] The rest of ESP-IDF should call taskYield() instead
|
||||||
|
*/
|
||||||
|
void vPortYield( void );
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief
|
||||||
|
*
|
||||||
|
* @note [refactor-todo] Refactor this to avoid va_args
|
||||||
|
* @param argc
|
||||||
|
* @param ... Variable arguments to allow for IDF prototype without arguments, and vanilla version WITH argument
|
||||||
|
*/
|
||||||
|
void vPortEvaluateYieldFromISR(int argc, ...);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Yields the other core
|
||||||
|
*
|
||||||
|
* - Send an interrupt to another core in order to make the task running on it yield for a higher-priority task.
|
||||||
|
* - Can be used to yield current core as well
|
||||||
|
*
|
||||||
|
* @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
|
||||||
|
* @return true Core can yield
|
||||||
|
* @return false Core cannot yield
|
||||||
|
*/
|
||||||
|
static inline bool IRAM_ATTR xPortCanYield(void);
|
||||||
|
|
||||||
|
// ------------------- Hook Functions ----------------------
|
||||||
|
|
||||||
|
extern void esp_vApplicationIdleHook(void); /* Required by tasks.c */
|
||||||
|
extern void esp_vApplicationTickHook(void); /* Required by tasks.c */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Hook function called on entry to tickless idle
|
||||||
|
*
|
||||||
|
* - Implemented in pm_impl.c
|
||||||
|
*
|
||||||
|
* @param xExpectedIdleTime Expected idle time
|
||||||
|
*/
|
||||||
|
void vApplicationSleep(TickType_t xExpectedIdleTime);
|
||||||
|
|
||||||
|
// ----------------------- System --------------------------
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Get the tick rate per second
|
||||||
|
*
|
||||||
|
* @note [refactor-todo] make this inline
|
||||||
|
* @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 [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);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/* ------------------------------------------- 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 --------------------------
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @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) heap_caps_malloc(size, portTcbMemoryCaps)
|
||||||
|
#define pvPortMallocStackMem(size) heap_caps_malloc(size, portStackMemoryCaps)
|
||||||
|
|
||||||
|
// --------------------- Interrupts ------------------------
|
||||||
|
|
||||||
|
#define portEXIT_CRITICAL_NESTED(state) do { portbenchmarkINTERRUPT_RESTORE(state); XTOS_RESTORE_JUST_INTLEVEL(state); } while (0)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* - Only applies to current core
|
||||||
|
* - These cannot be nested. They should be used with a lot of care and cannot be called from interrupt level.
|
||||||
|
*
|
||||||
|
* @note [refactor-todo] replace XTOS_SET_INTLEVEL with more efficient version, if any?
|
||||||
|
*/
|
||||||
|
#define portDISABLE_INTERRUPTS() do { XTOS_SET_INTLEVEL(XCHAL_EXCM_LEVEL); portbenchmarkINTERRUPT_DISABLE(); } while (0)
|
||||||
|
#define portENABLE_INTERRUPTS() do { portbenchmarkINTERRUPT_RESTORE(0); XTOS_SET_INTLEVEL(0); } while (0)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ISR versions to enable/disable interrupts
|
||||||
|
*/
|
||||||
|
#define portSET_INTERRUPT_MASK_FROM_ISR() portENTER_CRITICAL_NESTED()
|
||||||
|
#define portCLEAR_INTERRUPT_MASK_FROM_ISR(state) portEXIT_CRITICAL_NESTED(state)
|
||||||
|
|
||||||
|
#define portASSERT_IF_IN_ISR() vPortAssertIfInISR()
|
||||||
|
|
||||||
|
// ------------------ Critical Sections --------------------
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief FreeRTOS critical section macros
|
||||||
|
*
|
||||||
|
* - Added a spinlock argument for SMP
|
||||||
|
* - Can be nested
|
||||||
|
* - Compliance versions will assert if regular critical section API is used in ISR context
|
||||||
|
* - Safe versions can be called from either contexts
|
||||||
|
*/
|
||||||
|
#ifdef CONFIG_FREERTOS_CHECK_PORT_CRITICAL_COMPLIANCE
|
||||||
|
#define portENTER_CRITICAL(mux) vPortEnterCriticalCompliance(mux)
|
||||||
|
#define portEXIT_CRITICAL(mux) vPortExitCriticalCompliance(mux)
|
||||||
|
#else
|
||||||
|
#define portENTER_CRITICAL(mux) vPortEnterCritical(mux)
|
||||||
|
#define portEXIT_CRITICAL(mux) vPortExitCritical(mux)
|
||||||
|
#endif /* CONFIG_FREERTOS_CHECK_PORT_CRITICAL_COMPLIANCE */
|
||||||
|
#define portENTER_CRITICAL_ISR(mux) vPortEnterCritical(mux)
|
||||||
|
#define portEXIT_CRITICAL_ISR(mux) vPortExitCritical(mux)
|
||||||
|
#define portENTER_CRITICAL_SAFE(mux) vPortEnterCriticalSafe(mux)
|
||||||
|
#define portEXIT_CRITICAL_SAFE(mux) vPortExitCriticalSafe(mux)
|
||||||
|
|
||||||
|
// ---------------------- Yielding -------------------------
|
||||||
|
|
||||||
|
#define portYIELD() vPortYield()
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @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
|
||||||
|
*
|
||||||
|
* @note [refactor-todo] Refactor this to avoid va_args
|
||||||
|
*/
|
||||||
|
#if defined(__cplusplus) && (__cplusplus > 201703L)
|
||||||
|
#define portYIELD_FROM_ISR(...) vPortEvaluateYieldFromISR(portGET_ARGUMENT_COUNT(__VA_ARGS__) __VA_OPT__(,) __VA_ARGS__)
|
||||||
|
#else
|
||||||
|
#define portYIELD_FROM_ISR(...) vPortEvaluateYieldFromISR(portGET_ARGUMENT_COUNT(__VA_ARGS__), ##__VA_ARGS__)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* 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() esp_crosscore_int_send_yield(xPortGetCoreID())
|
||||||
|
|
||||||
|
// ------------------- Hook Functions ----------------------
|
||||||
|
|
||||||
|
#ifndef CONFIG_FREERTOS_LEGACY_HOOKS
|
||||||
|
#define vApplicationIdleHook esp_vApplicationIdleHook
|
||||||
|
#define vApplicationTickHook esp_vApplicationTickHook
|
||||||
|
#endif /* !CONFIG_FREERTOS_LEGACY_HOOKS */
|
||||||
|
|
||||||
|
#define portSUPPRESS_TICKS_AND_SLEEP(idleTime) vApplicationSleep(idleTime)
|
||||||
|
|
||||||
|
// ------------------- Run Time Stats ----------------------
|
||||||
|
|
||||||
|
#define portCONFIGURE_TIMER_FOR_RUN_TIME_STATS()
|
||||||
|
|
||||||
|
/**
|
||||||
|
* - Fine resolution uses ccount
|
||||||
|
* - ALT is coarse and uses esp_timer
|
||||||
|
* @note [refactor-todo] Make fine and alt timers mutually exclusive
|
||||||
|
*/
|
||||||
|
#define portGET_RUN_TIME_COUNTER_VALUE() xthal_get_ccount()
|
||||||
|
#ifdef CONFIG_FREERTOS_RUN_TIME_STATS_USING_ESP_TIMER
|
||||||
|
#define portALT_GET_RUN_TIME_COUNTER_VALUE(x) do {x = (uint32_t)esp_timer_get_time();} while(0)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// -------------- Optimized Task Selection -----------------
|
||||||
|
|
||||||
|
#if configUSE_PORT_OPTIMISED_TASK_SELECTION == 1
|
||||||
|
/* Check the configuration. */
|
||||||
|
#if( configMAX_PRIORITIES > 32 )
|
||||||
|
#error configUSE_PORT_OPTIMISED_TASK_SELECTION can only be set to 1 when configMAX_PRIORITIES is less than or equal to 32. It is very rare that a system requires more than 10 to 15 different priorities as tasks that share a priority will time slice.
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* Store/clear the ready priorities in a bit map. */
|
||||||
|
#define portRECORD_READY_PRIORITY( uxPriority, uxReadyPriorities ) ( uxReadyPriorities ) |= ( 1UL << ( uxPriority ) )
|
||||||
|
#define portRESET_READY_PRIORITY( uxPriority, uxReadyPriorities ) ( uxReadyPriorities ) &= ~( 1UL << ( uxPriority ) )
|
||||||
|
#define portGET_HIGHEST_PRIORITY( uxTopPriority, uxReadyPriorities ) uxTopPriority = ( 31 - __builtin_clz( ( uxReadyPriorities ) ) )
|
||||||
|
#endif /* configUSE_PORT_OPTIMISED_TASK_SELECTION */
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/* --------------------------------------------- Inline Implementations ------------------------------------------------
|
||||||
|
* - Implementation of inline functions of the forward declares
|
||||||
|
* - Should come after forward declare and FreeRTOS Porting interface, as implementation may use both.
|
||||||
|
* - For implementation of non-inlined functions, see port.c
|
||||||
|
* ------------------------------------------------------------------------------------------------------------------ */
|
||||||
|
|
||||||
|
// --------------------- Interrupts ------------------------
|
||||||
|
|
||||||
|
static inline unsigned portENTER_CRITICAL_NESTED(void)
|
||||||
|
{
|
||||||
unsigned state = XTOS_SET_INTLEVEL(XCHAL_EXCM_LEVEL);
|
unsigned state = XTOS_SET_INTLEVEL(XCHAL_EXCM_LEVEL);
|
||||||
portbenchmarkINTERRUPT_DISABLE();
|
portbenchmarkINTERRUPT_DISABLE();
|
||||||
return state;
|
return state;
|
||||||
}
|
}
|
||||||
#define portEXIT_CRITICAL_NESTED(state) do { portbenchmarkINTERRUPT_RESTORE(state); XTOS_RESTORE_JUST_INTLEVEL(state); } while (0)
|
|
||||||
|
|
||||||
/*
|
// ---------------------- Spinlocks ------------------------
|
||||||
Modifications to portENTER_CRITICAL.
|
|
||||||
|
|
||||||
For an introduction, see "Critical Sections & Disabling Interrupts" in docs/api-guides/freertos-smp.rst
|
|
||||||
|
|
||||||
The original portENTER_CRITICAL only disabled the ISRs. This is enough for single-CPU operation: by
|
|
||||||
disabling the interrupts, there is no task switch so no other tasks can meddle in the data, and because
|
|
||||||
interrupts are disabled, ISRs can't corrupt data structures either.
|
|
||||||
|
|
||||||
For multiprocessing, things get a bit more hairy. First of all, disabling the interrupts doesn't stop
|
|
||||||
the tasks or ISRs on the other processors meddling with our CPU. For tasks, this is solved by adding
|
|
||||||
a spinlock to the portENTER_CRITICAL macro. A task running on the other CPU accessing the same data will
|
|
||||||
spinlock in the portENTER_CRITICAL code until the first CPU is done.
|
|
||||||
|
|
||||||
For ISRs, we now also need muxes: while portENTER_CRITICAL disabling interrupts will stop ISRs on the same
|
|
||||||
CPU from meddling with the data, it does not stop interrupts on the other cores from interfering with the
|
|
||||||
data. For this, we also use a spinlock in the routines called by the ISR, but these spinlocks
|
|
||||||
do not disable the interrupts (because they already are).
|
|
||||||
|
|
||||||
This all assumes that interrupts are either entirely disabled or enabled. Interrupt priority levels
|
|
||||||
will break this scheme.
|
|
||||||
|
|
||||||
Remark: For the ESP32, portENTER_CRITICAL and portENTER_CRITICAL_ISR both alias vPortEnterCritical, meaning
|
|
||||||
that either function can be called both from ISR as well as task context. This is not standard FreeRTOS
|
|
||||||
behaviour; please keep this in mind if you need any compatibility with other FreeRTOS implementations.
|
|
||||||
*/
|
|
||||||
/* "mux" data structure (spinlock) */
|
|
||||||
typedef spinlock_t portMUX_TYPE;
|
|
||||||
|
|
||||||
#define portMUX_FREE_VAL SPINLOCK_FREE
|
|
||||||
#define portMUX_NO_TIMEOUT SPINLOCK_WAIT_FOREVER /* When passed for 'timeout_cycles', spin forever if necessary */
|
|
||||||
#define portMUX_TRY_LOCK SPINLOCK_NO_WAIT /* Try to acquire the spinlock a single time only */
|
|
||||||
#define portMUX_INITIALIZER_UNLOCKED SPINLOCK_INITIALIZER
|
|
||||||
|
|
||||||
#define portCRITICAL_NESTING_IN_TCB 0
|
|
||||||
|
|
||||||
static inline void __attribute__((always_inline)) vPortCPUInitializeMutex(portMUX_TYPE *mux)
|
static inline void __attribute__((always_inline)) vPortCPUInitializeMutex(portMUX_TYPE *mux)
|
||||||
{
|
{
|
||||||
@@ -168,17 +559,19 @@ static inline void __attribute__((always_inline)) vPortCPUReleaseMutex(portMUX_T
|
|||||||
spinlock_release(mux);
|
spinlock_release(mux);
|
||||||
}
|
}
|
||||||
|
|
||||||
void vPortEnterCritical(portMUX_TYPE *mux);
|
static inline void __attribute__((always_inline)) uxPortCompareSet(volatile uint32_t *addr, uint32_t compare, uint32_t *set)
|
||||||
void vPortExitCritical(portMUX_TYPE *mux);
|
{
|
||||||
|
compare_and_set_native(addr, compare, set);
|
||||||
|
}
|
||||||
|
|
||||||
#define portASSERT_IF_IN_ISR() vPortAssertIfInISR()
|
static inline void uxPortCompareSetExtram(volatile uint32_t *addr, uint32_t compare, uint32_t *set)
|
||||||
void vPortAssertIfInISR(void);
|
{
|
||||||
|
#ifdef CONFIG_SPIRAM
|
||||||
|
compare_and_set_extram(addr, compare, set);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
// ------------------ Critical Sections --------------------
|
||||||
* Returns true if the current core is in ISR context; low prio ISR, med prio ISR or timer tick ISR. High prio ISRs
|
|
||||||
* aren't detected here, but they normally cannot call C code, so that should not be an issue anyway.
|
|
||||||
*/
|
|
||||||
BaseType_t xPortInIsrContext(void);
|
|
||||||
|
|
||||||
static inline void __attribute__((always_inline)) vPortEnterCriticalCompliance(portMUX_TYPE *mux)
|
static inline void __attribute__((always_inline)) vPortEnterCriticalCompliance(portMUX_TYPE *mux)
|
||||||
{
|
{
|
||||||
@@ -202,20 +595,6 @@ static inline void __attribute__((always_inline)) vPortExitCriticalCompliance(po
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef CONFIG_FREERTOS_CHECK_PORT_CRITICAL_COMPLIANCE
|
|
||||||
/* Calling port*_CRITICAL from ISR context would cause an assert failure.
|
|
||||||
* If the parent function is called from both ISR and Non-ISR context then call port*_CRITICAL_SAFE
|
|
||||||
*/
|
|
||||||
#define portENTER_CRITICAL(mux) vPortEnterCriticalCompliance(mux)
|
|
||||||
#define portEXIT_CRITICAL(mux) vPortExitCriticalCompliance(mux)
|
|
||||||
#else
|
|
||||||
#define portENTER_CRITICAL(mux) vPortEnterCritical(mux)
|
|
||||||
#define portEXIT_CRITICAL(mux) vPortExitCritical(mux)
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#define portENTER_CRITICAL_ISR(mux) vPortEnterCritical(mux)
|
|
||||||
#define portEXIT_CRITICAL_ISR(mux) vPortExitCritical(mux)
|
|
||||||
|
|
||||||
static inline void __attribute__((always_inline)) vPortEnterCriticalSafe(portMUX_TYPE *mux)
|
static inline void __attribute__((always_inline)) vPortEnterCriticalSafe(portMUX_TYPE *mux)
|
||||||
{
|
{
|
||||||
if (xPortInIsrContext()) {
|
if (xPortInIsrContext()) {
|
||||||
@@ -234,80 +613,82 @@ static inline void __attribute__((always_inline)) vPortExitCriticalSafe(portMUX_
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#define portENTER_CRITICAL_SAFE(mux) vPortEnterCriticalSafe(mux)
|
// ---------------------- Yielding -------------------------
|
||||||
#define portEXIT_CRITICAL_SAFE(mux) vPortExitCriticalSafe(mux)
|
|
||||||
|
static inline bool IRAM_ATTR xPortCanYield(void)
|
||||||
|
{
|
||||||
|
uint32_t ps_reg = 0;
|
||||||
|
|
||||||
|
//Get the current value of PS (processor status) register
|
||||||
|
RSR(PS, ps_reg);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Wrapper for the Xtensa compare-and-set instruction. This subroutine will atomically compare
|
* intlevel = (ps_reg & 0xf);
|
||||||
* *addr to 'compare'. If *addr == compare, *addr is set to *set. *set is updated with the previous
|
* excm = (ps_reg >> 4) & 0x1;
|
||||||
* value of *addr (either 'compare' or some other value.)
|
* CINTLEVEL is max(excm * EXCMLEVEL, INTLEVEL), where EXCMLEVEL is 3.
|
||||||
*
|
* However, just return true, only intlevel is zero.
|
||||||
* Warning: From the ISA docs: in some (unspecified) cases, the s32c1i instruction may return the
|
|
||||||
* *bitwise inverse* of the old mem if the mem wasn't written. This doesn't seem to happen on the
|
|
||||||
* ESP32 (portMUX assertions would fail).
|
|
||||||
*/
|
*/
|
||||||
static inline void __attribute__((always_inline)) uxPortCompareSet(volatile uint32_t *addr, uint32_t compare, uint32_t *set) {
|
|
||||||
compare_and_set_native(addr, compare, set);
|
return ((ps_reg & PS_INTLEVEL_MASK) == 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Critical section management. NW-TODO: replace XTOS_SET_INTLEVEL with more efficient version, if any?
|
// ----------------------- System --------------------------
|
||||||
// These cannot be nested. They should be used with a lot of care and cannot be called from interrupt level.
|
|
||||||
//
|
|
||||||
// Only applies to one CPU. See notes above & below for reasons not to use these.
|
|
||||||
#define portDISABLE_INTERRUPTS() do { XTOS_SET_INTLEVEL(XCHAL_EXCM_LEVEL); portbenchmarkINTERRUPT_DISABLE(); } while (0)
|
|
||||||
#define portENABLE_INTERRUPTS() do { portbenchmarkINTERRUPT_RESTORE(0); XTOS_SET_INTLEVEL(0); } while (0)
|
|
||||||
|
|
||||||
|
static inline BaseType_t IRAM_ATTR xPortGetCoreID(void)
|
||||||
// These FreeRTOS versions are similar to the nested versions above
|
|
||||||
#define portSET_INTERRUPT_MASK_FROM_ISR() portENTER_CRITICAL_NESTED()
|
|
||||||
#define portCLEAR_INTERRUPT_MASK_FROM_ISR(state) portEXIT_CRITICAL_NESTED(state)
|
|
||||||
|
|
||||||
//Because the ROM routines don't necessarily handle a stack in external RAM correctly, we force
|
|
||||||
//the stack memory to always be internal.
|
|
||||||
#define portTcbMemoryCaps (MALLOC_CAP_INTERNAL|MALLOC_CAP_8BIT)
|
|
||||||
#define portStackMemoryCaps (MALLOC_CAP_INTERNAL|MALLOC_CAP_8BIT)
|
|
||||||
#define pvPortMallocTcbMem(size) heap_caps_malloc(size, portTcbMemoryCaps)
|
|
||||||
#define pvPortMallocStackMem(size) heap_caps_malloc(size, portStackMemoryCaps)
|
|
||||||
|
|
||||||
//xTaskCreateStatic uses these functions to check incoming memory.
|
|
||||||
#define portVALID_TCB_MEM(ptr) (esp_ptr_internal(ptr) && esp_ptr_byte_accessible(ptr))
|
|
||||||
#ifdef CONFIG_SPIRAM_ALLOW_STACK_EXTERNAL_MEMORY
|
|
||||||
#define portVALID_STACK_MEM(ptr) esp_ptr_byte_accessible(ptr)
|
|
||||||
#else
|
|
||||||
#define portVALID_STACK_MEM(ptr) (esp_ptr_internal(ptr) && esp_ptr_byte_accessible(ptr))
|
|
||||||
#endif
|
|
||||||
|
|
||||||
|
|
||||||
static inline void uxPortCompareSetExtram(volatile uint32_t *addr, uint32_t compare, uint32_t *set)
|
|
||||||
{
|
{
|
||||||
#ifdef CONFIG_SPIRAM
|
return cpu_hal_get_core_id();
|
||||||
compare_and_set_extram(addr, compare, set);
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/*-----------------------------------------------------------*/
|
|
||||||
|
|
||||||
/* Architecture specifics. */
|
/* ------------------------------------------------------ Misc ---------------------------------------------------------
|
||||||
#define portSTACK_GROWTH ( -1 )
|
* - Miscellaneous porting macros
|
||||||
#define portTICK_PERIOD_MS ( ( TickType_t ) 1000 / configTICK_RATE_HZ )
|
* - These are not port of the FreeRTOS porting interface, but are used by other FreeRTOS dependent components
|
||||||
#define portBYTE_ALIGNMENT 4
|
* - [refactor-todo] Remove dependency on MPU wrappers by modifying TCB
|
||||||
#define portNOP() XT_NOP()
|
* ------------------------------------------------------------------------------------------------------------------ */
|
||||||
/*-----------------------------------------------------------*/
|
|
||||||
|
|
||||||
/* Fine resolution time */
|
// -------------------- Co-Processor -----------------------
|
||||||
#define portGET_RUN_TIME_COUNTER_VALUE() xthal_get_ccount()
|
|
||||||
//ccount or esp_timer are initialized elsewhere
|
|
||||||
#define portCONFIGURE_TIMER_FOR_RUN_TIME_STATS()
|
|
||||||
|
|
||||||
#ifdef CONFIG_FREERTOS_RUN_TIME_STATS_USING_ESP_TIMER
|
// When coprocessors are defined, we maintain a pointer to coprocessors area.
|
||||||
/* Coarse resolution time (us) */
|
// We currently use a hack: redefine field xMPU_SETTINGS in TCB block as a structure that can hold:
|
||||||
#define portALT_GET_RUN_TIME_COUNTER_VALUE(x) do {x = (uint32_t)esp_timer_get_time();} while(0)
|
// MPU wrappers, coprocessor area pointer, trace code structure, and more if needed.
|
||||||
|
// The field is normally used for memory protection. FreeRTOS should create another general purpose field.
|
||||||
|
typedef struct {
|
||||||
|
#if XCHAL_CP_NUM > 0
|
||||||
|
volatile StackType_t *coproc_area; // Pointer to coprocessor save area; MUST BE FIRST
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
void vPortYield( void );
|
#if portUSING_MPU_WRAPPERS
|
||||||
void vPortEvaluateYieldFromISR(int argc, ...);
|
// Define here mpu_settings, which is port dependent
|
||||||
void _frxt_setup_switch( void );
|
int mpu_setting; // Just a dummy example here; MPU not ported to Xtensa yet
|
||||||
|
#endif
|
||||||
|
} xMPU_SETTINGS;
|
||||||
|
|
||||||
|
// Main hack to use MPU_wrappers even when no MPU is defined (warning: mpu_setting should not be accessed; otherwise move this above xMPU_SETTINGS)
|
||||||
|
#if (XCHAL_CP_NUM > 0) && !portUSING_MPU_WRAPPERS // If MPU wrappers not used, we still need to allocate coproc area
|
||||||
|
#undef portUSING_MPU_WRAPPERS
|
||||||
|
#define portUSING_MPU_WRAPPERS 1 // Enable it to allocate coproc area
|
||||||
|
#define MPU_WRAPPERS_H // Override mpu_wrapper.h to disable unwanted code
|
||||||
|
#define PRIVILEGED_FUNCTION
|
||||||
|
#define PRIVILEGED_DATA
|
||||||
|
#endif
|
||||||
|
|
||||||
|
void _xt_coproc_release(volatile void *coproc_sa_base);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The structures and methods of manipulating the MPU are contained within the
|
||||||
|
* port layer.
|
||||||
|
*
|
||||||
|
* Fills the xMPUSettings structure with the memory region information
|
||||||
|
* contained in xRegions.
|
||||||
|
*/
|
||||||
|
#if( portUSING_MPU_WRAPPERS == 1 )
|
||||||
|
struct xMEMORY_REGION;
|
||||||
|
void vPortStoreTaskMPUSettings( xMPU_SETTINGS *xMPUSettings, const struct xMEMORY_REGION *const xRegions, StackType_t *pxBottomOfStack, uint32_t usStackDepth ) PRIVILEGED_FUNCTION;
|
||||||
|
void vPortReleaseTaskMPUSettings( xMPU_SETTINGS *xMPUSettings );
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// -------------------- VA_ARGS Yield ----------------------
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Macro to count number of arguments of a __VA_ARGS__ used to support portYIELD_FROM_ISR with,
|
* Macro to count number of arguments of a __VA_ARGS__ used to support portYIELD_FROM_ISR with,
|
||||||
@@ -329,177 +710,37 @@ void _frxt_setup_switch( void );
|
|||||||
_Static_assert(portGET_ARGUMENT_COUNT() == 0, "portGET_ARGUMENT_COUNT() result does not match for 0 arguments");
|
_Static_assert(portGET_ARGUMENT_COUNT() == 0, "portGET_ARGUMENT_COUNT() result does not match for 0 arguments");
|
||||||
_Static_assert(portGET_ARGUMENT_COUNT(1) == 1, "portGET_ARGUMENT_COUNT() result does not match for 1 argument");
|
_Static_assert(portGET_ARGUMENT_COUNT(1) == 1, "portGET_ARGUMENT_COUNT() result does not match for 1 argument");
|
||||||
|
|
||||||
#define portYIELD() vPortYield()
|
// -------------------- Heap Related -----------------------
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @note The macro below could be used when passing a single argument, or without any argument,
|
* @brief Checks if a given piece of memory can be used to store a task's TCB
|
||||||
* it was developed to support both usages of portYIELD inside of an ISR. Any other usage form
|
|
||||||
* might result in undesired behaviour
|
|
||||||
*/
|
|
||||||
#if defined(__cplusplus) && (__cplusplus > 201703L)
|
|
||||||
#define portYIELD_FROM_ISR(...) vPortEvaluateYieldFromISR(portGET_ARGUMENT_COUNT(__VA_ARGS__) __VA_OPT__(,) __VA_ARGS__)
|
|
||||||
#else
|
|
||||||
#define portYIELD_FROM_ISR(...) vPortEvaluateYieldFromISR(portGET_ARGUMENT_COUNT(__VA_ARGS__), ##__VA_ARGS__)
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/* 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() esp_crosscore_int_send_yield(xPortGetCoreID())
|
|
||||||
|
|
||||||
/*-----------------------------------------------------------*/
|
|
||||||
|
|
||||||
/* Task function macros as described on the FreeRTOS.org WEB site. */
|
|
||||||
#define portTASK_FUNCTION_PROTO( vFunction, pvParameters ) void vFunction( void *pvParameters )
|
|
||||||
#define portTASK_FUNCTION( vFunction, pvParameters ) void vFunction( void *pvParameters )
|
|
||||||
|
|
||||||
// When coprocessors are defined, we to maintain a pointer to coprocessors area.
|
|
||||||
// We currently use a hack: redefine field xMPU_SETTINGS in TCB block as a structure that can hold:
|
|
||||||
// MPU wrappers, coprocessor area pointer, trace code structure, and more if needed.
|
|
||||||
// The field is normally used for memory protection. FreeRTOS should create another general purpose field.
|
|
||||||
typedef struct {
|
|
||||||
#if XCHAL_CP_NUM > 0
|
|
||||||
volatile StackType_t* coproc_area; // Pointer to coprocessor save area; MUST BE FIRST
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if portUSING_MPU_WRAPPERS
|
|
||||||
// Define here mpu_settings, which is port dependent
|
|
||||||
int mpu_setting; // Just a dummy example here; MPU not ported to Xtensa yet
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if configUSE_TRACE_FACILITY_2
|
|
||||||
struct {
|
|
||||||
// Cf. porttraceStamp()
|
|
||||||
int taskstamp; /* Stamp from inside task to see where we are */
|
|
||||||
int taskstampcount; /* A counter usually incremented when we restart the task's loop */
|
|
||||||
} porttrace;
|
|
||||||
#endif
|
|
||||||
} xMPU_SETTINGS;
|
|
||||||
|
|
||||||
// Main hack to use MPU_wrappers even when no MPU is defined (warning: mpu_setting should not be accessed; otherwise move this above xMPU_SETTINGS)
|
|
||||||
#if (XCHAL_CP_NUM > 0 || configUSE_TRACE_FACILITY_2) && !portUSING_MPU_WRAPPERS // If MPU wrappers not used, we still need to allocate coproc area
|
|
||||||
#undef portUSING_MPU_WRAPPERS
|
|
||||||
#define portUSING_MPU_WRAPPERS 1 // Enable it to allocate coproc area
|
|
||||||
#define MPU_WRAPPERS_H // Override mpu_wrapper.h to disable unwanted code
|
|
||||||
#define PRIVILEGED_FUNCTION
|
|
||||||
#define PRIVILEGED_DATA
|
|
||||||
#endif
|
|
||||||
|
|
||||||
extern void esp_vApplicationIdleHook( void );
|
|
||||||
extern void esp_vApplicationTickHook( void );
|
|
||||||
|
|
||||||
#ifndef CONFIG_FREERTOS_LEGACY_HOOKS
|
|
||||||
#define vApplicationIdleHook esp_vApplicationIdleHook
|
|
||||||
#define vApplicationTickHook esp_vApplicationTickHook
|
|
||||||
#endif /* !CONFIG_FREERTOS_LEGACY_HOOKS */
|
|
||||||
|
|
||||||
void vApplicationSleep( TickType_t xExpectedIdleTime );
|
|
||||||
|
|
||||||
#define portSUPPRESS_TICKS_AND_SLEEP( idleTime ) vApplicationSleep( idleTime )
|
|
||||||
|
|
||||||
void _xt_coproc_release(volatile void * coproc_sa_base);
|
|
||||||
|
|
||||||
/* Architecture specific optimisations. */
|
|
||||||
#if configUSE_PORT_OPTIMISED_TASK_SELECTION == 1
|
|
||||||
|
|
||||||
/* Check the configuration. */
|
|
||||||
#if( configMAX_PRIORITIES > 32 )
|
|
||||||
#error configUSE_PORT_OPTIMISED_TASK_SELECTION can only be set to 1 when configMAX_PRIORITIES is less than or equal to 32. It is very rare that a system requires more than 10 to 15 different priorities as tasks that share a priority will time slice.
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/* Store/clear the ready priorities in a bit map. */
|
|
||||||
#define portRECORD_READY_PRIORITY( uxPriority, uxReadyPriorities ) ( uxReadyPriorities ) |= ( 1UL << ( uxPriority ) )
|
|
||||||
#define portRESET_READY_PRIORITY( uxPriority, uxReadyPriorities ) ( uxReadyPriorities ) &= ~( 1UL << ( uxPriority ) )
|
|
||||||
|
|
||||||
/*-----------------------------------------------------------*/
|
|
||||||
|
|
||||||
#define portGET_HIGHEST_PRIORITY( uxTopPriority, uxReadyPriorities ) uxTopPriority = ( 31 - __builtin_clz( ( uxReadyPriorities ) ) )
|
|
||||||
|
|
||||||
#endif /* configUSE_PORT_OPTIMISED_TASK_SELECTION */
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Send an interrupt to another core in order to make the task running
|
|
||||||
* on it yield for a higher-priority task.
|
|
||||||
*/
|
|
||||||
|
|
||||||
void vPortYieldOtherCore( BaseType_t coreid) ;
|
|
||||||
|
|
||||||
/*
|
|
||||||
Callback to set a watchpoint on the end of the stack. Called every context switch to change the stack
|
|
||||||
watchpoint around.
|
|
||||||
*/
|
|
||||||
void vPortSetStackWatchpoint( void* pxStackStart );
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Returns true if the current core is in ISR context; low prio ISR, med prio ISR or timer tick ISR. High prio ISRs
|
|
||||||
* aren't detected here, but they normally cannot call C code, so that should not be an issue anyway.
|
|
||||||
*/
|
|
||||||
BaseType_t xPortInIsrContext(void);
|
|
||||||
|
|
||||||
/*
|
|
||||||
* This function will be called in High prio ISRs. Returns true if the current core was in ISR context
|
|
||||||
* before calling into high prio ISR context.
|
|
||||||
*/
|
|
||||||
BaseType_t xPortInterruptedFromISRContext(void);
|
|
||||||
|
|
||||||
/*
|
|
||||||
* The structures and methods of manipulating the MPU are contained within the
|
|
||||||
* port layer.
|
|
||||||
*
|
*
|
||||||
* Fills the xMPUSettings structure with the memory region information
|
* - Defined in port_common.c
|
||||||
* contained in xRegions.
|
*
|
||||||
|
* @param ptr Pointer to memory
|
||||||
|
* @return true Memory can be used to store a TCB
|
||||||
|
* @return false Otherwise
|
||||||
*/
|
*/
|
||||||
#if( portUSING_MPU_WRAPPERS == 1 )
|
bool xPortCheckValidTCBMem(const void *ptr);
|
||||||
struct xMEMORY_REGION;
|
|
||||||
void vPortStoreTaskMPUSettings( xMPU_SETTINGS *xMPUSettings, const struct xMEMORY_REGION * const xRegions, StackType_t *pxBottomOfStack, uint32_t usStackDepth ) PRIVILEGED_FUNCTION;
|
|
||||||
void vPortReleaseTaskMPUSettings( xMPU_SETTINGS *xMPUSettings );
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/* Multi-core: get current core ID */
|
/**
|
||||||
static inline BaseType_t IRAM_ATTR xPortGetCoreID(void) {
|
* @brief Checks if a given piece of memory can be used to store a task's stack
|
||||||
return cpu_hal_get_core_id();
|
*
|
||||||
}
|
* - Defined in port_common.c
|
||||||
|
*
|
||||||
/* Get tick rate per second */
|
* @param ptr Pointer to memory
|
||||||
uint32_t xPortGetTickRateHz(void);
|
* @return true Memory can be used to store a task stack
|
||||||
|
* @return false Otherwise
|
||||||
static inline bool IRAM_ATTR xPortCanYield(void)
|
|
||||||
{
|
|
||||||
uint32_t ps_reg = 0;
|
|
||||||
|
|
||||||
//Get the current value of PS (processor status) register
|
|
||||||
RSR(PS, ps_reg);
|
|
||||||
|
|
||||||
/*
|
|
||||||
* intlevel = (ps_reg & 0xf);
|
|
||||||
* excm = (ps_reg >> 4) & 0x1;
|
|
||||||
* CINTLEVEL is max(excm * EXCMLEVEL, INTLEVEL), where EXCMLEVEL is 3.
|
|
||||||
* However, just return true, only intlevel is zero.
|
|
||||||
*/
|
*/
|
||||||
|
bool xPortcheckValidStackMem(const void *ptr);
|
||||||
|
|
||||||
return ((ps_reg & PS_INTLEVEL_MASK) == 0);
|
#define portVALID_TCB_MEM(ptr) xPortCheckValidTCBMem(ptr)
|
||||||
}
|
#define portVALID_STACK_MEM(ptr) xPortcheckValidStackMem(ptr)
|
||||||
|
|
||||||
// porttrace
|
|
||||||
#if configUSE_TRACE_FACILITY_2
|
|
||||||
#include "porttrace.h"
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// configASSERT_2 if requested
|
|
||||||
#if configASSERT_2
|
|
||||||
#include <stdio.h>
|
|
||||||
void exit(int);
|
|
||||||
#define configASSERT( x ) if (!(x)) { porttracePrint(-1); printf("\nAssertion failed in %s:%d\n", __FILE__, __LINE__); exit(-1); }
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#endif // __ASSEMBLER__
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#endif // __ASSEMBLER__
|
||||||
|
|
||||||
#endif /* PORTMACRO_H */
|
#endif /* PORTMACRO_H */
|
||||||
|
@@ -1,78 +0,0 @@
|
|||||||
/*
|
|
||||||
FreeRTOS V8.2.0 - Copyright (C) 2015 Real Time Engineers Ltd.
|
|
||||||
All rights reserved
|
|
||||||
|
|
||||||
VISIT http://www.FreeRTOS.org TO ENSURE YOU ARE USING THE LATEST VERSION.
|
|
||||||
|
|
||||||
***************************************************************************
|
|
||||||
* *
|
|
||||||
* FreeRTOS provides completely free yet professionally developed, *
|
|
||||||
* robust, strictly quality controlled, supported, and cross *
|
|
||||||
* platform software that has become a de facto standard. *
|
|
||||||
* *
|
|
||||||
* Help yourself get started quickly and support the FreeRTOS *
|
|
||||||
* project by purchasing a FreeRTOS tutorial book, reference *
|
|
||||||
* manual, or both from: http://www.FreeRTOS.org/Documentation *
|
|
||||||
* *
|
|
||||||
* Thank you! *
|
|
||||||
* *
|
|
||||||
***************************************************************************
|
|
||||||
|
|
||||||
This file is part of the FreeRTOS distribution.
|
|
||||||
|
|
||||||
FreeRTOS is free software; you can redistribute it and/or modify it under
|
|
||||||
the terms of the GNU General Public License (version 2) as published by the
|
|
||||||
Free Software Foundation >>!AND MODIFIED BY!<< the FreeRTOS exception.
|
|
||||||
|
|
||||||
>>! NOTE: The modification to the GPL is included to allow you to !<<
|
|
||||||
>>! distribute a combined work that includes FreeRTOS without being !<<
|
|
||||||
>>! obliged to provide the source code for proprietary components !<<
|
|
||||||
>>! outside of the FreeRTOS kernel. !<<
|
|
||||||
|
|
||||||
FreeRTOS is distributed in the hope that it will be useful, but WITHOUT ANY
|
|
||||||
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
|
||||||
FOR A PARTICULAR PURPOSE. Full license text is available from the following
|
|
||||||
link: http://www.freertos.org/a00114.html
|
|
||||||
|
|
||||||
1 tab == 4 spaces!
|
|
||||||
|
|
||||||
***************************************************************************
|
|
||||||
* *
|
|
||||||
* Having a problem? Start by reading the FAQ "My application does *
|
|
||||||
* not run, what could be wrong?" *
|
|
||||||
* *
|
|
||||||
* http://www.FreeRTOS.org/FAQHelp.html *
|
|
||||||
* *
|
|
||||||
***************************************************************************
|
|
||||||
|
|
||||||
http://www.FreeRTOS.org - Documentation, books, training, latest versions,
|
|
||||||
license and Real Time Engineers Ltd. contact details.
|
|
||||||
|
|
||||||
http://www.FreeRTOS.org/plus - A selection of FreeRTOS ecosystem products,
|
|
||||||
including FreeRTOS+Trace - an indispensable productivity tool, a DOS
|
|
||||||
compatible FAT file system, and our tiny thread aware UDP/IP stack.
|
|
||||||
|
|
||||||
http://www.OpenRTOS.com - Real Time Engineers ltd license FreeRTOS to High
|
|
||||||
Integrity Systems to sell under the OpenRTOS brand. Low cost OpenRTOS
|
|
||||||
licenses offer ticketed support, indemnification and middleware.
|
|
||||||
|
|
||||||
http://www.SafeRTOS.com - High Integrity Systems also provide a safety
|
|
||||||
engineered and independently SIL3 certified version for use in safety and
|
|
||||||
mission critical applications that require provable dependability.
|
|
||||||
|
|
||||||
1 tab == 4 spaces!
|
|
||||||
*/
|
|
||||||
|
|
||||||
|
|
||||||
/* This header holds the macros for porting which should only be used inside FreeRTOS */
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
#include "soc/soc_memory_layout.h"
|
|
||||||
|
|
||||||
//xTaskCreateStatic uses these functions to check incoming memory.
|
|
||||||
#define portVALID_TCB_MEM(ptr) (esp_ptr_internal(ptr) && esp_ptr_byte_accessible(ptr))
|
|
||||||
#ifdef CONFIG_SPIRAM_ALLOW_STACK_EXTERNAL_MEMORY
|
|
||||||
#define portVALID_STACK_MEM(ptr) esp_ptr_byte_accessible(ptr)
|
|
||||||
#else
|
|
||||||
#define portVALID_STACK_MEM(ptr) (esp_ptr_internal(ptr) && esp_ptr_byte_accessible(ptr))
|
|
||||||
#endif
|
|
@@ -1,153 +1,124 @@
|
|||||||
/*
|
/*
|
||||||
FreeRTOS V8.2.0 - Copyright (C) 2015 Real Time Engineers Ltd.
|
* FreeRTOS Kernel V10.4.3
|
||||||
All rights reserved
|
* Copyright (C) 2017 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
||||||
|
*
|
||||||
VISIT http://www.FreeRTOS.org TO ENSURE YOU ARE USING THE LATEST VERSION.
|
* Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||||
|
* this software and associated documentation files (the "Software"), to deal in
|
||||||
This file is part of the FreeRTOS distribution.
|
* the Software without restriction, including without limitation the rights to
|
||||||
|
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
||||||
FreeRTOS is free software; you can redistribute it and/or modify it under
|
* the Software, and to permit persons to whom the Software is furnished to do so,
|
||||||
the terms of the GNU General Public License (version 2) as published by the
|
* subject to the following conditions:
|
||||||
Free Software Foundation >>!AND MODIFIED BY!<< the FreeRTOS exception.
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in all
|
||||||
***************************************************************************
|
* copies or substantial portions of the Software. If you wish to use our Amazon
|
||||||
>>! NOTE: The modification to the GPL is included to allow you to !<<
|
* FreeRTOS name, please do so in a fair use way that does not cause confusion.
|
||||||
>>! distribute a combined work that includes FreeRTOS without being !<<
|
*
|
||||||
>>! obliged to provide the source code for proprietary components !<<
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
>>! outside of the FreeRTOS kernel. !<<
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||||
***************************************************************************
|
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
||||||
|
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
||||||
FreeRTOS is distributed in the hope that it will be useful, but WITHOUT ANY
|
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||||
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
FOR A PARTICULAR PURPOSE. Full license text is available on the following
|
*
|
||||||
link: http://www.freertos.org/a00114.html
|
* https://www.FreeRTOS.org
|
||||||
|
* https://github.com/FreeRTOS
|
||||||
***************************************************************************
|
*
|
||||||
* *
|
* 1 tab == 4 spaces!
|
||||||
* FreeRTOS provides completely free yet professionally developed, *
|
|
||||||
* robust, strictly quality controlled, supported, and cross *
|
|
||||||
* platform software that is more than just the market leader, it *
|
|
||||||
* is the industry's de facto standard. *
|
|
||||||
* *
|
|
||||||
* Help yourself get started quickly while simultaneously helping *
|
|
||||||
* to support the FreeRTOS project by purchasing a FreeRTOS *
|
|
||||||
* tutorial book, reference manual, or both: *
|
|
||||||
* http://www.FreeRTOS.org/Documentation *
|
|
||||||
* *
|
|
||||||
***************************************************************************
|
|
||||||
|
|
||||||
http://www.FreeRTOS.org/FAQHelp.html - Having a problem? Start by reading
|
|
||||||
the FAQ page "My application does not run, what could be wrong?". Have you
|
|
||||||
defined configASSERT()?
|
|
||||||
|
|
||||||
http://www.FreeRTOS.org/support - In return for receiving this top quality
|
|
||||||
embedded software for free we request you assist our global community by
|
|
||||||
participating in the support forum.
|
|
||||||
|
|
||||||
http://www.FreeRTOS.org/training - Investing in training allows your team to
|
|
||||||
be as productive as possible as early as possible. Now you can receive
|
|
||||||
FreeRTOS training directly from Richard Barry, CEO of Real Time Engineers
|
|
||||||
Ltd, and the world's leading authority on the world's leading RTOS.
|
|
||||||
|
|
||||||
http://www.FreeRTOS.org/plus - A selection of FreeRTOS ecosystem products,
|
|
||||||
including FreeRTOS+Trace - an indispensable productivity tool, a DOS
|
|
||||||
compatible FAT file system, and our tiny thread aware UDP/IP stack.
|
|
||||||
|
|
||||||
http://www.FreeRTOS.org/labs - Where new FreeRTOS products go to incubate.
|
|
||||||
Come and try FreeRTOS+TCP, our new open source TCP/IP stack for FreeRTOS.
|
|
||||||
|
|
||||||
http://www.OpenRTOS.com - Real Time Engineers ltd. license FreeRTOS to High
|
|
||||||
Integrity Systems ltd. to sell under the OpenRTOS brand. Low cost OpenRTOS
|
|
||||||
licenses offer ticketed support, indemnification and commercial middleware.
|
|
||||||
|
|
||||||
http://www.SafeRTOS.com - High Integrity Systems also provide a safety
|
|
||||||
engineered and independently SIL3 certified version for use in safety and
|
|
||||||
mission critical applications that require provable dependability.
|
|
||||||
|
|
||||||
1 tab == 4 spaces!
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/*******************************************************************************
|
/*
|
||||||
// Copyright (c) 2003-2015 Cadence Design Systems, Inc.
|
* Copyright (c) 2015-2019 Cadence Design Systems, Inc.
|
||||||
//
|
*
|
||||||
// Permission is hereby granted, free of charge, to any person obtaining
|
* Permission is hereby granted, free of charge, to any person obtaining
|
||||||
// a copy of this software and associated documentation files (the
|
* a copy of this software and associated documentation files (the
|
||||||
// "Software"), to deal in the Software without restriction, including
|
* "Software"), to deal in the Software without restriction, including
|
||||||
// without limitation the rights to use, copy, modify, merge, publish,
|
* without limitation the rights to use, copy, modify, merge, publish,
|
||||||
// distribute, sublicense, and/or sell copies of the Software, and to
|
* distribute, sublicense, and/or sell copies of the Software, and to
|
||||||
// permit persons to whom the Software is furnished to do so, subject to
|
* permit persons to whom the Software is furnished to do so, subject to
|
||||||
// the following conditions:
|
* the following conditions:
|
||||||
//
|
*
|
||||||
// The above copyright notice and this permission notice shall be included
|
* The above copyright notice and this permission notice shall be included
|
||||||
// in all copies or substantial portions of the Software.
|
* in all copies or substantial portions of the Software.
|
||||||
//
|
*
|
||||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||||
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||||
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||||
// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
||||||
// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
||||||
// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
||||||
// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
--------------------------------------------------------------------------------
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#include "sdkconfig.h"
|
||||||
|
#include <stdint.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
#include <stdarg.h>
|
||||||
#include <xtensa/config/core.h>
|
#include <xtensa/config/core.h>
|
||||||
|
#include <xtensa/xtensa_context.h>
|
||||||
#include "xtensa_rtos.h"
|
|
||||||
|
|
||||||
#include "soc/cpu.h"
|
|
||||||
|
|
||||||
#include "FreeRTOS.h"
|
|
||||||
#include "task.h"
|
|
||||||
|
|
||||||
#include "esp_debug_helpers.h"
|
|
||||||
#include "esp_heap_caps.h"
|
|
||||||
#include "esp_heap_caps_init.h"
|
|
||||||
#include "esp_private/crosscore_int.h"
|
|
||||||
|
|
||||||
#include "esp_intr_alloc.h"
|
|
||||||
#include "esp_log.h"
|
|
||||||
#include "sdkconfig.h"
|
|
||||||
|
|
||||||
#include "esp_task_wdt.h"
|
|
||||||
#include "esp_task.h"
|
|
||||||
|
|
||||||
#include "soc/soc_caps.h"
|
#include "soc/soc_caps.h"
|
||||||
#include "soc/efuse_reg.h"
|
#include "esp_private/crosscore_int.h"
|
||||||
#include "soc/dport_access.h"
|
#include "esp_system.h"
|
||||||
#include "soc/dport_reg.h"
|
#include "esp_log.h"
|
||||||
#include "esp_int_wdt.h"
|
#include "esp_int_wdt.h"
|
||||||
|
#include "esp_app_trace.h" /* Required for esp_apptrace_init. [refactor-todo] */
|
||||||
|
#include "FreeRTOS.h" /* This pulls in portmacro.h */
|
||||||
#include "sdkconfig.h"
|
#include "task.h" /* Required for TaskHandle_t, tskNO_AFFINITY, and vTaskStartScheduler */
|
||||||
|
|
||||||
#if CONFIG_IDF_TARGET_ESP32
|
|
||||||
#include "esp32/spiram.h"
|
|
||||||
#elif CONFIG_IDF_TARGET_ESP32S2
|
|
||||||
#include "esp32s2/spiram.h"
|
|
||||||
#elif CONFIG_IDF_TARGET_ESP32S3
|
|
||||||
#include "esp32s3/spiram.h"
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#include "port_systick.h"
|
#include "port_systick.h"
|
||||||
#include "esp_private/startup_internal.h" // [refactor-todo] for g_spiram_ok
|
|
||||||
#include "esp_app_trace.h" // [refactor-todo] for esp_app_trace_init
|
|
||||||
|
|
||||||
/* Defined in xtensa_context.S */
|
|
||||||
extern void _xt_coproc_init(void);
|
|
||||||
|
|
||||||
static const char* TAG = "cpu_start"; // [refactor-todo]: might be appropriate to change in the future, but
|
|
||||||
// for now maintain the same log output
|
|
||||||
|
|
||||||
_Static_assert(tskNO_AFFINITY == CONFIG_FREERTOS_NO_AFFINITY, "incorrect tskNO_AFFINITY value");
|
_Static_assert(tskNO_AFFINITY == CONFIG_FREERTOS_NO_AFFINITY, "incorrect tskNO_AFFINITY value");
|
||||||
|
|
||||||
/*-----------------------------------------------------------*/
|
|
||||||
|
/* ---------------------------------------------------- Variables ------------------------------------------------------
|
||||||
|
*
|
||||||
|
* ------------------------------------------------------------------------------------------------------------------ */
|
||||||
|
|
||||||
|
static const char *TAG = "cpu_start"; /* [refactor-todo]: might be appropriate to change in the future, but for now maintain the same log output */
|
||||||
extern volatile int port_xSchedulerRunning[portNUM_PROCESSORS];
|
extern volatile int port_xSchedulerRunning[portNUM_PROCESSORS];
|
||||||
unsigned port_interruptNesting[portNUM_PROCESSORS] = {0}; // Interrupt nesting level. Increased/decreased in portasm.c, _frxt_int_enter/_frxt_int_exit
|
unsigned port_interruptNesting[portNUM_PROCESSORS] = {0}; // Interrupt nesting level. Increased/decreased in portasm.c, _frxt_int_enter/_frxt_int_exit
|
||||||
BaseType_t port_uxCriticalNesting[portNUM_PROCESSORS] = {0};
|
BaseType_t port_uxCriticalNesting[portNUM_PROCESSORS] = {0};
|
||||||
BaseType_t port_uxOldInterruptState[portNUM_PROCESSORS] = {0};
|
BaseType_t port_uxOldInterruptState[portNUM_PROCESSORS] = {0};
|
||||||
/*-----------------------------------------------------------*/
|
|
||||||
|
|
||||||
|
/* ------------------------------------------------ FreeRTOS Portable --------------------------------------------------
|
||||||
|
* - Provides implementation for functions required by FreeRTOS
|
||||||
|
* - Declared in portable.h
|
||||||
|
* ------------------------------------------------------------------------------------------------------------------ */
|
||||||
|
|
||||||
|
// ----------------- Scheduler Start/End -------------------
|
||||||
|
|
||||||
|
/* Defined in xtensa_context.S */
|
||||||
|
extern void _xt_coproc_init(void);
|
||||||
|
|
||||||
|
BaseType_t xPortStartScheduler( void )
|
||||||
|
{
|
||||||
|
// Interrupts are disabled at this point and stack contains PS with enabled interrupts when task context is restored
|
||||||
|
|
||||||
|
#if XCHAL_CP_NUM > 0
|
||||||
|
/* Initialize co-processor management for tasks. Leave CPENABLE alone. */
|
||||||
|
_xt_coproc_init();
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* Setup the hardware to generate the tick. */
|
||||||
|
vPortSetupTimer();
|
||||||
|
|
||||||
|
port_xSchedulerRunning[xPortGetCoreID()] = 1;
|
||||||
|
|
||||||
|
// Cannot be directly called from C; never returns
|
||||||
|
__asm__ volatile ("call0 _frxt_dispatch\n");
|
||||||
|
|
||||||
|
/* Should not get here. */
|
||||||
|
return pdTRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
void vPortEndScheduler( void )
|
||||||
|
{
|
||||||
|
/* It is unlikely that the Xtensa port will get stopped. If required simply
|
||||||
|
disable the tick interrupt here. */
|
||||||
|
abort();
|
||||||
|
}
|
||||||
|
|
||||||
|
// ------------------------ Stack --------------------------
|
||||||
|
|
||||||
// User exception dispatcher when exiting
|
// User exception dispatcher when exiting
|
||||||
void _xt_user_exit(void);
|
void _xt_user_exit(void);
|
||||||
@@ -164,9 +135,6 @@ static void vPortTaskWrapper(TaskFunction_t pxCode, void *pvParameters)
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/*
|
|
||||||
* Stack initialization
|
|
||||||
*/
|
|
||||||
#if portUSING_MPU_WRAPPERS
|
#if portUSING_MPU_WRAPPERS
|
||||||
StackType_t *pxPortInitialiseStack( StackType_t *pxTopOfStack, TaskFunction_t pxCode, void *pvParameters, BaseType_t xRunPrivileged )
|
StackType_t *pxPortInitialiseStack( StackType_t *pxTopOfStack, TaskFunction_t pxCode, void *pvParameters, BaseType_t xRunPrivileged )
|
||||||
#else
|
#else
|
||||||
@@ -198,8 +166,9 @@ StackType_t *pxPortInitialiseStack( StackType_t *pxTopOfStack, TaskFunction_t px
|
|||||||
sp = (StackType_t *) (((UBaseType_t)pxTopOfStack - XT_CP_SIZE - thread_local_sz - XT_STK_FRMSZ) & ~0xf);
|
sp = (StackType_t *) (((UBaseType_t)pxTopOfStack - XT_CP_SIZE - thread_local_sz - XT_STK_FRMSZ) & ~0xf);
|
||||||
|
|
||||||
/* Clear the entire frame (do not use memset() because we don't depend on C library) */
|
/* Clear the entire frame (do not use memset() because we don't depend on C library) */
|
||||||
for (tp = sp; tp <= pxTopOfStack; ++tp)
|
for (tp = sp; tp <= pxTopOfStack; ++tp) {
|
||||||
*tp = 0;
|
*tp = 0;
|
||||||
|
}
|
||||||
|
|
||||||
frame = (XtExcFrame *) sp;
|
frame = (XtExcFrame *) sp;
|
||||||
|
|
||||||
@@ -223,7 +192,7 @@ StackType_t *pxPortInitialiseStack( StackType_t *pxTopOfStack, TaskFunction_t px
|
|||||||
frame->a2 = (UBaseType_t) pvParameters;
|
frame->a2 = (UBaseType_t) pvParameters;
|
||||||
#endif
|
#endif
|
||||||
frame->ps = PS_UM | PS_EXCM;
|
frame->ps = PS_UM | PS_EXCM;
|
||||||
#else
|
#else /* __XTENSA_CALL0_ABI__ */
|
||||||
/* + for windowed ABI also set WOE and CALLINC (pretend task was 'call4'd). */
|
/* + for windowed ABI also set WOE and CALLINC (pretend task was 'call4'd). */
|
||||||
#if CONFIG_FREERTOS_TASK_FUNCTION_WRAPPER
|
#if CONFIG_FREERTOS_TASK_FUNCTION_WRAPPER
|
||||||
frame->a6 = (UBaseType_t) pxCode;
|
frame->a6 = (UBaseType_t) pxCode;
|
||||||
@@ -232,7 +201,7 @@ StackType_t *pxPortInitialiseStack( StackType_t *pxTopOfStack, TaskFunction_t px
|
|||||||
frame->a6 = (UBaseType_t) pvParameters;
|
frame->a6 = (UBaseType_t) pvParameters;
|
||||||
#endif
|
#endif
|
||||||
frame->ps = PS_UM | PS_EXCM | PS_WOE | PS_CALLINC(1);
|
frame->ps = PS_UM | PS_EXCM | PS_WOE | PS_CALLINC(1);
|
||||||
#endif
|
#endif /* __XTENSA_CALL0_ABI__ */
|
||||||
|
|
||||||
#ifdef XT_USE_SWPRI
|
#ifdef XT_USE_SWPRI
|
||||||
/* Set the initial virtual priority mask value to all 1's. */
|
/* Set the initial virtual priority mask value to all 1's. */
|
||||||
@@ -269,80 +238,19 @@ StackType_t *pxPortInitialiseStack( StackType_t *pxTopOfStack, TaskFunction_t px
|
|||||||
p[0] = 0;
|
p[0] = 0;
|
||||||
p[1] = 0;
|
p[1] = 0;
|
||||||
p[2] = (((uint32_t) p) + 12 + XCHAL_TOTAL_SA_ALIGN - 1) & -XCHAL_TOTAL_SA_ALIGN;
|
p[2] = (((uint32_t) p) + 12 + XCHAL_TOTAL_SA_ALIGN - 1) & -XCHAL_TOTAL_SA_ALIGN;
|
||||||
#endif
|
#endif /* XCHAL_CP_NUM */
|
||||||
|
|
||||||
return sp;
|
return sp;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*-----------------------------------------------------------*/
|
|
||||||
|
|
||||||
void vPortEndScheduler( void )
|
|
||||||
{
|
|
||||||
/* It is unlikely that the Xtensa port will get stopped. If required simply
|
|
||||||
disable the tick interrupt here. */
|
|
||||||
abort();
|
|
||||||
}
|
|
||||||
|
|
||||||
/*-----------------------------------------------------------*/
|
|
||||||
|
|
||||||
BaseType_t xPortStartScheduler( void )
|
|
||||||
{
|
|
||||||
// Interrupts are disabled at this point and stack contains PS with enabled interrupts when task context is restored
|
|
||||||
|
|
||||||
#if XCHAL_CP_NUM > 0
|
|
||||||
/* Initialize co-processor management for tasks. Leave CPENABLE alone. */
|
|
||||||
_xt_coproc_init();
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/* Setup the hardware to generate the tick. */
|
|
||||||
vPortSetupTimer();
|
|
||||||
|
|
||||||
port_xSchedulerRunning[xPortGetCoreID()] = 1;
|
|
||||||
|
|
||||||
// Cannot be directly called from C; never returns
|
|
||||||
__asm__ volatile ("call0 _frxt_dispatch\n");
|
|
||||||
|
|
||||||
/* Should not get here. */
|
|
||||||
return pdTRUE;
|
|
||||||
}
|
|
||||||
/*-----------------------------------------------------------*/
|
|
||||||
|
|
||||||
void vPortYieldOtherCore( BaseType_t coreid ) {
|
|
||||||
esp_crosscore_int_send_yield( coreid );
|
|
||||||
}
|
|
||||||
|
|
||||||
/*-----------------------------------------------------------*/
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Used to set coprocessor area in stack. Current hack is to reuse MPU pointer for coprocessor area.
|
|
||||||
*/
|
|
||||||
#if portUSING_MPU_WRAPPERS
|
|
||||||
void vPortStoreTaskMPUSettings( xMPU_SETTINGS *xMPUSettings, const struct xMEMORY_REGION * const xRegions, StackType_t *pxBottomOfStack, uint32_t usStackDepth )
|
|
||||||
{
|
|
||||||
#if XCHAL_CP_NUM > 0
|
|
||||||
xMPUSettings->coproc_area = ( StackType_t * ) ( ( uint32_t ) ( pxBottomOfStack + usStackDepth - 1 ));
|
|
||||||
xMPUSettings->coproc_area = ( StackType_t * ) ( ( ( portPOINTER_SIZE_TYPE ) xMPUSettings->coproc_area ) & ( ~( ( portPOINTER_SIZE_TYPE ) portBYTE_ALIGNMENT_MASK ) ) );
|
|
||||||
xMPUSettings->coproc_area = ( StackType_t * ) ( ( ( uint32_t ) xMPUSettings->coproc_area - XT_CP_SIZE ) & ~0xf );
|
|
||||||
|
|
||||||
|
|
||||||
/* NOTE: we cannot initialize the coprocessor save area here because FreeRTOS is going to
|
/* ---------------------------------------------- Port Implementations -------------------------------------------------
|
||||||
* clear the stack area after we return. This is done in pxPortInitialiseStack().
|
*
|
||||||
*/
|
* ------------------------------------------------------------------------------------------------------------------ */
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
void vPortReleaseTaskMPUSettings( xMPU_SETTINGS *xMPUSettings )
|
// --------------------- Interrupts ------------------------
|
||||||
{
|
|
||||||
/* If task has live floating point registers somewhere, release them */
|
|
||||||
_xt_coproc_release( xMPUSettings->coproc_area );
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Returns true if the current core is in ISR context; low prio ISR, med prio ISR or timer tick ISR. High prio ISRs
|
|
||||||
* aren't detected here, but they normally cannot call C code, so that should not be an issue anyway.
|
|
||||||
*/
|
|
||||||
BaseType_t xPortInIsrContext(void)
|
BaseType_t xPortInIsrContext(void)
|
||||||
{
|
{
|
||||||
unsigned int irqStatus;
|
unsigned int irqStatus;
|
||||||
@@ -353,15 +261,63 @@ BaseType_t xPortInIsrContext(void)
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
void vPortAssertIfInISR(void)
|
||||||
* This function will be called in High prio ISRs. Returns true if the current core was in ISR context
|
{
|
||||||
* before calling into high prio ISR context.
|
configASSERT(xPortInIsrContext());
|
||||||
*/
|
}
|
||||||
|
|
||||||
BaseType_t IRAM_ATTR xPortInterruptedFromISRContext(void)
|
BaseType_t IRAM_ATTR xPortInterruptedFromISRContext(void)
|
||||||
{
|
{
|
||||||
return (port_interruptNesting[xPortGetCoreID()] != 0);
|
return (port_interruptNesting[xPortGetCoreID()] != 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ------------------ Critical Sections --------------------
|
||||||
|
|
||||||
|
void __attribute__((optimize("-O3"))) vPortEnterCritical(portMUX_TYPE *mux)
|
||||||
|
{
|
||||||
|
BaseType_t oldInterruptLevel = portENTER_CRITICAL_NESTED();
|
||||||
|
/* Interrupts may already be disabled (because we're doing this recursively)
|
||||||
|
* but we can't get the interrupt level after
|
||||||
|
* vPortCPUAquireMutex, because it also may mess with interrupts.
|
||||||
|
* Get it here first, then later figure out if we're nesting
|
||||||
|
* and save for real there.
|
||||||
|
*/
|
||||||
|
vPortCPUAcquireMutex( mux );
|
||||||
|
BaseType_t coreID = xPortGetCoreID();
|
||||||
|
BaseType_t newNesting = port_uxCriticalNesting[coreID] + 1;
|
||||||
|
port_uxCriticalNesting[coreID] = newNesting;
|
||||||
|
|
||||||
|
if ( newNesting == 1 ) {
|
||||||
|
//This is the first time we get called. Save original interrupt level.
|
||||||
|
port_uxOldInterruptState[coreID] = oldInterruptLevel;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void __attribute__((optimize("-O3"))) vPortExitCritical(portMUX_TYPE *mux)
|
||||||
|
{
|
||||||
|
vPortCPUReleaseMutex( mux );
|
||||||
|
BaseType_t coreID = xPortGetCoreID();
|
||||||
|
BaseType_t nesting = port_uxCriticalNesting[coreID];
|
||||||
|
|
||||||
|
if (nesting > 0) {
|
||||||
|
nesting--;
|
||||||
|
port_uxCriticalNesting[coreID] = nesting;
|
||||||
|
|
||||||
|
if ( nesting == 0 ) {
|
||||||
|
portEXIT_CRITICAL_NESTED(port_uxOldInterruptState[coreID]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ---------------------- Yielding -------------------------
|
||||||
|
|
||||||
|
void vPortYieldOtherCore( BaseType_t coreid )
|
||||||
|
{
|
||||||
|
esp_crosscore_int_send_yield( coreid );
|
||||||
|
}
|
||||||
|
|
||||||
|
extern void _frxt_setup_switch( void ); //Defined in portasm.S
|
||||||
|
|
||||||
void IRAM_ATTR vPortEvaluateYieldFromISR(int argc, ...)
|
void IRAM_ATTR vPortEvaluateYieldFromISR(int argc, ...)
|
||||||
{
|
{
|
||||||
BaseType_t xYield;
|
BaseType_t xYield;
|
||||||
@@ -386,68 +342,7 @@ void IRAM_ATTR vPortEvaluateYieldFromISR(int argc, ...)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void vPortAssertIfInISR(void)
|
// ------------------- Hook Functions ----------------------
|
||||||
{
|
|
||||||
configASSERT(xPortInIsrContext());
|
|
||||||
}
|
|
||||||
|
|
||||||
#define STACK_WATCH_AREA_SIZE 32
|
|
||||||
#define STACK_WATCH_POINT_NUMBER (SOC_CPU_WATCHPOINTS_NUM - 1)
|
|
||||||
|
|
||||||
void vPortSetStackWatchpoint( void* pxStackStart ) {
|
|
||||||
//Set watchpoint 1 to watch the last 32 bytes of the stack.
|
|
||||||
//Unfortunately, the Xtensa watchpoints can't set a watchpoint on a random [base - base+n] region because
|
|
||||||
//the size works by masking off the lowest address bits. For that reason, we futz a bit and watch the lowest 32
|
|
||||||
//bytes of the stack we can actually watch. In general, this can cause the watchpoint to be triggered at most
|
|
||||||
//28 bytes early. The value 32 is chosen because it's larger than the stack canary, which in FreeRTOS is 20 bytes.
|
|
||||||
//This way, we make sure we trigger before/when the stack canary is corrupted, not after.
|
|
||||||
int addr=(int)pxStackStart;
|
|
||||||
addr=(addr+31)&(~31);
|
|
||||||
esp_cpu_set_watchpoint(STACK_WATCH_POINT_NUMBER, (char*)addr, 32, ESP_WATCHPOINT_STORE);
|
|
||||||
}
|
|
||||||
|
|
||||||
uint32_t xPortGetTickRateHz(void) {
|
|
||||||
return (uint32_t)configTICK_RATE_HZ;
|
|
||||||
}
|
|
||||||
|
|
||||||
void __attribute__((optimize("-O3"))) vPortEnterCritical(portMUX_TYPE *mux)
|
|
||||||
{
|
|
||||||
BaseType_t oldInterruptLevel = portENTER_CRITICAL_NESTED();
|
|
||||||
/* Interrupts may already be disabled (because we're doing this recursively)
|
|
||||||
* but we can't get the interrupt level after
|
|
||||||
* vPortCPUAquireMutex, because it also may mess with interrupts.
|
|
||||||
* Get it here first, then later figure out if we're nesting
|
|
||||||
* and save for real there.
|
|
||||||
*/
|
|
||||||
vPortCPUAcquireMutex( mux );
|
|
||||||
BaseType_t coreID = xPortGetCoreID();
|
|
||||||
BaseType_t newNesting = port_uxCriticalNesting[coreID] + 1;
|
|
||||||
port_uxCriticalNesting[coreID] = newNesting;
|
|
||||||
|
|
||||||
if( newNesting == 1 )
|
|
||||||
{
|
|
||||||
//This is the first time we get called. Save original interrupt level.
|
|
||||||
port_uxOldInterruptState[coreID] = oldInterruptLevel;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void __attribute__((optimize("-O3"))) vPortExitCritical(portMUX_TYPE *mux)
|
|
||||||
{
|
|
||||||
vPortCPUReleaseMutex( mux );
|
|
||||||
BaseType_t coreID = xPortGetCoreID();
|
|
||||||
BaseType_t nesting = port_uxCriticalNesting[coreID];
|
|
||||||
|
|
||||||
if(nesting > 0)
|
|
||||||
{
|
|
||||||
nesting--;
|
|
||||||
port_uxCriticalNesting[coreID] = nesting;
|
|
||||||
|
|
||||||
if( nesting == 0 )
|
|
||||||
{
|
|
||||||
portEXIT_CRITICAL_NESTED(port_uxOldInterruptState[coreID]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void __attribute__((weak)) vApplicationStackOverflowHook( TaskHandle_t xTask, char *pcTaskName )
|
void __attribute__((weak)) vApplicationStackOverflowHook( TaskHandle_t xTask, char *pcTaskName )
|
||||||
{
|
{
|
||||||
@@ -464,6 +359,63 @@ void __attribute__((weak)) vApplicationStackOverflowHook( TaskHandle_t xTask, c
|
|||||||
esp_system_abort(buf);
|
esp_system_abort(buf);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ----------------------- System --------------------------
|
||||||
|
|
||||||
|
uint32_t xPortGetTickRateHz(void)
|
||||||
|
{
|
||||||
|
return (uint32_t)configTICK_RATE_HZ;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#define STACK_WATCH_AREA_SIZE 32
|
||||||
|
#define STACK_WATCH_POINT_NUMBER (SOC_CPU_WATCHPOINTS_NUM - 1)
|
||||||
|
|
||||||
|
void vPortSetStackWatchpoint( void *pxStackStart )
|
||||||
|
{
|
||||||
|
//Set watchpoint 1 to watch the last 32 bytes of the stack.
|
||||||
|
//Unfortunately, the Xtensa watchpoints can't set a watchpoint on a random [base - base+n] region because
|
||||||
|
//the size works by masking off the lowest address bits. For that reason, we futz a bit and watch the lowest 32
|
||||||
|
//bytes of the stack we can actually watch. In general, this can cause the watchpoint to be triggered at most
|
||||||
|
//28 bytes early. The value 32 is chosen because it's larger than the stack canary, which in FreeRTOS is 20 bytes.
|
||||||
|
//This way, we make sure we trigger before/when the stack canary is corrupted, not after.
|
||||||
|
int addr = (int)pxStackStart;
|
||||||
|
addr = (addr + 31) & (~31);
|
||||||
|
esp_cpu_set_watchpoint(STACK_WATCH_POINT_NUMBER, (char *)addr, 32, ESP_WATCHPOINT_STORE);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ---------------------------------------------- Misc Implementations -------------------------------------------------
|
||||||
|
*
|
||||||
|
* ------------------------------------------------------------------------------------------------------------------ */
|
||||||
|
|
||||||
|
// -------------------- Co-Processor -----------------------
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Used to set coprocessor area in stack. Current hack is to reuse MPU pointer for coprocessor area.
|
||||||
|
*/
|
||||||
|
#if portUSING_MPU_WRAPPERS
|
||||||
|
void vPortStoreTaskMPUSettings( xMPU_SETTINGS *xMPUSettings, const struct xMEMORY_REGION *const xRegions, StackType_t *pxBottomOfStack, uint32_t usStackDepth )
|
||||||
|
{
|
||||||
|
#if XCHAL_CP_NUM > 0
|
||||||
|
xMPUSettings->coproc_area = ( StackType_t * ) ( ( uint32_t ) ( pxBottomOfStack + usStackDepth - 1 ));
|
||||||
|
xMPUSettings->coproc_area = ( StackType_t * ) ( ( ( portPOINTER_SIZE_TYPE ) xMPUSettings->coproc_area ) & ( ~( ( portPOINTER_SIZE_TYPE ) portBYTE_ALIGNMENT_MASK ) ) );
|
||||||
|
xMPUSettings->coproc_area = ( StackType_t * ) ( ( ( uint32_t ) xMPUSettings->coproc_area - XT_CP_SIZE ) & ~0xf );
|
||||||
|
|
||||||
|
|
||||||
|
/* NOTE: we cannot initialize the coprocessor save area here because FreeRTOS is going to
|
||||||
|
* clear the stack area after we return. This is done in pxPortInitialiseStack().
|
||||||
|
*/
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
void vPortReleaseTaskMPUSettings( xMPU_SETTINGS *xMPUSettings )
|
||||||
|
{
|
||||||
|
/* If task has live floating point registers somewhere, release them */
|
||||||
|
_xt_coproc_release( xMPUSettings->coproc_area );
|
||||||
|
}
|
||||||
|
#endif /* portUSING_MPU_WRAPPERS */
|
||||||
|
|
||||||
|
// --------------------- App Start-up ----------------------
|
||||||
|
|
||||||
#if !CONFIG_FREERTOS_UNICORE
|
#if !CONFIG_FREERTOS_UNICORE
|
||||||
void esp_startup_start_app_other_cores(void)
|
void esp_startup_start_app_other_cores(void)
|
||||||
{
|
{
|
||||||
|
@@ -1382,10 +1382,10 @@ components/freertos/croutine.c
|
|||||||
components/freertos/esp_additions/task_snapshot.c
|
components/freertos/esp_additions/task_snapshot.c
|
||||||
components/freertos/event_groups.c
|
components/freertos/event_groups.c
|
||||||
components/freertos/freertos_v8_compat.c
|
components/freertos/freertos_v8_compat.c
|
||||||
|
components/freertos/include/esp_additions/freertos/FreeRTOSConfig.h
|
||||||
components/freertos/include/esp_additions/freertos/task_snapshot.h
|
components/freertos/include/esp_additions/freertos/task_snapshot.h
|
||||||
components/freertos/include/esp_additions/freertos_tasks_c_additions.h
|
components/freertos/include/esp_additions/freertos_tasks_c_additions.h
|
||||||
components/freertos/include/freertos/FreeRTOS.h
|
components/freertos/include/freertos/FreeRTOS.h
|
||||||
components/freertos/include/freertos/FreeRTOSConfig.h
|
|
||||||
components/freertos/include/freertos/StackMacros.h
|
components/freertos/include/freertos/StackMacros.h
|
||||||
components/freertos/include/freertos/atomic.h
|
components/freertos/include/freertos/atomic.h
|
||||||
components/freertos/include/freertos/croutine.h
|
components/freertos/include/freertos/croutine.h
|
||||||
@@ -1404,14 +1404,13 @@ components/freertos/include/freertos/stream_buffer.h
|
|||||||
components/freertos/include/freertos/task.h
|
components/freertos/include/freertos/task.h
|
||||||
components/freertos/include/freertos/timers.h
|
components/freertos/include/freertos/timers.h
|
||||||
components/freertos/list.c
|
components/freertos/list.c
|
||||||
components/freertos/port/linux/include/freertos/FreeRTOSConfig.h
|
components/freertos/port/linux/include/freertos/FreeRTOSConfig_arch.h
|
||||||
components/freertos/port/linux/include/freertos/portmacro.h
|
components/freertos/port/linux/include/freertos/portmacro.h
|
||||||
components/freertos/port/port_common.c
|
components/freertos/port/riscv/include/freertos/FreeRTOSConfig_arch.h
|
||||||
components/freertos/port/riscv/include/freertos/FreeRTOSConfig.h
|
|
||||||
components/freertos/port/riscv/include/freertos/portbenchmark.h
|
components/freertos/port/riscv/include/freertos/portbenchmark.h
|
||||||
components/freertos/port/riscv/include/freertos/portmacro.h
|
components/freertos/port/riscv/include/freertos/portmacro.h
|
||||||
components/freertos/port/riscv/port.c
|
components/freertos/port/riscv/port.c
|
||||||
components/freertos/port/xtensa/include/freertos/FreeRTOSConfig.h
|
components/freertos/port/xtensa/include/freertos/FreeRTOSConfig_arch.h
|
||||||
components/freertos/port/xtensa/include/freertos/portbenchmark.h
|
components/freertos/port/xtensa/include/freertos/portbenchmark.h
|
||||||
components/freertos/port/xtensa/include/freertos/portmacro.h
|
components/freertos/port/xtensa/include/freertos/portmacro.h
|
||||||
components/freertos/port/xtensa/include/freertos/portmacro_priv.h
|
components/freertos/port/xtensa/include/freertos/portmacro_priv.h
|
||||||
|
Reference in New Issue
Block a user