Synced portable section.

This commit is contained in:
Carl Lundin 2020-01-23 17:46:58 -08:00
parent 7ceed10420
commit 0b9e3b2c5f
514 changed files with 172645 additions and 170941 deletions

View file

@ -242,10 +242,10 @@ extern "C" {
#endif #endif
/* configPRECONDITION should be resolve to configASSERT. /* configPRECONDITION should be resolve to configASSERT.
The CBMC proofs need a way to track assumptions and assertions. The CBMC proofs need a way to track assumptions and assertions.
A configPRECONDITION statement should express an implicit invariant or assumption made. A configPRECONDITION statement should express an implicit invariant or
A configASSERT statement should express an invariant that must hold explicit before calling assumption made. A configASSERT statement should express an invariant that must
the code. */ hold explicit before calling the code. */
#ifndef configPRECONDITION #ifndef configPRECONDITION
#define configPRECONDITION( X ) configASSERT(X) #define configPRECONDITION( X ) configASSERT(X)
#define configPRECONDITION_DEFINED 0 #define configPRECONDITION_DEFINED 0
@ -257,6 +257,10 @@ extern "C" {
#define portMEMORY_BARRIER() #define portMEMORY_BARRIER()
#endif #endif
#ifndef portSOFTWARE_BARRIER
#define portSOFTWARE_BARRIER()
#endif
/* The timers module relies on xTaskGetSchedulerState(). */ /* The timers module relies on xTaskGetSchedulerState(). */
#if configUSE_TIMERS == 1 #if configUSE_TIMERS == 1

View file

@ -29,16 +29,16 @@
* @file atomic.h * @file atomic.h
* @brief FreeRTOS atomic operation support. * @brief FreeRTOS atomic operation support.
* *
* This file implements atomic by disabling interrupts globally. * This file implements atomic functions by disabling interrupts globally.
* Implementation with architecture specific atomic instructions * Implementations with architecture specific atomic instructions can be
* are to be provided under each compiler directory. * provided under each compiler directory.
*/ */
#ifndef ATOMIC_H #ifndef ATOMIC_H
#define ATOMIC_H #define ATOMIC_H
#ifndef INC_FREERTOS_H #ifndef INC_FREERTOS_H
#error "include FreeRTOS.h must appear in source files before include atomic.h" #error "include FreeRTOS.h must appear in source files before include atomic.h"
#endif #endif
/* Standard includes. */ /* Standard includes. */
@ -48,41 +48,44 @@
extern "C" { extern "C" {
#endif #endif
/* Port specific definitions -- entering/exiting critical section. /*
* Port specific definitions -- entering/exiting critical section.
* Refer template -- ./lib/FreeRTOS/portable/Compiler/Arch/portmacro.h * Refer template -- ./lib/FreeRTOS/portable/Compiler/Arch/portmacro.h
* *
* Every call to ATOMIC_EXIT_CRITICAL() must be closely paired with * Every call to ATOMIC_EXIT_CRITICAL() must be closely paired with
* ATOMIC_ENTER_CRITICAL(). * ATOMIC_ENTER_CRITICAL().
* */ *
*/
#if defined( portSET_INTERRUPT_MASK_FROM_ISR ) #if defined( portSET_INTERRUPT_MASK_FROM_ISR )
/* Nested interrupt scheme is supported in this port. */ /* Nested interrupt scheme is supported in this port. */
#define ATOMIC_ENTER_CRITICAL() \ #define ATOMIC_ENTER_CRITICAL() \
UBaseType_t uxCriticalSectionType = portSET_INTERRUPT_MASK_FROM_ISR() UBaseType_t uxCriticalSectionType = portSET_INTERRUPT_MASK_FROM_ISR()
#define ATOMIC_EXIT_CRITICAL() \ #define ATOMIC_EXIT_CRITICAL() \
portCLEAR_INTERRUPT_MASK_FROM_ISR( uxCriticalSectionType ) portCLEAR_INTERRUPT_MASK_FROM_ISR( uxCriticalSectionType )
#else #else
/* Nested interrupt scheme is NOT supported in this port. */ /* Nested interrupt scheme is NOT supported in this port. */
#define ATOMIC_ENTER_CRITICAL() portENTER_CRITICAL() #define ATOMIC_ENTER_CRITICAL() portENTER_CRITICAL()
#define ATOMIC_EXIT_CRITICAL() portEXIT_CRITICAL() #define ATOMIC_EXIT_CRITICAL() portEXIT_CRITICAL()
#endif /* portSET_INTERRUPT_MASK_FROM_ISR() */ #endif /* portSET_INTERRUPT_MASK_FROM_ISR() */
/* Port specific definition -- "always inline". /*
* Inline is compiler specific, and may not always get inlined depending on your optimization level. * Port specific definition -- "always inline".
* Also, inline is considerred as performance optimization for atomic. * Inline is compiler specific, and may not always get inlined depending on your
* Thus, if portFORCE_INLINE is not provided by portmacro.h, instead of resulting error, * optimization level. Also, inline is considered as performance optimization
* simply define it. * for atomic. Thus, if portFORCE_INLINE is not provided by portmacro.h,
* instead of resulting error, simply define it away.
*/ */
#ifndef portFORCE_INLINE #ifndef portFORCE_INLINE
#define portFORCE_INLINE #define portFORCE_INLINE
#endif #endif
#define ATOMIC_COMPARE_AND_SWAP_SUCCESS 0x1U /**< Compare and swap succeeded, swapped. */ #define ATOMIC_COMPARE_AND_SWAP_SUCCESS 0x1U /**< Compare and swap succeeded, swapped. */
#define ATOMIC_COMPARE_AND_SWAP_FAILURE 0x0U /**< Compare and swap failed, did not swap. */ #define ATOMIC_COMPARE_AND_SWAP_FAILURE 0x0U /**< Compare and swap failed, did not swap. */
/*----------------------------- Swap && CAS ------------------------------*/ /*----------------------------- Swap && CAS ------------------------------*/
@ -91,66 +94,67 @@ extern "C" {
* *
* @brief Performs an atomic compare-and-swap operation on the specified values. * @brief Performs an atomic compare-and-swap operation on the specified values.
* *
* @param[in, out] pDestination Pointer to memory location from where value is * @param[in, out] pulDestination Pointer to memory location from where value is
* to be loaded and checked. * to be loaded and checked.
* @param[in] ulExchange If condition meets, write this value to memory. * @param[in] ulExchange If condition meets, write this value to memory.
* @param[in] ulComparand Swap condition. * @param[in] ulComparand Swap condition.
* *
* @return Unsigned integer of value 1 or 0. 1 for swapped, 0 for not swapped. * @return Unsigned integer of value 1 or 0. 1 for swapped, 0 for not swapped.
* *
* @note This function only swaps *pDestination with ulExchange, if previous * @note This function only swaps *pulDestination with ulExchange, if previous
* *pDestination value equals ulComparand. * *pulDestination value equals ulComparand.
*/ */
static portFORCE_INLINE uint32_t Atomic_CompareAndSwap_u32( static portFORCE_INLINE uint32_t Atomic_CompareAndSwap_u32( uint32_t volatile * pulDestination,
uint32_t volatile * pDestination, uint32_t ulExchange,
uint32_t ulExchange, uint32_t ulComparand )
uint32_t ulComparand )
{ {
uint32_t ulReturnValue;
uint32_t ulReturnValue = ATOMIC_COMPARE_AND_SWAP_FAILURE; ATOMIC_ENTER_CRITICAL();
{
ATOMIC_ENTER_CRITICAL(); if( *pulDestination == ulComparand )
{
if ( *pDestination == ulComparand ) *pulDestination = ulExchange;
{ ulReturnValue = ATOMIC_COMPARE_AND_SWAP_SUCCESS;
*pDestination = ulExchange; }
ulReturnValue = ATOMIC_COMPARE_AND_SWAP_SUCCESS; else
} {
ulReturnValue = ATOMIC_COMPARE_AND_SWAP_FAILURE;
ATOMIC_EXIT_CRITICAL(); }
}
return ulReturnValue; ATOMIC_EXIT_CRITICAL();
return ulReturnValue;
} }
/*-----------------------------------------------------------*/
/** /**
* Atomic swap (pointers) * Atomic swap (pointers)
* *
* @brief Atomically sets the address pointed to by *ppDestination to the value * @brief Atomically sets the address pointed to by *ppvDestination to the value
* of *pExchange. * of *pvExchange.
* *
* @param[in, out] ppDestination Pointer to memory location from where a pointer * @param[in, out] ppvDestination Pointer to memory location from where a pointer
* value is to be loaded and written back to. * value is to be loaded and written back to.
* @param[in] pExchange Pointer value to be written to *ppDestination. * @param[in] pvExchange Pointer value to be written to *ppvDestination.
* *
* @return The initial value of *ppDestination. * @return The initial value of *ppvDestination.
*/ */
static portFORCE_INLINE void * Atomic_SwapPointers_p32( static portFORCE_INLINE void * Atomic_SwapPointers_p32( void * volatile * ppvDestination,
void * volatile * ppDestination, void * pvExchange )
void * pExchange )
{ {
void * pReturnValue; void * pReturnValue;
ATOMIC_ENTER_CRITICAL(); ATOMIC_ENTER_CRITICAL();
{
pReturnValue = *ppvDestination;
*ppvDestination = pvExchange;
}
ATOMIC_EXIT_CRITICAL();
pReturnValue = *ppDestination; return pReturnValue;
*ppDestination = pExchange;
ATOMIC_EXIT_CRITICAL();
return pReturnValue;
} }
/*-----------------------------------------------------------*/
/** /**
* Atomic compare-and-swap (pointers) * Atomic compare-and-swap (pointers)
@ -158,33 +162,33 @@ static portFORCE_INLINE void * Atomic_SwapPointers_p32(
* @brief Performs an atomic compare-and-swap operation on the specified pointer * @brief Performs an atomic compare-and-swap operation on the specified pointer
* values. * values.
* *
* @param[in, out] ppDestination Pointer to memory location from where a pointer * @param[in, out] ppvDestination Pointer to memory location from where a pointer
* value is to be loaded and checked. * value is to be loaded and checked.
* @param[in] pExchange If condition meets, write this value to memory. * @param[in] pvExchange If condition meets, write this value to memory.
* @param[in] pComparand Swap condition. * @param[in] pvComparand Swap condition.
* *
* @return Unsigned integer of value 1 or 0. 1 for swapped, 0 for not swapped. * @return Unsigned integer of value 1 or 0. 1 for swapped, 0 for not swapped.
* *
* @note This function only swaps *ppDestination with pExchange, if previous * @note This function only swaps *ppvDestination with pvExchange, if previous
* *ppDestination value equals pComparand. * *ppvDestination value equals pvComparand.
*/ */
static portFORCE_INLINE uint32_t Atomic_CompareAndSwapPointers_p32( static portFORCE_INLINE uint32_t Atomic_CompareAndSwapPointers_p32( void * volatile * ppvDestination,
void * volatile * ppDestination, void * pvExchange,
void * pExchange, void * pComparand ) void * pvComparand )
{ {
uint32_t ulReturnValue = ATOMIC_COMPARE_AND_SWAP_FAILURE; uint32_t ulReturnValue = ATOMIC_COMPARE_AND_SWAP_FAILURE;
ATOMIC_ENTER_CRITICAL(); ATOMIC_ENTER_CRITICAL();
{
if( *ppvDestination == pvComparand )
{
*ppvDestination = pvExchange;
ulReturnValue = ATOMIC_COMPARE_AND_SWAP_SUCCESS;
}
}
ATOMIC_EXIT_CRITICAL();
if ( *ppDestination == pComparand ) return ulReturnValue;
{
*ppDestination = pExchange;
ulReturnValue = ATOMIC_COMPARE_AND_SWAP_SUCCESS;
}
ATOMIC_EXIT_CRITICAL();
return ulReturnValue;
} }
@ -195,28 +199,27 @@ static portFORCE_INLINE uint32_t Atomic_CompareAndSwapPointers_p32(
* *
* @brief Atomically adds count to the value of the specified pointer points to. * @brief Atomically adds count to the value of the specified pointer points to.
* *
* @param[in,out] pAddend Pointer to memory location from where value is to be * @param[in,out] pulAddend Pointer to memory location from where value is to be
* loaded and written back to. * loaded and written back to.
* @param[in] ulCount Value to be added to *pAddend. * @param[in] ulCount Value to be added to *pulAddend.
* *
* @return previous *pAddend value. * @return previous *pulAddend value.
*/ */
static portFORCE_INLINE uint32_t Atomic_Add_u32( static portFORCE_INLINE uint32_t Atomic_Add_u32( uint32_t volatile * pulAddend,
uint32_t volatile * pAddend, uint32_t ulCount )
uint32_t ulCount )
{ {
uint32_t ulCurrent; uint32_t ulCurrent;
ATOMIC_ENTER_CRITICAL(); ATOMIC_ENTER_CRITICAL();
{
ulCurrent = *pulAddend;
*pulAddend += ulCount;
}
ATOMIC_EXIT_CRITICAL();
ulCurrent = *pAddend; return ulCurrent;
*pAddend += ulCount;
ATOMIC_EXIT_CRITICAL();
return ulCurrent;
} }
/*-----------------------------------------------------------*/
/** /**
* Atomic subtract * Atomic subtract
@ -224,77 +227,75 @@ static portFORCE_INLINE uint32_t Atomic_Add_u32(
* @brief Atomically subtracts count from the value of the specified pointer * @brief Atomically subtracts count from the value of the specified pointer
* pointers to. * pointers to.
* *
* @param[in,out] pAddend Pointer to memory location from where value is to be * @param[in,out] pulAddend Pointer to memory location from where value is to be
* loaded and written back to. * loaded and written back to.
* @param[in] ulCount Value to be subtract from *pAddend. * @param[in] ulCount Value to be subtract from *pulAddend.
* *
* @return previous *pAddend value. * @return previous *pulAddend value.
*/ */
static portFORCE_INLINE uint32_t Atomic_Subtract_u32( static portFORCE_INLINE uint32_t Atomic_Subtract_u32( uint32_t volatile * pulAddend,
uint32_t volatile * pAddend, uint32_t ulCount )
uint32_t ulCount )
{ {
uint32_t ulCurrent; uint32_t ulCurrent;
ATOMIC_ENTER_CRITICAL(); ATOMIC_ENTER_CRITICAL();
{
ulCurrent = *pulAddend;
*pulAddend -= ulCount;
}
ATOMIC_EXIT_CRITICAL();
ulCurrent = *pAddend; return ulCurrent;
*pAddend -= ulCount;
ATOMIC_EXIT_CRITICAL();
return ulCurrent;
} }
/*-----------------------------------------------------------*/
/** /**
* Atomic increment * Atomic increment
* *
* @brief Atomically increments the value of the specified pointer points to. * @brief Atomically increments the value of the specified pointer points to.
* *
* @param[in,out] pAddend Pointer to memory location from where value is to be * @param[in,out] pulAddend Pointer to memory location from where value is to be
* loaded and written back to. * loaded and written back to.
* *
* @return *pAddend value before increment. * @return *pulAddend value before increment.
*/ */
static portFORCE_INLINE uint32_t Atomic_Increment_u32( uint32_t volatile * pAddend ) static portFORCE_INLINE uint32_t Atomic_Increment_u32( uint32_t volatile * pulAddend )
{ {
uint32_t ulCurrent; uint32_t ulCurrent;
ATOMIC_ENTER_CRITICAL(); ATOMIC_ENTER_CRITICAL();
{
ulCurrent = *pulAddend;
*pulAddend += 1;
}
ATOMIC_EXIT_CRITICAL();
ulCurrent = *pAddend; return ulCurrent;
*pAddend += 1;
ATOMIC_EXIT_CRITICAL();
return ulCurrent;
} }
/*-----------------------------------------------------------*/
/** /**
* Atomic decrement * Atomic decrement
* *
* @brief Atomically decrements the value of the specified pointer points to * @brief Atomically decrements the value of the specified pointer points to
* *
* @param[in,out] pAddend Pointer to memory location from where value is to be * @param[in,out] pulAddend Pointer to memory location from where value is to be
* loaded and written back to. * loaded and written back to.
* *
* @return *pAddend value before decrement. * @return *pulAddend value before decrement.
*/ */
static portFORCE_INLINE uint32_t Atomic_Decrement_u32( uint32_t volatile * pAddend ) static portFORCE_INLINE uint32_t Atomic_Decrement_u32( uint32_t volatile * pulAddend )
{ {
uint32_t ulCurrent; uint32_t ulCurrent;
ATOMIC_ENTER_CRITICAL(); ATOMIC_ENTER_CRITICAL();
{
ulCurrent = *pulAddend;
*pulAddend -= 1;
}
ATOMIC_EXIT_CRITICAL();
ulCurrent = *pAddend; return ulCurrent;
*pAddend -= 1;
ATOMIC_EXIT_CRITICAL();
return ulCurrent;
} }
/*----------------------------- Bitwise Logical ------------------------------*/ /*----------------------------- Bitwise Logical ------------------------------*/
@ -304,111 +305,106 @@ static portFORCE_INLINE uint32_t Atomic_Decrement_u32( uint32_t volatile * pAdde
* *
* @brief Performs an atomic OR operation on the specified values. * @brief Performs an atomic OR operation on the specified values.
* *
* @param [in, out] pDestination Pointer to memory location from where value is * @param [in, out] pulDestination Pointer to memory location from where value is
* to be loaded and written back to. * to be loaded and written back to.
* @param [in] ulValue Value to be ORed with *pDestination. * @param [in] ulValue Value to be ORed with *pulDestination.
* *
* @return The original value of *pDestination. * @return The original value of *pulDestination.
*/ */
static portFORCE_INLINE uint32_t Atomic_OR_u32( static portFORCE_INLINE uint32_t Atomic_OR_u32( uint32_t volatile * pulDestination,
uint32_t volatile * pDestination, uint32_t ulValue )
uint32_t ulValue )
{ {
uint32_t ulCurrent; uint32_t ulCurrent;
ATOMIC_ENTER_CRITICAL(); ATOMIC_ENTER_CRITICAL();
{
ulCurrent = *pulDestination;
*pulDestination |= ulValue;
}
ATOMIC_EXIT_CRITICAL();
ulCurrent = *pDestination; return ulCurrent;
*pDestination |= ulValue;
ATOMIC_EXIT_CRITICAL();
return ulCurrent;
} }
/*-----------------------------------------------------------*/
/** /**
* Atomic AND * Atomic AND
* *
* @brief Performs an atomic AND operation on the specified values. * @brief Performs an atomic AND operation on the specified values.
* *
* @param [in, out] pDestination Pointer to memory location from where value is * @param [in, out] pulDestination Pointer to memory location from where value is
* to be loaded and written back to. * to be loaded and written back to.
* @param [in] ulValue Value to be ANDed with *pDestination. * @param [in] ulValue Value to be ANDed with *pulDestination.
* *
* @return The original value of *pDestination. * @return The original value of *pulDestination.
*/ */
static portFORCE_INLINE uint32_t Atomic_AND_u32( static portFORCE_INLINE uint32_t Atomic_AND_u32( uint32_t volatile * pulDestination,
uint32_t volatile * pDestination, uint32_t ulValue )
uint32_t ulValue )
{ {
uint32_t ulCurrent; uint32_t ulCurrent;
ATOMIC_ENTER_CRITICAL(); ATOMIC_ENTER_CRITICAL();
{
ulCurrent = *pulDestination;
*pulDestination &= ulValue;
}
ATOMIC_EXIT_CRITICAL();
ulCurrent = *pDestination; return ulCurrent;
*pDestination &= ulValue;
ATOMIC_EXIT_CRITICAL();
return ulCurrent;
} }
/*-----------------------------------------------------------*/
/** /**
* Atomic NAND * Atomic NAND
* *
* @brief Performs an atomic NAND operation on the specified values. * @brief Performs an atomic NAND operation on the specified values.
* *
* @param [in, out] pDestination Pointer to memory location from where value is * @param [in, out] pulDestination Pointer to memory location from where value is
* to be loaded and written back to. * to be loaded and written back to.
* @param [in] ulValue Value to be NANDed with *pDestination. * @param [in] ulValue Value to be NANDed with *pulDestination.
* *
* @return The original value of *pDestination. * @return The original value of *pulDestination.
*/ */
static portFORCE_INLINE uint32_t Atomic_NAND_u32( static portFORCE_INLINE uint32_t Atomic_NAND_u32( uint32_t volatile * pulDestination,
uint32_t volatile * pDestination, uint32_t ulValue )
uint32_t ulValue )
{ {
uint32_t ulCurrent; uint32_t ulCurrent;
ATOMIC_ENTER_CRITICAL(); ATOMIC_ENTER_CRITICAL();
{
ulCurrent = *pulDestination;
*pulDestination = ~( ulCurrent & ulValue );
}
ATOMIC_EXIT_CRITICAL();
ulCurrent = *pDestination; return ulCurrent;
*pDestination = ~(ulCurrent & ulValue);
ATOMIC_EXIT_CRITICAL();
return ulCurrent;
} }
/*-----------------------------------------------------------*/
/** /**
* Atomic XOR * Atomic XOR
* *
* @brief Performs an atomic XOR operation on the specified values. * @brief Performs an atomic XOR operation on the specified values.
* *
* @param [in, out] pDestination Pointer to memory location from where value is * @param [in, out] pulDestination Pointer to memory location from where value is
* to be loaded and written back to. * to be loaded and written back to.
* @param [in] ulValue Value to be XORed with *pDestination. * @param [in] ulValue Value to be XORed with *pulDestination.
* *
* @return The original value of *pDestination. * @return The original value of *pulDestination.
*/ */
static portFORCE_INLINE uint32_t Atomic_XOR_u32( static portFORCE_INLINE uint32_t Atomic_XOR_u32( uint32_t volatile * pulDestination,
uint32_t volatile * pDestination, uint32_t ulValue )
uint32_t ulValue )
{ {
uint32_t ulCurrent; uint32_t ulCurrent;
ATOMIC_ENTER_CRITICAL(); ATOMIC_ENTER_CRITICAL();
{
ulCurrent = *pulDestination;
*pulDestination ^= ulValue;
}
ATOMIC_EXIT_CRITICAL();
ulCurrent = *pDestination; return ulCurrent;
*pDestination ^= ulValue;
ATOMIC_EXIT_CRITICAL();
return ulCurrent;
} }
#ifdef __cplusplus #ifdef __cplusplus

View file

@ -157,7 +157,7 @@ BaseType_t xCoRoutineCreate( crCOROUTINE_CODE pxCoRoutineCode, UBaseType_t uxPri
} }
// Alternatively, if you do not require any other part of the idle task to // Alternatively, if you do not require any other part of the idle task to
// execute, the idle task hook can call vCoRoutineScheduler() within an // execute, the idle task hook can call vCoRoutineSchedule() within an
// infinite loop. // infinite loop.
void vApplicationIdleHook( void ) void vApplicationIdleHook( void )
{ {

View file

@ -76,6 +76,7 @@ BaseType_t MPU_xTaskGenericNotify( TaskHandle_t xTaskToNotify, uint32_t ulValue,
BaseType_t MPU_xTaskNotifyWait( uint32_t ulBitsToClearOnEntry, uint32_t ulBitsToClearOnExit, uint32_t *pulNotificationValue, TickType_t xTicksToWait ) FREERTOS_SYSTEM_CALL; BaseType_t MPU_xTaskNotifyWait( uint32_t ulBitsToClearOnEntry, uint32_t ulBitsToClearOnExit, uint32_t *pulNotificationValue, TickType_t xTicksToWait ) FREERTOS_SYSTEM_CALL;
uint32_t MPU_ulTaskNotifyTake( BaseType_t xClearCountOnExit, TickType_t xTicksToWait ) FREERTOS_SYSTEM_CALL; uint32_t MPU_ulTaskNotifyTake( BaseType_t xClearCountOnExit, TickType_t xTicksToWait ) FREERTOS_SYSTEM_CALL;
BaseType_t MPU_xTaskNotifyStateClear( TaskHandle_t xTask ) FREERTOS_SYSTEM_CALL; BaseType_t MPU_xTaskNotifyStateClear( TaskHandle_t xTask ) FREERTOS_SYSTEM_CALL;
uint32_t MPU_ulTaskNotifyValueClear( TaskHandle_t xTask, uint32_t ulBitsToClear ) FREERTOS_SYSTEM_CALL;
BaseType_t MPU_xTaskIncrementTick( void ) FREERTOS_SYSTEM_CALL; BaseType_t MPU_xTaskIncrementTick( void ) FREERTOS_SYSTEM_CALL;
TaskHandle_t MPU_xTaskGetCurrentTaskHandle( void ) FREERTOS_SYSTEM_CALL; TaskHandle_t MPU_xTaskGetCurrentTaskHandle( void ) FREERTOS_SYSTEM_CALL;
void MPU_vTaskSetTimeOutState( TimeOut_t * const pxTimeOut ) FREERTOS_SYSTEM_CALL; void MPU_vTaskSetTimeOutState( TimeOut_t * const pxTimeOut ) FREERTOS_SYSTEM_CALL;
@ -123,6 +124,7 @@ TaskHandle_t MPU_xTimerGetTimerDaemonTaskHandle( void ) FREERTOS_SYSTEM_CALL;
BaseType_t MPU_xTimerPendFunctionCall( PendedFunction_t xFunctionToPend, void *pvParameter1, uint32_t ulParameter2, TickType_t xTicksToWait ) FREERTOS_SYSTEM_CALL; BaseType_t MPU_xTimerPendFunctionCall( PendedFunction_t xFunctionToPend, void *pvParameter1, uint32_t ulParameter2, TickType_t xTicksToWait ) FREERTOS_SYSTEM_CALL;
const char * MPU_pcTimerGetName( TimerHandle_t xTimer ) FREERTOS_SYSTEM_CALL; const char * MPU_pcTimerGetName( TimerHandle_t xTimer ) FREERTOS_SYSTEM_CALL;
void MPU_vTimerSetReloadMode( TimerHandle_t xTimer, const UBaseType_t uxAutoReload ) FREERTOS_SYSTEM_CALL; void MPU_vTimerSetReloadMode( TimerHandle_t xTimer, const UBaseType_t uxAutoReload ) FREERTOS_SYSTEM_CALL;
UBaseType_t MPU_uxTimerGetReloadMode( TimerHandle_t xTimer ) FREERTOS_SYSTEM_CALL;
TickType_t MPU_xTimerGetPeriod( TimerHandle_t xTimer ) FREERTOS_SYSTEM_CALL; TickType_t MPU_xTimerGetPeriod( TimerHandle_t xTimer ) FREERTOS_SYSTEM_CALL;
TickType_t MPU_xTimerGetExpiryTime( TimerHandle_t xTimer ) FREERTOS_SYSTEM_CALL; TickType_t MPU_xTimerGetExpiryTime( TimerHandle_t xTimer ) FREERTOS_SYSTEM_CALL;
BaseType_t MPU_xTimerCreateTimerTask( void ) FREERTOS_SYSTEM_CALL; BaseType_t MPU_xTimerCreateTimerTask( void ) FREERTOS_SYSTEM_CALL;

View file

@ -82,6 +82,7 @@ only for ports that are using the MPU. */
#define xTaskNotifyWait MPU_xTaskNotifyWait #define xTaskNotifyWait MPU_xTaskNotifyWait
#define ulTaskNotifyTake MPU_ulTaskNotifyTake #define ulTaskNotifyTake MPU_ulTaskNotifyTake
#define xTaskNotifyStateClear MPU_xTaskNotifyStateClear #define xTaskNotifyStateClear MPU_xTaskNotifyStateClear
#define ulTaskNotifyValueClear MPU_ulTaskNotifyValueClear
#define xTaskCatchUpTicks MPU_xTaskCatchUpTicks #define xTaskCatchUpTicks MPU_xTaskCatchUpTicks
#define xTaskGetCurrentTaskHandle MPU_xTaskGetCurrentTaskHandle #define xTaskGetCurrentTaskHandle MPU_xTaskGetCurrentTaskHandle
@ -128,6 +129,7 @@ only for ports that are using the MPU. */
#define xTimerPendFunctionCall MPU_xTimerPendFunctionCall #define xTimerPendFunctionCall MPU_xTimerPendFunctionCall
#define pcTimerGetName MPU_pcTimerGetName #define pcTimerGetName MPU_pcTimerGetName
#define vTimerSetReloadMode MPU_vTimerSetReloadMode #define vTimerSetReloadMode MPU_vTimerSetReloadMode
#define uxTimerGetReloadMode MPU_uxTimerGetReloadMode
#define xTimerGetPeriod MPU_xTimerGetPeriod #define xTimerGetPeriod MPU_xTimerGetPeriod
#define xTimerGetExpiryTime MPU_xTimerGetExpiryTime #define xTimerGetExpiryTime MPU_xTimerGetExpiryTime
#define xTimerGenericCommand MPU_xTimerGenericCommand #define xTimerGenericCommand MPU_xTimerGenericCommand

View file

@ -43,7 +43,7 @@
* (such as xStreamBufferSend()) inside a critical section and set the send * (such as xStreamBufferSend()) inside a critical section and set the send
* block time to 0. Likewise, if there are to be multiple different readers * block time to 0. Likewise, if there are to be multiple different readers
* then the application writer must place each call to a reading API function * then the application writer must place each call to a reading API function
* (such as xStreamBufferRead()) inside a critical section section and set the * (such as xStreamBufferReceive()) inside a critical section section and set the
* receive block time to 0. * receive block time to 0.
* *
*/ */
@ -241,7 +241,7 @@ size_t xStreamBufferSend( StreamBufferHandle_t xStreamBuffer,
* (such as xStreamBufferSend()) inside a critical section and set the send * (such as xStreamBufferSend()) inside a critical section and set the send
* block time to 0. Likewise, if there are to be multiple different readers * block time to 0. Likewise, if there are to be multiple different readers
* then the application writer must place each call to a reading API function * then the application writer must place each call to a reading API function
* (such as xStreamBufferRead()) inside a critical section and set the receive * (such as xStreamBufferReceive()) inside a critical section and set the receive
* block time to 0. * block time to 0.
* *
* Use xStreamBufferSend() to write to a stream buffer from a task. Use * Use xStreamBufferSend() to write to a stream buffer from a task. Use
@ -339,7 +339,7 @@ size_t xStreamBufferSendFromISR( StreamBufferHandle_t xStreamBuffer,
* (such as xStreamBufferSend()) inside a critical section and set the send * (such as xStreamBufferSend()) inside a critical section and set the send
* block time to 0. Likewise, if there are to be multiple different readers * block time to 0. Likewise, if there are to be multiple different readers
* then the application writer must place each call to a reading API function * then the application writer must place each call to a reading API function
* (such as xStreamBufferRead()) inside a critical section and set the receive * (such as xStreamBufferReceive()) inside a critical section and set the receive
* block time to 0. * block time to 0.
* *
* Use xStreamBufferSend() to write to a stream buffer from a task. Use * Use xStreamBufferSend() to write to a stream buffer from a task. Use
@ -439,7 +439,7 @@ size_t xStreamBufferReceive( StreamBufferHandle_t xStreamBuffer,
* (such as xStreamBufferSend()) inside a critical section and set the send * (such as xStreamBufferSend()) inside a critical section and set the send
* block time to 0. Likewise, if there are to be multiple different readers * block time to 0. Likewise, if there are to be multiple different readers
* then the application writer must place each call to a reading API function * then the application writer must place each call to a reading API function
* (such as xStreamBufferRead()) inside a critical section and set the receive * (such as xStreamBufferReceive()) inside a critical section and set the receive
* block time to 0. * block time to 0.
* *
* Use xStreamBufferReceive() to read from a stream buffer from a task. Use * Use xStreamBufferReceive() to read from a stream buffer from a task. Use

View file

@ -314,13 +314,13 @@ is used in assert() statements. */
// an automatic stack variable it might no longer exist, or at least have been corrupted, by the time // an automatic stack variable it might no longer exist, or at least have been corrupted, by the time
// the new task attempts to access it. // the new task attempts to access it.
xTaskCreate( vTaskCode, "NAME", STACK_SIZE, &ucParameterToPass, tskIDLE_PRIORITY, &xHandle ); xTaskCreate( vTaskCode, "NAME", STACK_SIZE, &ucParameterToPass, tskIDLE_PRIORITY, &xHandle );
configASSERT( xHandle ); configASSERT( xHandle );
// Use the handle to delete the task. // Use the handle to delete the task.
if( xHandle != NULL ) if( xHandle != NULL )
{ {
vTaskDelete( xHandle ); vTaskDelete( xHandle );
} }
} }
</pre> </pre>
* \defgroup xTaskCreate xTaskCreate * \defgroup xTaskCreate xTaskCreate
@ -498,9 +498,9 @@ static const TaskParameters_t xCheckTaskParameters =
// for full information. // for full information.
{ {
// Base address Length Parameters // Base address Length Parameters
{ cReadWriteArray, 32, portMPU_REGION_READ_WRITE }, { cReadWriteArray, 32, portMPU_REGION_READ_WRITE },
{ cReadOnlyArray, 32, portMPU_REGION_READ_ONLY }, { cReadOnlyArray, 32, portMPU_REGION_READ_ONLY },
{ cPrivilegedOnlyAccessArray, 128, portMPU_REGION_PRIVILEGED_READ_WRITE } { cPrivilegedOnlyAccessArray, 128, portMPU_REGION_PRIVILEGED_READ_WRITE }
} }
}; };
@ -584,9 +584,9 @@ static const TaskParameters_t xCheckTaskParameters =
// for full information. // for full information.
{ {
// Base address Length Parameters // Base address Length Parameters
{ cReadWriteArray, 32, portMPU_REGION_READ_WRITE }, { cReadWriteArray, 32, portMPU_REGION_READ_WRITE },
{ cReadOnlyArray, 32, portMPU_REGION_READ_ONLY }, { cReadOnlyArray, 32, portMPU_REGION_READ_ONLY },
{ cPrivilegedOnlyAccessArray, 128, portMPU_REGION_PRIVILEGED_READ_WRITE } { cPrivilegedOnlyAccessArray, 128, portMPU_REGION_PRIVILEGED_READ_WRITE }
} }
&xTaskBuffer; // Holds the task's data structure. &xTaskBuffer; // Holds the task's data structure.
@ -841,6 +841,39 @@ void vTaskDelayUntil( TickType_t * const pxPreviousWakeTime, const TickType_t xT
*/ */
BaseType_t xTaskAbortDelay( TaskHandle_t xTask ) PRIVILEGED_FUNCTION; BaseType_t xTaskAbortDelay( TaskHandle_t xTask ) PRIVILEGED_FUNCTION;
/**
* task. h
* <pre>BaseType_t xTaskAbortDelayFromISR( TaskHandle_t xTask, BaseType_t * const pxHigherPriorityTaskWoken )</pre>
*
* INCLUDE_xTaskAbortDelay must be defined as 1 in FreeRTOSConfig.h for this
* function to be available.
*
* A version of xTaskAbortDelay() that can be used from an interrupt service routine.
*
* A task will enter the Blocked state when it is waiting for an event. The
* event it is waiting for can be a temporal event (waiting for a time), such
* as when vTaskDelay() is called, or an event on an object, such as when
* xQueueReceive() or ulTaskNotifyTake() is called. If the handle of a task
* that is in the Blocked state is used in a call to xTaskAbortDelay() then the
* task will leave the Blocked state, and return from whichever function call
* placed the task into the Blocked state.
*
* @param xTask The handle of the task to remove from the Blocked state.
*
* @param pxHigherPriorityTaskWoken xTaskAbortDelayFromISR() will set
* *pxHigherPriorityTaskWoken to pdTRUE if a task was removed from the Blocked state,
* and the task that was removed from the Blocked state has a priority higher than the
* currently running task. If xTaskAbortDelayFromISR() sets this value to pdTRUE then
* a context switch should be requested before the interrupt is exited.
*
* @return If the task referenced by xTask was not in the Blocked state then
* pdFAIL is returned. Otherwise pdPASS is returned.
*
* \defgroup xTaskAbortDelay xTaskAbortDelayFromISR
* \ingroup TaskCtrl
*/
BaseType_t xTaskAbortDelayFromISR( TaskHandle_t xTask, BaseType_t * const pxHigherPriorityTaskWoken ) PRIVILEGED_FUNCTION;
/** /**
* task. h * task. h
* <pre>UBaseType_t uxTaskPriorityGet( const TaskHandle_t xTask );</pre> * <pre>UBaseType_t uxTaskPriorityGet( const TaskHandle_t xTask );</pre>
@ -2201,6 +2234,121 @@ uint32_t ulTaskNotifyTake( BaseType_t xClearCountOnExit, TickType_t xTicksToWait
*/ */
BaseType_t xTaskNotifyStateClear( TaskHandle_t xTask ); BaseType_t xTaskNotifyStateClear( TaskHandle_t xTask );
/**
* task. h
* <PRE>uint32_t ulTaskNotifyValueClear( TaskHandle_t xTask, uint32_t ulBitsToClear );</pre>
*
* Clears the bits specified by the ulBitsToClear bit mask in the notification
* value of the task referenced by xTask.
*
* Set ulBitsToClear to to 0xffffffff (UINT_MAX on 32-bit architectures) to clear
* the notification value to 0. Set ulBitsToClear to 0 to query the task's
* notification value without clearing any bits.
*
* @return The value of the target task's notification value before the bits
* specified by ulBitsToClear were cleared.
* \defgroup ulTaskNotifyValueClear ulTaskNotifyValueClear
* \ingroup TaskNotifications
*/
uint32_t ulTaskNotifyValueClear( TaskHandle_t xTask, uint32_t ulBitsToClear ) PRIVILEGED_FUNCTION;
/**
* task.h
* <pre>void vTaskSetTimeOutState( TimeOut_t * const pxTimeOut )</pre>
*
* Capture the current time for future use with xTaskCheckForTimeOut().
*
* @param pxTimeOut Pointer to a timeout object into which the current time
* is to be captured. The captured time includes the tick count and the number
* of times the tick count has overflowed since the system first booted.
* \defgroup vTaskSetTimeOutState vTaskSetTimeOutState
* \ingroup TaskCtrl
*/
void vTaskSetTimeOutState( TimeOut_t * const pxTimeOut ) PRIVILEGED_FUNCTION;
/**
* task.h
* <pre>BaseType_t xTaskCheckForTimeOut( TimeOut_t * const pxTimeOut, TickType_t * const pxTicksToWait );</pre>
*
* Determines if pxTicksToWait ticks has passed since a time was captured
* using a call to vTaskSetTimeOutState(). The captured time includes the tick
* count and the number of times the tick count has overflowed.
*
* @param pxTimeOut The time status as captured previously using
* vTaskSetTimeOutState. If the timeout has not yet occurred, it is updated
* to reflect the current time status.
* @param pxTicksToWait The number of ticks to check for timeout i.e. if
* pxTicksToWait ticks have passed since pxTimeOut was last updated (either by
* vTaskSetTimeOutState() or xTaskCheckForTimeOut()), the timeout has occurred.
* If the timeout has not occurred, pxTIcksToWait is updated to reflect the
* number of remaining ticks.
*
* @return If timeout has occurred, pdTRUE is returned. Otherwise pdFALSE is
* returned and pxTicksToWait is updated to reflect the number of remaining
* ticks.
*
* @see https://www.freertos.org/xTaskCheckForTimeOut.html
*
* Example Usage:
* <pre>
// Driver library function used to receive uxWantedBytes from an Rx buffer
// that is filled by a UART interrupt. If there are not enough bytes in the
// Rx buffer then the task enters the Blocked state until it is notified that
// more data has been placed into the buffer. If there is still not enough
// data then the task re-enters the Blocked state, and xTaskCheckForTimeOut()
// is used to re-calculate the Block time to ensure the total amount of time
// spent in the Blocked state does not exceed MAX_TIME_TO_WAIT. This
// continues until either the buffer contains at least uxWantedBytes bytes,
// or the total amount of time spent in the Blocked state reaches
// MAX_TIME_TO_WAIT at which point the task reads however many bytes are
// available up to a maximum of uxWantedBytes.
size_t xUART_Receive( uint8_t *pucBuffer, size_t uxWantedBytes )
{
size_t uxReceived = 0;
TickType_t xTicksToWait = MAX_TIME_TO_WAIT;
TimeOut_t xTimeOut;
// Initialize xTimeOut. This records the time at which this function
// was entered.
vTaskSetTimeOutState( &xTimeOut );
// Loop until the buffer contains the wanted number of bytes, or a
// timeout occurs.
while( UART_bytes_in_rx_buffer( pxUARTInstance ) < uxWantedBytes )
{
// The buffer didn't contain enough data so this task is going to
// enter the Blocked state. Adjusting xTicksToWait to account for
// any time that has been spent in the Blocked state within this
// function so far to ensure the total amount of time spent in the
// Blocked state does not exceed MAX_TIME_TO_WAIT.
if( xTaskCheckForTimeOut( &xTimeOut, &xTicksToWait ) != pdFALSE )
{
//Timed out before the wanted number of bytes were available,
// exit the loop.
break;
}
// Wait for a maximum of xTicksToWait ticks to be notified that the
// receive interrupt has placed more data into the buffer.
ulTaskNotifyTake( pdTRUE, xTicksToWait );
}
// Attempt to read uxWantedBytes from the receive buffer into pucBuffer.
// The actual number of bytes read (which might be less than
// uxWantedBytes) is returned.
uxReceived = UART_read_from_receive_buffer( pxUARTInstance,
pucBuffer,
uxWantedBytes );
return uxReceived;
}
</pre>
* \defgroup xTaskCheckForTimeOut xTaskCheckForTimeOut
* \ingroup TaskCtrl
*/
BaseType_t xTaskCheckForTimeOut( TimeOut_t * const pxTimeOut, TickType_t * const pxTicksToWait ) PRIVILEGED_FUNCTION;
/*----------------------------------------------------------- /*-----------------------------------------------------------
* SCHEDULER INTERNALS AVAILABLE FOR PORTING PURPOSES * SCHEDULER INTERNALS AVAILABLE FOR PORTING PURPOSES
*----------------------------------------------------------*/ *----------------------------------------------------------*/
@ -2317,17 +2465,6 @@ TickType_t uxTaskResetEventItemValue( void ) PRIVILEGED_FUNCTION;
*/ */
TaskHandle_t xTaskGetCurrentTaskHandle( void ) PRIVILEGED_FUNCTION; TaskHandle_t xTaskGetCurrentTaskHandle( void ) PRIVILEGED_FUNCTION;
/*
* Capture the current time status for future reference.
*/
void vTaskSetTimeOutState( TimeOut_t * const pxTimeOut ) PRIVILEGED_FUNCTION;
/*
* Compare the time status now with that previously captured to see if the
* timeout has expired.
*/
BaseType_t xTaskCheckForTimeOut( TimeOut_t * const pxTimeOut, TickType_t * const pxTicksToWait ) PRIVILEGED_FUNCTION;
/* /*
* Shortcut used by the queue implementation to prevent unnecessary call to * Shortcut used by the queue implementation to prevent unnecessary call to
* taskYIELD(); * taskYIELD();

View file

@ -1234,8 +1234,8 @@ const char * pcTimerGetName( TimerHandle_t xTimer ) PRIVILEGED_FUNCTION; /*lint
/** /**
* void vTimerSetReloadMode( TimerHandle_t xTimer, const UBaseType_t uxAutoReload ); * void vTimerSetReloadMode( TimerHandle_t xTimer, const UBaseType_t uxAutoReload );
* *
* Updates a timer to be either an autoreload timer, in which case the timer * Updates a timer to be either an auto-reload timer, in which case the timer
* automatically resets itself each time it expires, or a one shot timer, in * automatically resets itself each time it expires, or a one-shot timer, in
* which case the timer will only expire once unless it is manually restarted. * which case the timer will only expire once unless it is manually restarted.
* *
* @param xTimer The handle of the timer being updated. * @param xTimer The handle of the timer being updated.
@ -1248,6 +1248,20 @@ const char * pcTimerGetName( TimerHandle_t xTimer ) PRIVILEGED_FUNCTION; /*lint
*/ */
void vTimerSetReloadMode( TimerHandle_t xTimer, const UBaseType_t uxAutoReload ) PRIVILEGED_FUNCTION; void vTimerSetReloadMode( TimerHandle_t xTimer, const UBaseType_t uxAutoReload ) PRIVILEGED_FUNCTION;
/**
* UBaseType_t uxTimerGetReloadMode( TimerHandle_t xTimer );
*
* Queries a timer to determine if it is an auto-reload timer, in which case the timer
* automatically resets itself each time it expires, or a one-shot timer, in
* which case the timer will only expire once unless it is manually restarted.
*
* @param xTimer The handle of the timer being queried.
*
* @return If the timer is an auto-reload timer then pdTRUE is returned, otherwise
* pdFALSE is returned.
*/
UBaseType_t uxTimerGetReloadMode( TimerHandle_t xTimer ) PRIVILEGED_FUNCTION;
/** /**
* TickType_t xTimerGetPeriod( TimerHandle_t xTimer ); * TickType_t xTimerGetPeriod( TimerHandle_t xTimer );
* *

View file

@ -0,0 +1,2 @@
The FreeRTOS GCC port layer also builds and works with the ARMClang compiler.
To use the ARMClang compiler build the port files from FreeRTOS/Source/portable/GCC.

View file

@ -210,13 +210,6 @@ uint32_t ulSetInterruptMaskFromISR( void ) /* __attribute__(( naked )) PRIVILEGE
" bx lr \n" " bx lr \n"
::: "memory" ::: "memory"
); );
#if !defined (__ARMCC_VERSION) && (__ARMCC_VERSION >= 6010050)
/* To avoid compiler warnings. The return statement will never be reached,
* but some compilers warn if it is not included, while others won't compile
* if it is. */
return 0;
#endif
} }
/*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/
@ -228,14 +221,6 @@ void vClearInterruptMaskFromISR( __attribute__( ( unused ) ) uint32_t ulMask ) /
" bx lr \n" " bx lr \n"
::: "memory" ::: "memory"
); );
#if !defined (__ARMCC_VERSION) && (__ARMCC_VERSION >= 6010050)
/* Just to avoid compiler warning. ulMask is used from the asm code but
* the compiler can't see that. Some compilers generate warnings without
* the following line, while others generate warnings if the line is
* included. */
( void ) ulMask;
#endif
} }
/*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/

View file

@ -205,13 +205,6 @@ uint32_t ulSetInterruptMaskFromISR( void ) /* __attribute__(( naked )) PRIVILEGE
" bx lr \n" " bx lr \n"
::: "memory" ::: "memory"
); );
#if !defined (__ARMCC_VERSION) && (__ARMCC_VERSION >= 6010050)
/* To avoid compiler warnings. The return statement will never be reached,
* but some compilers warn if it is not included, while others won't compile
* if it is. */
return 0;
#endif
} }
/*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/
@ -223,14 +216,6 @@ void vClearInterruptMaskFromISR( __attribute__( ( unused ) ) uint32_t ulMask ) /
" bx lr \n" " bx lr \n"
::: "memory" ::: "memory"
); );
#if !defined (__ARMCC_VERSION) && (__ARMCC_VERSION >= 6010050)
/* Just to avoid compiler warning. ulMask is used from the asm code but
* the compiler can't see that. Some compilers generate warnings without
* the following line, while others generate warnings if the line is
* included. */
( void ) ulMask;
#endif
} }
/*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/

View file

@ -185,13 +185,6 @@ uint32_t ulSetInterruptMaskFromISR( void ) /* __attribute__(( naked )) PRIVILEGE
" bx lr \n" " bx lr \n"
::: "memory" ::: "memory"
); );
#if !defined (__ARMCC_VERSION) && (__ARMCC_VERSION >= 6010050)
/* To avoid compiler warnings. The return statement will never be reached,
* but some compilers warn if it is not included, while others won't compile
* if it is. */
return 0;
#endif
} }
/*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/
@ -203,14 +196,6 @@ void vClearInterruptMaskFromISR( __attribute__( ( unused ) ) uint32_t ulMask ) /
" bx lr \n" " bx lr \n"
::: "memory" ::: "memory"
); );
#if !defined (__ARMCC_VERSION) && (__ARMCC_VERSION >= 6010050)
/* Just to avoid compiler warning. ulMask is used from the asm code but
* the compiler can't see that. Some compilers generate warnings without
* the following line, while others generate warnings if the line is
* included. */
( void ) ulMask;
#endif
} }
/*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/

View file

@ -180,13 +180,6 @@ uint32_t ulSetInterruptMaskFromISR( void ) /* __attribute__(( naked )) PRIVILEGE
" bx lr \n" " bx lr \n"
::: "memory" ::: "memory"
); );
#if !defined (__ARMCC_VERSION) && (__ARMCC_VERSION >= 6010050)
/* To avoid compiler warnings. The return statement will never be reached,
* but some compilers warn if it is not included, while others won't compile
* if it is. */
return 0;
#endif
} }
/*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/
@ -198,14 +191,6 @@ void vClearInterruptMaskFromISR( __attribute__( ( unused ) ) uint32_t ulMask ) /
" bx lr \n" " bx lr \n"
::: "memory" ::: "memory"
); );
#if !defined (__ARMCC_VERSION) && (__ARMCC_VERSION >= 6010050)
/* Just to avoid compiler warning. ulMask is used from the asm code but
* the compiler can't see that. Some compilers generate warnings without
* the following line, while others generate warnings if the line is
* included. */
( void ) ulMask;
#endif
} }
/*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/

View file

@ -292,6 +292,13 @@ typedef struct MPU_SETTINGS
#define portMEMORY_BARRIER() __asm volatile( "" ::: "memory" ) #define portMEMORY_BARRIER() __asm volatile( "" ::: "memory" )
/*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/
/* Suppress warnings that are generated by the IAR tools, but cannot be fixed in
* the source code because to do so would cause other compilers to generate
* warnings. */
#pragma diag_suppress=Be006
#pragma diag_suppress=Pa082
/*-----------------------------------------------------------*/
#ifdef __cplusplus #ifdef __cplusplus
} }
#endif #endif

View file

@ -292,6 +292,13 @@ typedef struct MPU_SETTINGS
#define portMEMORY_BARRIER() __asm volatile( "" ::: "memory" ) #define portMEMORY_BARRIER() __asm volatile( "" ::: "memory" )
/*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/
/* Suppress warnings that are generated by the IAR tools, but cannot be fixed in
* the source code because to do so would cause other compilers to generate
* warnings. */
#pragma diag_suppress=Be006
#pragma diag_suppress=Pa082
/*-----------------------------------------------------------*/
#ifdef __cplusplus #ifdef __cplusplus
} }
#endif #endif

View file

@ -292,6 +292,13 @@ typedef struct MPU_SETTINGS
#define portMEMORY_BARRIER() __asm volatile( "" ::: "memory" ) #define portMEMORY_BARRIER() __asm volatile( "" ::: "memory" )
/*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/
/* Suppress warnings that are generated by the IAR tools, but cannot be fixed in
* the source code because to do so would cause other compilers to generate
* warnings. */
#pragma diag_suppress=Be006
#pragma diag_suppress=Pa082
/*-----------------------------------------------------------*/
#ifdef __cplusplus #ifdef __cplusplus
} }
#endif #endif

View file

@ -292,6 +292,13 @@ typedef struct MPU_SETTINGS
#define portMEMORY_BARRIER() __asm volatile( "" ::: "memory" ) #define portMEMORY_BARRIER() __asm volatile( "" ::: "memory" )
/*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/
/* Suppress warnings that are generated by the IAR tools, but cannot be fixed in
* the source code because to do so would cause other compilers to generate
* warnings. */
#pragma diag_suppress=Be006
#pragma diag_suppress=Pa082
/*-----------------------------------------------------------*/
#ifdef __cplusplus #ifdef __cplusplus
} }
#endif #endif

View file

@ -586,6 +586,19 @@ BaseType_t xRunningPrivileged = xPortRaisePrivilege();
#endif #endif
/*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/
#if( configUSE_TASK_NOTIFICATIONS == 1 )
uint32_t MPU_ulTaskNotifyValueClear( TaskHandle_t xTask, uint32_t ulBitsToClear ) /* FREERTOS_SYSTEM_CALL */
{
uint32_t ulReturn;
BaseType_t xRunningPrivileged = xPortRaisePrivilege();
ulReturn = ulTaskNotifyValueClear( xTask, ulBitsToClear );
vPortResetPrivilege( xRunningPrivileged );
return ulReturn;
}
#endif
/*-----------------------------------------------------------*/
#if( configSUPPORT_DYNAMIC_ALLOCATION == 1 ) #if( configSUPPORT_DYNAMIC_ALLOCATION == 1 )
QueueHandle_t MPU_xQueueGenericCreate( UBaseType_t uxQueueLength, UBaseType_t uxItemSize, uint8_t ucQueueType ) /* FREERTOS_SYSTEM_CALL */ QueueHandle_t MPU_xQueueGenericCreate( UBaseType_t uxQueueLength, UBaseType_t uxItemSize, uint8_t ucQueueType ) /* FREERTOS_SYSTEM_CALL */
{ {
@ -1041,6 +1054,19 @@ BaseType_t xRunningPrivileged = xPortRaisePrivilege();
#endif #endif
/*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/
#if( configUSE_TIMERS == 1 )
UBaseType_t MPU_uxTimerGetReloadMode( TimerHandle_t xTimer )
{
BaseType_t xRunningPrivileged = xPortRaisePrivilege();
UBaseType_t uxReturn;
uxReturn = uxTimerGetReloadMode( xTimer );
vPortResetPrivilege( xRunningPrivileged );
return uxReturn;
}
#endif
/*-----------------------------------------------------------*/
#if( configUSE_TIMERS == 1 ) #if( configUSE_TIMERS == 1 )
const char * MPU_pcTimerGetName( TimerHandle_t xTimer ) /* FREERTOS_SYSTEM_CALL */ const char * MPU_pcTimerGetName( TimerHandle_t xTimer ) /* FREERTOS_SYSTEM_CALL */
{ {

View file

@ -34,15 +34,16 @@
#include "task.h" #include "task.h"
/* Constants required to manipulate the NVIC. */ /* Constants required to manipulate the NVIC. */
#define portNVIC_SYSTICK_CTRL ( ( volatile uint32_t * ) 0xe000e010 ) #define portNVIC_SYSTICK_CTRL_REG ( * ( ( volatile uint32_t * ) 0xe000e010 ) )
#define portNVIC_SYSTICK_LOAD ( ( volatile uint32_t * ) 0xe000e014 ) #define portNVIC_SYSTICK_LOAD_REG ( * ( ( volatile uint32_t * ) 0xe000e014 ) )
#define portNVIC_SYSTICK_CURRENT_VALUE ( ( volatile uint32_t * ) 0xe000e018 ) #define portNVIC_SYSTICK_CURRENT_VALUE_REG ( * ( ( volatile uint32_t * ) 0xe000e018 ) )
#define portNVIC_INT_CTRL ( ( volatile uint32_t *) 0xe000ed04 ) #define portNVIC_INT_CTRL_REG ( * ( ( volatile uint32_t * ) 0xe000ed04 ) )
#define portNVIC_SYSPRI2 ( ( volatile uint32_t *) 0xe000ed20 ) #define portNVIC_SYSPRI2_REG ( * ( ( volatile uint32_t * ) 0xe000ed20 ) )
#define portNVIC_SYSTICK_CLK 0x00000004 #define portNVIC_SYSTICK_CLK_BIT ( 1UL << 2UL )
#define portNVIC_SYSTICK_INT 0x00000002 #define portNVIC_SYSTICK_INT_BIT ( 1UL << 1UL )
#define portNVIC_SYSTICK_ENABLE 0x00000001 #define portNVIC_SYSTICK_ENABLE_BIT ( 1UL << 0UL )
#define portNVIC_PENDSVSET 0x10000000 #define portNVIC_SYSTICK_COUNT_FLAG_BIT ( 1UL << 16UL )
#define portNVIC_PENDSVSET_BIT ( 1UL << 28UL )
#define portMIN_INTERRUPT_PRIORITY ( 255UL ) #define portMIN_INTERRUPT_PRIORITY ( 255UL )
#define portNVIC_PENDSV_PRI ( portMIN_INTERRUPT_PRIORITY << 16UL ) #define portNVIC_PENDSV_PRI ( portMIN_INTERRUPT_PRIORITY << 16UL )
#define portNVIC_SYSTICK_PRI ( portMIN_INTERRUPT_PRIORITY << 24UL ) #define portNVIC_SYSTICK_PRI ( portMIN_INTERRUPT_PRIORITY << 24UL )
@ -50,6 +51,16 @@
/* Constants required to set up the initial stack. */ /* Constants required to set up the initial stack. */
#define portINITIAL_XPSR ( 0x01000000 ) #define portINITIAL_XPSR ( 0x01000000 )
/* The systick is a 24-bit counter. */
#define portMAX_24_BIT_NUMBER ( 0xffffffUL )
/* A fiddle factor to estimate the number of SysTick counts that would have
occurred while the SysTick counter is stopped during tickless idle
calculations. */
#ifndef portMISSED_COUNTS_FACTOR
#define portMISSED_COUNTS_FACTOR ( 45UL )
#endif
/* Let the user override the pre-loading of the initial LR with the address of /* Let the user override the pre-loading of the initial LR with the address of
prvTaskExitError() in case it messes up unwinding of the stack in the prvTaskExitError() in case it messes up unwinding of the stack in the
debugger. */ debugger. */
@ -60,9 +71,11 @@ debugger. */
#endif #endif
/* /*
* Setup the timer to generate the tick interrupts. * Setup the timer to generate the tick interrupts. The implementation in this
* file is weak to allow application writers to change the timer used to
* generate the tick interrupt.
*/ */
static void prvSetupTimerInterrupt( void ); void vPortSetupTimerInterrupt( void );
/* /*
* Exception handlers. * Exception handlers.
@ -89,6 +102,31 @@ static UBaseType_t uxCriticalNesting = 0xaaaaaaaa;
/*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/
/*
* The number of SysTick increments that make up one tick period.
*/
#if( configUSE_TICKLESS_IDLE == 1 )
static uint32_t ulTimerCountsForOneTick = 0;
#endif /* configUSE_TICKLESS_IDLE */
/*
* The maximum number of tick periods that can be suppressed is limited by the
* 24 bit resolution of the SysTick timer.
*/
#if( configUSE_TICKLESS_IDLE == 1 )
static uint32_t xMaximumPossibleSuppressedTicks = 0;
#endif /* configUSE_TICKLESS_IDLE */
/*
* Compensate for the CPU cycles that pass while the SysTick is stopped (low
* power functionality only.
*/
#if( configUSE_TICKLESS_IDLE == 1 )
static uint32_t ulStoppedTimerCompensation = 0;
#endif /* configUSE_TICKLESS_IDLE */
/*-----------------------------------------------------------*/
/* /*
* See header file for description. * See header file for description.
*/ */
@ -176,12 +214,12 @@ void vPortStartFirstTask( void )
BaseType_t xPortStartScheduler( void ) BaseType_t xPortStartScheduler( void )
{ {
/* Make PendSV, CallSV and SysTick the same priority as the kernel. */ /* Make PendSV, CallSV and SysTick the same priority as the kernel. */
*(portNVIC_SYSPRI2) |= portNVIC_PENDSV_PRI; portNVIC_SYSPRI2_REG |= portNVIC_PENDSV_PRI;
*(portNVIC_SYSPRI2) |= portNVIC_SYSTICK_PRI; portNVIC_SYSPRI2_REG |= portNVIC_SYSTICK_PRI;
/* Start the timer that generates the tick ISR. Interrupts are disabled /* Start the timer that generates the tick ISR. Interrupts are disabled
here already. */ here already. */
prvSetupTimerInterrupt(); vPortSetupTimerInterrupt();
/* Initialise the critical nesting count ready for the first task. */ /* Initialise the critical nesting count ready for the first task. */
uxCriticalNesting = 0; uxCriticalNesting = 0;
@ -214,7 +252,7 @@ void vPortEndScheduler( void )
void vPortYield( void ) void vPortYield( void )
{ {
/* Set a PendSV to request a context switch. */ /* Set a PendSV to request a context switch. */
*( portNVIC_INT_CTRL ) = portNVIC_PENDSVSET; portNVIC_INT_CTRL_REG = portNVIC_PENDSVSET_BIT;
/* Barriers are normally not required but do ensure the code is completely /* Barriers are normally not required but do ensure the code is completely
within the specified behaviour for the architecture. */ within the specified behaviour for the architecture. */
@ -225,8 +263,8 @@ void vPortYield( void )
void vPortEnterCritical( void ) void vPortEnterCritical( void )
{ {
portDISABLE_INTERRUPTS(); portDISABLE_INTERRUPTS();
uxCriticalNesting++; uxCriticalNesting++;
__asm volatile( "dsb" ::: "memory" ); __asm volatile( "dsb" ::: "memory" );
__asm volatile( "isb" ); __asm volatile( "isb" );
} }
@ -235,11 +273,11 @@ void vPortEnterCritical( void )
void vPortExitCritical( void ) void vPortExitCritical( void )
{ {
configASSERT( uxCriticalNesting ); configASSERT( uxCriticalNesting );
uxCriticalNesting--; uxCriticalNesting--;
if( uxCriticalNesting == 0 ) if( uxCriticalNesting == 0 )
{ {
portENABLE_INTERRUPTS(); portENABLE_INTERRUPTS();
} }
} }
/*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/
@ -251,13 +289,6 @@ uint32_t ulSetInterruptMaskFromISR( void )
" bx lr " " bx lr "
::: "memory" ::: "memory"
); );
#if !defined (__ARMCC_VERSION) && (__ARMCC_VERSION >= 6010050)
/* To avoid compiler warnings. The return statement will nevere be reached,
but some compilers warn if it is not included, while others won't compile if
it is. */
return 0;
#endif
} }
/*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/
@ -268,13 +299,6 @@ void vClearInterruptMaskFromISR( __attribute__( ( unused ) ) uint32_t ulMask )
" bx lr " " bx lr "
::: "memory" ::: "memory"
); );
#if !defined (__ARMCC_VERSION) && (__ARMCC_VERSION >= 6010050)
/* Just to avoid compiler warning. ulMask is used from the asm code but
the compiler can't see that. Some compilers generate warnings without the
following line, while others generate warnings if the line is included. */
( void ) ulMask;
#endif
} }
/*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/
@ -337,7 +361,7 @@ uint32_t ulPreviousMask;
if( xTaskIncrementTick() != pdFALSE ) if( xTaskIncrementTick() != pdFALSE )
{ {
/* Pend a context switch. */ /* Pend a context switch. */
*(portNVIC_INT_CTRL) = portNVIC_PENDSVSET; portNVIC_INT_CTRL_REG = portNVIC_PENDSVSET_BIT;
} }
} }
portCLEAR_INTERRUPT_MASK_FROM_ISR( ulPreviousMask ); portCLEAR_INTERRUPT_MASK_FROM_ISR( ulPreviousMask );
@ -348,15 +372,189 @@ uint32_t ulPreviousMask;
* Setup the systick timer to generate the tick interrupts at the required * Setup the systick timer to generate the tick interrupts at the required
* frequency. * frequency.
*/ */
void prvSetupTimerInterrupt( void ) __attribute__(( weak )) void vPortSetupTimerInterrupt( void )
{ {
/* Calculate the constants required to configure the tick interrupt. */
#if( configUSE_TICKLESS_IDLE == 1 )
{
ulTimerCountsForOneTick = ( configCPU_CLOCK_HZ / configTICK_RATE_HZ );
xMaximumPossibleSuppressedTicks = portMAX_24_BIT_NUMBER / ulTimerCountsForOneTick;
ulStoppedTimerCompensation = portMISSED_COUNTS_FACTOR;
}
#endif /* configUSE_TICKLESS_IDLE */
/* Stop and reset the SysTick. */ /* Stop and reset the SysTick. */
*(portNVIC_SYSTICK_CTRL) = 0UL; portNVIC_SYSTICK_CTRL_REG = 0UL;
*(portNVIC_SYSTICK_CURRENT_VALUE) = 0UL; portNVIC_SYSTICK_CURRENT_VALUE_REG = 0UL;
/* Configure SysTick to interrupt at the requested rate. */ /* Configure SysTick to interrupt at the requested rate. */
*(portNVIC_SYSTICK_LOAD) = ( configCPU_CLOCK_HZ / configTICK_RATE_HZ ) - 1UL; portNVIC_SYSTICK_LOAD_REG = ( configCPU_CLOCK_HZ / configTICK_RATE_HZ ) - 1UL;
*(portNVIC_SYSTICK_CTRL) = portNVIC_SYSTICK_CLK | portNVIC_SYSTICK_INT | portNVIC_SYSTICK_ENABLE; portNVIC_SYSTICK_CTRL_REG = portNVIC_SYSTICK_CLK_BIT | portNVIC_SYSTICK_INT_BIT | portNVIC_SYSTICK_ENABLE_BIT;
} }
/*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/
#if( configUSE_TICKLESS_IDLE == 1 )
__attribute__((weak)) void vPortSuppressTicksAndSleep( TickType_t xExpectedIdleTime )
{
uint32_t ulReloadValue, ulCompleteTickPeriods, ulCompletedSysTickDecrements;
TickType_t xModifiableIdleTime;
/* Make sure the SysTick reload value does not overflow the counter. */
if( xExpectedIdleTime > xMaximumPossibleSuppressedTicks )
{
xExpectedIdleTime = xMaximumPossibleSuppressedTicks;
}
/* Stop the SysTick momentarily. The time the SysTick is stopped for
is accounted for as best it can be, but using the tickless mode will
inevitably result in some tiny drift of the time maintained by the
kernel with respect to calendar time. */
portNVIC_SYSTICK_CTRL_REG &= ~portNVIC_SYSTICK_ENABLE_BIT;
/* Calculate the reload value required to wait xExpectedIdleTime
tick periods. -1 is used because this code will execute part way
through one of the tick periods. */
ulReloadValue = portNVIC_SYSTICK_CURRENT_VALUE_REG + ( ulTimerCountsForOneTick * ( xExpectedIdleTime - 1UL ) );
if( ulReloadValue > ulStoppedTimerCompensation )
{
ulReloadValue -= ulStoppedTimerCompensation;
}
/* Enter a critical section but don't use the taskENTER_CRITICAL()
method as that will mask interrupts that should exit sleep mode. */
__asm volatile( "cpsid i" ::: "memory" );
__asm volatile( "dsb" );
__asm volatile( "isb" );
/* If a context switch is pending or a task is waiting for the scheduler
to be unsuspended then abandon the low power entry. */
if( eTaskConfirmSleepModeStatus() == eAbortSleep )
{
/* Restart from whatever is left in the count register to complete
this tick period. */
portNVIC_SYSTICK_LOAD_REG = portNVIC_SYSTICK_CURRENT_VALUE_REG;
/* Restart SysTick. */
portNVIC_SYSTICK_CTRL_REG |= portNVIC_SYSTICK_ENABLE_BIT;
/* Reset the reload register to the value required for normal tick
periods. */
portNVIC_SYSTICK_LOAD_REG = ulTimerCountsForOneTick - 1UL;
/* Re-enable interrupts - see comments above the cpsid instruction()
above. */
__asm volatile( "cpsie i" ::: "memory" );
}
else
{
/* Set the new reload value. */
portNVIC_SYSTICK_LOAD_REG = ulReloadValue;
/* Clear the SysTick count flag and set the count value back to
zero. */
portNVIC_SYSTICK_CURRENT_VALUE_REG = 0UL;
/* Restart SysTick. */
portNVIC_SYSTICK_CTRL_REG |= portNVIC_SYSTICK_ENABLE_BIT;
/* Sleep until something happens. configPRE_SLEEP_PROCESSING() can
set its parameter to 0 to indicate that its implementation contains
its own wait for interrupt or wait for event instruction, and so wfi
should not be executed again. However, the original expected idle
time variable must remain unmodified, so a copy is taken. */
xModifiableIdleTime = xExpectedIdleTime;
configPRE_SLEEP_PROCESSING( xModifiableIdleTime );
if( xModifiableIdleTime > 0 )
{
__asm volatile( "dsb" ::: "memory" );
__asm volatile( "wfi" );
__asm volatile( "isb" );
}
configPOST_SLEEP_PROCESSING( xExpectedIdleTime );
/* Re-enable interrupts to allow the interrupt that brought the MCU
out of sleep mode to execute immediately. see comments above
__disable_interrupt() call above. */
__asm volatile( "cpsie i" ::: "memory" );
__asm volatile( "dsb" );
__asm volatile( "isb" );
/* Disable interrupts again because the clock is about to be stopped
and interrupts that execute while the clock is stopped will increase
any slippage between the time maintained by the RTOS and calendar
time. */
__asm volatile( "cpsid i" ::: "memory" );
__asm volatile( "dsb" );
__asm volatile( "isb" );
/* Disable the SysTick clock without reading the
portNVIC_SYSTICK_CTRL_REG register to ensure the
portNVIC_SYSTICK_COUNT_FLAG_BIT is not cleared if it is set. Again,
the time the SysTick is stopped for is accounted for as best it can
be, but using the tickless mode will inevitably result in some tiny
drift of the time maintained by the kernel with respect to calendar
time*/
portNVIC_SYSTICK_CTRL_REG = ( portNVIC_SYSTICK_CLK_BIT | portNVIC_SYSTICK_INT_BIT );
/* Determine if the SysTick clock has already counted to zero and
been set back to the current reload value (the reload back being
correct for the entire expected idle time) or if the SysTick is yet
to count to zero (in which case an interrupt other than the SysTick
must have brought the system out of sleep mode). */
if( ( portNVIC_SYSTICK_CTRL_REG & portNVIC_SYSTICK_COUNT_FLAG_BIT ) != 0 )
{
uint32_t ulCalculatedLoadValue;
/* The tick interrupt is already pending, and the SysTick count
reloaded with ulReloadValue. Reset the
portNVIC_SYSTICK_LOAD_REG with whatever remains of this tick
period. */
ulCalculatedLoadValue = ( ulTimerCountsForOneTick - 1UL ) - ( ulReloadValue - portNVIC_SYSTICK_CURRENT_VALUE_REG );
/* Don't allow a tiny value, or values that have somehow
underflowed because the post sleep hook did something
that took too long. */
if( ( ulCalculatedLoadValue < ulStoppedTimerCompensation ) || ( ulCalculatedLoadValue > ulTimerCountsForOneTick ) )
{
ulCalculatedLoadValue = ( ulTimerCountsForOneTick - 1UL );
}
portNVIC_SYSTICK_LOAD_REG = ulCalculatedLoadValue;
/* As the pending tick will be processed as soon as this
function exits, the tick value maintained by the tick is stepped
forward by one less than the time spent waiting. */
ulCompleteTickPeriods = xExpectedIdleTime - 1UL;
}
else
{
/* Something other than the tick interrupt ended the sleep.
Work out how long the sleep lasted rounded to complete tick
periods (not the ulReload value which accounted for part
ticks). */
ulCompletedSysTickDecrements = ( xExpectedIdleTime * ulTimerCountsForOneTick ) - portNVIC_SYSTICK_CURRENT_VALUE_REG;
/* How many complete tick periods passed while the processor
was waiting? */
ulCompleteTickPeriods = ulCompletedSysTickDecrements / ulTimerCountsForOneTick;
/* The reload value is set to whatever fraction of a single tick
period remains. */
portNVIC_SYSTICK_LOAD_REG = ( ( ulCompleteTickPeriods + 1UL ) * ulTimerCountsForOneTick ) - ulCompletedSysTickDecrements;
}
/* Restart SysTick so it runs from portNVIC_SYSTICK_LOAD_REG
again, then set portNVIC_SYSTICK_LOAD_REG back to its standard
value. */
portNVIC_SYSTICK_CURRENT_VALUE_REG = 0UL;
portNVIC_SYSTICK_CTRL_REG |= portNVIC_SYSTICK_ENABLE_BIT;
vTaskStepTick( ulCompleteTickPeriods );
portNVIC_SYSTICK_LOAD_REG = ulTimerCountsForOneTick - 1UL;
/* Exit with interrpts enabled. */
__asm volatile( "cpsie i" ::: "memory" );
}
}
#endif /* configUSE_TICKLESS_IDLE */

View file

@ -101,6 +101,13 @@ extern void vClearInterruptMaskFromISR( uint32_t ulMask ) __attribute__((naked)
/*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/
/* Tickless idle/low power functionality. */
#ifndef portSUPPRESS_TICKS_AND_SLEEP
extern void vPortSuppressTicksAndSleep( TickType_t xExpectedIdleTime );
#define portSUPPRESS_TICKS_AND_SLEEP( xExpectedIdleTime ) vPortSuppressTicksAndSleep( xExpectedIdleTime )
#endif
/*-----------------------------------------------------------*/
/* Task function macros as described on the FreeRTOS.org WEB site. */ /* Task function macros as described on the FreeRTOS.org WEB site. */
#define portTASK_FUNCTION_PROTO( vFunction, pvParameters ) void vFunction( void *pvParameters ) #define portTASK_FUNCTION_PROTO( vFunction, pvParameters ) void vFunction( void *pvParameters )
#define portTASK_FUNCTION( vFunction, pvParameters ) void vFunction( void *pvParameters ) #define portTASK_FUNCTION( vFunction, pvParameters ) void vFunction( void *pvParameters )

View file

@ -210,13 +210,6 @@ uint32_t ulSetInterruptMaskFromISR( void ) /* __attribute__(( naked )) PRIVILEGE
" bx lr \n" " bx lr \n"
::: "memory" ::: "memory"
); );
#if !defined (__ARMCC_VERSION) && (__ARMCC_VERSION >= 6010050)
/* To avoid compiler warnings. The return statement will never be reached,
* but some compilers warn if it is not included, while others won't compile
* if it is. */
return 0;
#endif
} }
/*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/
@ -228,14 +221,6 @@ void vClearInterruptMaskFromISR( __attribute__( ( unused ) ) uint32_t ulMask ) /
" bx lr \n" " bx lr \n"
::: "memory" ::: "memory"
); );
#if !defined (__ARMCC_VERSION) && (__ARMCC_VERSION >= 6010050)
/* Just to avoid compiler warning. ulMask is used from the asm code but
* the compiler can't see that. Some compilers generate warnings without
* the following line, while others generate warnings if the line is
* included. */
( void ) ulMask;
#endif
} }
/*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/

View file

@ -205,13 +205,6 @@ uint32_t ulSetInterruptMaskFromISR( void ) /* __attribute__(( naked )) PRIVILEGE
" bx lr \n" " bx lr \n"
::: "memory" ::: "memory"
); );
#if !defined (__ARMCC_VERSION) && (__ARMCC_VERSION >= 6010050)
/* To avoid compiler warnings. The return statement will never be reached,
* but some compilers warn if it is not included, while others won't compile
* if it is. */
return 0;
#endif
} }
/*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/
@ -223,14 +216,6 @@ void vClearInterruptMaskFromISR( __attribute__( ( unused ) ) uint32_t ulMask ) /
" bx lr \n" " bx lr \n"
::: "memory" ::: "memory"
); );
#if !defined (__ARMCC_VERSION) && (__ARMCC_VERSION >= 6010050)
/* Just to avoid compiler warning. ulMask is used from the asm code but
* the compiler can't see that. Some compilers generate warnings without
* the following line, while others generate warnings if the line is
* included. */
( void ) ulMask;
#endif
} }
/*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/

View file

@ -166,6 +166,8 @@ not necessary for to use this port. They are defined so the common demo files
#define portFORCE_INLINE inline __attribute__(( always_inline)) #define portFORCE_INLINE inline __attribute__(( always_inline))
#endif #endif
/*-----------------------------------------------------------*/
portFORCE_INLINE static BaseType_t xPortIsInsideInterrupt( void ) portFORCE_INLINE static BaseType_t xPortIsInsideInterrupt( void )
{ {
uint32_t ulCurrentInterrupt; uint32_t ulCurrentInterrupt;

View file

@ -185,13 +185,6 @@ uint32_t ulSetInterruptMaskFromISR( void ) /* __attribute__(( naked )) PRIVILEGE
" bx lr \n" " bx lr \n"
::: "memory" ::: "memory"
); );
#if !defined (__ARMCC_VERSION) && (__ARMCC_VERSION >= 6010050)
/* To avoid compiler warnings. The return statement will never be reached,
* but some compilers warn if it is not included, while others won't compile
* if it is. */
return 0;
#endif
} }
/*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/
@ -203,14 +196,6 @@ void vClearInterruptMaskFromISR( __attribute__( ( unused ) ) uint32_t ulMask ) /
" bx lr \n" " bx lr \n"
::: "memory" ::: "memory"
); );
#if !defined (__ARMCC_VERSION) && (__ARMCC_VERSION >= 6010050)
/* Just to avoid compiler warning. ulMask is used from the asm code but
* the compiler can't see that. Some compilers generate warnings without
* the following line, while others generate warnings if the line is
* included. */
( void ) ulMask;
#endif
} }
/*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/

View file

@ -180,13 +180,6 @@ uint32_t ulSetInterruptMaskFromISR( void ) /* __attribute__(( naked )) PRIVILEGE
" bx lr \n" " bx lr \n"
::: "memory" ::: "memory"
); );
#if !defined (__ARMCC_VERSION) && (__ARMCC_VERSION >= 6010050)
/* To avoid compiler warnings. The return statement will never be reached,
* but some compilers warn if it is not included, while others won't compile
* if it is. */
return 0;
#endif
} }
/*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/
@ -198,14 +191,6 @@ void vClearInterruptMaskFromISR( __attribute__( ( unused ) ) uint32_t ulMask ) /
" bx lr \n" " bx lr \n"
::: "memory" ::: "memory"
); );
#if !defined (__ARMCC_VERSION) && (__ARMCC_VERSION >= 6010050)
/* Just to avoid compiler warning. ulMask is used from the asm code but
* the compiler can't see that. Some compilers generate warnings without
* the following line, while others generate warnings if the line is
* included. */
( void ) ulMask;
#endif
} }
/*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/

View file

@ -30,8 +30,8 @@
*----------------------------------------------------------*/ *----------------------------------------------------------*/
/* Defining MPU_WRAPPERS_INCLUDED_FROM_API_FILE prevents task.h from redefining /* Defining MPU_WRAPPERS_INCLUDED_FROM_API_FILE prevents task.h from redefining
all the API functions to use the MPU wrappers. That should only be done when * all the API functions to use the MPU wrappers. That should only be done when
task.h is included from an application file. */ * task.h is included from an application file. */
#define MPU_WRAPPERS_INCLUDED_FROM_API_FILE #define MPU_WRAPPERS_INCLUDED_FROM_API_FILE
/* Scheduler includes. */ /* Scheduler includes. */
@ -46,7 +46,7 @@ task.h is included from an application file. */
#define portNVIC_SYSTICK_CLK ( 1UL << 2UL ) #define portNVIC_SYSTICK_CLK ( 1UL << 2UL )
#else #else
/* The way the SysTick is clocked is not modified in case it is not the same /* The way the SysTick is clocked is not modified in case it is not the same
as the core. */ * as the core. */
#define portNVIC_SYSTICK_CLK ( 0 ) #define portNVIC_SYSTICK_CLK ( 0 )
#endif #endif
@ -86,21 +86,22 @@ task.h is included from an application file. */
#define portINITIAL_CONTROL_IF_PRIVILEGED ( 0x02 ) #define portINITIAL_CONTROL_IF_PRIVILEGED ( 0x02 )
/* Constants required to check the validity of an interrupt priority. */ /* Constants required to check the validity of an interrupt priority. */
#define portFIRST_USER_INTERRUPT_NUMBER ( 16 ) #define portFIRST_USER_INTERRUPT_NUMBER ( 16 )
#define portNVIC_IP_REGISTERS_OFFSET_16 ( 0xE000E3F0 ) #define portNVIC_IP_REGISTERS_OFFSET_16 ( 0xE000E3F0 )
#define portAIRCR_REG ( * ( ( volatile uint32_t * ) 0xE000ED0C ) ) #define portAIRCR_REG ( * ( ( volatile uint32_t * ) 0xE000ED0C ) )
#define portMAX_8_BIT_VALUE ( ( uint8_t ) 0xff ) #define portMAX_8_BIT_VALUE ( ( uint8_t ) 0xff )
#define portTOP_BIT_OF_BYTE ( ( uint8_t ) 0x80 ) #define portTOP_BIT_OF_BYTE ( ( uint8_t ) 0x80 )
#define portMAX_PRIGROUP_BITS ( ( uint8_t ) 7 ) #define portMAX_PRIGROUP_BITS ( ( uint8_t ) 7 )
#define portPRIORITY_GROUP_MASK ( 0x07UL << 8UL ) #define portPRIORITY_GROUP_MASK ( 0x07UL << 8UL )
#define portPRIGROUP_SHIFT ( 8UL ) #define portPRIGROUP_SHIFT ( 8UL )
/* Offsets in the stack to the parameters when inside the SVC handler. */ /* Offsets in the stack to the parameters when inside the SVC handler. */
#define portOFFSET_TO_PC ( 6 ) #define portOFFSET_TO_PC ( 6 )
/* For strict compliance with the Cortex-M spec the task start address should /* For strict compliance with the Cortex-M spec the task start address should
have bit-0 clear, as it is loaded into the PC on exit from an ISR. */ * have bit-0 clear, as it is loaded into the PC on exit from an ISR. */
#define portSTART_ADDRESS_MASK ( ( StackType_t ) 0xfffffffeUL ) #define portSTART_ADDRESS_MASK ( ( StackType_t ) 0xfffffffeUL )
/*-----------------------------------------------------------*/
/* /*
* Configure a number of standard MPU regions that are used by all tasks. * Configure a number of standard MPU regions that are used by all tasks.
@ -171,8 +172,8 @@ extern void vPortResetPrivilege( BaseType_t xRunningPrivileged );
/*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/
/* Each task maintains its own interrupt status in the critical nesting /* Each task maintains its own interrupt status in the critical nesting
variable. Note this is not saved as part of the task context as context * variable. Note this is not saved as part of the task context as context
switches can only occur when uxCriticalNesting is zero. */ * switches can only occur when uxCriticalNesting is zero. */
static UBaseType_t uxCriticalNesting = 0xaaaaaaaa; static UBaseType_t uxCriticalNesting = 0xaaaaaaaa;
/* /*
@ -185,7 +186,6 @@ static UBaseType_t uxCriticalNesting = 0xaaaaaaaa;
static uint32_t ulMaxPRIGROUPValue = 0; static uint32_t ulMaxPRIGROUPValue = 0;
static const volatile uint8_t * const pcInterruptPriorityRegisters = ( const volatile uint8_t * const ) portNVIC_IP_REGISTERS_OFFSET_16; static const volatile uint8_t * const pcInterruptPriorityRegisters = ( const volatile uint8_t * const ) portNVIC_IP_REGISTERS_OFFSET_16;
#endif /* configASSERT_DEFINED */ #endif /* configASSERT_DEFINED */
/*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/
/* /*
@ -194,7 +194,7 @@ static UBaseType_t uxCriticalNesting = 0xaaaaaaaa;
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 )
{ {
/* Simulate the stack frame as it would be created by a context switch /* Simulate the stack frame as it would be created by a context switch
interrupt. */ * interrupt. */
pxTopOfStack--; /* Offset added to account for the way the MCU uses the stack on entry/exit of interrupts. */ pxTopOfStack--; /* Offset added to account for the way the MCU uses the stack on entry/exit of interrupts. */
*pxTopOfStack = portINITIAL_XPSR; /* xPSR */ *pxTopOfStack = portINITIAL_XPSR; /* xPSR */
pxTopOfStack--; pxTopOfStack--;
@ -240,10 +240,25 @@ void vPortSVCHandler( void )
static void prvSVCHandler( uint32_t *pulParam ) static void prvSVCHandler( uint32_t *pulParam )
{ {
uint8_t ucSVCNumber; uint8_t ucSVCNumber;
uint32_t ulPC;
#if( configENFORCE_SYSTEM_CALLS_FROM_KERNEL_ONLY == 1 )
#if defined( __ARMCC_VERSION )
/* Declaration when these variable are defined in code instead of being
* exported from linker scripts. */
extern uint32_t * __syscalls_flash_start__;
extern uint32_t * __syscalls_flash_end__;
#else
/* Declaration when these variable are exported from linker scripts. */
extern uint32_t __syscalls_flash_start__[];
extern uint32_t __syscalls_flash_end__[];
#endif /* #if defined( __ARMCC_VERSION ) */
#endif /* #if( configENFORCE_SYSTEM_CALLS_FROM_KERNEL_ONLY == 1 ) */
/* The stack contains: r0, r1, r2, r3, r12, LR, PC and xPSR. The first
* argument (r0) is pulParam[ 0 ]. */
ulPC = pulParam[ portOFFSET_TO_PC ];
ucSVCNumber = ( ( uint8_t * ) ulPC )[ -2 ];
/* The stack contains: r0, r1, r2, r3, r12, r14, the return address and
xPSR. The first argument (r0) is pulParam[ 0 ]. */
ucSVCNumber = ( ( uint8_t * ) pulParam[ portOFFSET_TO_PC ] )[ -2 ];
switch( ucSVCNumber ) switch( ucSVCNumber )
{ {
case portSVC_START_SCHEDULER : portNVIC_SYSPRI1_REG |= portNVIC_SVC_PRI; case portSVC_START_SCHEDULER : portNVIC_SYSPRI1_REG |= portNVIC_SVC_PRI;
@ -252,14 +267,32 @@ uint8_t ucSVCNumber;
case portSVC_YIELD : portNVIC_INT_CTRL_REG = portNVIC_PENDSVSET_BIT; case portSVC_YIELD : portNVIC_INT_CTRL_REG = portNVIC_PENDSVSET_BIT;
/* Barriers are normally not required /* Barriers are normally not required
but do ensure the code is completely * but do ensure the code is completely
within the specified behaviour for the * within the specified behaviour for the
architecture. */ * architecture. */
__asm volatile( "dsb" ::: "memory" ); __asm volatile( "dsb" ::: "memory" );
__asm volatile( "isb" ); __asm volatile( "isb" );
break; break;
#if( configENFORCE_SYSTEM_CALLS_FROM_KERNEL_ONLY == 1 )
case portSVC_RAISE_PRIVILEGE : /* Only raise the privilege, if the
* svc was raised from any of the
* system calls. */
if( ulPC >= ( uint32_t ) __syscalls_flash_start__ &&
ulPC <= ( uint32_t ) __syscalls_flash_end__ )
{
__asm volatile
(
" mrs r1, control \n" /* Obtain current control value. */
" bic r1, #1 \n" /* Set privilege bit. */
" msr control, r1 \n" /* Write back new control value. */
::: "r1", "memory"
);
}
break;
#else
case portSVC_RAISE_PRIVILEGE : __asm volatile case portSVC_RAISE_PRIVILEGE : __asm volatile
( (
" mrs r1, control \n" /* Obtain current control value. */ " mrs r1, control \n" /* Obtain current control value. */
@ -268,6 +301,7 @@ uint8_t ucSVCNumber;
::: "r1", "memory" ::: "r1", "memory"
); );
break; break;
#endif /* #if( configENFORCE_SYSTEM_CALLS_FROM_KERNEL_ONLY == 1 ) */
default : /* Unknown SVC call. */ default : /* Unknown SVC call. */
break; break;
@ -287,9 +321,23 @@ static void prvRestoreContextOfFirstTask( void )
" ldr r1, [r3] \n" " ldr r1, [r3] \n"
" ldr r0, [r1] \n" /* The first item in the TCB is the task top of stack. */ " ldr r0, [r1] \n" /* The first item in the TCB is the task top of stack. */
" add r1, r1, #4 \n" /* Move onto the second item in the TCB... */ " add r1, r1, #4 \n" /* Move onto the second item in the TCB... */
" \n"
" dmb \n" /* Complete outstanding transfers before disabling MPU. */
" ldr r2, =0xe000ed94 \n" /* MPU_CTRL register. */
" ldr r3, [r2] \n" /* Read the value of MPU_CTRL. */
" bic r3, #1 \n" /* r3 = r3 & ~1 i.e. Clear the bit 0 in r3. */
" str r3, [r2] \n" /* Disable MPU. */
" \n"
" ldr r2, =0xe000ed9c \n" /* Region Base Address register. */ " ldr r2, =0xe000ed9c \n" /* Region Base Address register. */
" ldmia r1!, {r4-r11} \n" /* Read 4 sets of MPU registers. */ " ldmia r1!, {r4-r11} \n" /* Read 4 sets of MPU registers. */
" stmia r2!, {r4-r11} \n" /* Write 4 sets of MPU registers. */ " stmia r2!, {r4-r11} \n" /* Write 4 sets of MPU registers. */
" \n"
" ldr r2, =0xe000ed94 \n" /* MPU_CTRL register. */
" ldr r3, [r2] \n" /* Read the value of MPU_CTRL. */
" orr r3, #1 \n" /* r3 = r3 | 1 i.e. Set the bit 0 in r3. */
" str r3, [r2] \n" /* Enable MPU. */
" dsb \n" /* Force memory writes before continuing. */
" \n"
" ldmia r0!, {r3, r4-r11} \n" /* Pop the registers that are not automatically saved on exception entry. */ " ldmia r0!, {r3, r4-r11} \n" /* Pop the registers that are not automatically saved on exception entry. */
" msr control, r3 \n" " msr control, r3 \n"
" msr psp, r0 \n" /* Restore the task stack pointer. */ " msr psp, r0 \n" /* Restore the task stack pointer. */
@ -310,7 +358,7 @@ static void prvRestoreContextOfFirstTask( void )
BaseType_t xPortStartScheduler( void ) BaseType_t xPortStartScheduler( void )
{ {
/* configMAX_SYSCALL_INTERRUPT_PRIORITY must not be set to 0. See /* configMAX_SYSCALL_INTERRUPT_PRIORITY must not be set to 0. See
http://www.FreeRTOS.org/RTOS-Cortex-M3-M4.html */ * http://www.FreeRTOS.org/RTOS-Cortex-M3-M4.html */
configASSERT( ( configMAX_SYSCALL_INTERRUPT_PRIORITY ) ); configASSERT( ( configMAX_SYSCALL_INTERRUPT_PRIORITY ) );
#if( configASSERT_DEFINED == 1 ) #if( configASSERT_DEFINED == 1 )
@ -320,15 +368,15 @@ BaseType_t xPortStartScheduler( void )
volatile uint8_t ucMaxPriorityValue; volatile uint8_t ucMaxPriorityValue;
/* Determine the maximum priority from which ISR safe FreeRTOS API /* Determine the maximum priority from which ISR safe FreeRTOS API
functions can be called. ISR safe functions are those that end in * functions can be called. ISR safe functions are those that end in
"FromISR". FreeRTOS maintains separate thread and ISR API functions to * "FromISR". FreeRTOS maintains separate thread and ISR API functions
ensure interrupt entry is as fast and simple as possible. * to ensure interrupt entry is as fast and simple as possible.
Save the interrupt priority value that is about to be clobbered. */ * Save the interrupt priority value that is about to be clobbered. */
ulOriginalPriority = *pucFirstUserPriorityRegister; ulOriginalPriority = *pucFirstUserPriorityRegister;
/* Determine the number of priority bits available. First write to all /* Determine the number of priority bits available. First write to all
possible bits. */ * possible bits. */
*pucFirstUserPriorityRegister = portMAX_8_BIT_VALUE; *pucFirstUserPriorityRegister = portMAX_8_BIT_VALUE;
/* Read the value back to see how many bits stuck. */ /* Read the value back to see how many bits stuck. */
@ -338,7 +386,7 @@ BaseType_t xPortStartScheduler( void )
ucMaxSysCallPriority = configMAX_SYSCALL_INTERRUPT_PRIORITY & ucMaxPriorityValue; ucMaxSysCallPriority = configMAX_SYSCALL_INTERRUPT_PRIORITY & ucMaxPriorityValue;
/* Calculate the maximum acceptable priority group value for the number /* Calculate the maximum acceptable priority group value for the number
of bits read back. */ * of bits read back. */
ulMaxPRIGROUPValue = portMAX_PRIGROUP_BITS; ulMaxPRIGROUPValue = portMAX_PRIGROUP_BITS;
while( ( ucMaxPriorityValue & portTOP_BIT_OF_BYTE ) == portTOP_BIT_OF_BYTE ) while( ( ucMaxPriorityValue & portTOP_BIT_OF_BYTE ) == portTOP_BIT_OF_BYTE )
{ {
@ -349,8 +397,8 @@ BaseType_t xPortStartScheduler( void )
#ifdef __NVIC_PRIO_BITS #ifdef __NVIC_PRIO_BITS
{ {
/* Check the CMSIS configuration that defines the number of /* Check the CMSIS configuration that defines the number of
priority bits matches the number of priority bits actually queried * priority bits matches the number of priority bits actually queried
from the hardware. */ * from the hardware. */
configASSERT( ( portMAX_PRIGROUP_BITS - ulMaxPRIGROUPValue ) == __NVIC_PRIO_BITS ); configASSERT( ( portMAX_PRIGROUP_BITS - ulMaxPRIGROUPValue ) == __NVIC_PRIO_BITS );
} }
#endif #endif
@ -358,26 +406,26 @@ BaseType_t xPortStartScheduler( void )
#ifdef configPRIO_BITS #ifdef configPRIO_BITS
{ {
/* Check the FreeRTOS configuration that defines the number of /* Check the FreeRTOS configuration that defines the number of
priority bits matches the number of priority bits actually queried * priority bits matches the number of priority bits actually queried
from the hardware. */ * from the hardware. */
configASSERT( ( portMAX_PRIGROUP_BITS - ulMaxPRIGROUPValue ) == configPRIO_BITS ); configASSERT( ( portMAX_PRIGROUP_BITS - ulMaxPRIGROUPValue ) == configPRIO_BITS );
} }
#endif #endif
/* Shift the priority group value back to its position within the AIRCR /* Shift the priority group value back to its position within the AIRCR
register. */ * register. */
ulMaxPRIGROUPValue <<= portPRIGROUP_SHIFT; ulMaxPRIGROUPValue <<= portPRIGROUP_SHIFT;
ulMaxPRIGROUPValue &= portPRIORITY_GROUP_MASK; ulMaxPRIGROUPValue &= portPRIORITY_GROUP_MASK;
/* Restore the clobbered interrupt priority register to its original /* Restore the clobbered interrupt priority register to its original
value. */ * value. */
*pucFirstUserPriorityRegister = ulOriginalPriority; *pucFirstUserPriorityRegister = ulOriginalPriority;
} }
#endif /* conifgASSERT_DEFINED */ #endif /* conifgASSERT_DEFINED */
/* Make PendSV and SysTick the same priority as the kernel, and the SVC /* Make PendSV and SysTick the same priority as the kernel, and the SVC
handler higher priority so it can be used to exit a critical section (where * handler higher priority so it can be used to exit a critical section (where
lower priorities are masked). */ * lower priorities are masked). */
portNVIC_SYSPRI2_REG |= portNVIC_PENDSV_PRI; portNVIC_SYSPRI2_REG |= portNVIC_PENDSV_PRI;
portNVIC_SYSPRI2_REG |= portNVIC_SYSTICK_PRI; portNVIC_SYSPRI2_REG |= portNVIC_SYSTICK_PRI;
@ -385,7 +433,7 @@ BaseType_t xPortStartScheduler( void )
prvSetupMPU(); prvSetupMPU();
/* Start the timer that generates the tick ISR. Interrupts are disabled /* Start the timer that generates the tick ISR. Interrupts are disabled
here already. */ * here already. */
vPortSetupTimerInterrupt(); vPortSetupTimerInterrupt();
/* Initialise the critical nesting count ready for the first task. */ /* Initialise the critical nesting count ready for the first task. */
@ -413,7 +461,7 @@ BaseType_t xPortStartScheduler( void )
void vPortEndScheduler( void ) void vPortEndScheduler( void )
{ {
/* Not implemented in ports where there is nothing to return to. /* Not implemented in ports where there is nothing to return to.
Artificially force an assert. */ * Artificially force an assert. */
configASSERT( uxCriticalNesting == 1000UL ); configASSERT( uxCriticalNesting == 1000UL );
} }
/*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/
@ -471,9 +519,23 @@ void xPortPendSVHandler( void )
" ldr r1, [r3] \n" " ldr r1, [r3] \n"
" ldr r0, [r1] \n" /* The first item in the TCB is the task top of stack. */ " ldr r0, [r1] \n" /* The first item in the TCB is the task top of stack. */
" add r1, r1, #4 \n" /* Move onto the second item in the TCB... */ " add r1, r1, #4 \n" /* Move onto the second item in the TCB... */
" \n"
" dmb \n" /* Complete outstanding transfers before disabling MPU. */
" ldr r2, =0xe000ed94 \n" /* MPU_CTRL register. */
" ldr r3, [r2] \n" /* Read the value of MPU_CTRL. */
" bic r3, #1 \n" /* r3 = r3 & ~1 i.e. Clear the bit 0 in r3. */
" str r3, [r2] \n" /* Disable MPU. */
" \n"
" ldr r2, =0xe000ed9c \n" /* Region Base Address register. */ " ldr r2, =0xe000ed9c \n" /* Region Base Address register. */
" ldmia r1!, {r4-r11} \n" /* Read 4 sets of MPU registers. */ " ldmia r1!, {r4-r11} \n" /* Read 4 sets of MPU registers. */
" stmia r2!, {r4-r11} \n" /* Write 4 sets of MPU registers. */ " stmia r2!, {r4-r11} \n" /* Write 4 sets of MPU registers. */
" \n"
" ldr r2, =0xe000ed94 \n" /* MPU_CTRL register. */
" ldr r3, [r2] \n" /* Read the value of MPU_CTRL. */
" orr r3, #1 \n" /* r3 = r3 | 1 i.e. Set the bit 0 in r3. */
" str r3, [r2] \n" /* Enable MPU. */
" dsb \n" /* Force memory writes before continuing. */
" \n"
" ldmia r0!, {r3, r4-r11} \n" /* Pop the registers that are not automatically saved on exception entry. */ " ldmia r0!, {r3, r4-r11} \n" /* Pop the registers that are not automatically saved on exception entry. */
" msr control, r3 \n" " msr control, r3 \n"
" \n" " \n"
@ -542,8 +604,8 @@ extern uint32_t __privileged_data_end__[];
( portMPU_REGION_ENABLE ); ( portMPU_REGION_ENABLE );
/* Setup the first 16K for privileged only access (even though less /* Setup the first 16K for privileged only access (even though less
than 10K is actually being used). This is where the kernel code is * than 10K is actually being used). This is where the kernel code is
placed. */ * placed. */
portMPU_REGION_BASE_ADDRESS_REG = ( ( uint32_t ) __FLASH_segment_start__ ) | /* Base address. */ portMPU_REGION_BASE_ADDRESS_REG = ( ( uint32_t ) __FLASH_segment_start__ ) | /* Base address. */
( portMPU_REGION_VALID ) | ( portMPU_REGION_VALID ) |
( portPRIVILEGED_FLASH_REGION ); ( portPRIVILEGED_FLASH_REGION );
@ -554,7 +616,7 @@ extern uint32_t __privileged_data_end__[];
( portMPU_REGION_ENABLE ); ( portMPU_REGION_ENABLE );
/* Setup the privileged data RAM region. This is where the kernel data /* Setup the privileged data RAM region. This is where the kernel data
is placed. */ * is placed. */
portMPU_REGION_BASE_ADDRESS_REG = ( ( uint32_t ) __privileged_data_start__ ) | /* Base address. */ portMPU_REGION_BASE_ADDRESS_REG = ( ( uint32_t ) __privileged_data_start__ ) | /* Base address. */
( portMPU_REGION_VALID ) | ( portMPU_REGION_VALID ) |
( portPRIVILEGED_RAM_REGION ); ( portPRIVILEGED_RAM_REGION );
@ -565,7 +627,7 @@ extern uint32_t __privileged_data_end__[];
( portMPU_REGION_ENABLE ); ( portMPU_REGION_ENABLE );
/* By default allow everything to access the general peripherals. The /* By default allow everything to access the general peripherals. The
system peripherals and registers are protected. */ * system peripherals and registers are protected. */
portMPU_REGION_BASE_ADDRESS_REG = ( portPERIPHERALS_START_ADDRESS ) | portMPU_REGION_BASE_ADDRESS_REG = ( portPERIPHERALS_START_ADDRESS ) |
( portMPU_REGION_VALID ) | ( portMPU_REGION_VALID ) |
( portGENERAL_PERIPHERALS_REGION ); ( portGENERAL_PERIPHERALS_REGION );
@ -588,7 +650,7 @@ static uint32_t prvGetMPURegionSizeSetting( uint32_t ulActualSizeInBytes )
uint32_t ulRegionSize, ulReturnValue = 4; uint32_t ulRegionSize, ulReturnValue = 4;
/* 32 is the smallest region size, 31 is the largest valid value for /* 32 is the smallest region size, 31 is the largest valid value for
ulReturnValue. */ * ulReturnValue. */
for( ulRegionSize = 32UL; ulReturnValue < 31UL; ( ulRegionSize <<= 1UL ) ) for( ulRegionSize = 32UL; ulReturnValue < 31UL; ( ulRegionSize <<= 1UL ) )
{ {
if( ulActualSizeInBytes <= ulRegionSize ) if( ulActualSizeInBytes <= ulRegionSize )
@ -602,7 +664,7 @@ uint32_t ulRegionSize, ulReturnValue = 4;
} }
/* Shift the code by one before returning so it can be written directly /* Shift the code by one before returning so it can be written directly
into the the correct bit position of the attribute register. */ * into the the correct bit position of the attribute register. */
return ( ulReturnValue << 1UL ); return ( ulReturnValue << 1UL );
} }
/*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/
@ -661,7 +723,7 @@ uint32_t ul;
( portMPU_REGION_ENABLE ); ( portMPU_REGION_ENABLE );
/* Re-instate the privileged only RAM region as xRegion[ 0 ] will have /* Re-instate the privileged only RAM region as xRegion[ 0 ] will have
just removed the privileged only parameters. */ * just removed the privileged only parameters. */
xMPUSettings->xRegion[ 1 ].ulRegionBaseAddress = xMPUSettings->xRegion[ 1 ].ulRegionBaseAddress =
( ( uint32_t ) __privileged_data_start__ ) | /* Base address. */ ( ( uint32_t ) __privileged_data_start__ ) | /* Base address. */
( portMPU_REGION_VALID ) | ( portMPU_REGION_VALID ) |
@ -683,9 +745,9 @@ uint32_t ul;
else else
{ {
/* This function is called automatically when the task is created - in /* This function is called automatically when the task is created - in
which case the stack region parameters will be valid. At all other * which case the stack region parameters will be valid. At all other
times the stack parameters will not be valid and it is assumed that the * times the stack parameters will not be valid and it is assumed that the
stack region has already been configured. */ * stack region has already been configured. */
if( ulStackDepth > 0 ) if( ulStackDepth > 0 )
{ {
/* Define the region that allows access to the stack. */ /* Define the region that allows access to the stack. */
@ -708,8 +770,8 @@ uint32_t ul;
if( ( xRegions[ lIndex ] ).ulLengthInBytes > 0UL ) if( ( xRegions[ lIndex ] ).ulLengthInBytes > 0UL )
{ {
/* Translate the generic region definition contained in /* Translate the generic region definition contained in
xRegions into the CM3 specific MPU settings that are then * xRegions into the CM3 specific MPU settings that are then
stored in xMPUSettings. */ * stored in xMPUSettings. */
xMPUSettings->xRegion[ ul ].ulRegionBaseAddress = xMPUSettings->xRegion[ ul ].ulRegionBaseAddress =
( ( uint32_t ) xRegions[ lIndex ].pvBaseAddress ) | ( ( uint32_t ) xRegions[ lIndex ].pvBaseAddress ) |
( portMPU_REGION_VALID ) | ( portMPU_REGION_VALID ) |
@ -750,48 +812,46 @@ uint32_t ul;
ucCurrentPriority = pcInterruptPriorityRegisters[ ulCurrentInterrupt ]; ucCurrentPriority = pcInterruptPriorityRegisters[ ulCurrentInterrupt ];
/* The following assertion will fail if a service routine (ISR) for /* The following assertion will fail if a service routine (ISR) for
an interrupt that has been assigned a priority above * an interrupt that has been assigned a priority above
configMAX_SYSCALL_INTERRUPT_PRIORITY calls an ISR safe FreeRTOS API * configMAX_SYSCALL_INTERRUPT_PRIORITY calls an ISR safe FreeRTOS API
function. ISR safe FreeRTOS API functions must *only* be called * function. ISR safe FreeRTOS API functions must *only* be called
from interrupts that have been assigned a priority at or below * from interrupts that have been assigned a priority at or below
configMAX_SYSCALL_INTERRUPT_PRIORITY. * configMAX_SYSCALL_INTERRUPT_PRIORITY.
Numerically low interrupt priority numbers represent logically high * Numerically low interrupt priority numbers represent logically high
interrupt priorities, therefore the priority of the interrupt must * interrupt priorities, therefore the priority of the interrupt must
be set to a value equal to or numerically *higher* than * be set to a value equal to or numerically *higher* than
configMAX_SYSCALL_INTERRUPT_PRIORITY. * configMAX_SYSCALL_INTERRUPT_PRIORITY.
Interrupts that use the FreeRTOS API must not be left at their * Interrupts that use the FreeRTOS API must not be left at their
default priority of zero as that is the highest possible priority, * default priority of zero as that is the highest possible priority,
which is guaranteed to be above configMAX_SYSCALL_INTERRUPT_PRIORITY, * which is guaranteed to be above configMAX_SYSCALL_INTERRUPT_PRIORITY,
and therefore also guaranteed to be invalid. * and therefore also guaranteed to be invalid.
FreeRTOS maintains separate thread and ISR API functions to ensure * FreeRTOS maintains separate thread and ISR API functions to ensure
interrupt entry is as fast and simple as possible. * interrupt entry is as fast and simple as possible.
The following links provide detailed information: * The following links provide detailed information:
http://www.freertos.org/RTOS-Cortex-M3-M4.html * http://www.freertos.org/RTOS-Cortex-M3-M4.html
http://www.freertos.org/FAQHelp.html */ * http://www.freertos.org/FAQHelp.html */
configASSERT( ucCurrentPriority >= ucMaxSysCallPriority ); configASSERT( ucCurrentPriority >= ucMaxSysCallPriority );
} }
/* Priority grouping: The interrupt controller (NVIC) allows the bits /* Priority grouping: The interrupt controller (NVIC) allows the bits
that define each interrupt's priority to be split between bits that * that define each interrupt's priority to be split between bits that
define the interrupt's pre-emption priority bits and bits that define * define the interrupt's pre-emption priority bits and bits that define
the interrupt's sub-priority. For simplicity all bits must be defined * the interrupt's sub-priority. For simplicity all bits must be defined
to be pre-emption priority bits. The following assertion will fail if * to be pre-emption priority bits. The following assertion will fail if
this is not the case (if some bits represent a sub-priority). * this is not the case (if some bits represent a sub-priority).
If the application only uses CMSIS libraries for interrupt * If the application only uses CMSIS libraries for interrupt
configuration then the correct setting can be achieved on all Cortex-M * configuration then the correct setting can be achieved on all Cortex-M
devices by calling NVIC_SetPriorityGrouping( 0 ); before starting the * devices by calling NVIC_SetPriorityGrouping( 0 ); before starting the
scheduler. Note however that some vendor specific peripheral libraries * scheduler. Note however that some vendor specific peripheral libraries
assume a non-zero priority group setting, in which cases using a value * assume a non-zero priority group setting, in which cases using a value
of zero will result in unpredicable behaviour. */ * of zero will result in unpredicable behaviour. */
configASSERT( ( portAIRCR_REG & portPRIORITY_GROUP_MASK ) <= ulMaxPRIGROUPValue ); configASSERT( ( portAIRCR_REG & portPRIORITY_GROUP_MASK ) <= ulMaxPRIGROUPValue );
} }
#endif /* configASSERT_DEFINED */ #endif /* configASSERT_DEFINED */
/*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/

View file

@ -73,12 +73,13 @@ typedef unsigned long UBaseType_t;
#define portUSING_MPU_WRAPPERS 1 #define portUSING_MPU_WRAPPERS 1
#define portPRIVILEGE_BIT ( 0x80000000UL ) #define portPRIVILEGE_BIT ( 0x80000000UL )
#define portMPU_REGION_READ_WRITE ( 0x03UL << 24UL ) #define portMPU_REGION_READ_WRITE ( 0x03UL << 24UL )
#define portMPU_REGION_PRIVILEGED_READ_ONLY ( 0x05UL << 24UL ) #define portMPU_REGION_PRIVILEGED_READ_ONLY ( 0x05UL << 24UL )
#define portMPU_REGION_READ_ONLY ( 0x06UL << 24UL ) #define portMPU_REGION_READ_ONLY ( 0x06UL << 24UL )
#define portMPU_REGION_PRIVILEGED_READ_WRITE ( 0x01UL << 24UL ) #define portMPU_REGION_PRIVILEGED_READ_WRITE ( 0x01UL << 24UL )
#define portMPU_REGION_CACHEABLE_BUFFERABLE ( 0x07UL << 16UL ) #define portMPU_REGION_PRIVILEGED_READ_WRITE_UNPRIV_READ_ONLY ( 0x02UL << 24UL )
#define portMPU_REGION_EXECUTE_NEVER ( 0x01UL << 28UL ) #define portMPU_REGION_CACHEABLE_BUFFERABLE ( 0x07UL << 16UL )
#define portMPU_REGION_EXECUTE_NEVER ( 0x01UL << 28UL )
#define portUNPRIVILEGED_FLASH_REGION ( 0UL ) #define portUNPRIVILEGED_FLASH_REGION ( 0UL )
#define portPRIVILEGED_FLASH_REGION ( 1UL ) #define portPRIVILEGED_FLASH_REGION ( 1UL )
@ -293,6 +294,11 @@ portFORCE_INLINE static void vPortSetBASEPRI( uint32_t ulNewMaskValue )
#define portMEMORY_BARRIER() __asm volatile( "" ::: "memory" ) #define portMEMORY_BARRIER() __asm volatile( "" ::: "memory" )
#ifndef configENFORCE_SYSTEM_CALLS_FROM_KERNEL_ONLY
#warning "configENFORCE_SYSTEM_CALLS_FROM_KERNEL_ONLY is not defined. We recommend defining it to 1 in FreeRTOSConfig.h for better security."
#define configENFORCE_SYSTEM_CALLS_FROM_KERNEL_ONLY 0
#endif
/*-----------------------------------------------------------*/
#ifdef __cplusplus #ifdef __cplusplus
} }
#endif #endif

View file

@ -134,7 +134,7 @@ void vPortSetupTimerInterrupt( void );
* Standard FreeRTOS exception handlers. * Standard FreeRTOS exception handlers.
*/ */
void xPortPendSVHandler( void ) __attribute__ (( naked )) PRIVILEGED_FUNCTION; void xPortPendSVHandler( void ) __attribute__ (( naked )) PRIVILEGED_FUNCTION;
void xPortSysTickHandler( void ) __attribute__ ((optimize("3"))) PRIVILEGED_FUNCTION; void xPortSysTickHandler( void ) PRIVILEGED_FUNCTION;
void vPortSVCHandler( void ) __attribute__ (( naked )) PRIVILEGED_FUNCTION; void vPortSVCHandler( void ) __attribute__ (( naked )) PRIVILEGED_FUNCTION;
/* /*
@ -260,10 +260,25 @@ void vPortSVCHandler( void )
static void prvSVCHandler( uint32_t *pulParam ) static void prvSVCHandler( uint32_t *pulParam )
{ {
uint8_t ucSVCNumber; uint8_t ucSVCNumber;
uint32_t ulPC;
#if( configENFORCE_SYSTEM_CALLS_FROM_KERNEL_ONLY == 1 )
#if defined( __ARMCC_VERSION )
/* Declaration when these variable are defined in code instead of being
* exported from linker scripts. */
extern uint32_t * __syscalls_flash_start__;
extern uint32_t * __syscalls_flash_end__;
#else
/* Declaration when these variable are exported from linker scripts. */
extern uint32_t __syscalls_flash_start__[];
extern uint32_t __syscalls_flash_end__[];
#endif /* #if defined( __ARMCC_VERSION ) */
#endif /* #if( configENFORCE_SYSTEM_CALLS_FROM_KERNEL_ONLY == 1 ) */
/* The stack contains: r0, r1, r2, r3, r12, LR, PC and xPSR. The first
argument (r0) is pulParam[ 0 ]. */
ulPC = pulParam[ portOFFSET_TO_PC ];
ucSVCNumber = ( ( uint8_t * ) ulPC )[ -2 ];
/* The stack contains: r0, r1, r2, r3, r12, r14, the return address and
xPSR. The first argument (r0) is pulParam[ 0 ]. */
ucSVCNumber = ( ( uint8_t * ) pulParam[ portOFFSET_TO_PC ] )[ -2 ];
switch( ucSVCNumber ) switch( ucSVCNumber )
{ {
case portSVC_START_SCHEDULER : portNVIC_SYSPRI1_REG |= portNVIC_SVC_PRI; case portSVC_START_SCHEDULER : portNVIC_SYSPRI1_REG |= portNVIC_SVC_PRI;
@ -280,6 +295,23 @@ uint8_t ucSVCNumber;
break; break;
#if( configENFORCE_SYSTEM_CALLS_FROM_KERNEL_ONLY == 1 )
case portSVC_RAISE_PRIVILEGE : /* Only raise the privilege, if the
* svc was raised from any of the
* system calls. */
if( ulPC >= ( uint32_t ) __syscalls_flash_start__ &&
ulPC <= ( uint32_t ) __syscalls_flash_end__ )
{
__asm volatile
(
" mrs r1, control \n" /* Obtain current control value. */
" bic r1, #1 \n" /* Set privilege bit. */
" msr control, r1 \n" /* Write back new control value. */
::: "r1", "memory"
);
}
break;
#else
case portSVC_RAISE_PRIVILEGE : __asm volatile case portSVC_RAISE_PRIVILEGE : __asm volatile
( (
" mrs r1, control \n" /* Obtain current control value. */ " mrs r1, control \n" /* Obtain current control value. */
@ -288,6 +320,7 @@ uint8_t ucSVCNumber;
::: "r1", "memory" ::: "r1", "memory"
); );
break; break;
#endif /* #if( configENFORCE_SYSTEM_CALLS_FROM_KERNEL_ONLY == 1 ) */
default : /* Unknown SVC call. */ default : /* Unknown SVC call. */
break; break;
@ -307,9 +340,23 @@ static void prvRestoreContextOfFirstTask( void )
" ldr r1, [r3] \n" " ldr r1, [r3] \n"
" ldr r0, [r1] \n" /* The first item in the TCB is the task top of stack. */ " ldr r0, [r1] \n" /* The first item in the TCB is the task top of stack. */
" add r1, r1, #4 \n" /* Move onto the second item in the TCB... */ " add r1, r1, #4 \n" /* Move onto the second item in the TCB... */
" \n"
" dmb \n" /* Complete outstanding transfers before disabling MPU. */
" ldr r2, =0xe000ed94 \n" /* MPU_CTRL register. */
" ldr r3, [r2] \n" /* Read the value of MPU_CTRL. */
" bic r3, #1 \n" /* r3 = r3 & ~1 i.e. Clear the bit 0 in r3. */
" str r3, [r2] \n" /* Disable MPU. */
" \n"
" ldr r2, =0xe000ed9c \n" /* Region Base Address register. */ " ldr r2, =0xe000ed9c \n" /* Region Base Address register. */
" ldmia r1!, {r4-r11} \n" /* Read 4 sets of MPU registers. */ " ldmia r1!, {r4-r11} \n" /* Read 4 sets of MPU registers from TCB. */
" stmia r2!, {r4-r11} \n" /* Write 4 sets of MPU registers. */ " stmia r2!, {r4-r11} \n" /* Write 4 sets of MPU registers. */
" \n"
" ldr r2, =0xe000ed94 \n" /* MPU_CTRL register. */
" ldr r3, [r2] \n" /* Read the value of MPU_CTRL. */
" orr r3, #1 \n" /* r3 = r3 | 1 i.e. Set the bit 0 in r3. */
" str r3, [r2] \n" /* Enable MPU. */
" dsb \n" /* Force memory writes before continuing. */
" \n"
" ldmia r0!, {r3-r11, r14} \n" /* Pop the registers that are not automatically saved on exception entry. */ " ldmia r0!, {r3-r11, r14} \n" /* Pop the registers that are not automatically saved on exception entry. */
" msr control, r3 \n" " msr control, r3 \n"
" msr psp, r0 \n" /* Restore the task stack pointer. */ " msr psp, r0 \n" /* Restore the task stack pointer. */
@ -506,9 +553,23 @@ void xPortPendSVHandler( void )
" ldr r1, [r3] \n" " ldr r1, [r3] \n"
" ldr r0, [r1] \n" /* The first item in the TCB is the task top of stack. */ " ldr r0, [r1] \n" /* The first item in the TCB is the task top of stack. */
" add r1, r1, #4 \n" /* Move onto the second item in the TCB... */ " add r1, r1, #4 \n" /* Move onto the second item in the TCB... */
" \n"
" dmb \n" /* Complete outstanding transfers before disabling MPU. */
" ldr r2, =0xe000ed94 \n" /* MPU_CTRL register. */
" ldr r3, [r2] \n" /* Read the value of MPU_CTRL. */
" bic r3, #1 \n" /* r3 = r3 & ~1 i.e. Clear the bit 0 in r3. */
" str r3, [r2] \n" /* Disable MPU. */
" \n"
" ldr r2, =0xe000ed9c \n" /* Region Base Address register. */ " ldr r2, =0xe000ed9c \n" /* Region Base Address register. */
" ldmia r1!, {r4-r11} \n" /* Read 4 sets of MPU registers. */ " ldmia r1!, {r4-r11} \n" /* Read 4 sets of MPU registers from TCB. */
" stmia r2!, {r4-r11} \n" /* Write 4 sets of MPU registers. */ " stmia r2!, {r4-r11} \n" /* Write 4 sets of MPU registers. */
" \n"
" ldr r2, =0xe000ed94 \n" /* MPU_CTRL register. */
" ldr r3, [r2] \n" /* Read the value of MPU_CTRL. */
" orr r3, #1 \n" /* r3 = r3 | 1 i.e. Set the bit 0 in r3. */
" str r3, [r2] \n" /* Enable MPU. */
" dsb \n" /* Force memory writes before continuing. */
" \n"
" ldmia r0!, {r3-r11, r14} \n" /* Pop the registers that are not automatically saved on exception entry. */ " ldmia r0!, {r3-r11, r14} \n" /* Pop the registers that are not automatically saved on exception entry. */
" msr control, r3 \n" " msr control, r3 \n"
" \n" " \n"
@ -576,12 +637,22 @@ static void vPortEnableVFP( void )
static void prvSetupMPU( void ) static void prvSetupMPU( void )
{ {
extern uint32_t __privileged_functions_end__[]; #if defined( __ARMCC_VERSION )
extern uint32_t __FLASH_segment_start__[]; /* Declaration when these variable are defined in code instead of being
extern uint32_t __FLASH_segment_end__[]; * exported from linker scripts. */
extern uint32_t __privileged_data_start__[]; extern uint32_t * __privileged_functions_end__;
extern uint32_t __privileged_data_end__[]; extern uint32_t * __FLASH_segment_start__;
extern uint32_t * __FLASH_segment_end__;
extern uint32_t * __privileged_data_start__;
extern uint32_t * __privileged_data_end__;
#else
/* Declaration when these variable are exported from linker scripts. */
extern uint32_t __privileged_functions_end__[];
extern uint32_t __FLASH_segment_start__[];
extern uint32_t __FLASH_segment_end__[];
extern uint32_t __privileged_data_start__[];
extern uint32_t __privileged_data_end__[];
#endif
/* Check the expected MPU is present. */ /* Check the expected MPU is present. */
if( portMPU_TYPE_REG == portEXPECTED_MPU_TYPE_VALUE ) if( portMPU_TYPE_REG == portEXPECTED_MPU_TYPE_VALUE )
{ {
@ -693,10 +764,21 @@ void vResetPrivilege( void ) /* __attribute__ (( naked )) */
void vPortStoreTaskMPUSettings( xMPU_SETTINGS *xMPUSettings, const struct xMEMORY_REGION * const xRegions, StackType_t *pxBottomOfStack, uint32_t ulStackDepth ) void vPortStoreTaskMPUSettings( xMPU_SETTINGS *xMPUSettings, const struct xMEMORY_REGION * const xRegions, StackType_t *pxBottomOfStack, uint32_t ulStackDepth )
{ {
extern uint32_t __SRAM_segment_start__[]; #if defined( __ARMCC_VERSION )
extern uint32_t __SRAM_segment_end__[]; /* Declaration when these variable are defined in code instead of being
extern uint32_t __privileged_data_start__[]; * exported from linker scripts. */
extern uint32_t __privileged_data_end__[]; extern uint32_t * __SRAM_segment_start__;
extern uint32_t * __SRAM_segment_end__;
extern uint32_t * __privileged_data_start__;
extern uint32_t * __privileged_data_end__;
#else
/* Declaration when these variable are exported from linker scripts. */
extern uint32_t __SRAM_segment_start__[];
extern uint32_t __SRAM_segment_end__[];
extern uint32_t __privileged_data_start__[];
extern uint32_t __privileged_data_end__[];
#endif
int32_t lIndex; int32_t lIndex;
uint32_t ul; uint32_t ul;

View file

@ -73,12 +73,13 @@ typedef unsigned long UBaseType_t;
#define portUSING_MPU_WRAPPERS 1 #define portUSING_MPU_WRAPPERS 1
#define portPRIVILEGE_BIT ( 0x80000000UL ) #define portPRIVILEGE_BIT ( 0x80000000UL )
#define portMPU_REGION_READ_WRITE ( 0x03UL << 24UL ) #define portMPU_REGION_READ_WRITE ( 0x03UL << 24UL )
#define portMPU_REGION_PRIVILEGED_READ_ONLY ( 0x05UL << 24UL ) #define portMPU_REGION_PRIVILEGED_READ_ONLY ( 0x05UL << 24UL )
#define portMPU_REGION_READ_ONLY ( 0x06UL << 24UL ) #define portMPU_REGION_READ_ONLY ( 0x06UL << 24UL )
#define portMPU_REGION_PRIVILEGED_READ_WRITE ( 0x01UL << 24UL ) #define portMPU_REGION_PRIVILEGED_READ_WRITE ( 0x01UL << 24UL )
#define portMPU_REGION_CACHEABLE_BUFFERABLE ( 0x07UL << 16UL ) #define portMPU_REGION_PRIVILEGED_READ_WRITE_UNPRIV_READ_ONLY ( 0x02UL << 24UL )
#define portMPU_REGION_EXECUTE_NEVER ( 0x01UL << 28UL ) #define portMPU_REGION_CACHEABLE_BUFFERABLE ( 0x07UL << 16UL )
#define portMPU_REGION_EXECUTE_NEVER ( 0x01UL << 28UL )
#define portUNPRIVILEGED_FLASH_REGION ( 0UL ) #define portUNPRIVILEGED_FLASH_REGION ( 0UL )
#define portPRIVILEGED_FLASH_REGION ( 1UL ) #define portPRIVILEGED_FLASH_REGION ( 1UL )
@ -293,6 +294,11 @@ portFORCE_INLINE static void vPortSetBASEPRI( uint32_t ulNewMaskValue )
#define portMEMORY_BARRIER() __asm volatile( "" ::: "memory" ) #define portMEMORY_BARRIER() __asm volatile( "" ::: "memory" )
#ifndef configENFORCE_SYSTEM_CALLS_FROM_KERNEL_ONLY
#warning "configENFORCE_SYSTEM_CALLS_FROM_KERNEL_ONLY is not defined. We recommend defining it to 1 in FreeRTOSConfig.h for better security."
#define configENFORCE_SYSTEM_CALLS_FROM_KERNEL_ONLY 0
#endif
/*-----------------------------------------------------------*/
#ifdef __cplusplus #ifdef __cplusplus
} }
#endif #endif

View file

@ -59,7 +59,7 @@
#ifndef __FREERTOS_RISC_V_EXTENSIONS_H__ #ifndef __FREERTOS_RISC_V_EXTENSIONS_H__
#define __FREERTOS_RISC_V_EXTENSIONS_H__ #define __FREERTOS_RISC_V_EXTENSIONS_H__
#define portasmHAS_CLINT 0 #define portasmHAS_MTIME 0
/* Constants to define the additional registers found on the Pulpino RI5KY. */ /* Constants to define the additional registers found on the Pulpino RI5KY. */
#define lpstart0 0x7b0 #define lpstart0 0x7b0

View file

@ -53,7 +53,7 @@
#ifndef __FREERTOS_RISC_V_EXTENSIONS_H__ #ifndef __FREERTOS_RISC_V_EXTENSIONS_H__
#define __FREERTOS_RISC_V_EXTENSIONS_H__ #define __FREERTOS_RISC_V_EXTENSIONS_H__
#define portasmHAS_CLINT 1 #define portasmHAS_MTIME 1
#define portasmADDITIONAL_CONTEXT_SIZE 0 /* Must be even number on 32-bit cores. */ #define portasmADDITIONAL_CONTEXT_SIZE 0 /* Must be even number on 32-bit cores. */
.macro portasmSAVE_ADDITIONAL_REGISTERS .macro portasmSAVE_ADDITIONAL_REGISTERS

View file

@ -34,8 +34,19 @@
#include "task.h" #include "task.h"
#include "portmacro.h" #include "portmacro.h"
#ifndef configCLINT_BASE_ADDRESS /* Standard includes. */
#warning configCLINT_BASE_ADDRESS must be defined in FreeRTOSConfig.h. If the target chip includes a Core Local Interrupter (CLINT) then set configCLINT_BASE_ADDRESS to the CLINT base address. Otherwise set configCLINT_BASE_ADDRESS to 0. #include "string.h"
#ifdef configCLINT_BASE_ADDRESS
#warning The configCLINT_BASE_ADDRESS constant has been deprecated. configMTIME_BASE_ADDRESS and configMTIMECMP_BASE_ADDRESS are currently being derived from the (possibly 0) configCLINT_BASE_ADDRESS setting. Please update to define configMTIME_BASE_ADDRESS and configMTIMECMP_BASE_ADDRESS dirctly in place of configCLINT_BASE_ADDRESS.
#endif
#ifndef configMTIME_BASE_ADDRESS
#warning configMTIME_BASE_ADDRESS must be defined in FreeRTOSConfig.h. If the target chip includes a memory-mapped mtime register then set configMTIME_BASE_ADDRESS to the mapped address. Otherwise set configMTIME_BASE_ADDRESS to 0.
#endif
#ifndef configMTIMECMP_BASE_ADDRESS
#warning configMTIMECMP_BASE_ADDRESS must be defined in FreeRTOSConfig.h. If the target chip includes a memory-mapped mtimecmp register then set configMTIMECMP_BASE_ADDRESS to the mapped address. Otherwise set configMTIMECMP_BASE_ADDRESS to 0.
#endif #endif
/* Let the user override the pre-loading of the initial LR with the address of /* Let the user override the pre-loading of the initial LR with the address of
@ -57,6 +68,11 @@ interrupt stack after the scheduler has started. */
#ifdef configISR_STACK_SIZE_WORDS #ifdef configISR_STACK_SIZE_WORDS
static __attribute__ ((aligned(16))) StackType_t xISRStack[ configISR_STACK_SIZE_WORDS ] = { 0 }; static __attribute__ ((aligned(16))) StackType_t xISRStack[ configISR_STACK_SIZE_WORDS ] = { 0 };
const StackType_t xISRStackTop = ( StackType_t ) &( xISRStack[ configISR_STACK_SIZE_WORDS & ~portBYTE_ALIGNMENT_MASK ] ); const StackType_t xISRStackTop = ( StackType_t ) &( xISRStack[ configISR_STACK_SIZE_WORDS & ~portBYTE_ALIGNMENT_MASK ] );
/* Don't use 0xa5 as the stack fill bytes as that is used by the kernerl for
the task stacks, and so will legitimately appear in many positions within
the ISR stack. */
#define portISR_STACK_FILL_BYTE 0xee
#else #else
extern const uint32_t __freertos_irq_stack_top[]; extern const uint32_t __freertos_irq_stack_top[];
const StackType_t xISRStackTop = ( StackType_t ) __freertos_irq_stack_top; const StackType_t xISRStackTop = ( StackType_t ) __freertos_irq_stack_top;
@ -74,20 +90,16 @@ void vPortSetupTimerInterrupt( void ) __attribute__(( weak ));
/* Used to program the machine timer compare register. */ /* Used to program the machine timer compare register. */
uint64_t ullNextTime = 0ULL; uint64_t ullNextTime = 0ULL;
const uint64_t *pullNextTime = &ullNextTime; const uint64_t *pullNextTime = &ullNextTime;
const size_t uxTimerIncrementsForOneTick = ( size_t ) ( configCPU_CLOCK_HZ / configTICK_RATE_HZ ); /* Assumes increment won't go over 32-bits. */ const size_t uxTimerIncrementsForOneTick = ( size_t ) ( ( configCPU_CLOCK_HZ ) / ( configTICK_RATE_HZ ) ); /* Assumes increment won't go over 32-bits. */
volatile uint64_t * const pullMachineTimerCompareRegisterBase = ( volatile uint64_t * const ) ( configCLINT_BASE_ADDRESS + 0x4000 ); uint32_t const ullMachineTimerCompareRegisterBase = configMTIMECMP_BASE_ADDRESS;
volatile uint64_t * pullMachineTimerCompareRegister = 0; volatile uint64_t * pullMachineTimerCompareRegister = NULL;
/* Set configCHECK_FOR_STACK_OVERFLOW to 3 to add ISR stack checking to task /* Set configCHECK_FOR_STACK_OVERFLOW to 3 to add ISR stack checking to task
stack checking. A problem in the ISR stack will trigger an assert, not call the stack checking. A problem in the ISR stack will trigger an assert, not call the
stack overflow hook function (because the stack overflow hook is specific to a stack overflow hook function (because the stack overflow hook is specific to a
task stack, not the ISR stack). */ task stack, not the ISR stack). */
#if( configCHECK_FOR_STACK_OVERFLOW > 2 ) #if defined( configISR_STACK_SIZE_WORDS ) && ( configCHECK_FOR_STACK_OVERFLOW > 2 )
#warning This path not tested, or even compiled yet. #warning This path not tested, or even compiled yet.
/* Don't use 0xa5 as the stack fill bytes as that is used by the kernerl for
the task stacks, and so will legitimately appear in many positions within
the ISR stack. */
#define portISR_STACK_FILL_BYTE 0xee
static const uint8_t ucExpectedStackBytes[] = { static const uint8_t ucExpectedStackBytes[] = {
portISR_STACK_FILL_BYTE, portISR_STACK_FILL_BYTE, portISR_STACK_FILL_BYTE, portISR_STACK_FILL_BYTE, \ portISR_STACK_FILL_BYTE, portISR_STACK_FILL_BYTE, portISR_STACK_FILL_BYTE, portISR_STACK_FILL_BYTE, \
@ -104,17 +116,17 @@ task stack, not the ISR stack). */
/*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/
#if( configCLINT_BASE_ADDRESS != 0 ) #if( configMTIME_BASE_ADDRESS != 0 ) && ( configMTIMECMP_BASE_ADDRESS != 0 )
void vPortSetupTimerInterrupt( void ) void vPortSetupTimerInterrupt( void )
{ {
uint32_t ulCurrentTimeHigh, ulCurrentTimeLow; uint32_t ulCurrentTimeHigh, ulCurrentTimeLow;
volatile uint32_t * const pulTimeHigh = ( volatile uint32_t * const ) ( configCLINT_BASE_ADDRESS + 0xBFFC ); volatile uint32_t * const pulTimeHigh = ( volatile uint32_t * const ) ( ( configMTIME_BASE_ADDRESS ) + 4UL ); /* 8-byte typer so high 32-bit word is 4 bytes up. */
volatile uint32_t * const pulTimeLow = ( volatile uint32_t * const ) ( configCLINT_BASE_ADDRESS + 0xBFF8 ); volatile uint32_t * const pulTimeLow = ( volatile uint32_t * const ) ( configMTIME_BASE_ADDRESS );
volatile uint32_t ulHartId = 0; volatile uint32_t ulHartId;
__asm volatile( "csrr %0, mhartid" : "=r"( ulHartId ) ); __asm volatile( "csrr %0, mhartid" : "=r"( ulHartId ) );
pullMachineTimerCompareRegister = &( pullMachineTimerCompareRegisterBase[ ulHartId ] ); pullMachineTimerCompareRegister = ( volatile uint64_t * ) ( ullMachineTimerCompareRegisterBase + ( ulHartId * sizeof( uint64_t ) ) );
do do
{ {
@ -123,7 +135,7 @@ task stack, not the ISR stack). */
} while( ulCurrentTimeHigh != *pulTimeHigh ); } while( ulCurrentTimeHigh != *pulTimeHigh );
ullNextTime = ( uint64_t ) ulCurrentTimeHigh; ullNextTime = ( uint64_t ) ulCurrentTimeHigh;
ullNextTime <<= 32ULL; ullNextTime <<= 32ULL; /* High 4-byte word is 32-bits up. */
ullNextTime |= ( uint64_t ) ulCurrentTimeLow; ullNextTime |= ( uint64_t ) ulCurrentTimeLow;
ullNextTime += ( uint64_t ) uxTimerIncrementsForOneTick; ullNextTime += ( uint64_t ) uxTimerIncrementsForOneTick;
*pullMachineTimerCompareRegister = ullNextTime; *pullMachineTimerCompareRegister = ullNextTime;
@ -132,7 +144,7 @@ task stack, not the ISR stack). */
ullNextTime += ( uint64_t ) uxTimerIncrementsForOneTick; ullNextTime += ( uint64_t ) uxTimerIncrementsForOneTick;
} }
#endif /* ( configCLINT_BASE_ADDRESS != 0 ) */ #endif /* ( configMTIME_BASE_ADDRESS != 0 ) && ( configMTIME_BASE_ADDRESS != 0 ) */
/*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/
BaseType_t xPortStartScheduler( void ) BaseType_t xPortStartScheduler( void )
@ -152,6 +164,12 @@ extern void xPortStartFirstTask( void );
stack that was being used by main() prior to the scheduler being stack that was being used by main() prior to the scheduler being
started. */ started. */
configASSERT( ( xISRStackTop & portBYTE_ALIGNMENT_MASK ) == 0 ); configASSERT( ( xISRStackTop & portBYTE_ALIGNMENT_MASK ) == 0 );
#ifdef configISR_STACK_SIZE_WORDS
{
memset( ( void * ) xISRStack, portISR_STACK_FILL_BYTE, sizeof( xISRStack ) );
}
#endif /* configISR_STACK_SIZE_WORDS */
} }
#endif /* configASSERT_DEFINED */ #endif /* configASSERT_DEFINED */
@ -160,7 +178,7 @@ extern void xPortStartFirstTask( void );
configure whichever clock is to be used to generate the tick interrupt. */ configure whichever clock is to be used to generate the tick interrupt. */
vPortSetupTimerInterrupt(); vPortSetupTimerInterrupt();
#if( configCLINT_BASE_ADDRESS != 0 ) #if( ( configMTIME_BASE_ADDRESS != 0 ) && ( configMTIMECMP_BASE_ADDRESS != 0 ) )
{ {
/* Enable mtime and external interrupts. 1<<7 for timer interrupt, 1<<11 /* Enable mtime and external interrupts. 1<<7 for timer interrupt, 1<<11
for external interrupt. _RB_ What happens here when mtime is not present as for external interrupt. _RB_ What happens here when mtime is not present as
@ -172,7 +190,7 @@ extern void xPortStartFirstTask( void );
/* Enable external interrupts. */ /* Enable external interrupts. */
__asm volatile( "csrs mie, %0" :: "r"(0x800) ); __asm volatile( "csrs mie, %0" :: "r"(0x800) );
} }
#endif /* configCLINT_BASE_ADDRESS */ #endif /* ( configMTIME_BASE_ADDRESS != 0 ) && ( configMTIMECMP_BASE_ADDRESS != 0 ) */
xPortStartFirstTask(); xPortStartFirstTask();

View file

@ -71,8 +71,17 @@
/* Check the freertos_risc_v_chip_specific_extensions.h and/or command line /* Check the freertos_risc_v_chip_specific_extensions.h and/or command line
definitions. */ definitions. */
#ifndef portasmHAS_CLINT #if defined( portasmHAS_CLINT ) && defined( portasmHAS_MTIME )
#error freertos_risc_v_chip_specific_extensions.h must define portasmHAS_CLINT to either 1 (CLINT present) or 0 (clint not present). #error The portasmHAS_CLINT constant has been depracted. Please replace it with portasmHAS_CLINT. portasmHAS_CLINT and portasmHAS_MTIME cannot both be defined at once.
#endif
#ifdef portasmHAS_CLINT
#warning The portasmHAS_CLINT constant has been depracted. Please replace it with portasmHAS_CLINT. For now portasmHAS_MTIME is derived from portasmHAS_CLINT.
#define portasmHAS_MTIME portasmHAS_CLINT
#endif
#ifndef portasmHAS_MTIME
#error freertos_risc_v_chip_specific_extensions.h must define portasmHAS_MTIME to either 1 (MTIME clock present) or 0 (MTIME clock not present).
#endif #endif
#ifndef portasmHANDLE_INTERRUPT #ifndef portasmHANDLE_INTERRUPT
@ -153,7 +162,7 @@ test_if_asynchronous:
handle_asynchronous: handle_asynchronous:
#if( portasmHAS_CLINT != 0 ) #if( portasmHAS_MTIME != 0 )
test_if_mtimer: /* If there is a CLINT then the mtimer is used to generate the tick interrupt. */ test_if_mtimer: /* If there is a CLINT then the mtimer is used to generate the tick interrupt. */
@ -172,7 +181,7 @@ handle_asynchronous:
li t4, -1 li t4, -1
lw t2, 0(t1) /* Load the low word of ullNextTime into t2. */ lw t2, 0(t1) /* Load the low word of ullNextTime into t2. */
lw t3, 4(t1) /* Load the high word of ullNextTime into t3. */ lw t3, 4(t1) /* Load the high word of ullNextTime into t3. */
sw t4, 0(t0) /* Low word no smaller than old value. */ sw t4, 0(t0) /* Low word no smaller than old value to start with - will be overwritten below. */
sw t3, 4(t0) /* Store high word of ullNextTime into compare register. No smaller than new value. */ sw t3, 4(t0) /* Store high word of ullNextTime into compare register. No smaller than new value. */
sw t2, 0(t0) /* Store low word of ullNextTime into compare register. */ sw t2, 0(t0) /* Store low word of ullNextTime into compare register. */
lw t0, uxTimerIncrementsForOneTick /* Load the value of ullTimerIncrementForOneTick into t0 (could this be optimized by storing in an array next to pullNextTime?). */ lw t0, uxTimerIncrementsForOneTick /* Load the value of ullTimerIncrementForOneTick into t0 (could this be optimized by storing in an array next to pullNextTime?). */
@ -205,7 +214,7 @@ handle_asynchronous:
addi t1, t1, 4 /* 0x80000007 + 4 = 0x8000000b == Machine external interrupt. */ addi t1, t1, 4 /* 0x80000007 + 4 = 0x8000000b == Machine external interrupt. */
bne a0, t1, as_yet_unhandled /* Something as yet unhandled. */ bne a0, t1, as_yet_unhandled /* Something as yet unhandled. */
#endif /* portasmHAS_CLINT */ #endif /* portasmHAS_MTIME */
load_x sp, xISRStackTop /* Switch to ISR stack before function call. */ load_x sp, xISRStackTop /* Switch to ISR stack before function call. */
jal portasmHANDLE_INTERRUPT /* Jump to the interrupt handler if there is no CLINT or if there is a CLINT and it has been determined that an external interrupt is pending. */ jal portasmHANDLE_INTERRUPT /* Jump to the interrupt handler if there is no CLINT or if there is a CLINT and it has been determined that an external interrupt is pending. */
@ -223,11 +232,13 @@ test_if_environment_call:
j processed_source j processed_source
is_exception: is_exception:
ebreak csrr t0, mcause /* For viewing in the debugger only. */
j is_exception csrr t1, mepc /* For viewing in the debugger only */
csrr t2, mstatus
j is_exception /* No other exceptions handled yet. */
as_yet_unhandled: as_yet_unhandled:
ebreak csrr t0, mcause /* For viewing in the debugger only. */
j as_yet_unhandled j as_yet_unhandled
processed_source: processed_source:
@ -282,7 +293,7 @@ processed_source:
.func .func
xPortStartFirstTask: xPortStartFirstTask:
#if( portasmHAS_CLINT != 0 ) #if( portasmHAS_MTIME != 0 )
/* If there is a clint then interrupts can branch directly to the FreeRTOS /* If there is a clint then interrupts can branch directly to the FreeRTOS
trap handler. Otherwise the interrupt controller will need to be configured trap handler. Otherwise the interrupt controller will need to be configured
outside of this file. */ outside of this file. */
@ -298,6 +309,7 @@ xPortStartFirstTask:
portasmRESTORE_ADDITIONAL_REGISTERS /* Defined in freertos_risc_v_chip_specific_extensions.h to restore any registers unique to the RISC-V implementation. */ portasmRESTORE_ADDITIONAL_REGISTERS /* Defined in freertos_risc_v_chip_specific_extensions.h to restore any registers unique to the RISC-V implementation. */
load_x t0, 29 * portWORD_SIZE( sp ) /* mstatus */ load_x t0, 29 * portWORD_SIZE( sp ) /* mstatus */
addi t0, t0, 0x08 /* Set MIE bit so the first task starts with interrupts enabled - required as returns with ret not eret. */
csrrw x0, mstatus, t0 /* Interrupts enabled from here! */ csrrw x0, mstatus, t0 /* Interrupts enabled from here! */
load_x x5, 2 * portWORD_SIZE( sp ) /* t0 */ load_x x5, 2 * portWORD_SIZE( sp ) /* t0 */

View file

@ -65,6 +65,13 @@ typedef portBASE_TYPE BaseType_t;
typedef portUBASE_TYPE UBaseType_t; typedef portUBASE_TYPE UBaseType_t;
typedef portUBASE_TYPE TickType_t; typedef portUBASE_TYPE TickType_t;
/* Legacy type definitions. */
#define portCHAR char
#define portFLOAT float
#define portDOUBLE double
#define portLONG long
#define portSHORT short
/* 32-bit tick type on a 32-bit architecture, so reads of the tick count do /* 32-bit tick type on a 32-bit architecture, so reads of the tick count do
not need to be guarded with a critical section. */ not need to be guarded with a critical section. */
#define portTICK_TYPE_IS_ATOMIC 1 #define portTICK_TYPE_IS_ATOMIC 1
@ -146,6 +153,30 @@ not necessary for to use this port. They are defined so the common demo files
#endif #endif
#define portMEMORY_BARRIER() __asm volatile( "" ::: "memory" ) #define portMEMORY_BARRIER() __asm volatile( "" ::: "memory" )
/*-----------------------------------------------------------*/
/* configCLINT_BASE_ADDRESS is a legacy definition that was replaced by the
configMTIME_BASE_ADDRESS and configMTIMECMP_BASE_ADDRESS definitions. For
backward compatibility derive the newer definitions from the old if the old
definition is found. */
#if defined( configCLINT_BASE_ADDRESS ) && !defined( configMTIME_BASE_ADDRESS ) && ( configCLINT_BASE_ADDRESS == 0 )
/* Legacy case where configCLINT_BASE_ADDRESS was defined as 0 to indicate
there was no CLINT. Equivalent now is to set the MTIME and MTIMECMP
addresses to 0. */
#define configMTIME_BASE_ADDRESS ( 0 )
#define configMTIMECMP_BASE_ADDRESS ( 0 )
#elif defined( configCLINT_BASE_ADDRESS ) && !defined( configMTIME_BASE_ADDRESS )
/* Legacy case where configCLINT_BASE_ADDRESS was set to the base address of
the CLINT. Equivalent now is to derive the MTIME and MTIMECMP addresses
from the CLINT address. */
#define configMTIME_BASE_ADDRESS ( ( configCLINT_BASE_ADDRESS ) + 0xBFF8UL )
#define configMTIMECMP_BASE_ADDRESS ( ( configCLINT_BASE_ADDRESS ) + 0x4000UL )
#elif !defined( configMTIME_BASE_ADDRESS ) || !defined( configMTIMECMP_BASE_ADDRESS )
#error configMTIME_BASE_ADDRESS and configMTIMECMP_BASE_ADDRESS must be defined in FreeRTOSConfig.h. Set them to zero if there is no MTIME (machine time) clock. See https://www.freertos.org/Using-FreeRTOS-on-RISC-V.html
#endif
#ifdef __cplusplus #ifdef __cplusplus
} }

View file

@ -46,7 +46,7 @@
/* Tasks should start with interrupts enabled and in Supervisor mode, therefore /* Tasks should start with interrupts enabled and in Supervisor mode, therefore
PSW is set with U and I set, and PM and IPL clear. */ PSW is set with U and I set, and PM and IPL clear. */
#define portINITIAL_PSW ( ( StackType_t ) 0x00030000 ) #define portINITIAL_PSW ( ( StackType_t ) 0x00030000 )
/* The peripheral clock is divided by this value before being supplying the /* The peripheral clock is divided by this value before being supplying the
CMT. */ CMT. */
@ -105,7 +105,7 @@ void vPortTickISR( void ) __attribute__((interrupt));
static void prvSetupTimerInterrupt( void ); static void prvSetupTimerInterrupt( void );
#ifndef configSETUP_TICK_INTERRUPT #ifndef configSETUP_TICK_INTERRUPT
/* The user has not provided their own tick interrupt configuration so use /* The user has not provided their own tick interrupt configuration so use
the definition in this file (which uses the interval timer). */ the definition in this file (which uses the interval timer). */
#define configSETUP_TICK_INTERRUPT() prvSetupTimerInterrupt() #define configSETUP_TICK_INTERRUPT() prvSetupTimerInterrupt()
#endif /* configSETUP_TICK_INTERRUPT */ #endif /* configSETUP_TICK_INTERRUPT */
@ -162,7 +162,7 @@ StackType_t *pxPortInitialiseStack( StackType_t *pxTopOfStack, TaskFunction_t px
/* R0 is not included as it is the stack pointer. */ /* R0 is not included as it is the stack pointer. */
*pxTopOfStack = 0x00; *pxTopOfStack = 0x00;
pxTopOfStack--; pxTopOfStack--;
*pxTopOfStack = 0x00; *pxTopOfStack = 0x00;
pxTopOfStack--; pxTopOfStack--;
*pxTopOfStack = portINITIAL_PSW; *pxTopOfStack = portINITIAL_PSW;
pxTopOfStack--; pxTopOfStack--;
@ -284,22 +284,22 @@ static void prvStartFirstTask( void )
/* Restore the registers from the stack of the task pointed to by /* Restore the registers from the stack of the task pointed to by
pxCurrentTCB. */ pxCurrentTCB. */
"POP R15 \n" \ "POP R15 \n" \
/* Accumulator low 32 bits. */ /* Accumulator low 32 bits. */
"MVTACLO R15 \n" \ "MVTACLO R15 \n" \
"POP R15 \n" \ "POP R15 \n" \
/* Accumulator high 32 bits. */ /* Accumulator high 32 bits. */
"MVTACHI R15 \n" \ "MVTACHI R15 \n" \
/* R1 to R15 - R0 is not included as it is the SP. */ /* R1 to R15 - R0 is not included as it is the SP. */
"POPM R1-R15 \n" \ "POPM R1-R15 \n" \
/* This pops the remaining registers. */ /* This pops the remaining registers. */
"RTE \n" \ "RTE \n" \
"NOP \n" \ "NOP \n" \
"NOP \n" "NOP \n"
); );
} }
/*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/
@ -573,14 +573,14 @@ static void prvSetupTimerInterrupt( void )
} }
else if( eSleepAction == eNoTasksWaitingTimeout ) else if( eSleepAction == eNoTasksWaitingTimeout )
{ {
/* Protection off. */ /* Protection off. */
SYSTEM.PRCR.WORD = portUNLOCK_KEY; SYSTEM.PRCR.WORD = portUNLOCK_KEY;
/* Ready for software standby with all clocks stopped. */ /* Ready for software standby with all clocks stopped. */
SYSTEM.SBYCR.BIT.SSBY = 1; SYSTEM.SBYCR.BIT.SSBY = 1;
/* Protection on. */ /* Protection on. */
SYSTEM.PRCR.WORD = portLOCK_KEY; SYSTEM.PRCR.WORD = portLOCK_KEY;
/* Sleep until something happens. Calling prvSleep() will /* Sleep until something happens. Calling prvSleep() will
automatically reset the i bit in the PSW. */ automatically reset the i bit in the PSW. */
@ -591,18 +591,18 @@ static void prvSetupTimerInterrupt( void )
} }
else else
{ {
/* Protection off. */ /* Protection off. */
SYSTEM.PRCR.WORD = portUNLOCK_KEY; SYSTEM.PRCR.WORD = portUNLOCK_KEY;
/* Ready for deep sleep mode. */ /* Ready for deep sleep mode. */
SYSTEM.MSTPCRC.BIT.DSLPE = 1; SYSTEM.MSTPCRC.BIT.DSLPE = 1;
SYSTEM.MSTPCRA.BIT.MSTPA28 = 1; SYSTEM.MSTPCRA.BIT.MSTPA28 = 1;
SYSTEM.SBYCR.BIT.SSBY = 0; SYSTEM.SBYCR.BIT.SSBY = 0;
/* Protection on. */ /* Protection on. */
SYSTEM.PRCR.WORD = portLOCK_KEY; SYSTEM.PRCR.WORD = portLOCK_KEY;
/* Adjust the match value to take into account that the current /* Adjust the match value to take into account that the current
time slice is already partially complete. */ time slice is already partially complete. */
ulMatchValue -= ( uint32_t ) CMT0.CMCNT; ulMatchValue -= ( uint32_t ) CMT0.CMCNT;
CMT0.CMCOR = ( uint16_t ) ulMatchValue; CMT0.CMCOR = ( uint16_t ) ulMatchValue;

View file

@ -37,13 +37,15 @@
#include "task.h" #include "task.h"
/* Constants required to manipulate the NVIC. */ /* Constants required to manipulate the NVIC. */
#define portNVIC_SYSTICK_CTRL ( ( volatile uint32_t * ) 0xe000e010 ) #define portNVIC_SYSTICK_CTRL_REG ( * ( ( volatile uint32_t * ) 0xe000e010 ) )
#define portNVIC_SYSTICK_LOAD ( ( volatile uint32_t * ) 0xe000e014 ) #define portNVIC_SYSTICK_LOAD_REG ( * ( ( volatile uint32_t * ) 0xe000e014 ) )
#define portNVIC_SYSTICK_CURRENT_VALUE ( ( volatile uint32_t * ) 0xe000e018 ) #define portNVIC_SYSTICK_CURRENT_VALUE_REG ( * ( ( volatile uint32_t * ) 0xe000e018 ) )
#define portNVIC_SYSPRI2 ( ( volatile uint32_t *) 0xe000ed20 ) #define portNVIC_INT_CTRL_REG ( * ( ( volatile uint32_t * ) 0xe000ed04 ) )
#define portNVIC_SYSTICK_CLK 0x00000004 #define portNVIC_SYSPRI2_REG ( * ( ( volatile uint32_t *) 0xe000ed20 ) )
#define portNVIC_SYSTICK_INT 0x00000002 #define portNVIC_SYSTICK_CLK_BIT ( 1UL << 2UL )
#define portNVIC_SYSTICK_ENABLE 0x00000001 #define portNVIC_SYSTICK_INT_BIT ( 1UL << 1UL )
#define portNVIC_SYSTICK_ENABLE_BIT ( 1UL << 0UL )
#define portNVIC_SYSTICK_COUNT_FLAG_BIT ( 1UL << 16UL )
#define portMIN_INTERRUPT_PRIORITY ( 255UL ) #define portMIN_INTERRUPT_PRIORITY ( 255UL )
#define portNVIC_PENDSV_PRI ( portMIN_INTERRUPT_PRIORITY << 16UL ) #define portNVIC_PENDSV_PRI ( portMIN_INTERRUPT_PRIORITY << 16UL )
#define portNVIC_SYSTICK_PRI ( portMIN_INTERRUPT_PRIORITY << 24UL ) #define portNVIC_SYSTICK_PRI ( portMIN_INTERRUPT_PRIORITY << 24UL )
@ -62,10 +64,40 @@ FreeRTOS.org versions prior to V4.3.0 did not include this definition. */
variable. */ variable. */
static UBaseType_t uxCriticalNesting = 0xaaaaaaaa; static UBaseType_t uxCriticalNesting = 0xaaaaaaaa;
/* The systick is a 24-bit counter. */
#define portMAX_24_BIT_NUMBER ( 0xffffffUL )
/* A fiddle factor to estimate the number of SysTick counts that would have
occurred while the SysTick counter is stopped during tickless idle
calculations. */
#ifndef portMISSED_COUNTS_FACTOR
#define portMISSED_COUNTS_FACTOR ( 45UL )
#endif
/* The number of SysTick increments that make up one tick period. */
#if( configUSE_TICKLESS_IDLE == 1 )
static uint32_t ulTimerCountsForOneTick = 0;
#endif /* configUSE_TICKLESS_IDLE */
/* The maximum number of tick periods that can be suppressed is limited by the
24 bit resolution of the SysTick timer. */
#if( configUSE_TICKLESS_IDLE == 1 )
static uint32_t xMaximumPossibleSuppressedTicks = 0;
#endif /* configUSE_TICKLESS_IDLE */
/* Compensate for the CPU cycles that pass while the SysTick is stopped (low
power functionality only. */
#if( configUSE_TICKLESS_IDLE == 1 )
static uint32_t ulStoppedTimerCompensation = 0;
#endif /* configUSE_TICKLESS_IDLE */
/* /*
* Setup the timer to generate the tick interrupts. * Setup the timer to generate the tick interrupts. The implementation in this
* file is weak to allow application writers to change the timer used to
* generate the tick interrupt.
*/ */
static void prvSetupTimerInterrupt( void ); #pragma weak vPortSetupTimerInterrupt
void vPortSetupTimerInterrupt( void );
/* /*
* Exception handlers. * Exception handlers.
@ -125,12 +157,12 @@ static void prvTaskExitError( void )
BaseType_t xPortStartScheduler( void ) BaseType_t xPortStartScheduler( void )
{ {
/* Make PendSV and SysTick the lowest priority interrupts. */ /* Make PendSV and SysTick the lowest priority interrupts. */
*(portNVIC_SYSPRI2) |= portNVIC_PENDSV_PRI; portNVIC_SYSPRI2_REG |= portNVIC_PENDSV_PRI;
*(portNVIC_SYSPRI2) |= portNVIC_SYSTICK_PRI; portNVIC_SYSPRI2_REG |= portNVIC_SYSTICK_PRI;
/* Start the timer that generates the tick ISR. Interrupts are disabled /* Start the timer that generates the tick ISR. Interrupts are disabled
here already. */ here already. */
prvSetupTimerInterrupt(); vPortSetupTimerInterrupt();
/* Initialise the critical nesting count ready for the first task. */ /* Initialise the critical nesting count ready for the first task. */
uxCriticalNesting = 0; uxCriticalNesting = 0;
@ -154,7 +186,7 @@ void vPortEndScheduler( void )
void vPortYield( void ) void vPortYield( void )
{ {
/* Set a PendSV to request a context switch. */ /* Set a PendSV to request a context switch. */
*(portNVIC_INT_CTRL) = portNVIC_PENDSVSET; portNVIC_INT_CTRL_REG = portNVIC_PENDSVSET;
/* Barriers are normally not required but do ensure the code is completely /* Barriers are normally not required but do ensure the code is completely
within the specified behaviour for the architecture. */ within the specified behaviour for the architecture. */
@ -193,7 +225,7 @@ uint32_t ulPreviousMask;
if( xTaskIncrementTick() != pdFALSE ) if( xTaskIncrementTick() != pdFALSE )
{ {
/* Pend a context switch. */ /* Pend a context switch. */
*(portNVIC_INT_CTRL) = portNVIC_PENDSVSET; portNVIC_INT_CTRL_REG = portNVIC_PENDSVSET;
} }
} }
portCLEAR_INTERRUPT_MASK_FROM_ISR( ulPreviousMask ); portCLEAR_INTERRUPT_MASK_FROM_ISR( ulPreviousMask );
@ -204,15 +236,189 @@ uint32_t ulPreviousMask;
* Setup the systick timer to generate the tick interrupts at the required * Setup the systick timer to generate the tick interrupts at the required
* frequency. * frequency.
*/ */
static void prvSetupTimerInterrupt( void ) void vPortSetupTimerInterrupt( void )
{ {
/* Calculate the constants required to configure the tick interrupt. */
#if( configUSE_TICKLESS_IDLE == 1 )
{
ulTimerCountsForOneTick = ( configCPU_CLOCK_HZ / configTICK_RATE_HZ );
xMaximumPossibleSuppressedTicks = portMAX_24_BIT_NUMBER / ulTimerCountsForOneTick;
ulStoppedTimerCompensation = portMISSED_COUNTS_FACTOR;
}
#endif /* configUSE_TICKLESS_IDLE */
/* Stop and reset the SysTick. */ /* Stop and reset the SysTick. */
*(portNVIC_SYSTICK_CTRL) = 0UL; portNVIC_SYSTICK_CTRL_REG = 0UL;
*(portNVIC_SYSTICK_CURRENT_VALUE) = 0UL; portNVIC_SYSTICK_CURRENT_VALUE_REG = 0UL;
/* Configure SysTick to interrupt at the requested rate. */ /* Configure SysTick to interrupt at the requested rate. */
*(portNVIC_SYSTICK_LOAD) = ( configCPU_CLOCK_HZ / configTICK_RATE_HZ ) - 1UL; portNVIC_SYSTICK_LOAD_REG = ( configCPU_CLOCK_HZ / configTICK_RATE_HZ ) - 1UL;
*(portNVIC_SYSTICK_CTRL) = portNVIC_SYSTICK_CLK | portNVIC_SYSTICK_INT | portNVIC_SYSTICK_ENABLE; portNVIC_SYSTICK_CTRL_REG = portNVIC_SYSTICK_CLK_BIT | portNVIC_SYSTICK_INT_BIT | portNVIC_SYSTICK_ENABLE_BIT;
} }
/*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/
#if( configUSE_TICKLESS_IDLE == 1 )
__weak void vPortSuppressTicksAndSleep( TickType_t xExpectedIdleTime )
{
uint32_t ulReloadValue, ulCompleteTickPeriods, ulCompletedSysTickDecrements;
TickType_t xModifiableIdleTime;
/* Make sure the SysTick reload value does not overflow the counter. */
if( xExpectedIdleTime > xMaximumPossibleSuppressedTicks )
{
xExpectedIdleTime = xMaximumPossibleSuppressedTicks;
}
/* Stop the SysTick momentarily. The time the SysTick is stopped for
is accounted for as best it can be, but using the tickless mode will
inevitably result in some tiny drift of the time maintained by the
kernel with respect to calendar time. */
portNVIC_SYSTICK_CTRL_REG &= ~portNVIC_SYSTICK_ENABLE_BIT;
/* Calculate the reload value required to wait xExpectedIdleTime
tick periods. -1 is used because this code will execute part way
through one of the tick periods. */
ulReloadValue = portNVIC_SYSTICK_CURRENT_VALUE_REG + ( ulTimerCountsForOneTick * ( xExpectedIdleTime - 1UL ) );
if( ulReloadValue > ulStoppedTimerCompensation )
{
ulReloadValue -= ulStoppedTimerCompensation;
}
/* Enter a critical section but don't use the taskENTER_CRITICAL()
method as that will mask interrupts that should exit sleep mode. */
__disable_interrupt();
__DSB();
__ISB();
/* If a context switch is pending or a task is waiting for the scheduler
to be unsuspended then abandon the low power entry. */
if( eTaskConfirmSleepModeStatus() == eAbortSleep )
{
/* Restart from whatever is left in the count register to complete
this tick period. */
portNVIC_SYSTICK_LOAD_REG = portNVIC_SYSTICK_CURRENT_VALUE_REG;
/* Restart SysTick. */
portNVIC_SYSTICK_CTRL_REG |= portNVIC_SYSTICK_ENABLE_BIT;
/* Reset the reload register to the value required for normal tick
periods. */
portNVIC_SYSTICK_LOAD_REG = ulTimerCountsForOneTick - 1UL;
/* Re-enable interrupts - see comments above __disable_interrupt()
call above. */
__enable_interrupt();
}
else
{
/* Set the new reload value. */
portNVIC_SYSTICK_LOAD_REG = ulReloadValue;
/* Clear the SysTick count flag and set the count value back to
zero. */
portNVIC_SYSTICK_CURRENT_VALUE_REG = 0UL;
/* Restart SysTick. */
portNVIC_SYSTICK_CTRL_REG |= portNVIC_SYSTICK_ENABLE_BIT;
/* Sleep until something happens. configPRE_SLEEP_PROCESSING() can
set its parameter to 0 to indicate that its implementation contains
its own wait for interrupt or wait for event instruction, and so wfi
should not be executed again. However, the original expected idle
time variable must remain unmodified, so a copy is taken. */
xModifiableIdleTime = xExpectedIdleTime;
configPRE_SLEEP_PROCESSING( xModifiableIdleTime );
if( xModifiableIdleTime > 0 )
{
__DSB();
__WFI();
__ISB();
}
configPOST_SLEEP_PROCESSING( xExpectedIdleTime );
/* Re-enable interrupts to allow the interrupt that brought the MCU
out of sleep mode to execute immediately. see comments above
__disable_interrupt() call above. */
__enable_interrupt();
__DSB();
__ISB();
/* Disable interrupts again because the clock is about to be stopped
and interrupts that execute while the clock is stopped will increase
any slippage between the time maintained by the RTOS and calendar
time. */
__disable_interrupt();
__DSB();
__ISB();
/* Disable the SysTick clock without reading the
portNVIC_SYSTICK_CTRL_REG register to ensure the
portNVIC_SYSTICK_COUNT_FLAG_BIT is not cleared if it is set. Again,
the time the SysTick is stopped for is accounted for as best it can
be, but using the tickless mode will inevitably result in some tiny
drift of the time maintained by the kernel with respect to calendar
time*/
portNVIC_SYSTICK_CTRL_REG = ( portNVIC_SYSTICK_CLK_BIT | portNVIC_SYSTICK_INT_BIT );
/* Determine if the SysTick clock has already counted to zero and
been set back to the current reload value (the reload back being
correct for the entire expected idle time) or if the SysTick is yet
to count to zero (in which case an interrupt other than the SysTick
must have brought the system out of sleep mode). */
if( ( portNVIC_SYSTICK_CTRL_REG & portNVIC_SYSTICK_COUNT_FLAG_BIT ) != 0 )
{
uint32_t ulCalculatedLoadValue;
/* The tick interrupt is already pending, and the SysTick count
reloaded with ulReloadValue. Reset the
portNVIC_SYSTICK_LOAD_REG with whatever remains of this tick
period. */
ulCalculatedLoadValue = ( ulTimerCountsForOneTick - 1UL ) - ( ulReloadValue - portNVIC_SYSTICK_CURRENT_VALUE_REG );
/* Don't allow a tiny value, or values that have somehow
underflowed because the post sleep hook did something
that took too long. */
if( ( ulCalculatedLoadValue < ulStoppedTimerCompensation ) || ( ulCalculatedLoadValue > ulTimerCountsForOneTick ) )
{
ulCalculatedLoadValue = ( ulTimerCountsForOneTick - 1UL );
}
portNVIC_SYSTICK_LOAD_REG = ulCalculatedLoadValue;
/* As the pending tick will be processed as soon as this
function exits, the tick value maintained by the tick is stepped
forward by one less than the time spent waiting. */
ulCompleteTickPeriods = xExpectedIdleTime - 1UL;
}
else
{
/* Something other than the tick interrupt ended the sleep.
Work out how long the sleep lasted rounded to complete tick
periods (not the ulReload value which accounted for part
ticks). */
ulCompletedSysTickDecrements = ( xExpectedIdleTime * ulTimerCountsForOneTick ) - portNVIC_SYSTICK_CURRENT_VALUE_REG ;
/* How many complete tick periods passed while the processor
was waiting? */
ulCompleteTickPeriods = ulCompletedSysTickDecrements / ulTimerCountsForOneTick;
/* The reload value is set to whatever fraction of a single tick
period remains. */
portNVIC_SYSTICK_LOAD_REG = ( ( ulCompleteTickPeriods + 1UL ) * ulTimerCountsForOneTick ) - ulCompletedSysTickDecrements;
}
/* Restart SysTick so it runs from portNVIC_SYSTICK_LOAD_REG
again, then set portNVIC_SYSTICK_LOAD_REG back to its standard
value. */
portNVIC_SYSTICK_CURRENT_VALUE_REG = 0UL;
portNVIC_SYSTICK_CTRL_REG |= portNVIC_SYSTICK_ENABLE_BIT;
vTaskStepTick( ulCompleteTickPeriods );
portNVIC_SYSTICK_LOAD_REG = ulTimerCountsForOneTick - 1UL;
/* Exit with interrpts enabled. */
__enable_interrupt();
}
}
#endif /* configUSE_TICKLESS_IDLE */

View file

@ -103,6 +103,13 @@ extern void vClearInterruptMaskFromISR( uint32_t ulMask );
/*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/
/* Tickless idle/low power functionality. */
#ifndef portSUPPRESS_TICKS_AND_SLEEP
extern void vPortSuppressTicksAndSleep( TickType_t xExpectedIdleTime );
#define portSUPPRESS_TICKS_AND_SLEEP( xExpectedIdleTime ) vPortSuppressTicksAndSleep( xExpectedIdleTime )
#endif
/*-----------------------------------------------------------*/
/* Task function macros as described on the FreeRTOS.org WEB site. */ /* Task function macros as described on the FreeRTOS.org WEB site. */
#define portTASK_FUNCTION_PROTO( vFunction, pvParameters ) void vFunction( void *pvParameters ) #define portTASK_FUNCTION_PROTO( vFunction, pvParameters ) void vFunction( void *pvParameters )
#define portTASK_FUNCTION( vFunction, pvParameters ) void vFunction( void *pvParameters ) #define portTASK_FUNCTION( vFunction, pvParameters ) void vFunction( void *pvParameters )

View file

@ -292,6 +292,13 @@ typedef struct MPU_SETTINGS
#define portMEMORY_BARRIER() __asm volatile( "" ::: "memory" ) #define portMEMORY_BARRIER() __asm volatile( "" ::: "memory" )
/*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/
/* Suppress warnings that are generated by the IAR tools, but cannot be fixed in
* the source code because to do so would cause other compilers to generate
* warnings. */
#pragma diag_suppress=Be006
#pragma diag_suppress=Pa082
/*-----------------------------------------------------------*/
#ifdef __cplusplus #ifdef __cplusplus
} }
#endif #endif

View file

@ -292,6 +292,13 @@ typedef struct MPU_SETTINGS
#define portMEMORY_BARRIER() __asm volatile( "" ::: "memory" ) #define portMEMORY_BARRIER() __asm volatile( "" ::: "memory" )
/*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/
/* Suppress warnings that are generated by the IAR tools, but cannot be fixed in
* the source code because to do so would cause other compilers to generate
* warnings. */
#pragma diag_suppress=Be006
#pragma diag_suppress=Pa082
/*-----------------------------------------------------------*/
#ifdef __cplusplus #ifdef __cplusplus
} }
#endif #endif

View file

@ -164,6 +164,34 @@ not necessary for to use this port. They are defined so the common demo files
/* portNOP() is not required by this port. */ /* portNOP() is not required by this port. */
#define portNOP() #define portNOP()
#define portINLINE __inline
#ifndef portFORCE_INLINE
#define portFORCE_INLINE inline __attribute__(( always_inline))
#endif
/*-----------------------------------------------------------*/
portFORCE_INLINE static BaseType_t xPortIsInsideInterrupt( void )
{
uint32_t ulCurrentInterrupt;
BaseType_t xReturn;
/* Obtain the number of the currently executing interrupt. */
__asm volatile( "mrs %0, ipsr" : "=r"( ulCurrentInterrupt ) :: "memory" );
if( ulCurrentInterrupt == 0 )
{
xReturn = pdFALSE;
}
else
{
xReturn = pdTRUE;
}
return xReturn;
}
/*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/
/* Suppress warnings that are generated by the IAR tools, but cannot be fixed in /* Suppress warnings that are generated by the IAR tools, but cannot be fixed in

View file

@ -292,6 +292,13 @@ typedef struct MPU_SETTINGS
#define portMEMORY_BARRIER() __asm volatile( "" ::: "memory" ) #define portMEMORY_BARRIER() __asm volatile( "" ::: "memory" )
/*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/
/* Suppress warnings that are generated by the IAR tools, but cannot be fixed in
* the source code because to do so would cause other compilers to generate
* warnings. */
#pragma diag_suppress=Be006
#pragma diag_suppress=Pa082
/*-----------------------------------------------------------*/
#ifdef __cplusplus #ifdef __cplusplus
} }
#endif #endif

View file

@ -292,6 +292,13 @@ typedef struct MPU_SETTINGS
#define portMEMORY_BARRIER() __asm volatile( "" ::: "memory" ) #define portMEMORY_BARRIER() __asm volatile( "" ::: "memory" )
/*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/
/* Suppress warnings that are generated by the IAR tools, but cannot be fixed in
* the source code because to do so would cause other compilers to generate
* warnings. */
#pragma diag_suppress=Be006
#pragma diag_suppress=Pa082
/*-----------------------------------------------------------*/
#ifdef __cplusplus #ifdef __cplusplus
} }
#endif #endif

View file

@ -77,6 +77,12 @@ typedef unsigned long UBaseType_t;
#define portBYTE_ALIGNMENT 8 #define portBYTE_ALIGNMENT 8
/*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/
/* Compiler directives. */
#define portWEAK_SYMBOL __attribute__( ( weak ) )
/*-----------------------------------------------------------*/
/* Scheduler utilities. */ /* Scheduler utilities. */
#define portYIELD() \ #define portYIELD() \
{ \ { \
@ -157,6 +163,34 @@ not necessary for to use this port. They are defined so the common demo files
/* portNOP() is not required by this port. */ /* portNOP() is not required by this port. */
#define portNOP() #define portNOP()
#define portINLINE __inline
#ifndef portFORCE_INLINE
#define portFORCE_INLINE inline __attribute__(( always_inline))
#endif
/*-----------------------------------------------------------*/
portFORCE_INLINE static BaseType_t xPortIsInsideInterrupt( void )
{
uint32_t ulCurrentInterrupt;
BaseType_t xReturn;
/* Obtain the number of the currently executing interrupt. */
__asm volatile( "mrs %0, ipsr" : "=r"( ulCurrentInterrupt ) :: "memory" );
if( ulCurrentInterrupt == 0 )
{
xReturn = pdFALSE;
}
else
{
xReturn = pdTRUE;
}
return xReturn;
}
/*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/
/* Suppress warnings that are generated by the IAR tools, but cannot be fixed in /* Suppress warnings that are generated by the IAR tools, but cannot be fixed in

View file

@ -33,8 +33,8 @@
#include <intrinsics.h> #include <intrinsics.h>
/* Defining MPU_WRAPPERS_INCLUDED_FROM_API_FILE prevents task.h from redefining /* Defining MPU_WRAPPERS_INCLUDED_FROM_API_FILE prevents task.h from redefining
all the API functions to use the MPU wrappers. That should only be done when * all the API functions to use the MPU wrappers. That should only be done when
task.h is included from an application file. */ * task.h is included from an application file. */
#define MPU_WRAPPERS_INCLUDED_FROM_API_FILE #define MPU_WRAPPERS_INCLUDED_FROM_API_FILE
/* Scheduler includes. */ /* Scheduler includes. */
@ -43,8 +43,6 @@ task.h is included from an application file. */
#undef MPU_WRAPPERS_INCLUDED_FROM_API_FILE #undef MPU_WRAPPERS_INCLUDED_FROM_API_FILE
#warning This is not yet a documented port as it has not been fully tested, so no demo projects that use this port are provided.
#ifndef __ARMVFP__ #ifndef __ARMVFP__
#error This port can only be used when the project options are configured to enable hardware floating point support. #error This port can only be used when the project options are configured to enable hardware floating point support.
#endif #endif
@ -94,7 +92,7 @@ task.h is included from an application file. */
#define portNVIC_PEND_SYSTICK_CLEAR_BIT ( 1UL << 25UL ) #define portNVIC_PEND_SYSTICK_CLEAR_BIT ( 1UL << 25UL )
/* Constants used to detect a Cortex-M7 r0p1 core, which should use the ARM_CM7 /* Constants used to detect a Cortex-M7 r0p1 core, which should use the ARM_CM7
r0p1 port. */ * r0p1 port. */
#define portCPUID ( * ( ( volatile uint32_t * ) 0xE000ed00 ) ) #define portCPUID ( * ( ( volatile uint32_t * ) 0xE000ed00 ) )
#define portCORTEX_M7_r0p1_ID ( 0x410FC271UL ) #define portCORTEX_M7_r0p1_ID ( 0x410FC271UL )
#define portCORTEX_M7_r0p0_ID ( 0x410FC270UL ) #define portCORTEX_M7_r0p0_ID ( 0x410FC270UL )
@ -222,10 +220,10 @@ static UBaseType_t uxCriticalNesting = 0xaaaaaaaa;
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 )
{ {
/* Simulate the stack frame as it would be created by a context switch /* Simulate the stack frame as it would be created by a context switch
interrupt. */ * interrupt. */
/* Offset added to account for the way the MCU uses the stack on entry/exit /* Offset added to account for the way the MCU uses the stack on entry/exit
of interrupts, and to ensure alignment. */ * of interrupts, and to ensure alignment. */
pxTopOfStack--; pxTopOfStack--;
*pxTopOfStack = portINITIAL_XPSR; /* xPSR */ *pxTopOfStack = portINITIAL_XPSR; /* xPSR */
@ -239,7 +237,7 @@ StackType_t *pxPortInitialiseStack( StackType_t *pxTopOfStack, TaskFunction_t px
*pxTopOfStack = ( StackType_t ) pvParameters; /* R0 */ *pxTopOfStack = ( StackType_t ) pvParameters; /* R0 */
/* A save method is being used that requires each task to maintain its /* A save method is being used that requires each task to maintain its
own exec return value. */ * own exec return value. */
pxTopOfStack--; pxTopOfStack--;
*pxTopOfStack = portINITIAL_EXC_RETURN; *pxTopOfStack = portINITIAL_EXC_RETURN;
@ -261,10 +259,16 @@ StackType_t *pxPortInitialiseStack( StackType_t *pxTopOfStack, TaskFunction_t px
void vPortSVCHandler_C( uint32_t *pulParam ) void vPortSVCHandler_C( uint32_t *pulParam )
{ {
uint8_t ucSVCNumber; uint8_t ucSVCNumber;
uint32_t ulPC;
#if( configENFORCE_SYSTEM_CALLS_FROM_KERNEL_ONLY == 1 )
extern uint32_t __syscalls_flash_start__[];
extern uint32_t __syscalls_flash_end__[];
#endif /* #if( configENFORCE_SYSTEM_CALLS_FROM_KERNEL_ONLY == 1 ) */
/* The stack contains: r0, r1, r2, r3, r12, r14, the return address and /* The stack contains: r0, r1, r2, r3, r12, LR, PC and xPSR. The first
xPSR. The first argument (r0) is pulParam[ 0 ]. */ * argument (r0) is pulParam[ 0 ]. */
ucSVCNumber = ( ( uint8_t * ) pulParam[ portOFFSET_TO_PC ] )[ -2 ]; ulPC = pulParam[ portOFFSET_TO_PC ];
ucSVCNumber = ( ( uint8_t * ) ulPC )[ -2 ];
switch( ucSVCNumber ) switch( ucSVCNumber )
{ {
case portSVC_START_SCHEDULER : portNVIC_SYSPRI1_REG |= portNVIC_SVC_PRI; case portSVC_START_SCHEDULER : portNVIC_SYSPRI1_REG |= portNVIC_SVC_PRI;
@ -273,14 +277,31 @@ uint8_t ucSVCNumber;
case portSVC_YIELD : portNVIC_INT_CTRL_REG = portNVIC_PENDSVSET_BIT; case portSVC_YIELD : portNVIC_INT_CTRL_REG = portNVIC_PENDSVSET_BIT;
/* Barriers are normally not required /* Barriers are normally not required
but do ensure the code is completely * but do ensure the code is completely
within the specified behaviour for the * within the specified behaviour for the
architecture. */ * architecture. */
__asm volatile( "dsb" ::: "memory" ); __asm volatile( "dsb" ::: "memory" );
__asm volatile( "isb" ); __asm volatile( "isb" );
break; break;
#if( configENFORCE_SYSTEM_CALLS_FROM_KERNEL_ONLY == 1 )
case portSVC_RAISE_PRIVILEGE : /* Only raise the privilege, if the
* svc was raised from any of the
* system calls. */
if( ulPC >= ( uint32_t ) __syscalls_flash_start__ &&
ulPC <= ( uint32_t ) __syscalls_flash_end__ )
{
__asm volatile
(
" mrs r1, control \n" /* Obtain current control value. */
" bic r1, r1, #1 \n" /* Set privilege bit. */
" msr control, r1 \n" /* Write back new control value. */
::: "r1", "memory"
);
}
break;
#else
case portSVC_RAISE_PRIVILEGE : __asm volatile case portSVC_RAISE_PRIVILEGE : __asm volatile
( (
" mrs r1, control \n" /* Obtain current control value. */ " mrs r1, control \n" /* Obtain current control value. */
@ -289,6 +310,7 @@ uint8_t ucSVCNumber;
::: "r1", "memory" ::: "r1", "memory"
); );
break; break;
#endif /* #if( configENFORCE_SYSTEM_CALLS_FROM_KERNEL_ONLY == 1 ) */
default : /* Unknown SVC call. */ default : /* Unknown SVC call. */
break; break;
@ -302,12 +324,12 @@ uint8_t ucSVCNumber;
BaseType_t xPortStartScheduler( void ) BaseType_t xPortStartScheduler( void )
{ {
/* configMAX_SYSCALL_INTERRUPT_PRIORITY must not be set to 0. /* configMAX_SYSCALL_INTERRUPT_PRIORITY must not be set to 0.
See http://www.FreeRTOS.org/RTOS-Cortex-M3-M4.html */ * See http://www.FreeRTOS.org/RTOS-Cortex-M3-M4.html */
configASSERT( configMAX_SYSCALL_INTERRUPT_PRIORITY ); configASSERT( configMAX_SYSCALL_INTERRUPT_PRIORITY );
/* This port can be used on all revisions of the Cortex-M7 core other than /* This port can be used on all revisions of the Cortex-M7 core other than
the r0p1 parts. r0p1 parts should use the port from the * the r0p1 parts. r0p1 parts should use the port from the
/source/portable/GCC/ARM_CM7/r0p1 directory. */ * /source/portable/GCC/ARM_CM7/r0p1 directory. */
configASSERT( portCPUID != portCORTEX_M7_r0p1_ID ); configASSERT( portCPUID != portCORTEX_M7_r0p1_ID );
configASSERT( portCPUID != portCORTEX_M7_r0p0_ID ); configASSERT( portCPUID != portCORTEX_M7_r0p0_ID );
@ -318,15 +340,15 @@ BaseType_t xPortStartScheduler( void )
volatile uint8_t ucMaxPriorityValue; volatile uint8_t ucMaxPriorityValue;
/* Determine the maximum priority from which ISR safe FreeRTOS API /* Determine the maximum priority from which ISR safe FreeRTOS API
functions can be called. ISR safe functions are those that end in * functions can be called. ISR safe functions are those that end in
"FromISR". FreeRTOS maintains separate thread and ISR API functions to * "FromISR". FreeRTOS maintains separate thread and ISR API functions to
ensure interrupt entry is as fast and simple as possible. * ensure interrupt entry is as fast and simple as possible.
Save the interrupt priority value that is about to be clobbered. */ Save the interrupt priority value that is about to be clobbered. */
ulOriginalPriority = *pucFirstUserPriorityRegister; ulOriginalPriority = *pucFirstUserPriorityRegister;
/* Determine the number of priority bits available. First write to all /* Determine the number of priority bits available. First write to all
possible bits. */ * possible bits. */
*pucFirstUserPriorityRegister = portMAX_8_BIT_VALUE; *pucFirstUserPriorityRegister = portMAX_8_BIT_VALUE;
/* Read the value back to see how many bits stuck. */ /* Read the value back to see how many bits stuck. */
@ -336,7 +358,7 @@ BaseType_t xPortStartScheduler( void )
ucMaxSysCallPriority = configMAX_SYSCALL_INTERRUPT_PRIORITY & ucMaxPriorityValue; ucMaxSysCallPriority = configMAX_SYSCALL_INTERRUPT_PRIORITY & ucMaxPriorityValue;
/* Calculate the maximum acceptable priority group value for the number /* Calculate the maximum acceptable priority group value for the number
of bits read back. */ * of bits read back. */
ulMaxPRIGROUPValue = portMAX_PRIGROUP_BITS; ulMaxPRIGROUPValue = portMAX_PRIGROUP_BITS;
while( ( ucMaxPriorityValue & portTOP_BIT_OF_BYTE ) == portTOP_BIT_OF_BYTE ) while( ( ucMaxPriorityValue & portTOP_BIT_OF_BYTE ) == portTOP_BIT_OF_BYTE )
{ {
@ -347,8 +369,8 @@ BaseType_t xPortStartScheduler( void )
#ifdef __NVIC_PRIO_BITS #ifdef __NVIC_PRIO_BITS
{ {
/* Check the CMSIS configuration that defines the number of /* Check the CMSIS configuration that defines the number of
priority bits matches the number of priority bits actually queried * priority bits matches the number of priority bits actually queried
from the hardware. */ * from the hardware. */
configASSERT( ( portMAX_PRIGROUP_BITS - ulMaxPRIGROUPValue ) == __NVIC_PRIO_BITS ); configASSERT( ( portMAX_PRIGROUP_BITS - ulMaxPRIGROUPValue ) == __NVIC_PRIO_BITS );
} }
#endif #endif
@ -356,19 +378,19 @@ BaseType_t xPortStartScheduler( void )
#ifdef configPRIO_BITS #ifdef configPRIO_BITS
{ {
/* Check the FreeRTOS configuration that defines the number of /* Check the FreeRTOS configuration that defines the number of
priority bits matches the number of priority bits actually queried * priority bits matches the number of priority bits actually queried
from the hardware. */ * from the hardware. */
configASSERT( ( portMAX_PRIGROUP_BITS - ulMaxPRIGROUPValue ) == configPRIO_BITS ); configASSERT( ( portMAX_PRIGROUP_BITS - ulMaxPRIGROUPValue ) == configPRIO_BITS );
} }
#endif #endif
/* Shift the priority group value back to its position within the AIRCR /* Shift the priority group value back to its position within the AIRCR
register. */ * register. */
ulMaxPRIGROUPValue <<= portPRIGROUP_SHIFT; ulMaxPRIGROUPValue <<= portPRIGROUP_SHIFT;
ulMaxPRIGROUPValue &= portPRIORITY_GROUP_MASK; ulMaxPRIGROUPValue &= portPRIORITY_GROUP_MASK;
/* Restore the clobbered interrupt priority register to its original /* Restore the clobbered interrupt priority register to its original
value. */ * value. */
*pucFirstUserPriorityRegister = ulOriginalPriority; *pucFirstUserPriorityRegister = ulOriginalPriority;
} }
#endif /* conifgASSERT_DEFINED */ #endif /* conifgASSERT_DEFINED */
@ -381,7 +403,7 @@ BaseType_t xPortStartScheduler( void )
prvSetupMPU(); prvSetupMPU();
/* Start the timer that generates the tick ISR. Interrupts are disabled /* Start the timer that generates the tick ISR. Interrupts are disabled
here already. */ * here already. */
vPortSetupTimerInterrupt(); vPortSetupTimerInterrupt();
/* Initialise the critical nesting count ready for the first task. */ /* Initialise the critical nesting count ready for the first task. */
@ -404,7 +426,7 @@ BaseType_t xPortStartScheduler( void )
void vPortEndScheduler( void ) void vPortEndScheduler( void )
{ {
/* Not implemented in ports where there is nothing to return to. /* Not implemented in ports where there is nothing to return to.
Artificially force an assert. */ * Artificially force an assert. */
configASSERT( uxCriticalNesting == 1000UL ); configASSERT( uxCriticalNesting == 1000UL );
} }
/*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/
@ -419,10 +441,10 @@ void vPortEnterCritical( void )
vPortResetPrivilege( xRunningPrivileged ); vPortResetPrivilege( xRunningPrivileged );
/* This is not the interrupt safe version of the enter critical function so /* This is not the interrupt safe version of the enter critical function so
assert() if it is being called from an interrupt context. Only API * assert() if it is being called from an interrupt context. Only API
functions that end in "FromISR" can be used in an interrupt. Only assert if * functions that end in "FromISR" can be used in an interrupt. Only assert if
the critical nesting count is 1 to protect against recursive calls if the * the critical nesting count is 1 to protect against recursive calls if the
assert function also uses a critical section. */ * assert function also uses a critical section. */
if( uxCriticalNesting == 1 ) if( uxCriticalNesting == 1 )
{ {
configASSERT( ( portNVIC_INT_CTRL_REG & portVECTACTIVE_MASK ) == 0 ); configASSERT( ( portNVIC_INT_CTRL_REG & portVECTACTIVE_MASK ) == 0 );
@ -449,16 +471,16 @@ BaseType_t xRunningPrivileged = xPortRaisePrivilege();
void xPortSysTickHandler( void ) void xPortSysTickHandler( void )
{ {
/* The SysTick runs at the lowest interrupt priority, so when this interrupt /* The SysTick runs at the lowest interrupt priority, so when this interrupt
executes all interrupts must be unmasked. There is therefore no need to * executes all interrupts must be unmasked. There is therefore no need to
save and then restore the interrupt mask value as its value is already * save and then restore the interrupt mask value as its value is already
known. */ * known. */
portDISABLE_INTERRUPTS(); portDISABLE_INTERRUPTS();
{ {
/* Increment the RTOS tick. */ /* Increment the RTOS tick. */
if( xTaskIncrementTick() != pdFALSE ) if( xTaskIncrementTick() != pdFALSE )
{ {
/* A context switch is required. Context switching is performed in /* A context switch is required. Context switching is performed in
the PendSV interrupt. Pend the PendSV interrupt. */ * the PendSV interrupt. Pend the PendSV interrupt. */
portNVIC_INT_CTRL_REG = portNVIC_PENDSVSET_BIT; portNVIC_INT_CTRL_REG = portNVIC_PENDSVSET_BIT;
} }
} }
@ -504,8 +526,8 @@ extern uint32_t __privileged_data_end__[];
( portMPU_REGION_ENABLE ); ( portMPU_REGION_ENABLE );
/* Setup the first 16K for privileged only access (even though less /* Setup the first 16K for privileged only access (even though less
than 10K is actually being used). This is where the kernel code is * than 10K is actually being used). This is where the kernel code is
placed. */ * placed. */
portMPU_REGION_BASE_ADDRESS_REG = ( ( uint32_t ) __FLASH_segment_start__ ) | /* Base address. */ portMPU_REGION_BASE_ADDRESS_REG = ( ( uint32_t ) __FLASH_segment_start__ ) | /* Base address. */
( portMPU_REGION_VALID ) | ( portMPU_REGION_VALID ) |
( portPRIVILEGED_FLASH_REGION ); ( portPRIVILEGED_FLASH_REGION );
@ -516,7 +538,7 @@ extern uint32_t __privileged_data_end__[];
( portMPU_REGION_ENABLE ); ( portMPU_REGION_ENABLE );
/* Setup the privileged data RAM region. This is where the kernel data /* Setup the privileged data RAM region. This is where the kernel data
is placed. */ * is placed. */
portMPU_REGION_BASE_ADDRESS_REG = ( ( uint32_t ) __privileged_data_start__ ) | /* Base address. */ portMPU_REGION_BASE_ADDRESS_REG = ( ( uint32_t ) __privileged_data_start__ ) | /* Base address. */
( portMPU_REGION_VALID ) | ( portMPU_REGION_VALID ) |
( portPRIVILEGED_RAM_REGION ); ( portPRIVILEGED_RAM_REGION );
@ -527,7 +549,7 @@ extern uint32_t __privileged_data_end__[];
( portMPU_REGION_ENABLE ); ( portMPU_REGION_ENABLE );
/* By default allow everything to access the general peripherals. The /* By default allow everything to access the general peripherals. The
system peripherals and registers are protected. */ * system peripherals and registers are protected. */
portMPU_REGION_BASE_ADDRESS_REG = ( portPERIPHERALS_START_ADDRESS ) | portMPU_REGION_BASE_ADDRESS_REG = ( portPERIPHERALS_START_ADDRESS ) |
( portMPU_REGION_VALID ) | ( portMPU_REGION_VALID ) |
( portGENERAL_PERIPHERALS_REGION ); ( portGENERAL_PERIPHERALS_REGION );
@ -550,7 +572,7 @@ static uint32_t prvGetMPURegionSizeSetting( uint32_t ulActualSizeInBytes )
uint32_t ulRegionSize, ulReturnValue = 4; uint32_t ulRegionSize, ulReturnValue = 4;
/* 32 is the smallest region size, 31 is the largest valid value for /* 32 is the smallest region size, 31 is the largest valid value for
ulReturnValue. */ * ulReturnValue. */
for( ulRegionSize = 32UL; ulReturnValue < 31UL; ( ulRegionSize <<= 1UL ) ) for( ulRegionSize = 32UL; ulReturnValue < 31UL; ( ulRegionSize <<= 1UL ) )
{ {
if( ulActualSizeInBytes <= ulRegionSize ) if( ulActualSizeInBytes <= ulRegionSize )
@ -564,7 +586,7 @@ uint32_t ulRegionSize, ulReturnValue = 4;
} }
/* Shift the code by one before returning so it can be written directly /* Shift the code by one before returning so it can be written directly
into the the correct bit position of the attribute register. */ * into the the correct bit position of the attribute register. */
return ( ulReturnValue << 1UL ); return ( ulReturnValue << 1UL );
} }
/*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/
@ -593,7 +615,7 @@ uint32_t ul;
( portMPU_REGION_ENABLE ); ( portMPU_REGION_ENABLE );
/* Re-instate the privileged only RAM region as xRegion[ 0 ] will have /* Re-instate the privileged only RAM region as xRegion[ 0 ] will have
just removed the privileged only parameters. */ * just removed the privileged only parameters. */
xMPUSettings->xRegion[ 1 ].ulRegionBaseAddress = xMPUSettings->xRegion[ 1 ].ulRegionBaseAddress =
( ( uint32_t ) __privileged_data_start__ ) | /* Base address. */ ( ( uint32_t ) __privileged_data_start__ ) | /* Base address. */
( portMPU_REGION_VALID ) | ( portMPU_REGION_VALID ) |
@ -615,9 +637,9 @@ uint32_t ul;
else else
{ {
/* This function is called automatically when the task is created - in /* This function is called automatically when the task is created - in
which case the stack region parameters will be valid. At all other * which case the stack region parameters will be valid. At all other
times the stack parameters will not be valid and it is assumed that the * times the stack parameters will not be valid and it is assumed that the
stack region has already been configured. */ * stack region has already been configured. */
if( ulStackDepth > 0 ) if( ulStackDepth > 0 )
{ {
/* Define the region that allows access to the stack. */ /* Define the region that allows access to the stack. */
@ -640,8 +662,8 @@ uint32_t ul;
if( ( xRegions[ lIndex ] ).ulLengthInBytes > 0UL ) if( ( xRegions[ lIndex ] ).ulLengthInBytes > 0UL )
{ {
/* Translate the generic region definition contained in /* Translate the generic region definition contained in
xRegions into the CM3 specific MPU settings that are then * xRegions into the CM3 specific MPU settings that are then
stored in xMPUSettings. */ * stored in xMPUSettings. */
xMPUSettings->xRegion[ ul ].ulRegionBaseAddress = xMPUSettings->xRegion[ ul ].ulRegionBaseAddress =
( ( uint32_t ) xRegions[ lIndex ].pvBaseAddress ) | ( ( uint32_t ) xRegions[ lIndex ].pvBaseAddress ) |
( portMPU_REGION_VALID ) | ( portMPU_REGION_VALID ) |
@ -682,66 +704,46 @@ uint32_t ul;
ucCurrentPriority = pcInterruptPriorityRegisters[ ulCurrentInterrupt ]; ucCurrentPriority = pcInterruptPriorityRegisters[ ulCurrentInterrupt ];
/* The following assertion will fail if a service routine (ISR) for /* The following assertion will fail if a service routine (ISR) for
an interrupt that has been assigned a priority above * an interrupt that has been assigned a priority above
configMAX_SYSCALL_INTERRUPT_PRIORITY calls an ISR safe FreeRTOS API * configMAX_SYSCALL_INTERRUPT_PRIORITY calls an ISR safe FreeRTOS API
function. ISR safe FreeRTOS API functions must *only* be called * function. ISR safe FreeRTOS API functions must *only* be called
from interrupts that have been assigned a priority at or below * from interrupts that have been assigned a priority at or below
configMAX_SYSCALL_INTERRUPT_PRIORITY. * configMAX_SYSCALL_INTERRUPT_PRIORITY.
Numerically low interrupt priority numbers represent logically high * Numerically low interrupt priority numbers represent logically high
interrupt priorities, therefore the priority of the interrupt must * interrupt priorities, therefore the priority of the interrupt must
be set to a value equal to or numerically *higher* than * be set to a value equal to or numerically *higher* than
configMAX_SYSCALL_INTERRUPT_PRIORITY. * configMAX_SYSCALL_INTERRUPT_PRIORITY.
Interrupts that use the FreeRTOS API must not be left at their * Interrupts that use the FreeRTOS API must not be left at their
default priority of zero as that is the highest possible priority, * default priority of zero as that is the highest possible priority,
which is guaranteed to be above configMAX_SYSCALL_INTERRUPT_PRIORITY, * which is guaranteed to be above configMAX_SYSCALL_INTERRUPT_PRIORITY,
and therefore also guaranteed to be invalid. * and therefore also guaranteed to be invalid.
FreeRTOS maintains separate thread and ISR API functions to ensure * FreeRTOS maintains separate thread and ISR API functions to ensure
interrupt entry is as fast and simple as possible. * interrupt entry is as fast and simple as possible.
The following links provide detailed information: * The following links provide detailed information:
http://www.freertos.org/RTOS-Cortex-M3-M4.html * http://www.freertos.org/RTOS-Cortex-M3-M4.html
http://www.freertos.org/FAQHelp.html */ * http://www.freertos.org/FAQHelp.html */
configASSERT( ucCurrentPriority >= ucMaxSysCallPriority ); configASSERT( ucCurrentPriority >= ucMaxSysCallPriority );
} }
/* Priority grouping: The interrupt controller (NVIC) allows the bits /* Priority grouping: The interrupt controller (NVIC) allows the bits
that define each interrupt's priority to be split between bits that * that define each interrupt's priority to be split between bits that
define the interrupt's pre-emption priority bits and bits that define * define the interrupt's pre-emption priority bits and bits that define
the interrupt's sub-priority. For simplicity all bits must be defined * the interrupt's sub-priority. For simplicity all bits must be defined
to be pre-emption priority bits. The following assertion will fail if * to be pre-emption priority bits. The following assertion will fail if
this is not the case (if some bits represent a sub-priority). * this is not the case (if some bits represent a sub-priority).
If the application only uses CMSIS libraries for interrupt * If the application only uses CMSIS libraries for interrupt
configuration then the correct setting can be achieved on all Cortex-M * configuration then the correct setting can be achieved on all Cortex-M
devices by calling NVIC_SetPriorityGrouping( 0 ); before starting the * devices by calling NVIC_SetPriorityGrouping( 0 ); before starting the
scheduler. Note however that some vendor specific peripheral libraries * scheduler. Note however that some vendor specific peripheral libraries
assume a non-zero priority group setting, in which cases using a value * assume a non-zero priority group setting, in which cases using a value
of zero will result in unpredictable behaviour. */ * of zero will result in unpredictable behaviour. */
configASSERT( ( portAIRCR_REG & portPRIORITY_GROUP_MASK ) <= ulMaxPRIGROUPValue ); configASSERT( ( portAIRCR_REG & portPRIORITY_GROUP_MASK ) <= ulMaxPRIGROUPValue );
} }
#endif /* configASSERT_DEFINED */ #endif /* configASSERT_DEFINED */
/*-----------------------------------------------------------*/

View file

@ -78,12 +78,26 @@ xPortPendSVHandler:
ldr r0, [r1] ldr r0, [r1]
/* Move onto the second item in the TCB... */ /* Move onto the second item in the TCB... */
add r1, r1, #4 add r1, r1, #4
dmb /* Complete outstanding transfers before disabling MPU. */
ldr r2, =0xe000ed94 /* MPU_CTRL register. */
ldr r3, [r2] /* Read the value of MPU_CTRL. */
bic r3, r3, #1 /* r3 = r3 & ~1 i.e. Clear the bit 0 in r3. */
str r3, [r2] /* Disable MPU. */
/* Region Base Address register. */ /* Region Base Address register. */
ldr r2, =0xe000ed9c ldr r2, =0xe000ed9c
/* Read 4 sets of MPU registers. */ /* Read 4 sets of MPU registers. */
ldmia r1!, {r4-r11} ldmia r1!, {r4-r11}
/* Write 4 sets of MPU registers. */ /* Write 4 sets of MPU registers. */
stmia r2!, {r4-r11} stmia r2!, {r4-r11}
ldr r2, =0xe000ed94 /* MPU_CTRL register. */
ldr r3, [r2] /* Read the value of MPU_CTRL. */
orr r3, r3, #1 /* r3 = r3 | 1 i.e. Set the bit 0 in r3. */
str r3, [r2] /* Enable MPU. */
dsb /* Force memory writes before continuing. */
/* Pop the registers that are not automatically saved on exception entry. */ /* Pop the registers that are not automatically saved on exception entry. */
ldmia r0!, {r3-r11, r14} ldmia r0!, {r3-r11, r14}
msr control, r3 msr control, r3
@ -151,12 +165,26 @@ vPortRestoreContextOfFirstTask:
ldr r0, [r1] ldr r0, [r1]
/* Move onto the second item in the TCB... */ /* Move onto the second item in the TCB... */
add r1, r1, #4 add r1, r1, #4
dmb /* Complete outstanding transfers before disabling MPU. */
ldr r2, =0xe000ed94 /* MPU_CTRL register. */
ldr r3, [r2] /* Read the value of MPU_CTRL. */
bic r3, r3, #1 /* r3 = r3 & ~1 i.e. Clear the bit 0 in r3. */
str r3, [r2] /* Disable MPU. */
/* Region Base Address register. */ /* Region Base Address register. */
ldr r2, =0xe000ed9c ldr r2, =0xe000ed9c
/* Read 4 sets of MPU registers. */ /* Read 4 sets of MPU registers. */
ldmia r1!, {r4-r11} ldmia r1!, {r4-r11}
/* Write 4 sets of MPU registers. */ /* Write 4 sets of MPU registers. */
stmia r2!, {r4-r11} stmia r2!, {r4-r11}
ldr r2, =0xe000ed94 /* MPU_CTRL register. */
ldr r3, [r2] /* Read the value of MPU_CTRL. */
orr r3, r3, #1 /* r3 = r3 | 1 i.e. Set the bit 0 in r3. */
str r3, [r2] /* Enable MPU. */
dsb /* Force memory writes before continuing. */
/* Pop the registers that are not automatically saved on exception entry. */ /* Pop the registers that are not automatically saved on exception entry. */
ldmia r0!, {r3-r11, r14} ldmia r0!, {r3-r11, r14}
msr control, r3 msr control, r3

View file

@ -25,6 +25,7 @@
* 1 tab == 4 spaces! * 1 tab == 4 spaces!
*/ */
#ifndef PORTMACRO_H #ifndef PORTMACRO_H
#define PORTMACRO_H #define PORTMACRO_H
@ -75,12 +76,13 @@ typedef unsigned long UBaseType_t;
#define portUSING_MPU_WRAPPERS 1 #define portUSING_MPU_WRAPPERS 1
#define portPRIVILEGE_BIT ( 0x80000000UL ) #define portPRIVILEGE_BIT ( 0x80000000UL )
#define portMPU_REGION_READ_WRITE ( 0x03UL << 24UL ) #define portMPU_REGION_READ_WRITE ( 0x03UL << 24UL )
#define portMPU_REGION_PRIVILEGED_READ_ONLY ( 0x05UL << 24UL ) #define portMPU_REGION_PRIVILEGED_READ_ONLY ( 0x05UL << 24UL )
#define portMPU_REGION_READ_ONLY ( 0x06UL << 24UL ) #define portMPU_REGION_READ_ONLY ( 0x06UL << 24UL )
#define portMPU_REGION_PRIVILEGED_READ_WRITE ( 0x01UL << 24UL ) #define portMPU_REGION_PRIVILEGED_READ_WRITE ( 0x01UL << 24UL )
#define portMPU_REGION_CACHEABLE_BUFFERABLE ( 0x07UL << 16UL ) #define portMPU_REGION_PRIVILEGED_READ_WRITE_UNPRIV_READ_ONLY ( 0x02UL << 24UL )
#define portMPU_REGION_EXECUTE_NEVER ( 0x01UL << 28UL ) #define portMPU_REGION_CACHEABLE_BUFFERABLE ( 0x07UL << 16UL )
#define portMPU_REGION_EXECUTE_NEVER ( 0x01UL << 28UL )
#define portUNPRIVILEGED_FLASH_REGION ( 0UL ) #define portUNPRIVILEGED_FLASH_REGION ( 0UL )
#define portPRIVILEGED_FLASH_REGION ( 1UL ) #define portPRIVILEGED_FLASH_REGION ( 1UL )
@ -106,7 +108,6 @@ typedef struct MPU_SETTINGS
xMPU_REGION_REGISTERS xRegion[ portTOTAL_NUM_REGIONS ]; xMPU_REGION_REGISTERS xRegion[ portTOTAL_NUM_REGIONS ];
} xMPU_SETTINGS; } xMPU_SETTINGS;
/* Architecture specifics. */ /* Architecture specifics. */
#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 )
@ -119,6 +120,7 @@ typedef struct MPU_SETTINGS
#define portSVC_RAISE_PRIVILEGE 2 #define portSVC_RAISE_PRIVILEGE 2
/* Scheduler utilities. */ /* Scheduler utilities. */
#define portYIELD() __asm volatile ( " SVC %0 \n" :: "i" (portSVC_YIELD) : "memory" ) #define portYIELD() __asm volatile ( " SVC %0 \n" :: "i" (portSVC_YIELD) : "memory" )
#define portYIELD_WITHIN_API() \ #define portYIELD_WITHIN_API() \
{ \ { \
@ -132,7 +134,6 @@ typedef struct MPU_SETTINGS
#define portNVIC_PENDSVSET_BIT ( 1UL << 28UL ) #define portNVIC_PENDSVSET_BIT ( 1UL << 28UL )
#define portEND_SWITCHING_ISR( xSwitchRequired ) if( xSwitchRequired != pdFALSE ) portYIELD_WITHIN_API() #define portEND_SWITCHING_ISR( xSwitchRequired ) if( xSwitchRequired != pdFALSE ) portYIELD_WITHIN_API()
#define portYIELD_FROM_ISR( x ) portEND_SWITCHING_ISR( x ) #define portYIELD_FROM_ISR( x ) portEND_SWITCHING_ISR( x )
/*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/
/* Architecture specific optimisations. */ /* Architecture specific optimisations. */
@ -190,6 +191,36 @@ not necessary for to use this port. They are defined so the common demo files
/* portNOP() is not required by this port. */ /* portNOP() is not required by this port. */
#define portNOP() #define portNOP()
#define portINLINE __inline
#ifndef portFORCE_INLINE
#define portFORCE_INLINE inline __attribute__(( always_inline))
#endif
/*-----------------------------------------------------------*/
portFORCE_INLINE static BaseType_t xPortIsInsideInterrupt( void )
{
uint32_t ulCurrentInterrupt;
BaseType_t xReturn;
/* Obtain the number of the currently executing interrupt. */
__asm volatile( "mrs %0, ipsr" : "=r"( ulCurrentInterrupt ) :: "memory" );
if( ulCurrentInterrupt == 0 )
{
xReturn = pdFALSE;
}
else
{
xReturn = pdTRUE;
}
return xReturn;
}
/*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/
extern BaseType_t xIsPrivileged( void ); extern BaseType_t xIsPrivileged( void );
@ -214,11 +245,19 @@ extern void vResetPrivilege( void );
#define portRESET_PRIVILEGE() vResetPrivilege() #define portRESET_PRIVILEGE() vResetPrivilege()
/*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/
#ifndef configENFORCE_SYSTEM_CALLS_FROM_KERNEL_ONLY
#warning "configENFORCE_SYSTEM_CALLS_FROM_KERNEL_ONLY is not defined. We recommend defining it to 1 in FreeRTOSConfig.h for better security."
#define configENFORCE_SYSTEM_CALLS_FROM_KERNEL_ONLY 0
#endif
/*-----------------------------------------------------------*/
/* Suppress warnings that are generated by the IAR tools, but cannot be fixed in /* Suppress warnings that are generated by the IAR tools, but cannot be fixed in
the source code because to do so would cause other compilers to generate the source code because to do so would cause other compilers to generate
warnings. */ warnings. */
#pragma diag_suppress=Pe191 #pragma diag_suppress=Pe191
#pragma diag_suppress=Pa082 #pragma diag_suppress=Pa082
#pragma diag_suppress=Be006
/*-----------------------------------------------------------*/
#ifdef __cplusplus #ifdef __cplusplus
} }

View file

@ -77,6 +77,12 @@ typedef unsigned long UBaseType_t;
#define portBYTE_ALIGNMENT 8 #define portBYTE_ALIGNMENT 8
/*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/
/* Compiler directives. */
#define portWEAK_SYMBOL __attribute__( ( weak ) )
/*-----------------------------------------------------------*/
/* Scheduler utilities. */ /* Scheduler utilities. */
#define portYIELD() \ #define portYIELD() \
{ \ { \
@ -160,6 +166,34 @@ not necessary for to use this port. They are defined so the common demo files
/* portNOP() is not required by this port. */ /* portNOP() is not required by this port. */
#define portNOP() #define portNOP()
#define portINLINE __inline
#ifndef portFORCE_INLINE
#define portFORCE_INLINE inline __attribute__(( always_inline))
#endif
/*-----------------------------------------------------------*/
portFORCE_INLINE static BaseType_t xPortIsInsideInterrupt( void )
{
uint32_t ulCurrentInterrupt;
BaseType_t xReturn;
/* Obtain the number of the currently executing interrupt. */
__asm volatile( "mrs %0, ipsr" : "=r"( ulCurrentInterrupt ) :: "memory" );
if( ulCurrentInterrupt == 0 )
{
xReturn = pdFALSE;
}
else
{
xReturn = pdTRUE;
}
return xReturn;
}
/*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/
/* Suppress warnings that are generated by the IAR tools, but cannot be fixed in /* Suppress warnings that are generated by the IAR tools, but cannot be fixed in

View file

@ -53,7 +53,7 @@
#ifndef __FREERTOS_RISC_V_EXTENSIONS_H__ #ifndef __FREERTOS_RISC_V_EXTENSIONS_H__
#define __FREERTOS_RISC_V_EXTENSIONS_H__ #define __FREERTOS_RISC_V_EXTENSIONS_H__
#define portasmHAS_CLINT 1 #define portasmHAS_MTIME 1
#define portasmADDITIONAL_CONTEXT_SIZE 0 /* Must be even number on 32-bit cores. */ #define portasmADDITIONAL_CONTEXT_SIZE 0 /* Must be even number on 32-bit cores. */
portasmSAVE_ADDITIONAL_REGISTERS MACRO portasmSAVE_ADDITIONAL_REGISTERS MACRO

View file

@ -34,8 +34,19 @@
#include "task.h" #include "task.h"
#include "portmacro.h" #include "portmacro.h"
#ifndef configCLINT_BASE_ADDRESS /* Standard includes. */
#warning configCLINT_BASE_ADDRESS must be defined in FreeRTOSConfig.h. If the target chip includes a Core Local Interrupter (CLINT) then set configCLINT_BASE_ADDRESS to the CLINT base address. Otherwise set configCLINT_BASE_ADDRESS to 0. #include "string.h"
#ifdef configCLINT_BASE_ADDRESS
#warning The configCLINT_BASE_ADDRESS constant has been deprecated. configMTIME_BASE_ADDRESS and configMTIMECMP_BASE_ADDRESS are currently being derived from the (possibly 0) configCLINT_BASE_ADDRESS setting. Please update to define configMTIME_BASE_ADDRESS and configMTIMECMP_BASE_ADDRESS dirctly in place of configCLINT_BASE_ADDRESS.
#endif
#ifndef configMTIME_BASE_ADDRESS
#warning configMTIME_BASE_ADDRESS must be defined in FreeRTOSConfig.h. If the target chip includes a memory-mapped mtime register then set configMTIME_BASE_ADDRESS to the mapped address. Otherwise set configMTIME_BASE_ADDRESS to 0.
#endif
#ifndef configMTIMECMP_BASE_ADDRESS
#warning configMTIMECMP_BASE_ADDRESS must be defined in FreeRTOSConfig.h. If the target chip includes a memory-mapped mtimecmp register then set configMTIMECMP_BASE_ADDRESS to the mapped address. Otherwise set configMTIMECMP_BASE_ADDRESS to 0.
#endif #endif
/* Let the user override the pre-loading of the initial LR with the address of /* Let the user override the pre-loading of the initial LR with the address of
@ -57,6 +68,11 @@ interrupt stack after the scheduler has started. */
#ifdef configISR_STACK_SIZE_WORDS #ifdef configISR_STACK_SIZE_WORDS
static __attribute__ ((aligned(16))) StackType_t xISRStack[ configISR_STACK_SIZE_WORDS ] = { 0 }; static __attribute__ ((aligned(16))) StackType_t xISRStack[ configISR_STACK_SIZE_WORDS ] = { 0 };
const StackType_t xISRStackTop = ( StackType_t ) &( xISRStack[ configISR_STACK_SIZE_WORDS & ~portBYTE_ALIGNMENT_MASK ] ); const StackType_t xISRStackTop = ( StackType_t ) &( xISRStack[ configISR_STACK_SIZE_WORDS & ~portBYTE_ALIGNMENT_MASK ] );
/* Don't use 0xa5 as the stack fill bytes as that is used by the kernerl for
the task stacks, and so will legitimately appear in many positions within
the ISR stack. */
#define portISR_STACK_FILL_BYTE 0xee
#else #else
extern const uint32_t __freertos_irq_stack_top[]; extern const uint32_t __freertos_irq_stack_top[];
const StackType_t xISRStackTop = ( StackType_t ) __freertos_irq_stack_top; const StackType_t xISRStackTop = ( StackType_t ) __freertos_irq_stack_top;
@ -74,20 +90,16 @@ void vPortSetupTimerInterrupt( void ) __attribute__(( weak ));
/* Used to program the machine timer compare register. */ /* Used to program the machine timer compare register. */
uint64_t ullNextTime = 0ULL; uint64_t ullNextTime = 0ULL;
const uint64_t *pullNextTime = &ullNextTime; const uint64_t *pullNextTime = &ullNextTime;
const size_t uxTimerIncrementsForOneTick = ( size_t ) ( configCPU_CLOCK_HZ / configTICK_RATE_HZ ); /* Assumes increment won't go over 32-bits. */ const size_t uxTimerIncrementsForOneTick = ( size_t ) ( ( configCPU_CLOCK_HZ ) / ( configTICK_RATE_HZ ) ); /* Assumes increment won't go over 32-bits. */
volatile uint64_t * const pullMachineTimerCompareRegisterBase = ( uint64_t * ) ( configCLINT_BASE_ADDRESS + 0x4000 ); uint32_t const ullMachineTimerCompareRegisterBase = configMTIMECMP_BASE_ADDRESS;
volatile uint64_t * pullMachineTimerCompareRegister = 0; volatile uint64_t * pullMachineTimerCompareRegister = NULL;
/* Set configCHECK_FOR_STACK_OVERFLOW to 3 to add ISR stack checking to task /* Set configCHECK_FOR_STACK_OVERFLOW to 3 to add ISR stack checking to task
stack checking. A problem in the ISR stack will trigger an assert, not call the stack checking. A problem in the ISR stack will trigger an assert, not call the
stack overflow hook function (because the stack overflow hook is specific to a stack overflow hook function (because the stack overflow hook is specific to a
task stack, not the ISR stack). */ task stack, not the ISR stack). */
#if( configCHECK_FOR_STACK_OVERFLOW > 2 ) #if defined( configISR_STACK_SIZE_WORDS ) && ( configCHECK_FOR_STACK_OVERFLOW > 2 )
#warning This path not tested, or even compiled yet. #warning This path not tested, or even compiled yet.
/* Don't use 0xa5 as the stack fill bytes as that is used by the kernerl for
the task stacks, and so will legitimately appear in many positions within
the ISR stack. */
#define portISR_STACK_FILL_BYTE 0xee
static const uint8_t ucExpectedStackBytes[] = { static const uint8_t ucExpectedStackBytes[] = {
portISR_STACK_FILL_BYTE, portISR_STACK_FILL_BYTE, portISR_STACK_FILL_BYTE, portISR_STACK_FILL_BYTE, \ portISR_STACK_FILL_BYTE, portISR_STACK_FILL_BYTE, portISR_STACK_FILL_BYTE, portISR_STACK_FILL_BYTE, \
@ -104,17 +116,17 @@ task stack, not the ISR stack). */
/*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/
#if( configCLINT_BASE_ADDRESS != 0 ) #if( configMTIME_BASE_ADDRESS != 0 ) && ( configMTIMECMP_BASE_ADDRESS != 0 )
void vPortSetupTimerInterrupt( void ) void vPortSetupTimerInterrupt( void )
{ {
uint32_t ulCurrentTimeHigh, ulCurrentTimeLow; uint32_t ulCurrentTimeHigh, ulCurrentTimeLow;
volatile uint32_t * const pulTimeHigh = ( uint32_t * ) ( configCLINT_BASE_ADDRESS + 0xBFFC ); volatile uint32_t * const pulTimeHigh = ( uint32_t * ) ( ( configMTIME_BASE_ADDRESS ) + 4UL ); /* 8-byte typer so high 32-bit word is 4 bytes up. */
volatile uint32_t * const pulTimeLow = ( uint32_t * ) ( configCLINT_BASE_ADDRESS + 0xBFF8 ); volatile uint32_t * const pulTimeLow = ( uint32_t * ) ( configMTIME_BASE_ADDRESS );
volatile uint32_t ulHartId = 0; volatile uint32_t ulHartId;
__asm volatile( "csrr %0, 0xf14" : "=r"( ulHartId ) ); /* 0xf14 is hartid. */ __asm volatile( "csrr %0, 0xf14" : "=r"( ulHartId ) ); /* 0xf14 is hartid. */
pullMachineTimerCompareRegister = &( pullMachineTimerCompareRegisterBase[ ulHartId ] ); pullMachineTimerCompareRegister = ( volatile uint64_t * ) ( ullMachineTimerCompareRegisterBase + ( ulHartId * sizeof( uint64_t ) ) );
do do
{ {
@ -123,7 +135,7 @@ task stack, not the ISR stack). */
} while( ulCurrentTimeHigh != *pulTimeHigh ); } while( ulCurrentTimeHigh != *pulTimeHigh );
ullNextTime = ( uint64_t ) ulCurrentTimeHigh; ullNextTime = ( uint64_t ) ulCurrentTimeHigh;
ullNextTime <<= 32ULL; ullNextTime <<= 32ULL; /* High 4-byte word is 32-bits up. */
ullNextTime |= ( uint64_t ) ulCurrentTimeLow; ullNextTime |= ( uint64_t ) ulCurrentTimeLow;
ullNextTime += ( uint64_t ) uxTimerIncrementsForOneTick; ullNextTime += ( uint64_t ) uxTimerIncrementsForOneTick;
*pullMachineTimerCompareRegister = ullNextTime; *pullMachineTimerCompareRegister = ullNextTime;
@ -132,7 +144,7 @@ task stack, not the ISR stack). */
ullNextTime += ( uint64_t ) uxTimerIncrementsForOneTick; ullNextTime += ( uint64_t ) uxTimerIncrementsForOneTick;
} }
#endif /* ( configCLINT_BASE_ADDRESS != 0 ) */ #endif /* ( configMTIME_BASE_ADDRESS != 0 ) && ( configMTIME_BASE_ADDRESS != 0 ) */
/*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/
BaseType_t xPortStartScheduler( void ) BaseType_t xPortStartScheduler( void )
@ -152,6 +164,12 @@ extern void xPortStartFirstTask( void );
stack that was being used by main() prior to the scheduler being stack that was being used by main() prior to the scheduler being
started. */ started. */
configASSERT( ( xISRStackTop & portBYTE_ALIGNMENT_MASK ) == 0 ); configASSERT( ( xISRStackTop & portBYTE_ALIGNMENT_MASK ) == 0 );
#ifdef configISR_STACK_SIZE_WORDS
{
memset( ( void * ) xISRStack, portISR_STACK_FILL_BYTE, sizeof( xISRStack ) );
}
#endif /* configISR_STACK_SIZE_WORDS */
} }
#endif /* configASSERT_DEFINED */ #endif /* configASSERT_DEFINED */
@ -160,7 +178,7 @@ extern void xPortStartFirstTask( void );
configure whichever clock is to be used to generate the tick interrupt. */ configure whichever clock is to be used to generate the tick interrupt. */
vPortSetupTimerInterrupt(); vPortSetupTimerInterrupt();
#if( configCLINT_BASE_ADDRESS != 0 ) #if( ( configMTIME_BASE_ADDRESS != 0 ) && ( configMTIMECMP_BASE_ADDRESS != 0 ) )
{ {
/* Enable mtime and external interrupts. 1<<7 for timer interrupt, 1<<11 /* Enable mtime and external interrupts. 1<<7 for timer interrupt, 1<<11
for external interrupt. _RB_ What happens here when mtime is not present as for external interrupt. _RB_ What happens here when mtime is not present as
@ -172,7 +190,7 @@ extern void xPortStartFirstTask( void );
/* Enable external interrupts. */ /* Enable external interrupts. */
__asm volatile( "csrs 0x304, %0" :: "r"(0x800) ); /* 304 is mie. */ __asm volatile( "csrs 0x304, %0" :: "r"(0x800) ); /* 304 is mie. */
} }
#endif /* configCLINT_BASE_ADDRESS */ #endif /* ( configMTIME_BASE_ADDRESS != 0 ) && ( configMTIMECMP_BASE_ADDRESS != 0 ) */
xPortStartFirstTask(); xPortStartFirstTask();

View file

@ -71,8 +71,17 @@
/* Check the freertos_risc_v_chip_specific_extensions.h and/or command line /* Check the freertos_risc_v_chip_specific_extensions.h and/or command line
definitions. */ definitions. */
#ifndef portasmHAS_CLINT #if defined( portasmHAS_CLINT ) && defined( portasmHAS_MTIME )
#error freertos_risc_v_chip_specific_extensions.h must define portasmHAS_CLINT to either 1 (CLINT present) or 0 (clint not present). #error The portasmHAS_CLINT constant has been depracted. Please replace it with portasmHAS_CLINT. portasmHAS_CLINT and portasmHAS_MTIME cannot both be defined at once.
#endif
#ifdef portasmHAS_CLINT
#warning The portasmHAS_CLINT constant has been depracted. Please replace it with portasmHAS_CLINT. For now portasmHAS_MTIME is derived from portasmHAS_CLINT.
#define portasmHAS_MTIME portasmHAS_CLINT
#endif
#ifndef portasmHAS_MTIME
#error freertos_risc_v_chip_specific_extensions.h must define portasmHAS_MTIME to either 1 (MTIME clock present) or 0 (MTIME clock not present).
#endif #endif
#ifndef portasmHANDLE_INTERRUPT #ifndef portasmHANDLE_INTERRUPT
@ -99,12 +108,12 @@ at the top of this file. */
EXTERN pxCurrentTCB EXTERN pxCurrentTCB
EXTERN ulPortTrapHandler EXTERN ulPortTrapHandler
EXTERN vTaskSwitchContext EXTERN vTaskSwitchContext
EXTERN xTaskIncrementTick
EXTERN Timer_IRQHandler EXTERN Timer_IRQHandler
EXTERN pullMachineTimerCompareRegister EXTERN pullMachineTimerCompareRegister
EXTERN pullNextTime EXTERN pullNextTime
EXTERN uxTimerIncrementsForOneTick /* size_t type so 32-bit on 32-bit core and 64-bits on 64-bit core. */ EXTERN uxTimerIncrementsForOneTick /* size_t type so 32-bit on 32-bit core and 64-bits on 64-bit core. */
EXTERN xISRStackTop EXTERN xISRStackTop
EXTERN xTaskIncrementTick
EXTERN portasmHANDLE_INTERRUPT EXTERN portasmHANDLE_INTERRUPT
/*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/
@ -161,7 +170,7 @@ test_if_asynchronous:
handle_asynchronous: handle_asynchronous:
#if( portasmHAS_CLINT != 0 ) #if( portasmHAS_MTIME != 0 )
test_if_mtimer: /* If there is a CLINT then the mtimer is used to generate the tick interrupt. */ test_if_mtimer: /* If there is a CLINT then the mtimer is used to generate the tick interrupt. */
@ -180,7 +189,7 @@ handle_asynchronous:
li t4, -1 li t4, -1
lw t2, 0(t1) /* Load the low word of ullNextTime into t2. */ lw t2, 0(t1) /* Load the low word of ullNextTime into t2. */
lw t3, 4(t1) /* Load the high word of ullNextTime into t3. */ lw t3, 4(t1) /* Load the high word of ullNextTime into t3. */
sw t4, 0(t0) /* Low word no smaller than old value. */ sw t4, 0(t0) /* Low word no smaller than old value to start with - will be overwritten below. */
sw t3, 4(t0) /* Store high word of ullNextTime into compare register. No smaller than new value. */ sw t3, 4(t0) /* Store high word of ullNextTime into compare register. No smaller than new value. */
sw t2, 0(t0) /* Store low word of ullNextTime into compare register. */ sw t2, 0(t0) /* Store low word of ullNextTime into compare register. */
lw t0, uxTimerIncrementsForOneTick /* Load the value of ullTimerIncrementForOneTick into t0 (could this be optimized by storing in an array next to pullNextTime?). */ lw t0, uxTimerIncrementsForOneTick /* Load the value of ullTimerIncrementForOneTick into t0 (could this be optimized by storing in an array next to pullNextTime?). */
@ -213,7 +222,7 @@ handle_asynchronous:
addi t1, t1, 4 /* 0x80000007 + 4 = 0x8000000b == Machine external interrupt. */ addi t1, t1, 4 /* 0x80000007 + 4 = 0x8000000b == Machine external interrupt. */
bne a0, t1, as_yet_unhandled /* Something as yet unhandled. */ bne a0, t1, as_yet_unhandled /* Something as yet unhandled. */
#endif /* portasmHAS_CLINT */ #endif /* portasmHAS_MTIME */
load_x sp, xISRStackTop /* Switch to ISR stack before function call. */ load_x sp, xISRStackTop /* Switch to ISR stack before function call. */
jal portasmHANDLE_INTERRUPT /* Jump to the interrupt handler if there is no CLINT or if there is a CLINT and it has been determined that an external interrupt is pending. */ jal portasmHANDLE_INTERRUPT /* Jump to the interrupt handler if there is no CLINT or if there is a CLINT and it has been determined that an external interrupt is pending. */
@ -231,11 +240,13 @@ test_if_environment_call:
j processed_source j processed_source
is_exception: is_exception:
ebreak csrr t0, CSR_MCAUSE /* For viewing in the debugger only. */
j is_exception csrr t1, CSR_MEPC /* For viewing in the debugger only */
csrr t2, CSR_MSTATUS
j is_exception /* No other exceptions handled yet. */
as_yet_unhandled: as_yet_unhandled:
ebreak csrr t0, mcause /* For viewing in the debugger only. */
j as_yet_unhandled j as_yet_unhandled
processed_source: processed_source:
@ -288,7 +299,7 @@ processed_source:
xPortStartFirstTask: xPortStartFirstTask:
#if( portasmHAS_CLINT != 0 ) #if( portasmHAS_MTIME != 0 )
/* If there is a clint then interrupts can branch directly to the FreeRTOS /* If there is a clint then interrupts can branch directly to the FreeRTOS
trap handler. Otherwise the interrupt controller will need to be configured trap handler. Otherwise the interrupt controller will need to be configured
outside of this file. */ outside of this file. */
@ -304,6 +315,7 @@ xPortStartFirstTask:
portasmRESTORE_ADDITIONAL_REGISTERS /* Defined in freertos_risc_v_chip_specific_extensions.h to restore any registers unique to the RISC-V implementation. */ portasmRESTORE_ADDITIONAL_REGISTERS /* Defined in freertos_risc_v_chip_specific_extensions.h to restore any registers unique to the RISC-V implementation. */
load_x t0, 29 * portWORD_SIZE( sp ) /* mstatus */ load_x t0, 29 * portWORD_SIZE( sp ) /* mstatus */
addi t0, t0, 0x08 /* Set MIE bit so the first task starts with interrupts enabled - required as returns with ret not eret. */
csrrw x0, CSR_MSTATUS, t0 /* Interrupts enabled from here! */ csrrw x0, CSR_MSTATUS, t0 /* Interrupts enabled from here! */
load_x x5, 2 * portWORD_SIZE( sp ) /* t0 */ load_x x5, 2 * portWORD_SIZE( sp ) /* t0 */

View file

@ -67,6 +67,13 @@ typedef portBASE_TYPE BaseType_t;
typedef portUBASE_TYPE UBaseType_t; typedef portUBASE_TYPE UBaseType_t;
typedef portUBASE_TYPE TickType_t; typedef portUBASE_TYPE TickType_t;
/* Legacy type definitions. */
#define portCHAR char
#define portFLOAT float
#define portDOUBLE double
#define portLONG long
#define portSHORT short
/* 32-bit tick type on a 32-bit architecture, so reads of the tick count do /* 32-bit tick type on a 32-bit architecture, so reads of the tick count do
not need to be guarded with a critical section. */ not need to be guarded with a critical section. */
#define portTICK_TYPE_IS_ATOMIC 1 #define portTICK_TYPE_IS_ATOMIC 1
@ -140,6 +147,27 @@ the source code because to do so would cause other compilers to generate
warnings. */ warnings. */
#pragma diag_suppress=Pa082 #pragma diag_suppress=Pa082
/* configCLINT_BASE_ADDRESS is a legacy definition that was replaced by the
configMTIME_BASE_ADDRESS and configMTIMECMP_BASE_ADDRESS definitions. For
backward compatibility derive the newer definitions from the old if the old
definition is found. */
#if defined( configCLINT_BASE_ADDRESS ) && !defined( configMTIME_BASE_ADDRESS ) && ( configCLINT_BASE_ADDRESS == 0 )
/* Legacy case where configCLINT_BASE_ADDRESS was defined as 0 to indicate
there was no CLINT. Equivalent now is to set the MTIME and MTIMECMP
addresses to 0. */
#define configMTIME_BASE_ADDRESS ( 0 )
#define configMTIMECMP_BASE_ADDRESS ( 0 )
#elif defined( configCLINT_BASE_ADDRESS ) && !defined( configMTIME_BASE_ADDRESS )
/* Legacy case where configCLINT_BASE_ADDRESS was set to the base address of
the CLINT. Equivalent now is to derive the MTIME and MTIMECMP addresses
from the CLINT address. */
#define configMTIME_BASE_ADDRESS ( ( configCLINT_BASE_ADDRESS ) + 0xBFF8UL )
#define configMTIMECMP_BASE_ADDRESS ( ( configCLINT_BASE_ADDRESS ) + 0x4000UL )
#elif !defined( configMTIME_BASE_ADDRESS ) || !defined( configMTIMECMP_BASE_ADDRESS )
#error configMTIME_BASE_ADDRESS and configMTIMECMP_BASE_ADDRESS must be defined in FreeRTOSConfig.h. Set them to zero if there is no MTIME (machine time) clock. See https://www.freertos.org/Using-FreeRTOS-on-RISC-V.html
#endif
#ifdef __cplusplus #ifdef __cplusplus
} }

View file

@ -75,7 +75,7 @@ static uint32_t prvProcessTickInterrupt( void );
* attempt to obtain pvInterruptEventMutex if a critical section is used inside * attempt to obtain pvInterruptEventMutex if a critical section is used inside
* an interrupt handler itself. * an interrupt handler itself.
*/ */
static volatile BaseType_t xInsideInterrupt = pdFALSE; volatile BaseType_t xInsideInterrupt = pdFALSE;
/* /*
* Called when the process exits to let Windows know the high timer resolution * Called when the process exits to let Windows know the high timer resolution
@ -394,7 +394,7 @@ CONTEXT xContext;
xInsideInterrupt = pdFALSE; xInsideInterrupt = pdFALSE;
WaitForMultipleObjects( sizeof( pvObjectList ) / sizeof( void * ), pvObjectList, TRUE, INFINITE ); WaitForMultipleObjects( sizeof( pvObjectList ) / sizeof( void * ), pvObjectList, TRUE, INFINITE );
/* /* Cannot be in a critical section to get here. Tasks that exist a /* Cannot be in a critical section to get here. Tasks that exist a
critical section will block on a yield mutex to wait for an interrupt to critical section will block on a yield mutex to wait for an interrupt to
process if an interrupt was set pending while the task was inside the process if an interrupt was set pending while the task was inside the
critical section. xInsideInterrupt prevents interrupts that contain critical section. xInsideInterrupt prevents interrupts that contain

View file

@ -74,6 +74,11 @@ typedef unsigned long UBaseType_t;
#define portYIELD() vPortGenerateSimulatedInterrupt( portINTERRUPT_YIELD ) #define portYIELD() vPortGenerateSimulatedInterrupt( portINTERRUPT_YIELD )
extern volatile BaseType_t xInsideInterrupt;
#define portSOFTWARE_BARRIER() while( xInsideInterrupt != pdFALSE )
/* Simulated interrupts return pdFALSE if no context switch should be performed, /* Simulated interrupts return pdFALSE if no context switch should be performed,
or a non-zero number if a context switch should be performed. */ or a non-zero number if a context switch should be performed. */
#define portYIELD_FROM_ISR( x ) ( void ) x #define portYIELD_FROM_ISR( x ) ( void ) x

View file

@ -34,33 +34,73 @@
#include "task.h" #include "task.h"
/* Constants required to manipulate the NVIC. */ /* Constants required to manipulate the NVIC. */
#define portNVIC_SYSTICK_CTRL ( ( volatile uint32_t * ) 0xe000e010 ) #define portNVIC_SYSTICK_CTRL_REG ( * ( ( volatile uint32_t * ) 0xe000e010 ) )
#define portNVIC_SYSTICK_LOAD ( ( volatile uint32_t * ) 0xe000e014 ) #define portNVIC_SYSTICK_LOAD_REG ( * ( ( volatile uint32_t * ) 0xe000e014 ) )
#define portNVIC_SYSTICK_CURRENT_VALUE ( ( volatile uint32_t * ) 0xe000e018 ) #define portNVIC_SYSTICK_CURRENT_VALUE_REG ( * ( ( volatile uint32_t * ) 0xe000e018 ) )
#define portNVIC_INT_CTRL ( ( volatile uint32_t *) 0xe000ed04 ) #define portNVIC_INT_CTRL_REG ( * ( ( volatile uint32_t * ) 0xe000ed04 ) )
#define portNVIC_SYSPRI2 ( ( volatile uint32_t *) 0xe000ed20 ) #define portNVIC_SYSPRI2_REG ( * ( ( volatile uint32_t * ) 0xe000ed20 ) )
#define portNVIC_SYSTICK_CLK 0x00000004 #define portNVIC_SYSTICK_CLK_BIT ( 1UL << 2UL )
#define portNVIC_SYSTICK_INT 0x00000002 #define portNVIC_SYSTICK_INT_BIT ( 1UL << 1UL )
#define portNVIC_SYSTICK_ENABLE 0x00000001 #define portNVIC_SYSTICK_ENABLE_BIT ( 1UL << 0UL )
#define portNVIC_PENDSVSET 0x10000000 #define portNVIC_SYSTICK_COUNT_FLAG_BIT ( 1UL << 16UL )
#define portMIN_INTERRUPT_PRIORITY ( 255UL ) #define portNVIC_PENDSVSET_BIT ( 1UL << 28UL )
#define portNVIC_PENDSV_PRI ( portMIN_INTERRUPT_PRIORITY << 16UL ) #define portMIN_INTERRUPT_PRIORITY ( 255UL )
#define portNVIC_SYSTICK_PRI ( portMIN_INTERRUPT_PRIORITY << 24UL ) #define portNVIC_PENDSV_PRI ( portMIN_INTERRUPT_PRIORITY << 16UL )
#define portNVIC_SYSTICK_PRI ( portMIN_INTERRUPT_PRIORITY << 24UL )
/* Constants required to set up the initial stack. */ /* Constants required to set up the initial stack. */
#define portINITIAL_XPSR ( 0x01000000 ) #define portINITIAL_XPSR ( 0x01000000 )
/* The systick is a 24-bit counter. */
#define portMAX_24_BIT_NUMBER ( 0xffffffUL )
/* A fiddle factor to estimate the number of SysTick counts that would have
occurred while the SysTick counter is stopped during tickless idle
calculations. */
#ifndef portMISSED_COUNTS_FACTOR
#define portMISSED_COUNTS_FACTOR ( 45UL )
#endif
/* Constants used with memory barrier intrinsics. */ /* Constants used with memory barrier intrinsics. */
#define portSY_FULL_READ_WRITE ( 15 ) #define portSY_FULL_READ_WRITE ( 15 )
/* Legacy macro for backward compatibility only. This macro used to be used to
replace the function that configures the clock used to generate the tick
interrupt (prvSetupTimerInterrupt()), but now the function is declared weak so
the application writer can override it by simply defining a function of the
same name (vApplicationSetupTickInterrupt()). */
#ifndef configOVERRIDE_DEFAULT_TICK_CONFIGURATION
#define configOVERRIDE_DEFAULT_TICK_CONFIGURATION 0
#endif
/* Each task maintains its own interrupt status in the critical nesting /* Each task maintains its own interrupt status in the critical nesting
variable. */ variable. */
static UBaseType_t uxCriticalNesting = 0xaaaaaaaa; static UBaseType_t uxCriticalNesting = 0xaaaaaaaa;
/* The number of SysTick increments that make up one tick period. */
#if( configUSE_TICKLESS_IDLE == 1 )
static uint32_t ulTimerCountsForOneTick = 0;
#endif /* configUSE_TICKLESS_IDLE */
/* The maximum number of tick periods that can be suppressed is limited by the
24 bit resolution of the SysTick timer. */
#if( configUSE_TICKLESS_IDLE == 1 )
static uint32_t xMaximumPossibleSuppressedTicks = 0;
#endif /* configUSE_TICKLESS_IDLE */
/* Compensate for the CPU cycles that pass while the SysTick is stopped (low
power functionality only.
*/
#if( configUSE_TICKLESS_IDLE == 1 )
static uint32_t ulStoppedTimerCompensation = 0;
#endif /* configUSE_TICKLESS_IDLE */
/* /*
* Setup the timer to generate the tick interrupts. * Setup the timer to generate the tick interrupts. The implementation in this
* file is weak to allow application writers to change the timer used to
* generate the tick interrupt.
*/ */
static void prvSetupTimerInterrupt( void ); void vPortSetupTimerInterrupt( void );
/* /*
* Exception handlers. * Exception handlers.
@ -158,12 +198,12 @@ __asm void prvPortStartFirstTask( void )
BaseType_t xPortStartScheduler( void ) BaseType_t xPortStartScheduler( void )
{ {
/* Make PendSV, CallSV and SysTick the same priority as the kernel. */ /* Make PendSV, CallSV and SysTick the same priority as the kernel. */
*(portNVIC_SYSPRI2) |= portNVIC_PENDSV_PRI; portNVIC_SYSPRI2_REG |= portNVIC_PENDSV_PRI;
*(portNVIC_SYSPRI2) |= portNVIC_SYSTICK_PRI; portNVIC_SYSPRI2_REG |= portNVIC_SYSTICK_PRI;
/* Start the timer that generates the tick ISR. Interrupts are disabled /* Start the timer that generates the tick ISR. Interrupts are disabled
here already. */ here already. */
prvSetupTimerInterrupt(); vPortSetupTimerInterrupt();
/* Initialise the critical nesting count ready for the first task. */ /* Initialise the critical nesting count ready for the first task. */
uxCriticalNesting = 0; uxCriticalNesting = 0;
@ -187,7 +227,7 @@ void vPortEndScheduler( void )
void vPortYield( void ) void vPortYield( void )
{ {
/* Set a PendSV to request a context switch. */ /* Set a PendSV to request a context switch. */
*( portNVIC_INT_CTRL ) = portNVIC_PENDSVSET; portNVIC_INT_CTRL_REG = portNVIC_PENDSVSET_BIT;
/* Barriers are normally not required but do ensure the code is completely /* Barriers are normally not required but do ensure the code is completely
within the specified behaviour for the architecture. */ within the specified behaviour for the architecture. */
@ -287,7 +327,7 @@ uint32_t ulPreviousMask;
if( xTaskIncrementTick() != pdFALSE ) if( xTaskIncrementTick() != pdFALSE )
{ {
/* Pend a context switch. */ /* Pend a context switch. */
*(portNVIC_INT_CTRL) = portNVIC_PENDSVSET; portNVIC_INT_CTRL_REG = portNVIC_PENDSVSET_BIT;
} }
} }
portCLEAR_INTERRUPT_MASK_FROM_ISR( ulPreviousMask ); portCLEAR_INTERRUPT_MASK_FROM_ISR( ulPreviousMask );
@ -298,15 +338,193 @@ uint32_t ulPreviousMask;
* Setup the systick timer to generate the tick interrupts at the required * Setup the systick timer to generate the tick interrupts at the required
* frequency. * frequency.
*/ */
void prvSetupTimerInterrupt( void ) #if( configOVERRIDE_DEFAULT_TICK_CONFIGURATION == 0 )
{
/* Stop and reset the SysTick. */
*(portNVIC_SYSTICK_CTRL) = 0UL;
*(portNVIC_SYSTICK_CURRENT_VALUE) = 0UL;
/* Configure SysTick to interrupt at the requested rate. */ __weak void vPortSetupTimerInterrupt( void )
*(portNVIC_SYSTICK_LOAD) = ( configCPU_CLOCK_HZ / configTICK_RATE_HZ ) - 1UL; {
*(portNVIC_SYSTICK_CTRL) = portNVIC_SYSTICK_CLK | portNVIC_SYSTICK_INT | portNVIC_SYSTICK_ENABLE; /* Calculate the constants required to configure the tick interrupt. */
} #if( configUSE_TICKLESS_IDLE == 1 )
ulTimerCountsForOneTick = ( configCPU_CLOCK_HZ / configTICK_RATE_HZ );
xMaximumPossibleSuppressedTicks = portMAX_24_BIT_NUMBER / ulTimerCountsForOneTick;
ulStoppedTimerCompensation = portMISSED_COUNTS_FACTOR;
#endif /* configUSE_TICKLESS_IDLE */
/* Stop and reset the SysTick. */
portNVIC_SYSTICK_CTRL_REG = 0UL;
portNVIC_SYSTICK_CURRENT_VALUE_REG = 0UL;
/* Configure SysTick to interrupt at the requested rate. */
portNVIC_SYSTICK_LOAD_REG = ( configCPU_CLOCK_HZ / configTICK_RATE_HZ ) - 1UL;
portNVIC_SYSTICK_CTRL_REG = portNVIC_SYSTICK_CLK_BIT | portNVIC_SYSTICK_INT_BIT | portNVIC_SYSTICK_ENABLE_BIT;
}
#endif /* configOVERRIDE_DEFAULT_TICK_CONFIGURATION */
/*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/
#if( configUSE_TICKLESS_IDLE == 1 )
__weak void vPortSuppressTicksAndSleep( TickType_t xExpectedIdleTime )
{
uint32_t ulReloadValue, ulCompleteTickPeriods, ulCompletedSysTickDecrements;
TickType_t xModifiableIdleTime;
/* Make sure the SysTick reload value does not overflow the counter. */
if( xExpectedIdleTime > xMaximumPossibleSuppressedTicks )
{
xExpectedIdleTime = xMaximumPossibleSuppressedTicks;
}
/* Stop the SysTick momentarily. The time the SysTick is stopped for
is accounted for as best it can be, but using the tickless mode will
inevitably result in some tiny drift of the time maintained by the
kernel with respect to calendar time. */
portNVIC_SYSTICK_CTRL_REG &= ~portNVIC_SYSTICK_ENABLE_BIT;
/* Calculate the reload value required to wait xExpectedIdleTime
tick periods. -1 is used because this code will execute part way
through one of the tick periods. */
ulReloadValue = portNVIC_SYSTICK_CURRENT_VALUE_REG + ( ulTimerCountsForOneTick * ( xExpectedIdleTime - 1UL ) );
if( ulReloadValue > ulStoppedTimerCompensation )
{
ulReloadValue -= ulStoppedTimerCompensation;
}
/* Enter a critical section but don't use the taskENTER_CRITICAL()
method as that will mask interrupts that should exit sleep mode. */
__disable_irq();
__dsb( portSY_FULL_READ_WRITE );
__isb( portSY_FULL_READ_WRITE );
/* If a context switch is pending or a task is waiting for the scheduler
to be unsuspended then abandon the low power entry. */
if( eTaskConfirmSleepModeStatus() == eAbortSleep )
{
/* Restart from whatever is left in the count register to complete
this tick period. */
portNVIC_SYSTICK_LOAD_REG = portNVIC_SYSTICK_CURRENT_VALUE_REG;
/* Restart SysTick. */
portNVIC_SYSTICK_CTRL_REG |= portNVIC_SYSTICK_ENABLE_BIT;
/* Reset the reload register to the value required for normal tick
periods. */
portNVIC_SYSTICK_LOAD_REG = ulTimerCountsForOneTick - 1UL;
/* Re-enable interrupts - see comments above __disable_irq() call
above. */
__enable_irq();
}
else
{
/* Set the new reload value. */
portNVIC_SYSTICK_LOAD_REG = ulReloadValue;
/* Clear the SysTick count flag and set the count value back to
zero. */
portNVIC_SYSTICK_CURRENT_VALUE_REG = 0UL;
/* Restart SysTick. */
portNVIC_SYSTICK_CTRL_REG |= portNVIC_SYSTICK_ENABLE_BIT;
/* Sleep until something happens. configPRE_SLEEP_PROCESSING() can
set its parameter to 0 to indicate that its implementation contains
its own wait for interrupt or wait for event instruction, and so wfi
should not be executed again. However, the original expected idle
time variable must remain unmodified, so a copy is taken. */
xModifiableIdleTime = xExpectedIdleTime;
configPRE_SLEEP_PROCESSING( xModifiableIdleTime );
if( xModifiableIdleTime > 0 )
{
__dsb( portSY_FULL_READ_WRITE );
__wfi();
__isb( portSY_FULL_READ_WRITE );
}
configPOST_SLEEP_PROCESSING( xExpectedIdleTime );
/* Re-enable interrupts to allow the interrupt that brought the MCU
out of sleep mode to execute immediately. see comments above
__disable_interrupt() call above. */
__enable_irq();
__dsb( portSY_FULL_READ_WRITE );
__isb( portSY_FULL_READ_WRITE );
/* Disable interrupts again because the clock is about to be stopped
and interrupts that execute while the clock is stopped will increase
any slippage between the time maintained by the RTOS and calendar
time. */
__disable_irq();
__dsb( portSY_FULL_READ_WRITE );
__isb( portSY_FULL_READ_WRITE );
/* Disable the SysTick clock without reading the
portNVIC_SYSTICK_CTRL_REG register to ensure the
portNVIC_SYSTICK_COUNT_FLAG_BIT is not cleared if it is set. Again,
the time the SysTick is stopped for is accounted for as best it can
be, but using the tickless mode will inevitably result in some tiny
drift of the time maintained by the kernel with respect to calendar
time*/
portNVIC_SYSTICK_CTRL_REG = ( portNVIC_SYSTICK_CLK_BIT | portNVIC_SYSTICK_INT_BIT );
/* Determine if the SysTick clock has already counted to zero and
been set back to the current reload value (the reload back being
correct for the entire expected idle time) or if the SysTick is yet
to count to zero (in which case an interrupt other than the SysTick
must have brought the system out of sleep mode). */
if( ( portNVIC_SYSTICK_CTRL_REG & portNVIC_SYSTICK_COUNT_FLAG_BIT ) != 0 )
{
uint32_t ulCalculatedLoadValue;
/* The tick interrupt is already pending, and the SysTick count
reloaded with ulReloadValue. Reset the
portNVIC_SYSTICK_LOAD with whatever remains of this tick
period. */
ulCalculatedLoadValue = ( ulTimerCountsForOneTick - 1UL ) - ( ulReloadValue - portNVIC_SYSTICK_CURRENT_VALUE_REG );
/* Don't allow a tiny value, or values that have somehow
underflowed because the post sleep hook did something
that took too long. */
if( ( ulCalculatedLoadValue < ulStoppedTimerCompensation ) || ( ulCalculatedLoadValue > ulTimerCountsForOneTick ) )
{
ulCalculatedLoadValue = ( ulTimerCountsForOneTick - 1UL );
}
portNVIC_SYSTICK_LOAD_REG = ulCalculatedLoadValue;
/* As the pending tick will be processed as soon as this
function exits, the tick value maintained by the tick is stepped
forward by one less than the time spent waiting. */
ulCompleteTickPeriods = xExpectedIdleTime - 1UL;
}
else
{
/* Something other than the tick interrupt ended the sleep.
Work out how long the sleep lasted rounded to complete tick
periods (not the ulReload value which accounted for part
ticks). */
ulCompletedSysTickDecrements = ( xExpectedIdleTime * ulTimerCountsForOneTick ) - portNVIC_SYSTICK_CURRENT_VALUE_REG;
/* How many complete tick periods passed while the processor
was waiting? */
ulCompleteTickPeriods = ulCompletedSysTickDecrements / ulTimerCountsForOneTick;
/* The reload value is set to whatever fraction of a single tick
period remains. */
portNVIC_SYSTICK_LOAD_REG = ( ( ulCompleteTickPeriods + 1UL ) * ulTimerCountsForOneTick ) - ulCompletedSysTickDecrements;
}
/* Restart SysTick so it runs from portNVIC_SYSTICK_LOAD
again, then set portNVIC_SYSTICK_LOAD back to its standard
value. */
portNVIC_SYSTICK_CURRENT_VALUE_REG = 0UL;
portNVIC_SYSTICK_CTRL_REG |= portNVIC_SYSTICK_ENABLE_BIT;
vTaskStepTick( ulCompleteTickPeriods );
portNVIC_SYSTICK_LOAD_REG = ulTimerCountsForOneTick - 1UL;
/* Exit with interrpts enabled. */
__enable_irq();
}
}
#endif /* #if configUSE_TICKLESS_IDLE */
/*-----------------------------------------------------------*/

View file

@ -100,6 +100,13 @@ extern void vClearInterruptMaskFromISR( uint32_t ulMask );
/*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/
/* Tickless idle/low power functionality. */
#ifndef portSUPPRESS_TICKS_AND_SLEEP
extern void vPortSuppressTicksAndSleep( TickType_t xExpectedIdleTime );
#define portSUPPRESS_TICKS_AND_SLEEP( xExpectedIdleTime ) vPortSuppressTicksAndSleep( xExpectedIdleTime )
#endif
/*-----------------------------------------------------------*/
/* Task function macros as described on the FreeRTOS.org WEB site. */ /* Task function macros as described on the FreeRTOS.org WEB site. */
#define portTASK_FUNCTION_PROTO( vFunction, pvParameters ) void vFunction( void *pvParameters ) #define portTASK_FUNCTION_PROTO( vFunction, pvParameters ) void vFunction( void *pvParameters )
#define portTASK_FUNCTION( vFunction, pvParameters ) void vFunction( void *pvParameters ) #define portTASK_FUNCTION( vFunction, pvParameters ) void vFunction( void *pvParameters )

View file

@ -51,11 +51,11 @@
#define portNVIC_SYSTICK_CLK_BIT ( 0 ) #define portNVIC_SYSTICK_CLK_BIT ( 0 )
#endif #endif
/* The __weak attribute does not work as you might expect with the Keil tools /* Legacy macro for backward compatibility only. This macro used to be used to
so the configOVERRIDE_DEFAULT_TICK_CONFIGURATION constant must be set to 1 if replace the function that configures the clock used to generate the tick
the application writer wants to provide their own implementation of interrupt (prvSetupTimerInterrupt()), but now the function is declared weak so
vPortSetupTimerInterrupt(). Ensure configOVERRIDE_DEFAULT_TICK_CONFIGURATION the application writer can override it by simply defining a function of the
is defined. */ same name (vApplicationSetupTickInterrupt()). */
#ifndef configOVERRIDE_DEFAULT_TICK_CONFIGURATION #ifndef configOVERRIDE_DEFAULT_TICK_CONFIGURATION
#define configOVERRIDE_DEFAULT_TICK_CONFIGURATION 0 #define configOVERRIDE_DEFAULT_TICK_CONFIGURATION 0
#endif #endif
@ -603,7 +603,7 @@ void xPortSysTickHandler( void )
*/ */
#if( configOVERRIDE_DEFAULT_TICK_CONFIGURATION == 0 ) #if( configOVERRIDE_DEFAULT_TICK_CONFIGURATION == 0 )
void vPortSetupTimerInterrupt( void ) __weak void vPortSetupTimerInterrupt( void )
{ {
/* Calculate the constants required to configure the tick interrupt. */ /* Calculate the constants required to configure the tick interrupt. */
#if( configUSE_TICKLESS_IDLE == 1 ) #if( configUSE_TICKLESS_IDLE == 1 )

View file

@ -51,11 +51,11 @@
#define portNVIC_SYSTICK_CLK_BIT ( 0 ) #define portNVIC_SYSTICK_CLK_BIT ( 0 )
#endif #endif
/* The __weak attribute does not work as you might expect with the Keil tools /* Legacy macro for backward compatibility only. This macro used to be used to
so the configOVERRIDE_DEFAULT_TICK_CONFIGURATION constant must be set to 1 if replace the function that configures the clock used to generate the tick
the application writer wants to provide their own implementation of interrupt (prvSetupTimerInterrupt()), but now the function is declared weak so
vPortSetupTimerInterrupt(). Ensure configOVERRIDE_DEFAULT_TICK_CONFIGURATION the application writer can override it by simply defining a function of the
is defined. */ same name (vApplicationSetupTickInterrupt()). */
#ifndef configOVERRIDE_DEFAULT_TICK_CONFIGURATION #ifndef configOVERRIDE_DEFAULT_TICK_CONFIGURATION
#define configOVERRIDE_DEFAULT_TICK_CONFIGURATION 0 #define configOVERRIDE_DEFAULT_TICK_CONFIGURATION 0
#endif #endif
@ -693,7 +693,7 @@ void xPortSysTickHandler( void )
*/ */
#if( configOVERRIDE_DEFAULT_TICK_CONFIGURATION == 0 ) #if( configOVERRIDE_DEFAULT_TICK_CONFIGURATION == 0 )
void vPortSetupTimerInterrupt( void ) __weak void vPortSetupTimerInterrupt( void )
{ {
/* Calculate the constants required to configure the tick interrupt. */ /* Calculate the constants required to configure the tick interrupt. */
#if( configUSE_TICKLESS_IDLE == 1 ) #if( configUSE_TICKLESS_IDLE == 1 )

View file

@ -30,8 +30,8 @@
*----------------------------------------------------------*/ *----------------------------------------------------------*/
/* Defining MPU_WRAPPERS_INCLUDED_FROM_API_FILE prevents task.h from redefining /* Defining MPU_WRAPPERS_INCLUDED_FROM_API_FILE prevents task.h from redefining
all the API functions to use the MPU wrappers. That should only be done when * all the API functions to use the MPU wrappers. That should only be done when
task.h is included from an application file. */ * task.h is included from an application file. */
#define MPU_WRAPPERS_INCLUDED_FROM_API_FILE #define MPU_WRAPPERS_INCLUDED_FROM_API_FILE
/* Scheduler includes. */ /* Scheduler includes. */
@ -99,18 +99,18 @@ task.h is included from an application file. */
#define portOFFSET_TO_PC ( 6 ) #define portOFFSET_TO_PC ( 6 )
/* For strict compliance with the Cortex-M spec the task start address should /* For strict compliance with the Cortex-M spec the task start address should
have bit-0 clear, as it is loaded into the PC on exit from an ISR. */ * have bit-0 clear, as it is loaded into the PC on exit from an ISR. */
#define portSTART_ADDRESS_MASK ( ( StackType_t ) 0xfffffffeUL ) #define portSTART_ADDRESS_MASK ( ( StackType_t ) 0xfffffffeUL )
/* Each task maintains its own interrupt status in the critical nesting /* Each task maintains its own interrupt status in the critical nesting
variable. Note this is not saved as part of the task context as context * variable. Note this is not saved as part of the task context as context
switches can only occur when uxCriticalNesting is zero. */ * switches can only occur when uxCriticalNesting is zero. */
static UBaseType_t uxCriticalNesting = 0xaaaaaaaa; static UBaseType_t uxCriticalNesting = 0xaaaaaaaa;
/* /*
* Setup the timer to generate the tick interrupts. * Setup the timer to generate the tick interrupts.
*/ */
static void prvSetupTimerInterrupt( void ) PRIVILEGED_FUNCTION; void vSetupTimerInterrupt( void ) PRIVILEGED_FUNCTION;
/* /*
* Configure a number of standard MPU regions that are used by all tasks. * Configure a number of standard MPU regions that are used by all tasks.
@ -205,7 +205,7 @@ extern void vPortResetPrivilege( BaseType_t xRunningPrivileged );
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 )
{ {
/* Simulate the stack frame as it would be created by a context switch /* Simulate the stack frame as it would be created by a context switch
interrupt. */ * interrupt. */
pxTopOfStack--; /* Offset added to account for the way the MCU uses the stack on entry/exit of interrupts. */ pxTopOfStack--; /* Offset added to account for the way the MCU uses the stack on entry/exit of interrupts. */
*pxTopOfStack = portINITIAL_XPSR; /* xPSR */ *pxTopOfStack = portINITIAL_XPSR; /* xPSR */
pxTopOfStack--; pxTopOfStack--;
@ -216,7 +216,7 @@ StackType_t *pxPortInitialiseStack( StackType_t *pxTopOfStack, TaskFunction_t px
*pxTopOfStack = ( StackType_t ) pvParameters; /* R0 */ *pxTopOfStack = ( StackType_t ) pvParameters; /* R0 */
/* A save method is being used that requires each task to maintain its /* A save method is being used that requires each task to maintain its
own exec return value. */ * own exec return value. */
pxTopOfStack--; pxTopOfStack--;
*pxTopOfStack = portINITIAL_EXC_RETURN; *pxTopOfStack = portINITIAL_EXC_RETURN;
@ -238,11 +238,16 @@ StackType_t *pxPortInitialiseStack( StackType_t *pxTopOfStack, TaskFunction_t px
void prvSVCHandler( uint32_t *pulParam ) void prvSVCHandler( uint32_t *pulParam )
{ {
uint8_t ucSVCNumber; uint8_t ucSVCNumber;
uint32_t ulReg; uint32_t ulReg, ulPC;
#if( configENFORCE_SYSTEM_CALLS_FROM_KERNEL_ONLY == 1 )
extern uint32_t __syscalls_flash_start__;
extern uint32_t __syscalls_flash_end__;
#endif /* #if( configENFORCE_SYSTEM_CALLS_FROM_KERNEL_ONLY == 1 ) */
/* The stack contains: r0, r1, r2, r3, r12, r14, the return address and /* The stack contains: r0, r1, r2, r3, r12, LR, PC and xPSR. The first
xPSR. The first argument (r0) is pulParam[ 0 ]. */ * argument (r0) is pulParam[ 0 ]. */
ucSVCNumber = ( ( uint8_t * ) pulParam[ portOFFSET_TO_PC ] )[ -2 ]; ulPC = pulParam[ portOFFSET_TO_PC ];
ucSVCNumber = ( ( uint8_t * ) ulPC )[ -2 ];
switch( ucSVCNumber ) switch( ucSVCNumber )
{ {
case portSVC_START_SCHEDULER : portNVIC_SYSPRI1_REG |= portNVIC_SVC_PRI; case portSVC_START_SCHEDULER : portNVIC_SYSPRI1_REG |= portNVIC_SVC_PRI;
@ -251,14 +256,30 @@ uint32_t ulReg;
case portSVC_YIELD : portNVIC_INT_CTRL_REG = portNVIC_PENDSVSET_BIT; case portSVC_YIELD : portNVIC_INT_CTRL_REG = portNVIC_PENDSVSET_BIT;
/* Barriers are normally not required /* Barriers are normally not required
but do ensure the code is completely * but do ensure the code is completely
within the specified behaviour for the * within the specified behaviour for the
architecture. */ * architecture. */
__asm volatile( "dsb" ); __asm volatile( "dsb" );
__asm volatile( "isb" ); __asm volatile( "isb" );
break; break;
#if( configENFORCE_SYSTEM_CALLS_FROM_KERNEL_ONLY == 1 )
case portSVC_RAISE_PRIVILEGE : /* Only raise the privilege, if the
* svc was raised from any of the
* system calls. */
if( ulPC >= ( uint32_t ) __syscalls_flash_start__ &&
ulPC <= ( uint32_t ) __syscalls_flash_end__ )
{
__asm
{
mrs ulReg, control /* Obtain current control value. */
bic ulReg, #1 /* Set privilege bit. */
msr control, ulReg /* Write back new control value. */
}
}
break;
#else
case portSVC_RAISE_PRIVILEGE : __asm case portSVC_RAISE_PRIVILEGE : __asm
{ {
mrs ulReg, control /* Obtain current control value. */ mrs ulReg, control /* Obtain current control value. */
@ -266,6 +287,7 @@ uint32_t ulReg;
msr control, ulReg /* Write back new control value. */ msr control, ulReg /* Write back new control value. */
} }
break; break;
#endif /* #if( configENFORCE_SYSTEM_CALLS_FROM_KERNEL_ONLY == 1 ) */
default : /* Unknown SVC call. */ default : /* Unknown SVC call. */
break; break;
@ -304,10 +326,24 @@ __asm void prvRestoreContextOfFirstTask( void )
ldr r1, [r3] ldr r1, [r3]
ldr r0, [r1] /* The first item in the TCB is the task top of stack. */ ldr r0, [r1] /* The first item in the TCB is the task top of stack. */
add r1, r1, #4 /* Move onto the second item in the TCB... */ add r1, r1, #4 /* Move onto the second item in the TCB... */
dmb /* Complete outstanding transfers before disabling MPU. */
ldr r2, =0xe000ed94 /* MPU_CTRL register. */
ldr r3, [r2] /* Read the value of MPU_CTRL. */
bic r3, r3, #1 /* r3 = r3 & ~1 i.e. Clear the bit 0 in r3. */
str r3, [r2] /* Disable MPU. */
ldr r2, =0xe000ed9c /* Region Base Address register. */ ldr r2, =0xe000ed9c /* Region Base Address register. */
ldmia r1!, {r4-r11} /* Read 4 sets of MPU registers. */ ldmia r1!, {r4-r11} /* Read 4 sets of MPU registers. */
stmia r2!, {r4-r11} /* Write 4 sets of MPU registers. */ stmia r2!, {r4-r11} /* Write 4 sets of MPU registers. */
ldmia r0!, {r3-r11, r14} /* Pop the registers that are not automatically saved on exception entry. */
ldr r2, =0xe000ed94 /* MPU_CTRL register. */
ldr r3, [r2] /* Read the value of MPU_CTRL. */
orr r3, r3, #1 /* r3 = r3 | 1 i.e. Set the bit 0 in r3. */
str r3, [r2] /* Enable MPU. */
dsb /* Force memory writes before continuing. */
ldmia r0!, {r3-r11, r14} /* Pop the registers that are not automatically saved on exception entry. */
msr control, r3 msr control, r3
msr psp, r0 /* Restore the task stack pointer. */ msr psp, r0 /* Restore the task stack pointer. */
mov r0, #0 mov r0, #0
@ -323,7 +359,7 @@ __asm void prvRestoreContextOfFirstTask( void )
BaseType_t xPortStartScheduler( void ) BaseType_t xPortStartScheduler( void )
{ {
/* configMAX_SYSCALL_INTERRUPT_PRIORITY must not be set to 0. See /* configMAX_SYSCALL_INTERRUPT_PRIORITY must not be set to 0. See
http://www.FreeRTOS.org/RTOS-Cortex-M3-M4.html */ * http://www.FreeRTOS.org/RTOS-Cortex-M3-M4.html */
configASSERT( ( configMAX_SYSCALL_INTERRUPT_PRIORITY ) ); configASSERT( ( configMAX_SYSCALL_INTERRUPT_PRIORITY ) );
#if( configASSERT_DEFINED == 1 ) #if( configASSERT_DEFINED == 1 )
@ -333,15 +369,15 @@ BaseType_t xPortStartScheduler( void )
volatile uint8_t ucMaxPriorityValue; volatile uint8_t ucMaxPriorityValue;
/* Determine the maximum priority from which ISR safe FreeRTOS API /* Determine the maximum priority from which ISR safe FreeRTOS API
functions can be called. ISR safe functions are those that end in * functions can be called. ISR safe functions are those that end in
"FromISR". FreeRTOS maintains separate thread and ISR API functions to * "FromISR". FreeRTOS maintains separate thread and ISR API functions to
ensure interrupt entry is as fast and simple as possible. * ensure interrupt entry is as fast and simple as possible.
Save the interrupt priority value that is about to be clobbered. */ * Save the interrupt priority value that is about to be clobbered. */
ulOriginalPriority = *pucFirstUserPriorityRegister; ulOriginalPriority = *pucFirstUserPriorityRegister;
/* Determine the number of priority bits available. First write to all /* Determine the number of priority bits available. First write to all
possible bits. */ * possible bits. */
*pucFirstUserPriorityRegister = portMAX_8_BIT_VALUE; *pucFirstUserPriorityRegister = portMAX_8_BIT_VALUE;
/* Read the value back to see how many bits stuck. */ /* Read the value back to see how many bits stuck. */
@ -351,7 +387,7 @@ BaseType_t xPortStartScheduler( void )
ucMaxSysCallPriority = configMAX_SYSCALL_INTERRUPT_PRIORITY & ucMaxPriorityValue; ucMaxSysCallPriority = configMAX_SYSCALL_INTERRUPT_PRIORITY & ucMaxPriorityValue;
/* Calculate the maximum acceptable priority group value for the number /* Calculate the maximum acceptable priority group value for the number
of bits read back. */ * of bits read back. */
ulMaxPRIGROUPValue = portMAX_PRIGROUP_BITS; ulMaxPRIGROUPValue = portMAX_PRIGROUP_BITS;
while( ( ucMaxPriorityValue & portTOP_BIT_OF_BYTE ) == portTOP_BIT_OF_BYTE ) while( ( ucMaxPriorityValue & portTOP_BIT_OF_BYTE ) == portTOP_BIT_OF_BYTE )
{ {
@ -362,8 +398,8 @@ BaseType_t xPortStartScheduler( void )
#ifdef __NVIC_PRIO_BITS #ifdef __NVIC_PRIO_BITS
{ {
/* Check the CMSIS configuration that defines the number of /* Check the CMSIS configuration that defines the number of
priority bits matches the number of priority bits actually queried * priority bits matches the number of priority bits actually queried
from the hardware. */ * from the hardware. */
configASSERT( ( portMAX_PRIGROUP_BITS - ulMaxPRIGROUPValue ) == __NVIC_PRIO_BITS ); configASSERT( ( portMAX_PRIGROUP_BITS - ulMaxPRIGROUPValue ) == __NVIC_PRIO_BITS );
} }
#endif #endif
@ -371,26 +407,26 @@ BaseType_t xPortStartScheduler( void )
#ifdef configPRIO_BITS #ifdef configPRIO_BITS
{ {
/* Check the FreeRTOS configuration that defines the number of /* Check the FreeRTOS configuration that defines the number of
priority bits matches the number of priority bits actually queried * priority bits matches the number of priority bits actually queried
from the hardware. */ * from the hardware. */
configASSERT( ( portMAX_PRIGROUP_BITS - ulMaxPRIGROUPValue ) == configPRIO_BITS ); configASSERT( ( portMAX_PRIGROUP_BITS - ulMaxPRIGROUPValue ) == configPRIO_BITS );
} }
#endif #endif
/* Shift the priority group value back to its position within the AIRCR /* Shift the priority group value back to its position within the AIRCR
register. */ * register. */
ulMaxPRIGROUPValue <<= portPRIGROUP_SHIFT; ulMaxPRIGROUPValue <<= portPRIGROUP_SHIFT;
ulMaxPRIGROUPValue &= portPRIORITY_GROUP_MASK; ulMaxPRIGROUPValue &= portPRIORITY_GROUP_MASK;
/* Restore the clobbered interrupt priority register to its original /* Restore the clobbered interrupt priority register to its original
value. */ * value. */
*pucFirstUserPriorityRegister = ulOriginalPriority; *pucFirstUserPriorityRegister = ulOriginalPriority;
} }
#endif /* conifgASSERT_DEFINED */ #endif /* conifgASSERT_DEFINED */
/* Make PendSV and SysTick the same priority as the kernel, and the SVC /* Make PendSV and SysTick the same priority as the kernel, and the SVC
handler higher priority so it can be used to exit a critical section (where * handler higher priority so it can be used to exit a critical section (where
lower priorities are masked). */ * lower priorities are masked). */
portNVIC_SYSPRI2_REG |= portNVIC_PENDSV_PRI; portNVIC_SYSPRI2_REG |= portNVIC_PENDSV_PRI;
portNVIC_SYSPRI2_REG |= portNVIC_SYSTICK_PRI; portNVIC_SYSPRI2_REG |= portNVIC_SYSTICK_PRI;
@ -398,8 +434,8 @@ BaseType_t xPortStartScheduler( void )
prvSetupMPU(); prvSetupMPU();
/* Start the timer that generates the tick ISR. Interrupts are disabled /* Start the timer that generates the tick ISR. Interrupts are disabled
here already. */ * here already. */
prvSetupTimerInterrupt(); vSetupTimerInterrupt();
/* Initialise the critical nesting count ready for the first task. */ /* Initialise the critical nesting count ready for the first task. */
uxCriticalNesting = 0; uxCriticalNesting = 0;
@ -429,9 +465,9 @@ __asm void prvStartFirstTask( void )
/* Set the msp back to the start of the stack. */ /* Set the msp back to the start of the stack. */
msr msp, r0 msr msp, r0
/* Clear the bit that indicates the FPU is in use in case the FPU was used /* Clear the bit that indicates the FPU is in use in case the FPU was used
before the scheduler was started - which would otherwise result in the * before the scheduler was started - which would otherwise result in the
unnecessary leaving of space in the SVC stack for lazy saving of FPU * unnecessary leaving of space in the SVC stack for lazy saving of FPU
registers. */ * registers. */
mov r0, #0 mov r0, #0
msr control, r0 msr control, r0
/* Globally enable interrupts. */ /* Globally enable interrupts. */
@ -447,7 +483,7 @@ __asm void prvStartFirstTask( void )
void vPortEndScheduler( void ) void vPortEndScheduler( void )
{ {
/* Not implemented in ports where there is nothing to return to. /* Not implemented in ports where there is nothing to return to.
Artificially force an assert. */ * Artificially force an assert. */
configASSERT( uxCriticalNesting == 1000UL ); configASSERT( uxCriticalNesting == 1000UL );
} }
/*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/
@ -511,9 +547,23 @@ __asm void xPortPendSVHandler( void )
ldr r1, [r3] ldr r1, [r3]
ldr r0, [r1] /* The first item in the TCB is the task top of stack. */ ldr r0, [r1] /* The first item in the TCB is the task top of stack. */
add r1, r1, #4 /* Move onto the second item in the TCB... */ add r1, r1, #4 /* Move onto the second item in the TCB... */
dmb /* Complete outstanding transfers before disabling MPU. */
ldr r2, =0xe000ed94 /* MPU_CTRL register. */
ldr r3, [r2] /* Read the value of MPU_CTRL. */
bic r3, r3, #1 /* r3 = r3 & ~1 i.e. Clear the bit 0 in r3. */
str r3, [r2] /* Disable MPU. */
ldr r2, =0xe000ed9c /* Region Base Address register. */ ldr r2, =0xe000ed9c /* Region Base Address register. */
ldmia r1!, {r4-r11} /* Read 4 sets of MPU registers. */ ldmia r1!, {r4-r11} /* Read 4 sets of MPU registers. */
stmia r2!, {r4-r11} /* Write 4 sets of MPU registers. */ stmia r2!, {r4-r11} /* Write 4 sets of MPU registers. */
ldr r2, =0xe000ed94 /* MPU_CTRL register. */
ldr r3, [r2] /* Read the value of MPU_CTRL. */
orr r3, r3, #1 /* r3 = r3 | 1 i.e. Set the bit 0 in r3. */
str r3, [r2] /* Enable MPU. */
dsb /* Force memory writes before continuing. */
ldmia r0!, {r3-r11, r14} /* Pop the registers that are not automatically saved on exception entry. */ ldmia r0!, {r3-r11, r14} /* Pop the registers that are not automatically saved on exception entry. */
msr control, r3 msr control, r3
@ -548,7 +598,7 @@ uint32_t ulDummy;
* Setup the systick timer to generate the tick interrupts at the required * Setup the systick timer to generate the tick interrupts at the required
* frequency. * frequency.
*/ */
static void prvSetupTimerInterrupt( void ) __weak void vSetupTimerInterrupt( void )
{ {
/* Reset the SysTick. */ /* Reset the SysTick. */
portNVIC_SYSTICK_CTRL_REG = 0UL; portNVIC_SYSTICK_CTRL_REG = 0UL;
@ -608,8 +658,8 @@ extern uint32_t __privileged_data_end__;
( portMPU_REGION_ENABLE ); ( portMPU_REGION_ENABLE );
/* Setup the first 16K for privileged only access (even though less /* Setup the first 16K for privileged only access (even though less
than 10K is actually being used). This is where the kernel code is * than 10K is actually being used). This is where the kernel code is
placed. */ * placed. */
portMPU_REGION_BASE_ADDRESS_REG = ( ( uint32_t ) __FLASH_segment_start__ ) | /* Base address. */ portMPU_REGION_BASE_ADDRESS_REG = ( ( uint32_t ) __FLASH_segment_start__ ) | /* Base address. */
( portMPU_REGION_VALID ) | ( portMPU_REGION_VALID ) |
( portPRIVILEGED_FLASH_REGION ); ( portPRIVILEGED_FLASH_REGION );
@ -620,7 +670,7 @@ extern uint32_t __privileged_data_end__;
( portMPU_REGION_ENABLE ); ( portMPU_REGION_ENABLE );
/* Setup the privileged data RAM region. This is where the kernel data /* Setup the privileged data RAM region. This is where the kernel data
is placed. */ * is placed. */
portMPU_REGION_BASE_ADDRESS_REG = ( ( uint32_t ) __privileged_data_start__ ) | /* Base address. */ portMPU_REGION_BASE_ADDRESS_REG = ( ( uint32_t ) __privileged_data_start__ ) | /* Base address. */
( portMPU_REGION_VALID ) | ( portMPU_REGION_VALID ) |
( portPRIVILEGED_RAM_REGION ); ( portPRIVILEGED_RAM_REGION );
@ -631,7 +681,7 @@ extern uint32_t __privileged_data_end__;
( portMPU_REGION_ENABLE ); ( portMPU_REGION_ENABLE );
/* By default allow everything to access the general peripherals. The /* By default allow everything to access the general peripherals. The
system peripherals and registers are protected. */ * system peripherals and registers are protected. */
portMPU_REGION_BASE_ADDRESS_REG = ( portPERIPHERALS_START_ADDRESS ) | portMPU_REGION_BASE_ADDRESS_REG = ( portPERIPHERALS_START_ADDRESS ) |
( portMPU_REGION_VALID ) | ( portMPU_REGION_VALID ) |
( portGENERAL_PERIPHERALS_REGION ); ( portGENERAL_PERIPHERALS_REGION );
@ -654,7 +704,7 @@ static uint32_t prvGetMPURegionSizeSetting( uint32_t ulActualSizeInBytes )
uint32_t ulRegionSize, ulReturnValue = 4; uint32_t ulRegionSize, ulReturnValue = 4;
/* 32 is the smallest region size, 31 is the largest valid value for /* 32 is the smallest region size, 31 is the largest valid value for
ulReturnValue. */ * ulReturnValue. */
for( ulRegionSize = 32UL; ulReturnValue < 31UL; ( ulRegionSize <<= 1UL ) ) for( ulRegionSize = 32UL; ulReturnValue < 31UL; ( ulRegionSize <<= 1UL ) )
{ {
if( ulActualSizeInBytes <= ulRegionSize ) if( ulActualSizeInBytes <= ulRegionSize )
@ -668,7 +718,7 @@ uint32_t ulRegionSize, ulReturnValue = 4;
} }
/* Shift the code by one before returning so it can be written directly /* Shift the code by one before returning so it can be written directly
into the the correct bit position of the attribute register. */ * into the the correct bit position of the attribute register. */
return ( ulReturnValue << 1UL ); return ( ulReturnValue << 1UL );
} }
/*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/
@ -723,7 +773,7 @@ uint32_t ul;
( portMPU_REGION_ENABLE ); ( portMPU_REGION_ENABLE );
/* Re-instate the privileged only RAM region as xRegion[ 0 ] will have /* Re-instate the privileged only RAM region as xRegion[ 0 ] will have
just removed the privileged only parameters. */ * just removed the privileged only parameters. */
xMPUSettings->xRegion[ 1 ].ulRegionBaseAddress = xMPUSettings->xRegion[ 1 ].ulRegionBaseAddress =
( ( uint32_t ) __privileged_data_start__ ) | /* Base address. */ ( ( uint32_t ) __privileged_data_start__ ) | /* Base address. */
( portMPU_REGION_VALID ) | ( portMPU_REGION_VALID ) |
@ -745,9 +795,9 @@ uint32_t ul;
else else
{ {
/* This function is called automatically when the task is created - in /* This function is called automatically when the task is created - in
which case the stack region parameters will be valid. At all other * which case the stack region parameters will be valid. At all other
times the stack parameters will not be valid and it is assumed that the * times the stack parameters will not be valid and it is assumed that the
stack region has already been configured. */ * stack region has already been configured. */
if( ulStackDepth > 0 ) if( ulStackDepth > 0 )
{ {
/* Define the region that allows access to the stack. */ /* Define the region that allows access to the stack. */
@ -770,8 +820,8 @@ uint32_t ul;
if( ( xRegions[ lIndex ] ).ulLengthInBytes > 0UL ) if( ( xRegions[ lIndex ] ).ulLengthInBytes > 0UL )
{ {
/* Translate the generic region definition contained in /* Translate the generic region definition contained in
xRegions into the CM3 specific MPU settings that are then * xRegions into the CM3 specific MPU settings that are then
stored in xMPUSettings. */ * stored in xMPUSettings. */
xMPUSettings->xRegion[ ul ].ulRegionBaseAddress = xMPUSettings->xRegion[ ul ].ulRegionBaseAddress =
( ( uint32_t ) xRegions[ lIndex ].pvBaseAddress ) | ( ( uint32_t ) xRegions[ lIndex ].pvBaseAddress ) |
( portMPU_REGION_VALID ) | ( portMPU_REGION_VALID ) |
@ -821,47 +871,46 @@ __asm uint32_t prvPortGetIPSR( void )
ucCurrentPriority = pcInterruptPriorityRegisters[ ulCurrentInterrupt ]; ucCurrentPriority = pcInterruptPriorityRegisters[ ulCurrentInterrupt ];
/* The following assertion will fail if a service routine (ISR) for /* The following assertion will fail if a service routine (ISR) for
an interrupt that has been assigned a priority above * an interrupt that has been assigned a priority above
configMAX_SYSCALL_INTERRUPT_PRIORITY calls an ISR safe FreeRTOS API * configMAX_SYSCALL_INTERRUPT_PRIORITY calls an ISR safe FreeRTOS API
function. ISR safe FreeRTOS API functions must *only* be called * function. ISR safe FreeRTOS API functions must *only* be called
from interrupts that have been assigned a priority at or below * from interrupts that have been assigned a priority at or below
configMAX_SYSCALL_INTERRUPT_PRIORITY. * configMAX_SYSCALL_INTERRUPT_PRIORITY.
Numerically low interrupt priority numbers represent logically high * Numerically low interrupt priority numbers represent logically high
interrupt priorities, therefore the priority of the interrupt must * interrupt priorities, therefore the priority of the interrupt must
be set to a value equal to or numerically *higher* than * be set to a value equal to or numerically *higher* than
configMAX_SYSCALL_INTERRUPT_PRIORITY. * configMAX_SYSCALL_INTERRUPT_PRIORITY.
Interrupts that use the FreeRTOS API must not be left at their * Interrupts that use the FreeRTOS API must not be left at their
default priority of zero as that is the highest possible priority, * default priority of zero as that is the highest possible priority,
which is guaranteed to be above configMAX_SYSCALL_INTERRUPT_PRIORITY, * which is guaranteed to be above configMAX_SYSCALL_INTERRUPT_PRIORITY,
and therefore also guaranteed to be invalid. * and therefore also guaranteed to be invalid.
FreeRTOS maintains separate thread and ISR API functions to ensure * FreeRTOS maintains separate thread and ISR API functions to ensure
interrupt entry is as fast and simple as possible. * interrupt entry is as fast and simple as possible.
The following links provide detailed information: * The following links provide detailed information:
http://www.freertos.org/RTOS-Cortex-M3-M4.html * http://www.freertos.org/RTOS-Cortex-M3-M4.html
http://www.freertos.org/FAQHelp.html */ * http://www.freertos.org/FAQHelp.html */
configASSERT( ucCurrentPriority >= ucMaxSysCallPriority ); configASSERT( ucCurrentPriority >= ucMaxSysCallPriority );
} }
/* Priority grouping: The interrupt controller (NVIC) allows the bits /* Priority grouping: The interrupt controller (NVIC) allows the bits
that define each interrupt's priority to be split between bits that * that define each interrupt's priority to be split between bits that
define the interrupt's pre-emption priority bits and bits that define * define the interrupt's pre-emption priority bits and bits that define
the interrupt's sub-priority. For simplicity all bits must be defined * the interrupt's sub-priority. For simplicity all bits must be defined
to be pre-emption priority bits. The following assertion will fail if * to be pre-emption priority bits. The following assertion will fail if
this is not the case (if some bits represent a sub-priority). * this is not the case (if some bits represent a sub-priority).
If the application only uses CMSIS libraries for interrupt * If the application only uses CMSIS libraries for interrupt
configuration then the correct setting can be achieved on all Cortex-M * configuration then the correct setting can be achieved on all Cortex-M
devices by calling NVIC_SetPriorityGrouping( 0 ); before starting the * devices by calling NVIC_SetPriorityGrouping( 0 ); before starting the
scheduler. Note however that some vendor specific peripheral libraries * scheduler. Note however that some vendor specific peripheral libraries
assume a non-zero priority group setting, in which cases using a value * assume a non-zero priority group setting, in which cases using a value
of zero will result in unpredicable behaviour. */ * of zero will result in unpredicable behaviour. */
configASSERT( ( portAIRCR_REG & portPRIORITY_GROUP_MASK ) <= ulMaxPRIGROUPValue ); configASSERT( ( portAIRCR_REG & portPRIORITY_GROUP_MASK ) <= ulMaxPRIGROUPValue );
} }
#endif /* configASSERT_DEFINED */ #endif /* configASSERT_DEFINED */
/*-----------------------------------------------------------*/

View file

@ -73,12 +73,13 @@ typedef unsigned long UBaseType_t;
#define portUSING_MPU_WRAPPERS 1 #define portUSING_MPU_WRAPPERS 1
#define portPRIVILEGE_BIT ( 0x80000000UL ) #define portPRIVILEGE_BIT ( 0x80000000UL )
#define portMPU_REGION_READ_WRITE ( 0x03UL << 24UL ) #define portMPU_REGION_READ_WRITE ( 0x03UL << 24UL )
#define portMPU_REGION_PRIVILEGED_READ_ONLY ( 0x05UL << 24UL ) #define portMPU_REGION_PRIVILEGED_READ_ONLY ( 0x05UL << 24UL )
#define portMPU_REGION_READ_ONLY ( 0x06UL << 24UL ) #define portMPU_REGION_READ_ONLY ( 0x06UL << 24UL )
#define portMPU_REGION_PRIVILEGED_READ_WRITE ( 0x01UL << 24UL ) #define portMPU_REGION_PRIVILEGED_READ_WRITE ( 0x01UL << 24UL )
#define portMPU_REGION_CACHEABLE_BUFFERABLE ( 0x07UL << 16UL ) #define portMPU_REGION_PRIVILEGED_READ_WRITE_UNPRIV_READ_ONLY ( 0x02UL << 24UL )
#define portMPU_REGION_EXECUTE_NEVER ( 0x01UL << 28UL ) #define portMPU_REGION_CACHEABLE_BUFFERABLE ( 0x07UL << 16UL )
#define portMPU_REGION_EXECUTE_NEVER ( 0x01UL << 28UL )
#define portUNPRIVILEGED_FLASH_REGION ( 0UL ) #define portUNPRIVILEGED_FLASH_REGION ( 0UL )
#define portPRIVILEGED_FLASH_REGION ( 1UL ) #define portPRIVILEGED_FLASH_REGION ( 1UL )
@ -301,6 +302,12 @@ BaseType_t xReturn;
} }
/*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/
#ifndef configENFORCE_SYSTEM_CALLS_FROM_KERNEL_ONLY
#warning "configENFORCE_SYSTEM_CALLS_FROM_KERNEL_ONLY is not defined. We recommend defining it to 1 in FreeRTOSConfig.h for better security."
#define configENFORCE_SYSTEM_CALLS_FROM_KERNEL_ONLY 0
#endif
/*-----------------------------------------------------------*/
#ifdef __cplusplus #ifdef __cplusplus
} }
#endif #endif

View file

@ -679,7 +679,7 @@ void xPortSysTickHandler( void )
*/ */
#if( configOVERRIDE_DEFAULT_TICK_CONFIGURATION == 0 ) #if( configOVERRIDE_DEFAULT_TICK_CONFIGURATION == 0 )
void vPortSetupTimerInterrupt( void ) __weak void vPortSetupTimerInterrupt( void )
{ {
/* Calculate the constants required to configure the tick interrupt. */ /* Calculate the constants required to configure the tick interrupt. */
#if( configUSE_TICKLESS_IDLE == 1 ) #if( configUSE_TICKLESS_IDLE == 1 )

View file

@ -0,0 +1,150 @@
/*
* Copyright (C) 2017 C-SKY Microsystems Co., Ltd. All rights reserved.
*
* 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
* the Software without restriction, including without limitation the rights to
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
* the Software, and to permit persons to whom the Software is furnished to do so,
* subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* 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
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*
* 1 tab == 4 spaces!
*/
/* Kernel includes. */
#include "FreeRTOS.h"
#include "task.h"
extern void vPortStartTask(void);
/* Used to keep track of the number of nested calls to taskENTER_CRITICAL(). This
will be set to 0 prior to the first task being started. */
portLONG ulCriticalNesting = 0x9999UL;
/* Used to record one tack want to swtich task after enter critical area, we need know it
* and implement task switch after exit critical area */
portLONG pendsvflag = 0;
StackType_t *pxPortInitialiseStack( StackType_t * pxTopOfStack, TaskFunction_t pxCode, void *pvParameters )
{
StackType_t *stk = NULL;
stk = pxTopOfStack;
*(--stk) = (uint32_t)pxCode; /* Entry Point */
*(--stk) = (uint32_t)0xE0000140L; /* PSR */
*(--stk) = (uint32_t)0xFFFFFFFEL; /* R15 (LR) (init value will cause fault if ever used) */
*(--stk) = (uint32_t)0x13131313L; /* R13 */
*(--stk) = (uint32_t)0x12121212L; /* R12 */
*(--stk) = (uint32_t)0x11111111L; /* R11 */
*(--stk) = (uint32_t)0x10101010L; /* R10 */
*(--stk) = (uint32_t)0x09090909L; /* R9 */
*(--stk) = (uint32_t)0x08080808L; /* R8 */
*(--stk) = (uint32_t)0x07070707L; /* R7 */
*(--stk) = (uint32_t)0x06060606L; /* R6 */
*(--stk) = (uint32_t)0x05050505L; /* R5 */
*(--stk) = (uint32_t)0x04040404L; /* R4 */
*(--stk) = (uint32_t)0x03030303L; /* R3 */
*(--stk) = (uint32_t)0x02020202L; /* R2 */
*(--stk) = (uint32_t)0x01010101L; /* R1 */
*(--stk) = (uint32_t)pvParameters; /* R0 : argument */
return stk;
}
BaseType_t xPortStartScheduler( void )
{
ulCriticalNesting = 0UL;
vPortStartTask();
return pdFALSE;
}
void vPortEndScheduler( void )
{
/* Not implemented as there is nothing to return to. */
}
void vPortEnterCritical( void )
{
portDISABLE_INTERRUPTS();
ulCriticalNesting ++;
}
void vPortExitCritical( void )
{
if (ulCriticalNesting == 0) {
while(1);
}
ulCriticalNesting --;
if (ulCriticalNesting == 0)
{
portENABLE_INTERRUPTS();
if (pendsvflag)
{
pendsvflag = 0;
portYIELD();
}
}
}
#if configUSE_PREEMPTION == 0
void xPortSysTickHandler( void )
{
portLONG ulDummy;
ulDummy = portSET_INTERRUPT_MASK_FROM_ISR();
xTaskIncrementTick();
portCLEAR_INTERRUPT_MASK_FROM_ISR( ulDummy );
}
#else
void xPortSysTickHandler( void )
{
portLONG ulDummy;
ulDummy = portSET_INTERRUPT_MASK_FROM_ISR();
{
if (xTaskIncrementTick() != pdFALSE)
{
portYIELD_FROM_ISR(pdTRUE);
}
}
portCLEAR_INTERRUPT_MASK_FROM_ISR( ulDummy );
}
#endif
void vPortYieldHandler( void )
{
uint32_t ulSavedInterruptMask;
ulSavedInterruptMask = portSET_INTERRUPT_MASK_FROM_ISR();
vTaskSwitchContext();
portCLEAR_INTERRUPT_MASK_FROM_ISR( ulSavedInterruptMask );
}
__attribute__((weak)) void vApplicationStackOverflowHook( xTaskHandle *pxTask, signed portCHAR *pcTaskName )
{
for(;;);
}
__attribute__((weak)) void vApplicationMallocFailedHook( void )
{
for(;;);
}

View file

@ -0,0 +1,126 @@
/*
* Copyright (C) 2017 C-SKY Microsystems Co., Ltd. All rights reserved.
*
* 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
* the Software without restriction, including without limitation the rights to
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
* the Software, and to permit persons to whom the Software is furnished to do so,
* subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* 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
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*
* 1 tab == 4 spaces!
*/
//#include <csi_config.h>
/********************************************************************
* Functions: vPortStartTask
*
********************************************************************/
.global vPortStartTask
.type vPortStartTask, %function
vPortStartTask:
psrclr ie
lrw r4, pxCurrentTCB
ld.w r4, (r4) // the current task stack pointer is the first member
ld.w sp, (r4)
ldw r0, (sp, 64)
mtcr r0, epc
ldw r0, (sp, 60)
mtcr r0, epsr
ldw r15, (sp, 56)
ldm r0-r13, (sp)
addi sp, 68
rte
/********************************************************************
* Functions: vPortYield
*
********************************************************************/
.global vPortYield
.type vPortYield, %function
vPortYield:
psrclr ee
subi sp, 68
stm r0-r13, (sp)
stw r15, (sp, 56)
mfcr r0, psr
bseti r0, 8
stw r0, (sp, 60)
stw r15, (sp, 64)
lrw r2, pxCurrentTCB
ld.w r3, (r2)
st.w sp, (r3)
jbsr vTaskSwitchContext
lrw r4, pxCurrentTCB
ld.w r4, (r4)
ld.w sp, (r4)
ldw r0, (sp, 64)
mtcr r0, epc
ldw r0, (sp, 60)
mtcr r0, epsr
ldw r15, (sp, 56)
ldm r0-r13, (sp)
addi sp, 68
rte
/********************************************************************
* Functions: NOVIC_IRQ_Default_Handler
*
********************************************************************/
.global NOVIC_IRQ_Default_Handler
.type NOVIC_IRQ_Default_Handler, %function
NOVIC_IRQ_Default_Handler:
psrset ee
subi sp, 68
stm r0-r13, (sp)
stw r15, (sp, 56)
mfcr r0, epsr
stw r0, (sp, 60)
mfcr r0, epc
stw r0, (sp, 64)
lrw r7, pxCurrentTCB
ldw r7, (r7)
stw sp, (r7)
lrw sp, g_top_irqstack
lrw r1, g_irqvector
mfcr r0, psr
lsri r0, 16
sextb r0
subi r0, 32
lsli r0, 2
add r1, r0
ldw r1, (r1)
lsri r0, 2
jsr r1
lrw r7, pxCurrentTCB
ldw r7, (r7)
ldw sp, (r7)
ldw r0, (sp, 64)
mtcr r0, epc
ldw r0, (sp, 60)
mtcr r0, epsr
ldm r0-r13, (sp)
ldw r15, (sp, 56)
addi sp, 68
rte

View file

@ -0,0 +1,159 @@
/*
* Copyright (C) 2017 C-SKY Microsystems Co., Ltd. All rights reserved.
*
* 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
* the Software without restriction, including without limitation the rights to
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
* the Software, and to permit persons to whom the Software is furnished to do so,
* subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* 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
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*
* 1 tab == 4 spaces!
*/
#ifndef PORTMACRO_H
#define PORTMACRO_H
#include <stdlib.h>
#include <stdint.h>
#include <csi_core.h>
extern void vPortYield(void);
#ifdef __cplusplus
class vPortYield;
extern "C" {
#endif
/*-----------------------------------------------------------
* 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 char
#define portFLOAT float
#define portDOUBLE double
#define portLONG long
#define portSHORT short
#define portSTACK_TYPE uint32_t
#define portBASE_TYPE long
typedef portSTACK_TYPE StackType_t;
typedef long BaseType_t;
typedef unsigned long UBaseType_t;
typedef void (*portvectorfunc)(void);
#if( configUSE_16_BIT_TICKS == 1 )
typedef uint16_t TickType_t;
#define portMAX_DELAY ( TickType_t ) 0xffff
#else
typedef uint32_t TickType_t;
#define portMAX_DELAY ( TickType_t ) 0xffffffffUL
#endif
/* Hardware specifics. */
#define portBYTE_ALIGNMENT 8
#define portSTACK_GROWTH -1
#define portMS_PERIOD_TICK 10
#define portTICK_PERIOD_MS ( ( TickType_t ) 1000 / configTICK_RATE_HZ )
static inline void vPortEnableInterrupt( void )
{
__enable_irq();
}
static inline void vPortDisableInterrupt( void )
{
__disable_irq();
}
static inline portLONG GetCurrentPSR (void)
{
return __get_PSR();
}
static inline portLONG SaveLocalPSR (void)
{
portLONG flags = __get_PSR();
__disable_irq();
return flags;
}
static inline void RestoreLocalPSR (portLONG newMask)
{
__asm__ __volatile__(
"mtcr %0, psr \n"
:
:"r" (newMask)
:"memory"
);
}
extern void vPortEnterCritical( void );
extern void vPortExitCritical( void );
extern __attribute__((naked)) void cpu_yeild(void);
#define portDISABLE_INTERRUPTS() vPortDisableInterrupt()
#define portENABLE_INTERRUPTS() vPortEnableInterrupt()
#define portENTER_CRITICAL() vPortEnterCritical()
#define portEXIT_CRITICAL() vPortExitCritical()
#define portSET_INTERRUPT_MASK_FROM_ISR() SaveLocalPSR()
#define portCLEAR_INTERRUPT_MASK_FROM_ISR(a) RestoreLocalPSR(a)
#define portNOP() asm("nop")
extern portLONG ulCriticalNesting;
extern portLONG pendsvflag;
#define portYIELD() if (ulCriticalNesting == 0) \
{ \
vPortYield(); \
} \
else \
{ \
pendsvflag = 1; \
} \
portNOP();portNOP()
/*-----------------------------------------------------------*/
/* Task function macros as described on the FreeRTOS.org WEB site. */
#define portTASK_FUNCTION_PROTO( vFunction, pvParameters ) void vFunction( void *pvParameters ) __attribute__((noreturn))
#define portTASK_FUNCTION( vFunction, pvParameters ) void vFunction( void *pvParameters )
/*-----------------------------------------------------------*/
#define portEND_SWITCHING_ISR( xSwitchRequired ) do { \
if( xSwitchRequired != pdFALSE ) \
{ \
portYIELD(); \
} \
}while(0)
#define portYIELD_FROM_ISR( a ) vTaskSwitchContext()
#ifdef __cplusplus
}
#endif
#endif /* PORTMACRO_H */

View file

@ -0,0 +1,6 @@
The official and MIT licensed FreeRTOS ports for RISC-V are located in the following directories:
\FreeRTOS\Source\portable\GCC\RISC-V
\FreeRTOS\Source\portable\IAR\RISC-V
Also so https://www.freertos.org/Using-FreeRTOS-on-RISC-V.html