add lib/CMSIS_5 v5.7 locally
This commit is contained in:
@@ -0,0 +1,756 @@
|
||||
/*
|
||||
* Copyright (c) 2013-2018 Arm Limited. All rights reserved.
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the License); you may
|
||||
* not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an AS IS BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
* ----------------------------------------------------------------------
|
||||
*
|
||||
* $Date: 18. June 2018
|
||||
* $Revision: V2.1.3
|
||||
*
|
||||
* Project: CMSIS-RTOS2 API
|
||||
* Title: cmsis_os2.h header file
|
||||
*
|
||||
* Version 2.1.3
|
||||
* Additional functions allowed to be called from Interrupt Service Routines:
|
||||
* - osThreadGetId
|
||||
* Version 2.1.2
|
||||
* Additional functions allowed to be called from Interrupt Service Routines:
|
||||
* - osKernelGetInfo, osKernelGetState
|
||||
* Version 2.1.1
|
||||
* Additional functions allowed to be called from Interrupt Service Routines:
|
||||
* - osKernelGetTickCount, osKernelGetTickFreq
|
||||
* Changed Kernel Tick type to uint32_t:
|
||||
* - updated: osKernelGetTickCount, osDelayUntil
|
||||
* Version 2.1.0
|
||||
* Support for critical and uncritical sections (nesting safe):
|
||||
* - updated: osKernelLock, osKernelUnlock
|
||||
* - added: osKernelRestoreLock
|
||||
* Updated Thread and Event Flags:
|
||||
* - changed flags parameter and return type from int32_t to uint32_t
|
||||
* Version 2.0.0
|
||||
* Initial Release
|
||||
*---------------------------------------------------------------------------*/
|
||||
|
||||
#ifndef CMSIS_OS2_H_
|
||||
#define CMSIS_OS2_H_
|
||||
|
||||
#ifndef __NO_RETURN
|
||||
#if defined(__CC_ARM)
|
||||
#define __NO_RETURN __declspec(noreturn)
|
||||
#elif defined(__ARMCC_VERSION) && (__ARMCC_VERSION >= 6010050)
|
||||
#define __NO_RETURN __attribute__((__noreturn__))
|
||||
#elif defined(__GNUC__)
|
||||
#define __NO_RETURN __attribute__((__noreturn__))
|
||||
#elif defined(__ICCARM__)
|
||||
#define __NO_RETURN __noreturn
|
||||
#else
|
||||
#define __NO_RETURN
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C"
|
||||
{
|
||||
#endif
|
||||
|
||||
|
||||
// ==== Enumerations, structures, defines ====
|
||||
|
||||
/// Version information.
|
||||
typedef struct {
|
||||
uint32_t api; ///< API version (major.minor.rev: mmnnnrrrr dec).
|
||||
uint32_t kernel; ///< Kernel version (major.minor.rev: mmnnnrrrr dec).
|
||||
} osVersion_t;
|
||||
|
||||
/// Kernel state.
|
||||
typedef enum {
|
||||
osKernelInactive = 0, ///< Inactive.
|
||||
osKernelReady = 1, ///< Ready.
|
||||
osKernelRunning = 2, ///< Running.
|
||||
osKernelLocked = 3, ///< Locked.
|
||||
osKernelSuspended = 4, ///< Suspended.
|
||||
osKernelError = -1, ///< Error.
|
||||
osKernelReserved = 0x7FFFFFFFU ///< Prevents enum down-size compiler optimization.
|
||||
} osKernelState_t;
|
||||
|
||||
/// Thread state.
|
||||
typedef enum {
|
||||
osThreadInactive = 0, ///< Inactive.
|
||||
osThreadReady = 1, ///< Ready.
|
||||
osThreadRunning = 2, ///< Running.
|
||||
osThreadBlocked = 3, ///< Blocked.
|
||||
osThreadTerminated = 4, ///< Terminated.
|
||||
osThreadError = -1, ///< Error.
|
||||
osThreadReserved = 0x7FFFFFFF ///< Prevents enum down-size compiler optimization.
|
||||
} osThreadState_t;
|
||||
|
||||
/// Priority values.
|
||||
typedef enum {
|
||||
osPriorityNone = 0, ///< No priority (not initialized).
|
||||
osPriorityIdle = 1, ///< Reserved for Idle thread.
|
||||
osPriorityLow = 8, ///< Priority: low
|
||||
osPriorityLow1 = 8+1, ///< Priority: low + 1
|
||||
osPriorityLow2 = 8+2, ///< Priority: low + 2
|
||||
osPriorityLow3 = 8+3, ///< Priority: low + 3
|
||||
osPriorityLow4 = 8+4, ///< Priority: low + 4
|
||||
osPriorityLow5 = 8+5, ///< Priority: low + 5
|
||||
osPriorityLow6 = 8+6, ///< Priority: low + 6
|
||||
osPriorityLow7 = 8+7, ///< Priority: low + 7
|
||||
osPriorityBelowNormal = 16, ///< Priority: below normal
|
||||
osPriorityBelowNormal1 = 16+1, ///< Priority: below normal + 1
|
||||
osPriorityBelowNormal2 = 16+2, ///< Priority: below normal + 2
|
||||
osPriorityBelowNormal3 = 16+3, ///< Priority: below normal + 3
|
||||
osPriorityBelowNormal4 = 16+4, ///< Priority: below normal + 4
|
||||
osPriorityBelowNormal5 = 16+5, ///< Priority: below normal + 5
|
||||
osPriorityBelowNormal6 = 16+6, ///< Priority: below normal + 6
|
||||
osPriorityBelowNormal7 = 16+7, ///< Priority: below normal + 7
|
||||
osPriorityNormal = 24, ///< Priority: normal
|
||||
osPriorityNormal1 = 24+1, ///< Priority: normal + 1
|
||||
osPriorityNormal2 = 24+2, ///< Priority: normal + 2
|
||||
osPriorityNormal3 = 24+3, ///< Priority: normal + 3
|
||||
osPriorityNormal4 = 24+4, ///< Priority: normal + 4
|
||||
osPriorityNormal5 = 24+5, ///< Priority: normal + 5
|
||||
osPriorityNormal6 = 24+6, ///< Priority: normal + 6
|
||||
osPriorityNormal7 = 24+7, ///< Priority: normal + 7
|
||||
osPriorityAboveNormal = 32, ///< Priority: above normal
|
||||
osPriorityAboveNormal1 = 32+1, ///< Priority: above normal + 1
|
||||
osPriorityAboveNormal2 = 32+2, ///< Priority: above normal + 2
|
||||
osPriorityAboveNormal3 = 32+3, ///< Priority: above normal + 3
|
||||
osPriorityAboveNormal4 = 32+4, ///< Priority: above normal + 4
|
||||
osPriorityAboveNormal5 = 32+5, ///< Priority: above normal + 5
|
||||
osPriorityAboveNormal6 = 32+6, ///< Priority: above normal + 6
|
||||
osPriorityAboveNormal7 = 32+7, ///< Priority: above normal + 7
|
||||
osPriorityHigh = 40, ///< Priority: high
|
||||
osPriorityHigh1 = 40+1, ///< Priority: high + 1
|
||||
osPriorityHigh2 = 40+2, ///< Priority: high + 2
|
||||
osPriorityHigh3 = 40+3, ///< Priority: high + 3
|
||||
osPriorityHigh4 = 40+4, ///< Priority: high + 4
|
||||
osPriorityHigh5 = 40+5, ///< Priority: high + 5
|
||||
osPriorityHigh6 = 40+6, ///< Priority: high + 6
|
||||
osPriorityHigh7 = 40+7, ///< Priority: high + 7
|
||||
osPriorityRealtime = 48, ///< Priority: realtime
|
||||
osPriorityRealtime1 = 48+1, ///< Priority: realtime + 1
|
||||
osPriorityRealtime2 = 48+2, ///< Priority: realtime + 2
|
||||
osPriorityRealtime3 = 48+3, ///< Priority: realtime + 3
|
||||
osPriorityRealtime4 = 48+4, ///< Priority: realtime + 4
|
||||
osPriorityRealtime5 = 48+5, ///< Priority: realtime + 5
|
||||
osPriorityRealtime6 = 48+6, ///< Priority: realtime + 6
|
||||
osPriorityRealtime7 = 48+7, ///< Priority: realtime + 7
|
||||
osPriorityISR = 56, ///< Reserved for ISR deferred thread.
|
||||
osPriorityError = -1, ///< System cannot determine priority or illegal priority.
|
||||
osPriorityReserved = 0x7FFFFFFF ///< Prevents enum down-size compiler optimization.
|
||||
} osPriority_t;
|
||||
|
||||
/// Entry point of a thread.
|
||||
typedef void (*osThreadFunc_t) (void *argument);
|
||||
|
||||
/// Timer callback function.
|
||||
typedef void (*osTimerFunc_t) (void *argument);
|
||||
|
||||
/// Timer type.
|
||||
typedef enum {
|
||||
osTimerOnce = 0, ///< One-shot timer.
|
||||
osTimerPeriodic = 1 ///< Repeating timer.
|
||||
} osTimerType_t;
|
||||
|
||||
// Timeout value.
|
||||
#define osWaitForever 0xFFFFFFFFU ///< Wait forever timeout value.
|
||||
|
||||
// Flags options (\ref osThreadFlagsWait and \ref osEventFlagsWait).
|
||||
#define osFlagsWaitAny 0x00000000U ///< Wait for any flag (default).
|
||||
#define osFlagsWaitAll 0x00000001U ///< Wait for all flags.
|
||||
#define osFlagsNoClear 0x00000002U ///< Do not clear flags which have been specified to wait for.
|
||||
|
||||
// Flags errors (returned by osThreadFlagsXxxx and osEventFlagsXxxx).
|
||||
#define osFlagsError 0x80000000U ///< Error indicator.
|
||||
#define osFlagsErrorUnknown 0xFFFFFFFFU ///< osError (-1).
|
||||
#define osFlagsErrorTimeout 0xFFFFFFFEU ///< osErrorTimeout (-2).
|
||||
#define osFlagsErrorResource 0xFFFFFFFDU ///< osErrorResource (-3).
|
||||
#define osFlagsErrorParameter 0xFFFFFFFCU ///< osErrorParameter (-4).
|
||||
#define osFlagsErrorISR 0xFFFFFFFAU ///< osErrorISR (-6).
|
||||
|
||||
// Thread attributes (attr_bits in \ref osThreadAttr_t).
|
||||
#define osThreadDetached 0x00000000U ///< Thread created in detached mode (default)
|
||||
#define osThreadJoinable 0x00000001U ///< Thread created in joinable mode
|
||||
|
||||
// Mutex attributes (attr_bits in \ref osMutexAttr_t).
|
||||
#define osMutexRecursive 0x00000001U ///< Recursive mutex.
|
||||
#define osMutexPrioInherit 0x00000002U ///< Priority inherit protocol.
|
||||
#define osMutexRobust 0x00000008U ///< Robust mutex.
|
||||
|
||||
/// Status code values returned by CMSIS-RTOS functions.
|
||||
typedef enum {
|
||||
osOK = 0, ///< Operation completed successfully.
|
||||
osError = -1, ///< Unspecified RTOS error: run-time error but no other error message fits.
|
||||
osErrorTimeout = -2, ///< Operation not completed within the timeout period.
|
||||
osErrorResource = -3, ///< Resource not available.
|
||||
osErrorParameter = -4, ///< Parameter error.
|
||||
osErrorNoMemory = -5, ///< System is out of memory: it was impossible to allocate or reserve memory for the operation.
|
||||
osErrorISR = -6, ///< Not allowed in ISR context: the function cannot be called from interrupt service routines.
|
||||
osStatusReserved = 0x7FFFFFFF ///< Prevents enum down-size compiler optimization.
|
||||
} osStatus_t;
|
||||
|
||||
|
||||
/// \details Thread ID identifies the thread.
|
||||
typedef void *osThreadId_t;
|
||||
|
||||
/// \details Timer ID identifies the timer.
|
||||
typedef void *osTimerId_t;
|
||||
|
||||
/// \details Event Flags ID identifies the event flags.
|
||||
typedef void *osEventFlagsId_t;
|
||||
|
||||
/// \details Mutex ID identifies the mutex.
|
||||
typedef void *osMutexId_t;
|
||||
|
||||
/// \details Semaphore ID identifies the semaphore.
|
||||
typedef void *osSemaphoreId_t;
|
||||
|
||||
/// \details Memory Pool ID identifies the memory pool.
|
||||
typedef void *osMemoryPoolId_t;
|
||||
|
||||
/// \details Message Queue ID identifies the message queue.
|
||||
typedef void *osMessageQueueId_t;
|
||||
|
||||
|
||||
#ifndef TZ_MODULEID_T
|
||||
#define TZ_MODULEID_T
|
||||
/// \details Data type that identifies secure software modules called by a process.
|
||||
typedef uint32_t TZ_ModuleId_t;
|
||||
#endif
|
||||
|
||||
|
||||
/// Attributes structure for thread.
|
||||
typedef struct {
|
||||
const char *name; ///< name of the thread
|
||||
uint32_t attr_bits; ///< attribute bits
|
||||
void *cb_mem; ///< memory for control block
|
||||
uint32_t cb_size; ///< size of provided memory for control block
|
||||
void *stack_mem; ///< memory for stack
|
||||
uint32_t stack_size; ///< size of stack
|
||||
osPriority_t priority; ///< initial thread priority (default: osPriorityNormal)
|
||||
TZ_ModuleId_t tz_module; ///< TrustZone module identifier
|
||||
uint32_t reserved; ///< reserved (must be 0)
|
||||
} osThreadAttr_t;
|
||||
|
||||
/// Attributes structure for timer.
|
||||
typedef struct {
|
||||
const char *name; ///< name of the timer
|
||||
uint32_t attr_bits; ///< attribute bits
|
||||
void *cb_mem; ///< memory for control block
|
||||
uint32_t cb_size; ///< size of provided memory for control block
|
||||
} osTimerAttr_t;
|
||||
|
||||
/// Attributes structure for event flags.
|
||||
typedef struct {
|
||||
const char *name; ///< name of the event flags
|
||||
uint32_t attr_bits; ///< attribute bits
|
||||
void *cb_mem; ///< memory for control block
|
||||
uint32_t cb_size; ///< size of provided memory for control block
|
||||
} osEventFlagsAttr_t;
|
||||
|
||||
/// Attributes structure for mutex.
|
||||
typedef struct {
|
||||
const char *name; ///< name of the mutex
|
||||
uint32_t attr_bits; ///< attribute bits
|
||||
void *cb_mem; ///< memory for control block
|
||||
uint32_t cb_size; ///< size of provided memory for control block
|
||||
} osMutexAttr_t;
|
||||
|
||||
/// Attributes structure for semaphore.
|
||||
typedef struct {
|
||||
const char *name; ///< name of the semaphore
|
||||
uint32_t attr_bits; ///< attribute bits
|
||||
void *cb_mem; ///< memory for control block
|
||||
uint32_t cb_size; ///< size of provided memory for control block
|
||||
} osSemaphoreAttr_t;
|
||||
|
||||
/// Attributes structure for memory pool.
|
||||
typedef struct {
|
||||
const char *name; ///< name of the memory pool
|
||||
uint32_t attr_bits; ///< attribute bits
|
||||
void *cb_mem; ///< memory for control block
|
||||
uint32_t cb_size; ///< size of provided memory for control block
|
||||
void *mp_mem; ///< memory for data storage
|
||||
uint32_t mp_size; ///< size of provided memory for data storage
|
||||
} osMemoryPoolAttr_t;
|
||||
|
||||
/// Attributes structure for message queue.
|
||||
typedef struct {
|
||||
const char *name; ///< name of the message queue
|
||||
uint32_t attr_bits; ///< attribute bits
|
||||
void *cb_mem; ///< memory for control block
|
||||
uint32_t cb_size; ///< size of provided memory for control block
|
||||
void *mq_mem; ///< memory for data storage
|
||||
uint32_t mq_size; ///< size of provided memory for data storage
|
||||
} osMessageQueueAttr_t;
|
||||
|
||||
|
||||
// ==== Kernel Management Functions ====
|
||||
|
||||
/// Initialize the RTOS Kernel.
|
||||
/// \return status code that indicates the execution status of the function.
|
||||
osStatus_t osKernelInitialize (void);
|
||||
|
||||
/// Get RTOS Kernel Information.
|
||||
/// \param[out] version pointer to buffer for retrieving version information.
|
||||
/// \param[out] id_buf pointer to buffer for retrieving kernel identification string.
|
||||
/// \param[in] id_size size of buffer for kernel identification string.
|
||||
/// \return status code that indicates the execution status of the function.
|
||||
osStatus_t osKernelGetInfo (osVersion_t *version, char *id_buf, uint32_t id_size);
|
||||
|
||||
/// Get the current RTOS Kernel state.
|
||||
/// \return current RTOS Kernel state.
|
||||
osKernelState_t osKernelGetState (void);
|
||||
|
||||
/// Start the RTOS Kernel scheduler.
|
||||
/// \return status code that indicates the execution status of the function.
|
||||
osStatus_t osKernelStart (void);
|
||||
|
||||
/// Lock the RTOS Kernel scheduler.
|
||||
/// \return previous lock state (1 - locked, 0 - not locked, error code if negative).
|
||||
int32_t osKernelLock (void);
|
||||
|
||||
/// Unlock the RTOS Kernel scheduler.
|
||||
/// \return previous lock state (1 - locked, 0 - not locked, error code if negative).
|
||||
int32_t osKernelUnlock (void);
|
||||
|
||||
/// Restore the RTOS Kernel scheduler lock state.
|
||||
/// \param[in] lock lock state obtained by \ref osKernelLock or \ref osKernelUnlock.
|
||||
/// \return new lock state (1 - locked, 0 - not locked, error code if negative).
|
||||
int32_t osKernelRestoreLock (int32_t lock);
|
||||
|
||||
/// Suspend the RTOS Kernel scheduler.
|
||||
/// \return time in ticks, for how long the system can sleep or power-down.
|
||||
uint32_t osKernelSuspend (void);
|
||||
|
||||
/// Resume the RTOS Kernel scheduler.
|
||||
/// \param[in] sleep_ticks time in ticks for how long the system was in sleep or power-down mode.
|
||||
void osKernelResume (uint32_t sleep_ticks);
|
||||
|
||||
/// Get the RTOS kernel tick count.
|
||||
/// \return RTOS kernel current tick count.
|
||||
uint32_t osKernelGetTickCount (void);
|
||||
|
||||
/// Get the RTOS kernel tick frequency.
|
||||
/// \return frequency of the kernel tick in hertz, i.e. kernel ticks per second.
|
||||
uint32_t osKernelGetTickFreq (void);
|
||||
|
||||
/// Get the RTOS kernel system timer count.
|
||||
/// \return RTOS kernel current system timer count as 32-bit value.
|
||||
uint32_t osKernelGetSysTimerCount (void);
|
||||
|
||||
/// Get the RTOS kernel system timer frequency.
|
||||
/// \return frequency of the system timer in hertz, i.e. timer ticks per second.
|
||||
uint32_t osKernelGetSysTimerFreq (void);
|
||||
|
||||
|
||||
// ==== Thread Management Functions ====
|
||||
|
||||
/// Create a thread and add it to Active Threads.
|
||||
/// \param[in] func thread function.
|
||||
/// \param[in] argument pointer that is passed to the thread function as start argument.
|
||||
/// \param[in] attr thread attributes; NULL: default values.
|
||||
/// \return thread ID for reference by other functions or NULL in case of error.
|
||||
osThreadId_t osThreadNew (osThreadFunc_t func, void *argument, const osThreadAttr_t *attr);
|
||||
|
||||
/// Get name of a thread.
|
||||
/// \param[in] thread_id thread ID obtained by \ref osThreadNew or \ref osThreadGetId.
|
||||
/// \return name as null-terminated string.
|
||||
const char *osThreadGetName (osThreadId_t thread_id);
|
||||
|
||||
/// Return the thread ID of the current running thread.
|
||||
/// \return thread ID for reference by other functions or NULL in case of error.
|
||||
osThreadId_t osThreadGetId (void);
|
||||
|
||||
/// Get current thread state of a thread.
|
||||
/// \param[in] thread_id thread ID obtained by \ref osThreadNew or \ref osThreadGetId.
|
||||
/// \return current thread state of the specified thread.
|
||||
osThreadState_t osThreadGetState (osThreadId_t thread_id);
|
||||
|
||||
/// Get stack size of a thread.
|
||||
/// \param[in] thread_id thread ID obtained by \ref osThreadNew or \ref osThreadGetId.
|
||||
/// \return stack size in bytes.
|
||||
uint32_t osThreadGetStackSize (osThreadId_t thread_id);
|
||||
|
||||
/// Get available stack space of a thread based on stack watermark recording during execution.
|
||||
/// \param[in] thread_id thread ID obtained by \ref osThreadNew or \ref osThreadGetId.
|
||||
/// \return remaining stack space in bytes.
|
||||
uint32_t osThreadGetStackSpace (osThreadId_t thread_id);
|
||||
|
||||
/// Change priority of a thread.
|
||||
/// \param[in] thread_id thread ID obtained by \ref osThreadNew or \ref osThreadGetId.
|
||||
/// \param[in] priority new priority value for the thread function.
|
||||
/// \return status code that indicates the execution status of the function.
|
||||
osStatus_t osThreadSetPriority (osThreadId_t thread_id, osPriority_t priority);
|
||||
|
||||
/// Get current priority of a thread.
|
||||
/// \param[in] thread_id thread ID obtained by \ref osThreadNew or \ref osThreadGetId.
|
||||
/// \return current priority value of the specified thread.
|
||||
osPriority_t osThreadGetPriority (osThreadId_t thread_id);
|
||||
|
||||
/// Pass control to next thread that is in state \b READY.
|
||||
/// \return status code that indicates the execution status of the function.
|
||||
osStatus_t osThreadYield (void);
|
||||
|
||||
/// Suspend execution of a thread.
|
||||
/// \param[in] thread_id thread ID obtained by \ref osThreadNew or \ref osThreadGetId.
|
||||
/// \return status code that indicates the execution status of the function.
|
||||
osStatus_t osThreadSuspend (osThreadId_t thread_id);
|
||||
|
||||
/// Resume execution of a thread.
|
||||
/// \param[in] thread_id thread ID obtained by \ref osThreadNew or \ref osThreadGetId.
|
||||
/// \return status code that indicates the execution status of the function.
|
||||
osStatus_t osThreadResume (osThreadId_t thread_id);
|
||||
|
||||
/// Detach a thread (thread storage can be reclaimed when thread terminates).
|
||||
/// \param[in] thread_id thread ID obtained by \ref osThreadNew or \ref osThreadGetId.
|
||||
/// \return status code that indicates the execution status of the function.
|
||||
osStatus_t osThreadDetach (osThreadId_t thread_id);
|
||||
|
||||
/// Wait for specified thread to terminate.
|
||||
/// \param[in] thread_id thread ID obtained by \ref osThreadNew or \ref osThreadGetId.
|
||||
/// \return status code that indicates the execution status of the function.
|
||||
osStatus_t osThreadJoin (osThreadId_t thread_id);
|
||||
|
||||
/// Terminate execution of current running thread.
|
||||
__NO_RETURN void osThreadExit (void);
|
||||
|
||||
/// Terminate execution of a thread.
|
||||
/// \param[in] thread_id thread ID obtained by \ref osThreadNew or \ref osThreadGetId.
|
||||
/// \return status code that indicates the execution status of the function.
|
||||
osStatus_t osThreadTerminate (osThreadId_t thread_id);
|
||||
|
||||
/// Get number of active threads.
|
||||
/// \return number of active threads.
|
||||
uint32_t osThreadGetCount (void);
|
||||
|
||||
/// Enumerate active threads.
|
||||
/// \param[out] thread_array pointer to array for retrieving thread IDs.
|
||||
/// \param[in] array_items maximum number of items in array for retrieving thread IDs.
|
||||
/// \return number of enumerated threads.
|
||||
uint32_t osThreadEnumerate (osThreadId_t *thread_array, uint32_t array_items);
|
||||
|
||||
|
||||
// ==== Thread Flags Functions ====
|
||||
|
||||
/// Set the specified Thread Flags of a thread.
|
||||
/// \param[in] thread_id thread ID obtained by \ref osThreadNew or \ref osThreadGetId.
|
||||
/// \param[in] flags specifies the flags of the thread that shall be set.
|
||||
/// \return thread flags after setting or error code if highest bit set.
|
||||
uint32_t osThreadFlagsSet (osThreadId_t thread_id, uint32_t flags);
|
||||
|
||||
/// Clear the specified Thread Flags of current running thread.
|
||||
/// \param[in] flags specifies the flags of the thread that shall be cleared.
|
||||
/// \return thread flags before clearing or error code if highest bit set.
|
||||
uint32_t osThreadFlagsClear (uint32_t flags);
|
||||
|
||||
/// Get the current Thread Flags of current running thread.
|
||||
/// \return current thread flags.
|
||||
uint32_t osThreadFlagsGet (void);
|
||||
|
||||
/// Wait for one or more Thread Flags of the current running thread to become signaled.
|
||||
/// \param[in] flags specifies the flags to wait for.
|
||||
/// \param[in] options specifies flags options (osFlagsXxxx).
|
||||
/// \param[in] timeout \ref CMSIS_RTOS_TimeOutValue or 0 in case of no time-out.
|
||||
/// \return thread flags before clearing or error code if highest bit set.
|
||||
uint32_t osThreadFlagsWait (uint32_t flags, uint32_t options, uint32_t timeout);
|
||||
|
||||
|
||||
// ==== Generic Wait Functions ====
|
||||
|
||||
/// Wait for Timeout (Time Delay).
|
||||
/// \param[in] ticks \ref CMSIS_RTOS_TimeOutValue "time ticks" value
|
||||
/// \return status code that indicates the execution status of the function.
|
||||
osStatus_t osDelay (uint32_t ticks);
|
||||
|
||||
/// Wait until specified time.
|
||||
/// \param[in] ticks absolute time in ticks
|
||||
/// \return status code that indicates the execution status of the function.
|
||||
osStatus_t osDelayUntil (uint32_t ticks);
|
||||
|
||||
|
||||
// ==== Timer Management Functions ====
|
||||
|
||||
/// Create and Initialize a timer.
|
||||
/// \param[in] func function pointer to callback function.
|
||||
/// \param[in] type \ref osTimerOnce for one-shot or \ref osTimerPeriodic for periodic behavior.
|
||||
/// \param[in] argument argument to the timer callback function.
|
||||
/// \param[in] attr timer attributes; NULL: default values.
|
||||
/// \return timer ID for reference by other functions or NULL in case of error.
|
||||
osTimerId_t osTimerNew (osTimerFunc_t func, osTimerType_t type, void *argument, const osTimerAttr_t *attr);
|
||||
|
||||
/// Get name of a timer.
|
||||
/// \param[in] timer_id timer ID obtained by \ref osTimerNew.
|
||||
/// \return name as null-terminated string.
|
||||
const char *osTimerGetName (osTimerId_t timer_id);
|
||||
|
||||
/// Start or restart a timer.
|
||||
/// \param[in] timer_id timer ID obtained by \ref osTimerNew.
|
||||
/// \param[in] ticks \ref CMSIS_RTOS_TimeOutValue "time ticks" value of the timer.
|
||||
/// \return status code that indicates the execution status of the function.
|
||||
osStatus_t osTimerStart (osTimerId_t timer_id, uint32_t ticks);
|
||||
|
||||
/// Stop a timer.
|
||||
/// \param[in] timer_id timer ID obtained by \ref osTimerNew.
|
||||
/// \return status code that indicates the execution status of the function.
|
||||
osStatus_t osTimerStop (osTimerId_t timer_id);
|
||||
|
||||
/// Check if a timer is running.
|
||||
/// \param[in] timer_id timer ID obtained by \ref osTimerNew.
|
||||
/// \return 0 not running, 1 running.
|
||||
uint32_t osTimerIsRunning (osTimerId_t timer_id);
|
||||
|
||||
/// Delete a timer.
|
||||
/// \param[in] timer_id timer ID obtained by \ref osTimerNew.
|
||||
/// \return status code that indicates the execution status of the function.
|
||||
osStatus_t osTimerDelete (osTimerId_t timer_id);
|
||||
|
||||
|
||||
// ==== Event Flags Management Functions ====
|
||||
|
||||
/// Create and Initialize an Event Flags object.
|
||||
/// \param[in] attr event flags attributes; NULL: default values.
|
||||
/// \return event flags ID for reference by other functions or NULL in case of error.
|
||||
osEventFlagsId_t osEventFlagsNew (const osEventFlagsAttr_t *attr);
|
||||
|
||||
/// Get name of an Event Flags object.
|
||||
/// \param[in] ef_id event flags ID obtained by \ref osEventFlagsNew.
|
||||
/// \return name as null-terminated string.
|
||||
const char *osEventFlagsGetName (osEventFlagsId_t ef_id);
|
||||
|
||||
/// Set the specified Event Flags.
|
||||
/// \param[in] ef_id event flags ID obtained by \ref osEventFlagsNew.
|
||||
/// \param[in] flags specifies the flags that shall be set.
|
||||
/// \return event flags after setting or error code if highest bit set.
|
||||
uint32_t osEventFlagsSet (osEventFlagsId_t ef_id, uint32_t flags);
|
||||
|
||||
/// Clear the specified Event Flags.
|
||||
/// \param[in] ef_id event flags ID obtained by \ref osEventFlagsNew.
|
||||
/// \param[in] flags specifies the flags that shall be cleared.
|
||||
/// \return event flags before clearing or error code if highest bit set.
|
||||
uint32_t osEventFlagsClear (osEventFlagsId_t ef_id, uint32_t flags);
|
||||
|
||||
/// Get the current Event Flags.
|
||||
/// \param[in] ef_id event flags ID obtained by \ref osEventFlagsNew.
|
||||
/// \return current event flags.
|
||||
uint32_t osEventFlagsGet (osEventFlagsId_t ef_id);
|
||||
|
||||
/// Wait for one or more Event Flags to become signaled.
|
||||
/// \param[in] ef_id event flags ID obtained by \ref osEventFlagsNew.
|
||||
/// \param[in] flags specifies the flags to wait for.
|
||||
/// \param[in] options specifies flags options (osFlagsXxxx).
|
||||
/// \param[in] timeout \ref CMSIS_RTOS_TimeOutValue or 0 in case of no time-out.
|
||||
/// \return event flags before clearing or error code if highest bit set.
|
||||
uint32_t osEventFlagsWait (osEventFlagsId_t ef_id, uint32_t flags, uint32_t options, uint32_t timeout);
|
||||
|
||||
/// Delete an Event Flags object.
|
||||
/// \param[in] ef_id event flags ID obtained by \ref osEventFlagsNew.
|
||||
/// \return status code that indicates the execution status of the function.
|
||||
osStatus_t osEventFlagsDelete (osEventFlagsId_t ef_id);
|
||||
|
||||
|
||||
// ==== Mutex Management Functions ====
|
||||
|
||||
/// Create and Initialize a Mutex object.
|
||||
/// \param[in] attr mutex attributes; NULL: default values.
|
||||
/// \return mutex ID for reference by other functions or NULL in case of error.
|
||||
osMutexId_t osMutexNew (const osMutexAttr_t *attr);
|
||||
|
||||
/// Get name of a Mutex object.
|
||||
/// \param[in] mutex_id mutex ID obtained by \ref osMutexNew.
|
||||
/// \return name as null-terminated string.
|
||||
const char *osMutexGetName (osMutexId_t mutex_id);
|
||||
|
||||
/// Acquire a Mutex or timeout if it is locked.
|
||||
/// \param[in] mutex_id mutex ID obtained by \ref osMutexNew.
|
||||
/// \param[in] timeout \ref CMSIS_RTOS_TimeOutValue or 0 in case of no time-out.
|
||||
/// \return status code that indicates the execution status of the function.
|
||||
osStatus_t osMutexAcquire (osMutexId_t mutex_id, uint32_t timeout);
|
||||
|
||||
/// Release a Mutex that was acquired by \ref osMutexAcquire.
|
||||
/// \param[in] mutex_id mutex ID obtained by \ref osMutexNew.
|
||||
/// \return status code that indicates the execution status of the function.
|
||||
osStatus_t osMutexRelease (osMutexId_t mutex_id);
|
||||
|
||||
/// Get Thread which owns a Mutex object.
|
||||
/// \param[in] mutex_id mutex ID obtained by \ref osMutexNew.
|
||||
/// \return thread ID of owner thread or NULL when mutex was not acquired.
|
||||
osThreadId_t osMutexGetOwner (osMutexId_t mutex_id);
|
||||
|
||||
/// Delete a Mutex object.
|
||||
/// \param[in] mutex_id mutex ID obtained by \ref osMutexNew.
|
||||
/// \return status code that indicates the execution status of the function.
|
||||
osStatus_t osMutexDelete (osMutexId_t mutex_id);
|
||||
|
||||
|
||||
// ==== Semaphore Management Functions ====
|
||||
|
||||
/// Create and Initialize a Semaphore object.
|
||||
/// \param[in] max_count maximum number of available tokens.
|
||||
/// \param[in] initial_count initial number of available tokens.
|
||||
/// \param[in] attr semaphore attributes; NULL: default values.
|
||||
/// \return semaphore ID for reference by other functions or NULL in case of error.
|
||||
osSemaphoreId_t osSemaphoreNew (uint32_t max_count, uint32_t initial_count, const osSemaphoreAttr_t *attr);
|
||||
|
||||
/// Get name of a Semaphore object.
|
||||
/// \param[in] semaphore_id semaphore ID obtained by \ref osSemaphoreNew.
|
||||
/// \return name as null-terminated string.
|
||||
const char *osSemaphoreGetName (osSemaphoreId_t semaphore_id);
|
||||
|
||||
/// Acquire a Semaphore token or timeout if no tokens are available.
|
||||
/// \param[in] semaphore_id semaphore ID obtained by \ref osSemaphoreNew.
|
||||
/// \param[in] timeout \ref CMSIS_RTOS_TimeOutValue or 0 in case of no time-out.
|
||||
/// \return status code that indicates the execution status of the function.
|
||||
osStatus_t osSemaphoreAcquire (osSemaphoreId_t semaphore_id, uint32_t timeout);
|
||||
|
||||
/// Release a Semaphore token up to the initial maximum count.
|
||||
/// \param[in] semaphore_id semaphore ID obtained by \ref osSemaphoreNew.
|
||||
/// \return status code that indicates the execution status of the function.
|
||||
osStatus_t osSemaphoreRelease (osSemaphoreId_t semaphore_id);
|
||||
|
||||
/// Get current Semaphore token count.
|
||||
/// \param[in] semaphore_id semaphore ID obtained by \ref osSemaphoreNew.
|
||||
/// \return number of tokens available.
|
||||
uint32_t osSemaphoreGetCount (osSemaphoreId_t semaphore_id);
|
||||
|
||||
/// Delete a Semaphore object.
|
||||
/// \param[in] semaphore_id semaphore ID obtained by \ref osSemaphoreNew.
|
||||
/// \return status code that indicates the execution status of the function.
|
||||
osStatus_t osSemaphoreDelete (osSemaphoreId_t semaphore_id);
|
||||
|
||||
|
||||
// ==== Memory Pool Management Functions ====
|
||||
|
||||
/// Create and Initialize a Memory Pool object.
|
||||
/// \param[in] block_count maximum number of memory blocks in memory pool.
|
||||
/// \param[in] block_size memory block size in bytes.
|
||||
/// \param[in] attr memory pool attributes; NULL: default values.
|
||||
/// \return memory pool ID for reference by other functions or NULL in case of error.
|
||||
osMemoryPoolId_t osMemoryPoolNew (uint32_t block_count, uint32_t block_size, const osMemoryPoolAttr_t *attr);
|
||||
|
||||
/// Get name of a Memory Pool object.
|
||||
/// \param[in] mp_id memory pool ID obtained by \ref osMemoryPoolNew.
|
||||
/// \return name as null-terminated string.
|
||||
const char *osMemoryPoolGetName (osMemoryPoolId_t mp_id);
|
||||
|
||||
/// Allocate a memory block from a Memory Pool.
|
||||
/// \param[in] mp_id memory pool ID obtained by \ref osMemoryPoolNew.
|
||||
/// \param[in] timeout \ref CMSIS_RTOS_TimeOutValue or 0 in case of no time-out.
|
||||
/// \return address of the allocated memory block or NULL in case of no memory is available.
|
||||
void *osMemoryPoolAlloc (osMemoryPoolId_t mp_id, uint32_t timeout);
|
||||
|
||||
/// Return an allocated memory block back to a Memory Pool.
|
||||
/// \param[in] mp_id memory pool ID obtained by \ref osMemoryPoolNew.
|
||||
/// \param[in] block address of the allocated memory block to be returned to the memory pool.
|
||||
/// \return status code that indicates the execution status of the function.
|
||||
osStatus_t osMemoryPoolFree (osMemoryPoolId_t mp_id, void *block);
|
||||
|
||||
/// Get maximum number of memory blocks in a Memory Pool.
|
||||
/// \param[in] mp_id memory pool ID obtained by \ref osMemoryPoolNew.
|
||||
/// \return maximum number of memory blocks.
|
||||
uint32_t osMemoryPoolGetCapacity (osMemoryPoolId_t mp_id);
|
||||
|
||||
/// Get memory block size in a Memory Pool.
|
||||
/// \param[in] mp_id memory pool ID obtained by \ref osMemoryPoolNew.
|
||||
/// \return memory block size in bytes.
|
||||
uint32_t osMemoryPoolGetBlockSize (osMemoryPoolId_t mp_id);
|
||||
|
||||
/// Get number of memory blocks used in a Memory Pool.
|
||||
/// \param[in] mp_id memory pool ID obtained by \ref osMemoryPoolNew.
|
||||
/// \return number of memory blocks used.
|
||||
uint32_t osMemoryPoolGetCount (osMemoryPoolId_t mp_id);
|
||||
|
||||
/// Get number of memory blocks available in a Memory Pool.
|
||||
/// \param[in] mp_id memory pool ID obtained by \ref osMemoryPoolNew.
|
||||
/// \return number of memory blocks available.
|
||||
uint32_t osMemoryPoolGetSpace (osMemoryPoolId_t mp_id);
|
||||
|
||||
/// Delete a Memory Pool object.
|
||||
/// \param[in] mp_id memory pool ID obtained by \ref osMemoryPoolNew.
|
||||
/// \return status code that indicates the execution status of the function.
|
||||
osStatus_t osMemoryPoolDelete (osMemoryPoolId_t mp_id);
|
||||
|
||||
|
||||
// ==== Message Queue Management Functions ====
|
||||
|
||||
/// Create and Initialize a Message Queue object.
|
||||
/// \param[in] msg_count maximum number of messages in queue.
|
||||
/// \param[in] msg_size maximum message size in bytes.
|
||||
/// \param[in] attr message queue attributes; NULL: default values.
|
||||
/// \return message queue ID for reference by other functions or NULL in case of error.
|
||||
osMessageQueueId_t osMessageQueueNew (uint32_t msg_count, uint32_t msg_size, const osMessageQueueAttr_t *attr);
|
||||
|
||||
/// Get name of a Message Queue object.
|
||||
/// \param[in] mq_id message queue ID obtained by \ref osMessageQueueNew.
|
||||
/// \return name as null-terminated string.
|
||||
const char *osMessageQueueGetName (osMessageQueueId_t mq_id);
|
||||
|
||||
/// Put a Message into a Queue or timeout if Queue is full.
|
||||
/// \param[in] mq_id message queue ID obtained by \ref osMessageQueueNew.
|
||||
/// \param[in] msg_ptr pointer to buffer with message to put into a queue.
|
||||
/// \param[in] msg_prio message priority.
|
||||
/// \param[in] timeout \ref CMSIS_RTOS_TimeOutValue or 0 in case of no time-out.
|
||||
/// \return status code that indicates the execution status of the function.
|
||||
osStatus_t osMessageQueuePut (osMessageQueueId_t mq_id, const void *msg_ptr, uint8_t msg_prio, uint32_t timeout);
|
||||
|
||||
/// Get a Message from a Queue or timeout if Queue is empty.
|
||||
/// \param[in] mq_id message queue ID obtained by \ref osMessageQueueNew.
|
||||
/// \param[out] msg_ptr pointer to buffer for message to get from a queue.
|
||||
/// \param[out] msg_prio pointer to buffer for message priority or NULL.
|
||||
/// \param[in] timeout \ref CMSIS_RTOS_TimeOutValue or 0 in case of no time-out.
|
||||
/// \return status code that indicates the execution status of the function.
|
||||
osStatus_t osMessageQueueGet (osMessageQueueId_t mq_id, void *msg_ptr, uint8_t *msg_prio, uint32_t timeout);
|
||||
|
||||
/// Get maximum number of messages in a Message Queue.
|
||||
/// \param[in] mq_id message queue ID obtained by \ref osMessageQueueNew.
|
||||
/// \return maximum number of messages.
|
||||
uint32_t osMessageQueueGetCapacity (osMessageQueueId_t mq_id);
|
||||
|
||||
/// Get maximum message size in a Memory Pool.
|
||||
/// \param[in] mq_id message queue ID obtained by \ref osMessageQueueNew.
|
||||
/// \return maximum message size in bytes.
|
||||
uint32_t osMessageQueueGetMsgSize (osMessageQueueId_t mq_id);
|
||||
|
||||
/// Get number of queued messages in a Message Queue.
|
||||
/// \param[in] mq_id message queue ID obtained by \ref osMessageQueueNew.
|
||||
/// \return number of queued messages.
|
||||
uint32_t osMessageQueueGetCount (osMessageQueueId_t mq_id);
|
||||
|
||||
/// Get number of available slots for messages in a Message Queue.
|
||||
/// \param[in] mq_id message queue ID obtained by \ref osMessageQueueNew.
|
||||
/// \return number of available slots for messages.
|
||||
uint32_t osMessageQueueGetSpace (osMessageQueueId_t mq_id);
|
||||
|
||||
/// Reset a Message Queue to initial empty state.
|
||||
/// \param[in] mq_id message queue ID obtained by \ref osMessageQueueNew.
|
||||
/// \return status code that indicates the execution status of the function.
|
||||
osStatus_t osMessageQueueReset (osMessageQueueId_t mq_id);
|
||||
|
||||
/// Delete a Message Queue object.
|
||||
/// \param[in] mq_id message queue ID obtained by \ref osMessageQueueNew.
|
||||
/// \return status code that indicates the execution status of the function.
|
||||
osStatus_t osMessageQueueDelete (osMessageQueueId_t mq_id);
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif // CMSIS_OS2_H_
|
||||
@@ -0,0 +1,71 @@
|
||||
/**************************************************************************//**
|
||||
* @file os_tick.h
|
||||
* @brief CMSIS OS Tick header file
|
||||
* @version V1.0.1
|
||||
* @date 24. November 2017
|
||||
******************************************************************************/
|
||||
/*
|
||||
* Copyright (c) 2017-2017 ARM Limited. All rights reserved.
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the License); you may
|
||||
* not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an AS IS BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#ifndef OS_TICK_H
|
||||
#define OS_TICK_H
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
/// IRQ Handler.
|
||||
#ifndef IRQHANDLER_T
|
||||
#define IRQHANDLER_T
|
||||
typedef void (*IRQHandler_t) (void);
|
||||
#endif
|
||||
|
||||
/// Setup OS Tick timer to generate periodic RTOS Kernel Ticks
|
||||
/// \param[in] freq tick frequency in Hz
|
||||
/// \param[in] handler tick IRQ handler
|
||||
/// \return 0 on success, -1 on error.
|
||||
int32_t OS_Tick_Setup (uint32_t freq, IRQHandler_t handler);
|
||||
|
||||
/// Enable OS Tick timer interrupt
|
||||
void OS_Tick_Enable (void);
|
||||
|
||||
/// Disable OS Tick timer interrupt
|
||||
void OS_Tick_Disable (void);
|
||||
|
||||
/// Acknowledge execution of OS Tick timer interrupt
|
||||
void OS_Tick_AcknowledgeIRQ (void);
|
||||
|
||||
/// Get OS Tick timer IRQ number
|
||||
/// \return OS Tick IRQ number
|
||||
int32_t OS_Tick_GetIRQn (void);
|
||||
|
||||
/// Get OS Tick timer clock frequency
|
||||
/// \return OS Tick timer clock frequency in Hz
|
||||
uint32_t OS_Tick_GetClock (void);
|
||||
|
||||
/// Get OS Tick timer interval reload value
|
||||
/// \return OS Tick timer interval reload value
|
||||
uint32_t OS_Tick_GetInterval (void);
|
||||
|
||||
/// Get OS Tick timer counter value
|
||||
/// \return OS Tick timer counter value
|
||||
uint32_t OS_Tick_GetCount (void);
|
||||
|
||||
/// Get OS Tick timer overflow status
|
||||
/// \return OS Tick overflow status (1 - overflow, 0 - no overflow).
|
||||
uint32_t OS_Tick_GetOverflow (void);
|
||||
|
||||
#endif /* OS_TICK_H */
|
||||
@@ -0,0 +1,64 @@
|
||||
/*
|
||||
* Copyright (c) 2013-2018 Arm Limited. All rights reserved.
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the License); you may
|
||||
* not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an AS IS BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
* -----------------------------------------------------------------------------
|
||||
*
|
||||
* $Revision: V5.1.0
|
||||
*
|
||||
* Project: CMSIS-RTOS RTX
|
||||
* Title: RTX Configuration
|
||||
*
|
||||
* -----------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
#include "cmsis_compiler.h"
|
||||
#include "rtx_os.h"
|
||||
|
||||
// OS Idle Thread
|
||||
__WEAK __NO_RETURN void osRtxIdleThread (void *argument) {
|
||||
(void)argument;
|
||||
|
||||
for (;;) {}
|
||||
}
|
||||
|
||||
// OS Error Callback function
|
||||
__WEAK uint32_t osRtxErrorNotify (uint32_t code, void *object_id) {
|
||||
(void)object_id;
|
||||
|
||||
switch (code) {
|
||||
case osRtxErrorStackUnderflow:
|
||||
// Stack overflow detected for thread (thread_id=object_id)
|
||||
break;
|
||||
case osRtxErrorISRQueueOverflow:
|
||||
// ISR Queue overflow detected when inserting object (object_id)
|
||||
break;
|
||||
case osRtxErrorTimerQueueOverflow:
|
||||
// User Timer Callback Queue overflow detected for timer (timer_id=object_id)
|
||||
break;
|
||||
case osRtxErrorClibSpace:
|
||||
// Standard C/C++ library libspace not available: increase OS_THREAD_LIBSPACE_NUM
|
||||
break;
|
||||
case osRtxErrorClibMutex:
|
||||
// Standard C/C++ library mutex initialization failed
|
||||
break;
|
||||
default:
|
||||
// Reserved
|
||||
break;
|
||||
}
|
||||
for (;;) {}
|
||||
//return 0U;
|
||||
}
|
||||
@@ -0,0 +1,580 @@
|
||||
/*
|
||||
* Copyright (c) 2013-2020 Arm Limited. All rights reserved.
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the License); you may
|
||||
* not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an AS IS BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
* -----------------------------------------------------------------------------
|
||||
*
|
||||
* $Revision: V5.5.1
|
||||
*
|
||||
* Project: CMSIS-RTOS RTX
|
||||
* Title: RTX Configuration definitions
|
||||
*
|
||||
* -----------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
#ifndef RTX_CONFIG_H_
|
||||
#define RTX_CONFIG_H_
|
||||
|
||||
#ifdef _RTE_
|
||||
#include "RTE_Components.h"
|
||||
#ifdef RTE_RTX_CONFIG_H
|
||||
#include RTE_RTX_CONFIG_H
|
||||
#endif
|
||||
#endif
|
||||
|
||||
//-------- <<< Use Configuration Wizard in Context Menu >>> --------------------
|
||||
|
||||
// <h>System Configuration
|
||||
// =======================
|
||||
|
||||
// <o>Global Dynamic Memory size [bytes] <0-1073741824:8>
|
||||
// <i> Defines the combined global dynamic memory size.
|
||||
// <i> Default: 32768
|
||||
#ifndef OS_DYNAMIC_MEM_SIZE
|
||||
#define OS_DYNAMIC_MEM_SIZE 32768
|
||||
#endif
|
||||
|
||||
// <o>Kernel Tick Frequency [Hz] <1-1000000>
|
||||
// <i> Defines base time unit for delays and timeouts.
|
||||
// <i> Default: 1000 (1ms tick)
|
||||
#ifndef OS_TICK_FREQ
|
||||
#define OS_TICK_FREQ 1000
|
||||
#endif
|
||||
|
||||
// <e>Round-Robin Thread switching
|
||||
// <i> Enables Round-Robin Thread switching.
|
||||
#ifndef OS_ROBIN_ENABLE
|
||||
#define OS_ROBIN_ENABLE 1
|
||||
#endif
|
||||
|
||||
// <o>Round-Robin Timeout <1-1000>
|
||||
// <i> Defines how many ticks a thread will execute before a thread switch.
|
||||
// <i> Default: 5
|
||||
#ifndef OS_ROBIN_TIMEOUT
|
||||
#define OS_ROBIN_TIMEOUT 5
|
||||
#endif
|
||||
|
||||
// </e>
|
||||
|
||||
// <o>ISR FIFO Queue
|
||||
// <4=> 4 entries <8=> 8 entries <12=> 12 entries <16=> 16 entries
|
||||
// <24=> 24 entries <32=> 32 entries <48=> 48 entries <64=> 64 entries
|
||||
// <96=> 96 entries <128=> 128 entries <196=> 196 entries <256=> 256 entries
|
||||
// <i> RTOS Functions called from ISR store requests to this buffer.
|
||||
// <i> Default: 16 entries
|
||||
#ifndef OS_ISR_FIFO_QUEUE
|
||||
#define OS_ISR_FIFO_QUEUE 16
|
||||
#endif
|
||||
|
||||
// <q>Object Memory usage counters
|
||||
// <i> Enables object memory usage counters (requires RTX source variant).
|
||||
#ifndef OS_OBJ_MEM_USAGE
|
||||
#define OS_OBJ_MEM_USAGE 0
|
||||
#endif
|
||||
|
||||
// </h>
|
||||
|
||||
// <h>Thread Configuration
|
||||
// =======================
|
||||
|
||||
// <e>Object specific Memory allocation
|
||||
// <i> Enables object specific memory allocation.
|
||||
#ifndef OS_THREAD_OBJ_MEM
|
||||
#define OS_THREAD_OBJ_MEM 0
|
||||
#endif
|
||||
|
||||
// <o>Number of user Threads <1-1000>
|
||||
// <i> Defines maximum number of user threads that can be active at the same time.
|
||||
// <i> Applies to user threads with system provided memory for control blocks.
|
||||
#ifndef OS_THREAD_NUM
|
||||
#define OS_THREAD_NUM 1
|
||||
#endif
|
||||
|
||||
// <o>Number of user Threads with default Stack size <0-1000>
|
||||
// <i> Defines maximum number of user threads with default stack size.
|
||||
// <i> Applies to user threads with zero stack size specified.
|
||||
#ifndef OS_THREAD_DEF_STACK_NUM
|
||||
#define OS_THREAD_DEF_STACK_NUM 0
|
||||
#endif
|
||||
|
||||
// <o>Total Stack size [bytes] for user Threads with user-provided Stack size <0-1073741824:8>
|
||||
// <i> Defines the combined stack size for user threads with user-provided stack size.
|
||||
// <i> Applies to user threads with user-provided stack size and system provided memory for stack.
|
||||
// <i> Default: 0
|
||||
#ifndef OS_THREAD_USER_STACK_SIZE
|
||||
#define OS_THREAD_USER_STACK_SIZE 0
|
||||
#endif
|
||||
|
||||
// </e>
|
||||
|
||||
// <o>Default Thread Stack size [bytes] <96-1073741824:8>
|
||||
// <i> Defines stack size for threads with zero stack size specified.
|
||||
// <i> Default: 3072
|
||||
#ifndef OS_STACK_SIZE
|
||||
#define OS_STACK_SIZE 3072
|
||||
#endif
|
||||
|
||||
// <o>Idle Thread Stack size [bytes] <72-1073741824:8>
|
||||
// <i> Defines stack size for Idle thread.
|
||||
// <i> Default: 512
|
||||
#ifndef OS_IDLE_THREAD_STACK_SIZE
|
||||
#define OS_IDLE_THREAD_STACK_SIZE 512
|
||||
#endif
|
||||
|
||||
// <o>Idle Thread TrustZone Module Identifier
|
||||
// <i> Defines TrustZone Thread Context Management Identifier.
|
||||
// <i> Applies only to cores with TrustZone technology.
|
||||
// <i> Default: 0 (not used)
|
||||
#ifndef OS_IDLE_THREAD_TZ_MOD_ID
|
||||
#define OS_IDLE_THREAD_TZ_MOD_ID 0
|
||||
#endif
|
||||
|
||||
// <q>Stack overrun checking
|
||||
// <i> Enables stack overrun check at thread switch.
|
||||
// <i> Enabling this option increases slightly the execution time of a thread switch.
|
||||
#ifndef OS_STACK_CHECK
|
||||
#define OS_STACK_CHECK 1
|
||||
#endif
|
||||
|
||||
// <q>Stack usage watermark
|
||||
// <i> Initializes thread stack with watermark pattern for analyzing stack usage.
|
||||
// <i> Enabling this option increases significantly the execution time of thread creation.
|
||||
#ifndef OS_STACK_WATERMARK
|
||||
#define OS_STACK_WATERMARK 0
|
||||
#endif
|
||||
|
||||
// <o>Processor mode for Thread execution
|
||||
// <0=> Unprivileged mode
|
||||
// <1=> Privileged mode
|
||||
// <i> Default: Privileged mode
|
||||
#ifndef OS_PRIVILEGE_MODE
|
||||
#define OS_PRIVILEGE_MODE 1
|
||||
#endif
|
||||
|
||||
// </h>
|
||||
|
||||
// <h>Timer Configuration
|
||||
// ======================
|
||||
|
||||
// <e>Object specific Memory allocation
|
||||
// <i> Enables object specific memory allocation.
|
||||
#ifndef OS_TIMER_OBJ_MEM
|
||||
#define OS_TIMER_OBJ_MEM 0
|
||||
#endif
|
||||
|
||||
// <o>Number of Timer objects <1-1000>
|
||||
// <i> Defines maximum number of objects that can be active at the same time.
|
||||
// <i> Applies to objects with system provided memory for control blocks.
|
||||
#ifndef OS_TIMER_NUM
|
||||
#define OS_TIMER_NUM 1
|
||||
#endif
|
||||
|
||||
// </e>
|
||||
|
||||
// <o>Timer Thread Priority
|
||||
// <8=> Low
|
||||
// <16=> Below Normal <24=> Normal <32=> Above Normal
|
||||
// <40=> High
|
||||
// <48=> Realtime
|
||||
// <i> Defines priority for timer thread
|
||||
// <i> Default: High
|
||||
#ifndef OS_TIMER_THREAD_PRIO
|
||||
#define OS_TIMER_THREAD_PRIO 40
|
||||
#endif
|
||||
|
||||
// <o>Timer Thread Stack size [bytes] <0-1073741824:8>
|
||||
// <i> Defines stack size for Timer thread.
|
||||
// <i> May be set to 0 when timers are not used.
|
||||
// <i> Default: 512
|
||||
#ifndef OS_TIMER_THREAD_STACK_SIZE
|
||||
#define OS_TIMER_THREAD_STACK_SIZE 512
|
||||
#endif
|
||||
|
||||
// <o>Timer Thread TrustZone Module Identifier
|
||||
// <i> Defines TrustZone Thread Context Management Identifier.
|
||||
// <i> Applies only to cores with TrustZone technology.
|
||||
// <i> Default: 0 (not used)
|
||||
#ifndef OS_TIMER_THREAD_TZ_MOD_ID
|
||||
#define OS_TIMER_THREAD_TZ_MOD_ID 0
|
||||
#endif
|
||||
|
||||
// <o>Timer Callback Queue entries <0-256>
|
||||
// <i> Number of concurrent active timer callback functions.
|
||||
// <i> May be set to 0 when timers are not used.
|
||||
// <i> Default: 4
|
||||
#ifndef OS_TIMER_CB_QUEUE
|
||||
#define OS_TIMER_CB_QUEUE 4
|
||||
#endif
|
||||
|
||||
// </h>
|
||||
|
||||
// <h>Event Flags Configuration
|
||||
// ============================
|
||||
|
||||
// <e>Object specific Memory allocation
|
||||
// <i> Enables object specific memory allocation.
|
||||
#ifndef OS_EVFLAGS_OBJ_MEM
|
||||
#define OS_EVFLAGS_OBJ_MEM 0
|
||||
#endif
|
||||
|
||||
// <o>Number of Event Flags objects <1-1000>
|
||||
// <i> Defines maximum number of objects that can be active at the same time.
|
||||
// <i> Applies to objects with system provided memory for control blocks.
|
||||
#ifndef OS_EVFLAGS_NUM
|
||||
#define OS_EVFLAGS_NUM 1
|
||||
#endif
|
||||
|
||||
// </e>
|
||||
|
||||
// </h>
|
||||
|
||||
// <h>Mutex Configuration
|
||||
// ======================
|
||||
|
||||
// <e>Object specific Memory allocation
|
||||
// <i> Enables object specific memory allocation.
|
||||
#ifndef OS_MUTEX_OBJ_MEM
|
||||
#define OS_MUTEX_OBJ_MEM 0
|
||||
#endif
|
||||
|
||||
// <o>Number of Mutex objects <1-1000>
|
||||
// <i> Defines maximum number of objects that can be active at the same time.
|
||||
// <i> Applies to objects with system provided memory for control blocks.
|
||||
#ifndef OS_MUTEX_NUM
|
||||
#define OS_MUTEX_NUM 1
|
||||
#endif
|
||||
|
||||
// </e>
|
||||
|
||||
// </h>
|
||||
|
||||
// <h>Semaphore Configuration
|
||||
// ==========================
|
||||
|
||||
// <e>Object specific Memory allocation
|
||||
// <i> Enables object specific memory allocation.
|
||||
#ifndef OS_SEMAPHORE_OBJ_MEM
|
||||
#define OS_SEMAPHORE_OBJ_MEM 0
|
||||
#endif
|
||||
|
||||
// <o>Number of Semaphore objects <1-1000>
|
||||
// <i> Defines maximum number of objects that can be active at the same time.
|
||||
// <i> Applies to objects with system provided memory for control blocks.
|
||||
#ifndef OS_SEMAPHORE_NUM
|
||||
#define OS_SEMAPHORE_NUM 1
|
||||
#endif
|
||||
|
||||
// </e>
|
||||
|
||||
// </h>
|
||||
|
||||
// <h>Memory Pool Configuration
|
||||
// ============================
|
||||
|
||||
// <e>Object specific Memory allocation
|
||||
// <i> Enables object specific memory allocation.
|
||||
#ifndef OS_MEMPOOL_OBJ_MEM
|
||||
#define OS_MEMPOOL_OBJ_MEM 0
|
||||
#endif
|
||||
|
||||
// <o>Number of Memory Pool objects <1-1000>
|
||||
// <i> Defines maximum number of objects that can be active at the same time.
|
||||
// <i> Applies to objects with system provided memory for control blocks.
|
||||
#ifndef OS_MEMPOOL_NUM
|
||||
#define OS_MEMPOOL_NUM 1
|
||||
#endif
|
||||
|
||||
// <o>Data Storage Memory size [bytes] <0-1073741824:8>
|
||||
// <i> Defines the combined data storage memory size.
|
||||
// <i> Applies to objects with system provided memory for data storage.
|
||||
// <i> Default: 0
|
||||
#ifndef OS_MEMPOOL_DATA_SIZE
|
||||
#define OS_MEMPOOL_DATA_SIZE 0
|
||||
#endif
|
||||
|
||||
// </e>
|
||||
|
||||
// </h>
|
||||
|
||||
// <h>Message Queue Configuration
|
||||
// ==============================
|
||||
|
||||
// <e>Object specific Memory allocation
|
||||
// <i> Enables object specific memory allocation.
|
||||
#ifndef OS_MSGQUEUE_OBJ_MEM
|
||||
#define OS_MSGQUEUE_OBJ_MEM 0
|
||||
#endif
|
||||
|
||||
// <o>Number of Message Queue objects <1-1000>
|
||||
// <i> Defines maximum number of objects that can be active at the same time.
|
||||
// <i> Applies to objects with system provided memory for control blocks.
|
||||
#ifndef OS_MSGQUEUE_NUM
|
||||
#define OS_MSGQUEUE_NUM 1
|
||||
#endif
|
||||
|
||||
// <o>Data Storage Memory size [bytes] <0-1073741824:8>
|
||||
// <i> Defines the combined data storage memory size.
|
||||
// <i> Applies to objects with system provided memory for data storage.
|
||||
// <i> Default: 0
|
||||
#ifndef OS_MSGQUEUE_DATA_SIZE
|
||||
#define OS_MSGQUEUE_DATA_SIZE 0
|
||||
#endif
|
||||
|
||||
// </e>
|
||||
|
||||
// </h>
|
||||
|
||||
// <h>Event Recorder Configuration
|
||||
// ===============================
|
||||
|
||||
// <e>Global Initialization
|
||||
// <i> Initialize Event Recorder during 'osKernelInitialize'.
|
||||
#ifndef OS_EVR_INIT
|
||||
#define OS_EVR_INIT 0
|
||||
#endif
|
||||
|
||||
// <q>Start recording
|
||||
// <i> Start event recording after initialization.
|
||||
#ifndef OS_EVR_START
|
||||
#define OS_EVR_START 1
|
||||
#endif
|
||||
|
||||
// <h>Global Event Filter Setup
|
||||
// <i> Initial recording level applied to all components.
|
||||
// <o.0>Error events
|
||||
// <o.1>API function call events
|
||||
// <o.2>Operation events
|
||||
// <o.3>Detailed operation events
|
||||
// </h>
|
||||
#ifndef OS_EVR_LEVEL
|
||||
#define OS_EVR_LEVEL 0x00U
|
||||
#endif
|
||||
|
||||
// <h>RTOS Event Filter Setup
|
||||
// <i> Recording levels for RTX components.
|
||||
// <i> Only applicable if events for the respective component are generated.
|
||||
|
||||
// <h>Memory Management
|
||||
// <i> Recording level for Memory Management events.
|
||||
// <o.0>Error events
|
||||
// <o.1>API function call events
|
||||
// <o.2>Operation events
|
||||
// <o.3>Detailed operation events
|
||||
// </h>
|
||||
#ifndef OS_EVR_MEMORY_LEVEL
|
||||
#define OS_EVR_MEMORY_LEVEL 0x01U
|
||||
#endif
|
||||
|
||||
// <h>Kernel
|
||||
// <i> Recording level for Kernel events.
|
||||
// <o.0>Error events
|
||||
// <o.1>API function call events
|
||||
// <o.2>Operation events
|
||||
// <o.3>Detailed operation events
|
||||
// </h>
|
||||
#ifndef OS_EVR_KERNEL_LEVEL
|
||||
#define OS_EVR_KERNEL_LEVEL 0x01U
|
||||
#endif
|
||||
|
||||
// <h>Thread
|
||||
// <i> Recording level for Thread events.
|
||||
// <o.0>Error events
|
||||
// <o.1>API function call events
|
||||
// <o.2>Operation events
|
||||
// <o.3>Detailed operation events
|
||||
// </h>
|
||||
#ifndef OS_EVR_THREAD_LEVEL
|
||||
#define OS_EVR_THREAD_LEVEL 0x05U
|
||||
#endif
|
||||
|
||||
// <h>Generic Wait
|
||||
// <i> Recording level for Generic Wait events.
|
||||
// <o.0>Error events
|
||||
// <o.1>API function call events
|
||||
// <o.2>Operation events
|
||||
// <o.3>Detailed operation events
|
||||
// </h>
|
||||
#ifndef OS_EVR_WAIT_LEVEL
|
||||
#define OS_EVR_WAIT_LEVEL 0x01U
|
||||
#endif
|
||||
|
||||
// <h>Thread Flags
|
||||
// <i> Recording level for Thread Flags events.
|
||||
// <o.0>Error events
|
||||
// <o.1>API function call events
|
||||
// <o.2>Operation events
|
||||
// <o.3>Detailed operation events
|
||||
// </h>
|
||||
#ifndef OS_EVR_THFLAGS_LEVEL
|
||||
#define OS_EVR_THFLAGS_LEVEL 0x01U
|
||||
#endif
|
||||
|
||||
// <h>Event Flags
|
||||
// <i> Recording level for Event Flags events.
|
||||
// <o.0>Error events
|
||||
// <o.1>API function call events
|
||||
// <o.2>Operation events
|
||||
// <o.3>Detailed operation events
|
||||
// </h>
|
||||
#ifndef OS_EVR_EVFLAGS_LEVEL
|
||||
#define OS_EVR_EVFLAGS_LEVEL 0x01U
|
||||
#endif
|
||||
|
||||
// <h>Timer
|
||||
// <i> Recording level for Timer events.
|
||||
// <o.0>Error events
|
||||
// <o.1>API function call events
|
||||
// <o.2>Operation events
|
||||
// <o.3>Detailed operation events
|
||||
// </h>
|
||||
#ifndef OS_EVR_TIMER_LEVEL
|
||||
#define OS_EVR_TIMER_LEVEL 0x01U
|
||||
#endif
|
||||
|
||||
// <h>Mutex
|
||||
// <i> Recording level for Mutex events.
|
||||
// <o.0>Error events
|
||||
// <o.1>API function call events
|
||||
// <o.2>Operation events
|
||||
// <o.3>Detailed operation events
|
||||
// </h>
|
||||
#ifndef OS_EVR_MUTEX_LEVEL
|
||||
#define OS_EVR_MUTEX_LEVEL 0x01U
|
||||
#endif
|
||||
|
||||
// <h>Semaphore
|
||||
// <i> Recording level for Semaphore events.
|
||||
// <o.0>Error events
|
||||
// <o.1>API function call events
|
||||
// <o.2>Operation events
|
||||
// <o.3>Detailed operation events
|
||||
// </h>
|
||||
#ifndef OS_EVR_SEMAPHORE_LEVEL
|
||||
#define OS_EVR_SEMAPHORE_LEVEL 0x01U
|
||||
#endif
|
||||
|
||||
// <h>Memory Pool
|
||||
// <i> Recording level for Memory Pool events.
|
||||
// <o.0>Error events
|
||||
// <o.1>API function call events
|
||||
// <o.2>Operation events
|
||||
// <o.3>Detailed operation events
|
||||
// </h>
|
||||
#ifndef OS_EVR_MEMPOOL_LEVEL
|
||||
#define OS_EVR_MEMPOOL_LEVEL 0x01U
|
||||
#endif
|
||||
|
||||
// <h>Message Queue
|
||||
// <i> Recording level for Message Queue events.
|
||||
// <o.0>Error events
|
||||
// <o.1>API function call events
|
||||
// <o.2>Operation events
|
||||
// <o.3>Detailed operation events
|
||||
// </h>
|
||||
#ifndef OS_EVR_MSGQUEUE_LEVEL
|
||||
#define OS_EVR_MSGQUEUE_LEVEL 0x01U
|
||||
#endif
|
||||
|
||||
// </h>
|
||||
|
||||
// </e>
|
||||
|
||||
// <h>RTOS Event Generation
|
||||
// <i> Enables event generation for RTX components (requires RTX source variant).
|
||||
|
||||
// <q>Memory Management
|
||||
// <i> Enables Memory Management event generation.
|
||||
#ifndef OS_EVR_MEMORY
|
||||
#define OS_EVR_MEMORY 1
|
||||
#endif
|
||||
|
||||
// <q>Kernel
|
||||
// <i> Enables Kernel event generation.
|
||||
#ifndef OS_EVR_KERNEL
|
||||
#define OS_EVR_KERNEL 1
|
||||
#endif
|
||||
|
||||
// <q>Thread
|
||||
// <i> Enables Thread event generation.
|
||||
#ifndef OS_EVR_THREAD
|
||||
#define OS_EVR_THREAD 1
|
||||
#endif
|
||||
|
||||
// <q>Generic Wait
|
||||
// <i> Enables Generic Wait event generation.
|
||||
#ifndef OS_EVR_WAIT
|
||||
#define OS_EVR_WAIT 1
|
||||
#endif
|
||||
|
||||
// <q>Thread Flags
|
||||
// <i> Enables Thread Flags event generation.
|
||||
#ifndef OS_EVR_THFLAGS
|
||||
#define OS_EVR_THFLAGS 1
|
||||
#endif
|
||||
|
||||
// <q>Event Flags
|
||||
// <i> Enables Event Flags event generation.
|
||||
#ifndef OS_EVR_EVFLAGS
|
||||
#define OS_EVR_EVFLAGS 1
|
||||
#endif
|
||||
|
||||
// <q>Timer
|
||||
// <i> Enables Timer event generation.
|
||||
#ifndef OS_EVR_TIMER
|
||||
#define OS_EVR_TIMER 1
|
||||
#endif
|
||||
|
||||
// <q>Mutex
|
||||
// <i> Enables Mutex event generation.
|
||||
#ifndef OS_EVR_MUTEX
|
||||
#define OS_EVR_MUTEX 1
|
||||
#endif
|
||||
|
||||
// <q>Semaphore
|
||||
// <i> Enables Semaphore event generation.
|
||||
#ifndef OS_EVR_SEMAPHORE
|
||||
#define OS_EVR_SEMAPHORE 1
|
||||
#endif
|
||||
|
||||
// <q>Memory Pool
|
||||
// <i> Enables Memory Pool event generation.
|
||||
#ifndef OS_EVR_MEMPOOL
|
||||
#define OS_EVR_MEMPOOL 1
|
||||
#endif
|
||||
|
||||
// <q>Message Queue
|
||||
// <i> Enables Message Queue event generation.
|
||||
#ifndef OS_EVR_MSGQUEUE
|
||||
#define OS_EVR_MSGQUEUE 1
|
||||
#endif
|
||||
|
||||
// </h>
|
||||
|
||||
// </h>
|
||||
|
||||
// Number of Threads which use standard C/C++ library libspace
|
||||
// (when thread specific memory allocation is not used).
|
||||
#if (OS_THREAD_OBJ_MEM == 0)
|
||||
#ifndef OS_THREAD_LIBSPACE_NUM
|
||||
#define OS_THREAD_LIBSPACE_NUM 4
|
||||
#endif
|
||||
#else
|
||||
#define OS_THREAD_LIBSPACE_NUM OS_THREAD_NUM
|
||||
#endif
|
||||
|
||||
//------------- <<< end of configuration section >>> ---------------------------
|
||||
|
||||
#endif // RTX_CONFIG_H_
|
||||
@@ -0,0 +1,158 @@
|
||||
/*
|
||||
* Copyright (c) 2013-2018 Arm Limited. All rights reserved.
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the License); you may
|
||||
* not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an AS IS BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
* -----------------------------------------------------------------------------
|
||||
*
|
||||
* Project: CMSIS-RTOS RTX
|
||||
* Title: Exception handlers (C functions)
|
||||
*
|
||||
* -----------------------------------------------------------------------------
|
||||
*/
|
||||
#include "RTE_Components.h"
|
||||
#include CMSIS_device_header
|
||||
|
||||
|
||||
//Fault Status Register (IFSR/DFSR) definitions
|
||||
#define FSR_ALIGNMENT_FAULT 0x01 //DFSR only. Fault on first lookup
|
||||
#define FSR_INSTRUCTION_CACHE_MAINTENANCE 0x04 //DFSR only - async/external
|
||||
#define FSR_SYNC_EXT_TTB_WALK_FIRST 0x0c //sync/external
|
||||
#define FSR_SYNC_EXT_TTB_WALK_SECOND 0x0e //sync/external
|
||||
#define FSR_SYNC_PARITY_TTB_WALK_FIRST 0x1c //sync/external
|
||||
#define FSR_SYNC_PARITY_TTB_WALK_SECOND 0x1e //sync/external
|
||||
#define FSR_TRANSLATION_FAULT_FIRST 0x05 //MMU Fault - internal
|
||||
#define FSR_TRANSLATION_FAULT_SECOND 0x07 //MMU Fault - internal
|
||||
#define FSR_ACCESS_FLAG_FAULT_FIRST 0x03 //MMU Fault - internal
|
||||
#define FSR_ACCESS_FLAG_FAULT_SECOND 0x06 //MMU Fault - internal
|
||||
#define FSR_DOMAIN_FAULT_FIRST 0x09 //MMU Fault - internal
|
||||
#define FSR_DOMAIN_FAULT_SECOND 0x0b //MMU Fault - internal
|
||||
#define FSR_PERMISSION_FAULT_FIRST 0x0f //MMU Fault - internal
|
||||
#define FSR_PERMISSION_FAULT_SECOND 0x0d //MMU Fault - internal
|
||||
#define FSR_DEBUG_EVENT 0x02 //internal
|
||||
#define FSR_SYNC_EXT_ABORT 0x08 //sync/external
|
||||
#define FSR_TLB_CONFLICT_ABORT 0x10 //sync/external
|
||||
#define FSR_LOCKDOWN 0x14 //internal
|
||||
#define FSR_COPROCESSOR_ABORT 0x1a //internal
|
||||
#define FSR_SYNC_PARITY_ERROR 0x19 //sync/external
|
||||
#define FSR_ASYNC_EXTERNAL_ABORT 0x16 //DFSR only - async/external
|
||||
#define FSR_ASYNC_PARITY_ERROR 0x18 //DFSR only - async/external
|
||||
|
||||
void CDAbtHandler(uint32_t DFSR, uint32_t DFAR, uint32_t LR) {
|
||||
uint32_t FS = (DFSR & (1U << 10U)) >> 6U | (DFSR & 0x0FU); //Store Fault Status
|
||||
(void)DFAR;
|
||||
(void)LR;
|
||||
|
||||
switch(FS) {
|
||||
//Synchronous parity errors - retry
|
||||
case FSR_SYNC_PARITY_ERROR:
|
||||
case FSR_SYNC_PARITY_TTB_WALK_FIRST:
|
||||
case FSR_SYNC_PARITY_TTB_WALK_SECOND:
|
||||
return;
|
||||
|
||||
//Your code here. Value in DFAR is invalid for some fault statuses.
|
||||
case FSR_ALIGNMENT_FAULT:
|
||||
case FSR_INSTRUCTION_CACHE_MAINTENANCE:
|
||||
case FSR_SYNC_EXT_TTB_WALK_FIRST:
|
||||
case FSR_SYNC_EXT_TTB_WALK_SECOND:
|
||||
case FSR_TRANSLATION_FAULT_FIRST:
|
||||
case FSR_TRANSLATION_FAULT_SECOND:
|
||||
case FSR_ACCESS_FLAG_FAULT_FIRST:
|
||||
case FSR_ACCESS_FLAG_FAULT_SECOND:
|
||||
case FSR_DOMAIN_FAULT_FIRST:
|
||||
case FSR_DOMAIN_FAULT_SECOND:
|
||||
case FSR_PERMISSION_FAULT_FIRST:
|
||||
case FSR_PERMISSION_FAULT_SECOND:
|
||||
case FSR_DEBUG_EVENT:
|
||||
case FSR_SYNC_EXT_ABORT:
|
||||
case FSR_TLB_CONFLICT_ABORT:
|
||||
case FSR_LOCKDOWN:
|
||||
case FSR_COPROCESSOR_ABORT:
|
||||
case FSR_ASYNC_EXTERNAL_ABORT: //DFAR invalid
|
||||
case FSR_ASYNC_PARITY_ERROR: //DFAR invalid
|
||||
default:
|
||||
while(1);
|
||||
}
|
||||
}
|
||||
|
||||
void CPAbtHandler(uint32_t IFSR, uint32_t IFAR, uint32_t LR) {
|
||||
uint32_t FS = (IFSR & (1U << 10U)) >> 6U | (IFSR & 0x0FU); //Store Fault Status
|
||||
(void)IFAR;
|
||||
(void)LR;
|
||||
|
||||
switch(FS) {
|
||||
//Synchronous parity errors - retry
|
||||
case FSR_SYNC_PARITY_ERROR:
|
||||
case FSR_SYNC_PARITY_TTB_WALK_FIRST:
|
||||
case FSR_SYNC_PARITY_TTB_WALK_SECOND:
|
||||
return;
|
||||
|
||||
//Your code here. Value in IFAR is invalid for some fault statuses.
|
||||
case FSR_SYNC_EXT_TTB_WALK_FIRST:
|
||||
case FSR_SYNC_EXT_TTB_WALK_SECOND:
|
||||
case FSR_TRANSLATION_FAULT_FIRST:
|
||||
case FSR_TRANSLATION_FAULT_SECOND:
|
||||
case FSR_ACCESS_FLAG_FAULT_FIRST:
|
||||
case FSR_ACCESS_FLAG_FAULT_SECOND:
|
||||
case FSR_DOMAIN_FAULT_FIRST:
|
||||
case FSR_DOMAIN_FAULT_SECOND:
|
||||
case FSR_PERMISSION_FAULT_FIRST:
|
||||
case FSR_PERMISSION_FAULT_SECOND:
|
||||
case FSR_DEBUG_EVENT: //IFAR invalid
|
||||
case FSR_SYNC_EXT_ABORT:
|
||||
case FSR_TLB_CONFLICT_ABORT:
|
||||
case FSR_LOCKDOWN:
|
||||
case FSR_COPROCESSOR_ABORT:
|
||||
default:
|
||||
while(1);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//returns amount to decrement lr by
|
||||
//this will be 0 when we have emulated the instruction and want to execute the next instruction
|
||||
//this will be 2 when we have performed some maintenance and want to retry the instruction in Thumb (state == 2)
|
||||
//this will be 4 when we have performed some maintenance and want to retry the instruction in Arm (state == 4)
|
||||
uint32_t CUndefHandler(uint32_t opcode, uint32_t state, uint32_t LR) {
|
||||
const uint32_t THUMB = 2U;
|
||||
const uint32_t ARM = 4U;
|
||||
(void)LR;
|
||||
//Lazy VFP/NEON initialisation and switching
|
||||
|
||||
// (Arm Architecture Reference Manual section A7.5) VFP data processing instruction?
|
||||
// (Arm Architecture Reference Manual section A7.6) VFP/NEON register load/store instruction?
|
||||
// (Arm Architecture Reference Manual section A7.8) VFP/NEON register data transfer instruction?
|
||||
// (Arm Architecture Reference Manual section A7.9) VFP/NEON 64-bit register data transfer instruction?
|
||||
if ((state == ARM && ((opcode & 0x0C000000U) >> 26U == 0x03U)) ||
|
||||
(state == THUMB && ((opcode & 0xEC000000U) >> 26U == 0x3BU))) {
|
||||
if (((opcode & 0x00000E00U) >> 9U) == 5U) {
|
||||
__FPU_Enable();
|
||||
return state;
|
||||
}
|
||||
}
|
||||
|
||||
// (Arm Architecture Reference Manual section A7.4) NEON data processing instruction?
|
||||
if ((state == ARM && ((opcode & 0xFE000000U) >> 24U == 0xF2U)) ||
|
||||
(state == THUMB && ((opcode & 0xEF000000U) >> 24U == 0xEFU)) ||
|
||||
// (Arm Architecture Reference Manual section A7.7) NEON load/store instruction?
|
||||
(state == ARM && ((opcode >> 24U) == 0xF4U)) ||
|
||||
(state == THUMB && ((opcode >> 24U) == 0xF9U))) {
|
||||
__FPU_Enable();
|
||||
return state;
|
||||
}
|
||||
|
||||
//Add code here for other Undef cases
|
||||
while(1);
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,472 @@
|
||||
/*
|
||||
* Copyright (c) 2013-2019 Arm Limited. All rights reserved.
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the License); you may
|
||||
* not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an AS IS BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
* -----------------------------------------------------------------------------
|
||||
*
|
||||
* Project: CMSIS-RTOS RTX
|
||||
* Title: RTX OS definitions
|
||||
*
|
||||
* -----------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
#ifndef RTX_OS_H_
|
||||
#define RTX_OS_H_
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
#include "cmsis_os2.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C"
|
||||
{
|
||||
#endif
|
||||
|
||||
|
||||
/// Kernel Information
|
||||
#define osRtxVersionAPI 20010003 ///< API version (2.1.3)
|
||||
#define osRtxVersionKernel 50050002 ///< Kernel version (5.5.2)
|
||||
#define osRtxKernelId "RTX V5.5.2" ///< Kernel identification string
|
||||
|
||||
|
||||
// ==== Common definitions ====
|
||||
|
||||
/// Object Identifier definitions
|
||||
#define osRtxIdInvalid 0x00U
|
||||
#define osRtxIdThread 0xF1U
|
||||
#define osRtxIdTimer 0xF2U
|
||||
#define osRtxIdEventFlags 0xF3U
|
||||
#define osRtxIdMutex 0xF5U
|
||||
#define osRtxIdSemaphore 0xF6U
|
||||
#define osRtxIdMemoryPool 0xF7U
|
||||
#define osRtxIdMessage 0xF9U
|
||||
#define osRtxIdMessageQueue 0xFAU
|
||||
|
||||
/// Object Flags definitions
|
||||
#define osRtxFlagSystemObject 0x01U
|
||||
#define osRtxFlagSystemMemory 0x02U
|
||||
|
||||
|
||||
// ==== Kernel definitions ====
|
||||
|
||||
/// Kernel State definitions
|
||||
#define osRtxKernelInactive ((uint8_t)osKernelInactive)
|
||||
#define osRtxKernelReady ((uint8_t)osKernelReady)
|
||||
#define osRtxKernelRunning ((uint8_t)osKernelRunning)
|
||||
#define osRtxKernelLocked ((uint8_t)osKernelLocked)
|
||||
#define osRtxKernelSuspended ((uint8_t)osKernelSuspended)
|
||||
|
||||
|
||||
// ==== Thread definitions ====
|
||||
|
||||
/// Thread State definitions (extending osThreadState)
|
||||
#define osRtxThreadStateMask 0x0FU
|
||||
|
||||
#define osRtxThreadInactive ((uint8_t)osThreadInactive)
|
||||
#define osRtxThreadReady ((uint8_t)osThreadReady)
|
||||
#define osRtxThreadRunning ((uint8_t)osThreadRunning)
|
||||
#define osRtxThreadBlocked ((uint8_t)osThreadBlocked)
|
||||
#define osRtxThreadTerminated ((uint8_t)osThreadTerminated)
|
||||
|
||||
#define osRtxThreadWaitingDelay ((uint8_t)(osRtxThreadBlocked | 0x10U))
|
||||
#define osRtxThreadWaitingJoin ((uint8_t)(osRtxThreadBlocked | 0x20U))
|
||||
#define osRtxThreadWaitingThreadFlags ((uint8_t)(osRtxThreadBlocked | 0x30U))
|
||||
#define osRtxThreadWaitingEventFlags ((uint8_t)(osRtxThreadBlocked | 0x40U))
|
||||
#define osRtxThreadWaitingMutex ((uint8_t)(osRtxThreadBlocked | 0x50U))
|
||||
#define osRtxThreadWaitingSemaphore ((uint8_t)(osRtxThreadBlocked | 0x60U))
|
||||
#define osRtxThreadWaitingMemoryPool ((uint8_t)(osRtxThreadBlocked | 0x70U))
|
||||
#define osRtxThreadWaitingMessageGet ((uint8_t)(osRtxThreadBlocked | 0x80U))
|
||||
#define osRtxThreadWaitingMessagePut ((uint8_t)(osRtxThreadBlocked | 0x90U))
|
||||
|
||||
/// Thread Flags definitions
|
||||
#define osRtxThreadFlagDefStack 0x10U ///< Default Stack flag
|
||||
|
||||
/// Stack Marker definitions
|
||||
#define osRtxStackMagicWord 0xE25A2EA5U ///< Stack Magic Word (Stack Base)
|
||||
#define osRtxStackFillPattern 0xCCCCCCCCU ///< Stack Fill Pattern
|
||||
|
||||
/// Thread Control Block
|
||||
typedef struct osRtxThread_s {
|
||||
uint8_t id; ///< Object Identifier
|
||||
uint8_t state; ///< Object State
|
||||
uint8_t flags; ///< Object Flags
|
||||
uint8_t attr; ///< Object Attributes
|
||||
const char *name; ///< Object Name
|
||||
struct osRtxThread_s *thread_next; ///< Link pointer to next Thread in Object list
|
||||
struct osRtxThread_s *thread_prev; ///< Link pointer to previous Thread in Object list
|
||||
struct osRtxThread_s *delay_next; ///< Link pointer to next Thread in Delay list
|
||||
struct osRtxThread_s *delay_prev; ///< Link pointer to previous Thread in Delay list
|
||||
struct osRtxThread_s *thread_join; ///< Thread waiting to Join
|
||||
uint32_t delay; ///< Delay Time
|
||||
int8_t priority; ///< Thread Priority
|
||||
int8_t priority_base; ///< Base Priority
|
||||
uint8_t stack_frame; ///< Stack Frame (EXC_RETURN[7..0])
|
||||
uint8_t flags_options; ///< Thread/Event Flags Options
|
||||
uint32_t wait_flags; ///< Waiting Thread/Event Flags
|
||||
uint32_t thread_flags; ///< Thread Flags
|
||||
struct osRtxMutex_s *mutex_list; ///< Link pointer to list of owned Mutexes
|
||||
void *stack_mem; ///< Stack Memory
|
||||
uint32_t stack_size; ///< Stack Size
|
||||
uint32_t sp; ///< Current Stack Pointer
|
||||
uint32_t thread_addr; ///< Thread entry address
|
||||
uint32_t tz_memory; ///< TrustZone Memory Identifier
|
||||
#ifdef RTX_TF_M_EXTENSION
|
||||
uint32_t tz_module; ///< TrustZone Module Identifier
|
||||
#endif
|
||||
} osRtxThread_t;
|
||||
|
||||
|
||||
// ==== Timer definitions ====
|
||||
|
||||
/// Timer State definitions
|
||||
#define osRtxTimerInactive 0x00U ///< Timer Inactive
|
||||
#define osRtxTimerStopped 0x01U ///< Timer Stopped
|
||||
#define osRtxTimerRunning 0x02U ///< Timer Running
|
||||
|
||||
/// Timer Type definitions
|
||||
#define osRtxTimerPeriodic ((uint8_t)osTimerPeriodic)
|
||||
|
||||
/// Timer Function Information
|
||||
typedef struct {
|
||||
osTimerFunc_t func; ///< Function Pointer
|
||||
void *arg; ///< Function Argument
|
||||
} osRtxTimerFinfo_t;
|
||||
|
||||
/// Timer Control Block
|
||||
typedef struct osRtxTimer_s {
|
||||
uint8_t id; ///< Object Identifier
|
||||
uint8_t state; ///< Object State
|
||||
uint8_t flags; ///< Object Flags
|
||||
uint8_t type; ///< Timer Type (Periodic/One-shot)
|
||||
const char *name; ///< Object Name
|
||||
struct osRtxTimer_s *prev; ///< Pointer to previous active Timer
|
||||
struct osRtxTimer_s *next; ///< Pointer to next active Timer
|
||||
uint32_t tick; ///< Timer current Tick
|
||||
uint32_t load; ///< Timer Load value
|
||||
osRtxTimerFinfo_t finfo; ///< Timer Function Info
|
||||
} osRtxTimer_t;
|
||||
|
||||
|
||||
// ==== Event Flags definitions ====
|
||||
|
||||
/// Event Flags Control Block
|
||||
typedef struct {
|
||||
uint8_t id; ///< Object Identifier
|
||||
uint8_t reserved_state; ///< Object State (not used)
|
||||
uint8_t flags; ///< Object Flags
|
||||
uint8_t reserved;
|
||||
const char *name; ///< Object Name
|
||||
osRtxThread_t *thread_list; ///< Waiting Threads List
|
||||
uint32_t event_flags; ///< Event Flags
|
||||
} osRtxEventFlags_t;
|
||||
|
||||
|
||||
// ==== Mutex definitions ====
|
||||
|
||||
/// Mutex Control Block
|
||||
typedef struct osRtxMutex_s {
|
||||
uint8_t id; ///< Object Identifier
|
||||
uint8_t reserved_state; ///< Object State (not used)
|
||||
uint8_t flags; ///< Object Flags
|
||||
uint8_t attr; ///< Object Attributes
|
||||
const char *name; ///< Object Name
|
||||
osRtxThread_t *thread_list; ///< Waiting Threads List
|
||||
osRtxThread_t *owner_thread; ///< Owner Thread
|
||||
struct osRtxMutex_s *owner_prev; ///< Pointer to previous owned Mutex
|
||||
struct osRtxMutex_s *owner_next; ///< Pointer to next owned Mutex
|
||||
uint8_t lock; ///< Lock counter
|
||||
uint8_t padding[3];
|
||||
} osRtxMutex_t;
|
||||
|
||||
|
||||
// ==== Semaphore definitions ====
|
||||
|
||||
/// Semaphore Control Block
|
||||
typedef struct {
|
||||
uint8_t id; ///< Object Identifier
|
||||
uint8_t reserved_state; ///< Object State (not used)
|
||||
uint8_t flags; ///< Object Flags
|
||||
uint8_t reserved;
|
||||
const char *name; ///< Object Name
|
||||
osRtxThread_t *thread_list; ///< Waiting Threads List
|
||||
uint16_t tokens; ///< Current number of tokens
|
||||
uint16_t max_tokens; ///< Maximum number of tokens
|
||||
} osRtxSemaphore_t;
|
||||
|
||||
|
||||
// ==== Memory Pool definitions ====
|
||||
|
||||
/// Memory Pool Information
|
||||
typedef struct {
|
||||
uint32_t max_blocks; ///< Maximum number of Blocks
|
||||
uint32_t used_blocks; ///< Number of used Blocks
|
||||
uint32_t block_size; ///< Block Size
|
||||
void *block_base; ///< Block Memory Base Address
|
||||
void *block_lim; ///< Block Memory Limit Address
|
||||
void *block_free; ///< First free Block Address
|
||||
} osRtxMpInfo_t;
|
||||
|
||||
/// Memory Pool Control Block
|
||||
typedef struct {
|
||||
uint8_t id; ///< Object Identifier
|
||||
uint8_t reserved_state; ///< Object State (not used)
|
||||
uint8_t flags; ///< Object Flags
|
||||
uint8_t reserved;
|
||||
const char *name; ///< Object Name
|
||||
osRtxThread_t *thread_list; ///< Waiting Threads List
|
||||
osRtxMpInfo_t mp_info; ///< Memory Pool Info
|
||||
} osRtxMemoryPool_t;
|
||||
|
||||
|
||||
// ==== Message Queue definitions ====
|
||||
|
||||
/// Message Control Block
|
||||
typedef struct osRtxMessage_s {
|
||||
uint8_t id; ///< Object Identifier
|
||||
uint8_t reserved_state; ///< Object State (not used)
|
||||
uint8_t flags; ///< Object Flags
|
||||
uint8_t priority; ///< Message Priority
|
||||
struct osRtxMessage_s *prev; ///< Pointer to previous Message
|
||||
struct osRtxMessage_s *next; ///< Pointer to next Message
|
||||
} osRtxMessage_t;
|
||||
|
||||
/// Message Queue Control Block
|
||||
typedef struct {
|
||||
uint8_t id; ///< Object Identifier
|
||||
uint8_t reserved_state; ///< Object State (not used)
|
||||
uint8_t flags; ///< Object Flags
|
||||
uint8_t reserved;
|
||||
const char *name; ///< Object Name
|
||||
osRtxThread_t *thread_list; ///< Waiting Threads List
|
||||
osRtxMpInfo_t mp_info; ///< Memory Pool Info
|
||||
uint32_t msg_size; ///< Message Size
|
||||
uint32_t msg_count; ///< Number of queued Messages
|
||||
osRtxMessage_t *msg_first; ///< Pointer to first Message
|
||||
osRtxMessage_t *msg_last; ///< Pointer to last Message
|
||||
} osRtxMessageQueue_t;
|
||||
|
||||
|
||||
// ==== Generic Object definitions ====
|
||||
|
||||
/// Generic Object Control Block
|
||||
typedef struct {
|
||||
uint8_t id; ///< Object Identifier
|
||||
uint8_t state; ///< Object State
|
||||
uint8_t flags; ///< Object Flags
|
||||
uint8_t reserved;
|
||||
const char *name; ///< Object Name
|
||||
osRtxThread_t *thread_list; ///< Threads List
|
||||
} osRtxObject_t;
|
||||
|
||||
|
||||
// ==== OS Runtime Information definitions ====
|
||||
|
||||
/// OS Runtime Information structure
|
||||
typedef struct {
|
||||
const char *os_id; ///< OS Identification
|
||||
uint32_t version; ///< OS Version
|
||||
struct { ///< Kernel Info
|
||||
uint8_t state; ///< State
|
||||
volatile uint8_t blocked; ///< Blocked
|
||||
uint8_t pendSV; ///< Pending SV
|
||||
uint8_t reserved;
|
||||
uint32_t tick; ///< Tick counter
|
||||
} kernel;
|
||||
int32_t tick_irqn; ///< Tick Timer IRQ Number
|
||||
struct { ///< Thread Info
|
||||
struct { ///< Thread Run Info
|
||||
osRtxThread_t *curr; ///< Current running Thread
|
||||
osRtxThread_t *next; ///< Next Thread to Run
|
||||
} run;
|
||||
osRtxObject_t ready; ///< Ready List Object
|
||||
osRtxThread_t *idle; ///< Idle Thread
|
||||
osRtxThread_t *delay_list; ///< Delay List
|
||||
osRtxThread_t *wait_list; ///< Wait List (no Timeout)
|
||||
osRtxThread_t *terminate_list; ///< Terminate Thread List
|
||||
struct { ///< Thread Round Robin Info
|
||||
osRtxThread_t *thread; ///< Round Robin Thread
|
||||
uint32_t tick; ///< Round Robin Time Tick
|
||||
uint32_t timeout; ///< Round Robin Timeout
|
||||
} robin;
|
||||
} thread;
|
||||
struct { ///< Timer Info
|
||||
osRtxTimer_t *list; ///< Active Timer List
|
||||
osRtxThread_t *thread; ///< Timer Thread
|
||||
osRtxMessageQueue_t *mq; ///< Timer Message Queue
|
||||
void (*tick)(void); ///< Timer Tick Function
|
||||
} timer;
|
||||
struct { ///< ISR Post Processing Queue
|
||||
uint16_t max; ///< Maximum Items
|
||||
uint16_t cnt; ///< Item Count
|
||||
uint16_t in; ///< Incoming Item Index
|
||||
uint16_t out; ///< Outgoing Item Index
|
||||
void **data; ///< Queue Data
|
||||
} isr_queue;
|
||||
struct { ///< ISR Post Processing functions
|
||||
void (*thread)(osRtxThread_t*); ///< Thread Post Processing function
|
||||
void (*event_flags)(osRtxEventFlags_t*); ///< Event Flags Post Processing function
|
||||
void (*semaphore)(osRtxSemaphore_t*); ///< Semaphore Post Processing function
|
||||
void (*memory_pool)(osRtxMemoryPool_t*); ///< Memory Pool Post Processing function
|
||||
void (*message)(osRtxMessage_t*); ///< Message Post Processing function
|
||||
} post_process;
|
||||
struct { ///< Memory Pools (Variable Block Size)
|
||||
void *stack; ///< Stack Memory
|
||||
void *mp_data; ///< Memory Pool Data Memory
|
||||
void *mq_data; ///< Message Queue Data Memory
|
||||
void *common; ///< Common Memory
|
||||
} mem;
|
||||
struct { ///< Memory Pools (Fixed Block Size)
|
||||
osRtxMpInfo_t *stack; ///< Stack for Threads
|
||||
osRtxMpInfo_t *thread; ///< Thread Control Blocks
|
||||
osRtxMpInfo_t *timer; ///< Timer Control Blocks
|
||||
osRtxMpInfo_t *event_flags; ///< Event Flags Control Blocks
|
||||
osRtxMpInfo_t *mutex; ///< Mutex Control Blocks
|
||||
osRtxMpInfo_t *semaphore; ///< Semaphore Control Blocks
|
||||
osRtxMpInfo_t *memory_pool; ///< Memory Pool Control Blocks
|
||||
osRtxMpInfo_t *message_queue; ///< Message Queue Control Blocks
|
||||
} mpi;
|
||||
} osRtxInfo_t;
|
||||
|
||||
extern osRtxInfo_t osRtxInfo; ///< OS Runtime Information
|
||||
|
||||
/// OS Runtime Object Memory Usage structure
|
||||
typedef struct {
|
||||
uint32_t cnt_alloc; ///< Counter for alloc
|
||||
uint32_t cnt_free; ///< Counter for free
|
||||
uint32_t max_used; ///< Maximum used
|
||||
} osRtxObjectMemUsage_t;
|
||||
|
||||
/// OS Runtime Object Memory Usage variables
|
||||
extern osRtxObjectMemUsage_t osRtxThreadMemUsage;
|
||||
extern osRtxObjectMemUsage_t osRtxTimerMemUsage;
|
||||
extern osRtxObjectMemUsage_t osRtxEventFlagsMemUsage;
|
||||
extern osRtxObjectMemUsage_t osRtxMutexMemUsage;
|
||||
extern osRtxObjectMemUsage_t osRtxSemaphoreMemUsage;
|
||||
extern osRtxObjectMemUsage_t osRtxMemoryPoolMemUsage;
|
||||
extern osRtxObjectMemUsage_t osRtxMessageQueueMemUsage;
|
||||
|
||||
|
||||
// ==== OS API definitions ====
|
||||
|
||||
// Object Limits definitions
|
||||
#define osRtxThreadFlagsLimit 31U ///< number of Thread Flags available per thread
|
||||
#define osRtxEventFlagsLimit 31U ///< number of Event Flags available per object
|
||||
#define osRtxMutexLockLimit 255U ///< maximum number of recursive mutex locks
|
||||
#define osRtxSemaphoreTokenLimit 65535U ///< maximum number of tokens per semaphore
|
||||
|
||||
// Control Block sizes
|
||||
#define osRtxThreadCbSize sizeof(osRtxThread_t)
|
||||
#define osRtxTimerCbSize sizeof(osRtxTimer_t)
|
||||
#define osRtxEventFlagsCbSize sizeof(osRtxEventFlags_t)
|
||||
#define osRtxMutexCbSize sizeof(osRtxMutex_t)
|
||||
#define osRtxSemaphoreCbSize sizeof(osRtxSemaphore_t)
|
||||
#define osRtxMemoryPoolCbSize sizeof(osRtxMemoryPool_t)
|
||||
#define osRtxMessageQueueCbSize sizeof(osRtxMessageQueue_t)
|
||||
|
||||
/// Memory size in bytes for Memory Pool storage.
|
||||
/// \param block_count maximum number of memory blocks in memory pool.
|
||||
/// \param block_size memory block size in bytes.
|
||||
#define osRtxMemoryPoolMemSize(block_count, block_size) \
|
||||
(4*(block_count)*(((block_size)+3)/4))
|
||||
|
||||
/// Memory size in bytes for Message Queue storage.
|
||||
/// \param msg_count maximum number of messages in queue.
|
||||
/// \param msg_size maximum message size in bytes.
|
||||
#define osRtxMessageQueueMemSize(msg_count, msg_size) \
|
||||
(4*(msg_count)*(3+(((msg_size)+3)/4)))
|
||||
|
||||
|
||||
// ==== OS External Functions ====
|
||||
|
||||
// OS Error Codes
|
||||
#define osRtxErrorStackUnderflow 1U ///< Stack overflow, i.e. stack pointer below its lower memory limit for descending stacks.
|
||||
#define osRtxErrorISRQueueOverflow 2U ///< ISR Queue overflow detected when inserting object.
|
||||
#define osRtxErrorTimerQueueOverflow 3U ///< User Timer Callback Queue overflow detected for timer.
|
||||
#define osRtxErrorClibSpace 4U ///< Standard C/C++ library libspace not available: increase \c OS_THREAD_LIBSPACE_NUM.
|
||||
#define osRtxErrorClibMutex 5U ///< Standard C/C++ library mutex initialization failed.
|
||||
|
||||
/// OS Error Callback function
|
||||
extern uint32_t osRtxErrorNotify (uint32_t code, void *object_id);
|
||||
|
||||
/// OS Idle Thread
|
||||
extern void osRtxIdleThread (void *argument);
|
||||
|
||||
/// OS Exception handlers
|
||||
extern void SVC_Handler (void);
|
||||
extern void PendSV_Handler (void);
|
||||
extern void SysTick_Handler (void);
|
||||
|
||||
/// OS Trusted Firmware M Extension
|
||||
#ifdef RTX_TF_M_EXTENSION
|
||||
extern uint32_t osRtxTzGetModuleId (void);
|
||||
#endif
|
||||
|
||||
|
||||
// ==== OS External Configuration ====
|
||||
|
||||
/// OS Configuration flags
|
||||
#define osRtxConfigPrivilegedMode (1UL<<0) ///< Threads in Privileged mode
|
||||
#define osRtxConfigStackCheck (1UL<<1) ///< Stack overrun checking
|
||||
#define osRtxConfigStackWatermark (1UL<<2) ///< Stack usage Watermark
|
||||
|
||||
/// OS Configuration structure
|
||||
typedef struct {
|
||||
uint32_t flags; ///< OS Configuration Flags
|
||||
uint32_t tick_freq; ///< Kernel Tick Frequency
|
||||
uint32_t robin_timeout; ///< Round Robin Timeout Tick
|
||||
struct { ///< ISR Post Processing Queue
|
||||
void **data; ///< Queue Data
|
||||
uint16_t max; ///< Maximum Items
|
||||
uint16_t padding;
|
||||
} isr_queue;
|
||||
struct { ///< Memory Pools (Variable Block Size)
|
||||
void *stack_addr; ///< Stack Memory Address
|
||||
uint32_t stack_size; ///< Stack Memory Size
|
||||
void *mp_data_addr; ///< Memory Pool Memory Address
|
||||
uint32_t mp_data_size; ///< Memory Pool Memory Size
|
||||
void *mq_data_addr; ///< Message Queue Data Memory Address
|
||||
uint32_t mq_data_size; ///< Message Queue Data Memory Size
|
||||
void *common_addr; ///< Common Memory Address
|
||||
uint32_t common_size; ///< Common Memory Size
|
||||
} mem;
|
||||
struct { ///< Memory Pools (Fixed Block Size)
|
||||
osRtxMpInfo_t *stack; ///< Stack for Threads
|
||||
osRtxMpInfo_t *thread; ///< Thread Control Blocks
|
||||
osRtxMpInfo_t *timer; ///< Timer Control Blocks
|
||||
osRtxMpInfo_t *event_flags; ///< Event Flags Control Blocks
|
||||
osRtxMpInfo_t *mutex; ///< Mutex Control Blocks
|
||||
osRtxMpInfo_t *semaphore; ///< Semaphore Control Blocks
|
||||
osRtxMpInfo_t *memory_pool; ///< Memory Pool Control Blocks
|
||||
osRtxMpInfo_t *message_queue; ///< Message Queue Control Blocks
|
||||
} mpi;
|
||||
uint32_t thread_stack_size; ///< Default Thread Stack Size
|
||||
const
|
||||
osThreadAttr_t *idle_thread_attr; ///< Idle Thread Attributes
|
||||
const
|
||||
osThreadAttr_t *timer_thread_attr; ///< Timer Thread Attributes
|
||||
const
|
||||
osMessageQueueAttr_t *timer_mq_attr; ///< Timer Message Queue Attributes
|
||||
uint32_t timer_mq_mcnt; ///< Timer Message Queue maximum Messages
|
||||
} osRtxConfig_t;
|
||||
|
||||
extern const osRtxConfig_t osRtxConfig; ///< OS Configuration
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif // RTX_OS_H_
|
||||
@@ -0,0 +1,906 @@
|
||||
/*
|
||||
* Copyright (c) 2013-2017 ARM Limited. All rights reserved.
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the License); you may
|
||||
* not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an AS IS BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
* ----------------------------------------------------------------------
|
||||
*
|
||||
* $Date: 30. October 2017
|
||||
* $Revision: V2.1.2
|
||||
*
|
||||
* Project: CMSIS-RTOS API
|
||||
* Title: cmsis_os.h RTX header file
|
||||
*
|
||||
* Version 0.02
|
||||
* Initial Proposal Phase
|
||||
* Version 0.03
|
||||
* osKernelStart added, optional feature: main started as thread
|
||||
* osSemaphores have standard behavior
|
||||
* osTimerCreate does not start the timer, added osTimerStart
|
||||
* osThreadPass is renamed to osThreadYield
|
||||
* Version 1.01
|
||||
* Support for C++ interface
|
||||
* - const attribute removed from the osXxxxDef_t typedefs
|
||||
* - const attribute added to the osXxxxDef macros
|
||||
* Added: osTimerDelete, osMutexDelete, osSemaphoreDelete
|
||||
* Added: osKernelInitialize
|
||||
* Version 1.02
|
||||
* Control functions for short timeouts in microsecond resolution:
|
||||
* Added: osKernelSysTick, osKernelSysTickFrequency, osKernelSysTickMicroSec
|
||||
* Removed: osSignalGet
|
||||
* Version 2.0.0
|
||||
* OS objects creation without macros (dynamic creation and resource allocation):
|
||||
* - added: osXxxxNew functions which replace osXxxxCreate
|
||||
* - added: osXxxxAttr_t structures
|
||||
* - deprecated: osXxxxCreate functions, osXxxxDef_t structures
|
||||
* - deprecated: osXxxxDef and osXxxx macros
|
||||
* osStatus codes simplified and renamed to osStatus_t
|
||||
* osEvent return structure deprecated
|
||||
* Kernel:
|
||||
* - added: osKernelInfo_t and osKernelGetInfo
|
||||
* - added: osKernelState_t and osKernelGetState (replaces osKernelRunning)
|
||||
* - added: osKernelLock, osKernelUnlock
|
||||
* - added: osKernelSuspend, osKernelResume
|
||||
* - added: osKernelGetTickCount, osKernelGetTickFreq
|
||||
* - renamed osKernelSysTick to osKernelGetSysTimerCount
|
||||
* - replaced osKernelSysTickFrequency with osKernelGetSysTimerFreq
|
||||
* - deprecated osKernelSysTickMicroSec
|
||||
* Thread:
|
||||
* - extended number of thread priorities
|
||||
* - renamed osPrioriry to osPrioriry_t
|
||||
* - replaced osThreadCreate with osThreadNew
|
||||
* - added: osThreadGetName
|
||||
* - added: osThreadState_t and osThreadGetState
|
||||
* - added: osThreadGetStackSize, osThreadGetStackSpace
|
||||
* - added: osThreadSuspend, osThreadResume
|
||||
* - added: osThreadJoin, osThreadDetach, osThreadExit
|
||||
* - added: osThreadGetCount, osThreadEnumerate
|
||||
* - added: Thread Flags (moved from Signals)
|
||||
* Signals:
|
||||
* - renamed osSignals to osThreadFlags (moved to Thread Flags)
|
||||
* - changed return value of Set/Clear/Wait functions
|
||||
* - Clear function limited to current running thread
|
||||
* - extended Wait function (options)
|
||||
* - added: osThreadFlagsGet
|
||||
* Event Flags:
|
||||
* - added new independent object for handling Event Flags
|
||||
* Delay and Wait functions:
|
||||
* - added: osDelayUntil
|
||||
* - deprecated: osWait
|
||||
* Timer:
|
||||
* - replaced osTimerCreate with osTimerNew
|
||||
* - added: osTimerGetName, osTimerIsRunning
|
||||
* Mutex:
|
||||
* - extended: attributes (Recursive, Priority Inherit, Robust)
|
||||
* - replaced osMutexCreate with osMutexNew
|
||||
* - renamed osMutexWait to osMutexAcquire
|
||||
* - added: osMutexGetName, osMutexGetOwner
|
||||
* Semaphore:
|
||||
* - extended: maximum and initial token count
|
||||
* - replaced osSemaphoreCreate with osSemaphoreNew
|
||||
* - renamed osSemaphoreWait to osSemaphoreAcquire (changed return value)
|
||||
* - added: osSemaphoreGetName, osSemaphoreGetCount
|
||||
* Memory Pool:
|
||||
* - using osMemoryPool prefix instead of osPool
|
||||
* - replaced osPoolCreate with osMemoryPoolNew
|
||||
* - extended osMemoryPoolAlloc (timeout)
|
||||
* - added: osMemoryPoolGetName
|
||||
* - added: osMemoryPoolGetCapacity, osMemoryPoolGetBlockSize
|
||||
* - added: osMemoryPoolGetCount, osMemoryPoolGetSpace
|
||||
* - added: osMemoryPoolDelete
|
||||
* - deprecated: osPoolCAlloc
|
||||
* Message Queue:
|
||||
* - extended: fixed size message instead of a single 32-bit value
|
||||
* - using osMessageQueue prefix instead of osMessage
|
||||
* - replaced osMessageCreate with osMessageQueueNew
|
||||
* - updated: osMessageQueuePut, osMessageQueueGet
|
||||
* - added: osMessageQueueGetName
|
||||
* - added: osMessageQueueGetCapacity, osMessageQueueGetMsgSize
|
||||
* - added: osMessageQueueGetCount, osMessageQueueGetSpace
|
||||
* - added: osMessageQueueReset, osMessageQueueDelete
|
||||
* Mail Queue:
|
||||
* - deprecated (superseded by extended Message Queue functionality)
|
||||
* Version 2.1.0
|
||||
* Support for critical and uncritical sections (nesting safe):
|
||||
* - updated: osKernelLock, osKernelUnlock
|
||||
* - added: osKernelRestoreLock
|
||||
* Updated Thread and Event Flags:
|
||||
* - changed flags parameter and return type from int32_t to uint32_t
|
||||
* Version 2.1.1
|
||||
* Additional functions allowed to be called from Interrupt Service Routines:
|
||||
* - osKernelGetTickCount, osKernelGetTickFreq
|
||||
* Changed Kernel Tick type to uint32_t:
|
||||
* - updated: osKernelGetTickCount, osDelayUntil
|
||||
* Version 2.1.2
|
||||
* Additional functions allowed to be called from Interrupt Service Routines:
|
||||
* - osKernelGetInfo, osKernelGetState
|
||||
*---------------------------------------------------------------------------*/
|
||||
|
||||
#ifndef CMSIS_OS_H_
|
||||
#define CMSIS_OS_H_
|
||||
|
||||
#define osCMSIS 0x20001U ///< API version (main[31:16].sub[15:0])
|
||||
|
||||
#define osCMSIS_RTX 0x50003U ///< RTOS identification and version (main[31:16].sub[15:0])
|
||||
|
||||
#define osKernelSystemId "RTX V5.3" ///< RTOS identification string
|
||||
|
||||
#define osFeature_MainThread 0 ///< main thread 1=main can be thread, 0=not available
|
||||
#define osFeature_Signals 31U ///< maximum number of Signal Flags available per thread
|
||||
#define osFeature_Semaphore 65535U ///< maximum count for \ref osSemaphoreCreate function
|
||||
#define osFeature_Wait 0 ///< osWait function: 1=available, 0=not available
|
||||
#define osFeature_SysTick 1 ///< osKernelSysTick functions: 1=available, 0=not available
|
||||
#define osFeature_Pool 1 ///< Memory Pools: 1=available, 0=not available
|
||||
#define osFeature_MessageQ 1 ///< Message Queues: 1=available, 0=not available
|
||||
#define osFeature_MailQ 1 ///< Mail Queues: 1=available, 0=not available
|
||||
|
||||
#if defined(__CC_ARM)
|
||||
#define os_InRegs __value_in_regs
|
||||
#elif defined(__ARMCC_VERSION) && (__ARMCC_VERSION >= 6010050)
|
||||
#define os_InRegs __attribute__((value_in_regs))
|
||||
#else
|
||||
#define os_InRegs
|
||||
#endif
|
||||
|
||||
#if (osCMSIS >= 0x20000U)
|
||||
#include "cmsis_os2.h"
|
||||
#else
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
#endif
|
||||
#include "rtx_os.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C"
|
||||
{
|
||||
#endif
|
||||
|
||||
|
||||
// ==== Enumerations, structures, defines ====
|
||||
|
||||
/// Priority values.
|
||||
#if (osCMSIS < 0x20000U)
|
||||
typedef enum {
|
||||
osPriorityIdle = -3, ///< Priority: idle (lowest)
|
||||
osPriorityLow = -2, ///< Priority: low
|
||||
osPriorityBelowNormal = -1, ///< Priority: below normal
|
||||
osPriorityNormal = 0, ///< Priority: normal (default)
|
||||
osPriorityAboveNormal = +1, ///< Priority: above normal
|
||||
osPriorityHigh = +2, ///< Priority: high
|
||||
osPriorityRealtime = +3, ///< Priority: realtime (highest)
|
||||
osPriorityError = 0x84, ///< System cannot determine priority or illegal priority.
|
||||
osPriorityReserved = 0x7FFFFFFF ///< Prevents enum down-size compiler optimization.
|
||||
} osPriority;
|
||||
#else
|
||||
#define osPriority osPriority_t
|
||||
#endif
|
||||
|
||||
/// Entry point of a thread.
|
||||
typedef void (*os_pthread) (void const *argument);
|
||||
|
||||
/// Entry point of a timer call back function.
|
||||
typedef void (*os_ptimer) (void const *argument);
|
||||
|
||||
/// Timer type.
|
||||
#if (osCMSIS < 0x20000U)
|
||||
typedef enum {
|
||||
osTimerOnce = 0, ///< One-shot timer.
|
||||
osTimerPeriodic = 1 ///< Repeating timer.
|
||||
} os_timer_type;
|
||||
#else
|
||||
#define os_timer_type osTimerType_t
|
||||
#endif
|
||||
|
||||
/// Timeout value.
|
||||
#define osWaitForever 0xFFFFFFFFU ///< Wait forever timeout value.
|
||||
|
||||
/// Status code values returned by CMSIS-RTOS functions.
|
||||
#if (osCMSIS < 0x20000U)
|
||||
typedef enum {
|
||||
osOK = 0, ///< Function completed; no error or event occurred.
|
||||
osEventSignal = 0x08, ///< Function completed; signal event occurred.
|
||||
osEventMessage = 0x10, ///< Function completed; message event occurred.
|
||||
osEventMail = 0x20, ///< Function completed; mail event occurred.
|
||||
osEventTimeout = 0x40, ///< Function completed; timeout occurred.
|
||||
osErrorParameter = 0x80, ///< Parameter error: a mandatory parameter was missing or specified an incorrect object.
|
||||
osErrorResource = 0x81, ///< Resource not available: a specified resource was not available.
|
||||
osErrorTimeoutResource = 0xC1, ///< Resource not available within given time: a specified resource was not available within the timeout period.
|
||||
osErrorISR = 0x82, ///< Not allowed in ISR context: the function cannot be called from interrupt service routines.
|
||||
osErrorISRRecursive = 0x83, ///< Function called multiple times from ISR with same object.
|
||||
osErrorPriority = 0x84, ///< System cannot determine priority or thread has illegal priority.
|
||||
osErrorNoMemory = 0x85, ///< System is out of memory: it was impossible to allocate or reserve memory for the operation.
|
||||
osErrorValue = 0x86, ///< Value of a parameter is out of range.
|
||||
osErrorOS = 0xFF, ///< Unspecified RTOS error: run-time error but no other error message fits.
|
||||
osStatusReserved = 0x7FFFFFFF ///< Prevents enum down-size compiler optimization.
|
||||
} osStatus;
|
||||
#else
|
||||
typedef int32_t osStatus;
|
||||
#define osEventSignal (0x08)
|
||||
#define osEventMessage (0x10)
|
||||
#define osEventMail (0x20)
|
||||
#define osEventTimeout (0x40)
|
||||
#define osErrorOS osError
|
||||
#define osErrorTimeoutResource osErrorTimeout
|
||||
#define osErrorISRRecursive (-126)
|
||||
#define osErrorValue (-127)
|
||||
#define osErrorPriority (-128)
|
||||
#endif
|
||||
|
||||
|
||||
// >>> the following data type definitions may be adapted towards a specific RTOS
|
||||
|
||||
/// Thread ID identifies the thread.
|
||||
#if (osCMSIS < 0x20000U)
|
||||
typedef void *osThreadId;
|
||||
#else
|
||||
#define osThreadId osThreadId_t
|
||||
#endif
|
||||
|
||||
/// Timer ID identifies the timer.
|
||||
#if (osCMSIS < 0x20000U)
|
||||
typedef void *osTimerId;
|
||||
#else
|
||||
#define osTimerId osTimerId_t
|
||||
#endif
|
||||
|
||||
/// Mutex ID identifies the mutex.
|
||||
#if (osCMSIS < 0x20000U)
|
||||
typedef void *osMutexId;
|
||||
#else
|
||||
#define osMutexId osMutexId_t
|
||||
#endif
|
||||
|
||||
/// Semaphore ID identifies the semaphore.
|
||||
#if (osCMSIS < 0x20000U)
|
||||
typedef void *osSemaphoreId;
|
||||
#else
|
||||
#define osSemaphoreId osSemaphoreId_t
|
||||
#endif
|
||||
|
||||
/// Pool ID identifies the memory pool.
|
||||
typedef void *osPoolId;
|
||||
|
||||
/// Message ID identifies the message queue.
|
||||
typedef void *osMessageQId;
|
||||
|
||||
/// Mail ID identifies the mail queue.
|
||||
typedef void *osMailQId;
|
||||
|
||||
|
||||
/// Thread Definition structure contains startup information of a thread.
|
||||
#if (osCMSIS < 0x20000U)
|
||||
typedef struct os_thread_def {
|
||||
os_pthread pthread; ///< start address of thread function
|
||||
osPriority tpriority; ///< initial thread priority
|
||||
uint32_t instances; ///< maximum number of instances of that thread function
|
||||
uint32_t stacksize; ///< stack size requirements in bytes; 0 is default stack size
|
||||
} osThreadDef_t;
|
||||
#else
|
||||
typedef struct os_thread_def {
|
||||
os_pthread pthread; ///< start address of thread function
|
||||
osThreadAttr_t attr; ///< thread attributes
|
||||
} osThreadDef_t;
|
||||
#endif
|
||||
|
||||
/// Timer Definition structure contains timer parameters.
|
||||
#if (osCMSIS < 0x20000U)
|
||||
typedef struct os_timer_def {
|
||||
os_ptimer ptimer; ///< start address of a timer function
|
||||
} osTimerDef_t;
|
||||
#else
|
||||
typedef struct os_timer_def {
|
||||
os_ptimer ptimer; ///< start address of a timer function
|
||||
osTimerAttr_t attr; ///< timer attributes
|
||||
} osTimerDef_t;
|
||||
#endif
|
||||
|
||||
/// Mutex Definition structure contains setup information for a mutex.
|
||||
#if (osCMSIS < 0x20000U)
|
||||
typedef struct os_mutex_def {
|
||||
uint32_t dummy; ///< dummy value
|
||||
} osMutexDef_t;
|
||||
#else
|
||||
#define osMutexDef_t osMutexAttr_t
|
||||
#endif
|
||||
|
||||
/// Semaphore Definition structure contains setup information for a semaphore.
|
||||
#if (osCMSIS < 0x20000U)
|
||||
typedef struct os_semaphore_def {
|
||||
uint32_t dummy; ///< dummy value
|
||||
} osSemaphoreDef_t;
|
||||
#else
|
||||
#define osSemaphoreDef_t osSemaphoreAttr_t
|
||||
#endif
|
||||
|
||||
/// Definition structure for memory block allocation.
|
||||
#if (osCMSIS < 0x20000U)
|
||||
typedef struct os_pool_def {
|
||||
uint32_t pool_sz; ///< number of items (elements) in the pool
|
||||
uint32_t item_sz; ///< size of an item
|
||||
void *pool; ///< pointer to memory for pool
|
||||
} osPoolDef_t;
|
||||
#else
|
||||
typedef struct os_pool_def {
|
||||
uint32_t pool_sz; ///< number of items (elements) in the pool
|
||||
uint32_t item_sz; ///< size of an item
|
||||
osMemoryPoolAttr_t attr; ///< memory pool attributes
|
||||
} osPoolDef_t;
|
||||
#endif
|
||||
|
||||
/// Definition structure for message queue.
|
||||
#if (osCMSIS < 0x20000U)
|
||||
typedef struct os_messageQ_def {
|
||||
uint32_t queue_sz; ///< number of elements in the queue
|
||||
void *pool; ///< memory array for messages
|
||||
} osMessageQDef_t;
|
||||
#else
|
||||
typedef struct os_messageQ_def {
|
||||
uint32_t queue_sz; ///< number of elements in the queue
|
||||
osMessageQueueAttr_t attr; ///< message queue attributes
|
||||
} osMessageQDef_t;
|
||||
#endif
|
||||
|
||||
/// Definition structure for mail queue.
|
||||
#if (osCMSIS < 0x20000U)
|
||||
typedef struct os_mailQ_def {
|
||||
uint32_t queue_sz; ///< number of elements in the queue
|
||||
uint32_t item_sz; ///< size of an item
|
||||
void *pool; ///< memory array for mail
|
||||
} osMailQDef_t;
|
||||
#else
|
||||
typedef struct os_mailQ_def {
|
||||
uint32_t queue_sz; ///< number of elements in the queue
|
||||
uint32_t item_sz; ///< size of an item
|
||||
void *mail; ///< pointer to mail
|
||||
osMemoryPoolAttr_t mp_attr; ///< memory pool attributes
|
||||
osMessageQueueAttr_t mq_attr; ///< message queue attributes
|
||||
} osMailQDef_t;
|
||||
#endif
|
||||
|
||||
|
||||
/// Event structure contains detailed information about an event.
|
||||
typedef struct {
|
||||
osStatus status; ///< status code: event or error information
|
||||
union {
|
||||
uint32_t v; ///< message as 32-bit value
|
||||
void *p; ///< message or mail as void pointer
|
||||
int32_t signals; ///< signal flags
|
||||
} value; ///< event value
|
||||
union {
|
||||
osMailQId mail_id; ///< mail id obtained by \ref osMailCreate
|
||||
osMessageQId message_id; ///< message id obtained by \ref osMessageCreate
|
||||
} def; ///< event definition
|
||||
} osEvent;
|
||||
|
||||
|
||||
// ==== Kernel Management Functions ====
|
||||
|
||||
/// Initialize the RTOS Kernel for creating objects.
|
||||
/// \return status code that indicates the execution status of the function.
|
||||
#if (osCMSIS < 0x20000U)
|
||||
osStatus osKernelInitialize (void);
|
||||
#endif
|
||||
|
||||
/// Start the RTOS Kernel scheduler.
|
||||
/// \return status code that indicates the execution status of the function.
|
||||
#if (osCMSIS < 0x20000U)
|
||||
osStatus osKernelStart (void);
|
||||
#endif
|
||||
|
||||
/// Check if the RTOS kernel is already started.
|
||||
/// \return 0 RTOS is not started, 1 RTOS is started.
|
||||
#if (osCMSIS < 0x20000U)
|
||||
int32_t osKernelRunning(void);
|
||||
#endif
|
||||
|
||||
#if (defined(osFeature_SysTick) && (osFeature_SysTick != 0)) // System Timer available
|
||||
|
||||
/// Get the RTOS kernel system timer counter.
|
||||
/// \return RTOS kernel system timer as 32-bit value
|
||||
#if (osCMSIS < 0x20000U)
|
||||
uint32_t osKernelSysTick (void);
|
||||
#else
|
||||
#define osKernelSysTick osKernelGetSysTimerCount
|
||||
#endif
|
||||
|
||||
/// The RTOS kernel system timer frequency in Hz.
|
||||
/// \note Reflects the system timer setting and is typically defined in a configuration file.
|
||||
#if (osCMSIS < 0x20000U)
|
||||
#define osKernelSysTickFrequency 100000000
|
||||
#endif
|
||||
|
||||
/// Convert a microseconds value to a RTOS kernel system timer value.
|
||||
/// \param microsec time value in microseconds.
|
||||
/// \return time value normalized to the \ref osKernelSysTickFrequency
|
||||
#if (osCMSIS < 0x20000U)
|
||||
#define osKernelSysTickMicroSec(microsec) (((uint64_t)microsec * (osKernelSysTickFrequency)) / 1000000)
|
||||
#else
|
||||
#define osKernelSysTickMicroSec(microsec) (((uint64_t)microsec * osKernelGetSysTimerFreq()) / 1000000)
|
||||
#endif
|
||||
|
||||
#endif // System Timer available
|
||||
|
||||
|
||||
// ==== Thread Management Functions ====
|
||||
|
||||
/// Create a Thread Definition with function, priority, and stack requirements.
|
||||
/// \param name name of the thread function.
|
||||
/// \param priority initial priority of the thread function.
|
||||
/// \param instances number of possible thread instances.
|
||||
/// \param stacksz stack size (in bytes) requirements for the thread function.
|
||||
#if defined (osObjectsExternal) // object is external
|
||||
#define osThreadDef(name, priority, instances, stacksz) \
|
||||
extern const osThreadDef_t os_thread_def_##name
|
||||
#else // define the object
|
||||
#if (osCMSIS < 0x20000U)
|
||||
#define osThreadDef(name, priority, instances, stacksz) \
|
||||
const osThreadDef_t os_thread_def_##name = \
|
||||
{ (name), (priority), (instances), (stacksz) }
|
||||
#else
|
||||
#define osThreadDef(name, priority, instances, stacksz) \
|
||||
static uint64_t os_thread_stack##name[(stacksz)?(((stacksz+7)/8)):1] __attribute__((section(".bss.os.thread.stack"))); \
|
||||
static osRtxThread_t os_thread_cb_##name __attribute__((section(".bss.os.thread.cb"))); \
|
||||
const osThreadDef_t os_thread_def_##name = \
|
||||
{ (name), \
|
||||
{ NULL, osThreadDetached, \
|
||||
(instances == 1) ? (&os_thread_cb_##name) : NULL,\
|
||||
(instances == 1) ? osRtxThreadCbSize : 0U, \
|
||||
((stacksz) && (instances == 1)) ? (&os_thread_stack##name) : NULL, \
|
||||
8*((stacksz+7)/8), \
|
||||
(priority), 0U, 0U } }
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/// Access a Thread definition.
|
||||
/// \param name name of the thread definition object.
|
||||
#define osThread(name) \
|
||||
&os_thread_def_##name
|
||||
|
||||
/// Create a thread and add it to Active Threads and set it to state READY.
|
||||
/// \param[in] thread_def thread definition referenced with \ref osThread.
|
||||
/// \param[in] argument pointer that is passed to the thread function as start argument.
|
||||
/// \return thread ID for reference by other functions or NULL in case of error.
|
||||
osThreadId osThreadCreate (const osThreadDef_t *thread_def, void *argument);
|
||||
|
||||
/// Return the thread ID of the current running thread.
|
||||
/// \return thread ID for reference by other functions or NULL in case of error.
|
||||
#if (osCMSIS < 0x20000U)
|
||||
osThreadId osThreadGetId (void);
|
||||
#endif
|
||||
|
||||
/// Change priority of a thread.
|
||||
/// \param[in] thread_id thread ID obtained by \ref osThreadCreate or \ref osThreadGetId.
|
||||
/// \param[in] priority new priority value for the thread function.
|
||||
/// \return status code that indicates the execution status of the function.
|
||||
#if (osCMSIS < 0x20000U)
|
||||
osStatus osThreadSetPriority (osThreadId thread_id, osPriority priority);
|
||||
#endif
|
||||
|
||||
/// Get current priority of a thread.
|
||||
/// \param[in] thread_id thread ID obtained by \ref osThreadCreate or \ref osThreadGetId.
|
||||
/// \return current priority value of the specified thread.
|
||||
#if (osCMSIS < 0x20000U)
|
||||
osPriority osThreadGetPriority (osThreadId thread_id);
|
||||
#endif
|
||||
|
||||
/// Pass control to next thread that is in state \b READY.
|
||||
/// \return status code that indicates the execution status of the function.
|
||||
#if (osCMSIS < 0x20000U)
|
||||
osStatus osThreadYield (void);
|
||||
#endif
|
||||
|
||||
/// Terminate execution of a thread.
|
||||
/// \param[in] thread_id thread ID obtained by \ref osThreadCreate or \ref osThreadGetId.
|
||||
/// \return status code that indicates the execution status of the function.
|
||||
#if (osCMSIS < 0x20000U)
|
||||
osStatus osThreadTerminate (osThreadId thread_id);
|
||||
#endif
|
||||
|
||||
|
||||
// ==== Signal Management ====
|
||||
|
||||
/// Set the specified Signal Flags of an active thread.
|
||||
/// \param[in] thread_id thread ID obtained by \ref osThreadCreate or \ref osThreadGetId.
|
||||
/// \param[in] signals specifies the signal flags of the thread that should be set.
|
||||
/// \return previous signal flags of the specified thread or 0x80000000 in case of incorrect parameters.
|
||||
int32_t osSignalSet (osThreadId thread_id, int32_t signals);
|
||||
|
||||
/// Clear the specified Signal Flags of an active thread.
|
||||
/// \param[in] thread_id thread ID obtained by \ref osThreadCreate or \ref osThreadGetId.
|
||||
/// \param[in] signals specifies the signal flags of the thread that shall be cleared.
|
||||
/// \return previous signal flags of the specified thread or 0x80000000 in case of incorrect parameters or call from ISR.
|
||||
int32_t osSignalClear (osThreadId thread_id, int32_t signals);
|
||||
|
||||
/// Wait for one or more Signal Flags to become signaled for the current \b RUNNING thread.
|
||||
/// \param[in] signals wait until all specified signal flags set or 0 for any single signal flag.
|
||||
/// \param[in] millisec \ref CMSIS_RTOS_TimeOutValue or 0 in case of no time-out.
|
||||
/// \return event flag information or error code.
|
||||
os_InRegs osEvent osSignalWait (int32_t signals, uint32_t millisec);
|
||||
|
||||
|
||||
// ==== Generic Wait Functions ====
|
||||
|
||||
/// Wait for Timeout (Time Delay).
|
||||
/// \param[in] millisec \ref CMSIS_RTOS_TimeOutValue "time delay" value
|
||||
/// \return status code that indicates the execution status of the function.
|
||||
#if (osCMSIS < 0x20000U)
|
||||
osStatus osDelay (uint32_t millisec);
|
||||
#endif
|
||||
|
||||
#if (defined (osFeature_Wait) && (osFeature_Wait != 0)) // Generic Wait available
|
||||
|
||||
/// Wait for Signal, Message, Mail, or Timeout.
|
||||
/// \param[in] millisec \ref CMSIS_RTOS_TimeOutValue or 0 in case of no time-out
|
||||
/// \return event that contains signal, message, or mail information or error code.
|
||||
os_InRegs osEvent osWait (uint32_t millisec);
|
||||
|
||||
#endif // Generic Wait available
|
||||
|
||||
|
||||
// ==== Timer Management Functions ====
|
||||
|
||||
/// Define a Timer object.
|
||||
/// \param name name of the timer object.
|
||||
/// \param function name of the timer call back function.
|
||||
#if defined (osObjectsExternal) // object is external
|
||||
#define osTimerDef(name, function) \
|
||||
extern const osTimerDef_t os_timer_def_##name
|
||||
#else // define the object
|
||||
#if (osCMSIS < 0x20000U)
|
||||
#define osTimerDef(name, function) \
|
||||
const osTimerDef_t os_timer_def_##name = { (function) }
|
||||
#else
|
||||
#define osTimerDef(name, function) \
|
||||
static osRtxTimer_t os_timer_cb_##name __attribute__((section(".bss.os.timer.cb"))); \
|
||||
const osTimerDef_t os_timer_def_##name = \
|
||||
{ (function), { NULL, 0U, (&os_timer_cb_##name), osRtxTimerCbSize } }
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/// Access a Timer definition.
|
||||
/// \param name name of the timer object.
|
||||
#define osTimer(name) \
|
||||
&os_timer_def_##name
|
||||
|
||||
/// Create and Initialize a timer.
|
||||
/// \param[in] timer_def timer object referenced with \ref osTimer.
|
||||
/// \param[in] type osTimerOnce for one-shot or osTimerPeriodic for periodic behavior.
|
||||
/// \param[in] argument argument to the timer call back function.
|
||||
/// \return timer ID for reference by other functions or NULL in case of error.
|
||||
osTimerId osTimerCreate (const osTimerDef_t *timer_def, os_timer_type type, void *argument);
|
||||
|
||||
/// Start or restart a timer.
|
||||
/// \param[in] timer_id timer ID obtained by \ref osTimerCreate.
|
||||
/// \param[in] millisec \ref CMSIS_RTOS_TimeOutValue "time delay" value of the timer.
|
||||
/// \return status code that indicates the execution status of the function.
|
||||
#if (osCMSIS < 0x20000U)
|
||||
osStatus osTimerStart (osTimerId timer_id, uint32_t millisec);
|
||||
#endif
|
||||
|
||||
/// Stop a timer.
|
||||
/// \param[in] timer_id timer ID obtained by \ref osTimerCreate.
|
||||
/// \return status code that indicates the execution status of the function.
|
||||
#if (osCMSIS < 0x20000U)
|
||||
osStatus osTimerStop (osTimerId timer_id);
|
||||
#endif
|
||||
|
||||
/// Delete a timer.
|
||||
/// \param[in] timer_id timer ID obtained by \ref osTimerCreate.
|
||||
/// \return status code that indicates the execution status of the function.
|
||||
#if (osCMSIS < 0x20000U)
|
||||
osStatus osTimerDelete (osTimerId timer_id);
|
||||
#endif
|
||||
|
||||
|
||||
// ==== Mutex Management Functions ====
|
||||
|
||||
/// Define a Mutex.
|
||||
/// \param name name of the mutex object.
|
||||
#if defined (osObjectsExternal) // object is external
|
||||
#define osMutexDef(name) \
|
||||
extern const osMutexDef_t os_mutex_def_##name
|
||||
#else // define the object
|
||||
#if (osCMSIS < 0x20000U)
|
||||
#define osMutexDef(name) \
|
||||
const osMutexDef_t os_mutex_def_##name = { 0 }
|
||||
#else
|
||||
#define osMutexDef(name) \
|
||||
static osRtxMutex_t os_mutex_cb_##name __attribute__((section(".bss.os.mutex.cb"))); \
|
||||
const osMutexDef_t os_mutex_def_##name = \
|
||||
{ NULL, osMutexRecursive | osMutexPrioInherit | osMutexRobust, (&os_mutex_cb_##name), osRtxMutexCbSize }
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/// Access a Mutex definition.
|
||||
/// \param name name of the mutex object.
|
||||
#define osMutex(name) \
|
||||
&os_mutex_def_##name
|
||||
|
||||
/// Create and Initialize a Mutex object.
|
||||
/// \param[in] mutex_def mutex definition referenced with \ref osMutex.
|
||||
/// \return mutex ID for reference by other functions or NULL in case of error.
|
||||
osMutexId osMutexCreate (const osMutexDef_t *mutex_def);
|
||||
|
||||
/// Wait until a Mutex becomes available.
|
||||
/// \param[in] mutex_id mutex ID obtained by \ref osMutexCreate.
|
||||
/// \param[in] millisec \ref CMSIS_RTOS_TimeOutValue or 0 in case of no time-out.
|
||||
/// \return status code that indicates the execution status of the function.
|
||||
#if (osCMSIS < 0x20000U)
|
||||
osStatus osMutexWait (osMutexId mutex_id, uint32_t millisec);
|
||||
#else
|
||||
#define osMutexWait osMutexAcquire
|
||||
#endif
|
||||
|
||||
/// Release a Mutex that was obtained by \ref osMutexWait.
|
||||
/// \param[in] mutex_id mutex ID obtained by \ref osMutexCreate.
|
||||
/// \return status code that indicates the execution status of the function.
|
||||
#if (osCMSIS < 0x20000U)
|
||||
osStatus osMutexRelease (osMutexId mutex_id);
|
||||
#endif
|
||||
|
||||
/// Delete a Mutex object.
|
||||
/// \param[in] mutex_id mutex ID obtained by \ref osMutexCreate.
|
||||
/// \return status code that indicates the execution status of the function.
|
||||
#if (osCMSIS < 0x20000U)
|
||||
osStatus osMutexDelete (osMutexId mutex_id);
|
||||
#endif
|
||||
|
||||
|
||||
// ==== Semaphore Management Functions ====
|
||||
|
||||
#if (defined (osFeature_Semaphore) && (osFeature_Semaphore != 0U)) // Semaphore available
|
||||
|
||||
/// Define a Semaphore object.
|
||||
/// \param name name of the semaphore object.
|
||||
#if defined (osObjectsExternal) // object is external
|
||||
#define osSemaphoreDef(name) \
|
||||
extern const osSemaphoreDef_t os_semaphore_def_##name
|
||||
#else // define the object
|
||||
#if (osCMSIS < 0x20000U)
|
||||
#define osSemaphoreDef(name) \
|
||||
const osSemaphoreDef_t os_semaphore_def_##name = { 0 }
|
||||
#else
|
||||
#define osSemaphoreDef(name) \
|
||||
static osRtxSemaphore_t os_semaphore_cb_##name __attribute__((section(".bss.os.semaphore.cb"))); \
|
||||
const osSemaphoreDef_t os_semaphore_def_##name = \
|
||||
{ NULL, 0U, (&os_semaphore_cb_##name), osRtxSemaphoreCbSize }
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/// Access a Semaphore definition.
|
||||
/// \param name name of the semaphore object.
|
||||
#define osSemaphore(name) \
|
||||
&os_semaphore_def_##name
|
||||
|
||||
/// Create and Initialize a Semaphore object.
|
||||
/// \param[in] semaphore_def semaphore definition referenced with \ref osSemaphore.
|
||||
/// \param[in] count maximum and initial number of available tokens.
|
||||
/// \return semaphore ID for reference by other functions or NULL in case of error.
|
||||
osSemaphoreId osSemaphoreCreate (const osSemaphoreDef_t *semaphore_def, int32_t count);
|
||||
|
||||
/// Wait until a Semaphore token becomes available.
|
||||
/// \param[in] semaphore_id semaphore object referenced with \ref osSemaphoreCreate.
|
||||
/// \param[in] millisec \ref CMSIS_RTOS_TimeOutValue or 0 in case of no time-out.
|
||||
/// \return number of available tokens, or -1 in case of incorrect parameters.
|
||||
int32_t osSemaphoreWait (osSemaphoreId semaphore_id, uint32_t millisec);
|
||||
|
||||
/// Release a Semaphore token.
|
||||
/// \param[in] semaphore_id semaphore object referenced with \ref osSemaphoreCreate.
|
||||
/// \return status code that indicates the execution status of the function.
|
||||
#if (osCMSIS < 0x20000U)
|
||||
osStatus osSemaphoreRelease (osSemaphoreId semaphore_id);
|
||||
#endif
|
||||
|
||||
/// Delete a Semaphore object.
|
||||
/// \param[in] semaphore_id semaphore object referenced with \ref osSemaphoreCreate.
|
||||
/// \return status code that indicates the execution status of the function.
|
||||
#if (osCMSIS < 0x20000U)
|
||||
osStatus osSemaphoreDelete (osSemaphoreId semaphore_id);
|
||||
#endif
|
||||
|
||||
#endif // Semaphore available
|
||||
|
||||
|
||||
// ==== Memory Pool Management Functions ====
|
||||
|
||||
#if (defined(osFeature_Pool) && (osFeature_Pool != 0)) // Memory Pool available
|
||||
|
||||
/// \brief Define a Memory Pool.
|
||||
/// \param name name of the memory pool.
|
||||
/// \param no maximum number of blocks (objects) in the memory pool.
|
||||
/// \param type data type of a single block (object).
|
||||
#if defined (osObjectsExternal) // object is external
|
||||
#define osPoolDef(name, no, type) \
|
||||
extern const osPoolDef_t os_pool_def_##name
|
||||
#else // define the object
|
||||
#if (osCMSIS < 0x20000U)
|
||||
#define osPoolDef(name, no, type) \
|
||||
const osPoolDef_t os_pool_def_##name = \
|
||||
{ (no), sizeof(type), NULL }
|
||||
#else
|
||||
#define osPoolDef(name, no, type) \
|
||||
static osRtxMemoryPool_t os_mp_cb_##name __attribute__((section(".bss.os.mempool.cb"))); \
|
||||
static uint32_t os_mp_data_##name[osRtxMemoryPoolMemSize((no),sizeof(type))/4] __attribute__((section(".bss.os.mempool.mem"))); \
|
||||
const osPoolDef_t os_pool_def_##name = \
|
||||
{ (no), sizeof(type), \
|
||||
{ NULL, 0U, (&os_mp_cb_##name), osRtxMemoryPoolCbSize, \
|
||||
(&os_mp_data_##name), sizeof(os_mp_data_##name) } }
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/// \brief Access a Memory Pool definition.
|
||||
/// \param name name of the memory pool
|
||||
#define osPool(name) \
|
||||
&os_pool_def_##name
|
||||
|
||||
/// Create and Initialize a Memory Pool object.
|
||||
/// \param[in] pool_def memory pool definition referenced with \ref osPool.
|
||||
/// \return memory pool ID for reference by other functions or NULL in case of error.
|
||||
osPoolId osPoolCreate (const osPoolDef_t *pool_def);
|
||||
|
||||
/// Allocate a memory block from a Memory Pool.
|
||||
/// \param[in] pool_id memory pool ID obtain referenced with \ref osPoolCreate.
|
||||
/// \return address of the allocated memory block or NULL in case of no memory available.
|
||||
void *osPoolAlloc (osPoolId pool_id);
|
||||
|
||||
/// Allocate a memory block from a Memory Pool and set memory block to zero.
|
||||
/// \param[in] pool_id memory pool ID obtain referenced with \ref osPoolCreate.
|
||||
/// \return address of the allocated memory block or NULL in case of no memory available.
|
||||
void *osPoolCAlloc (osPoolId pool_id);
|
||||
|
||||
/// Return an allocated memory block back to a Memory Pool.
|
||||
/// \param[in] pool_id memory pool ID obtain referenced with \ref osPoolCreate.
|
||||
/// \param[in] block address of the allocated memory block to be returned to the memory pool.
|
||||
/// \return status code that indicates the execution status of the function.
|
||||
osStatus osPoolFree (osPoolId pool_id, void *block);
|
||||
|
||||
#endif // Memory Pool available
|
||||
|
||||
|
||||
// ==== Message Queue Management Functions ====
|
||||
|
||||
#if (defined(osFeature_MessageQ) && (osFeature_MessageQ != 0)) // Message Queue available
|
||||
|
||||
/// \brief Create a Message Queue Definition.
|
||||
/// \param name name of the queue.
|
||||
/// \param queue_sz maximum number of messages in the queue.
|
||||
/// \param type data type of a single message element (for debugger).
|
||||
#if defined (osObjectsExternal) // object is external
|
||||
#define osMessageQDef(name, queue_sz, type) \
|
||||
extern const osMessageQDef_t os_messageQ_def_##name
|
||||
#else // define the object
|
||||
#if (osCMSIS < 0x20000U)
|
||||
#define osMessageQDef(name, queue_sz, type) \
|
||||
const osMessageQDef_t os_messageQ_def_##name = \
|
||||
{ (queue_sz), NULL }
|
||||
#else
|
||||
#define osMessageQDef(name, queue_sz, type) \
|
||||
static osRtxMessageQueue_t os_mq_cb_##name __attribute__((section(".bss.os.msgqueue.cb"))); \
|
||||
static uint32_t os_mq_data_##name[osRtxMessageQueueMemSize((queue_sz),sizeof(uint32_t))/4] __attribute__((section(".bss.os.msgqueue.mem"))); \
|
||||
const osMessageQDef_t os_messageQ_def_##name = \
|
||||
{ (queue_sz), \
|
||||
{ NULL, 0U, (&os_mq_cb_##name), osRtxMessageQueueCbSize, \
|
||||
(&os_mq_data_##name), sizeof(os_mq_data_##name) } }
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/// \brief Access a Message Queue Definition.
|
||||
/// \param name name of the queue
|
||||
#define osMessageQ(name) \
|
||||
&os_messageQ_def_##name
|
||||
|
||||
/// Create and Initialize a Message Queue object.
|
||||
/// \param[in] queue_def message queue definition referenced with \ref osMessageQ.
|
||||
/// \param[in] thread_id thread ID (obtained by \ref osThreadCreate or \ref osThreadGetId) or NULL.
|
||||
/// \return message queue ID for reference by other functions or NULL in case of error.
|
||||
osMessageQId osMessageCreate (const osMessageQDef_t *queue_def, osThreadId thread_id);
|
||||
|
||||
/// Put a Message to a Queue.
|
||||
/// \param[in] queue_id message queue ID obtained with \ref osMessageCreate.
|
||||
/// \param[in] info message information.
|
||||
/// \param[in] millisec \ref CMSIS_RTOS_TimeOutValue or 0 in case of no time-out.
|
||||
/// \return status code that indicates the execution status of the function.
|
||||
osStatus osMessagePut (osMessageQId queue_id, uint32_t info, uint32_t millisec);
|
||||
|
||||
/// Get a Message from a Queue or timeout if Queue is empty.
|
||||
/// \param[in] queue_id message queue ID obtained with \ref osMessageCreate.
|
||||
/// \param[in] millisec \ref CMSIS_RTOS_TimeOutValue or 0 in case of no time-out.
|
||||
/// \return event information that includes status code.
|
||||
os_InRegs osEvent osMessageGet (osMessageQId queue_id, uint32_t millisec);
|
||||
|
||||
#endif // Message Queue available
|
||||
|
||||
|
||||
// ==== Mail Queue Management Functions ====
|
||||
|
||||
#if (defined(osFeature_MailQ) && (osFeature_MailQ != 0)) // Mail Queue available
|
||||
|
||||
/// \brief Create a Mail Queue Definition.
|
||||
/// \param name name of the queue.
|
||||
/// \param queue_sz maximum number of mails in the queue.
|
||||
/// \param type data type of a single mail element.
|
||||
#if defined (osObjectsExternal) // object is external
|
||||
#define osMailQDef(name, queue_sz, type) \
|
||||
extern const osMailQDef_t os_mailQ_def_##name
|
||||
#else // define the object
|
||||
#if (osCMSIS < 0x20000U)
|
||||
#define osMailQDef(name, queue_sz, type) \
|
||||
const osMailQDef_t os_mailQ_def_##name = \
|
||||
{ (queue_sz), sizeof(type), NULL }
|
||||
#else
|
||||
#define osMailQDef(name, queue_sz, type) \
|
||||
static void *os_mail_p_##name[2] __attribute__((section(".bss.os"))); \
|
||||
static osRtxMemoryPool_t os_mail_mp_cb_##name __attribute__((section(".bss.os.mempool.cb"))); \
|
||||
static osRtxMessageQueue_t os_mail_mq_cb_##name __attribute__((section(".bss.os.msgqueue.cb"))); \
|
||||
static uint32_t os_mail_mp_data_##name[osRtxMemoryPoolMemSize ((queue_sz),sizeof(type) )/4] __attribute__((section(".bss.os.mempool.mem"))); \
|
||||
static uint32_t os_mail_mq_data_##name[osRtxMessageQueueMemSize((queue_sz),sizeof(void*))/4] __attribute__((section(".bss.os.msgqueue.mem"))); \
|
||||
const osMailQDef_t os_mailQ_def_##name = \
|
||||
{ (queue_sz), sizeof(type), (&os_mail_p_##name), \
|
||||
{ NULL, 0U, (&os_mail_mp_cb_##name), osRtxMemoryPoolCbSize, \
|
||||
(&os_mail_mp_data_##name), sizeof(os_mail_mp_data_##name) }, \
|
||||
{ NULL, 0U, (&os_mail_mq_cb_##name), osRtxMessageQueueCbSize, \
|
||||
(&os_mail_mq_data_##name), sizeof(os_mail_mq_data_##name) } }
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/// \brief Access a Mail Queue Definition.
|
||||
/// \param name name of the queue
|
||||
#define osMailQ(name) \
|
||||
&os_mailQ_def_##name
|
||||
|
||||
/// Create and Initialize a Mail Queue object.
|
||||
/// \param[in] queue_def mail queue definition referenced with \ref osMailQ.
|
||||
/// \param[in] thread_id thread ID (obtained by \ref osThreadCreate or \ref osThreadGetId) or NULL.
|
||||
/// \return mail queue ID for reference by other functions or NULL in case of error.
|
||||
osMailQId osMailCreate (const osMailQDef_t *queue_def, osThreadId thread_id);
|
||||
|
||||
/// Allocate a memory block for mail from a mail memory pool.
|
||||
/// \param[in] queue_id mail queue ID obtained with \ref osMailCreate.
|
||||
/// \param[in] millisec \ref CMSIS_RTOS_TimeOutValue or 0 in case of no time-out
|
||||
/// \return pointer to memory block that can be filled with mail or NULL in case of error.
|
||||
void *osMailAlloc (osMailQId queue_id, uint32_t millisec);
|
||||
|
||||
/// Allocate a memory block for mail from a mail memory pool and set memory block to zero.
|
||||
/// \param[in] queue_id mail queue ID obtained with \ref osMailCreate.
|
||||
/// \param[in] millisec \ref CMSIS_RTOS_TimeOutValue or 0 in case of no time-out
|
||||
/// \return pointer to memory block that can be filled with mail or NULL in case of error.
|
||||
void *osMailCAlloc (osMailQId queue_id, uint32_t millisec);
|
||||
|
||||
/// Put a Mail into a Queue.
|
||||
/// \param[in] queue_id mail queue ID obtained with \ref osMailCreate.
|
||||
/// \param[in] mail pointer to memory with mail to put into a queue.
|
||||
/// \return status code that indicates the execution status of the function.
|
||||
osStatus osMailPut (osMailQId queue_id, const void *mail);
|
||||
|
||||
/// Get a Mail from a Queue or timeout if Queue is empty.
|
||||
/// \param[in] queue_id mail queue ID obtained with \ref osMailCreate.
|
||||
/// \param[in] millisec \ref CMSIS_RTOS_TimeOutValue or 0 in case of no time-out.
|
||||
/// \return event information that includes status code.
|
||||
os_InRegs osEvent osMailGet (osMailQId queue_id, uint32_t millisec);
|
||||
|
||||
/// Free a memory block by returning it to a mail memory pool.
|
||||
/// \param[in] queue_id mail queue ID obtained with \ref osMailCreate.
|
||||
/// \param[in] mail pointer to memory block that was obtained with \ref osMailGet.
|
||||
/// \return status code that indicates the execution status of the function.
|
||||
osStatus osMailFree (osMailQId queue_id, void *mail);
|
||||
|
||||
#endif // Mail Queue available
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif // CMSIS_OS_H_
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,335 @@
|
||||
;/*
|
||||
; * Copyright (c) 2016-2020 Arm Limited. All rights reserved.
|
||||
; *
|
||||
; * SPDX-License-Identifier: Apache-2.0
|
||||
; *
|
||||
; * Licensed under the Apache License, Version 2.0 (the License); you may
|
||||
; * not use this file except in compliance with the License.
|
||||
; * You may obtain a copy of the License at
|
||||
; *
|
||||
; * www.apache.org/licenses/LICENSE-2.0
|
||||
; *
|
||||
; * Unless required by applicable law or agreed to in writing, software
|
||||
; * distributed under the License is distributed on an AS IS BASIS, WITHOUT
|
||||
; * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
; * See the License for the specific language governing permissions and
|
||||
; * limitations under the License.
|
||||
; *
|
||||
; * -----------------------------------------------------------------------------
|
||||
; *
|
||||
; * Project: CMSIS-RTOS RTX
|
||||
; * Title: ARMv8M Baseline Exception handlers
|
||||
; *
|
||||
; * -----------------------------------------------------------------------------
|
||||
; */
|
||||
|
||||
|
||||
IF :LNOT::DEF:DOMAIN_NS
|
||||
DOMAIN_NS EQU 0
|
||||
ENDIF
|
||||
|
||||
I_T_RUN_OFS EQU 20 ; osRtxInfo.thread.run offset
|
||||
TCB_SM_OFS EQU 48 ; TCB.stack_mem offset
|
||||
TCB_SP_OFS EQU 56 ; TCB.SP offset
|
||||
TCB_SF_OFS EQU 34 ; TCB.stack_frame offset
|
||||
TCB_TZM_OFS EQU 64 ; TCB.tz_memory offset
|
||||
|
||||
|
||||
PRESERVE8
|
||||
THUMB
|
||||
|
||||
|
||||
AREA |.constdata|, DATA, READONLY
|
||||
EXPORT irqRtxLib
|
||||
irqRtxLib DCB 0 ; Non weak library reference
|
||||
|
||||
|
||||
AREA |.text|, CODE, READONLY
|
||||
|
||||
|
||||
SVC_Handler PROC
|
||||
EXPORT SVC_Handler
|
||||
IMPORT osRtxUserSVC
|
||||
IMPORT osRtxInfo
|
||||
IF :DEF:MPU_LOAD
|
||||
IMPORT osRtxMpuLoad
|
||||
ENDIF
|
||||
IF DOMAIN_NS = 1
|
||||
IMPORT TZ_LoadContext_S
|
||||
IMPORT TZ_StoreContext_S
|
||||
ENDIF
|
||||
|
||||
MOV R0,LR
|
||||
LSRS R0,R0,#3 ; Determine return stack from EXC_RETURN bit 2
|
||||
BCC SVC_MSP ; Branch if return stack is MSP
|
||||
MRS R0,PSP ; Get PSP
|
||||
|
||||
SVC_Number
|
||||
LDR R1,[R0,#24] ; Load saved PC from stack
|
||||
SUBS R1,R1,#2 ; Point to SVC instruction
|
||||
LDRB R1,[R1] ; Load SVC number
|
||||
CMP R1,#0
|
||||
BNE SVC_User ; Branch if not SVC 0
|
||||
|
||||
PUSH {R0,LR} ; Save SP and EXC_RETURN
|
||||
LDM R0,{R0-R3} ; Load function parameters from stack
|
||||
BLX R7 ; Call service function
|
||||
POP {R2,R3} ; Restore SP and EXC_RETURN
|
||||
STMIA R2!,{R0-R1} ; Store function return values
|
||||
MOV LR,R3 ; Set EXC_RETURN
|
||||
|
||||
SVC_Context
|
||||
LDR R3,=osRtxInfo+I_T_RUN_OFS; Load address of osRtxInfo.run
|
||||
LDMIA R3!,{R1,R2} ; Load osRtxInfo.thread.run: curr & next
|
||||
CMP R1,R2 ; Check if thread switch is required
|
||||
BEQ SVC_Exit ; Branch when threads are the same
|
||||
|
||||
CBZ R1,SVC_ContextSwitch ; Branch if running thread is deleted
|
||||
|
||||
SVC_ContextSave
|
||||
IF DOMAIN_NS = 1
|
||||
LDR R0,[R1,#TCB_TZM_OFS] ; Load TrustZone memory identifier
|
||||
CBZ R0,SVC_ContextSave1 ; Branch if there is no secure context
|
||||
PUSH {R1,R2,R3,R7} ; Save registers
|
||||
MOV R7,LR ; Get EXC_RETURN
|
||||
BL TZ_StoreContext_S ; Store secure context
|
||||
MOV LR,R7 ; Set EXC_RETURN
|
||||
POP {R1,R2,R3,R7} ; Restore registers
|
||||
ENDIF
|
||||
|
||||
SVC_ContextSave1
|
||||
MRS R0,PSP ; Get PSP
|
||||
SUBS R0,R0,#32 ; Calculate SP
|
||||
STR R0,[R1,#TCB_SP_OFS] ; Store SP
|
||||
STMIA R0!,{R4-R7} ; Save R4..R7
|
||||
MOV R4,R8
|
||||
MOV R5,R9
|
||||
MOV R6,R10
|
||||
MOV R7,R11
|
||||
STMIA R0!,{R4-R7} ; Save R8..R11
|
||||
|
||||
SVC_ContextSave2
|
||||
MOV R0,LR ; Get EXC_RETURN
|
||||
ADDS R1,R1,#TCB_SF_OFS ; Adjust address
|
||||
STRB R0,[R1] ; Store stack frame information
|
||||
|
||||
SVC_ContextSwitch
|
||||
SUBS R3,R3,#8 ; Adjust address
|
||||
STR R2,[R3] ; osRtxInfo.thread.run: curr = next
|
||||
|
||||
IF :DEF:MPU_LOAD
|
||||
PUSH {R2,R3} ; Save registers
|
||||
MOV R0,R2 ; osRtxMpuLoad parameter
|
||||
BL osRtxMpuLoad ; Load MPU for next thread
|
||||
POP {R2,R3} ; Restore registers
|
||||
ENDIF
|
||||
|
||||
SVC_ContextRestore
|
||||
IF DOMAIN_NS = 1
|
||||
LDR R0,[R2,#TCB_TZM_OFS] ; Load TrustZone memory identifier
|
||||
CBZ R0,SVC_ContextRestore1 ; Branch if there is no secure context
|
||||
PUSH {R2,R3} ; Save registers
|
||||
BL TZ_LoadContext_S ; Load secure context
|
||||
POP {R2,R3} ; Restore registers
|
||||
ENDIF
|
||||
|
||||
SVC_ContextRestore1
|
||||
MOV R1,R2
|
||||
ADDS R1,R1,#TCB_SF_OFS ; Adjust address
|
||||
LDRB R0,[R1] ; Load stack frame information
|
||||
MOVS R1,#0xFF
|
||||
MVNS R1,R1 ; R1=0xFFFFFF00
|
||||
ORRS R0,R1
|
||||
MOV LR,R0 ; Set EXC_RETURN
|
||||
|
||||
IF DOMAIN_NS = 1
|
||||
LSLS R0,R0,#25 ; Check domain of interrupted thread
|
||||
BPL SVC_ContextRestore2 ; Branch if non-secure
|
||||
LDR R0,[R2,#TCB_SP_OFS] ; Load SP
|
||||
MSR PSP,R0 ; Set PSP
|
||||
BX LR ; Exit from handler
|
||||
ELSE
|
||||
LDR R0,[R2,#TCB_SM_OFS] ; Load stack memory base
|
||||
MSR PSPLIM,R0 ; Set PSPLIM
|
||||
ENDIF
|
||||
|
||||
SVC_ContextRestore2
|
||||
LDR R0,[R2,#TCB_SP_OFS] ; Load SP
|
||||
ADDS R0,R0,#16 ; Adjust address
|
||||
LDMIA R0!,{R4-R7} ; Restore R8..R11
|
||||
MOV R8,R4
|
||||
MOV R9,R5
|
||||
MOV R10,R6
|
||||
MOV R11,R7
|
||||
MSR PSP,R0 ; Set PSP
|
||||
SUBS R0,R0,#32 ; Adjust address
|
||||
LDMIA R0!,{R4-R7} ; Restore R4..R7
|
||||
|
||||
SVC_Exit
|
||||
BX LR ; Exit from handler
|
||||
|
||||
SVC_MSP
|
||||
MRS R0,MSP ; Get MSP
|
||||
B SVC_Number
|
||||
|
||||
SVC_User
|
||||
LDR R2,=osRtxUserSVC ; Load address of SVC table
|
||||
LDR R3,[R2] ; Load SVC maximum number
|
||||
CMP R1,R3 ; Check SVC number range
|
||||
BHI SVC_Exit ; Branch if out of range
|
||||
|
||||
PUSH {R0,LR} ; Save SP and EXC_RETURN
|
||||
LSLS R1,R1,#2
|
||||
LDR R3,[R2,R1] ; Load address of SVC function
|
||||
MOV R12,R3
|
||||
LDMIA R0,{R0-R3} ; Load function parameters from stack
|
||||
BLX R12 ; Call service function
|
||||
POP {R2,R3} ; Restore SP and EXC_RETURN
|
||||
STR R0,[R2] ; Store function return value
|
||||
MOV LR,R3 ; Set EXC_RETURN
|
||||
|
||||
BX LR ; Return from handler
|
||||
|
||||
ALIGN
|
||||
ENDP
|
||||
|
||||
|
||||
PendSV_Handler PROC
|
||||
EXPORT PendSV_Handler
|
||||
IMPORT osRtxPendSV_Handler
|
||||
|
||||
PUSH {R0,LR} ; Save EXC_RETURN
|
||||
BL osRtxPendSV_Handler ; Call osRtxPendSV_Handler
|
||||
POP {R0,R1} ; Restore EXC_RETURN
|
||||
MOV LR,R1 ; Set EXC_RETURN
|
||||
B Sys_Context
|
||||
|
||||
ALIGN
|
||||
ENDP
|
||||
|
||||
|
||||
SysTick_Handler PROC
|
||||
EXPORT SysTick_Handler
|
||||
IMPORT osRtxTick_Handler
|
||||
|
||||
PUSH {R0,LR} ; Save EXC_RETURN
|
||||
BL osRtxTick_Handler ; Call osRtxTick_Handler
|
||||
POP {R0,R1} ; Restore EXC_RETURN
|
||||
MOV LR,R1 ; Set EXC_RETURN
|
||||
B Sys_Context
|
||||
|
||||
ALIGN
|
||||
ENDP
|
||||
|
||||
|
||||
Sys_Context PROC
|
||||
EXPORT Sys_Context
|
||||
IMPORT osRtxInfo
|
||||
IF :DEF:MPU_LOAD
|
||||
IMPORT osRtxMpuLoad
|
||||
ENDIF
|
||||
IF DOMAIN_NS = 1
|
||||
IMPORT TZ_LoadContext_S
|
||||
IMPORT TZ_StoreContext_S
|
||||
ENDIF
|
||||
|
||||
LDR R3,=osRtxInfo+I_T_RUN_OFS; Load address of osRtxInfo.run
|
||||
LDM R3!,{R1,R2} ; Load osRtxInfo.thread.run: curr & next
|
||||
CMP R1,R2 ; Check if thread switch is required
|
||||
BEQ Sys_ContextExit ; Branch when threads are the same
|
||||
|
||||
Sys_ContextSave
|
||||
IF DOMAIN_NS = 1
|
||||
LDR R0,[R1,#TCB_TZM_OFS] ; Load TrustZone memory identifier
|
||||
CBZ R0,Sys_ContextSave1 ; Branch if there is no secure context
|
||||
PUSH {R1,R2,R3,R7} ; Save registers
|
||||
MOV R7,LR ; Get EXC_RETURN
|
||||
BL TZ_StoreContext_S ; Store secure context
|
||||
MOV LR,R7 ; Set EXC_RETURN
|
||||
POP {R1,R2,R3,R7} ; Restore registers
|
||||
|
||||
Sys_ContextSave1
|
||||
MOV R0,LR ; Get EXC_RETURN
|
||||
LSLS R0,R0,#25 ; Check domain of interrupted thread
|
||||
BPL Sys_ContextSave2 ; Branch if non-secure
|
||||
MRS R0,PSP ; Get PSP
|
||||
STR R0,[R1,#TCB_SP_OFS] ; Store SP
|
||||
B Sys_ContextSave3
|
||||
ENDIF
|
||||
|
||||
Sys_ContextSave2
|
||||
MRS R0,PSP ; Get PSP
|
||||
SUBS R0,R0,#32 ; Adjust address
|
||||
STR R0,[R1,#TCB_SP_OFS] ; Store SP
|
||||
STMIA R0!,{R4-R7} ; Save R4..R7
|
||||
MOV R4,R8
|
||||
MOV R5,R9
|
||||
MOV R6,R10
|
||||
MOV R7,R11
|
||||
STMIA R0!,{R4-R7} ; Save R8..R11
|
||||
|
||||
Sys_ContextSave3
|
||||
MOV R0,LR ; Get EXC_RETURN
|
||||
ADDS R1,R1,#TCB_SF_OFS ; Adjust address
|
||||
STRB R0,[R1] ; Store stack frame information
|
||||
|
||||
Sys_ContextSwitch
|
||||
SUBS R3,R3,#8 ; Adjust address
|
||||
STR R2,[R3] ; osRtxInfo.run: curr = next
|
||||
|
||||
IF :DEF:MPU_LOAD
|
||||
PUSH {R2,R3} ; Save registers
|
||||
MOV R0,R2 ; osRtxMpuLoad parameter
|
||||
BL osRtxMpuLoad ; Load MPU for next thread
|
||||
POP {R2,R3} ; Restore registers
|
||||
ENDIF
|
||||
|
||||
Sys_ContextRestore
|
||||
IF DOMAIN_NS = 1
|
||||
LDR R0,[R2,#TCB_TZM_OFS] ; Load TrustZone memory identifier
|
||||
CBZ R0,Sys_ContextRestore1 ; Branch if there is no secure context
|
||||
PUSH {R2,R3} ; Save registers
|
||||
BL TZ_LoadContext_S ; Load secure context
|
||||
POP {R2,R3} ; Restore registers
|
||||
ENDIF
|
||||
|
||||
Sys_ContextRestore1
|
||||
MOV R1,R2
|
||||
ADDS R1,R1,#TCB_SF_OFS ; Adjust offset
|
||||
LDRB R0,[R1] ; Load stack frame information
|
||||
MOVS R1,#0xFF
|
||||
MVNS R1,R1 ; R1=0xFFFFFF00
|
||||
ORRS R0,R1
|
||||
MOV LR,R0 ; Set EXC_RETURN
|
||||
|
||||
IF DOMAIN_NS = 1
|
||||
LSLS R0,R0,#25 ; Check domain of interrupted thread
|
||||
BPL Sys_ContextRestore2 ; Branch if non-secure
|
||||
LDR R0,[R2,#TCB_SP_OFS] ; Load SP
|
||||
MSR PSP,R0 ; Set PSP
|
||||
BX LR ; Exit from handler
|
||||
ELSE
|
||||
LDR R0,[R2,#TCB_SM_OFS] ; Load stack memory base
|
||||
MSR PSPLIM,R0 ; Set PSPLIM
|
||||
ENDIF
|
||||
|
||||
Sys_ContextRestore2
|
||||
LDR R0,[R2,#TCB_SP_OFS] ; Load SP
|
||||
ADDS R0,R0,#16 ; Adjust address
|
||||
LDMIA R0!,{R4-R7} ; Restore R8..R11
|
||||
MOV R8,R4
|
||||
MOV R9,R5
|
||||
MOV R10,R6
|
||||
MOV R11,R7
|
||||
MSR PSP,R0 ; Set PSP
|
||||
SUBS R0,R0,#32 ; Adjust address
|
||||
LDMIA R0!,{R4-R7} ; Restore R4..R7
|
||||
|
||||
Sys_ContextExit
|
||||
BX LR ; Exit from handler
|
||||
|
||||
ALIGN
|
||||
ENDP
|
||||
|
||||
|
||||
END
|
||||
@@ -0,0 +1,3 @@
|
||||
DOMAIN_NS EQU 1
|
||||
INCLUDE irq_armv8mbl.s
|
||||
END
|
||||
@@ -0,0 +1,308 @@
|
||||
;/*
|
||||
; * Copyright (c) 2016-2020 Arm Limited. All rights reserved.
|
||||
; *
|
||||
; * SPDX-License-Identifier: Apache-2.0
|
||||
; *
|
||||
; * Licensed under the Apache License, Version 2.0 (the License); you may
|
||||
; * not use this file except in compliance with the License.
|
||||
; * You may obtain a copy of the License at
|
||||
; *
|
||||
; * www.apache.org/licenses/LICENSE-2.0
|
||||
; *
|
||||
; * Unless required by applicable law or agreed to in writing, software
|
||||
; * distributed under the License is distributed on an AS IS BASIS, WITHOUT
|
||||
; * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
; * See the License for the specific language governing permissions and
|
||||
; * limitations under the License.
|
||||
; *
|
||||
; * -----------------------------------------------------------------------------
|
||||
; *
|
||||
; * Project: CMSIS-RTOS RTX
|
||||
; * Title: ARMv8M Mainline Exception handlers
|
||||
; *
|
||||
; * -----------------------------------------------------------------------------
|
||||
; */
|
||||
|
||||
|
||||
IF :LNOT::DEF:DOMAIN_NS
|
||||
DOMAIN_NS EQU 0
|
||||
ENDIF
|
||||
|
||||
IF ({FPU}="FPv5-SP") || ({FPU}="FPv5_D16")
|
||||
FPU_USED EQU 1
|
||||
ELSE
|
||||
FPU_USED EQU 0
|
||||
ENDIF
|
||||
|
||||
I_T_RUN_OFS EQU 20 ; osRtxInfo.thread.run offset
|
||||
TCB_SM_OFS EQU 48 ; TCB.stack_mem offset
|
||||
TCB_SP_OFS EQU 56 ; TCB.SP offset
|
||||
TCB_SF_OFS EQU 34 ; TCB.stack_frame offset
|
||||
TCB_TZM_OFS EQU 64 ; TCB.tz_memory offset
|
||||
|
||||
|
||||
PRESERVE8
|
||||
THUMB
|
||||
|
||||
|
||||
AREA |.constdata|, DATA, READONLY
|
||||
EXPORT irqRtxLib
|
||||
irqRtxLib DCB 0 ; Non weak library reference
|
||||
|
||||
|
||||
AREA |.text|, CODE, READONLY
|
||||
|
||||
|
||||
SVC_Handler PROC
|
||||
EXPORT SVC_Handler
|
||||
IMPORT osRtxUserSVC
|
||||
IMPORT osRtxInfo
|
||||
IF :DEF:MPU_LOAD
|
||||
IMPORT osRtxMpuLoad
|
||||
ENDIF
|
||||
IF DOMAIN_NS = 1
|
||||
IMPORT TZ_LoadContext_S
|
||||
IMPORT TZ_StoreContext_S
|
||||
ENDIF
|
||||
|
||||
TST LR,#0x04 ; Determine return stack from EXC_RETURN bit 2
|
||||
ITE EQ
|
||||
MRSEQ R0,MSP ; Get MSP if return stack is MSP
|
||||
MRSNE R0,PSP ; Get PSP if return stack is PSP
|
||||
|
||||
LDR R1,[R0,#24] ; Load saved PC from stack
|
||||
LDRB R1,[R1,#-2] ; Load SVC number
|
||||
CMP R1,#0
|
||||
BNE SVC_User ; Branch if not SVC 0
|
||||
|
||||
PUSH {R0,LR} ; Save SP and EXC_RETURN
|
||||
LDM R0,{R0-R3,R12} ; Load function parameters and address from stack
|
||||
BLX R12 ; Call service function
|
||||
POP {R12,LR} ; Restore SP and EXC_RETURN
|
||||
STM R12,{R0-R1} ; Store function return values
|
||||
|
||||
SVC_Context
|
||||
LDR R3,=osRtxInfo+I_T_RUN_OFS; Load address of osRtxInfo.run
|
||||
LDM R3,{R1,R2} ; Load osRtxInfo.thread.run: curr & next
|
||||
CMP R1,R2 ; Check if thread switch is required
|
||||
IT EQ
|
||||
BXEQ LR ; Exit when threads are the same
|
||||
|
||||
IF FPU_USED = 1
|
||||
CBNZ R1,SVC_ContextSave ; Branch if running thread is not deleted
|
||||
TST LR,#0x10 ; Check if extended stack frame
|
||||
BNE SVC_ContextSwitch
|
||||
LDR R1,=0xE000EF34 ; FPCCR Address
|
||||
LDR R0,[R1] ; Load FPCCR
|
||||
BIC R0,R0,#1 ; Clear LSPACT (Lazy state)
|
||||
STR R0,[R1] ; Store FPCCR
|
||||
B SVC_ContextSwitch
|
||||
ELSE
|
||||
CBZ R1,SVC_ContextSwitch ; Branch if running thread is deleted
|
||||
ENDIF
|
||||
|
||||
SVC_ContextSave
|
||||
IF DOMAIN_NS = 1
|
||||
LDR R0,[R1,#TCB_TZM_OFS] ; Load TrustZone memory identifier
|
||||
CBZ R0,SVC_ContextSave1 ; Branch if there is no secure context
|
||||
PUSH {R1,R2,R3,LR} ; Save registers and EXC_RETURN
|
||||
BL TZ_StoreContext_S ; Store secure context
|
||||
POP {R1,R2,R3,LR} ; Restore registers and EXC_RETURN
|
||||
ENDIF
|
||||
|
||||
SVC_ContextSave1
|
||||
MRS R0,PSP ; Get PSP
|
||||
STMDB R0!,{R4-R11} ; Save R4..R11
|
||||
IF FPU_USED = 1
|
||||
TST LR,#0x10 ; Check if extended stack frame
|
||||
IT EQ
|
||||
VSTMDBEQ R0!,{S16-S31} ; Save VFP S16.S31
|
||||
ENDIF
|
||||
|
||||
SVC_ContextSave2
|
||||
STR R0,[R1,#TCB_SP_OFS] ; Store SP
|
||||
STRB LR,[R1,#TCB_SF_OFS] ; Store stack frame information
|
||||
|
||||
SVC_ContextSwitch
|
||||
STR R2,[R3] ; osRtxInfo.thread.run: curr = next
|
||||
|
||||
IF :DEF:MPU_LOAD
|
||||
PUSH {R2,R3} ; Save registers
|
||||
MOV R0,R2 ; osRtxMpuLoad parameter
|
||||
BL osRtxMpuLoad ; Load MPU for next thread
|
||||
POP {R2,R3} ; Restore registers
|
||||
ENDIF
|
||||
|
||||
SVC_ContextRestore
|
||||
IF DOMAIN_NS = 1
|
||||
LDR R0,[R2,#TCB_TZM_OFS] ; Load TrustZone memory identifier
|
||||
CBZ R0,SVC_ContextRestore1 ; Branch if there is no secure context
|
||||
PUSH {R2,R3} ; Save registers
|
||||
BL TZ_LoadContext_S ; Load secure context
|
||||
POP {R2,R3} ; Restore registers
|
||||
ENDIF
|
||||
|
||||
SVC_ContextRestore1
|
||||
LDR R0,[R2,#TCB_SM_OFS] ; Load stack memory base
|
||||
LDRB R1,[R2,#TCB_SF_OFS] ; Load stack frame information
|
||||
MSR PSPLIM,R0 ; Set PSPLIM
|
||||
LDR R0,[R2,#TCB_SP_OFS] ; Load SP
|
||||
ORR LR,R1,#0xFFFFFF00 ; Set EXC_RETURN
|
||||
|
||||
IF DOMAIN_NS = 1
|
||||
TST LR,#0x40 ; Check domain of interrupted thread
|
||||
BNE SVC_ContextRestore2 ; Branch if secure
|
||||
ENDIF
|
||||
|
||||
IF FPU_USED = 1
|
||||
TST LR,#0x10 ; Check if extended stack frame
|
||||
IT EQ
|
||||
VLDMIAEQ R0!,{S16-S31} ; Restore VFP S16..S31
|
||||
ENDIF
|
||||
LDMIA R0!,{R4-R11} ; Restore R4..R11
|
||||
|
||||
SVC_ContextRestore2
|
||||
MSR PSP,R0 ; Set PSP
|
||||
|
||||
SVC_Exit
|
||||
BX LR ; Exit from handler
|
||||
|
||||
SVC_User
|
||||
LDR R2,=osRtxUserSVC ; Load address of SVC table
|
||||
LDR R3,[R2] ; Load SVC maximum number
|
||||
CMP R1,R3 ; Check SVC number range
|
||||
BHI SVC_Exit ; Branch if out of range
|
||||
|
||||
PUSH {R0,LR} ; Save SP and EXC_RETURN
|
||||
LDR R12,[R2,R1,LSL #2] ; Load address of SVC function
|
||||
LDM R0,{R0-R3} ; Load function parameters from stack
|
||||
BLX R12 ; Call service function
|
||||
POP {R12,LR} ; Restore SP and EXC_RETURN
|
||||
STR R0,[R12] ; Store function return value
|
||||
|
||||
BX LR ; Return from handler
|
||||
|
||||
ALIGN
|
||||
ENDP
|
||||
|
||||
|
||||
PendSV_Handler PROC
|
||||
EXPORT PendSV_Handler
|
||||
IMPORT osRtxPendSV_Handler
|
||||
|
||||
PUSH {R0,LR} ; Save EXC_RETURN
|
||||
BL osRtxPendSV_Handler ; Call osRtxPendSV_Handler
|
||||
POP {R0,LR} ; Restore EXC_RETURN
|
||||
B Sys_Context
|
||||
|
||||
ALIGN
|
||||
ENDP
|
||||
|
||||
|
||||
SysTick_Handler PROC
|
||||
EXPORT SysTick_Handler
|
||||
IMPORT osRtxTick_Handler
|
||||
|
||||
PUSH {R0,LR} ; Save EXC_RETURN
|
||||
BL osRtxTick_Handler ; Call osRtxTick_Handler
|
||||
POP {R0,LR} ; Restore EXC_RETURN
|
||||
B Sys_Context
|
||||
|
||||
ALIGN
|
||||
ENDP
|
||||
|
||||
|
||||
Sys_Context PROC
|
||||
EXPORT Sys_Context
|
||||
IMPORT osRtxInfo
|
||||
IF :DEF:MPU_LOAD
|
||||
IMPORT osRtxMpuLoad
|
||||
ENDIF
|
||||
IF DOMAIN_NS = 1
|
||||
IMPORT TZ_LoadContext_S
|
||||
IMPORT TZ_StoreContext_S
|
||||
ENDIF
|
||||
|
||||
LDR R3,=osRtxInfo+I_T_RUN_OFS; Load address of osRtxInfo.run
|
||||
LDM R3,{R1,R2} ; Load osRtxInfo.thread.run: curr & next
|
||||
CMP R1,R2 ; Check if thread switch is required
|
||||
IT EQ
|
||||
BXEQ LR ; Exit when threads are the same
|
||||
|
||||
Sys_ContextSave
|
||||
IF DOMAIN_NS = 1
|
||||
LDR R0,[R1,#TCB_TZM_OFS] ; Load TrustZone memory identifier
|
||||
CBZ R0,Sys_ContextSave1 ; Branch if there is no secure context
|
||||
PUSH {R1,R2,R3,LR} ; Save registers and EXC_RETURN
|
||||
BL TZ_StoreContext_S ; Store secure context
|
||||
POP {R1,R2,R3,LR} ; Restore registers and EXC_RETURN
|
||||
|
||||
Sys_ContextSave1
|
||||
TST LR,#0x40 ; Check domain of interrupted thread
|
||||
IT NE
|
||||
MRSNE R0,PSP ; Get PSP
|
||||
BNE Sys_ContextSave3 ; Branch if secure
|
||||
ENDIF
|
||||
|
||||
Sys_ContextSave2
|
||||
MRS R0,PSP ; Get PSP
|
||||
STMDB R0!,{R4-R11} ; Save R4..R11
|
||||
IF FPU_USED = 1
|
||||
TST LR,#0x10 ; Check if extended stack frame
|
||||
IT EQ
|
||||
VSTMDBEQ R0!,{S16-S31} ; Save VFP S16.S31
|
||||
ENDIF
|
||||
|
||||
Sys_ContextSave3
|
||||
STR R0,[R1,#TCB_SP_OFS] ; Store SP
|
||||
STRB LR,[R1,#TCB_SF_OFS] ; Store stack frame information
|
||||
|
||||
Sys_ContextSwitch
|
||||
STR R2,[R3] ; osRtxInfo.run: curr = next
|
||||
|
||||
IF :DEF:MPU_LOAD
|
||||
PUSH {R2,R3} ; Save registers
|
||||
MOV R0,R2 ; osRtxMpuLoad parameter
|
||||
BL osRtxMpuLoad ; Load MPU for next thread
|
||||
POP {R2,R3} ; Restore registers
|
||||
ENDIF
|
||||
|
||||
Sys_ContextRestore
|
||||
IF DOMAIN_NS = 1
|
||||
LDR R0,[R2,#TCB_TZM_OFS] ; Load TrustZone memory identifier
|
||||
CBZ R0,Sys_ContextRestore1 ; Branch if there is no secure context
|
||||
PUSH {R2,R3} ; Save registers
|
||||
BL TZ_LoadContext_S ; Load secure context
|
||||
POP {R2,R3} ; Restore registers
|
||||
ENDIF
|
||||
|
||||
Sys_ContextRestore1
|
||||
LDR R0,[R2,#TCB_SM_OFS] ; Load stack memory base
|
||||
LDRB R1,[R2,#TCB_SF_OFS] ; Load stack frame information
|
||||
MSR PSPLIM,R0 ; Set PSPLIM
|
||||
LDR R0,[R2,#TCB_SP_OFS] ; Load SP
|
||||
ORR LR,R1,#0xFFFFFF00 ; Set EXC_RETURN
|
||||
|
||||
IF DOMAIN_NS = 1
|
||||
TST LR,#0x40 ; Check domain of interrupted thread
|
||||
BNE Sys_ContextRestore2 ; Branch if secure
|
||||
ENDIF
|
||||
|
||||
IF FPU_USED = 1
|
||||
TST LR,#0x10 ; Check if extended stack frame
|
||||
IT EQ
|
||||
VLDMIAEQ R0!,{S16-S31} ; Restore VFP S16..S31
|
||||
ENDIF
|
||||
LDMIA R0!,{R4-R11} ; Restore R4..R11
|
||||
|
||||
Sys_ContextRestore2
|
||||
MSR PSP,R0 ; Set PSP
|
||||
|
||||
Sys_ContextExit
|
||||
BX LR ; Exit from handler
|
||||
|
||||
ALIGN
|
||||
ENDP
|
||||
|
||||
|
||||
END
|
||||
@@ -0,0 +1,3 @@
|
||||
DOMAIN_NS EQU 1
|
||||
INCLUDE irq_armv8mml.s
|
||||
END
|
||||
@@ -0,0 +1,458 @@
|
||||
;/*
|
||||
; * Copyright (c) 2013-2018 Arm Limited. All rights reserved.
|
||||
; *
|
||||
; * SPDX-License-Identifier: Apache-2.0
|
||||
; *
|
||||
; * Licensed under the Apache License, Version 2.0 (the License); you may
|
||||
; * not use this file except in compliance with the License.
|
||||
; * You may obtain a copy of the License at
|
||||
; *
|
||||
; * www.apache.org/licenses/LICENSE-2.0
|
||||
; *
|
||||
; * Unless required by applicable law or agreed to in writing, software
|
||||
; * distributed under the License is distributed on an AS IS BASIS, WITHOUT
|
||||
; * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
; * See the License for the specific language governing permissions and
|
||||
; * limitations under the License.
|
||||
; *
|
||||
; * -----------------------------------------------------------------------------
|
||||
; *
|
||||
; * Project: CMSIS-RTOS RTX
|
||||
; * Title: Cortex-A Exception handlers
|
||||
; *
|
||||
; * -----------------------------------------------------------------------------
|
||||
; */
|
||||
|
||||
MODE_FIQ EQU 0x11
|
||||
MODE_IRQ EQU 0x12
|
||||
MODE_SVC EQU 0x13
|
||||
MODE_ABT EQU 0x17
|
||||
MODE_UND EQU 0x1B
|
||||
|
||||
CPSR_BIT_T EQU 0x20
|
||||
|
||||
K_STATE_RUNNING EQU 2 ; osKernelState_t::osKernelRunning
|
||||
I_K_STATE_OFS EQU 8 ; osRtxInfo.kernel.state offset
|
||||
I_TICK_IRQN_OFS EQU 16 ; osRtxInfo.tick_irqn offset
|
||||
I_T_RUN_OFS EQU 20 ; osRtxInfo.thread.run offset
|
||||
TCB_SP_FRAME EQU 34 ; osRtxThread_t.stack_frame offset
|
||||
TCB_SP_OFS EQU 56 ; osRtxThread_t.sp offset
|
||||
|
||||
|
||||
PRESERVE8
|
||||
ARM
|
||||
|
||||
|
||||
AREA |.constdata|, DATA, READONLY
|
||||
EXPORT irqRtxLib
|
||||
irqRtxLib DCB 0 ; Non weak library reference
|
||||
|
||||
|
||||
AREA |.data|, DATA, READWRITE
|
||||
EXPORT IRQ_PendSV
|
||||
IRQ_NestLevel DCD 0 ; IRQ nesting level counter
|
||||
IRQ_PendSV DCB 0 ; Pending SVC flag
|
||||
|
||||
|
||||
AREA |.text|, CODE, READONLY
|
||||
|
||||
|
||||
Undef_Handler\
|
||||
PROC
|
||||
EXPORT Undef_Handler
|
||||
IMPORT CUndefHandler
|
||||
|
||||
SRSFD SP!, #MODE_UND
|
||||
PUSH {R0-R4, R12} ; Save APCS corruptible registers to UND mode stack
|
||||
|
||||
MRS R0, SPSR
|
||||
TST R0, #CPSR_BIT_T ; Check mode
|
||||
MOVEQ R1, #4 ; R1 = 4 ARM mode
|
||||
MOVNE R1, #2 ; R1 = 2 Thumb mode
|
||||
SUB R0, LR, R1
|
||||
LDREQ R0, [R0] ; ARM mode - R0 points to offending instruction
|
||||
BEQ Undef_Cont
|
||||
|
||||
; Thumb instruction
|
||||
; Determine if it is a 32-bit Thumb instruction
|
||||
LDRH R0, [R0]
|
||||
MOV R2, #0x1C
|
||||
CMP R2, R0, LSR #11
|
||||
BHS Undef_Cont ; 16-bit Thumb instruction
|
||||
|
||||
; 32-bit Thumb instruction. Unaligned - reconstruct the offending instruction
|
||||
LDRH R2, [LR]
|
||||
ORR R0, R2, R0, LSL #16
|
||||
Undef_Cont
|
||||
MOV R2, LR ; Set LR to third argument
|
||||
|
||||
AND R12, SP, #4 ; Ensure stack is 8-byte aligned
|
||||
SUB SP, SP, R12 ; Adjust stack
|
||||
PUSH {R12, LR} ; Store stack adjustment and dummy LR
|
||||
|
||||
; R0 =Offending instruction, R1 =2(Thumb) or =4(ARM)
|
||||
BL CUndefHandler
|
||||
|
||||
POP {R12, LR} ; Get stack adjustment & discard dummy LR
|
||||
ADD SP, SP, R12 ; Unadjust stack
|
||||
|
||||
LDR LR, [SP, #24] ; Restore stacked LR and possibly adjust for retry
|
||||
SUB LR, LR, R0
|
||||
LDR R0, [SP, #28] ; Restore stacked SPSR
|
||||
MSR SPSR_CXSF, R0
|
||||
CLREX ; Clear exclusive monitor
|
||||
POP {R0-R4, R12} ; Restore stacked APCS registers
|
||||
ADD SP, SP, #8 ; Adjust SP for already-restored banked registers
|
||||
MOVS PC, LR
|
||||
|
||||
ENDP
|
||||
|
||||
|
||||
PAbt_Handler\
|
||||
PROC
|
||||
EXPORT PAbt_Handler
|
||||
IMPORT CPAbtHandler
|
||||
|
||||
SUB LR, LR, #4 ; Pre-adjust LR
|
||||
SRSFD SP!, #MODE_ABT ; Save LR and SPRS to ABT mode stack
|
||||
PUSH {R0-R4, R12} ; Save APCS corruptible registers to ABT mode stack
|
||||
MRC p15, 0, R0, c5, c0, 1 ; IFSR
|
||||
MRC p15, 0, R1, c6, c0, 2 ; IFAR
|
||||
|
||||
MOV R2, LR ; Set LR to third argument
|
||||
|
||||
AND R12, SP, #4 ; Ensure stack is 8-byte aligned
|
||||
SUB SP, SP, R12 ; Adjust stack
|
||||
PUSH {R12, LR} ; Store stack adjustment and dummy LR
|
||||
|
||||
BL CPAbtHandler
|
||||
|
||||
POP {R12, LR} ; Get stack adjustment & discard dummy LR
|
||||
ADD SP, SP, R12 ; Unadjust stack
|
||||
|
||||
CLREX ; Clear exclusive monitor
|
||||
POP {R0-R4, R12} ; Restore stack APCS registers
|
||||
RFEFD SP! ; Return from exception
|
||||
|
||||
ENDP
|
||||
|
||||
|
||||
DAbt_Handler\
|
||||
PROC
|
||||
EXPORT DAbt_Handler
|
||||
IMPORT CDAbtHandler
|
||||
|
||||
SUB LR, LR, #8 ; Pre-adjust LR
|
||||
SRSFD SP!, #MODE_ABT ; Save LR and SPRS to ABT mode stack
|
||||
PUSH {R0-R4, R12} ; Save APCS corruptible registers to ABT mode stack
|
||||
MRC p15, 0, R0, c5, c0, 0 ; DFSR
|
||||
MRC p15, 0, R1, c6, c0, 0 ; DFAR
|
||||
|
||||
MOV R2, LR ; Set LR to third argument
|
||||
|
||||
AND R12, SP, #4 ; Ensure stack is 8-byte aligned
|
||||
SUB SP, SP, R12 ; Adjust stack
|
||||
PUSH {R12, LR} ; Store stack adjustment and dummy LR
|
||||
|
||||
BL CDAbtHandler
|
||||
|
||||
POP {R12, LR} ; Get stack adjustment & discard dummy LR
|
||||
ADD SP, SP, R12 ; Unadjust stack
|
||||
|
||||
CLREX ; Clear exclusive monitor
|
||||
POP {R0-R4, R12} ; Restore stacked APCS registers
|
||||
RFEFD SP! ; Return from exception
|
||||
|
||||
ENDP
|
||||
|
||||
|
||||
IRQ_Handler\
|
||||
PROC
|
||||
EXPORT IRQ_Handler
|
||||
IMPORT IRQ_GetActiveIRQ
|
||||
IMPORT IRQ_GetHandler
|
||||
IMPORT IRQ_EndOfInterrupt
|
||||
|
||||
SUB LR, LR, #4 ; Pre-adjust LR
|
||||
SRSFD SP!, #MODE_SVC ; Save LR_irq and SPSR_irq on to the SVC stack
|
||||
CPS #MODE_SVC ; Change to SVC mode
|
||||
PUSH {R0-R3, R12, LR} ; Save APCS corruptible registers
|
||||
|
||||
LDR R0, =IRQ_NestLevel
|
||||
LDR R1, [R0]
|
||||
ADD R1, R1, #1 ; Increment IRQ nesting level
|
||||
STR R1, [R0]
|
||||
|
||||
MOV R3, SP ; Move SP into R3
|
||||
AND R3, R3, #4 ; Get stack adjustment to ensure 8-byte alignment
|
||||
SUB SP, SP, R3 ; Adjust stack
|
||||
PUSH {R3, R4} ; Store stack adjustment(R3) and user data(R4)
|
||||
|
||||
BLX IRQ_GetActiveIRQ ; Retrieve interrupt ID into R0
|
||||
MOV R4, R0 ; Move interrupt ID to R4
|
||||
|
||||
BLX IRQ_GetHandler ; Retrieve interrupt handler address for current ID
|
||||
CMP R0, #0 ; Check if handler address is 0
|
||||
BEQ IRQ_End ; If 0, end interrupt and return
|
||||
|
||||
CPSIE i ; Re-enable interrupts
|
||||
BLX R0 ; Call IRQ handler
|
||||
CPSID i ; Disable interrupts
|
||||
|
||||
IRQ_End
|
||||
MOV R0, R4 ; Move interrupt ID to R0
|
||||
BLX IRQ_EndOfInterrupt ; Signal end of interrupt
|
||||
|
||||
POP {R3, R4} ; Restore stack adjustment(R3) and user data(R4)
|
||||
ADD SP, SP, R3 ; Unadjust stack
|
||||
|
||||
BL osRtxContextSwitch ; Continue in context switcher
|
||||
|
||||
LDR R0, =IRQ_NestLevel
|
||||
LDR R1, [R0]
|
||||
SUBS R1, R1, #1 ; Decrement IRQ nesting level
|
||||
STR R1, [R0]
|
||||
|
||||
CLREX ; Clear exclusive monitor for interrupted code
|
||||
POP {R0-R3, R12, LR} ; Restore stacked APCS registers
|
||||
RFEFD SP! ; Return from IRQ handler
|
||||
|
||||
ENDP
|
||||
|
||||
|
||||
SVC_Handler\
|
||||
PROC
|
||||
EXPORT SVC_Handler
|
||||
IMPORT IRQ_Disable
|
||||
IMPORT IRQ_Enable
|
||||
IMPORT osRtxUserSVC
|
||||
IMPORT osRtxInfo
|
||||
|
||||
SRSFD SP!, #MODE_SVC ; Store SPSR_svc and LR_svc onto SVC stack
|
||||
PUSH {R12, LR}
|
||||
|
||||
MRS R12, SPSR ; Load SPSR
|
||||
TST R12, #CPSR_BIT_T ; Thumb bit set?
|
||||
LDRHNE R12, [LR,#-2] ; Thumb: load halfword
|
||||
BICNE R12, R12, #0xFF00 ; extract SVC number
|
||||
LDREQ R12, [LR,#-4] ; ARM: load word
|
||||
BICEQ R12, R12, #0xFF000000 ; extract SVC number
|
||||
CMP R12, #0 ; Compare SVC number
|
||||
BNE SVC_User ; Branch if User SVC
|
||||
|
||||
PUSH {R0-R3}
|
||||
|
||||
LDR R0, =IRQ_NestLevel
|
||||
LDR R1, [R0]
|
||||
ADD R1, R1, #1 ; Increment IRQ nesting level
|
||||
STR R1, [R0]
|
||||
|
||||
LDR R0, =osRtxInfo
|
||||
LDR R1, [R0, #I_K_STATE_OFS] ; Load RTX5 kernel state
|
||||
CMP R1, #K_STATE_RUNNING ; Check osKernelRunning
|
||||
BLT SVC_FuncCall ; Continue if kernel is not running
|
||||
LDR R0, [R0, #I_TICK_IRQN_OFS] ; Load OS Tick irqn
|
||||
BLX IRQ_Disable ; Disable OS Tick interrupt
|
||||
SVC_FuncCall
|
||||
POP {R0-R3}
|
||||
|
||||
LDR R12, [SP] ; Reload R12 from stack
|
||||
|
||||
CPSIE i ; Re-enable interrupts
|
||||
BLX R12 ; Branch to SVC function
|
||||
CPSID i ; Disable interrupts
|
||||
|
||||
SUB SP, SP, #4
|
||||
STM SP, {SP}^ ; Store SP_usr onto stack
|
||||
POP {R12} ; Pop SP_usr into R12
|
||||
SUB R12, R12, #16 ; Adjust pointer to SP_usr
|
||||
LDMDB R12, {R2,R3} ; Load return values from SVC function
|
||||
PUSH {R0-R3} ; Push return values to stack
|
||||
|
||||
LDR R0, =osRtxInfo
|
||||
LDR R1, [R0, #I_K_STATE_OFS] ; Load RTX5 kernel state
|
||||
CMP R1, #K_STATE_RUNNING ; Check osKernelRunning
|
||||
BLT SVC_ContextCheck ; Continue if kernel is not running
|
||||
LDR R0, [R0, #I_TICK_IRQN_OFS] ; Load OS Tick irqn
|
||||
BLX IRQ_Enable ; Enable OS Tick interrupt
|
||||
|
||||
SVC_ContextCheck
|
||||
BL osRtxContextSwitch ; Continue in context switcher
|
||||
|
||||
LDR R0, =IRQ_NestLevel
|
||||
LDR R1, [R0]
|
||||
SUB R1, R1, #1 ; Decrement IRQ nesting level
|
||||
STR R1, [R0]
|
||||
|
||||
CLREX ; Clear exclusive monitor
|
||||
POP {R0-R3, R12, LR} ; Restore stacked APCS registers
|
||||
RFEFD SP! ; Return from exception
|
||||
|
||||
SVC_User
|
||||
PUSH {R4, R5}
|
||||
LDR R5,=osRtxUserSVC ; Load address of SVC table
|
||||
LDR R4,[R5] ; Load SVC maximum number
|
||||
CMP R12,R4 ; Check SVC number range
|
||||
BHI SVC_Done ; Branch if out of range
|
||||
LDR R12,[R5,R12,LSL #2] ; Load SVC Function Address
|
||||
BLX R12 ; Call SVC Function
|
||||
SVC_Done
|
||||
CLREX ; Clear exclusive monitor
|
||||
POP {R4, R5, R12, LR}
|
||||
RFEFD SP! ; Return from exception
|
||||
|
||||
ENDP
|
||||
|
||||
|
||||
osRtxContextSwitch\
|
||||
PROC
|
||||
EXPORT osRtxContextSwitch
|
||||
IMPORT osRtxPendSV_Handler
|
||||
IMPORT osRtxInfo
|
||||
IMPORT IRQ_Disable
|
||||
IMPORT IRQ_Enable
|
||||
|
||||
PUSH {LR}
|
||||
|
||||
; Check interrupt nesting level
|
||||
LDR R0, =IRQ_NestLevel
|
||||
LDR R1, [R0] ; Load IRQ nest level
|
||||
CMP R1, #1
|
||||
BNE osRtxContextExit ; Nesting interrupts, exit context switcher
|
||||
|
||||
LDR R12, =osRtxInfo+I_T_RUN_OFS ; Load address of osRtxInfo.run
|
||||
LDM R12, {R0, R1} ; Load osRtxInfo.thread.run: curr & next
|
||||
LDR R2, =IRQ_PendSV ; Load address of IRQ_PendSV flag
|
||||
LDRB R3, [R2] ; Load PendSV flag
|
||||
|
||||
CMP R0, R1 ; Check if context switch is required
|
||||
BNE osRtxContextCheck ; Not equal, check if context save required
|
||||
CMP R3, #1 ; Compare IRQ_PendSV value
|
||||
BNE osRtxContextExit ; No post processing (and no context switch requested)
|
||||
|
||||
osRtxContextCheck
|
||||
STR R1, [R12] ; Store run.next as run.curr
|
||||
; R0 = curr, R1 = next, R2 = &IRQ_PendSV, R3 = IRQ_PendSV, R12 = &osRtxInfo.thread.run
|
||||
PUSH {R1-R3, R12}
|
||||
|
||||
CMP R0, #0 ; Is osRtxInfo.thread.run.curr == 0
|
||||
BEQ osRtxPostProcess ; Current deleted, skip context save
|
||||
|
||||
osRtxContextSave
|
||||
MOV LR, R0 ; Move &osRtxInfo.thread.run.curr to LR
|
||||
MOV R0, SP ; Move SP_svc into R0
|
||||
ADD R0, R0, #20 ; Adjust SP_svc to R0 of the basic frame
|
||||
SUB SP, SP, #4
|
||||
STM SP, {SP}^ ; Save SP_usr to current stack
|
||||
POP {R1} ; Pop SP_usr into R1
|
||||
|
||||
SUB R1, R1, #64 ; Adjust SP_usr to R4 of the basic frame
|
||||
STMIA R1!, {R4-R11} ; Save R4-R11 to user stack
|
||||
LDMIA R0!, {R4-R8} ; Load stacked R0-R3,R12 into R4-R8
|
||||
STMIA R1!, {R4-R8} ; Store them to user stack
|
||||
STM R1, {LR}^ ; Store LR_usr directly
|
||||
ADD R1, R1, #4 ; Adjust user sp to PC
|
||||
LDMIB R0!, {R5-R6} ; Load current PC, CPSR
|
||||
STMIA R1!, {R5-R6} ; Restore user PC and CPSR
|
||||
|
||||
SUB R1, R1, #64 ; Adjust SP_usr to stacked R4
|
||||
|
||||
; Check if VFP state need to be saved
|
||||
MRC p15, 0, R2, c1, c0, 2 ; VFP/NEON access enabled? (CPACR)
|
||||
AND R2, R2, #0x00F00000
|
||||
CMP R2, #0x00F00000
|
||||
BNE osRtxContextSave1 ; Continue, no VFP
|
||||
|
||||
VMRS R2, FPSCR
|
||||
STMDB R1!, {R2,R12} ; Push FPSCR, maintain 8-byte alignment
|
||||
|
||||
VSTMDB R1!, {D0-D15} ; Save D0-D15
|
||||
IF {TARGET_FEATURE_EXTENSION_REGISTER_COUNT} == 32
|
||||
VSTMDB R1!, {D16-D31} ; Save D16-D31
|
||||
ENDIF
|
||||
|
||||
LDRB R2, [LR, #TCB_SP_FRAME] ; Load osRtxInfo.thread.run.curr frame info
|
||||
IF {TARGET_FEATURE_EXTENSION_REGISTER_COUNT} == 32
|
||||
ORR R2, R2, #4 ; NEON state
|
||||
ELSE
|
||||
ORR R2, R2, #2 ; VFP state
|
||||
ENDIF
|
||||
STRB R2, [LR, #TCB_SP_FRAME] ; Store VFP/NEON state
|
||||
|
||||
osRtxContextSave1
|
||||
STR R1, [LR, #TCB_SP_OFS] ; Store user sp to osRtxInfo.thread.run.curr
|
||||
|
||||
osRtxPostProcess
|
||||
; RTX IRQ post processing check
|
||||
POP {R8-R11} ; Pop R8 = run.next, R9 = &IRQ_PendSV, R10 = IRQ_PendSV, R11 = &osRtxInfo.thread.run
|
||||
CMP R10, #1 ; Compare PendSV value
|
||||
BNE osRtxContextRestore ; Skip post processing if not pending
|
||||
|
||||
MOV R4, SP ; Move SP_svc into R4
|
||||
AND R4, R4, #4 ; Get stack adjustment to ensure 8-byte alignment
|
||||
SUB SP, SP, R4 ; Adjust stack
|
||||
|
||||
; Disable OS Tick
|
||||
LDR R5, =osRtxInfo ; Load address of osRtxInfo
|
||||
LDR R5, [R5, #I_TICK_IRQN_OFS] ; Load OS Tick irqn
|
||||
MOV R0, R5 ; Set it as function parameter
|
||||
BLX IRQ_Disable ; Disable OS Tick interrupt
|
||||
MOV R6, #0 ; Set PendSV clear value
|
||||
B osRtxPendCheck
|
||||
osRtxPendExec
|
||||
STRB R6, [R9] ; Clear PendSV flag
|
||||
CPSIE i ; Re-enable interrupts
|
||||
BLX osRtxPendSV_Handler ; Post process pending objects
|
||||
CPSID i ; Disable interrupts
|
||||
osRtxPendCheck
|
||||
LDR R8, [R11, #4] ; Load osRtxInfo.thread.run.next
|
||||
STR R8, [R11] ; Store run.next as run.curr
|
||||
LDRB R0, [R9] ; Load PendSV flag
|
||||
CMP R0, #1 ; Compare PendSV value
|
||||
BEQ osRtxPendExec ; Branch to PendExec if PendSV is set
|
||||
|
||||
; Re-enable OS Tick
|
||||
MOV R0, R5 ; Restore irqn as function parameter
|
||||
BLX IRQ_Enable ; Enable OS Tick interrupt
|
||||
|
||||
ADD SP, SP, R4 ; Restore stack adjustment
|
||||
|
||||
osRtxContextRestore
|
||||
LDR LR, [R8, #TCB_SP_OFS] ; Load next osRtxThread_t.sp
|
||||
LDRB R2, [R8, #TCB_SP_FRAME] ; Load next osRtxThread_t.stack_frame
|
||||
|
||||
ANDS R2, R2, #0x6 ; Check stack frame for VFP context
|
||||
MRC p15, 0, R2, c1, c0, 2 ; Read CPACR
|
||||
ANDEQ R2, R2, #0xFF0FFFFF ; VFP/NEON state not stacked, disable VFP/NEON
|
||||
ORRNE R2, R2, #0x00F00000 ; VFP/NEON state is stacked, enable VFP/NEON
|
||||
MCR p15, 0, R2, c1, c0, 2 ; Write CPACR
|
||||
BEQ osRtxContextRestore1 ; No VFP
|
||||
ISB ; Sync if VFP was enabled
|
||||
IF {TARGET_FEATURE_EXTENSION_REGISTER_COUNT} == 32
|
||||
VLDMIA LR!, {D16-D31} ; Restore D16-D31
|
||||
ENDIF
|
||||
VLDMIA LR!, {D0-D15} ; Restore D0-D15
|
||||
LDR R2, [LR]
|
||||
VMSR FPSCR, R2 ; Restore FPSCR
|
||||
ADD LR, LR, #8 ; Adjust sp pointer to R4
|
||||
|
||||
osRtxContextRestore1
|
||||
LDMIA LR!, {R4-R11} ; Restore R4-R11
|
||||
ADD R12, LR, #32 ; Adjust sp and save it into R12
|
||||
PUSH {R12} ; Push sp onto stack
|
||||
LDM SP, {SP}^ ; Restore SP_usr directly
|
||||
ADD SP, SP, #4 ; Adjust SP_svc
|
||||
LDMIA LR!, {R0-R3, R12} ; Load user registers R0-R3,R12
|
||||
STMIB SP!, {R0-R3, R12} ; Store them to SP_svc
|
||||
LDM LR, {LR}^ ; Restore LR_usr directly
|
||||
LDMIB LR!, {R0-R1} ; Load user registers PC,CPSR
|
||||
ADD SP, SP, #4
|
||||
STMIB SP!, {R0-R1} ; Store them to SP_svc
|
||||
SUB SP, SP, #32 ; Adjust SP_svc to stacked LR
|
||||
|
||||
osRtxContextExit
|
||||
POP {PC} ; Return
|
||||
|
||||
ENDP
|
||||
|
||||
END
|
||||
@@ -0,0 +1,174 @@
|
||||
;/*
|
||||
; * Copyright (c) 2013-2018 Arm Limited. All rights reserved.
|
||||
; *
|
||||
; * SPDX-License-Identifier: Apache-2.0
|
||||
; *
|
||||
; * Licensed under the Apache License, Version 2.0 (the License); you may
|
||||
; * not use this file except in compliance with the License.
|
||||
; * You may obtain a copy of the License at
|
||||
; *
|
||||
; * www.apache.org/licenses/LICENSE-2.0
|
||||
; *
|
||||
; * Unless required by applicable law or agreed to in writing, software
|
||||
; * distributed under the License is distributed on an AS IS BASIS, WITHOUT
|
||||
; * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
; * See the License for the specific language governing permissions and
|
||||
; * limitations under the License.
|
||||
; *
|
||||
; * -----------------------------------------------------------------------------
|
||||
; *
|
||||
; * Project: CMSIS-RTOS RTX
|
||||
; * Title: Cortex-M0 Exception handlers
|
||||
; *
|
||||
; * -----------------------------------------------------------------------------
|
||||
; */
|
||||
|
||||
|
||||
I_T_RUN_OFS EQU 20 ; osRtxInfo.thread.run offset
|
||||
TCB_SP_OFS EQU 56 ; TCB.SP offset
|
||||
|
||||
|
||||
PRESERVE8
|
||||
THUMB
|
||||
|
||||
|
||||
AREA |.constdata|, DATA, READONLY
|
||||
EXPORT irqRtxLib
|
||||
irqRtxLib DCB 0 ; Non weak library reference
|
||||
|
||||
|
||||
AREA |.text|, CODE, READONLY
|
||||
|
||||
|
||||
SVC_Handler PROC
|
||||
EXPORT SVC_Handler
|
||||
IMPORT osRtxUserSVC
|
||||
IMPORT osRtxInfo
|
||||
IF :DEF:MPU_LOAD
|
||||
IMPORT osRtxMpuLoad
|
||||
ENDIF
|
||||
|
||||
MOV R0,LR
|
||||
LSRS R0,R0,#3 ; Determine return stack from EXC_RETURN bit 2
|
||||
BCC SVC_MSP ; Branch if return stack is MSP
|
||||
MRS R0,PSP ; Get PSP
|
||||
|
||||
SVC_Number
|
||||
LDR R1,[R0,#24] ; Load saved PC from stack
|
||||
SUBS R1,R1,#2 ; Point to SVC instruction
|
||||
LDRB R1,[R1] ; Load SVC number
|
||||
CMP R1,#0
|
||||
BNE SVC_User ; Branch if not SVC 0
|
||||
|
||||
PUSH {R0,LR} ; Save SP and EXC_RETURN
|
||||
LDMIA R0,{R0-R3} ; Load function parameters from stack
|
||||
BLX R7 ; Call service function
|
||||
POP {R2,R3} ; Restore SP and EXC_RETURN
|
||||
STMIA R2!,{R0-R1} ; Store function return values
|
||||
MOV LR,R3 ; Set EXC_RETURN
|
||||
|
||||
SVC_Context
|
||||
LDR R3,=osRtxInfo+I_T_RUN_OFS; Load address of osRtxInfo.run
|
||||
LDMIA R3!,{R1,R2} ; Load osRtxInfo.thread.run: curr & next
|
||||
CMP R1,R2 ; Check if thread switch is required
|
||||
BEQ SVC_Exit ; Branch when threads are the same
|
||||
|
||||
CMP R1,#0
|
||||
BEQ SVC_ContextSwitch ; Branch if running thread is deleted
|
||||
|
||||
SVC_ContextSave
|
||||
MRS R0,PSP ; Get PSP
|
||||
SUBS R0,R0,#32 ; Calculate SP
|
||||
STR R0,[R1,#TCB_SP_OFS] ; Store SP
|
||||
STMIA R0!,{R4-R7} ; Save R4..R7
|
||||
MOV R4,R8
|
||||
MOV R5,R9
|
||||
MOV R6,R10
|
||||
MOV R7,R11
|
||||
STMIA R0!,{R4-R7} ; Save R8..R11
|
||||
|
||||
SVC_ContextSwitch
|
||||
SUBS R3,R3,#8 ; Adjust address
|
||||
STR R2,[R3] ; osRtxInfo.thread.run: curr = next
|
||||
|
||||
IF :DEF:MPU_LOAD
|
||||
PUSH {R2,R3} ; Save registers
|
||||
MOV R0,R2 ; osRtxMpuLoad parameter
|
||||
BL osRtxMpuLoad ; Load MPU for next thread
|
||||
POP {R2,R3} ; Restore registers
|
||||
ENDIF
|
||||
|
||||
SVC_ContextRestore
|
||||
LDR R0,[R2,#TCB_SP_OFS] ; Load SP
|
||||
ADDS R0,R0,#16 ; Adjust address
|
||||
LDMIA R0!,{R4-R7} ; Restore R8..R11
|
||||
MOV R8,R4
|
||||
MOV R9,R5
|
||||
MOV R10,R6
|
||||
MOV R11,R7
|
||||
MSR PSP,R0 ; Set PSP
|
||||
SUBS R0,R0,#32 ; Adjust address
|
||||
LDMIA R0!,{R4-R7} ; Restore R4..R7
|
||||
|
||||
MOVS R0,#~0xFFFFFFFD
|
||||
MVNS R0,R0 ; Set EXC_RETURN value
|
||||
BX R0 ; Exit from handler
|
||||
|
||||
SVC_MSP
|
||||
MRS R0,MSP ; Get MSP
|
||||
B SVC_Number
|
||||
|
||||
SVC_Exit
|
||||
BX LR ; Exit from handler
|
||||
|
||||
SVC_User
|
||||
LDR R2,=osRtxUserSVC ; Load address of SVC table
|
||||
LDR R3,[R2] ; Load SVC maximum number
|
||||
CMP R1,R3 ; Check SVC number range
|
||||
BHI SVC_Exit ; Branch if out of range
|
||||
|
||||
PUSH {R0,LR} ; Save SP and EXC_RETURN
|
||||
LSLS R1,R1,#2
|
||||
LDR R3,[R2,R1] ; Load address of SVC function
|
||||
MOV R12,R3
|
||||
LDMIA R0,{R0-R3} ; Load function parameters from stack
|
||||
BLX R12 ; Call service function
|
||||
POP {R2,R3} ; Restore SP and EXC_RETURN
|
||||
STR R0,[R2] ; Store function return value
|
||||
MOV LR,R3 ; Set EXC_RETURN
|
||||
|
||||
BX LR ; Return from handler
|
||||
|
||||
ALIGN
|
||||
ENDP
|
||||
|
||||
|
||||
PendSV_Handler PROC
|
||||
EXPORT PendSV_Handler
|
||||
IMPORT osRtxPendSV_Handler
|
||||
|
||||
PUSH {R0,LR} ; Save EXC_RETURN
|
||||
BL osRtxPendSV_Handler ; Call osRtxPendSV_Handler
|
||||
POP {R0,R1} ; Restore EXC_RETURN
|
||||
MOV LR,R1 ; Set EXC_RETURN
|
||||
B SVC_Context
|
||||
|
||||
ALIGN
|
||||
ENDP
|
||||
|
||||
|
||||
SysTick_Handler PROC
|
||||
EXPORT SysTick_Handler
|
||||
IMPORT osRtxTick_Handler
|
||||
|
||||
PUSH {R0,LR} ; Save EXC_RETURN
|
||||
BL osRtxTick_Handler ; Call osRtxTick_Handler
|
||||
POP {R0,R1} ; Restore EXC_RETURN
|
||||
MOV LR,R1 ; Set EXC_RETURN
|
||||
B SVC_Context
|
||||
|
||||
ALIGN
|
||||
ENDP
|
||||
|
||||
|
||||
END
|
||||
@@ -0,0 +1,146 @@
|
||||
;/*
|
||||
; * Copyright (c) 2013-2018 Arm Limited. All rights reserved.
|
||||
; *
|
||||
; * SPDX-License-Identifier: Apache-2.0
|
||||
; *
|
||||
; * Licensed under the Apache License, Version 2.0 (the License); you may
|
||||
; * not use this file except in compliance with the License.
|
||||
; * You may obtain a copy of the License at
|
||||
; *
|
||||
; * www.apache.org/licenses/LICENSE-2.0
|
||||
; *
|
||||
; * Unless required by applicable law or agreed to in writing, software
|
||||
; * distributed under the License is distributed on an AS IS BASIS, WITHOUT
|
||||
; * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
; * See the License for the specific language governing permissions and
|
||||
; * limitations under the License.
|
||||
; *
|
||||
; * -----------------------------------------------------------------------------
|
||||
; *
|
||||
; * Project: CMSIS-RTOS RTX
|
||||
; * Title: Cortex-M3 Exception handlers
|
||||
; *
|
||||
; * -----------------------------------------------------------------------------
|
||||
; */
|
||||
|
||||
|
||||
I_T_RUN_OFS EQU 20 ; osRtxInfo.thread.run offset
|
||||
TCB_SP_OFS EQU 56 ; TCB.SP offset
|
||||
|
||||
|
||||
PRESERVE8
|
||||
THUMB
|
||||
|
||||
|
||||
AREA |.constdata|, DATA, READONLY
|
||||
EXPORT irqRtxLib
|
||||
irqRtxLib DCB 0 ; Non weak library reference
|
||||
|
||||
|
||||
AREA |.text|, CODE, READONLY
|
||||
|
||||
|
||||
SVC_Handler PROC
|
||||
EXPORT SVC_Handler
|
||||
IMPORT osRtxUserSVC
|
||||
IMPORT osRtxInfo
|
||||
IF :DEF:MPU_LOAD
|
||||
IMPORT osRtxMpuLoad
|
||||
ENDIF
|
||||
|
||||
TST LR,#0x04 ; Determine return stack from EXC_RETURN bit 2
|
||||
ITE EQ
|
||||
MRSEQ R0,MSP ; Get MSP if return stack is MSP
|
||||
MRSNE R0,PSP ; Get PSP if return stack is PSP
|
||||
|
||||
LDR R1,[R0,#24] ; Load saved PC from stack
|
||||
LDRB R1,[R1,#-2] ; Load SVC number
|
||||
CBNZ R1,SVC_User ; Branch if not SVC 0
|
||||
|
||||
PUSH {R0,LR} ; Save SP and EXC_RETURN
|
||||
LDM R0,{R0-R3,R12} ; Load function parameters and address from stack
|
||||
BLX R12 ; Call service function
|
||||
POP {R12,LR} ; Restore SP and EXC_RETURN
|
||||
STM R12,{R0-R1} ; Store function return values
|
||||
|
||||
SVC_Context
|
||||
LDR R3,=osRtxInfo+I_T_RUN_OFS; Load address of osRtxInfo.run
|
||||
LDM R3,{R1,R2} ; Load osRtxInfo.thread.run: curr & next
|
||||
CMP R1,R2 ; Check if thread switch is required
|
||||
IT EQ
|
||||
BXEQ LR ; Exit when threads are the same
|
||||
|
||||
CBZ R1,SVC_ContextSwitch ; Branch if running thread is deleted
|
||||
|
||||
SVC_ContextSave
|
||||
STMDB R12!,{R4-R11} ; Save R4..R11
|
||||
STR R12,[R1,#TCB_SP_OFS] ; Store SP
|
||||
|
||||
SVC_ContextSwitch
|
||||
STR R2,[R3] ; osRtxInfo.thread.run: curr = next
|
||||
|
||||
IF :DEF:MPU_LOAD
|
||||
PUSH {R2,R3} ; Save registers
|
||||
MOV R0,R2 ; osRtxMpuLoad parameter
|
||||
BL osRtxMpuLoad ; Load MPU for next thread
|
||||
POP {R2,R3} ; Restore registers
|
||||
ENDIF
|
||||
|
||||
SVC_ContextRestore
|
||||
LDR R0,[R2,#TCB_SP_OFS] ; Load SP
|
||||
LDMIA R0!,{R4-R11} ; Restore R4..R11
|
||||
MSR PSP,R0 ; Set PSP
|
||||
|
||||
MVN LR,#~0xFFFFFFFD ; Set EXC_RETURN value
|
||||
|
||||
SVC_Exit
|
||||
BX LR ; Exit from handler
|
||||
|
||||
SVC_User
|
||||
LDR R2,=osRtxUserSVC ; Load address of SVC table
|
||||
LDR R3,[R2] ; Load SVC maximum number
|
||||
CMP R1,R3 ; Check SVC number range
|
||||
BHI SVC_Exit ; Branch if out of range
|
||||
|
||||
PUSH {R0,LR} ; Save SP and EXC_RETURN
|
||||
LDR R12,[R2,R1,LSL #2] ; Load address of SVC function
|
||||
LDM R0,{R0-R3} ; Load function parameters from stack
|
||||
BLX R12 ; Call service function
|
||||
POP {R12,LR} ; Restore SP and EXC_RETURN
|
||||
STR R0,[R12] ; Store function return value
|
||||
|
||||
BX LR ; Return from handler
|
||||
|
||||
ALIGN
|
||||
ENDP
|
||||
|
||||
|
||||
PendSV_Handler PROC
|
||||
EXPORT PendSV_Handler
|
||||
IMPORT osRtxPendSV_Handler
|
||||
|
||||
PUSH {R0,LR} ; Save EXC_RETURN
|
||||
BL osRtxPendSV_Handler ; Call osRtxPendSV_Handler
|
||||
POP {R0,LR} ; Restore EXC_RETURN
|
||||
MRS R12,PSP
|
||||
B SVC_Context
|
||||
|
||||
ALIGN
|
||||
ENDP
|
||||
|
||||
|
||||
SysTick_Handler PROC
|
||||
EXPORT SysTick_Handler
|
||||
IMPORT osRtxTick_Handler
|
||||
|
||||
PUSH {R0,LR} ; Save EXC_RETURN
|
||||
BL osRtxTick_Handler ; Call osRtxTick_Handler
|
||||
POP {R0,LR} ; Restore EXC_RETURN
|
||||
MRS R12,PSP
|
||||
B SVC_Context
|
||||
|
||||
ALIGN
|
||||
ENDP
|
||||
|
||||
|
||||
END
|
||||
@@ -0,0 +1,162 @@
|
||||
;/*
|
||||
; * Copyright (c) 2013-2018 Arm Limited. All rights reserved.
|
||||
; *
|
||||
; * SPDX-License-Identifier: Apache-2.0
|
||||
; *
|
||||
; * Licensed under the Apache License, Version 2.0 (the License); you may
|
||||
; * not use this file except in compliance with the License.
|
||||
; * You may obtain a copy of the License at
|
||||
; *
|
||||
; * www.apache.org/licenses/LICENSE-2.0
|
||||
; *
|
||||
; * Unless required by applicable law or agreed to in writing, software
|
||||
; * distributed under the License is distributed on an AS IS BASIS, WITHOUT
|
||||
; * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
; * See the License for the specific language governing permissions and
|
||||
; * limitations under the License.
|
||||
; *
|
||||
; * -----------------------------------------------------------------------------
|
||||
; *
|
||||
; * Project: CMSIS-RTOS RTX
|
||||
; * Title: Cortex-M4F Exception handlers
|
||||
; *
|
||||
; * -----------------------------------------------------------------------------
|
||||
; */
|
||||
|
||||
|
||||
I_T_RUN_OFS EQU 20 ; osRtxInfo.thread.run offset
|
||||
TCB_SP_OFS EQU 56 ; TCB.SP offset
|
||||
TCB_SF_OFS EQU 34 ; TCB.stack_frame offset
|
||||
|
||||
|
||||
PRESERVE8
|
||||
THUMB
|
||||
|
||||
|
||||
AREA |.constdata|, DATA, READONLY
|
||||
EXPORT irqRtxLib
|
||||
irqRtxLib DCB 0 ; Non weak library reference
|
||||
|
||||
|
||||
AREA |.text|, CODE, READONLY
|
||||
|
||||
|
||||
SVC_Handler PROC
|
||||
EXPORT SVC_Handler
|
||||
IMPORT osRtxUserSVC
|
||||
IMPORT osRtxInfo
|
||||
IF :DEF:MPU_LOAD
|
||||
IMPORT osRtxMpuLoad
|
||||
ENDIF
|
||||
|
||||
TST LR,#0x04 ; Determine return stack from EXC_RETURN bit 2
|
||||
ITE EQ
|
||||
MRSEQ R0,MSP ; Get MSP if return stack is MSP
|
||||
MRSNE R0,PSP ; Get PSP if return stack is PSP
|
||||
|
||||
LDR R1,[R0,#24] ; Load saved PC from stack
|
||||
LDRB R1,[R1,#-2] ; Load SVC number
|
||||
CBNZ R1,SVC_User ; Branch if not SVC 0
|
||||
|
||||
PUSH {R0,LR} ; Save SP and EXC_RETURN
|
||||
LDM R0,{R0-R3,R12} ; Load function parameters and address from stack
|
||||
BLX R12 ; Call service function
|
||||
POP {R12,LR} ; Restore SP and EXC_RETURN
|
||||
STM R12,{R0-R1} ; Store function return values
|
||||
|
||||
SVC_Context
|
||||
LDR R3,=osRtxInfo+I_T_RUN_OFS; Load address of osRtxInfo.run
|
||||
LDM R3,{R1,R2} ; Load osRtxInfo.thread.run: curr & next
|
||||
CMP R1,R2 ; Check if thread switch is required
|
||||
IT EQ
|
||||
BXEQ LR ; Exit when threads are the same
|
||||
|
||||
CBNZ R1,SVC_ContextSave ; Branch if running thread is not deleted
|
||||
TST LR,#0x10 ; Check if extended stack frame
|
||||
BNE SVC_ContextSwitch
|
||||
LDR R1,=0xE000EF34 ; FPCCR Address
|
||||
LDR R0,[R1] ; Load FPCCR
|
||||
BIC R0,R0,#1 ; Clear LSPACT (Lazy state)
|
||||
STR R0,[R1] ; Store FPCCR
|
||||
B SVC_ContextSwitch
|
||||
|
||||
SVC_ContextSave
|
||||
STMDB R12!,{R4-R11} ; Save R4..R11
|
||||
TST LR,#0x10 ; Check if extended stack frame
|
||||
IT EQ
|
||||
VSTMDBEQ R12!,{S16-S31} ; Save VFP S16.S31
|
||||
STR R12,[R1,#TCB_SP_OFS] ; Store SP
|
||||
STRB LR, [R1,#TCB_SF_OFS] ; Store stack frame information
|
||||
|
||||
SVC_ContextSwitch
|
||||
STR R2,[R3] ; osRtxInfo.thread.run: curr = next
|
||||
|
||||
IF :DEF:MPU_LOAD
|
||||
PUSH {R2,R3} ; Save registers
|
||||
MOV R0,R2 ; osRtxMpuLoad parameter
|
||||
BL osRtxMpuLoad ; Load MPU for next thread
|
||||
POP {R2,R3} ; Restore registers
|
||||
ENDIF
|
||||
|
||||
SVC_ContextRestore
|
||||
LDRB R1,[R2,#TCB_SF_OFS] ; Load stack frame information
|
||||
LDR R0,[R2,#TCB_SP_OFS] ; Load SP
|
||||
ORR LR,R1,#0xFFFFFF00 ; Set EXC_RETURN
|
||||
|
||||
TST LR,#0x10 ; Check if extended stack frame
|
||||
IT EQ
|
||||
VLDMIAEQ R0!,{S16-S31} ; Restore VFP S16..S31
|
||||
LDMIA R0!,{R4-R11} ; Restore R4..R11
|
||||
MSR PSP,R0 ; Set PSP
|
||||
|
||||
SVC_Exit
|
||||
BX LR ; Exit from handler
|
||||
|
||||
SVC_User
|
||||
LDR R2,=osRtxUserSVC ; Load address of SVC table
|
||||
LDR R3,[R2] ; Load SVC maximum number
|
||||
CMP R1,R3 ; Check SVC number range
|
||||
BHI SVC_Exit ; Branch if out of range
|
||||
|
||||
PUSH {R0,LR} ; Save SP and EXC_RETURN
|
||||
LDR R12,[R2,R1,LSL #2] ; Load address of SVC function
|
||||
LDM R0,{R0-R3} ; Load function parameters from stack
|
||||
BLX R12 ; Call service function
|
||||
POP {R12,LR} ; Restore SP and EXC_RETURN
|
||||
STR R0,[R12] ; Store function return value
|
||||
|
||||
BX LR ; Return from handler
|
||||
|
||||
ALIGN
|
||||
ENDP
|
||||
|
||||
|
||||
PendSV_Handler PROC
|
||||
EXPORT PendSV_Handler
|
||||
IMPORT osRtxPendSV_Handler
|
||||
|
||||
PUSH {R0,LR} ; Save EXC_RETURN
|
||||
BL osRtxPendSV_Handler ; Call osRtxPendSV_Handler
|
||||
POP {R0,LR} ; Restore EXC_RETURN
|
||||
MRS R12,PSP
|
||||
B SVC_Context
|
||||
|
||||
ALIGN
|
||||
ENDP
|
||||
|
||||
|
||||
SysTick_Handler PROC
|
||||
EXPORT SysTick_Handler
|
||||
IMPORT osRtxTick_Handler
|
||||
|
||||
PUSH {R0,LR} ; Save EXC_RETURN
|
||||
BL osRtxTick_Handler ; Call osRtxTick_Handler
|
||||
POP {R0,LR} ; Restore EXC_RETURN
|
||||
MRS R12,PSP
|
||||
B SVC_Context
|
||||
|
||||
ALIGN
|
||||
ENDP
|
||||
|
||||
|
||||
END
|
||||
@@ -0,0 +1,325 @@
|
||||
/*
|
||||
* Copyright (c) 2016-2020 Arm Limited. All rights reserved.
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the License); you may
|
||||
* not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an AS IS BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
* -----------------------------------------------------------------------------
|
||||
*
|
||||
* Project: CMSIS-RTOS RTX
|
||||
* Title: ARMv8M Baseline Exception handlers
|
||||
*
|
||||
* -----------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
|
||||
.syntax unified
|
||||
|
||||
#ifdef _RTE_
|
||||
#include "RTE_Components.h"
|
||||
#ifdef RTE_CMSIS_RTOS2_RTX5_ARMV8M_NS
|
||||
#define DOMAIN_NS 1
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifndef DOMAIN_NS
|
||||
#define DOMAIN_NS 0
|
||||
#endif
|
||||
|
||||
.equ I_T_RUN_OFS, 20 // osRtxInfo.thread.run offset
|
||||
.equ TCB_SM_OFS, 48 // TCB.stack_mem offset
|
||||
.equ TCB_SP_OFS, 56 // TCB.SP offset
|
||||
.equ TCB_SF_OFS, 34 // TCB.stack_frame offset
|
||||
.equ TCB_TZM_OFS, 64 // TCB.tz_memory offset
|
||||
|
||||
.section ".rodata"
|
||||
.global irqRtxLib // Non weak library reference
|
||||
irqRtxLib:
|
||||
.byte 0
|
||||
|
||||
|
||||
.thumb
|
||||
.section ".text"
|
||||
.align 2
|
||||
|
||||
|
||||
.thumb_func
|
||||
.type SVC_Handler, %function
|
||||
.global SVC_Handler
|
||||
.fnstart
|
||||
.cantunwind
|
||||
SVC_Handler:
|
||||
|
||||
MOV R0,LR
|
||||
LSRS R0,R0,#3 // Determine return stack from EXC_RETURN bit 2
|
||||
BCC SVC_MSP // Branch if return stack is MSP
|
||||
MRS R0,PSP // Get PSP
|
||||
|
||||
SVC_Number:
|
||||
LDR R1,[R0,#24] // Load saved PC from stack
|
||||
SUBS R1,R1,#2 // Point to SVC instruction
|
||||
LDRB R1,[R1] // Load SVC number
|
||||
CMP R1,#0
|
||||
BNE SVC_User // Branch if not SVC 0
|
||||
|
||||
PUSH {R0,LR} // Save SP and EXC_RETURN
|
||||
LDM R0,{R0-R3} // Load function parameters from stack
|
||||
BLX R7 // Call service function
|
||||
POP {R2,R3} // Restore SP and EXC_RETURN
|
||||
STMIA R2!,{R0-R1} // Store function return values
|
||||
MOV LR,R3 // Set EXC_RETURN
|
||||
|
||||
SVC_Context:
|
||||
LDR R3,=osRtxInfo+I_T_RUN_OFS // Load address of osRtxInfo.run
|
||||
LDMIA R3!,{R1,R2} // Load osRtxInfo.thread.run: curr & next
|
||||
CMP R1,R2 // Check if thread switch is required
|
||||
BEQ SVC_Exit // Branch when threads are the same
|
||||
|
||||
CBZ R1,SVC_ContextSwitch // Branch if running thread is deleted
|
||||
|
||||
SVC_ContextSave:
|
||||
#if (DOMAIN_NS == 1)
|
||||
LDR R0,[R1,#TCB_TZM_OFS] // Load TrustZone memory identifier
|
||||
CBZ R0,SVC_ContextSave1 // Branch if there is no secure context
|
||||
PUSH {R1,R2,R3,R7} // Save registers
|
||||
MOV R7,LR // Get EXC_RETURN
|
||||
BL TZ_StoreContext_S // Store secure context
|
||||
MOV LR,R7 // Set EXC_RETURN
|
||||
POP {R1,R2,R3,R7} // Restore registers
|
||||
#endif
|
||||
|
||||
SVC_ContextSave1:
|
||||
MRS R0,PSP // Get PSP
|
||||
SUBS R0,R0,#32 // Calculate SP
|
||||
STR R0,[R1,#TCB_SP_OFS] // Store SP
|
||||
STMIA R0!,{R4-R7} // Save R4..R7
|
||||
MOV R4,R8
|
||||
MOV R5,R9
|
||||
MOV R6,R10
|
||||
MOV R7,R11
|
||||
STMIA R0!,{R4-R7} // Save R8..R11
|
||||
|
||||
SVC_ContextSave2:
|
||||
MOV R0,LR // Get EXC_RETURN
|
||||
ADDS R1,R1,#TCB_SF_OFS // Adjust address
|
||||
STRB R0,[R1] // Store stack frame information
|
||||
|
||||
SVC_ContextSwitch:
|
||||
SUBS R3,R3,#8 // Adjust address
|
||||
STR R2,[R3] // osRtxInfo.thread.run: curr = next
|
||||
|
||||
SVC_ContextRestore:
|
||||
#if (DOMAIN_NS == 1)
|
||||
LDR R0,[R2,#TCB_TZM_OFS] // Load TrustZone memory identifier
|
||||
CBZ R0,SVC_ContextRestore1 // Branch if there is no secure context
|
||||
PUSH {R2,R3} // Save registers
|
||||
BL TZ_LoadContext_S // Load secure context
|
||||
POP {R2,R3} // Restore registers
|
||||
#endif
|
||||
|
||||
SVC_ContextRestore1:
|
||||
MOV R1,R2
|
||||
ADDS R1,R1,#TCB_SF_OFS // Adjust address
|
||||
LDRB R0,[R1] // Load stack frame information
|
||||
MOVS R1,#0xFF
|
||||
MVNS R1,R1 // R1=0xFFFFFF00
|
||||
ORRS R0,R1
|
||||
MOV LR,R0 // Set EXC_RETURN
|
||||
|
||||
#if (DOMAIN_NS == 1)
|
||||
LSLS R0,R0,#25 // Check domain of interrupted thread
|
||||
BPL SVC_ContextRestore2 // Branch if non-secure
|
||||
LDR R0,[R2,#TCB_SP_OFS] // Load SP
|
||||
MSR PSP,R0 // Set PSP
|
||||
BX LR // Exit from handler
|
||||
#else
|
||||
LDR R0,[R2,#TCB_SM_OFS] // Load stack memory base
|
||||
MSR PSPLIM,R0 // Set PSPLIM
|
||||
#endif
|
||||
|
||||
SVC_ContextRestore2:
|
||||
LDR R0,[R2,#TCB_SP_OFS] // Load SP
|
||||
ADDS R0,R0,#16 // Adjust address
|
||||
LDMIA R0!,{R4-R7} // Restore R8..R11
|
||||
MOV R8,R4
|
||||
MOV R9,R5
|
||||
MOV R10,R6
|
||||
MOV R11,R7
|
||||
MSR PSP,R0 // Set PSP
|
||||
SUBS R0,R0,#32 // Adjust address
|
||||
LDMIA R0!,{R4-R7} // Restore R4..R7
|
||||
|
||||
SVC_Exit:
|
||||
BX LR // Exit from handler
|
||||
|
||||
SVC_MSP:
|
||||
MRS R0,MSP // Get MSP
|
||||
B SVC_Number
|
||||
|
||||
SVC_User:
|
||||
LDR R2,=osRtxUserSVC // Load address of SVC table
|
||||
LDR R3,[R2] // Load SVC maximum number
|
||||
CMP R1,R3 // Check SVC number range
|
||||
BHI SVC_Exit // Branch if out of range
|
||||
|
||||
PUSH {R0,LR} // Save SP and EXC_RETURN
|
||||
LSLS R1,R1,#2
|
||||
LDR R3,[R2,R1] // Load address of SVC function
|
||||
MOV R12,R3
|
||||
LDMIA R0,{R0-R3} // Load function parameters from stack
|
||||
BLX R12 // Call service function
|
||||
POP {R2,R3} // Restore SP and EXC_RETURN
|
||||
STR R0,[R2] // Store function return value
|
||||
MOV LR,R3 // Set EXC_RETURN
|
||||
|
||||
BX LR // Return from handler
|
||||
|
||||
.fnend
|
||||
.size SVC_Handler, .-SVC_Handler
|
||||
|
||||
|
||||
.thumb_func
|
||||
.type PendSV_Handler, %function
|
||||
.global PendSV_Handler
|
||||
.fnstart
|
||||
.cantunwind
|
||||
PendSV_Handler:
|
||||
|
||||
PUSH {R0,LR} // Save EXC_RETURN
|
||||
BL osRtxPendSV_Handler // Call osRtxPendSV_Handler
|
||||
POP {R0,R1} // Restore EXC_RETURN
|
||||
MOV LR,R1 // Set EXC_RETURN
|
||||
B Sys_Context
|
||||
|
||||
.fnend
|
||||
.size PendSV_Handler, .-PendSV_Handler
|
||||
|
||||
|
||||
.thumb_func
|
||||
.type SysTick_Handler, %function
|
||||
.global SysTick_Handler
|
||||
.fnstart
|
||||
.cantunwind
|
||||
SysTick_Handler:
|
||||
|
||||
PUSH {R0,LR} // Save EXC_RETURN
|
||||
BL osRtxTick_Handler // Call osRtxTick_Handler
|
||||
POP {R0,R1} // Restore EXC_RETURN
|
||||
MOV LR,R1 // Set EXC_RETURN
|
||||
B Sys_Context
|
||||
|
||||
.fnend
|
||||
.size SysTick_Handler, .-SysTick_Handler
|
||||
|
||||
|
||||
.thumb_func
|
||||
.type Sys_Context, %function
|
||||
.global Sys_Context
|
||||
.fnstart
|
||||
.cantunwind
|
||||
Sys_Context:
|
||||
|
||||
LDR R3,=osRtxInfo+I_T_RUN_OFS // Load address of osRtxInfo.run
|
||||
LDM R3!,{R1,R2} // Load osRtxInfo.thread.run: curr & next
|
||||
CMP R1,R2 // Check if thread switch is required
|
||||
BEQ Sys_ContextExit // Branch when threads are the same
|
||||
|
||||
Sys_ContextSave:
|
||||
#if (DOMAIN_NS == 1)
|
||||
LDR R0,[R1,#TCB_TZM_OFS] // Load TrustZone memory identifier
|
||||
CBZ R0,Sys_ContextSave1 // Branch if there is no secure context
|
||||
PUSH {R1,R2,R3,R7} // Save registers
|
||||
MOV R7,LR // Get EXC_RETURN
|
||||
BL TZ_StoreContext_S // Store secure context
|
||||
MOV LR,R7 // Set EXC_RETURN
|
||||
POP {R1,R2,R3,R7} // Restore registers
|
||||
|
||||
Sys_ContextSave1:
|
||||
MOV R0,LR // Get EXC_RETURN
|
||||
LSLS R0,R0,#25 // Check domain of interrupted thread
|
||||
BPL Sys_ContextSave2 // Branch if non-secure
|
||||
MRS R0,PSP // Get PSP
|
||||
STR R0,[R1,#TCB_SP_OFS] // Store SP
|
||||
B Sys_ContextSave3
|
||||
#endif
|
||||
|
||||
Sys_ContextSave2:
|
||||
MRS R0,PSP // Get PSP
|
||||
SUBS R0,R0,#32 // Adjust address
|
||||
STR R0,[R1,#TCB_SP_OFS] // Store SP
|
||||
STMIA R0!,{R4-R7} // Save R4..R7
|
||||
MOV R4,R8
|
||||
MOV R5,R9
|
||||
MOV R6,R10
|
||||
MOV R7,R11
|
||||
STMIA R0!,{R4-R7} // Save R8..R11
|
||||
|
||||
Sys_ContextSave3:
|
||||
MOV R0,LR // Get EXC_RETURN
|
||||
ADDS R1,R1,#TCB_SF_OFS // Adjust address
|
||||
STRB R0,[R1] // Store stack frame information
|
||||
|
||||
Sys_ContextSwitch:
|
||||
SUBS R3,R3,#8 // Adjust address
|
||||
STR R2,[R3] // osRtxInfo.run: curr = next
|
||||
|
||||
Sys_ContextRestore:
|
||||
#if (DOMAIN_NS == 1)
|
||||
LDR R0,[R2,#TCB_TZM_OFS] // Load TrustZone memory identifier
|
||||
CBZ R0,Sys_ContextRestore1 // Branch if there is no secure context
|
||||
PUSH {R2,R3} // Save registers
|
||||
BL TZ_LoadContext_S // Load secure context
|
||||
POP {R2,R3} // Restore registers
|
||||
#endif
|
||||
|
||||
Sys_ContextRestore1:
|
||||
MOV R1,R2
|
||||
ADDS R1,R1,#TCB_SF_OFS // Adjust offset
|
||||
LDRB R0,[R1] // Load stack frame information
|
||||
MOVS R1,#0xFF
|
||||
MVNS R1,R1 // R1=0xFFFFFF00
|
||||
ORRS R0,R1
|
||||
MOV LR,R0 // Set EXC_RETURN
|
||||
|
||||
#if (DOMAIN_NS == 1)
|
||||
LSLS R0,R0,#25 // Check domain of interrupted thread
|
||||
BPL Sys_ContextRestore2 // Branch if non-secure
|
||||
LDR R0,[R2,#TCB_SP_OFS] // Load SP
|
||||
MSR PSP,R0 // Set PSP
|
||||
BX LR // Exit from handler
|
||||
#else
|
||||
LDR R0,[R2,#TCB_SM_OFS] // Load stack memory base
|
||||
MSR PSPLIM,R0 // Set PSPLIM
|
||||
#endif
|
||||
|
||||
Sys_ContextRestore2:
|
||||
LDR R0,[R2,#TCB_SP_OFS] // Load SP
|
||||
ADDS R0,R0,#16 // Adjust address
|
||||
LDMIA R0!,{R4-R7} // Restore R8..R11
|
||||
MOV R8,R4
|
||||
MOV R9,R5
|
||||
MOV R10,R6
|
||||
MOV R11,R7
|
||||
MSR PSP,R0 // Set PSP
|
||||
SUBS R0,R0,#32 // Adjust address
|
||||
LDMIA R0!,{R4-R7} // Restore R4..R7
|
||||
|
||||
Sys_ContextExit:
|
||||
BX LR // Exit from handler
|
||||
|
||||
.fnend
|
||||
.size Sys_Context, .-Sys_Context
|
||||
|
||||
|
||||
.end
|
||||
@@ -0,0 +1,304 @@
|
||||
/*
|
||||
* Copyright (c) 2016-2020 Arm Limited. All rights reserved.
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the License); you may
|
||||
* not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an AS IS BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
* -----------------------------------------------------------------------------
|
||||
*
|
||||
* Project: CMSIS-RTOS RTX
|
||||
* Title: ARMv8M Mainline Exception handlers
|
||||
*
|
||||
* -----------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
|
||||
.syntax unified
|
||||
|
||||
#ifdef _RTE_
|
||||
#include "RTE_Components.h"
|
||||
#ifdef RTE_CMSIS_RTOS2_RTX5_ARMV8M_NS
|
||||
#define DOMAIN_NS 1
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifndef DOMAIN_NS
|
||||
#define DOMAIN_NS 0
|
||||
#endif
|
||||
|
||||
#if (defined(__ARM_FP) && (__ARM_FP > 0))
|
||||
.equ FPU_USED, 1
|
||||
#else
|
||||
.equ FPU_USED, 0
|
||||
#endif
|
||||
|
||||
#if (defined(__ARM_FEATURE_MVE) && (__ARM_FEATURE_MVE > 0))
|
||||
.equ MVE_USED, 1
|
||||
#else
|
||||
.equ MVE_USED, 0
|
||||
#endif
|
||||
|
||||
.equ I_T_RUN_OFS, 20 // osRtxInfo.thread.run offset
|
||||
.equ TCB_SM_OFS, 48 // TCB.stack_mem offset
|
||||
.equ TCB_SP_OFS, 56 // TCB.SP offset
|
||||
.equ TCB_SF_OFS, 34 // TCB.stack_frame offset
|
||||
.equ TCB_TZM_OFS, 64 // TCB.tz_memory offset
|
||||
|
||||
.section ".rodata"
|
||||
.global irqRtxLib // Non weak library reference
|
||||
irqRtxLib:
|
||||
.byte 0
|
||||
|
||||
|
||||
.thumb
|
||||
.section ".text"
|
||||
.align 2
|
||||
|
||||
|
||||
.thumb_func
|
||||
.type SVC_Handler, %function
|
||||
.global SVC_Handler
|
||||
.fnstart
|
||||
.cantunwind
|
||||
SVC_Handler:
|
||||
|
||||
TST LR,#0x04 // Determine return stack from EXC_RETURN bit 2
|
||||
ITE EQ
|
||||
MRSEQ R0,MSP // Get MSP if return stack is MSP
|
||||
MRSNE R0,PSP // Get PSP if return stack is PSP
|
||||
|
||||
LDR R1,[R0,#24] // Load saved PC from stack
|
||||
LDRB R1,[R1,#-2] // Load SVC number
|
||||
CMP R1,#0
|
||||
BNE SVC_User // Branch if not SVC 0
|
||||
|
||||
PUSH {R0,LR} // Save SP and EXC_RETURN
|
||||
LDM R0,{R0-R3,R12} // Load function parameters and address from stack
|
||||
BLX R12 // Call service function
|
||||
POP {R12,LR} // Restore SP and EXC_RETURN
|
||||
STM R12,{R0-R1} // Store function return values
|
||||
|
||||
SVC_Context:
|
||||
LDR R3,=osRtxInfo+I_T_RUN_OFS // Load address of osRtxInfo.run
|
||||
LDM R3,{R1,R2} // Load osRtxInfo.thread.run: curr & next
|
||||
CMP R1,R2 // Check if thread switch is required
|
||||
IT EQ
|
||||
BXEQ LR // Exit when threads are the same
|
||||
|
||||
.if (FPU_USED == 1) || (MVE_USED == 1)
|
||||
CBNZ R1,SVC_ContextSave // Branch if running thread is not deleted
|
||||
TST LR,#0x10 // Check if extended stack frame
|
||||
BNE SVC_ContextSwitch
|
||||
LDR R1,=0xE000EF34 // FPCCR Address
|
||||
LDR R0,[R1] // Load FPCCR
|
||||
BIC R0,R0,#1 // Clear LSPACT (Lazy state)
|
||||
STR R0,[R1] // Store FPCCR
|
||||
B SVC_ContextSwitch
|
||||
.else
|
||||
CBZ R1,SVC_ContextSwitch // Branch if running thread is deleted
|
||||
.endif
|
||||
|
||||
SVC_ContextSave:
|
||||
#if (DOMAIN_NS == 1)
|
||||
LDR R0,[R1,#TCB_TZM_OFS] // Load TrustZone memory identifier
|
||||
CBZ R0,SVC_ContextSave1 // Branch if there is no secure context
|
||||
PUSH {R1,R2,R3,LR} // Save registers and EXC_RETURN
|
||||
BL TZ_StoreContext_S // Store secure context
|
||||
POP {R1,R2,R3,LR} // Restore registers and EXC_RETURN
|
||||
#endif
|
||||
|
||||
SVC_ContextSave1:
|
||||
MRS R0,PSP // Get PSP
|
||||
STMDB R0!,{R4-R11} // Save R4..R11
|
||||
.if (FPU_USED == 1) || (MVE_USED == 1)
|
||||
TST LR,#0x10 // Check if extended stack frame
|
||||
IT EQ
|
||||
VSTMDBEQ R0!,{S16-S31} // Save VFP S16.S31
|
||||
.endif
|
||||
|
||||
SVC_ContextSave2:
|
||||
STR R0,[R1,#TCB_SP_OFS] // Store SP
|
||||
STRB LR,[R1,#TCB_SF_OFS] // Store stack frame information
|
||||
|
||||
SVC_ContextSwitch:
|
||||
STR R2,[R3] // osRtxInfo.thread.run: curr = next
|
||||
|
||||
SVC_ContextRestore:
|
||||
#if (DOMAIN_NS == 1)
|
||||
LDR R0,[R2,#TCB_TZM_OFS] // Load TrustZone memory identifier
|
||||
CBZ R0,SVC_ContextRestore1 // Branch if there is no secure context
|
||||
PUSH {R2,R3} // Save registers
|
||||
BL TZ_LoadContext_S // Load secure context
|
||||
POP {R2,R3} // Restore registers
|
||||
#endif
|
||||
|
||||
SVC_ContextRestore1:
|
||||
LDR R0,[R2,#TCB_SM_OFS] // Load stack memory base
|
||||
LDRB R1,[R2,#TCB_SF_OFS] // Load stack frame information
|
||||
MSR PSPLIM,R0 // Set PSPLIM
|
||||
LDR R0,[R2,#TCB_SP_OFS] // Load SP
|
||||
ORR LR,R1,#0xFFFFFF00 // Set EXC_RETURN
|
||||
|
||||
#if (DOMAIN_NS == 1)
|
||||
TST LR,#0x40 // Check domain of interrupted thread
|
||||
BNE SVC_ContextRestore2 // Branch if secure
|
||||
#endif
|
||||
|
||||
.if (FPU_USED == 1) || (MVE_USED == 1)
|
||||
TST LR,#0x10 // Check if extended stack frame
|
||||
IT EQ
|
||||
VLDMIAEQ R0!,{S16-S31} // Restore VFP S16..S31
|
||||
.endif
|
||||
LDMIA R0!,{R4-R11} // Restore R4..R11
|
||||
|
||||
SVC_ContextRestore2:
|
||||
MSR PSP,R0 // Set PSP
|
||||
|
||||
SVC_Exit:
|
||||
BX LR // Exit from handler
|
||||
|
||||
SVC_User:
|
||||
LDR R2,=osRtxUserSVC // Load address of SVC table
|
||||
LDR R3,[R2] // Load SVC maximum number
|
||||
CMP R1,R3 // Check SVC number range
|
||||
BHI SVC_Exit // Branch if out of range
|
||||
|
||||
PUSH {R0,LR} // Save SP and EXC_RETURN
|
||||
LDR R12,[R2,R1,LSL #2] // Load address of SVC function
|
||||
LDM R0,{R0-R3} // Load function parameters from stack
|
||||
BLX R12 // Call service function
|
||||
POP {R12,LR} // Restore SP and EXC_RETURN
|
||||
STR R0,[R12] // Store function return value
|
||||
|
||||
BX LR // Return from handler
|
||||
|
||||
.fnend
|
||||
.size SVC_Handler, .-SVC_Handler
|
||||
|
||||
|
||||
.thumb_func
|
||||
.type PendSV_Handler, %function
|
||||
.global PendSV_Handler
|
||||
.fnstart
|
||||
.cantunwind
|
||||
PendSV_Handler:
|
||||
|
||||
PUSH {R0,LR} // Save EXC_RETURN
|
||||
BL osRtxPendSV_Handler // Call osRtxPendSV_Handler
|
||||
POP {R0,LR} // Restore EXC_RETURN
|
||||
B Sys_Context
|
||||
|
||||
.fnend
|
||||
.size PendSV_Handler, .-PendSV_Handler
|
||||
|
||||
|
||||
.thumb_func
|
||||
.type SysTick_Handler, %function
|
||||
.global SysTick_Handler
|
||||
.fnstart
|
||||
.cantunwind
|
||||
SysTick_Handler:
|
||||
|
||||
PUSH {R0,LR} // Save EXC_RETURN
|
||||
BL osRtxTick_Handler // Call osRtxTick_Handler
|
||||
POP {R0,LR} // Restore EXC_RETURN
|
||||
B Sys_Context
|
||||
|
||||
.fnend
|
||||
.size SysTick_Handler, .-SysTick_Handler
|
||||
|
||||
|
||||
.thumb_func
|
||||
.type Sys_Context, %function
|
||||
.global Sys_Context
|
||||
.fnstart
|
||||
.cantunwind
|
||||
Sys_Context:
|
||||
|
||||
LDR R3,=osRtxInfo+I_T_RUN_OFS // Load address of osRtxInfo.run
|
||||
LDM R3,{R1,R2} // Load osRtxInfo.thread.run: curr & next
|
||||
CMP R1,R2 // Check if thread switch is required
|
||||
IT EQ
|
||||
BXEQ LR // Exit when threads are the same
|
||||
|
||||
Sys_ContextSave:
|
||||
#if (DOMAIN_NS == 1)
|
||||
LDR R0,[R1,#TCB_TZM_OFS] // Load TrustZone memory identifier
|
||||
CBZ R0,Sys_ContextSave1 // Branch if there is no secure context
|
||||
PUSH {R1,R2,R3,LR} // Save registers and EXC_RETURN
|
||||
BL TZ_StoreContext_S // Store secure context
|
||||
POP {R1,R2,R3,LR} // Restore registers and EXC_RETURN
|
||||
|
||||
Sys_ContextSave1:
|
||||
TST LR,#0x40 // Check domain of interrupted thread
|
||||
IT NE
|
||||
MRSNE R0,PSP // Get PSP
|
||||
BNE Sys_ContextSave3 // Branch if secure
|
||||
#endif
|
||||
|
||||
Sys_ContextSave2:
|
||||
MRS R0,PSP // Get PSP
|
||||
STMDB R0!,{R4-R11} // Save R4..R11
|
||||
.if (FPU_USED == 1) || (MVE_USED == 1)
|
||||
TST LR,#0x10 // Check if extended stack frame
|
||||
IT EQ
|
||||
VSTMDBEQ R0!,{S16-S31} // Save VFP S16.S31
|
||||
.endif
|
||||
|
||||
Sys_ContextSave3:
|
||||
STR R0,[R1,#TCB_SP_OFS] // Store SP
|
||||
STRB LR,[R1,#TCB_SF_OFS] // Store stack frame information
|
||||
|
||||
Sys_ContextSwitch:
|
||||
STR R2,[R3] // osRtxInfo.run: curr = next
|
||||
|
||||
Sys_ContextRestore:
|
||||
#if (DOMAIN_NS == 1)
|
||||
LDR R0,[R2,#TCB_TZM_OFS] // Load TrustZone memory identifier
|
||||
CBZ R0,Sys_ContextRestore1 // Branch if there is no secure context
|
||||
PUSH {R2,R3} // Save registers
|
||||
BL TZ_LoadContext_S // Load secure context
|
||||
POP {R2,R3} // Restore registers
|
||||
#endif
|
||||
|
||||
Sys_ContextRestore1:
|
||||
LDR R0,[R2,#TCB_SM_OFS] // Load stack memory base
|
||||
LDRB R1,[R2,#TCB_SF_OFS] // Load stack frame information
|
||||
MSR PSPLIM,R0 // Set PSPLIM
|
||||
LDR R0,[R2,#TCB_SP_OFS] // Load SP
|
||||
ORR LR,R1,#0xFFFFFF00 // Set EXC_RETURN
|
||||
|
||||
#if (DOMAIN_NS == 1)
|
||||
TST LR,#0x40 // Check domain of interrupted thread
|
||||
BNE Sys_ContextRestore2 // Branch if secure
|
||||
#endif
|
||||
|
||||
.if (FPU_USED == 1) || (MVE_USED == 1)
|
||||
TST LR,#0x10 // Check if extended stack frame
|
||||
IT EQ
|
||||
VLDMIAEQ R0!,{S16-S31} // Restore VFP S16..S31
|
||||
.endif
|
||||
LDMIA R0!,{R4-R11} // Restore R4..R11
|
||||
|
||||
Sys_ContextRestore2:
|
||||
MSR PSP,R0 // Set PSP
|
||||
|
||||
Sys_ContextExit:
|
||||
BX LR // Exit from handler
|
||||
|
||||
.fnend
|
||||
.size Sys_Context, .-Sys_Context
|
||||
|
||||
|
||||
.end
|
||||
@@ -0,0 +1,464 @@
|
||||
/*
|
||||
* Copyright (c) 2013-2018 Arm Limited. All rights reserved.
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the License); you may
|
||||
* not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an AS IS BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
* -----------------------------------------------------------------------------
|
||||
*
|
||||
* Project: CMSIS-RTOS RTX
|
||||
* Title: Cortex-A Exception handlers
|
||||
*
|
||||
* -----------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
.syntax unified
|
||||
|
||||
.equ MODE_FIQ, 0x11
|
||||
.equ MODE_IRQ, 0x12
|
||||
.equ MODE_SVC, 0x13
|
||||
.equ MODE_ABT, 0x17
|
||||
.equ MODE_UND, 0x1B
|
||||
|
||||
.equ CPSR_BIT_T, 0x20
|
||||
|
||||
.equ K_STATE_RUNNING, 2 // osKernelState_t::osKernelRunning
|
||||
.equ I_K_STATE_OFS, 8 // osRtxInfo.kernel.state offset
|
||||
.equ I_TICK_IRQN_OFS, 16 // osRtxInfo.tick_irqn offset
|
||||
.equ I_T_RUN_OFS, 20 // osRtxInfo.thread.run offset
|
||||
.equ TCB_SP_FRAME, 34 // osRtxThread_t.stack_frame offset
|
||||
.equ TCB_SP_OFS, 56 // osRtxThread_t.sp offset
|
||||
|
||||
|
||||
.section ".rodata"
|
||||
.global irqRtxLib // Non weak library reference
|
||||
irqRtxLib:
|
||||
.byte 0
|
||||
|
||||
.section ".data"
|
||||
.global IRQ_PendSV
|
||||
IRQ_NestLevel:
|
||||
.word 0 // IRQ nesting level counter
|
||||
IRQ_PendSV:
|
||||
.byte 0 // Pending SVC flag
|
||||
|
||||
.arm
|
||||
.section ".text"
|
||||
.align 4
|
||||
|
||||
|
||||
.type Undef_Handler, %function
|
||||
.global Undef_Handler
|
||||
.fnstart
|
||||
.cantunwind
|
||||
Undef_Handler:
|
||||
|
||||
SRSFD SP!, #MODE_UND
|
||||
PUSH {R0-R4, R12} // Save APCS corruptible registers to UND mode stack
|
||||
|
||||
MRS R0, SPSR
|
||||
TST R0, #CPSR_BIT_T // Check mode
|
||||
MOVEQ R1, #4 // R1 = 4 ARM mode
|
||||
MOVNE R1, #2 // R1 = 2 Thumb mode
|
||||
SUB R0, LR, R1
|
||||
LDREQ R0, [R0] // ARM mode - R0 points to offending instruction
|
||||
BEQ Undef_Cont
|
||||
|
||||
// Thumb instruction
|
||||
// Determine if it is a 32-bit Thumb instruction
|
||||
LDRH R0, [R0]
|
||||
MOV R2, #0x1C
|
||||
CMP R2, R0, LSR #11
|
||||
BHS Undef_Cont // 16-bit Thumb instruction
|
||||
|
||||
// 32-bit Thumb instruction. Unaligned - reconstruct the offending instruction
|
||||
LDRH R2, [LR]
|
||||
ORR R0, R2, R0, LSL #16
|
||||
Undef_Cont:
|
||||
MOV R2, LR // Set LR to third argument
|
||||
|
||||
AND R12, SP, #4 // Ensure stack is 8-byte aligned
|
||||
SUB SP, SP, R12 // Adjust stack
|
||||
PUSH {R12, LR} // Store stack adjustment and dummy LR
|
||||
|
||||
// R0 =Offending instruction, R1 =2(Thumb) or =4(ARM)
|
||||
BL CUndefHandler
|
||||
|
||||
POP {R12, LR} // Get stack adjustment & discard dummy LR
|
||||
ADD SP, SP, R12 // Unadjust stack
|
||||
|
||||
LDR LR, [SP, #24] // Restore stacked LR and possibly adjust for retry
|
||||
SUB LR, LR, R0
|
||||
LDR R0, [SP, #28] // Restore stacked SPSR
|
||||
MSR SPSR_cxsf, R0
|
||||
CLREX // Clear exclusive monitor
|
||||
POP {R0-R4, R12} // Restore stacked APCS registers
|
||||
ADD SP, SP, #8 // Adjust SP for already-restored banked registers
|
||||
MOVS PC, LR
|
||||
|
||||
.fnend
|
||||
.size Undef_Handler, .-Undef_Handler
|
||||
|
||||
|
||||
.type PAbt_Handler, %function
|
||||
.global PAbt_Handler
|
||||
.fnstart
|
||||
.cantunwind
|
||||
PAbt_Handler:
|
||||
|
||||
SUB LR, LR, #4 // Pre-adjust LR
|
||||
SRSFD SP!, #MODE_ABT // Save LR and SPRS to ABT mode stack
|
||||
PUSH {R0-R4, R12} // Save APCS corruptible registers to ABT mode stack
|
||||
MRC p15, 0, R0, c5, c0, 1 // IFSR
|
||||
MRC p15, 0, R1, c6, c0, 2 // IFAR
|
||||
|
||||
MOV R2, LR // Set LR to third argument
|
||||
|
||||
AND R12, SP, #4 // Ensure stack is 8-byte aligned
|
||||
SUB SP, SP, R12 // Adjust stack
|
||||
PUSH {R12, LR} // Store stack adjustment and dummy LR
|
||||
|
||||
BL CPAbtHandler
|
||||
|
||||
POP {R12, LR} // Get stack adjustment & discard dummy LR
|
||||
ADD SP, SP, R12 // Unadjust stack
|
||||
|
||||
CLREX // Clear exclusive monitor
|
||||
POP {R0-R4, R12} // Restore stack APCS registers
|
||||
RFEFD SP! // Return from exception
|
||||
|
||||
.fnend
|
||||
.size PAbt_Handler, .-PAbt_Handler
|
||||
|
||||
|
||||
.type DAbt_Handler, %function
|
||||
.global DAbt_Handler
|
||||
.fnstart
|
||||
.cantunwind
|
||||
DAbt_Handler:
|
||||
SUB LR, LR, #8 // Pre-adjust LR
|
||||
SRSFD SP!, #MODE_ABT // Save LR and SPRS to ABT mode stack
|
||||
PUSH {R0-R4, R12} // Save APCS corruptible registers to ABT mode stack
|
||||
MRC p15, 0, R0, c5, c0, 0 // DFSR
|
||||
MRC p15, 0, R1, c6, c0, 0 // DFAR
|
||||
|
||||
MOV R2, LR // Set LR to third argument
|
||||
|
||||
AND R12, SP, #4 // Ensure stack is 8-byte aligned
|
||||
SUB SP, SP, R12 // Adjust stack
|
||||
PUSH {R12, LR} // Store stack adjustment and dummy LR
|
||||
|
||||
BL CDAbtHandler
|
||||
|
||||
POP {R12, LR} // Get stack adjustment & discard dummy LR
|
||||
ADD SP, SP, R12 // Unadjust stack
|
||||
|
||||
CLREX // Clear exclusive monitor
|
||||
POP {R0-R4, R12} // Restore stacked APCS registers
|
||||
RFEFD SP! // Return from exception
|
||||
|
||||
.fnend
|
||||
.size DAbt_Handler, .-DAbt_Handler
|
||||
|
||||
|
||||
.type IRQ_Handler, %function
|
||||
.global IRQ_Handler
|
||||
.fnstart
|
||||
.cantunwind
|
||||
IRQ_Handler:
|
||||
|
||||
SUB LR, LR, #4 // Pre-adjust LR
|
||||
SRSFD SP!, #MODE_SVC // Save LR_irq and SPSR_irq on to the SVC stack
|
||||
CPS #MODE_SVC // Change to SVC mode
|
||||
PUSH {R0-R3, R12, LR} // Save APCS corruptible registers
|
||||
|
||||
LDR R0, =IRQ_NestLevel
|
||||
LDR R1, [R0]
|
||||
ADD R1, R1, #1 // Increment IRQ nesting level
|
||||
STR R1, [R0]
|
||||
|
||||
MOV R3, SP // Move SP into R3
|
||||
AND R3, R3, #4 // Get stack adjustment to ensure 8-byte alignment
|
||||
SUB SP, SP, R3 // Adjust stack
|
||||
PUSH {R3, R4} // Store stack adjustment(R3) and user data(R4)
|
||||
|
||||
BLX IRQ_GetActiveIRQ // Retrieve interrupt ID into R0
|
||||
MOV R4, R0 // Move interrupt ID to R4
|
||||
|
||||
BLX IRQ_GetHandler // Retrieve interrupt handler address for current ID
|
||||
CMP R0, #0 // Check if handler address is 0
|
||||
BEQ IRQ_End // If 0, end interrupt and return
|
||||
|
||||
CPSIE i // Re-enable interrupts
|
||||
BLX R0 // Call IRQ handler
|
||||
CPSID i // Disable interrupts
|
||||
|
||||
IRQ_End:
|
||||
MOV R0, R4 // Move interrupt ID to R0
|
||||
BLX IRQ_EndOfInterrupt // Signal end of interrupt
|
||||
|
||||
POP {R3, R4} // Restore stack adjustment(R3) and user data(R4)
|
||||
ADD SP, SP, R3 // Unadjust stack
|
||||
|
||||
BL osRtxContextSwitch // Continue in context switcher
|
||||
|
||||
LDR R0, =IRQ_NestLevel
|
||||
LDR R1, [R0]
|
||||
SUBS R1, R1, #1 // Decrement IRQ nesting level
|
||||
STR R1, [R0]
|
||||
|
||||
CLREX // Clear exclusive monitor for interrupted code
|
||||
POP {R0-R3, R12, LR} // Restore stacked APCS registers
|
||||
RFEFD SP! // Return from IRQ handler
|
||||
|
||||
.fnend
|
||||
.size IRQ_Handler, .-IRQ_Handler
|
||||
|
||||
|
||||
.type SVC_Handler, %function
|
||||
.global SVC_Handler
|
||||
.fnstart
|
||||
.cantunwind
|
||||
SVC_Handler:
|
||||
|
||||
SRSFD SP!, #MODE_SVC // Store SPSR_svc and LR_svc onto SVC stack
|
||||
PUSH {R12, LR}
|
||||
|
||||
MRS R12, SPSR // Load SPSR
|
||||
TST R12, #CPSR_BIT_T // Thumb bit set?
|
||||
LDRHNE R12, [LR,#-2] // Thumb: load halfword
|
||||
BICNE R12, R12, #0xFF00 // extract SVC number
|
||||
LDREQ R12, [LR,#-4] // ARM: load word
|
||||
BICEQ R12, R12, #0xFF000000 // extract SVC number
|
||||
CMP R12, #0 // Compare SVC number
|
||||
BNE SVC_User // Branch if User SVC
|
||||
|
||||
PUSH {R0-R3}
|
||||
|
||||
LDR R0, =IRQ_NestLevel
|
||||
LDR R1, [R0]
|
||||
ADD R1, R1, #1 // Increment IRQ nesting level
|
||||
STR R1, [R0]
|
||||
|
||||
LDR R0, =osRtxInfo
|
||||
LDR R1, [R0, #I_K_STATE_OFS] // Load RTX5 kernel state
|
||||
CMP R1, #K_STATE_RUNNING // Check osKernelRunning
|
||||
BLT SVC_FuncCall // Continue if kernel is not running
|
||||
LDR R0, [R0, #I_TICK_IRQN_OFS] // Load OS Tick irqn
|
||||
BLX IRQ_Disable // Disable OS Tick interrupt
|
||||
SVC_FuncCall:
|
||||
POP {R0-R3}
|
||||
|
||||
LDR R12, [SP] // Reload R12 from stack
|
||||
|
||||
CPSIE i // Re-enable interrupts
|
||||
BLX R12 // Branch to SVC function
|
||||
CPSID i // Disable interrupts
|
||||
|
||||
SUB SP, SP, #4
|
||||
STM SP, {SP}^ // Store SP_usr onto stack
|
||||
POP {R12} // Pop SP_usr into R12
|
||||
SUB R12, R12, #16 // Adjust pointer to SP_usr
|
||||
LDMDB R12, {R2,R3} // Load return values from SVC function
|
||||
PUSH {R0-R3} // Push return values to stack
|
||||
|
||||
LDR R0, =osRtxInfo
|
||||
LDR R1, [R0, #I_K_STATE_OFS] // Load RTX5 kernel state
|
||||
CMP R1, #K_STATE_RUNNING // Check osKernelRunning
|
||||
BLT SVC_ContextCheck // Continue if kernel is not running
|
||||
LDR R0, [R0, #I_TICK_IRQN_OFS] // Load OS Tick irqn
|
||||
BLX IRQ_Enable // Enable OS Tick interrupt
|
||||
|
||||
SVC_ContextCheck:
|
||||
BL osRtxContextSwitch // Continue in context switcher
|
||||
|
||||
LDR R0, =IRQ_NestLevel
|
||||
LDR R1, [R0]
|
||||
SUB R1, R1, #1 // Decrement IRQ nesting level
|
||||
STR R1, [R0]
|
||||
|
||||
CLREX // Clear exclusive monitor
|
||||
POP {R0-R3, R12, LR} // Restore stacked APCS registers
|
||||
RFEFD SP! // Return from exception
|
||||
|
||||
SVC_User:
|
||||
PUSH {R4, R5}
|
||||
LDR R5,=osRtxUserSVC // Load address of SVC table
|
||||
LDR R4,[R5] // Load SVC maximum number
|
||||
CMP R12,R4 // Check SVC number range
|
||||
BHI SVC_Done // Branch if out of range
|
||||
|
||||
LDR R12,[R5,R12,LSL #2] // Load SVC Function Address
|
||||
BLX R12 // Call SVC Function
|
||||
|
||||
SVC_Done:
|
||||
CLREX // Clear exclusive monitor
|
||||
POP {R4, R5, R12, LR}
|
||||
RFEFD SP! // Return from exception
|
||||
|
||||
.fnend
|
||||
.size SVC_Handler, .-SVC_Handler
|
||||
|
||||
|
||||
.type osRtxContextSwitch, %function
|
||||
.global osRtxContextSwitch
|
||||
.fnstart
|
||||
.cantunwind
|
||||
osRtxContextSwitch:
|
||||
|
||||
PUSH {LR}
|
||||
|
||||
// Check interrupt nesting level
|
||||
LDR R0, =IRQ_NestLevel
|
||||
LDR R1, [R0] // Load IRQ nest level
|
||||
CMP R1, #1
|
||||
BNE osRtxContextExit // Nesting interrupts, exit context switcher
|
||||
|
||||
LDR R12, =osRtxInfo+I_T_RUN_OFS // Load address of osRtxInfo.run
|
||||
LDM R12, {R0, R1} // Load osRtxInfo.thread.run: curr & next
|
||||
LDR R2, =IRQ_PendSV // Load address of IRQ_PendSV flag
|
||||
LDRB R3, [R2] // Load PendSV flag
|
||||
|
||||
CMP R0, R1 // Check if context switch is required
|
||||
BNE osRtxContextCheck // Not equal, check if context save required
|
||||
CMP R3, #1 // Compare IRQ_PendSV value
|
||||
BNE osRtxContextExit // No post processing (and no context switch requested)
|
||||
|
||||
osRtxContextCheck:
|
||||
STR R1, [R12] // Store run.next as run.curr
|
||||
// R0 = curr, R1 = next, R2 = &IRQ_PendSV, R3 = IRQ_PendSV, R12 = &osRtxInfo.thread.run
|
||||
PUSH {R1-R3, R12}
|
||||
|
||||
CMP R0, #0 // Is osRtxInfo.thread.run.curr == 0
|
||||
BEQ osRtxPostProcess // Current deleted, skip context save
|
||||
|
||||
osRtxContextSave:
|
||||
MOV LR, R0 // Move &osRtxInfo.thread.run.curr to LR
|
||||
MOV R0, SP // Move SP_svc into R0
|
||||
ADD R0, R0, #20 // Adjust SP_svc to R0 of the basic frame
|
||||
SUB SP, SP, #4
|
||||
STM SP, {SP}^ // Save SP_usr to current stack
|
||||
POP {R1} // Pop SP_usr into R1
|
||||
|
||||
SUB R1, R1, #64 // Adjust SP_usr to R4 of the basic frame
|
||||
STMIA R1!, {R4-R11} // Save R4-R11 to user stack
|
||||
LDMIA R0!, {R4-R8} // Load stacked R0-R3,R12 into R4-R8
|
||||
STMIA R1!, {R4-R8} // Store them to user stack
|
||||
STM R1, {LR}^ // Store LR_usr directly
|
||||
ADD R1, R1, #4 // Adjust user sp to PC
|
||||
LDMIB R0!, {R5-R6} // Load current PC, CPSR
|
||||
STMIA R1!, {R5-R6} // Restore user PC and CPSR
|
||||
|
||||
SUB R1, R1, #64 // Adjust SP_usr to stacked R4
|
||||
|
||||
// Check if VFP state need to be saved
|
||||
MRC p15, 0, R2, c1, c0, 2 // VFP/NEON access enabled? (CPACR)
|
||||
AND R2, R2, #0x00F00000
|
||||
CMP R2, #0x00F00000
|
||||
BNE osRtxContextSave1 // Continue, no VFP
|
||||
|
||||
VMRS R2, FPSCR
|
||||
STMDB R1!, {R2,R12} // Push FPSCR, maintain 8-byte alignment
|
||||
|
||||
VSTMDB R1!, {D0-D15} // Save D0-D15
|
||||
#if __ARM_NEON == 1
|
||||
VSTMDB R1!, {D16-D31} // Save D16-D31
|
||||
#endif
|
||||
|
||||
LDRB R2, [LR, #TCB_SP_FRAME] // Load osRtxInfo.thread.run.curr frame info
|
||||
#if __ARM_NEON == 1
|
||||
ORR R2, R2, #4 // NEON state
|
||||
#else
|
||||
ORR R2, R2, #2 // VFP state
|
||||
#endif
|
||||
STRB R2, [LR, #TCB_SP_FRAME] // Store VFP/NEON state
|
||||
|
||||
osRtxContextSave1:
|
||||
STR R1, [LR, #TCB_SP_OFS] // Store user sp to osRtxInfo.thread.run.curr
|
||||
|
||||
osRtxPostProcess:
|
||||
// RTX IRQ post processing check
|
||||
POP {R8-R11} // Pop R8 = run.next, R9 = &IRQ_PendSV, R10 = IRQ_PendSV, R11 = &osRtxInfo.thread.run
|
||||
CMP R10, #1 // Compare PendSV value
|
||||
BNE osRtxContextRestore // Skip post processing if not pending
|
||||
|
||||
MOV R4, SP // Move SP_svc into R4
|
||||
AND R4, R4, #4 // Get stack adjustment to ensure 8-byte alignment
|
||||
SUB SP, SP, R4 // Adjust stack
|
||||
|
||||
// Disable OS Tick
|
||||
LDR R5, =osRtxInfo // Load address of osRtxInfo
|
||||
LDR R5, [R5, #I_TICK_IRQN_OFS] // Load OS Tick irqn
|
||||
MOV R0, R5 // Set it as function parameter
|
||||
BLX IRQ_Disable // Disable OS Tick interrupt
|
||||
MOV R6, #0 // Set PendSV clear value
|
||||
B osRtxPendCheck
|
||||
osRtxPendExec:
|
||||
STRB R6, [R9] // Clear PendSV flag
|
||||
CPSIE i // Re-enable interrupts
|
||||
BLX osRtxPendSV_Handler // Post process pending objects
|
||||
CPSID i // Disable interrupts
|
||||
osRtxPendCheck:
|
||||
LDR R8, [R11, #4] // Load osRtxInfo.thread.run.next
|
||||
STR R8, [R11] // Store run.next as run.curr
|
||||
LDRB R0, [R9] // Load PendSV flag
|
||||
CMP R0, #1 // Compare PendSV value
|
||||
BEQ osRtxPendExec // Branch to PendExec if PendSV is set
|
||||
|
||||
// Re-enable OS Tick
|
||||
MOV R0, R5 // Restore irqn as function parameter
|
||||
BLX IRQ_Enable // Enable OS Tick interrupt
|
||||
|
||||
ADD SP, SP, R4 // Restore stack adjustment
|
||||
|
||||
osRtxContextRestore:
|
||||
LDR LR, [R8, #TCB_SP_OFS] // Load next osRtxThread_t.sp
|
||||
LDRB R2, [R8, #TCB_SP_FRAME] // Load next osRtxThread_t.stack_frame
|
||||
|
||||
ANDS R2, R2, #0x6 // Check stack frame for VFP context
|
||||
MRC p15, 0, R2, c1, c0, 2 // Read CPACR
|
||||
ANDEQ R2, R2, #0xFF0FFFFF // VFP/NEON state not stacked, disable VFP/NEON
|
||||
ORRNE R2, R2, #0x00F00000 // VFP/NEON state is stacked, enable VFP/NEON
|
||||
MCR p15, 0, R2, c1, c0, 2 // Write CPACR
|
||||
BEQ osRtxContextRestore1 // No VFP
|
||||
ISB // Sync if VFP was enabled
|
||||
#if __ARM_NEON == 1
|
||||
VLDMIA LR!, {D16-D31} // Restore D16-D31
|
||||
#endif
|
||||
VLDMIA LR!, {D0-D15} // Restore D0-D15
|
||||
LDR R2, [LR]
|
||||
VMSR FPSCR, R2 // Restore FPSCR
|
||||
ADD LR, LR, #8 // Adjust sp pointer to R4
|
||||
|
||||
osRtxContextRestore1:
|
||||
LDMIA LR!, {R4-R11} // Restore R4-R11
|
||||
ADD R12, LR, #32 // Adjust sp and save it into R12
|
||||
PUSH {R12} // Push sp onto stack
|
||||
LDM SP, {SP}^ // Restore SP_usr directly
|
||||
ADD SP, SP, #4 // Adjust SP_svc
|
||||
LDMIA LR!, {R0-R3, R12} // Load user registers R0-R3,R12
|
||||
STMIB SP!, {R0-R3, R12} // Store them to SP_svc
|
||||
LDM LR, {LR}^ // Restore LR_usr directly
|
||||
LDMIB LR!, {R0-R1} // Load user registers PC,CPSR
|
||||
ADD SP, SP, #4
|
||||
STMIB SP!, {R0-R1} // Store them to SP_svc
|
||||
SUB SP, SP, #32 // Adjust SP_svc to stacked LR
|
||||
|
||||
osRtxContextExit:
|
||||
POP {PC} // Return
|
||||
|
||||
.fnend
|
||||
.size osRtxContextSwitch, .-osRtxContextSwitch
|
||||
|
||||
.end
|
||||
@@ -0,0 +1,172 @@
|
||||
/*
|
||||
* Copyright (c) 2013-2018 Arm Limited. All rights reserved.
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the License); you may
|
||||
* not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an AS IS BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
* -----------------------------------------------------------------------------
|
||||
*
|
||||
* Project: CMSIS-RTOS RTX
|
||||
* Title: Cortex-M0 Exception handlers
|
||||
*
|
||||
* -----------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
|
||||
.syntax unified
|
||||
|
||||
.equ I_T_RUN_OFS, 20 // osRtxInfo.thread.run offset
|
||||
.equ TCB_SP_OFS, 56 // TCB.SP offset
|
||||
|
||||
.section ".rodata"
|
||||
.global irqRtxLib // Non weak library reference
|
||||
irqRtxLib:
|
||||
.byte 0
|
||||
|
||||
|
||||
.thumb
|
||||
.section ".text"
|
||||
.align 2
|
||||
|
||||
|
||||
.thumb_func
|
||||
.type SVC_Handler, %function
|
||||
.global SVC_Handler
|
||||
.fnstart
|
||||
.cantunwind
|
||||
SVC_Handler:
|
||||
|
||||
MOV R0,LR
|
||||
LSRS R0,R0,#3 // Determine return stack from EXC_RETURN bit 2
|
||||
BCC SVC_MSP // Branch if return stack is MSP
|
||||
MRS R0,PSP // Get PSP
|
||||
|
||||
SVC_Number:
|
||||
LDR R1,[R0,#24] // Load saved PC from stack
|
||||
SUBS R1,R1,#2 // Point to SVC instruction
|
||||
LDRB R1,[R1] // Load SVC number
|
||||
CMP R1,#0
|
||||
BNE SVC_User // Branch if not SVC 0
|
||||
|
||||
PUSH {R0,LR} // Save SP and EXC_RETURN
|
||||
LDMIA R0,{R0-R3} // Load function parameters from stack
|
||||
BLX R7 // Call service function
|
||||
POP {R2,R3} // Restore SP and EXC_RETURN
|
||||
STMIA R2!,{R0-R1} // Store function return values
|
||||
MOV LR,R3 // Set EXC_RETURN
|
||||
|
||||
SVC_Context:
|
||||
LDR R3,=osRtxInfo+I_T_RUN_OFS // Load address of osRtxInfo.run
|
||||
LDMIA R3!,{R1,R2} // Load osRtxInfo.thread.run: curr & next
|
||||
CMP R1,R2 // Check if thread switch is required
|
||||
BEQ SVC_Exit // Branch when threads are the same
|
||||
|
||||
CMP R1,#0
|
||||
BEQ SVC_ContextSwitch // Branch if running thread is deleted
|
||||
|
||||
SVC_ContextSave:
|
||||
MRS R0,PSP // Get PSP
|
||||
SUBS R0,R0,#32 // Calculate SP
|
||||
STR R0,[R1,#TCB_SP_OFS] // Store SP
|
||||
STMIA R0!,{R4-R7} // Save R4..R7
|
||||
MOV R4,R8
|
||||
MOV R5,R9
|
||||
MOV R6,R10
|
||||
MOV R7,R11
|
||||
STMIA R0!,{R4-R7} // Save R8..R11
|
||||
|
||||
SVC_ContextSwitch:
|
||||
SUBS R3,R3,#8 // Adjust address
|
||||
STR R2,[R3] // osRtxInfo.thread.run: curr = next
|
||||
|
||||
SVC_ContextRestore:
|
||||
LDR R0,[R2,#TCB_SP_OFS] // Load SP
|
||||
ADDS R0,R0,#16 // Adjust address
|
||||
LDMIA R0!,{R4-R7} // Restore R8..R11
|
||||
MOV R8,R4
|
||||
MOV R9,R5
|
||||
MOV R10,R6
|
||||
MOV R11,R7
|
||||
MSR PSP,R0 // Set PSP
|
||||
SUBS R0,R0,#32 // Adjust address
|
||||
LDMIA R0!,{R4-R7} // Restore R4..R7
|
||||
|
||||
MOVS R0,#~0xFFFFFFFD
|
||||
MVNS R0,R0 // Set EXC_RETURN value
|
||||
BX R0 // Exit from handler
|
||||
|
||||
SVC_MSP:
|
||||
MRS R0,MSP // Get MSP
|
||||
B SVC_Number
|
||||
|
||||
SVC_Exit:
|
||||
BX LR // Exit from handler
|
||||
|
||||
SVC_User:
|
||||
LDR R2,=osRtxUserSVC // Load address of SVC table
|
||||
LDR R3,[R2] // Load SVC maximum number
|
||||
CMP R1,R3 // Check SVC number range
|
||||
BHI SVC_Exit // Branch if out of range
|
||||
|
||||
PUSH {R0,LR} // Save SP and EXC_RETURN
|
||||
LSLS R1,R1,#2
|
||||
LDR R3,[R2,R1] // Load address of SVC function
|
||||
MOV R12,R3
|
||||
LDMIA R0,{R0-R3} // Load function parameters from stack
|
||||
BLX R12 // Call service function
|
||||
POP {R2,R3} // Restore SP and EXC_RETURN
|
||||
STR R0,[R2] // Store function return value
|
||||
MOV LR,R3 // Set EXC_RETURN
|
||||
|
||||
BX LR // Return from handler
|
||||
|
||||
.fnend
|
||||
.size SVC_Handler, .-SVC_Handler
|
||||
|
||||
|
||||
.thumb_func
|
||||
.type PendSV_Handler, %function
|
||||
.global PendSV_Handler
|
||||
.fnstart
|
||||
.cantunwind
|
||||
PendSV_Handler:
|
||||
|
||||
PUSH {R0,LR} // Save EXC_RETURN
|
||||
BL osRtxPendSV_Handler // Call osRtxPendSV_Handler
|
||||
POP {R0,R1} // Restore EXC_RETURN
|
||||
MOV LR,R1 // Set EXC_RETURN
|
||||
B SVC_Context
|
||||
|
||||
.fnend
|
||||
.size PendSV_Handler, .-PendSV_Handler
|
||||
|
||||
|
||||
.thumb_func
|
||||
.type SysTick_Handler, %function
|
||||
.global SysTick_Handler
|
||||
.fnstart
|
||||
.cantunwind
|
||||
SysTick_Handler:
|
||||
|
||||
PUSH {R0,LR} // Save EXC_RETURN
|
||||
BL osRtxTick_Handler // Call osRtxTick_Handler
|
||||
POP {R0,R1} // Restore EXC_RETURN
|
||||
MOV LR,R1 // Set EXC_RETURN
|
||||
B SVC_Context
|
||||
|
||||
.fnend
|
||||
.size SysTick_Handler, .-SysTick_Handler
|
||||
|
||||
|
||||
.end
|
||||
@@ -0,0 +1,143 @@
|
||||
/*
|
||||
* Copyright (c) 2013-2018 Arm Limited. All rights reserved.
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the License); you may
|
||||
* not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an AS IS BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
* -----------------------------------------------------------------------------
|
||||
*
|
||||
* Project: CMSIS-RTOS RTX
|
||||
* Title: Cortex-M3 Exception handlers
|
||||
*
|
||||
* -----------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
|
||||
.syntax unified
|
||||
|
||||
.equ I_T_RUN_OFS, 20 // osRtxInfo.thread.run offset
|
||||
.equ TCB_SP_OFS, 56 // TCB.SP offset
|
||||
|
||||
.section ".rodata"
|
||||
.global irqRtxLib // Non weak library reference
|
||||
irqRtxLib:
|
||||
.byte 0
|
||||
|
||||
|
||||
.thumb
|
||||
.section ".text"
|
||||
.align 2
|
||||
|
||||
|
||||
.thumb_func
|
||||
.type SVC_Handler, %function
|
||||
.global SVC_Handler
|
||||
.fnstart
|
||||
.cantunwind
|
||||
SVC_Handler:
|
||||
|
||||
TST LR,#0x04 // Determine return stack from EXC_RETURN bit 2
|
||||
ITE EQ
|
||||
MRSEQ R0,MSP // Get MSP if return stack is MSP
|
||||
MRSNE R0,PSP // Get PSP if return stack is PSP
|
||||
|
||||
LDR R1,[R0,#24] // Load saved PC from stack
|
||||
LDRB R1,[R1,#-2] // Load SVC number
|
||||
CBNZ R1,SVC_User // Branch if not SVC 0
|
||||
|
||||
PUSH {R0,LR} // Save SP and EXC_RETURN
|
||||
LDM R0,{R0-R3,R12} // Load function parameters and address from stack
|
||||
BLX R12 // Call service function
|
||||
POP {R12,LR} // Restore SP and EXC_RETURN
|
||||
STM R12,{R0-R1} // Store function return values
|
||||
|
||||
SVC_Context:
|
||||
LDR R3,=osRtxInfo+I_T_RUN_OFS // Load address of osRtxInfo.run
|
||||
LDM R3,{R1,R2} // Load osRtxInfo.thread.run: curr & next
|
||||
CMP R1,R2 // Check if thread switch is required
|
||||
IT EQ
|
||||
BXEQ LR // Exit when threads are the same
|
||||
|
||||
CBZ R1,SVC_ContextSwitch // Branch if running thread is deleted
|
||||
|
||||
SVC_ContextSave:
|
||||
STMDB R12!,{R4-R11} // Save R4..R11
|
||||
STR R12,[R1,#TCB_SP_OFS] // Store SP
|
||||
|
||||
SVC_ContextSwitch:
|
||||
STR R2,[R3] // osRtxInfo.thread.run: curr = next
|
||||
|
||||
SVC_ContextRestore:
|
||||
LDR R0,[R2,#TCB_SP_OFS] // Load SP
|
||||
LDMIA R0!,{R4-R11} // Restore R4..R11
|
||||
MSR PSP,R0 // Set PSP
|
||||
MVN LR,#~0xFFFFFFFD // Set EXC_RETURN value
|
||||
|
||||
SVC_Exit:
|
||||
BX LR // Exit from handler
|
||||
|
||||
SVC_User:
|
||||
LDR R2,=osRtxUserSVC // Load address of SVC table
|
||||
LDR R3,[R2] // Load SVC maximum number
|
||||
CMP R1,R3 // Check SVC number range
|
||||
BHI SVC_Exit // Branch if out of range
|
||||
|
||||
PUSH {R0,LR} // Save SP and EXC_RETURN
|
||||
LDR R12,[R2,R1,LSL #2] // Load address of SVC function
|
||||
LDM R0,{R0-R3} // Load function parameters from stack
|
||||
BLX R12 // Call service function
|
||||
POP {R12,LR} // Restore SP and EXC_RETURN
|
||||
STR R0,[R12] // Store function return value
|
||||
|
||||
BX LR // Return from handler
|
||||
|
||||
.fnend
|
||||
.size SVC_Handler, .-SVC_Handler
|
||||
|
||||
|
||||
.thumb_func
|
||||
.type PendSV_Handler, %function
|
||||
.global PendSV_Handler
|
||||
.fnstart
|
||||
.cantunwind
|
||||
PendSV_Handler:
|
||||
|
||||
PUSH {R0,LR} // Save EXC_RETURN
|
||||
BL osRtxPendSV_Handler // Call osRtxPendSV_Handler
|
||||
POP {R0,LR} // Restore EXC_RETURN
|
||||
MRS R12,PSP
|
||||
B SVC_Context
|
||||
|
||||
.fnend
|
||||
.size PendSV_Handler, .-PendSV_Handler
|
||||
|
||||
|
||||
.thumb_func
|
||||
.type SysTick_Handler, %function
|
||||
.global SysTick_Handler
|
||||
.fnstart
|
||||
.cantunwind
|
||||
SysTick_Handler:
|
||||
|
||||
PUSH {R0,LR} // Save EXC_RETURN
|
||||
BL osRtxTick_Handler // Call osRtxTick_Handler
|
||||
POP {R0,LR} // Restore EXC_RETURN
|
||||
MRS R12,PSP
|
||||
B SVC_Context
|
||||
|
||||
.fnend
|
||||
.size SysTick_Handler, .-SysTick_Handler
|
||||
|
||||
|
||||
.end
|
||||
@@ -0,0 +1,160 @@
|
||||
/*
|
||||
* Copyright (c) 2013-2018 Arm Limited. All rights reserved.
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the License); you may
|
||||
* not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an AS IS BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
* -----------------------------------------------------------------------------
|
||||
*
|
||||
* Project: CMSIS-RTOS RTX
|
||||
* Title: Cortex-M4F Exception handlers
|
||||
*
|
||||
* -----------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
|
||||
.syntax unified
|
||||
|
||||
.equ I_T_RUN_OFS, 20 // osRtxInfo.thread.run offset
|
||||
.equ TCB_SP_OFS, 56 // TCB.SP offset
|
||||
.equ TCB_SF_OFS, 34 // TCB.stack_frame offset
|
||||
|
||||
.section ".rodata"
|
||||
.global irqRtxLib // Non weak library reference
|
||||
irqRtxLib:
|
||||
.byte 0
|
||||
|
||||
|
||||
.thumb
|
||||
.section ".text"
|
||||
.align 2
|
||||
|
||||
|
||||
.thumb_func
|
||||
.type SVC_Handler, %function
|
||||
.global SVC_Handler
|
||||
.fnstart
|
||||
.cantunwind
|
||||
SVC_Handler:
|
||||
|
||||
TST LR,#0x04 // Determine return stack from EXC_RETURN bit 2
|
||||
ITE EQ
|
||||
MRSEQ R0,MSP // Get MSP if return stack is MSP
|
||||
MRSNE R0,PSP // Get PSP if return stack is PSP
|
||||
|
||||
LDR R1,[R0,#24] // Load saved PC from stack
|
||||
LDRB R1,[R1,#-2] // Load SVC number
|
||||
CBNZ R1,SVC_User // Branch if not SVC 0
|
||||
|
||||
PUSH {R0,LR} // Save SP and EXC_RETURN
|
||||
LDM R0,{R0-R3,R12} // Load function parameters and address from stack
|
||||
BLX R12 // Call service function
|
||||
POP {R12,LR} // Restore SP and EXC_RETURN
|
||||
STM R12,{R0-R1} // Store function return values
|
||||
|
||||
SVC_Context:
|
||||
LDR R3,=osRtxInfo+I_T_RUN_OFS // Load address of osRtxInfo.run
|
||||
LDM R3,{R1,R2} // Load osRtxInfo.thread.run: curr & next
|
||||
CMP R1,R2 // Check if thread switch is required
|
||||
IT EQ
|
||||
BXEQ LR // Exit when threads are the same
|
||||
|
||||
CBNZ R1,SVC_ContextSave // Branch if running thread is not deleted
|
||||
TST LR,#0x10 // Check if extended stack frame
|
||||
BNE SVC_ContextSwitch
|
||||
LDR R1,=0xE000EF34 // FPCCR Address
|
||||
LDR R0,[R1] // Load FPCCR
|
||||
BIC R0,R0,#1 // Clear LSPACT (Lazy state)
|
||||
STR R0,[R1] // Store FPCCR
|
||||
B SVC_ContextSwitch
|
||||
|
||||
SVC_ContextSave:
|
||||
STMDB R12!,{R4-R11} // Save R4..R11
|
||||
TST LR,#0x10 // Check if extended stack frame
|
||||
IT EQ
|
||||
VSTMDBEQ R12!,{S16-S31} // Save VFP S16.S31
|
||||
STR R12,[R1,#TCB_SP_OFS] // Store SP
|
||||
STRB LR, [R1,#TCB_SF_OFS] // Store stack frame information
|
||||
|
||||
SVC_ContextSwitch:
|
||||
STR R2,[R3] // osRtxInfo.thread.run: curr = next
|
||||
|
||||
SVC_ContextRestore:
|
||||
LDRB R1,[R2,#TCB_SF_OFS] // Load stack frame information
|
||||
LDR R0,[R2,#TCB_SP_OFS] // Load SP
|
||||
ORR LR,R1,#0xFFFFFF00 // Set EXC_RETURN
|
||||
|
||||
TST LR,#0x10 // Check if extended stack frame
|
||||
IT EQ
|
||||
VLDMIAEQ R0!,{S16-S31} // Restore VFP S16..S31
|
||||
LDMIA R0!,{R4-R11} // Restore R4..R11
|
||||
MSR PSP,R0 // Set PSP
|
||||
|
||||
SVC_Exit:
|
||||
BX LR // Exit from handler
|
||||
|
||||
SVC_User:
|
||||
LDR R2,=osRtxUserSVC // Load address of SVC table
|
||||
LDR R3,[R2] // Load SVC maximum number
|
||||
CMP R1,R3 // Check SVC number range
|
||||
BHI SVC_Exit // Branch if out of range
|
||||
|
||||
PUSH {R0,LR} // Save SP and EXC_RETURN
|
||||
LDR R12,[R2,R1,LSL #2] // Load address of SVC function
|
||||
LDM R0,{R0-R3} // Load function parameters from stack
|
||||
BLX R12 // Call service function
|
||||
POP {R12,LR} // Restore SP and EXC_RETURN
|
||||
STR R0,[R12] // Store function return value
|
||||
|
||||
BX LR // Return from handler
|
||||
|
||||
.fnend
|
||||
.size SVC_Handler, .-SVC_Handler
|
||||
|
||||
|
||||
.thumb_func
|
||||
.type PendSV_Handler, %function
|
||||
.global PendSV_Handler
|
||||
.fnstart
|
||||
.cantunwind
|
||||
PendSV_Handler:
|
||||
|
||||
PUSH {R0,LR} // Save EXC_RETURN
|
||||
BL osRtxPendSV_Handler // Call osRtxPendSV_Handler
|
||||
POP {R0,LR} // Restore EXC_RETURN
|
||||
MRS R12,PSP
|
||||
B SVC_Context
|
||||
|
||||
.fnend
|
||||
.size PendSV_Handler, .-PendSV_Handler
|
||||
|
||||
|
||||
.thumb_func
|
||||
.type SysTick_Handler, %function
|
||||
.global SysTick_Handler
|
||||
.fnstart
|
||||
.cantunwind
|
||||
SysTick_Handler:
|
||||
|
||||
PUSH {R0,LR} // Save EXC_RETURN
|
||||
BL osRtxTick_Handler // Call osRtxTick_Handler
|
||||
POP {R0,LR} // Restore EXC_RETURN
|
||||
MRS R12,PSP
|
||||
B SVC_Context
|
||||
|
||||
.fnend
|
||||
.size SysTick_Handler, .-SysTick_Handler
|
||||
|
||||
|
||||
.end
|
||||
@@ -0,0 +1,4 @@
|
||||
NAME irq_armv8mbl.s
|
||||
#define DOMAIN_NS 0
|
||||
#include "irq_armv8mbl_common.s"
|
||||
END
|
||||
@@ -0,0 +1,301 @@
|
||||
;/*
|
||||
; * Copyright (c) 2016-2020 Arm Limited. All rights reserved.
|
||||
; *
|
||||
; * SPDX-License-Identifier: Apache-2.0
|
||||
; *
|
||||
; * Licensed under the Apache License, Version 2.0 (the License); you may
|
||||
; * not use this file except in compliance with the License.
|
||||
; * You may obtain a copy of the License at
|
||||
; *
|
||||
; * www.apache.org/licenses/LICENSE-2.0
|
||||
; *
|
||||
; * Unless required by applicable law or agreed to in writing, software
|
||||
; * distributed under the License is distributed on an AS IS BASIS, WITHOUT
|
||||
; * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
; * See the License for the specific language governing permissions and
|
||||
; * limitations under the License.
|
||||
; *
|
||||
; * -----------------------------------------------------------------------------
|
||||
; *
|
||||
; * Project: CMSIS-RTOS RTX
|
||||
; * Title: ARMv8M Baseline Exception handlers
|
||||
; *
|
||||
; * -----------------------------------------------------------------------------
|
||||
; */
|
||||
|
||||
|
||||
#ifndef DOMAIN_NS
|
||||
#define DOMAIN_NS 0
|
||||
#endif
|
||||
|
||||
I_T_RUN_OFS EQU 20 ; osRtxInfo.thread.run offset
|
||||
TCB_SM_OFS EQU 48 ; TCB.stack_mem offset
|
||||
TCB_SP_OFS EQU 56 ; TCB.SP offset
|
||||
TCB_SF_OFS EQU 34 ; TCB.stack_frame offset
|
||||
TCB_TZM_OFS EQU 64 ; TCB.tz_memory offset
|
||||
|
||||
|
||||
PRESERVE8
|
||||
|
||||
|
||||
SECTION .rodata:DATA:NOROOT(2)
|
||||
EXPORT irqRtxLib
|
||||
irqRtxLib DCB 0 ; Non weak library reference
|
||||
|
||||
|
||||
SECTION .text:CODE:NOROOT(2)
|
||||
THUMB
|
||||
|
||||
|
||||
SVC_Handler
|
||||
EXPORT SVC_Handler
|
||||
IMPORT osRtxUserSVC
|
||||
IMPORT osRtxInfo
|
||||
#if (DOMAIN_NS == 1)
|
||||
IMPORT TZ_LoadContext_S
|
||||
IMPORT TZ_StoreContext_S
|
||||
#endif
|
||||
|
||||
MOV R0,LR
|
||||
LSRS R0,R0,#3 ; Determine return stack from EXC_RETURN bit 2
|
||||
BCC SVC_MSP ; Branch if return stack is MSP
|
||||
MRS R0,PSP ; Get PSP
|
||||
|
||||
SVC_Number
|
||||
LDR R1,[R0,#24] ; Load saved PC from stack
|
||||
SUBS R1,R1,#2 ; Point to SVC instruction
|
||||
LDRB R1,[R1] ; Load SVC number
|
||||
CMP R1,#0
|
||||
BNE SVC_User ; Branch if not SVC 0
|
||||
|
||||
PUSH {R0,LR} ; Save SP and EXC_RETURN
|
||||
LDM R0,{R0-R3} ; Load function parameters from stack
|
||||
BLX R7 ; Call service function
|
||||
POP {R2,R3} ; Restore SP and EXC_RETURN
|
||||
STMIA R2!,{R0-R1} ; Store function return values
|
||||
MOV LR,R3 ; Set EXC_RETURN
|
||||
|
||||
SVC_Context
|
||||
LDR R3,=osRtxInfo+I_T_RUN_OFS; Load address of osRtxInfo.run
|
||||
LDMIA R3!,{R1,R2} ; Load osRtxInfo.thread.run: curr & next
|
||||
CMP R1,R2 ; Check if thread switch is required
|
||||
BEQ SVC_Exit ; Branch when threads are the same
|
||||
|
||||
CBZ R1,SVC_ContextSwitch ; Branch if running thread is deleted
|
||||
|
||||
SVC_ContextSave
|
||||
#if (DOMAIN_NS == 1)
|
||||
LDR R0,[R1,#TCB_TZM_OFS] ; Load TrustZone memory identifier
|
||||
CBZ R0,SVC_ContextSave1 ; Branch if there is no secure context
|
||||
PUSH {R1,R2,R3,R7} ; Save registers
|
||||
MOV R7,LR ; Get EXC_RETURN
|
||||
BL TZ_StoreContext_S ; Store secure context
|
||||
MOV LR,R7 ; Set EXC_RETURN
|
||||
POP {R1,R2,R3,R7} ; Restore registers
|
||||
#endif
|
||||
|
||||
SVC_ContextSave1
|
||||
MRS R0,PSP ; Get PSP
|
||||
SUBS R0,R0,#32 ; Calculate SP
|
||||
STR R0,[R1,#TCB_SP_OFS] ; Store SP
|
||||
STMIA R0!,{R4-R7} ; Save R4..R7
|
||||
MOV R4,R8
|
||||
MOV R5,R9
|
||||
MOV R6,R10
|
||||
MOV R7,R11
|
||||
STMIA R0!,{R4-R7} ; Save R8..R11
|
||||
|
||||
SVC_ContextSave2
|
||||
MOV R0,LR ; Get EXC_RETURN
|
||||
ADDS R1,R1,#TCB_SF_OFS ; Adjust address
|
||||
STRB R0,[R1] ; Store stack frame information
|
||||
|
||||
SVC_ContextSwitch
|
||||
SUBS R3,R3,#8 ; Adjust address
|
||||
STR R2,[R3] ; osRtxInfo.thread.run: curr = next
|
||||
|
||||
SVC_ContextRestore
|
||||
#if (DOMAIN_NS == 1)
|
||||
LDR R0,[R2,#TCB_TZM_OFS] ; Load TrustZone memory identifier
|
||||
CBZ R0,SVC_ContextRestore1 ; Branch if there is no secure context
|
||||
PUSH {R2,R3} ; Save registers
|
||||
BL TZ_LoadContext_S ; Load secure context
|
||||
POP {R2,R3} ; Restore registers
|
||||
#endif
|
||||
|
||||
SVC_ContextRestore1
|
||||
MOV R1,R2
|
||||
ADDS R1,R1,#TCB_SF_OFS ; Adjust address
|
||||
LDRB R0,[R1] ; Load stack frame information
|
||||
MOVS R1,#0xFF
|
||||
MVNS R1,R1 ; R1=0xFFFFFF00
|
||||
ORRS R0,R1
|
||||
MOV LR,R0 ; Set EXC_RETURN
|
||||
|
||||
#if (DOMAIN_NS == 1)
|
||||
LSLS R0,R0,#25 ; Check domain of interrupted thread
|
||||
BPL SVC_ContextRestore2 ; Branch if non-secure
|
||||
LDR R0,[R2,#TCB_SP_OFS] ; Load SP
|
||||
MSR PSP,R0 ; Set PSP
|
||||
BX LR ; Exit from handler
|
||||
#else
|
||||
LDR R0,[R2,#TCB_SM_OFS] ; Load stack memory base
|
||||
MSR PSPLIM,R0 ; Set PSPLIM
|
||||
#endif
|
||||
|
||||
SVC_ContextRestore2
|
||||
LDR R0,[R2,#TCB_SP_OFS] ; Load SP
|
||||
ADDS R0,R0,#16 ; Adjust address
|
||||
LDMIA R0!,{R4-R7} ; Restore R8..R11
|
||||
MOV R8,R4
|
||||
MOV R9,R5
|
||||
MOV R10,R6
|
||||
MOV R11,R7
|
||||
MSR PSP,R0 ; Set PSP
|
||||
SUBS R0,R0,#32 ; Adjust address
|
||||
LDMIA R0!,{R4-R7} ; Restore R4..R7
|
||||
|
||||
SVC_Exit
|
||||
BX LR ; Exit from handler
|
||||
|
||||
SVC_MSP
|
||||
MRS R0,MSP ; Get MSP
|
||||
B SVC_Number
|
||||
|
||||
SVC_User
|
||||
LDR R2,=osRtxUserSVC ; Load address of SVC table
|
||||
LDR R3,[R2] ; Load SVC maximum number
|
||||
CMP R1,R3 ; Check SVC number range
|
||||
BHI SVC_Exit ; Branch if out of range
|
||||
|
||||
PUSH {R0,LR} ; Save SP and EXC_RETURN
|
||||
LSLS R1,R1,#2
|
||||
LDR R3,[R2,R1] ; Load address of SVC function
|
||||
MOV R12,R3
|
||||
LDMIA R0,{R0-R3} ; Load function parameters from stack
|
||||
BLX R12 ; Call service function
|
||||
POP {R2,R3} ; Restore SP and EXC_RETURN
|
||||
STR R0,[R2] ; Store function return value
|
||||
MOV LR,R3 ; Set EXC_RETURN
|
||||
|
||||
BX LR ; Return from handler
|
||||
|
||||
|
||||
PendSV_Handler
|
||||
EXPORT PendSV_Handler
|
||||
IMPORT osRtxPendSV_Handler
|
||||
|
||||
PUSH {R0,LR} ; Save EXC_RETURN
|
||||
BL osRtxPendSV_Handler ; Call osRtxPendSV_Handler
|
||||
POP {R0,R1} ; Restore EXC_RETURN
|
||||
MOV LR,R1 ; Set EXC_RETURN
|
||||
B Sys_Context
|
||||
|
||||
|
||||
SysTick_Handler
|
||||
EXPORT SysTick_Handler
|
||||
IMPORT osRtxTick_Handler
|
||||
|
||||
PUSH {R0,LR} ; Save EXC_RETURN
|
||||
BL osRtxTick_Handler ; Call osRtxTick_Handler
|
||||
POP {R0,R1} ; Restore EXC_RETURN
|
||||
MOV LR,R1 ; Set EXC_RETURN
|
||||
B Sys_Context
|
||||
|
||||
|
||||
|
||||
Sys_Context
|
||||
EXPORT Sys_Context
|
||||
IMPORT osRtxInfo
|
||||
#if (DOMAIN_NS == 1)
|
||||
IMPORT TZ_LoadContext_S
|
||||
IMPORT TZ_StoreContext_S
|
||||
#endif
|
||||
|
||||
LDR R3,=osRtxInfo+I_T_RUN_OFS; Load address of osRtxInfo.run
|
||||
LDM R3!,{R1,R2} ; Load osRtxInfo.thread.run: curr & next
|
||||
CMP R1,R2 ; Check if thread switch is required
|
||||
BEQ Sys_ContextExit ; Branch when threads are the same
|
||||
|
||||
Sys_ContextSave
|
||||
#if (DOMAIN_NS == 1)
|
||||
LDR R0,[R1,#TCB_TZM_OFS] ; Load TrustZone memory identifier
|
||||
CBZ R0,Sys_ContextSave1 ; Branch if there is no secure context
|
||||
PUSH {R1,R2,R3,R7} ; Save registers
|
||||
MOV R7,LR ; Get EXC_RETURN
|
||||
BL TZ_StoreContext_S ; Store secure context
|
||||
MOV LR,R7 ; Set EXC_RETURN
|
||||
POP {R1,R2,R3,R7} ; Restore registers
|
||||
|
||||
Sys_ContextSave1
|
||||
MOV R0,LR ; Get EXC_RETURN
|
||||
LSLS R0,R0,#25 ; Check domain of interrupted thread
|
||||
BPL Sys_ContextSave2 ; Branch if non-secure
|
||||
MRS R0,PSP ; Get PSP
|
||||
STR R0,[R1,#TCB_SP_OFS] ; Store SP
|
||||
B Sys_ContextSave3
|
||||
#endif
|
||||
|
||||
Sys_ContextSave2
|
||||
MRS R0,PSP ; Get PSP
|
||||
SUBS R0,R0,#32 ; Adjust address
|
||||
STR R0,[R1,#TCB_SP_OFS] ; Store SP
|
||||
STMIA R0!,{R4-R7} ; Save R4..R7
|
||||
MOV R4,R8
|
||||
MOV R5,R9
|
||||
MOV R6,R10
|
||||
MOV R7,R11
|
||||
STMIA R0!,{R4-R7} ; Save R8..R11
|
||||
|
||||
Sys_ContextSave3
|
||||
MOV R0,LR ; Get EXC_RETURN
|
||||
ADDS R1,R1,#TCB_SF_OFS ; Adjust address
|
||||
STRB R0,[R1] ; Store stack frame information
|
||||
|
||||
Sys_ContextSwitch
|
||||
SUBS R3,R3,#8 ; Adjust address
|
||||
STR R2,[R3] ; osRtxInfo.run: curr = next
|
||||
|
||||
Sys_ContextRestore
|
||||
#if (DOMAIN_NS == 1)
|
||||
LDR R0,[R2,#TCB_TZM_OFS] ; Load TrustZone memory identifier
|
||||
CBZ R0,Sys_ContextRestore1 ; Branch if there is no secure context
|
||||
PUSH {R2,R3} ; Save registers
|
||||
BL TZ_LoadContext_S ; Load secure context
|
||||
POP {R2,R3} ; Restore registers
|
||||
#endif
|
||||
|
||||
Sys_ContextRestore1
|
||||
MOV R1,R2
|
||||
ADDS R1,R1,#TCB_SF_OFS ; Adjust offset
|
||||
LDRB R0,[R1] ; Load stack frame information
|
||||
MOVS R1,#0xFF
|
||||
MVNS R1,R1 ; R1=0xFFFFFF00
|
||||
ORRS R0,R1
|
||||
MOV LR,R0 ; Set EXC_RETURN
|
||||
|
||||
#if (DOMAIN_NS == 1)
|
||||
LSLS R0,R0,#25 ; Check domain of interrupted thread
|
||||
BPL Sys_ContextRestore2 ; Branch if non-secure
|
||||
LDR R0,[R2,#TCB_SP_OFS] ; Load SP
|
||||
MSR PSP,R0 ; Set PSP
|
||||
BX LR ; Exit from handler
|
||||
#else
|
||||
LDR R0,[R2,#TCB_SM_OFS] ; Load stack memory base
|
||||
MSR PSPLIM,R0 ; Set PSPLIM
|
||||
#endif
|
||||
|
||||
Sys_ContextRestore2
|
||||
LDR R0,[R2,#TCB_SP_OFS] ; Load SP
|
||||
ADDS R0,R0,#16 ; Adjust address
|
||||
LDMIA R0!,{R4-R7} ; Restore R8..R11
|
||||
MOV R8,R4
|
||||
MOV R9,R5
|
||||
MOV R10,R6
|
||||
MOV R11,R7
|
||||
MSR PSP,R0 ; Set PSP
|
||||
SUBS R0,R0,#32 ; Adjust address
|
||||
LDMIA R0!,{R4-R7} ; Restore R4..R7
|
||||
|
||||
Sys_ContextExit
|
||||
BX LR ; Exit from handler
|
||||
@@ -0,0 +1,4 @@
|
||||
NAME irq_armv8mbl_ns.s
|
||||
#define DOMAIN_NS 1
|
||||
#include "irq_armv8mbl_common.s"
|
||||
END
|
||||
@@ -0,0 +1,4 @@
|
||||
NAME irq_armv8mml.s
|
||||
#define DOMAIN_NS 0
|
||||
#include "irq_armv8mml_common.s"
|
||||
END
|
||||
@@ -0,0 +1,280 @@
|
||||
;/*
|
||||
; * Copyright (c) 2016-2020 Arm Limited. All rights reserved.
|
||||
; *
|
||||
; * SPDX-License-Identifier: Apache-2.0
|
||||
; *
|
||||
; * Licensed under the Apache License, Version 2.0 (the License); you may
|
||||
; * not use this file except in compliance with the License.
|
||||
; * You may obtain a copy of the License at
|
||||
; *
|
||||
; * www.apache.org/licenses/LICENSE-2.0
|
||||
; *
|
||||
; * Unless required by applicable law or agreed to in writing, software
|
||||
; * distributed under the License is distributed on an AS IS BASIS, WITHOUT
|
||||
; * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
; * See the License for the specific language governing permissions and
|
||||
; * limitations under the License.
|
||||
; *
|
||||
; * -----------------------------------------------------------------------------
|
||||
; *
|
||||
; * Project: CMSIS-RTOS RTX
|
||||
; * Title: ARMv8M Mainline Exception handlers
|
||||
; *
|
||||
; * -----------------------------------------------------------------------------
|
||||
; */
|
||||
|
||||
|
||||
#ifndef DOMAIN_NS
|
||||
#define DOMAIN_NS 0
|
||||
#endif
|
||||
|
||||
#ifdef __ARMVFP__
|
||||
FPU_USED EQU 1
|
||||
#else
|
||||
FPU_USED EQU 0
|
||||
#endif
|
||||
|
||||
#if (defined(__ARM_FEATURE_MVE) && (__ARM_FEATURE_MVE > 0))
|
||||
MVE_USED EQU 1
|
||||
#else
|
||||
MVE_USED EQU 0
|
||||
#endif
|
||||
|
||||
I_T_RUN_OFS EQU 20 ; osRtxInfo.thread.run offset
|
||||
TCB_SM_OFS EQU 48 ; TCB.stack_mem offset
|
||||
TCB_SP_OFS EQU 56 ; TCB.SP offset
|
||||
TCB_SF_OFS EQU 34 ; TCB.stack_frame offset
|
||||
TCB_TZM_OFS EQU 64 ; TCB.tz_memory offset
|
||||
|
||||
|
||||
PRESERVE8
|
||||
|
||||
|
||||
SECTION .rodata:DATA:NOROOT(2)
|
||||
EXPORT irqRtxLib
|
||||
irqRtxLib DCB 0 ; Non weak library reference
|
||||
|
||||
|
||||
SECTION .text:CODE:NOROOT(2)
|
||||
THUMB
|
||||
|
||||
|
||||
SVC_Handler
|
||||
EXPORT SVC_Handler
|
||||
IMPORT osRtxUserSVC
|
||||
IMPORT osRtxInfo
|
||||
#if (DOMAIN_NS == 1)
|
||||
IMPORT TZ_LoadContext_S
|
||||
IMPORT TZ_StoreContext_S
|
||||
#endif
|
||||
|
||||
TST LR,#0x04 ; Determine return stack from EXC_RETURN bit 2
|
||||
ITE EQ
|
||||
MRSEQ R0,MSP ; Get MSP if return stack is MSP
|
||||
MRSNE R0,PSP ; Get PSP if return stack is PSP
|
||||
|
||||
LDR R1,[R0,#24] ; Load saved PC from stack
|
||||
LDRB R1,[R1,#-2] ; Load SVC number
|
||||
CMP R1,#0
|
||||
BNE SVC_User ; Branch if not SVC 0
|
||||
|
||||
PUSH {R0,LR} ; Save SP and EXC_RETURN
|
||||
LDM R0,{R0-R3,R12} ; Load function parameters and address from stack
|
||||
BLX R12 ; Call service function
|
||||
POP {R12,LR} ; Restore SP and EXC_RETURN
|
||||
STM R12,{R0-R1} ; Store function return values
|
||||
|
||||
SVC_Context
|
||||
LDR R3,=osRtxInfo+I_T_RUN_OFS; Load address of osRtxInfo.run
|
||||
LDM R3,{R1,R2} ; Load osRtxInfo.thread.run: curr & next
|
||||
CMP R1,R2 ; Check if thread switch is required
|
||||
IT EQ
|
||||
BXEQ LR ; Exit when threads are the same
|
||||
|
||||
#if ((FPU_USED == 1) || (MVE_USED == 1))
|
||||
CBNZ R1,SVC_ContextSave ; Branch if running thread is not deleted
|
||||
TST LR,#0x10 ; Check if extended stack frame
|
||||
BNE SVC_ContextSwitch
|
||||
LDR R1,=0xE000EF34 ; FPCCR Address
|
||||
LDR R0,[R1] ; Load FPCCR
|
||||
BIC R0,R0,#1 ; Clear LSPACT (Lazy state)
|
||||
STR R0,[R1] ; Store FPCCR
|
||||
B SVC_ContextSwitch
|
||||
#else
|
||||
CBZ R1,SVC_ContextSwitch ; Branch if running thread is deleted
|
||||
#endif
|
||||
|
||||
SVC_ContextSave
|
||||
#if (DOMAIN_NS == 1)
|
||||
LDR R0,[R1,#TCB_TZM_OFS] ; Load TrustZone memory identifier
|
||||
CBZ R0,SVC_ContextSave1 ; Branch if there is no secure context
|
||||
PUSH {R1,R2,R3,LR} ; Save registers and EXC_RETURN
|
||||
BL TZ_StoreContext_S ; Store secure context
|
||||
POP {R1,R2,R3,LR} ; Restore registers and EXC_RETURN
|
||||
#endif
|
||||
|
||||
SVC_ContextSave1
|
||||
MRS R0,PSP ; Get PSP
|
||||
STMDB R0!,{R4-R11} ; Save R4..R11
|
||||
#if ((FPU_USED == 1) || (MVE_USED == 1))
|
||||
TST LR,#0x10 ; Check if extended stack frame
|
||||
IT EQ
|
||||
VSTMDBEQ R0!,{S16-S31} ; Save VFP S16.S31
|
||||
#endif
|
||||
|
||||
SVC_ContextSave2
|
||||
STR R0,[R1,#TCB_SP_OFS] ; Store SP
|
||||
STRB LR,[R1,#TCB_SF_OFS] ; Store stack frame information
|
||||
|
||||
SVC_ContextSwitch
|
||||
STR R2,[R3] ; osRtxInfo.thread.run: curr = next
|
||||
|
||||
SVC_ContextRestore
|
||||
#if (DOMAIN_NS == 1)
|
||||
LDR R0,[R2,#TCB_TZM_OFS] ; Load TrustZone memory identifier
|
||||
CBZ R0,SVC_ContextRestore1 ; Branch if there is no secure context
|
||||
PUSH {R2,R3} ; Save registers
|
||||
BL TZ_LoadContext_S ; Load secure context
|
||||
POP {R2,R3} ; Restore registers
|
||||
#endif
|
||||
|
||||
SVC_ContextRestore1
|
||||
LDR R0,[R2,#TCB_SM_OFS] ; Load stack memory base
|
||||
LDRB R1,[R2,#TCB_SF_OFS] ; Load stack frame information
|
||||
MSR PSPLIM,R0 ; Set PSPLIM
|
||||
LDR R0,[R2,#TCB_SP_OFS] ; Load SP
|
||||
ORR LR,R1,#0xFFFFFF00 ; Set EXC_RETURN
|
||||
|
||||
#if (DOMAIN_NS == 1)
|
||||
TST LR,#0x40 ; Check domain of interrupted thread
|
||||
BNE SVC_ContextRestore2 ; Branch if secure
|
||||
#endif
|
||||
|
||||
#if ((FPU_USED == 1) || (MVE_USED == 1))
|
||||
TST LR,#0x10 ; Check if extended stack frame
|
||||
IT EQ
|
||||
VLDMIAEQ R0!,{S16-S31} ; Restore VFP S16..S31
|
||||
#endif
|
||||
LDMIA R0!,{R4-R11} ; Restore R4..R11
|
||||
|
||||
SVC_ContextRestore2
|
||||
MSR PSP,R0 ; Set PSP
|
||||
|
||||
SVC_Exit
|
||||
BX LR ; Exit from handler
|
||||
|
||||
SVC_User
|
||||
LDR R2,=osRtxUserSVC ; Load address of SVC table
|
||||
LDR R3,[R2] ; Load SVC maximum number
|
||||
CMP R1,R3 ; Check SVC number range
|
||||
BHI SVC_Exit ; Branch if out of range
|
||||
|
||||
PUSH {R0,LR} ; Save SP and EXC_RETURN
|
||||
LDR R12,[R2,R1,LSL #2] ; Load address of SVC function
|
||||
LDM R0,{R0-R3} ; Load function parameters from stack
|
||||
BLX R12 ; Call service function
|
||||
POP {R12,LR} ; Restore SP and EXC_RETURN
|
||||
STR R0,[R12] ; Store function return value
|
||||
|
||||
BX LR ; Return from handler
|
||||
|
||||
|
||||
PendSV_Handler
|
||||
EXPORT PendSV_Handler
|
||||
IMPORT osRtxPendSV_Handler
|
||||
|
||||
PUSH {R0,LR} ; Save EXC_RETURN
|
||||
BL osRtxPendSV_Handler ; Call osRtxPendSV_Handler
|
||||
POP {R0,LR} ; Restore EXC_RETURN
|
||||
B Sys_Context
|
||||
|
||||
|
||||
SysTick_Handler
|
||||
EXPORT SysTick_Handler
|
||||
IMPORT osRtxTick_Handler
|
||||
|
||||
PUSH {R0,LR} ; Save EXC_RETURN
|
||||
BL osRtxTick_Handler ; Call osRtxTick_Handler
|
||||
POP {R0,LR} ; Restore EXC_RETURN
|
||||
B Sys_Context
|
||||
|
||||
|
||||
|
||||
Sys_Context
|
||||
EXPORT Sys_Context
|
||||
IMPORT osRtxInfo
|
||||
#if (DOMAIN_NS == 1)
|
||||
IMPORT TZ_LoadContext_S
|
||||
IMPORT TZ_StoreContext_S
|
||||
#endif
|
||||
|
||||
LDR R3,=osRtxInfo+I_T_RUN_OFS; Load address of osRtxInfo.run
|
||||
LDM R3,{R1,R2} ; Load osRtxInfo.thread.run: curr & next
|
||||
CMP R1,R2 ; Check if thread switch is required
|
||||
IT EQ
|
||||
BXEQ LR ; Exit when threads are the same
|
||||
|
||||
Sys_ContextSave
|
||||
#if (DOMAIN_NS == 1)
|
||||
LDR R0,[R1,#TCB_TZM_OFS] ; Load TrustZone memory identifier
|
||||
CBZ R0,Sys_ContextSave1 ; Branch if there is no secure context
|
||||
PUSH {R1,R2,R3,LR} ; Save registers and EXC_RETURN
|
||||
BL TZ_StoreContext_S ; Store secure context
|
||||
POP {R1,R2,R3,LR} ; Restore registers and EXC_RETURN
|
||||
|
||||
Sys_ContextSave1
|
||||
TST LR,#0x40 ; Check domain of interrupted thread
|
||||
IT NE
|
||||
MRSNE R0,PSP ; Get PSP
|
||||
BNE Sys_ContextSave3 ; Branch if secure
|
||||
#endif
|
||||
|
||||
Sys_ContextSave2
|
||||
MRS R0,PSP ; Get PSP
|
||||
STMDB R0!,{R4-R11} ; Save R4..R11
|
||||
#if ((FPU_USED == 1) || (MVE_USED == 1))
|
||||
TST LR,#0x10 ; Check if extended stack frame
|
||||
IT EQ
|
||||
VSTMDBEQ R0!,{S16-S31} ; Save VFP S16.S31
|
||||
#endif
|
||||
|
||||
Sys_ContextSave3
|
||||
STR R0,[R1,#TCB_SP_OFS] ; Store SP
|
||||
STRB LR,[R1,#TCB_SF_OFS] ; Store stack frame information
|
||||
|
||||
Sys_ContextSwitch
|
||||
STR R2,[R3] ; osRtxInfo.run: curr = next
|
||||
|
||||
Sys_ContextRestore
|
||||
#if (DOMAIN_NS == 1)
|
||||
LDR R0,[R2,#TCB_TZM_OFS] ; Load TrustZone memory identifier
|
||||
CBZ R0,Sys_ContextRestore1 ; Branch if there is no secure context
|
||||
PUSH {R2,R3} ; Save registers
|
||||
BL TZ_LoadContext_S ; Load secure context
|
||||
POP {R2,R3} ; Restore registers
|
||||
#endif
|
||||
|
||||
Sys_ContextRestore1
|
||||
LDR R0,[R2,#TCB_SM_OFS] ; Load stack memory base
|
||||
LDRB R1,[R2,#TCB_SF_OFS] ; Load stack frame information
|
||||
MSR PSPLIM,R0 ; Set PSPLIM
|
||||
LDR R0,[R2,#TCB_SP_OFS] ; Load SP
|
||||
ORR LR,R1,#0xFFFFFF00 ; Set EXC_RETURN
|
||||
|
||||
#if (DOMAIN_NS == 1)
|
||||
TST LR,#0x40 ; Check domain of interrupted thread
|
||||
BNE Sys_ContextRestore2 ; Branch if secure
|
||||
#endif
|
||||
|
||||
#if ((FPU_USED == 1) || (MVE_USED == 1))
|
||||
TST LR,#0x10 ; Check if extended stack frame
|
||||
IT EQ
|
||||
VLDMIAEQ R0!,{S16-S31} ; Restore VFP S16..S31
|
||||
#endif
|
||||
LDMIA R0!,{R4-R11} ; Restore R4..R11
|
||||
|
||||
Sys_ContextRestore2
|
||||
MSR PSP,R0 ; Set PSP
|
||||
|
||||
Sys_ContextExit
|
||||
BX LR ; Exit from handler
|
||||
@@ -0,0 +1,4 @@
|
||||
NAME irq_armv8mml_ns.s
|
||||
#define DOMAIN_NS 1
|
||||
#include "irq_armv8mml_common.s"
|
||||
END
|
||||
@@ -0,0 +1,441 @@
|
||||
;/*
|
||||
; * Copyright (c) 2013-2018 Arm Limited. All rights reserved.
|
||||
; *
|
||||
; * SPDX-License-Identifier: Apache-2.0
|
||||
; *
|
||||
; * Licensed under the Apache License, Version 2.0 (the License); you may
|
||||
; * not use this file except in compliance with the License.
|
||||
; * You may obtain a copy of the License at
|
||||
; *
|
||||
; * www.apache.org/licenses/LICENSE-2.0
|
||||
; *
|
||||
; * Unless required by applicable law or agreed to in writing, software
|
||||
; * distributed under the License is distributed on an AS IS BASIS, WITHOUT
|
||||
; * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
; * See the License for the specific language governing permissions and
|
||||
; * limitations under the License.
|
||||
; *
|
||||
; * -----------------------------------------------------------------------------
|
||||
; *
|
||||
; * Project: CMSIS-RTOS RTX
|
||||
; * Title: Cortex-A Exception handlers
|
||||
; *
|
||||
; * -----------------------------------------------------------------------------
|
||||
; */
|
||||
|
||||
NAME irq_ca.s
|
||||
|
||||
MODE_FIQ EQU 0x11
|
||||
MODE_IRQ EQU 0x12
|
||||
MODE_SVC EQU 0x13
|
||||
MODE_ABT EQU 0x17
|
||||
MODE_UND EQU 0x1B
|
||||
|
||||
CPSR_BIT_T EQU 0x20
|
||||
|
||||
K_STATE_RUNNING EQU 2 ; osKernelState_t::osKernelRunning
|
||||
I_K_STATE_OFS EQU 8 ; osRtxInfo.kernel.state offset
|
||||
I_TICK_IRQN_OFS EQU 16 ; osRtxInfo.tick_irqn offset
|
||||
I_T_RUN_OFS EQU 20 ; osRtxInfo.thread.run offset
|
||||
TCB_SP_FRAME EQU 34 ; osRtxThread_t.stack_frame offset
|
||||
TCB_SP_OFS EQU 56 ; osRtxThread_t.sp offset
|
||||
|
||||
|
||||
PRESERVE8
|
||||
|
||||
|
||||
SECTION .rodata:DATA:NOROOT(2)
|
||||
EXPORT irqRtxLib
|
||||
irqRtxLib DCB 0 ; Non weak library reference
|
||||
|
||||
|
||||
SECTION .data:DATA:NOROOT(2)
|
||||
EXPORT IRQ_PendSV
|
||||
IRQ_NestLevel DCD 0 ; IRQ nesting level counter
|
||||
IRQ_PendSV DCB 0 ; Pending SVC flag
|
||||
|
||||
|
||||
SECTION .text:CODE:NOROOT(2)
|
||||
|
||||
|
||||
Undef_Handler
|
||||
EXPORT Undef_Handler
|
||||
IMPORT CUndefHandler
|
||||
|
||||
SRSFD SP!, #MODE_UND
|
||||
PUSH {R0-R4, R12} ; Save APCS corruptible registers to UND mode stack
|
||||
|
||||
MRS R0, SPSR
|
||||
TST R0, #CPSR_BIT_T ; Check mode
|
||||
MOVEQ R1, #4 ; R1 = 4 ARM mode
|
||||
MOVNE R1, #2 ; R1 = 2 Thumb mode
|
||||
SUB R0, LR, R1
|
||||
LDREQ R0, [R0] ; ARM mode - R0 points to offending instruction
|
||||
BEQ Undef_Cont
|
||||
|
||||
; Thumb instruction
|
||||
; Determine if it is a 32-bit Thumb instruction
|
||||
LDRH R0, [R0]
|
||||
MOV R2, #0x1C
|
||||
CMP R2, R0, LSR #11
|
||||
BHS Undef_Cont ; 16-bit Thumb instruction
|
||||
|
||||
; 32-bit Thumb instruction. Unaligned - reconstruct the offending instruction
|
||||
LDRH R2, [LR]
|
||||
ORR R0, R2, R0, LSL #16
|
||||
Undef_Cont
|
||||
MOV R2, LR ; Set LR to third argument
|
||||
|
||||
AND R12, SP, #4 ; Ensure stack is 8-byte aligned
|
||||
SUB SP, SP, R12 ; Adjust stack
|
||||
PUSH {R12, LR} ; Store stack adjustment and dummy LR
|
||||
|
||||
; R0 =Offending instruction, R1 =2(Thumb) or =4(ARM)
|
||||
BL CUndefHandler
|
||||
|
||||
POP {R12, LR} ; Get stack adjustment & discard dummy LR
|
||||
ADD SP, SP, R12 ; Unadjust stack
|
||||
|
||||
LDR LR, [SP, #24] ; Restore stacked LR and possibly adjust for retry
|
||||
SUB LR, LR, R0
|
||||
LDR R0, [SP, #28] ; Restore stacked SPSR
|
||||
MSR SPSR_CXSF, R0
|
||||
CLREX ; Clear exclusive monitor
|
||||
POP {R0-R4, R12} ; Restore stacked APCS registers
|
||||
ADD SP, SP, #8 ; Adjust SP for already-restored banked registers
|
||||
MOVS PC, LR
|
||||
|
||||
|
||||
PAbt_Handler
|
||||
EXPORT PAbt_Handler
|
||||
IMPORT CPAbtHandler
|
||||
|
||||
SUB LR, LR, #4 ; Pre-adjust LR
|
||||
SRSFD SP!, #MODE_ABT ; Save LR and SPRS to ABT mode stack
|
||||
PUSH {R0-R4, R12} ; Save APCS corruptible registers to ABT mode stack
|
||||
MRC p15, 0, R0, c5, c0, 1 ; IFSR
|
||||
MRC p15, 0, R1, c6, c0, 2 ; IFAR
|
||||
|
||||
MOV R2, LR ; Set LR to third argument
|
||||
|
||||
AND R12, SP, #4 ; Ensure stack is 8-byte aligned
|
||||
SUB SP, SP, R12 ; Adjust stack
|
||||
PUSH {R12, LR} ; Store stack adjustment and dummy LR
|
||||
|
||||
BL CPAbtHandler
|
||||
|
||||
POP {R12, LR} ; Get stack adjustment & discard dummy LR
|
||||
ADD SP, SP, R12 ; Unadjust stack
|
||||
|
||||
CLREX ; Clear exclusive monitor
|
||||
POP {R0-R4, R12} ; Restore stack APCS registers
|
||||
RFEFD SP! ; Return from exception
|
||||
|
||||
|
||||
DAbt_Handler
|
||||
EXPORT DAbt_Handler
|
||||
IMPORT CDAbtHandler
|
||||
|
||||
SUB LR, LR, #8 ; Pre-adjust LR
|
||||
SRSFD SP!, #MODE_ABT ; Save LR and SPRS to ABT mode stack
|
||||
PUSH {R0-R4, R12} ; Save APCS corruptible registers to ABT mode stack
|
||||
MRC p15, 0, R0, c5, c0, 0 ; DFSR
|
||||
MRC p15, 0, R1, c6, c0, 0 ; DFAR
|
||||
|
||||
MOV R2, LR ; Set LR to third argument
|
||||
|
||||
AND R12, SP, #4 ; Ensure stack is 8-byte aligned
|
||||
SUB SP, SP, R12 ; Adjust stack
|
||||
PUSH {R12, LR} ; Store stack adjustment and dummy LR
|
||||
|
||||
BL CDAbtHandler
|
||||
|
||||
POP {R12, LR} ; Get stack adjustment & discard dummy LR
|
||||
ADD SP, SP, R12 ; Unadjust stack
|
||||
|
||||
CLREX ; Clear exclusive monitor
|
||||
POP {R0-R4, R12} ; Restore stacked APCS registers
|
||||
RFEFD SP! ; Return from exception
|
||||
|
||||
|
||||
IRQ_Handler
|
||||
EXPORT IRQ_Handler
|
||||
IMPORT IRQ_GetActiveIRQ
|
||||
IMPORT IRQ_GetHandler
|
||||
IMPORT IRQ_EndOfInterrupt
|
||||
|
||||
SUB LR, LR, #4 ; Pre-adjust LR
|
||||
SRSFD SP!, #MODE_SVC ; Save LR_irq and SPSR_irq on to the SVC stack
|
||||
CPS #MODE_SVC ; Change to SVC mode
|
||||
PUSH {R0-R3, R12, LR} ; Save APCS corruptible registers
|
||||
|
||||
LDR R0, =IRQ_NestLevel
|
||||
LDR R1, [R0]
|
||||
ADD R1, R1, #1 ; Increment IRQ nesting level
|
||||
STR R1, [R0]
|
||||
|
||||
MOV R3, SP ; Move SP into R3
|
||||
AND R3, R3, #4 ; Get stack adjustment to ensure 8-byte alignment
|
||||
SUB SP, SP, R3 ; Adjust stack
|
||||
PUSH {R3, R4} ; Store stack adjustment(R3) and user data(R4)
|
||||
|
||||
BLX IRQ_GetActiveIRQ ; Retrieve interrupt ID into R0
|
||||
MOV R4, R0 ; Move interrupt ID to R4
|
||||
|
||||
BLX IRQ_GetHandler ; Retrieve interrupt handler address for current ID
|
||||
CMP R0, #0 ; Check if handler address is 0
|
||||
BEQ IRQ_End ; If 0, end interrupt and return
|
||||
|
||||
CPSIE i ; Re-enable interrupts
|
||||
BLX R0 ; Call IRQ handler
|
||||
CPSID i ; Disable interrupts
|
||||
|
||||
IRQ_End
|
||||
MOV R0, R4 ; Move interrupt ID to R0
|
||||
BLX IRQ_EndOfInterrupt ; Signal end of interrupt
|
||||
|
||||
POP {R3, R4} ; Restore stack adjustment(R3) and user data(R4)
|
||||
ADD SP, SP, R3 ; Unadjust stack
|
||||
|
||||
BL osRtxContextSwitch ; Continue in context switcher
|
||||
|
||||
LDR R0, =IRQ_NestLevel
|
||||
LDR R1, [R0]
|
||||
SUBS R1, R1, #1 ; Decrement IRQ nesting level
|
||||
STR R1, [R0]
|
||||
|
||||
CLREX ; Clear exclusive monitor for interrupted code
|
||||
POP {R0-R3, R12, LR} ; Restore stacked APCS registers
|
||||
RFEFD SP! ; Return from IRQ handler
|
||||
|
||||
|
||||
SVC_Handler
|
||||
EXPORT SVC_Handler
|
||||
IMPORT IRQ_Disable
|
||||
IMPORT IRQ_Enable
|
||||
IMPORT osRtxUserSVC
|
||||
IMPORT osRtxInfo
|
||||
|
||||
SRSFD SP!, #MODE_SVC ; Store SPSR_svc and LR_svc onto SVC stack
|
||||
PUSH {R12, LR}
|
||||
|
||||
MRS R12, SPSR ; Load SPSR
|
||||
TST R12, #CPSR_BIT_T ; Thumb bit set?
|
||||
LDRHNE R12, [LR,#-2] ; Thumb: load halfword
|
||||
BICNE R12, R12, #0xFF00 ; extract SVC number
|
||||
LDREQ R12, [LR,#-4] ; ARM: load word
|
||||
BICEQ R12, R12, #0xFF000000 ; extract SVC number
|
||||
CMP R12, #0 ; Compare SVC number
|
||||
BNE SVC_User ; Branch if User SVC
|
||||
|
||||
PUSH {R0-R3}
|
||||
|
||||
LDR R0, =IRQ_NestLevel
|
||||
LDR R1, [R0]
|
||||
ADD R1, R1, #1 ; Increment IRQ nesting level
|
||||
STR R1, [R0]
|
||||
|
||||
LDR R0, =osRtxInfo
|
||||
LDR R1, [R0, #I_K_STATE_OFS] ; Load RTX5 kernel state
|
||||
CMP R1, #K_STATE_RUNNING ; Check osKernelRunning
|
||||
BLT SVC_FuncCall ; Continue if kernel is not running
|
||||
LDR R0, [R0, #I_TICK_IRQN_OFS] ; Load OS Tick irqn
|
||||
BLX IRQ_Disable ; Disable OS Tick interrupt
|
||||
SVC_FuncCall
|
||||
POP {R0-R3}
|
||||
|
||||
LDR R12, [SP] ; Reload R12 from stack
|
||||
|
||||
CPSIE i ; Re-enable interrupts
|
||||
BLX R12 ; Branch to SVC function
|
||||
CPSID i ; Disable interrupts
|
||||
|
||||
SUB SP, SP, #4
|
||||
STM SP, {SP}^ ; Store SP_usr onto stack
|
||||
POP {R12} ; Pop SP_usr into R12
|
||||
SUB R12, R12, #16 ; Adjust pointer to SP_usr
|
||||
LDMDB R12, {R2,R3} ; Load return values from SVC function
|
||||
PUSH {R0-R3} ; Push return values to stack
|
||||
|
||||
LDR R0, =osRtxInfo
|
||||
LDR R1, [R0, #I_K_STATE_OFS] ; Load RTX5 kernel state
|
||||
CMP R1, #K_STATE_RUNNING ; Check osKernelRunning
|
||||
BLT SVC_ContextCheck ; Continue if kernel is not running
|
||||
LDR R0, [R0, #I_TICK_IRQN_OFS] ; Load OS Tick irqn
|
||||
BLX IRQ_Enable ; Enable OS Tick interrupt
|
||||
|
||||
SVC_ContextCheck
|
||||
BL osRtxContextSwitch ; Continue in context switcher
|
||||
|
||||
LDR R0, =IRQ_NestLevel
|
||||
LDR R1, [R0]
|
||||
SUB R1, R1, #1 ; Decrement IRQ nesting level
|
||||
STR R1, [R0]
|
||||
|
||||
CLREX ; Clear exclusive monitor
|
||||
POP {R0-R3, R12, LR} ; Restore stacked APCS registers
|
||||
RFEFD SP! ; Return from exception
|
||||
|
||||
SVC_User
|
||||
PUSH {R4, R5}
|
||||
LDR R5,=osRtxUserSVC ; Load address of SVC table
|
||||
LDR R4,[R5] ; Load SVC maximum number
|
||||
CMP R12,R4 ; Check SVC number range
|
||||
BHI SVC_Done ; Branch if out of range
|
||||
LDR R12,[R5,R12,LSL #2] ; Load SVC Function Address
|
||||
BLX R12 ; Call SVC Function
|
||||
SVC_Done
|
||||
CLREX ; Clear exclusive monitor
|
||||
POP {R4, R5, R12, LR}
|
||||
RFEFD SP! ; Return from exception
|
||||
|
||||
|
||||
osRtxContextSwitch
|
||||
EXPORT osRtxContextSwitch
|
||||
IMPORT osRtxPendSV_Handler
|
||||
IMPORT osRtxInfo
|
||||
IMPORT IRQ_Disable
|
||||
IMPORT IRQ_Enable
|
||||
|
||||
PUSH {LR}
|
||||
|
||||
; Check interrupt nesting level
|
||||
LDR R0, =IRQ_NestLevel
|
||||
LDR R1, [R0] ; Load IRQ nest level
|
||||
CMP R1, #1
|
||||
BNE osRtxContextExit ; Nesting interrupts, exit context switcher
|
||||
|
||||
LDR R12, =osRtxInfo+I_T_RUN_OFS ; Load address of osRtxInfo.run
|
||||
LDM R12, {R0, R1} ; Load osRtxInfo.thread.run: curr & next
|
||||
LDR R2, =IRQ_PendSV ; Load address of IRQ_PendSV flag
|
||||
LDRB R3, [R2] ; Load PendSV flag
|
||||
|
||||
CMP R0, R1 ; Check if context switch is required
|
||||
BNE osRtxContextCheck ; Not equal, check if context save required
|
||||
CMP R3, #1 ; Compare IRQ_PendSV value
|
||||
BNE osRtxContextExit ; No post processing (and no context switch requested)
|
||||
|
||||
osRtxContextCheck
|
||||
STR R1, [R12] ; Store run.next as run.curr
|
||||
; R0 = curr, R1 = next, R2 = &IRQ_PendSV, R3 = IRQ_PendSV, R12 = &osRtxInfo.thread.run
|
||||
PUSH {R1-R3, R12}
|
||||
|
||||
CMP R0, #0 ; Is osRtxInfo.thread.run.curr == 0
|
||||
BEQ osRtxPostProcess ; Current deleted, skip context save
|
||||
|
||||
osRtxContextSave
|
||||
MOV LR, R0 ; Move &osRtxInfo.thread.run.curr to LR
|
||||
MOV R0, SP ; Move SP_svc into R0
|
||||
ADD R0, R0, #20 ; Adjust SP_svc to R0 of the basic frame
|
||||
SUB SP, SP, #4
|
||||
STM SP, {SP}^ ; Save SP_usr to current stack
|
||||
POP {R1} ; Pop SP_usr into R1
|
||||
|
||||
SUB R1, R1, #64 ; Adjust SP_usr to R4 of the basic frame
|
||||
STMIA R1!, {R4-R11} ; Save R4-R11 to user stack
|
||||
LDMIA R0!, {R4-R8} ; Load stacked R0-R3,R12 into R4-R8
|
||||
STMIA R1!, {R4-R8} ; Store them to user stack
|
||||
STM R1, {LR}^ ; Store LR_usr directly
|
||||
ADD R1, R1, #4 ; Adjust user sp to PC
|
||||
LDMIB R0!, {R5-R6} ; Load current PC, CPSR
|
||||
STMIA R1!, {R5-R6} ; Restore user PC and CPSR
|
||||
|
||||
SUB R1, R1, #64 ; Adjust SP_usr to stacked R4
|
||||
|
||||
; Check if VFP state need to be saved
|
||||
MRC p15, 0, R2, c1, c0, 2 ; VFP/NEON access enabled? (CPACR)
|
||||
AND R2, R2, #0x00F00000
|
||||
CMP R2, #0x00F00000
|
||||
BNE osRtxContextSave1 ; Continue, no VFP
|
||||
|
||||
VMRS R2, FPSCR
|
||||
STMDB R1!, {R2,R12} ; Push FPSCR, maintain 8-byte alignment
|
||||
|
||||
VSTMDB R1!, {D0-D15} ; Save D0-D15
|
||||
#ifdef __ARM_ADVANCED_SIMD__
|
||||
VSTMDB R1!, {D16-D31} ; Save D16-D31
|
||||
#endif
|
||||
|
||||
LDRB R2, [LR, #TCB_SP_FRAME] ; Load osRtxInfo.thread.run.curr frame info
|
||||
#ifdef __ARM_ADVANCED_SIMD__
|
||||
ORR R2, R2, #4 ; NEON state
|
||||
#else
|
||||
ORR R2, R2, #2 ; VFP state
|
||||
#endif
|
||||
STRB R2, [LR, #TCB_SP_FRAME] ; Store VFP/NEON state
|
||||
|
||||
osRtxContextSave1
|
||||
STR R1, [LR, #TCB_SP_OFS] ; Store user sp to osRtxInfo.thread.run.curr
|
||||
|
||||
osRtxPostProcess
|
||||
; RTX IRQ post processing check
|
||||
POP {R8-R11} ; Pop R8 = run.next, R9 = &IRQ_PendSV, R10 = IRQ_PendSV, R11 = &osRtxInfo.thread.run
|
||||
CMP R10, #1 ; Compare PendSV value
|
||||
BNE osRtxContextRestore ; Skip post processing if not pending
|
||||
|
||||
MOV R4, SP ; Move SP_svc into R4
|
||||
AND R4, R4, #4 ; Get stack adjustment to ensure 8-byte alignment
|
||||
SUB SP, SP, R4 ; Adjust stack
|
||||
|
||||
; Disable OS Tick
|
||||
LDR R5, =osRtxInfo ; Load address of osRtxInfo
|
||||
LDR R5, [R5, #I_TICK_IRQN_OFS] ; Load OS Tick irqn
|
||||
MOV R0, R5 ; Set it as function parameter
|
||||
BLX IRQ_Disable ; Disable OS Tick interrupt
|
||||
MOV R6, #0 ; Set PendSV clear value
|
||||
B osRtxPendCheck
|
||||
osRtxPendExec
|
||||
STRB R6, [R9] ; Clear PendSV flag
|
||||
CPSIE i ; Re-enable interrupts
|
||||
BLX osRtxPendSV_Handler ; Post process pending objects
|
||||
CPSID i ; Disable interrupts
|
||||
osRtxPendCheck
|
||||
LDR R8, [R11, #4] ; Load osRtxInfo.thread.run.next
|
||||
STR R8, [R11] ; Store run.next as run.curr
|
||||
LDRB R0, [R9] ; Load PendSV flag
|
||||
CMP R0, #1 ; Compare PendSV value
|
||||
BEQ osRtxPendExec ; Branch to PendExec if PendSV is set
|
||||
|
||||
; Re-enable OS Tick
|
||||
MOV R0, R5 ; Restore irqn as function parameter
|
||||
BLX IRQ_Enable ; Enable OS Tick interrupt
|
||||
|
||||
ADD SP, SP, R4 ; Restore stack adjustment
|
||||
|
||||
osRtxContextRestore
|
||||
LDR LR, [R8, #TCB_SP_OFS] ; Load next osRtxThread_t.sp
|
||||
LDRB R2, [R8, #TCB_SP_FRAME] ; Load next osRtxThread_t.stack_frame
|
||||
|
||||
ANDS R2, R2, #0x6 ; Check stack frame for VFP context
|
||||
MRC p15, 0, R2, c1, c0, 2 ; Read CPACR
|
||||
ANDEQ R2, R2, #0xFF0FFFFF ; VFP/NEON state not stacked, disable VFP/NEON
|
||||
ORRNE R2, R2, #0x00F00000 ; VFP/NEON state is stacked, enable VFP/NEON
|
||||
MCR p15, 0, R2, c1, c0, 2 ; Write CPACR
|
||||
BEQ osRtxContextRestore1 ; No VFP
|
||||
ISB ; Sync if VFP was enabled
|
||||
#ifdef __ARM_ADVANCED_SIMD__
|
||||
VLDMIA LR!, {D16-D31} ; Restore D16-D31
|
||||
#endif
|
||||
VLDMIA LR!, {D0-D15} ; Restore D0-D15
|
||||
LDR R2, [LR]
|
||||
VMSR FPSCR, R2 ; Restore FPSCR
|
||||
ADD LR, LR, #8 ; Adjust sp pointer to R4
|
||||
|
||||
osRtxContextRestore1
|
||||
LDMIA LR!, {R4-R11} ; Restore R4-R11
|
||||
ADD R12, LR, #32 ; Adjust sp and save it into R12
|
||||
PUSH {R12} ; Push sp onto stack
|
||||
LDM SP, {SP}^ ; Restore SP_usr directly
|
||||
ADD SP, SP, #4 ; Adjust SP_svc
|
||||
LDMIA LR!, {R0-R3, R12} ; Load user registers R0-R3,R12
|
||||
STMIB SP!, {R0-R3, R12} ; Store them to SP_svc
|
||||
LDM LR, {LR}^ ; Restore LR_usr directly
|
||||
LDMIB LR!, {R0-R1} ; Load user registers PC,CPSR
|
||||
ADD SP, SP, #4
|
||||
STMIB SP!, {R0-R1} ; Store them to SP_svc
|
||||
SUB SP, SP, #32 ; Adjust SP_svc to stacked LR
|
||||
|
||||
osRtxContextExit
|
||||
POP {PC} ; Return
|
||||
|
||||
END
|
||||
@@ -0,0 +1,158 @@
|
||||
;/*
|
||||
; * Copyright (c) 2013-2018 Arm Limited. All rights reserved.
|
||||
; *
|
||||
; * SPDX-License-Identifier: Apache-2.0
|
||||
; *
|
||||
; * Licensed under the Apache License, Version 2.0 (the License); you may
|
||||
; * not use this file except in compliance with the License.
|
||||
; * You may obtain a copy of the License at
|
||||
; *
|
||||
; * www.apache.org/licenses/LICENSE-2.0
|
||||
; *
|
||||
; * Unless required by applicable law or agreed to in writing, software
|
||||
; * distributed under the License is distributed on an AS IS BASIS, WITHOUT
|
||||
; * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
; * See the License for the specific language governing permissions and
|
||||
; * limitations under the License.
|
||||
; *
|
||||
; * -----------------------------------------------------------------------------
|
||||
; *
|
||||
; * Project: CMSIS-RTOS RTX
|
||||
; * Title: Cortex-M0 Exception handlers
|
||||
; *
|
||||
; * -----------------------------------------------------------------------------
|
||||
; */
|
||||
|
||||
|
||||
NAME irq_cm0.s
|
||||
|
||||
|
||||
I_T_RUN_OFS EQU 20 ; osRtxInfo.thread.run offset
|
||||
TCB_SP_OFS EQU 56 ; TCB.SP offset
|
||||
|
||||
|
||||
PRESERVE8
|
||||
SECTION .rodata:DATA:NOROOT(2)
|
||||
|
||||
|
||||
EXPORT irqRtxLib
|
||||
irqRtxLib DCB 0 ; Non weak library reference
|
||||
|
||||
|
||||
THUMB
|
||||
SECTION .text:CODE:NOROOT(2)
|
||||
|
||||
|
||||
SVC_Handler
|
||||
EXPORT SVC_Handler
|
||||
IMPORT osRtxUserSVC
|
||||
IMPORT osRtxInfo
|
||||
|
||||
MOV R0,LR
|
||||
LSRS R0,R0,#3 ; Determine return stack from EXC_RETURN bit 2
|
||||
BCC SVC_MSP ; Branch if return stack is MSP
|
||||
MRS R0,PSP ; Get PSP
|
||||
|
||||
SVC_Number
|
||||
LDR R1,[R0,#24] ; Load saved PC from stack
|
||||
SUBS R1,R1,#2 ; Point to SVC instruction
|
||||
LDRB R1,[R1] ; Load SVC number
|
||||
CMP R1,#0
|
||||
BNE SVC_User ; Branch if not SVC 0
|
||||
|
||||
PUSH {R0,LR} ; Save SP and EXC_RETURN
|
||||
LDMIA R0,{R0-R3} ; Load function parameters from stack
|
||||
BLX R7 ; Call service function
|
||||
POP {R2,R3} ; Restore SP and EXC_RETURN
|
||||
STMIA R2!,{R0-R1} ; Store function return values
|
||||
MOV LR,R3 ; Set EXC_RETURN
|
||||
|
||||
SVC_Context
|
||||
LDR R3,=osRtxInfo+I_T_RUN_OFS; Load address of osRtxInfo.run
|
||||
LDMIA R3!,{R1,R2} ; Load osRtxInfo.thread.run: curr & next
|
||||
CMP R1,R2 ; Check if thread switch is required
|
||||
BEQ SVC_Exit ; Branch when threads are the same
|
||||
|
||||
CMP R1,#0
|
||||
BEQ SVC_ContextSwitch ; Branch if running thread is deleted
|
||||
|
||||
SVC_ContextSave
|
||||
MRS R0,PSP ; Get PSP
|
||||
SUBS R0,R0,#32 ; Calculate SP
|
||||
STR R0,[R1,#TCB_SP_OFS] ; Store SP
|
||||
STMIA R0!,{R4-R7} ; Save R4..R7
|
||||
MOV R4,R8
|
||||
MOV R5,R9
|
||||
MOV R6,R10
|
||||
MOV R7,R11
|
||||
STMIA R0!,{R4-R7} ; Save R8..R11
|
||||
|
||||
SVC_ContextSwitch
|
||||
SUBS R3,R3,#8 ; Adjust address
|
||||
STR R2,[R3] ; osRtxInfo.thread.run: curr = next
|
||||
|
||||
SVC_ContextRestore
|
||||
LDR R0,[R2,#TCB_SP_OFS] ; Load SP
|
||||
ADDS R0,R0,#16 ; Adjust address
|
||||
LDMIA R0!,{R4-R7} ; Restore R8..R11
|
||||
MOV R8,R4
|
||||
MOV R9,R5
|
||||
MOV R10,R6
|
||||
MOV R11,R7
|
||||
MSR PSP,R0 ; Set PSP
|
||||
SUBS R0,R0,#32 ; Adjust address
|
||||
LDMIA R0!,{R4-R7} ; Restore R4..R7
|
||||
|
||||
MOVS R0,#~0xFFFFFFFD
|
||||
MVNS R0,R0 ; Set EXC_RETURN value
|
||||
BX R0 ; Exit from handler
|
||||
|
||||
SVC_MSP
|
||||
MRS R0,MSP ; Get MSP
|
||||
B SVC_Number
|
||||
|
||||
SVC_Exit
|
||||
BX LR ; Exit from handler
|
||||
|
||||
SVC_User
|
||||
LDR R2,=osRtxUserSVC ; Load address of SVC table
|
||||
LDR R3,[R2] ; Load SVC maximum number
|
||||
CMP R1,R3 ; Check SVC number range
|
||||
BHI SVC_Exit ; Branch if out of range
|
||||
|
||||
PUSH {R0,LR} ; Save SP and EXC_RETURN
|
||||
LSLS R1,R1,#2
|
||||
LDR R3,[R2,R1] ; Load address of SVC function
|
||||
MOV R12,R3
|
||||
LDMIA R0,{R0-R3} ; Load function parameters from stack
|
||||
BLX R12 ; Call service function
|
||||
POP {R2,R3} ; Restore SP and EXC_RETURN
|
||||
STR R0,[R2] ; Store function return value
|
||||
MOV LR,R3 ; Set EXC_RETURN
|
||||
|
||||
BX LR ; Return from handler
|
||||
|
||||
|
||||
PendSV_Handler
|
||||
EXPORT PendSV_Handler
|
||||
IMPORT osRtxPendSV_Handler
|
||||
|
||||
PUSH {R0,LR} ; Save EXC_RETURN
|
||||
BL osRtxPendSV_Handler ; Call osRtxPendSV_Handler
|
||||
POP {R0,R1} ; Restore EXC_RETURN
|
||||
MOV LR,R1 ; Set EXC_RETURN
|
||||
B SVC_Context
|
||||
|
||||
|
||||
SysTick_Handler
|
||||
EXPORT SysTick_Handler
|
||||
IMPORT osRtxTick_Handler
|
||||
|
||||
PUSH {R0,LR} ; Save EXC_RETURN
|
||||
BL osRtxTick_Handler ; Call osRtxTick_Handler
|
||||
POP {R0,R1} ; Restore EXC_RETURN
|
||||
MOV LR,R1 ; Set EXC_RETURN
|
||||
B SVC_Context
|
||||
|
||||
|
||||
END
|
||||
@@ -0,0 +1,130 @@
|
||||
;/*
|
||||
; * Copyright (c) 2013-2018 Arm Limited. All rights reserved.
|
||||
; *
|
||||
; * SPDX-License-Identifier: Apache-2.0
|
||||
; *
|
||||
; * Licensed under the Apache License, Version 2.0 (the License); you may
|
||||
; * not use this file except in compliance with the License.
|
||||
; * You may obtain a copy of the License at
|
||||
; *
|
||||
; * www.apache.org/licenses/LICENSE-2.0
|
||||
; *
|
||||
; * Unless required by applicable law or agreed to in writing, software
|
||||
; * distributed under the License is distributed on an AS IS BASIS, WITHOUT
|
||||
; * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
; * See the License for the specific language governing permissions and
|
||||
; * limitations under the License.
|
||||
; *
|
||||
; * -----------------------------------------------------------------------------
|
||||
; *
|
||||
; * Project: CMSIS-RTOS RTX
|
||||
; * Title: Cortex-M3 Exception handlers
|
||||
; *
|
||||
; * -----------------------------------------------------------------------------
|
||||
; */
|
||||
|
||||
|
||||
NAME irq_cm3.s
|
||||
|
||||
|
||||
I_T_RUN_OFS EQU 20 ; osRtxInfo.thread.run offset
|
||||
TCB_SP_OFS EQU 56 ; TCB.SP offset
|
||||
|
||||
|
||||
PRESERVE8
|
||||
SECTION .rodata:DATA:NOROOT(2)
|
||||
|
||||
|
||||
EXPORT irqRtxLib
|
||||
irqRtxLib DCB 0 ; Non weak library reference
|
||||
|
||||
|
||||
THUMB
|
||||
SECTION .text:CODE:NOROOT(2)
|
||||
|
||||
|
||||
SVC_Handler
|
||||
EXPORT SVC_Handler
|
||||
IMPORT osRtxUserSVC
|
||||
IMPORT osRtxInfo
|
||||
|
||||
TST LR,#0x04 ; Determine return stack from EXC_RETURN bit 2
|
||||
ITE EQ
|
||||
MRSEQ R0,MSP ; Get MSP if return stack is MSP
|
||||
MRSNE R0,PSP ; Get PSP if return stack is PSP
|
||||
|
||||
LDR R1,[R0,#24] ; Load saved PC from stack
|
||||
LDRB R1,[R1,#-2] ; Load SVC number
|
||||
CBNZ R1,SVC_User ; Branch if not SVC 0
|
||||
|
||||
PUSH {R0,LR} ; Save SP and EXC_RETURN
|
||||
LDM R0,{R0-R3,R12} ; Load function parameters and address from stack
|
||||
BLX R12 ; Call service function
|
||||
POP {R12,LR} ; Restore SP and EXC_RETURN
|
||||
STM R12,{R0-R1} ; Store function return values
|
||||
|
||||
SVC_Context
|
||||
LDR R3,=osRtxInfo+I_T_RUN_OFS; Load address of osRtxInfo.run
|
||||
LDM R3,{R1,R2} ; Load osRtxInfo.thread.run: curr & next
|
||||
CMP R1,R2 ; Check if thread switch is required
|
||||
IT EQ
|
||||
BXEQ LR ; Exit when threads are the same
|
||||
|
||||
CBZ R1,SVC_ContextSwitch ; Branch if running thread is deleted
|
||||
|
||||
SVC_ContextSave
|
||||
STMDB R12!,{R4-R11} ; Save R4..R11
|
||||
STR R12,[R1,#TCB_SP_OFS] ; Store SP
|
||||
|
||||
SVC_ContextSwitch
|
||||
STR R2,[R3] ; osRtxInfo.thread.run: curr = next
|
||||
|
||||
SVC_ContextRestore
|
||||
LDR R0,[R2,#TCB_SP_OFS] ; Load SP
|
||||
LDMIA R0!,{R4-R11} ; Restore R4..R11
|
||||
MSR PSP,R0 ; Set PSP
|
||||
|
||||
MVN LR,#~0xFFFFFFFD ; Set EXC_RETURN value
|
||||
|
||||
SVC_Exit
|
||||
BX LR ; Exit from handler
|
||||
|
||||
SVC_User
|
||||
LDR R2,=osRtxUserSVC ; Load address of SVC table
|
||||
LDR R3,[R2] ; Load SVC maximum number
|
||||
CMP R1,R3 ; Check SVC number range
|
||||
BHI SVC_Exit ; Branch if out of range
|
||||
|
||||
PUSH {R0,LR} ; Save SP and EXC_RETURN
|
||||
LDR R12,[R2,R1,LSL #2] ; Load address of SVC function
|
||||
LDM R0,{R0-R3} ; Load function parameters from stack
|
||||
BLX R12 ; Call service function
|
||||
POP {R12,LR} ; Restore SP and EXC_RETURN
|
||||
STR R0,[R12] ; Store function return value
|
||||
|
||||
BX LR ; Return from handler
|
||||
|
||||
|
||||
PendSV_Handler
|
||||
EXPORT PendSV_Handler
|
||||
IMPORT osRtxPendSV_Handler
|
||||
|
||||
PUSH {R0,LR} ; Save EXC_RETURN
|
||||
BL osRtxPendSV_Handler ; Call osRtxPendSV_Handler
|
||||
POP {R0,LR} ; Restore EXC_RETURN
|
||||
MRS R12,PSP
|
||||
B SVC_Context
|
||||
|
||||
|
||||
SysTick_Handler
|
||||
EXPORT SysTick_Handler
|
||||
IMPORT osRtxTick_Handler
|
||||
|
||||
PUSH {R0,LR} ; Save EXC_RETURN
|
||||
BL osRtxTick_Handler ; Call osRtxTick_Handler
|
||||
POP {R0,LR} ; Restore EXC_RETURN
|
||||
MRS R12,PSP
|
||||
B SVC_Context
|
||||
|
||||
|
||||
END
|
||||
@@ -0,0 +1,146 @@
|
||||
;/*
|
||||
; * Copyright (c) 2013-2018 Arm Limited. All rights reserved.
|
||||
; *
|
||||
; * SPDX-License-Identifier: Apache-2.0
|
||||
; *
|
||||
; * Licensed under the Apache License, Version 2.0 (the License); you may
|
||||
; * not use this file except in compliance with the License.
|
||||
; * You may obtain a copy of the License at
|
||||
; *
|
||||
; * www.apache.org/licenses/LICENSE-2.0
|
||||
; *
|
||||
; * Unless required by applicable law or agreed to in writing, software
|
||||
; * distributed under the License is distributed on an AS IS BASIS, WITHOUT
|
||||
; * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
; * See the License for the specific language governing permissions and
|
||||
; * limitations under the License.
|
||||
; *
|
||||
; * -----------------------------------------------------------------------------
|
||||
; *
|
||||
; * Project: CMSIS-RTOS RTX
|
||||
; * Title: Cortex-M4F Exception handlers
|
||||
; *
|
||||
; * -----------------------------------------------------------------------------
|
||||
; */
|
||||
|
||||
|
||||
NAME irq_cm4f.s
|
||||
|
||||
|
||||
I_T_RUN_OFS EQU 20 ; osRtxInfo.thread.run offset
|
||||
TCB_SP_OFS EQU 56 ; TCB.SP offset
|
||||
TCB_SF_OFS EQU 34 ; TCB.stack_frame offset
|
||||
|
||||
|
||||
PRESERVE8
|
||||
SECTION .rodata:DATA:NOROOT(2)
|
||||
|
||||
|
||||
EXPORT irqRtxLib
|
||||
irqRtxLib DCB 0 ; Non weak library reference
|
||||
|
||||
|
||||
THUMB
|
||||
SECTION .text:CODE:NOROOT(2)
|
||||
|
||||
|
||||
SVC_Handler
|
||||
EXPORT SVC_Handler
|
||||
IMPORT osRtxUserSVC
|
||||
IMPORT osRtxInfo
|
||||
|
||||
TST LR,#0x04 ; Determine return stack from EXC_RETURN bit 2
|
||||
ITE EQ
|
||||
MRSEQ R0,MSP ; Get MSP if return stack is MSP
|
||||
MRSNE R0,PSP ; Get PSP if return stack is PSP
|
||||
|
||||
LDR R1,[R0,#24] ; Load saved PC from stack
|
||||
LDRB R1,[R1,#-2] ; Load SVC number
|
||||
CBNZ R1,SVC_User ; Branch if not SVC 0
|
||||
|
||||
PUSH {R0,LR} ; Save SP and EXC_RETURN
|
||||
LDM R0,{R0-R3,R12} ; Load function parameters and address from stack
|
||||
BLX R12 ; Call service function
|
||||
POP {R12,LR} ; Restore SP and EXC_RETURN
|
||||
STM R12,{R0-R1} ; Store function return values
|
||||
|
||||
SVC_Context
|
||||
LDR R3,=osRtxInfo+I_T_RUN_OFS; Load address of osRtxInfo.run
|
||||
LDM R3,{R1,R2} ; Load osRtxInfo.thread.run: curr & next
|
||||
CMP R1,R2 ; Check if thread switch is required
|
||||
IT EQ
|
||||
BXEQ LR ; Exit when threads are the same
|
||||
|
||||
CBNZ R1,SVC_ContextSave ; Branch if running thread is not deleted
|
||||
TST LR,#0x10 ; Check if extended stack frame
|
||||
BNE SVC_ContextSwitch
|
||||
LDR R1,=0xE000EF34 ; FPCCR Address
|
||||
LDR R0,[R1] ; Load FPCCR
|
||||
BIC R0,R0,#1 ; Clear LSPACT (Lazy state)
|
||||
STR R0,[R1] ; Store FPCCR
|
||||
B SVC_ContextSwitch
|
||||
|
||||
SVC_ContextSave
|
||||
STMDB R12!,{R4-R11} ; Save R4..R11
|
||||
TST LR,#0x10 ; Check if extended stack frame
|
||||
IT EQ
|
||||
VSTMDBEQ R12!,{S16-S31} ; Save VFP S16.S31
|
||||
STR R12,[R1,#TCB_SP_OFS] ; Store SP
|
||||
STRB LR, [R1,#TCB_SF_OFS] ; Store stack frame information
|
||||
|
||||
SVC_ContextSwitch
|
||||
STR R2,[R3] ; osRtxInfo.thread.run: curr = next
|
||||
|
||||
SVC_ContextRestore
|
||||
LDRB R1,[R2,#TCB_SF_OFS] ; Load stack frame information
|
||||
LDR R0,[R2,#TCB_SP_OFS] ; Load SP
|
||||
ORR LR,R1,#0xFFFFFF00 ; Set EXC_RETURN
|
||||
|
||||
TST LR,#0x10 ; Check if extended stack frame
|
||||
IT EQ
|
||||
VLDMIAEQ R0!,{S16-S31} ; Restore VFP S16..S31
|
||||
LDMIA R0!,{R4-R11} ; Restore R4..R11
|
||||
MSR PSP,R0 ; Set PSP
|
||||
|
||||
SVC_Exit
|
||||
BX LR ; Exit from handler
|
||||
|
||||
SVC_User
|
||||
LDR R2,=osRtxUserSVC ; Load address of SVC table
|
||||
LDR R3,[R2] ; Load SVC maximum number
|
||||
CMP R1,R3 ; Check SVC number range
|
||||
BHI SVC_Exit ; Branch if out of range
|
||||
|
||||
PUSH {R0,LR} ; Save SP and EXC_RETURN
|
||||
LDR R12,[R2,R1,LSL #2] ; Load address of SVC function
|
||||
LDM R0,{R0-R3} ; Load function parameters from stack
|
||||
BLX R12 ; Call service function
|
||||
POP {R12,LR} ; Restore SP and EXC_RETURN
|
||||
STR R0,[R12] ; Store function return value
|
||||
|
||||
BX LR ; Return from handler
|
||||
|
||||
|
||||
PendSV_Handler
|
||||
EXPORT PendSV_Handler
|
||||
IMPORT osRtxPendSV_Handler
|
||||
|
||||
PUSH {R0,LR} ; Save EXC_RETURN
|
||||
BL osRtxPendSV_Handler ; Call osRtxPendSV_Handler
|
||||
POP {R0,LR} ; Restore EXC_RETURN
|
||||
MRS R12,PSP
|
||||
B SVC_Context
|
||||
|
||||
|
||||
SysTick_Handler
|
||||
EXPORT SysTick_Handler
|
||||
IMPORT osRtxTick_Handler
|
||||
|
||||
PUSH {R0,LR} ; Save EXC_RETURN
|
||||
BL osRtxTick_Handler ; Call osRtxTick_Handler
|
||||
POP {R0,LR} ; Restore EXC_RETURN
|
||||
MRS R12,PSP
|
||||
B SVC_Context
|
||||
|
||||
|
||||
END
|
||||
@@ -0,0 +1,49 @@
|
||||
/*
|
||||
* Copyright (c) 2013-2020 Arm Limited. All rights reserved.
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the License); you may
|
||||
* not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an AS IS BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
* -----------------------------------------------------------------------------
|
||||
*
|
||||
* Project: CMSIS-RTOS RTX
|
||||
* Title: Cortex Core definitions
|
||||
*
|
||||
* -----------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
#ifndef RTX_CORE_C_H_
|
||||
#define RTX_CORE_C_H_
|
||||
|
||||
//lint -emacro((923,9078),SCB) "cast from unsigned long to pointer" [MISRA Note 9]
|
||||
#include "RTE_Components.h"
|
||||
#include CMSIS_device_header
|
||||
|
||||
#if ((!defined(__ARM_ARCH_6M__)) && \
|
||||
(!defined(__ARM_ARCH_7A__)) && \
|
||||
(!defined(__ARM_ARCH_7M__)) && \
|
||||
(!defined(__ARM_ARCH_7EM__)) && \
|
||||
(!defined(__ARM_ARCH_8M_BASE__)) && \
|
||||
(!defined(__ARM_ARCH_8M_MAIN__)) && \
|
||||
(!defined(__ARM_ARCH_8_1M_MAIN__)))
|
||||
#error "Unknown Arm Architecture!"
|
||||
#endif
|
||||
|
||||
#if (defined(__ARM_ARCH_7A__) && (__ARM_ARCH_7A__ != 0))
|
||||
#include "rtx_core_ca.h"
|
||||
#else
|
||||
#include "rtx_core_cm.h"
|
||||
#endif
|
||||
|
||||
#endif // RTX_CORE_C_H_
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,101 @@
|
||||
/*
|
||||
* Copyright (c) 2013-2019 Arm Limited. All rights reserved.
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the License); you may
|
||||
* not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an AS IS BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
* -----------------------------------------------------------------------------
|
||||
*
|
||||
* Project: CMSIS-RTOS RTX
|
||||
* Title: Delay functions
|
||||
*
|
||||
* -----------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
#include "rtx_lib.h"
|
||||
|
||||
|
||||
// ==== Service Calls ====
|
||||
|
||||
/// Wait for Timeout (Time Delay).
|
||||
/// \note API identical to osDelay
|
||||
static osStatus_t svcRtxDelay (uint32_t ticks) {
|
||||
|
||||
if (ticks != 0U) {
|
||||
if (osRtxThreadWaitEnter(osRtxThreadWaitingDelay, ticks)) {
|
||||
EvrRtxDelayStarted(ticks);
|
||||
} else {
|
||||
EvrRtxDelayCompleted(osRtxThreadGetRunning());
|
||||
}
|
||||
}
|
||||
|
||||
return osOK;
|
||||
}
|
||||
|
||||
/// Wait until specified time.
|
||||
/// \note API identical to osDelayUntil
|
||||
static osStatus_t svcRtxDelayUntil (uint32_t ticks) {
|
||||
|
||||
ticks -= osRtxInfo.kernel.tick;
|
||||
if ((ticks == 0U) || (ticks > 0x7FFFFFFFU)) {
|
||||
EvrRtxDelayError((int32_t)osErrorParameter);
|
||||
//lint -e{904} "Return statement before end of function" [MISRA Note 1]
|
||||
return osErrorParameter;
|
||||
}
|
||||
|
||||
if (osRtxThreadWaitEnter(osRtxThreadWaitingDelay, ticks)) {
|
||||
EvrRtxDelayUntilStarted(ticks);
|
||||
} else {
|
||||
EvrRtxDelayCompleted(osRtxThreadGetRunning());
|
||||
}
|
||||
|
||||
return osOK;
|
||||
}
|
||||
|
||||
// Service Calls definitions
|
||||
//lint ++flb "Library Begin" [MISRA Note 11]
|
||||
SVC0_1(Delay, osStatus_t, uint32_t)
|
||||
SVC0_1(DelayUntil, osStatus_t, uint32_t)
|
||||
//lint --flb "Library End"
|
||||
|
||||
|
||||
// ==== Public API ====
|
||||
|
||||
/// Wait for Timeout (Time Delay).
|
||||
osStatus_t osDelay (uint32_t ticks) {
|
||||
osStatus_t status;
|
||||
|
||||
EvrRtxDelay(ticks);
|
||||
if (IsIrqMode() || IsIrqMasked()) {
|
||||
EvrRtxDelayError((int32_t)osErrorISR);
|
||||
status = osErrorISR;
|
||||
} else {
|
||||
status = __svcDelay(ticks);
|
||||
}
|
||||
return status;
|
||||
}
|
||||
|
||||
/// Wait until specified time.
|
||||
osStatus_t osDelayUntil (uint32_t ticks) {
|
||||
osStatus_t status;
|
||||
|
||||
EvrRtxDelayUntil(ticks);
|
||||
if (IsIrqMode() || IsIrqMasked()) {
|
||||
EvrRtxDelayError((int32_t)osErrorISR);
|
||||
status = osErrorISR;
|
||||
} else {
|
||||
status = __svcDelayUntil(ticks);
|
||||
}
|
||||
return status;
|
||||
}
|
||||
@@ -0,0 +1,582 @@
|
||||
/*
|
||||
* Copyright (c) 2013-2019 Arm Limited. All rights reserved.
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the License); you may
|
||||
* not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an AS IS BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
* -----------------------------------------------------------------------------
|
||||
*
|
||||
* Project: CMSIS-RTOS RTX
|
||||
* Title: Event Flags functions
|
||||
*
|
||||
* -----------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
#include "rtx_lib.h"
|
||||
|
||||
|
||||
// OS Runtime Object Memory Usage
|
||||
#if ((defined(OS_OBJ_MEM_USAGE) && (OS_OBJ_MEM_USAGE != 0)))
|
||||
osRtxObjectMemUsage_t osRtxEventFlagsMemUsage \
|
||||
__attribute__((section(".data.os.evflags.obj"))) =
|
||||
{ 0U, 0U, 0U };
|
||||
#endif
|
||||
|
||||
|
||||
// ==== Helper functions ====
|
||||
|
||||
/// Set Event Flags.
|
||||
/// \param[in] ef event flags object.
|
||||
/// \param[in] flags specifies the flags to set.
|
||||
/// \return event flags after setting.
|
||||
static uint32_t EventFlagsSet (os_event_flags_t *ef, uint32_t flags) {
|
||||
#if (EXCLUSIVE_ACCESS == 0)
|
||||
uint32_t primask = __get_PRIMASK();
|
||||
#endif
|
||||
uint32_t event_flags;
|
||||
|
||||
#if (EXCLUSIVE_ACCESS == 0)
|
||||
__disable_irq();
|
||||
|
||||
ef->event_flags |= flags;
|
||||
event_flags = ef->event_flags;
|
||||
|
||||
if (primask == 0U) {
|
||||
__enable_irq();
|
||||
}
|
||||
#else
|
||||
event_flags = atomic_set32(&ef->event_flags, flags);
|
||||
#endif
|
||||
|
||||
return event_flags;
|
||||
}
|
||||
|
||||
/// Clear Event Flags.
|
||||
/// \param[in] ef event flags object.
|
||||
/// \param[in] flags specifies the flags to clear.
|
||||
/// \return event flags before clearing.
|
||||
static uint32_t EventFlagsClear (os_event_flags_t *ef, uint32_t flags) {
|
||||
#if (EXCLUSIVE_ACCESS == 0)
|
||||
uint32_t primask = __get_PRIMASK();
|
||||
#endif
|
||||
uint32_t event_flags;
|
||||
|
||||
#if (EXCLUSIVE_ACCESS == 0)
|
||||
__disable_irq();
|
||||
|
||||
event_flags = ef->event_flags;
|
||||
ef->event_flags &= ~flags;
|
||||
|
||||
if (primask == 0U) {
|
||||
__enable_irq();
|
||||
}
|
||||
#else
|
||||
event_flags = atomic_clr32(&ef->event_flags, flags);
|
||||
#endif
|
||||
|
||||
return event_flags;
|
||||
}
|
||||
|
||||
/// Check Event Flags.
|
||||
/// \param[in] ef event flags object.
|
||||
/// \param[in] flags specifies the flags to check.
|
||||
/// \param[in] options specifies flags options (osFlagsXxxx).
|
||||
/// \return event flags before clearing or 0 if specified flags have not been set.
|
||||
static uint32_t EventFlagsCheck (os_event_flags_t *ef, uint32_t flags, uint32_t options) {
|
||||
#if (EXCLUSIVE_ACCESS == 0)
|
||||
uint32_t primask;
|
||||
#endif
|
||||
uint32_t event_flags;
|
||||
|
||||
if ((options & osFlagsNoClear) == 0U) {
|
||||
#if (EXCLUSIVE_ACCESS == 0)
|
||||
primask = __get_PRIMASK();
|
||||
__disable_irq();
|
||||
|
||||
event_flags = ef->event_flags;
|
||||
if ((((options & osFlagsWaitAll) != 0U) && ((event_flags & flags) != flags)) ||
|
||||
(((options & osFlagsWaitAll) == 0U) && ((event_flags & flags) == 0U))) {
|
||||
event_flags = 0U;
|
||||
} else {
|
||||
ef->event_flags &= ~flags;
|
||||
}
|
||||
|
||||
if (primask == 0U) {
|
||||
__enable_irq();
|
||||
}
|
||||
#else
|
||||
if ((options & osFlagsWaitAll) != 0U) {
|
||||
event_flags = atomic_chk32_all(&ef->event_flags, flags);
|
||||
} else {
|
||||
event_flags = atomic_chk32_any(&ef->event_flags, flags);
|
||||
}
|
||||
#endif
|
||||
} else {
|
||||
event_flags = ef->event_flags;
|
||||
if ((((options & osFlagsWaitAll) != 0U) && ((event_flags & flags) != flags)) ||
|
||||
(((options & osFlagsWaitAll) == 0U) && ((event_flags & flags) == 0U))) {
|
||||
event_flags = 0U;
|
||||
}
|
||||
}
|
||||
|
||||
return event_flags;
|
||||
}
|
||||
|
||||
|
||||
// ==== Post ISR processing ====
|
||||
|
||||
/// Event Flags post ISR processing.
|
||||
/// \param[in] ef event flags object.
|
||||
static void osRtxEventFlagsPostProcess (os_event_flags_t *ef) {
|
||||
os_thread_t *thread;
|
||||
os_thread_t *thread_next;
|
||||
uint32_t event_flags;
|
||||
|
||||
// Check if Threads are waiting for Event Flags
|
||||
thread = ef->thread_list;
|
||||
while (thread != NULL) {
|
||||
thread_next = thread->thread_next;
|
||||
event_flags = EventFlagsCheck(ef, thread->wait_flags, thread->flags_options);
|
||||
if (event_flags != 0U) {
|
||||
osRtxThreadListRemove(thread);
|
||||
osRtxThreadWaitExit(thread, event_flags, FALSE);
|
||||
EvrRtxEventFlagsWaitCompleted(ef, thread->wait_flags, thread->flags_options, event_flags);
|
||||
}
|
||||
thread = thread_next;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// ==== Service Calls ====
|
||||
|
||||
/// Create and Initialize an Event Flags object.
|
||||
/// \note API identical to osEventFlagsNew
|
||||
static osEventFlagsId_t svcRtxEventFlagsNew (const osEventFlagsAttr_t *attr) {
|
||||
os_event_flags_t *ef;
|
||||
uint8_t flags;
|
||||
const char *name;
|
||||
|
||||
// Process attributes
|
||||
if (attr != NULL) {
|
||||
name = attr->name;
|
||||
//lint -e{9079} "conversion from pointer to void to pointer to other type" [MISRA Note 6]
|
||||
ef = attr->cb_mem;
|
||||
if (ef != NULL) {
|
||||
//lint -e(923) -e(9078) "cast from pointer to unsigned int" [MISRA Note 7]
|
||||
if ((((uint32_t)ef & 3U) != 0U) || (attr->cb_size < sizeof(os_event_flags_t))) {
|
||||
EvrRtxEventFlagsError(NULL, osRtxErrorInvalidControlBlock);
|
||||
//lint -e{904} "Return statement before end of function" [MISRA Note 1]
|
||||
return NULL;
|
||||
}
|
||||
} else {
|
||||
if (attr->cb_size != 0U) {
|
||||
EvrRtxEventFlagsError(NULL, osRtxErrorInvalidControlBlock);
|
||||
//lint -e{904} "Return statement before end of function" [MISRA Note 1]
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
name = NULL;
|
||||
ef = NULL;
|
||||
}
|
||||
|
||||
// Allocate object memory if not provided
|
||||
if (ef == NULL) {
|
||||
if (osRtxInfo.mpi.event_flags != NULL) {
|
||||
//lint -e{9079} "conversion from pointer to void to pointer to other type" [MISRA Note 5]
|
||||
ef = osRtxMemoryPoolAlloc(osRtxInfo.mpi.event_flags);
|
||||
} else {
|
||||
//lint -e{9079} "conversion from pointer to void to pointer to other type" [MISRA Note 5]
|
||||
ef = osRtxMemoryAlloc(osRtxInfo.mem.common, sizeof(os_event_flags_t), 1U);
|
||||
}
|
||||
#if (defined(OS_OBJ_MEM_USAGE) && (OS_OBJ_MEM_USAGE != 0))
|
||||
if (ef != NULL) {
|
||||
uint32_t used;
|
||||
osRtxEventFlagsMemUsage.cnt_alloc++;
|
||||
used = osRtxEventFlagsMemUsage.cnt_alloc - osRtxEventFlagsMemUsage.cnt_free;
|
||||
if (osRtxEventFlagsMemUsage.max_used < used) {
|
||||
osRtxEventFlagsMemUsage.max_used = used;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
flags = osRtxFlagSystemObject;
|
||||
} else {
|
||||
flags = 0U;
|
||||
}
|
||||
|
||||
if (ef != NULL) {
|
||||
// Initialize control block
|
||||
ef->id = osRtxIdEventFlags;
|
||||
ef->flags = flags;
|
||||
ef->name = name;
|
||||
ef->thread_list = NULL;
|
||||
ef->event_flags = 0U;
|
||||
|
||||
// Register post ISR processing function
|
||||
osRtxInfo.post_process.event_flags = osRtxEventFlagsPostProcess;
|
||||
|
||||
EvrRtxEventFlagsCreated(ef, ef->name);
|
||||
} else {
|
||||
EvrRtxEventFlagsError(NULL, (int32_t)osErrorNoMemory);
|
||||
}
|
||||
|
||||
return ef;
|
||||
}
|
||||
|
||||
/// Get name of an Event Flags object.
|
||||
/// \note API identical to osEventFlagsGetName
|
||||
static const char *svcRtxEventFlagsGetName (osEventFlagsId_t ef_id) {
|
||||
os_event_flags_t *ef = osRtxEventFlagsId(ef_id);
|
||||
|
||||
// Check parameters
|
||||
if ((ef == NULL) || (ef->id != osRtxIdEventFlags)) {
|
||||
EvrRtxEventFlagsGetName(ef, NULL);
|
||||
//lint -e{904} "Return statement before end of function" [MISRA Note 1]
|
||||
return NULL;
|
||||
}
|
||||
|
||||
EvrRtxEventFlagsGetName(ef, ef->name);
|
||||
|
||||
return ef->name;
|
||||
}
|
||||
|
||||
/// Set the specified Event Flags.
|
||||
/// \note API identical to osEventFlagsSet
|
||||
static uint32_t svcRtxEventFlagsSet (osEventFlagsId_t ef_id, uint32_t flags) {
|
||||
os_event_flags_t *ef = osRtxEventFlagsId(ef_id);
|
||||
os_thread_t *thread;
|
||||
os_thread_t *thread_next;
|
||||
uint32_t event_flags;
|
||||
uint32_t event_flags0;
|
||||
|
||||
// Check parameters
|
||||
if ((ef == NULL) || (ef->id != osRtxIdEventFlags) ||
|
||||
((flags & ~(((uint32_t)1U << osRtxEventFlagsLimit) - 1U)) != 0U)) {
|
||||
EvrRtxEventFlagsError(ef, (int32_t)osErrorParameter);
|
||||
//lint -e{904} "Return statement before end of function" [MISRA Note 1]
|
||||
return ((uint32_t)osErrorParameter);
|
||||
}
|
||||
|
||||
// Set Event Flags
|
||||
event_flags = EventFlagsSet(ef, flags);
|
||||
|
||||
// Check if Threads are waiting for Event Flags
|
||||
thread = ef->thread_list;
|
||||
while (thread != NULL) {
|
||||
thread_next = thread->thread_next;
|
||||
event_flags0 = EventFlagsCheck(ef, thread->wait_flags, thread->flags_options);
|
||||
if (event_flags0 != 0U) {
|
||||
if ((thread->flags_options & osFlagsNoClear) == 0U) {
|
||||
event_flags = event_flags0 & ~thread->wait_flags;
|
||||
} else {
|
||||
event_flags = event_flags0;
|
||||
}
|
||||
osRtxThreadListRemove(thread);
|
||||
osRtxThreadWaitExit(thread, event_flags0, FALSE);
|
||||
EvrRtxEventFlagsWaitCompleted(ef, thread->wait_flags, thread->flags_options, event_flags0);
|
||||
}
|
||||
thread = thread_next;
|
||||
}
|
||||
osRtxThreadDispatch(NULL);
|
||||
|
||||
EvrRtxEventFlagsSetDone(ef, event_flags);
|
||||
|
||||
return event_flags;
|
||||
}
|
||||
|
||||
/// Clear the specified Event Flags.
|
||||
/// \note API identical to osEventFlagsClear
|
||||
static uint32_t svcRtxEventFlagsClear (osEventFlagsId_t ef_id, uint32_t flags) {
|
||||
os_event_flags_t *ef = osRtxEventFlagsId(ef_id);
|
||||
uint32_t event_flags;
|
||||
|
||||
// Check parameters
|
||||
if ((ef == NULL) || (ef->id != osRtxIdEventFlags) ||
|
||||
((flags & ~(((uint32_t)1U << osRtxEventFlagsLimit) - 1U)) != 0U)) {
|
||||
EvrRtxEventFlagsError(ef, (int32_t)osErrorParameter);
|
||||
//lint -e{904} "Return statement before end of function" [MISRA Note 1]
|
||||
return ((uint32_t)osErrorParameter);
|
||||
}
|
||||
|
||||
// Clear Event Flags
|
||||
event_flags = EventFlagsClear(ef, flags);
|
||||
|
||||
EvrRtxEventFlagsClearDone(ef, event_flags);
|
||||
|
||||
return event_flags;
|
||||
}
|
||||
|
||||
/// Get the current Event Flags.
|
||||
/// \note API identical to osEventFlagsGet
|
||||
static uint32_t svcRtxEventFlagsGet (osEventFlagsId_t ef_id) {
|
||||
os_event_flags_t *ef = osRtxEventFlagsId(ef_id);
|
||||
|
||||
// Check parameters
|
||||
if ((ef == NULL) || (ef->id != osRtxIdEventFlags)) {
|
||||
EvrRtxEventFlagsGet(ef, 0U);
|
||||
//lint -e{904} "Return statement before end of function" [MISRA Note 1]
|
||||
return 0U;
|
||||
}
|
||||
|
||||
EvrRtxEventFlagsGet(ef, ef->event_flags);
|
||||
|
||||
return ef->event_flags;
|
||||
}
|
||||
|
||||
/// Wait for one or more Event Flags to become signaled.
|
||||
/// \note API identical to osEventFlagsWait
|
||||
static uint32_t svcRtxEventFlagsWait (osEventFlagsId_t ef_id, uint32_t flags, uint32_t options, uint32_t timeout) {
|
||||
os_event_flags_t *ef = osRtxEventFlagsId(ef_id);
|
||||
os_thread_t *thread;
|
||||
uint32_t event_flags;
|
||||
|
||||
// Check parameters
|
||||
if ((ef == NULL) || (ef->id != osRtxIdEventFlags) ||
|
||||
((flags & ~(((uint32_t)1U << osRtxEventFlagsLimit) - 1U)) != 0U)) {
|
||||
EvrRtxEventFlagsError(ef, (int32_t)osErrorParameter);
|
||||
//lint -e{904} "Return statement before end of function" [MISRA Note 1]
|
||||
return ((uint32_t)osErrorParameter);
|
||||
}
|
||||
|
||||
// Check Event Flags
|
||||
event_flags = EventFlagsCheck(ef, flags, options);
|
||||
if (event_flags != 0U) {
|
||||
EvrRtxEventFlagsWaitCompleted(ef, flags, options, event_flags);
|
||||
} else {
|
||||
// Check if timeout is specified
|
||||
if (timeout != 0U) {
|
||||
EvrRtxEventFlagsWaitPending(ef, flags, options, timeout);
|
||||
// Suspend current Thread
|
||||
if (osRtxThreadWaitEnter(osRtxThreadWaitingEventFlags, timeout)) {
|
||||
thread = osRtxThreadGetRunning();
|
||||
osRtxThreadListPut(osRtxObject(ef), thread);
|
||||
// Store waiting flags and options
|
||||
thread->wait_flags = flags;
|
||||
thread->flags_options = (uint8_t)options;
|
||||
} else {
|
||||
EvrRtxEventFlagsWaitTimeout(ef);
|
||||
}
|
||||
event_flags = (uint32_t)osErrorTimeout;
|
||||
} else {
|
||||
EvrRtxEventFlagsWaitNotCompleted(ef, flags, options);
|
||||
event_flags = (uint32_t)osErrorResource;
|
||||
}
|
||||
}
|
||||
|
||||
return event_flags;
|
||||
}
|
||||
|
||||
/// Delete an Event Flags object.
|
||||
/// \note API identical to osEventFlagsDelete
|
||||
static osStatus_t svcRtxEventFlagsDelete (osEventFlagsId_t ef_id) {
|
||||
os_event_flags_t *ef = osRtxEventFlagsId(ef_id);
|
||||
os_thread_t *thread;
|
||||
|
||||
// Check parameters
|
||||
if ((ef == NULL) || (ef->id != osRtxIdEventFlags)) {
|
||||
EvrRtxEventFlagsError(ef, (int32_t)osErrorParameter);
|
||||
//lint -e{904} "Return statement before end of function" [MISRA Note 1]
|
||||
return osErrorParameter;
|
||||
}
|
||||
|
||||
// Unblock waiting threads
|
||||
if (ef->thread_list != NULL) {
|
||||
do {
|
||||
thread = osRtxThreadListGet(osRtxObject(ef));
|
||||
osRtxThreadWaitExit(thread, (uint32_t)osErrorResource, FALSE);
|
||||
} while (ef->thread_list != NULL);
|
||||
osRtxThreadDispatch(NULL);
|
||||
}
|
||||
|
||||
// Mark object as invalid
|
||||
ef->id = osRtxIdInvalid;
|
||||
|
||||
// Free object memory
|
||||
if ((ef->flags & osRtxFlagSystemObject) != 0U) {
|
||||
if (osRtxInfo.mpi.event_flags != NULL) {
|
||||
(void)osRtxMemoryPoolFree(osRtxInfo.mpi.event_flags, ef);
|
||||
} else {
|
||||
(void)osRtxMemoryFree(osRtxInfo.mem.common, ef);
|
||||
}
|
||||
#if (defined(OS_OBJ_MEM_USAGE) && (OS_OBJ_MEM_USAGE != 0))
|
||||
osRtxEventFlagsMemUsage.cnt_free++;
|
||||
#endif
|
||||
}
|
||||
|
||||
EvrRtxEventFlagsDestroyed(ef);
|
||||
|
||||
return osOK;
|
||||
}
|
||||
|
||||
// Service Calls definitions
|
||||
//lint ++flb "Library Begin" [MISRA Note 11]
|
||||
SVC0_1(EventFlagsNew, osEventFlagsId_t, const osEventFlagsAttr_t *)
|
||||
SVC0_1(EventFlagsGetName, const char *, osEventFlagsId_t)
|
||||
SVC0_2(EventFlagsSet, uint32_t, osEventFlagsId_t, uint32_t)
|
||||
SVC0_2(EventFlagsClear, uint32_t, osEventFlagsId_t, uint32_t)
|
||||
SVC0_1(EventFlagsGet, uint32_t, osEventFlagsId_t)
|
||||
SVC0_4(EventFlagsWait, uint32_t, osEventFlagsId_t, uint32_t, uint32_t, uint32_t)
|
||||
SVC0_1(EventFlagsDelete, osStatus_t, osEventFlagsId_t)
|
||||
//lint --flb "Library End"
|
||||
|
||||
|
||||
// ==== ISR Calls ====
|
||||
|
||||
/// Set the specified Event Flags.
|
||||
/// \note API identical to osEventFlagsSet
|
||||
__STATIC_INLINE
|
||||
uint32_t isrRtxEventFlagsSet (osEventFlagsId_t ef_id, uint32_t flags) {
|
||||
os_event_flags_t *ef = osRtxEventFlagsId(ef_id);
|
||||
uint32_t event_flags;
|
||||
|
||||
// Check parameters
|
||||
if ((ef == NULL) || (ef->id != osRtxIdEventFlags) ||
|
||||
((flags & ~(((uint32_t)1U << osRtxEventFlagsLimit) - 1U)) != 0U)) {
|
||||
EvrRtxEventFlagsError(ef, (int32_t)osErrorParameter);
|
||||
//lint -e{904} "Return statement before end of function" [MISRA Note 1]
|
||||
return ((uint32_t)osErrorParameter);
|
||||
}
|
||||
|
||||
// Set Event Flags
|
||||
event_flags = EventFlagsSet(ef, flags);
|
||||
|
||||
// Register post ISR processing
|
||||
osRtxPostProcess(osRtxObject(ef));
|
||||
|
||||
EvrRtxEventFlagsSetDone(ef, event_flags);
|
||||
|
||||
return event_flags;
|
||||
}
|
||||
|
||||
/// Wait for one or more Event Flags to become signaled.
|
||||
/// \note API identical to osEventFlagsWait
|
||||
__STATIC_INLINE
|
||||
uint32_t isrRtxEventFlagsWait (osEventFlagsId_t ef_id, uint32_t flags, uint32_t options, uint32_t timeout) {
|
||||
os_event_flags_t *ef = osRtxEventFlagsId(ef_id);
|
||||
uint32_t event_flags;
|
||||
|
||||
// Check parameters
|
||||
if ((ef == NULL) || (ef->id != osRtxIdEventFlags) || (timeout != 0U) ||
|
||||
((flags & ~(((uint32_t)1U << osRtxEventFlagsLimit) - 1U)) != 0U)) {
|
||||
EvrRtxEventFlagsError(ef, (int32_t)osErrorParameter);
|
||||
//lint -e{904} "Return statement before end of function" [MISRA Note 1]
|
||||
return ((uint32_t)osErrorParameter);
|
||||
}
|
||||
|
||||
// Check Event Flags
|
||||
event_flags = EventFlagsCheck(ef, flags, options);
|
||||
if (event_flags != 0U) {
|
||||
EvrRtxEventFlagsWaitCompleted(ef, flags, options, event_flags);
|
||||
} else {
|
||||
EvrRtxEventFlagsWaitNotCompleted(ef, flags, options);
|
||||
event_flags = (uint32_t)osErrorResource;
|
||||
}
|
||||
|
||||
return event_flags;
|
||||
}
|
||||
|
||||
|
||||
// ==== Public API ====
|
||||
|
||||
/// Create and Initialize an Event Flags object.
|
||||
osEventFlagsId_t osEventFlagsNew (const osEventFlagsAttr_t *attr) {
|
||||
osEventFlagsId_t ef_id;
|
||||
|
||||
EvrRtxEventFlagsNew(attr);
|
||||
if (IsIrqMode() || IsIrqMasked()) {
|
||||
EvrRtxEventFlagsError(NULL, (int32_t)osErrorISR);
|
||||
ef_id = NULL;
|
||||
} else {
|
||||
ef_id = __svcEventFlagsNew(attr);
|
||||
}
|
||||
return ef_id;
|
||||
}
|
||||
|
||||
/// Get name of an Event Flags object.
|
||||
const char *osEventFlagsGetName (osEventFlagsId_t ef_id) {
|
||||
const char *name;
|
||||
|
||||
if (IsIrqMode() || IsIrqMasked()) {
|
||||
EvrRtxEventFlagsGetName(ef_id, NULL);
|
||||
name = NULL;
|
||||
} else {
|
||||
name = __svcEventFlagsGetName(ef_id);
|
||||
}
|
||||
return name;
|
||||
}
|
||||
|
||||
/// Set the specified Event Flags.
|
||||
uint32_t osEventFlagsSet (osEventFlagsId_t ef_id, uint32_t flags) {
|
||||
uint32_t event_flags;
|
||||
|
||||
EvrRtxEventFlagsSet(ef_id, flags);
|
||||
if (IsIrqMode() || IsIrqMasked()) {
|
||||
event_flags = isrRtxEventFlagsSet(ef_id, flags);
|
||||
} else {
|
||||
event_flags = __svcEventFlagsSet(ef_id, flags);
|
||||
}
|
||||
return event_flags;
|
||||
}
|
||||
|
||||
/// Clear the specified Event Flags.
|
||||
uint32_t osEventFlagsClear (osEventFlagsId_t ef_id, uint32_t flags) {
|
||||
uint32_t event_flags;
|
||||
|
||||
EvrRtxEventFlagsClear(ef_id, flags);
|
||||
if (IsIrqMode() || IsIrqMasked()) {
|
||||
event_flags = svcRtxEventFlagsClear(ef_id, flags);
|
||||
} else {
|
||||
event_flags = __svcEventFlagsClear(ef_id, flags);
|
||||
}
|
||||
return event_flags;
|
||||
}
|
||||
|
||||
/// Get the current Event Flags.
|
||||
uint32_t osEventFlagsGet (osEventFlagsId_t ef_id) {
|
||||
uint32_t event_flags;
|
||||
|
||||
if (IsIrqMode() || IsIrqMasked()) {
|
||||
event_flags = svcRtxEventFlagsGet(ef_id);
|
||||
} else {
|
||||
event_flags = __svcEventFlagsGet(ef_id);
|
||||
}
|
||||
return event_flags;
|
||||
}
|
||||
|
||||
/// Wait for one or more Event Flags to become signaled.
|
||||
uint32_t osEventFlagsWait (osEventFlagsId_t ef_id, uint32_t flags, uint32_t options, uint32_t timeout) {
|
||||
uint32_t event_flags;
|
||||
|
||||
EvrRtxEventFlagsWait(ef_id, flags, options, timeout);
|
||||
if (IsIrqMode() || IsIrqMasked()) {
|
||||
event_flags = isrRtxEventFlagsWait(ef_id, flags, options, timeout);
|
||||
} else {
|
||||
event_flags = __svcEventFlagsWait(ef_id, flags, options, timeout);
|
||||
}
|
||||
return event_flags;
|
||||
}
|
||||
|
||||
/// Delete an Event Flags object.
|
||||
osStatus_t osEventFlagsDelete (osEventFlagsId_t ef_id) {
|
||||
osStatus_t status;
|
||||
|
||||
EvrRtxEventFlagsDelete(ef_id);
|
||||
if (IsIrqMode() || IsIrqMasked()) {
|
||||
EvrRtxEventFlagsError(ef_id, (int32_t)osErrorISR);
|
||||
status = osErrorISR;
|
||||
} else {
|
||||
status = __svcEventFlagsDelete(ef_id);
|
||||
}
|
||||
return status;
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,680 @@
|
||||
/*
|
||||
* Copyright (c) 2013-2019 Arm Limited. All rights reserved.
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the License); you may
|
||||
* not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an AS IS BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
* -----------------------------------------------------------------------------
|
||||
*
|
||||
* Project: CMSIS-RTOS RTX
|
||||
* Title: Kernel functions
|
||||
*
|
||||
* -----------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
#include "rtx_lib.h"
|
||||
|
||||
|
||||
// OS Runtime Information
|
||||
osRtxInfo_t osRtxInfo __attribute__((section(".data.os"))) =
|
||||
//lint -e{785} "Initialize only OS ID, OS Version and Kernel State"
|
||||
{ .os_id = osRtxKernelId, .version = osRtxVersionKernel, .kernel.state = osRtxKernelInactive };
|
||||
|
||||
|
||||
// ==== Helper functions ====
|
||||
|
||||
/// Block Kernel (disable: thread switching, time tick, post ISR processing).
|
||||
static void KernelBlock (void) {
|
||||
|
||||
OS_Tick_Disable();
|
||||
|
||||
osRtxInfo.kernel.blocked = 1U;
|
||||
__DSB();
|
||||
|
||||
if (GetPendSV() != 0U) {
|
||||
ClrPendSV();
|
||||
osRtxInfo.kernel.pendSV = 1U;
|
||||
}
|
||||
}
|
||||
|
||||
/// Unblock Kernel
|
||||
static void KernelUnblock (void) {
|
||||
|
||||
osRtxInfo.kernel.blocked = 0U;
|
||||
__DSB();
|
||||
|
||||
if (osRtxInfo.kernel.pendSV != 0U) {
|
||||
osRtxInfo.kernel.pendSV = 0U;
|
||||
SetPendSV();
|
||||
}
|
||||
|
||||
OS_Tick_Enable();
|
||||
}
|
||||
|
||||
|
||||
// ==== Service Calls ====
|
||||
|
||||
/// Initialize the RTOS Kernel.
|
||||
/// \note API identical to osKernelInitialize
|
||||
static osStatus_t svcRtxKernelInitialize (void) {
|
||||
|
||||
if (osRtxInfo.kernel.state == osRtxKernelReady) {
|
||||
EvrRtxKernelInitialized();
|
||||
//lint -e{904} "Return statement before end of function" [MISRA Note 1]
|
||||
return osOK;
|
||||
}
|
||||
if (osRtxInfo.kernel.state != osRtxKernelInactive) {
|
||||
EvrRtxKernelError((int32_t)osError);
|
||||
//lint -e{904} "Return statement before end of function" [MISRA Note 1]
|
||||
return osError;
|
||||
}
|
||||
|
||||
#if (DOMAIN_NS == 1)
|
||||
// Initialize Secure Process Stack
|
||||
if (TZ_InitContextSystem_S() == 0U) {
|
||||
EvrRtxKernelError(osRtxErrorTZ_InitContext_S);
|
||||
//lint -e{904} "Return statement before end of function" [MISRA Note 1]
|
||||
return osError;
|
||||
}
|
||||
#endif
|
||||
|
||||
// Initialize osRtxInfo
|
||||
memset(&osRtxInfo.kernel, 0, sizeof(osRtxInfo) - offsetof(osRtxInfo_t, kernel));
|
||||
|
||||
osRtxInfo.isr_queue.data = osRtxConfig.isr_queue.data;
|
||||
osRtxInfo.isr_queue.max = osRtxConfig.isr_queue.max;
|
||||
|
||||
osRtxInfo.thread.robin.timeout = osRtxConfig.robin_timeout;
|
||||
|
||||
// Initialize Memory Pools (Variable Block Size)
|
||||
if (osRtxMemoryInit(osRtxConfig.mem.common_addr, osRtxConfig.mem.common_size) != 0U) {
|
||||
osRtxInfo.mem.common = osRtxConfig.mem.common_addr;
|
||||
}
|
||||
if (osRtxMemoryInit(osRtxConfig.mem.stack_addr, osRtxConfig.mem.stack_size) != 0U) {
|
||||
osRtxInfo.mem.stack = osRtxConfig.mem.stack_addr;
|
||||
} else {
|
||||
osRtxInfo.mem.stack = osRtxInfo.mem.common;
|
||||
}
|
||||
if (osRtxMemoryInit(osRtxConfig.mem.mp_data_addr, osRtxConfig.mem.mp_data_size) != 0U) {
|
||||
osRtxInfo.mem.mp_data = osRtxConfig.mem.mp_data_addr;
|
||||
} else {
|
||||
osRtxInfo.mem.mp_data = osRtxInfo.mem.common;
|
||||
}
|
||||
if (osRtxMemoryInit(osRtxConfig.mem.mq_data_addr, osRtxConfig.mem.mq_data_size) != 0U) {
|
||||
osRtxInfo.mem.mq_data = osRtxConfig.mem.mq_data_addr;
|
||||
} else {
|
||||
osRtxInfo.mem.mq_data = osRtxInfo.mem.common;
|
||||
}
|
||||
|
||||
// Initialize Memory Pools (Fixed Block Size)
|
||||
if (osRtxConfig.mpi.stack != NULL) {
|
||||
(void)osRtxMemoryPoolInit(osRtxConfig.mpi.stack,
|
||||
osRtxConfig.mpi.stack->max_blocks,
|
||||
osRtxConfig.mpi.stack->block_size,
|
||||
osRtxConfig.mpi.stack->block_base);
|
||||
osRtxInfo.mpi.stack = osRtxConfig.mpi.stack;
|
||||
}
|
||||
if (osRtxConfig.mpi.thread != NULL) {
|
||||
(void)osRtxMemoryPoolInit(osRtxConfig.mpi.thread,
|
||||
osRtxConfig.mpi.thread->max_blocks,
|
||||
osRtxConfig.mpi.thread->block_size,
|
||||
osRtxConfig.mpi.thread->block_base);
|
||||
osRtxInfo.mpi.thread = osRtxConfig.mpi.thread;
|
||||
}
|
||||
if (osRtxConfig.mpi.timer != NULL) {
|
||||
(void)osRtxMemoryPoolInit(osRtxConfig.mpi.timer,
|
||||
osRtxConfig.mpi.timer->max_blocks,
|
||||
osRtxConfig.mpi.timer->block_size,
|
||||
osRtxConfig.mpi.timer->block_base);
|
||||
osRtxInfo.mpi.timer = osRtxConfig.mpi.timer;
|
||||
}
|
||||
if (osRtxConfig.mpi.event_flags != NULL) {
|
||||
(void)osRtxMemoryPoolInit(osRtxConfig.mpi.event_flags,
|
||||
osRtxConfig.mpi.event_flags->max_blocks,
|
||||
osRtxConfig.mpi.event_flags->block_size,
|
||||
osRtxConfig.mpi.event_flags->block_base);
|
||||
osRtxInfo.mpi.event_flags = osRtxConfig.mpi.event_flags;
|
||||
}
|
||||
if (osRtxConfig.mpi.mutex != NULL) {
|
||||
(void)osRtxMemoryPoolInit(osRtxConfig.mpi.mutex,
|
||||
osRtxConfig.mpi.mutex->max_blocks,
|
||||
osRtxConfig.mpi.mutex->block_size,
|
||||
osRtxConfig.mpi.mutex->block_base);
|
||||
osRtxInfo.mpi.mutex = osRtxConfig.mpi.mutex;
|
||||
}
|
||||
if (osRtxConfig.mpi.semaphore != NULL) {
|
||||
(void)osRtxMemoryPoolInit(osRtxConfig.mpi.semaphore,
|
||||
osRtxConfig.mpi.semaphore->max_blocks,
|
||||
osRtxConfig.mpi.semaphore->block_size,
|
||||
osRtxConfig.mpi.semaphore->block_base);
|
||||
osRtxInfo.mpi.semaphore = osRtxConfig.mpi.semaphore;
|
||||
}
|
||||
if (osRtxConfig.mpi.memory_pool != NULL) {
|
||||
(void)osRtxMemoryPoolInit(osRtxConfig.mpi.memory_pool,
|
||||
osRtxConfig.mpi.memory_pool->max_blocks,
|
||||
osRtxConfig.mpi.memory_pool->block_size,
|
||||
osRtxConfig.mpi.memory_pool->block_base);
|
||||
osRtxInfo.mpi.memory_pool = osRtxConfig.mpi.memory_pool;
|
||||
}
|
||||
if (osRtxConfig.mpi.message_queue != NULL) {
|
||||
(void)osRtxMemoryPoolInit(osRtxConfig.mpi.message_queue,
|
||||
osRtxConfig.mpi.message_queue->max_blocks,
|
||||
osRtxConfig.mpi.message_queue->block_size,
|
||||
osRtxConfig.mpi.message_queue->block_base);
|
||||
osRtxInfo.mpi.message_queue = osRtxConfig.mpi.message_queue;
|
||||
}
|
||||
|
||||
osRtxInfo.kernel.state = osRtxKernelReady;
|
||||
|
||||
EvrRtxKernelInitialized();
|
||||
|
||||
return osOK;
|
||||
}
|
||||
|
||||
/// Get RTOS Kernel Information.
|
||||
/// \note API identical to osKernelGetInfo
|
||||
static osStatus_t svcRtxKernelGetInfo (osVersion_t *version, char *id_buf, uint32_t id_size) {
|
||||
uint32_t size;
|
||||
|
||||
if (version != NULL) {
|
||||
version->api = osRtxVersionAPI;
|
||||
version->kernel = osRtxVersionKernel;
|
||||
}
|
||||
|
||||
if ((id_buf != NULL) && (id_size != 0U)) {
|
||||
if (id_size > sizeof(osRtxKernelId)) {
|
||||
size = sizeof(osRtxKernelId);
|
||||
} else {
|
||||
size = id_size;
|
||||
}
|
||||
memcpy(id_buf, osRtxKernelId, size);
|
||||
}
|
||||
|
||||
EvrRtxKernelInfoRetrieved(version, id_buf, id_size);
|
||||
|
||||
return osOK;
|
||||
}
|
||||
|
||||
/// Get the current RTOS Kernel state.
|
||||
/// \note API identical to osKernelGetState
|
||||
static osKernelState_t svcRtxKernelGetState (void) {
|
||||
osKernelState_t state = osRtxKernelState();
|
||||
EvrRtxKernelGetState(state);
|
||||
return state;
|
||||
}
|
||||
|
||||
/// Start the RTOS Kernel scheduler.
|
||||
/// \note API identical to osKernelStart
|
||||
static osStatus_t svcRtxKernelStart (void) {
|
||||
os_thread_t *thread;
|
||||
|
||||
if (osRtxInfo.kernel.state != osRtxKernelReady) {
|
||||
EvrRtxKernelError(osRtxErrorKernelNotReady);
|
||||
//lint -e{904} "Return statement before end of function" [MISRA Note 1]
|
||||
return osError;
|
||||
}
|
||||
|
||||
// Thread startup (Idle and Timer Thread)
|
||||
if (!osRtxThreadStartup()) {
|
||||
EvrRtxKernelError((int32_t)osError);
|
||||
//lint -e{904} "Return statement before end of function" [MISRA Note 1]
|
||||
return osError;
|
||||
}
|
||||
|
||||
// Setup SVC and PendSV System Service Calls
|
||||
SVC_Setup();
|
||||
|
||||
// Setup RTOS Tick
|
||||
if (OS_Tick_Setup(osRtxConfig.tick_freq, OS_TICK_HANDLER) != 0) {
|
||||
EvrRtxKernelError((int32_t)osError);
|
||||
//lint -e{904} "Return statement before end of function" [MISRA Note 1]
|
||||
return osError;
|
||||
}
|
||||
osRtxInfo.tick_irqn = OS_Tick_GetIRQn();
|
||||
|
||||
// Enable RTOS Tick
|
||||
OS_Tick_Enable();
|
||||
|
||||
// Switch to Ready Thread with highest Priority
|
||||
thread = osRtxThreadListGet(&osRtxInfo.thread.ready);
|
||||
osRtxThreadSwitch(thread);
|
||||
|
||||
if ((osRtxConfig.flags & osRtxConfigPrivilegedMode) != 0U) {
|
||||
// Privileged Thread mode & PSP
|
||||
__set_CONTROL(0x02U);
|
||||
} else {
|
||||
// Unprivileged Thread mode & PSP
|
||||
__set_CONTROL(0x03U);
|
||||
}
|
||||
|
||||
osRtxInfo.kernel.state = osRtxKernelRunning;
|
||||
|
||||
EvrRtxKernelStarted();
|
||||
|
||||
return osOK;
|
||||
}
|
||||
|
||||
/// Lock the RTOS Kernel scheduler.
|
||||
/// \note API identical to osKernelLock
|
||||
static int32_t svcRtxKernelLock (void) {
|
||||
int32_t lock;
|
||||
|
||||
switch (osRtxInfo.kernel.state) {
|
||||
case osRtxKernelRunning:
|
||||
osRtxInfo.kernel.state = osRtxKernelLocked;
|
||||
EvrRtxKernelLocked(0);
|
||||
lock = 0;
|
||||
break;
|
||||
case osRtxKernelLocked:
|
||||
EvrRtxKernelLocked(1);
|
||||
lock = 1;
|
||||
break;
|
||||
default:
|
||||
EvrRtxKernelError((int32_t)osError);
|
||||
lock = (int32_t)osError;
|
||||
break;
|
||||
}
|
||||
return lock;
|
||||
}
|
||||
|
||||
/// Unlock the RTOS Kernel scheduler.
|
||||
/// \note API identical to osKernelUnlock
|
||||
static int32_t svcRtxKernelUnlock (void) {
|
||||
int32_t lock;
|
||||
|
||||
switch (osRtxInfo.kernel.state) {
|
||||
case osRtxKernelRunning:
|
||||
EvrRtxKernelUnlocked(0);
|
||||
lock = 0;
|
||||
break;
|
||||
case osRtxKernelLocked:
|
||||
osRtxInfo.kernel.state = osRtxKernelRunning;
|
||||
EvrRtxKernelUnlocked(1);
|
||||
lock = 1;
|
||||
break;
|
||||
default:
|
||||
EvrRtxKernelError((int32_t)osError);
|
||||
lock = (int32_t)osError;
|
||||
break;
|
||||
}
|
||||
return lock;
|
||||
}
|
||||
|
||||
/// Restore the RTOS Kernel scheduler lock state.
|
||||
/// \note API identical to osKernelRestoreLock
|
||||
static int32_t svcRtxKernelRestoreLock (int32_t lock) {
|
||||
int32_t lock_new;
|
||||
|
||||
switch (osRtxInfo.kernel.state) {
|
||||
case osRtxKernelRunning:
|
||||
case osRtxKernelLocked:
|
||||
switch (lock) {
|
||||
case 0:
|
||||
osRtxInfo.kernel.state = osRtxKernelRunning;
|
||||
EvrRtxKernelLockRestored(0);
|
||||
lock_new = 0;
|
||||
break;
|
||||
case 1:
|
||||
osRtxInfo.kernel.state = osRtxKernelLocked;
|
||||
EvrRtxKernelLockRestored(1);
|
||||
lock_new = 1;
|
||||
break;
|
||||
default:
|
||||
EvrRtxKernelError((int32_t)osError);
|
||||
lock_new = (int32_t)osError;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
EvrRtxKernelError((int32_t)osError);
|
||||
lock_new = (int32_t)osError;
|
||||
break;
|
||||
}
|
||||
return lock_new;
|
||||
}
|
||||
|
||||
/// Suspend the RTOS Kernel scheduler.
|
||||
/// \note API identical to osKernelSuspend
|
||||
static uint32_t svcRtxKernelSuspend (void) {
|
||||
const os_thread_t *thread;
|
||||
const os_timer_t *timer;
|
||||
uint32_t delay;
|
||||
|
||||
if (osRtxInfo.kernel.state != osRtxKernelRunning) {
|
||||
EvrRtxKernelError(osRtxErrorKernelNotRunning);
|
||||
//lint -e{904} "Return statement before end of function" [MISRA Note 1]
|
||||
return 0U;
|
||||
}
|
||||
|
||||
KernelBlock();
|
||||
|
||||
delay = osWaitForever;
|
||||
|
||||
// Check Thread Delay list
|
||||
thread = osRtxInfo.thread.delay_list;
|
||||
if (thread != NULL) {
|
||||
delay = thread->delay;
|
||||
}
|
||||
|
||||
// Check Active Timer list
|
||||
timer = osRtxInfo.timer.list;
|
||||
if (timer != NULL) {
|
||||
if (timer->tick < delay) {
|
||||
delay = timer->tick;
|
||||
}
|
||||
}
|
||||
|
||||
osRtxInfo.kernel.state = osRtxKernelSuspended;
|
||||
|
||||
EvrRtxKernelSuspended(delay);
|
||||
|
||||
return delay;
|
||||
}
|
||||
|
||||
/// Resume the RTOS Kernel scheduler.
|
||||
/// \note API identical to osKernelResume
|
||||
static void svcRtxKernelResume (uint32_t sleep_ticks) {
|
||||
os_thread_t *thread;
|
||||
os_timer_t *timer;
|
||||
uint32_t delay;
|
||||
uint32_t ticks;
|
||||
|
||||
if (osRtxInfo.kernel.state != osRtxKernelSuspended) {
|
||||
EvrRtxKernelResumed();
|
||||
//lint -e{904} "Return statement before end of function" [MISRA Note 1]
|
||||
return;
|
||||
}
|
||||
|
||||
osRtxInfo.kernel.tick += sleep_ticks;
|
||||
|
||||
// Process Thread Delay list
|
||||
thread = osRtxInfo.thread.delay_list;
|
||||
if (thread != NULL) {
|
||||
delay = sleep_ticks;
|
||||
do {
|
||||
if (delay >= thread->delay) {
|
||||
delay -= thread->delay;
|
||||
thread->delay = 1U;
|
||||
osRtxThreadDelayTick();
|
||||
thread = osRtxInfo.thread.delay_list;
|
||||
} else {
|
||||
thread->delay -= delay;
|
||||
delay = 0U;
|
||||
}
|
||||
} while ((thread != NULL) && (delay != 0U));
|
||||
}
|
||||
|
||||
// Process Active Timer list
|
||||
timer = osRtxInfo.timer.list;
|
||||
if (timer != NULL) {
|
||||
ticks = sleep_ticks;
|
||||
do {
|
||||
if (ticks >= timer->tick) {
|
||||
ticks -= timer->tick;
|
||||
timer->tick = 1U;
|
||||
osRtxInfo.timer.tick();
|
||||
timer = osRtxInfo.timer.list;
|
||||
} else {
|
||||
timer->tick -= ticks;
|
||||
ticks = 0U;
|
||||
}
|
||||
} while ((timer != NULL) && (ticks != 0U));
|
||||
}
|
||||
|
||||
osRtxInfo.kernel.state = osRtxKernelRunning;
|
||||
|
||||
osRtxThreadDispatch(NULL);
|
||||
|
||||
KernelUnblock();
|
||||
|
||||
EvrRtxKernelResumed();
|
||||
}
|
||||
|
||||
/// Get the RTOS kernel tick count.
|
||||
/// \note API identical to osKernelGetTickCount
|
||||
static uint32_t svcRtxKernelGetTickCount (void) {
|
||||
EvrRtxKernelGetTickCount(osRtxInfo.kernel.tick);
|
||||
return osRtxInfo.kernel.tick;
|
||||
}
|
||||
|
||||
/// Get the RTOS kernel tick frequency.
|
||||
/// \note API identical to osKernelGetTickFreq
|
||||
static uint32_t svcRtxKernelGetTickFreq (void) {
|
||||
EvrRtxKernelGetTickFreq(osRtxConfig.tick_freq);
|
||||
return osRtxConfig.tick_freq;
|
||||
}
|
||||
|
||||
/// Get the RTOS kernel system timer count.
|
||||
/// \note API identical to osKernelGetSysTimerCount
|
||||
static uint32_t svcRtxKernelGetSysTimerCount (void) {
|
||||
uint32_t tick;
|
||||
uint32_t count;
|
||||
|
||||
tick = (uint32_t)osRtxInfo.kernel.tick;
|
||||
count = OS_Tick_GetCount();
|
||||
if (OS_Tick_GetOverflow() != 0U) {
|
||||
count = OS_Tick_GetCount();
|
||||
tick++;
|
||||
}
|
||||
count += tick * OS_Tick_GetInterval();
|
||||
EvrRtxKernelGetSysTimerCount(count);
|
||||
return count;
|
||||
}
|
||||
|
||||
/// Get the RTOS kernel system timer frequency.
|
||||
/// \note API identical to osKernelGetSysTimerFreq
|
||||
static uint32_t svcRtxKernelGetSysTimerFreq (void) {
|
||||
uint32_t freq = OS_Tick_GetClock();
|
||||
EvrRtxKernelGetSysTimerFreq(freq);
|
||||
return freq;
|
||||
}
|
||||
|
||||
// Service Calls definitions
|
||||
//lint ++flb "Library Begin" [MISRA Note 11]
|
||||
SVC0_0 (KernelInitialize, osStatus_t)
|
||||
SVC0_3 (KernelGetInfo, osStatus_t, osVersion_t *, char *, uint32_t)
|
||||
SVC0_0 (KernelStart, osStatus_t)
|
||||
SVC0_0 (KernelLock, int32_t)
|
||||
SVC0_0 (KernelUnlock, int32_t)
|
||||
SVC0_1 (KernelRestoreLock, int32_t, int32_t)
|
||||
SVC0_0 (KernelSuspend, uint32_t)
|
||||
SVC0_1N(KernelResume, void, uint32_t)
|
||||
SVC0_0 (KernelGetState, osKernelState_t)
|
||||
SVC0_0 (KernelGetTickCount, uint32_t)
|
||||
SVC0_0 (KernelGetTickFreq, uint32_t)
|
||||
SVC0_0 (KernelGetSysTimerCount, uint32_t)
|
||||
SVC0_0 (KernelGetSysTimerFreq, uint32_t)
|
||||
//lint --flb "Library End"
|
||||
|
||||
|
||||
// ==== Library functions ====
|
||||
|
||||
/// RTOS Kernel Pre-Initialization Hook
|
||||
//lint -esym(759,osRtxKernelPreInit) "Prototype in header"
|
||||
//lint -esym(765,osRtxKernelPreInit) "Global scope (can be overridden)"
|
||||
//lint -esym(522,osRtxKernelPreInit) "Can be overridden (do not lack side-effects)"
|
||||
__WEAK void osRtxKernelPreInit (void) {
|
||||
}
|
||||
|
||||
|
||||
// ==== Public API ====
|
||||
|
||||
/// Initialize the RTOS Kernel.
|
||||
osStatus_t osKernelInitialize (void) {
|
||||
osStatus_t status;
|
||||
|
||||
osRtxKernelPreInit();
|
||||
EvrRtxKernelInitialize();
|
||||
if (IsIrqMode() || IsIrqMasked()) {
|
||||
EvrRtxKernelError((int32_t)osErrorISR);
|
||||
status = osErrorISR;
|
||||
} else {
|
||||
status = __svcKernelInitialize();
|
||||
}
|
||||
return status;
|
||||
}
|
||||
|
||||
/// Get RTOS Kernel Information.
|
||||
osStatus_t osKernelGetInfo (osVersion_t *version, char *id_buf, uint32_t id_size) {
|
||||
osStatus_t status;
|
||||
|
||||
EvrRtxKernelGetInfo(version, id_buf, id_size);
|
||||
if (IsIrqMode() || IsIrqMasked() || IsPrivileged()) {
|
||||
status = svcRtxKernelGetInfo(version, id_buf, id_size);
|
||||
} else {
|
||||
status = __svcKernelGetInfo(version, id_buf, id_size);
|
||||
}
|
||||
return status;
|
||||
}
|
||||
|
||||
/// Get the current RTOS Kernel state.
|
||||
osKernelState_t osKernelGetState (void) {
|
||||
osKernelState_t state;
|
||||
|
||||
if (IsIrqMode() || IsIrqMasked() || IsPrivileged()) {
|
||||
state = svcRtxKernelGetState();
|
||||
} else {
|
||||
state = __svcKernelGetState();
|
||||
}
|
||||
return state;
|
||||
}
|
||||
|
||||
/// Start the RTOS Kernel scheduler.
|
||||
osStatus_t osKernelStart (void) {
|
||||
osStatus_t status;
|
||||
|
||||
EvrRtxKernelStart();
|
||||
if (IsIrqMode() || IsIrqMasked()) {
|
||||
EvrRtxKernelError((int32_t)osErrorISR);
|
||||
status = osErrorISR;
|
||||
} else {
|
||||
status = __svcKernelStart();
|
||||
}
|
||||
return status;
|
||||
}
|
||||
|
||||
/// Lock the RTOS Kernel scheduler.
|
||||
int32_t osKernelLock (void) {
|
||||
int32_t lock;
|
||||
|
||||
EvrRtxKernelLock();
|
||||
if (IsIrqMode() || IsIrqMasked()) {
|
||||
EvrRtxKernelError((int32_t)osErrorISR);
|
||||
lock = (int32_t)osErrorISR;
|
||||
} else {
|
||||
lock = __svcKernelLock();
|
||||
}
|
||||
return lock;
|
||||
}
|
||||
|
||||
/// Unlock the RTOS Kernel scheduler.
|
||||
int32_t osKernelUnlock (void) {
|
||||
int32_t lock;
|
||||
|
||||
EvrRtxKernelUnlock();
|
||||
if (IsIrqMode() || IsIrqMasked()) {
|
||||
EvrRtxKernelError((int32_t)osErrorISR);
|
||||
lock = (int32_t)osErrorISR;
|
||||
} else {
|
||||
lock = __svcKernelUnlock();
|
||||
}
|
||||
return lock;
|
||||
}
|
||||
|
||||
/// Restore the RTOS Kernel scheduler lock state.
|
||||
int32_t osKernelRestoreLock (int32_t lock) {
|
||||
int32_t lock_new;
|
||||
|
||||
EvrRtxKernelRestoreLock(lock);
|
||||
if (IsIrqMode() || IsIrqMasked()) {
|
||||
EvrRtxKernelError((int32_t)osErrorISR);
|
||||
lock_new = (int32_t)osErrorISR;
|
||||
} else {
|
||||
lock_new = __svcKernelRestoreLock(lock);
|
||||
}
|
||||
return lock_new;
|
||||
}
|
||||
|
||||
/// Suspend the RTOS Kernel scheduler.
|
||||
uint32_t osKernelSuspend (void) {
|
||||
uint32_t ticks;
|
||||
|
||||
EvrRtxKernelSuspend();
|
||||
if (IsIrqMode() || IsIrqMasked()) {
|
||||
EvrRtxKernelError((int32_t)osErrorISR);
|
||||
ticks = 0U;
|
||||
} else {
|
||||
ticks = __svcKernelSuspend();
|
||||
}
|
||||
return ticks;
|
||||
}
|
||||
|
||||
/// Resume the RTOS Kernel scheduler.
|
||||
void osKernelResume (uint32_t sleep_ticks) {
|
||||
|
||||
EvrRtxKernelResume(sleep_ticks);
|
||||
if (IsIrqMode() || IsIrqMasked()) {
|
||||
EvrRtxKernelError((int32_t)osErrorISR);
|
||||
} else {
|
||||
__svcKernelResume(sleep_ticks);
|
||||
}
|
||||
}
|
||||
|
||||
/// Get the RTOS kernel tick count.
|
||||
uint32_t osKernelGetTickCount (void) {
|
||||
uint32_t count;
|
||||
|
||||
if (IsIrqMode() || IsIrqMasked()) {
|
||||
count = svcRtxKernelGetTickCount();
|
||||
} else {
|
||||
count = __svcKernelGetTickCount();
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
/// Get the RTOS kernel tick frequency.
|
||||
uint32_t osKernelGetTickFreq (void) {
|
||||
uint32_t freq;
|
||||
|
||||
if (IsIrqMode() || IsIrqMasked()) {
|
||||
freq = svcRtxKernelGetTickFreq();
|
||||
} else {
|
||||
freq = __svcKernelGetTickFreq();
|
||||
}
|
||||
return freq;
|
||||
}
|
||||
|
||||
/// Get the RTOS kernel system timer count.
|
||||
uint32_t osKernelGetSysTimerCount (void) {
|
||||
uint32_t count;
|
||||
|
||||
if (IsIrqMode() || IsIrqMasked()) {
|
||||
count = svcRtxKernelGetSysTimerCount();
|
||||
} else {
|
||||
count = __svcKernelGetSysTimerCount();
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
/// Get the RTOS kernel system timer frequency.
|
||||
uint32_t osKernelGetSysTimerFreq (void) {
|
||||
uint32_t freq;
|
||||
|
||||
if (IsIrqMode() || IsIrqMasked()) {
|
||||
freq = svcRtxKernelGetSysTimerFreq();
|
||||
} else {
|
||||
freq = __svcKernelGetSysTimerFreq();
|
||||
}
|
||||
return freq;
|
||||
}
|
||||
@@ -0,0 +1,773 @@
|
||||
/*
|
||||
* Copyright (c) 2013-2019 Arm Limited. All rights reserved.
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the License); you may
|
||||
* not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an AS IS BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
* -----------------------------------------------------------------------------
|
||||
*
|
||||
* Project: CMSIS-RTOS RTX
|
||||
* Title: RTX Library Configuration
|
||||
*
|
||||
* -----------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
#include "cmsis_compiler.h"
|
||||
#include "RTX_Config.h"
|
||||
#include "rtx_os.h"
|
||||
|
||||
#ifdef RTE_Compiler_EventRecorder
|
||||
#include "EventRecorder.h"
|
||||
#include "EventRecorderConf.h"
|
||||
#endif
|
||||
#include "rtx_evr.h"
|
||||
|
||||
|
||||
// System Configuration
|
||||
// ====================
|
||||
|
||||
// Dynamic Memory
|
||||
#if (OS_DYNAMIC_MEM_SIZE != 0)
|
||||
#if ((OS_DYNAMIC_MEM_SIZE % 8) != 0)
|
||||
#error "Invalid Dynamic Memory size!"
|
||||
#endif
|
||||
static uint64_t os_mem[OS_DYNAMIC_MEM_SIZE/8] \
|
||||
__attribute__((section(".bss.os")));
|
||||
#endif
|
||||
|
||||
// Kernel Tick Frequency
|
||||
#if (OS_TICK_FREQ < 1)
|
||||
#error "Invalid Kernel Tick Frequency!"
|
||||
#endif
|
||||
|
||||
// ISR FIFO Queue
|
||||
#if (OS_ISR_FIFO_QUEUE < 4)
|
||||
#error "Invalid ISR FIFO Queue size!"
|
||||
#endif
|
||||
static void *os_isr_queue[OS_ISR_FIFO_QUEUE] \
|
||||
__attribute__((section(".bss.os")));
|
||||
|
||||
|
||||
// Thread Configuration
|
||||
// ====================
|
||||
|
||||
#if (((OS_STACK_SIZE % 8) != 0) || (OS_STACK_SIZE < 72))
|
||||
#error "Invalid default Thread Stack size!"
|
||||
#endif
|
||||
|
||||
#if (((OS_IDLE_THREAD_STACK_SIZE % 8) != 0) || (OS_IDLE_THREAD_STACK_SIZE < 72))
|
||||
#error "Invalid Idle Thread Stack size!"
|
||||
#endif
|
||||
|
||||
|
||||
#if (OS_THREAD_OBJ_MEM != 0)
|
||||
|
||||
#if (OS_THREAD_NUM == 0)
|
||||
#error "Invalid number of user Threads!"
|
||||
#endif
|
||||
|
||||
#if ((OS_THREAD_USER_STACK_SIZE != 0) && ((OS_THREAD_USER_STACK_SIZE % 8) != 0))
|
||||
#error "Invalid total Stack size!"
|
||||
#endif
|
||||
|
||||
// Thread Control Blocks
|
||||
static osRtxThread_t os_thread_cb[OS_THREAD_NUM] \
|
||||
__attribute__((section(".bss.os.thread.cb")));
|
||||
|
||||
// Thread Default Stack
|
||||
#if (OS_THREAD_DEF_STACK_NUM != 0)
|
||||
static uint64_t os_thread_def_stack[OS_THREAD_DEF_STACK_NUM*(OS_STACK_SIZE/8)] \
|
||||
__attribute__((section(".bss.os.thread.stack")));
|
||||
#endif
|
||||
|
||||
// Memory Pool for Thread Control Blocks
|
||||
static osRtxMpInfo_t os_mpi_thread \
|
||||
__attribute__((section(".data.os.thread.mpi"))) =
|
||||
{ (uint32_t)OS_THREAD_NUM, 0U, (uint32_t)osRtxThreadCbSize, &os_thread_cb[0], NULL, NULL };
|
||||
|
||||
// Memory Pool for Thread Default Stack
|
||||
#if (OS_THREAD_DEF_STACK_NUM != 0)
|
||||
static osRtxMpInfo_t os_mpi_def_stack \
|
||||
__attribute__((section(".data.os.thread.mpi"))) =
|
||||
{ (uint32_t)OS_THREAD_DEF_STACK_NUM, 0U, (uint32_t)OS_STACK_SIZE, &os_thread_def_stack[0], NULL, NULL };
|
||||
#endif
|
||||
|
||||
// Memory Pool for Thread Stack
|
||||
#if (OS_THREAD_USER_STACK_SIZE != 0)
|
||||
static uint64_t os_thread_stack[2 + OS_THREAD_NUM + (OS_THREAD_USER_STACK_SIZE/8)] \
|
||||
__attribute__((section(".bss.os.thread.stack")));
|
||||
#endif
|
||||
|
||||
#endif // (OS_THREAD_OBJ_MEM != 0)
|
||||
|
||||
|
||||
// Stack overrun checking
|
||||
#if (OS_STACK_CHECK == 0)
|
||||
// Override library function
|
||||
extern void osRtxThreadStackCheck (void);
|
||||
void osRtxThreadStackCheck (void) {}
|
||||
#endif
|
||||
|
||||
|
||||
// Idle Thread Control Block
|
||||
static osRtxThread_t os_idle_thread_cb \
|
||||
__attribute__((section(".bss.os.thread.cb")));
|
||||
|
||||
// Idle Thread Stack
|
||||
static uint64_t os_idle_thread_stack[OS_IDLE_THREAD_STACK_SIZE/8] \
|
||||
__attribute__((section(".bss.os.thread.stack")));
|
||||
|
||||
// Idle Thread Attributes
|
||||
static const osThreadAttr_t os_idle_thread_attr = {
|
||||
#if defined(OS_IDLE_THREAD_NAME)
|
||||
OS_IDLE_THREAD_NAME,
|
||||
#else
|
||||
NULL,
|
||||
#endif
|
||||
osThreadDetached,
|
||||
&os_idle_thread_cb,
|
||||
(uint32_t)sizeof(os_idle_thread_cb),
|
||||
&os_idle_thread_stack[0],
|
||||
(uint32_t)sizeof(os_idle_thread_stack),
|
||||
osPriorityIdle,
|
||||
#if defined(OS_IDLE_THREAD_TZ_MOD_ID)
|
||||
(uint32_t)OS_IDLE_THREAD_TZ_MOD_ID,
|
||||
#else
|
||||
0U,
|
||||
#endif
|
||||
0U
|
||||
};
|
||||
|
||||
|
||||
// Timer Configuration
|
||||
// ===================
|
||||
|
||||
#if (OS_TIMER_OBJ_MEM != 0)
|
||||
|
||||
#if (OS_TIMER_NUM == 0)
|
||||
#error "Invalid number of Timer objects!"
|
||||
#endif
|
||||
|
||||
// Timer Control Blocks
|
||||
static osRtxTimer_t os_timer_cb[OS_TIMER_NUM] \
|
||||
__attribute__((section(".bss.os.timer.cb")));
|
||||
|
||||
// Memory Pool for Timer Control Blocks
|
||||
static osRtxMpInfo_t os_mpi_timer \
|
||||
__attribute__((section(".data.os.timer.mpi"))) =
|
||||
{ (uint32_t)OS_TIMER_NUM, 0U, (uint32_t)osRtxTimerCbSize, &os_timer_cb[0], NULL, NULL };
|
||||
|
||||
#endif // (OS_TIMER_OBJ_MEM != 0)
|
||||
|
||||
|
||||
#if ((OS_TIMER_THREAD_STACK_SIZE != 0) && (OS_TIMER_CB_QUEUE != 0))
|
||||
|
||||
#if (((OS_TIMER_THREAD_STACK_SIZE % 8) != 0) || (OS_TIMER_THREAD_STACK_SIZE < 96))
|
||||
#error "Invalid Timer Thread Stack size!"
|
||||
#endif
|
||||
|
||||
// Timer Thread Control Block
|
||||
static osRtxThread_t os_timer_thread_cb \
|
||||
__attribute__((section(".bss.os.thread.cb")));
|
||||
|
||||
// Timer Thread Stack
|
||||
static uint64_t os_timer_thread_stack[OS_TIMER_THREAD_STACK_SIZE/8] \
|
||||
__attribute__((section(".bss.os.thread.stack")));
|
||||
|
||||
// Timer Thread Attributes
|
||||
static const osThreadAttr_t os_timer_thread_attr = {
|
||||
#if defined(OS_TIMER_THREAD_NAME)
|
||||
OS_TIMER_THREAD_NAME,
|
||||
#else
|
||||
NULL,
|
||||
#endif
|
||||
osThreadDetached,
|
||||
&os_timer_thread_cb,
|
||||
(uint32_t)sizeof(os_timer_thread_cb),
|
||||
&os_timer_thread_stack[0],
|
||||
(uint32_t)sizeof(os_timer_thread_stack),
|
||||
//lint -e{9030} -e{9034} "cast from signed to enum"
|
||||
(osPriority_t)OS_TIMER_THREAD_PRIO,
|
||||
#if defined(OS_TIMER_THREAD_TZ_MOD_ID)
|
||||
(uint32_t)OS_TIMER_THREAD_TZ_MOD_ID,
|
||||
#else
|
||||
0U,
|
||||
#endif
|
||||
0U
|
||||
};
|
||||
|
||||
// Timer Message Queue Control Block
|
||||
static osRtxMessageQueue_t os_timer_mq_cb \
|
||||
__attribute__((section(".bss.os.msgqueue.cb")));
|
||||
|
||||
// Timer Message Queue Data
|
||||
static uint32_t os_timer_mq_data[osRtxMessageQueueMemSize(OS_TIMER_CB_QUEUE,8)/4] \
|
||||
__attribute__((section(".bss.os.msgqueue.mem")));
|
||||
|
||||
// Timer Message Queue Attributes
|
||||
static const osMessageQueueAttr_t os_timer_mq_attr = {
|
||||
NULL,
|
||||
0U,
|
||||
&os_timer_mq_cb,
|
||||
(uint32_t)sizeof(os_timer_mq_cb),
|
||||
&os_timer_mq_data[0],
|
||||
(uint32_t)sizeof(os_timer_mq_data)
|
||||
};
|
||||
|
||||
#else
|
||||
|
||||
extern void osRtxTimerThread (void *argument);
|
||||
void osRtxTimerThread (void *argument) { (void)argument; }
|
||||
|
||||
#endif // ((OS_TIMER_THREAD_STACK_SIZE != 0) && (OS_TIMER_CB_QUEUE != 0))
|
||||
|
||||
|
||||
// Event Flags Configuration
|
||||
// =========================
|
||||
|
||||
#if (OS_EVFLAGS_OBJ_MEM != 0)
|
||||
|
||||
#if (OS_EVFLAGS_NUM == 0)
|
||||
#error "Invalid number of Event Flags objects!"
|
||||
#endif
|
||||
|
||||
// Event Flags Control Blocks
|
||||
static osRtxEventFlags_t os_ef_cb[OS_EVFLAGS_NUM] \
|
||||
__attribute__((section(".bss.os.evflags.cb")));
|
||||
|
||||
// Memory Pool for Event Flags Control Blocks
|
||||
static osRtxMpInfo_t os_mpi_ef \
|
||||
__attribute__((section(".data.os.evflags.mpi"))) =
|
||||
{ (uint32_t)OS_EVFLAGS_NUM, 0U, (uint32_t)osRtxEventFlagsCbSize, &os_ef_cb[0], NULL, NULL };
|
||||
|
||||
#endif // (OS_EVFLAGS_OBJ_MEM != 0)
|
||||
|
||||
|
||||
// Mutex Configuration
|
||||
// ===================
|
||||
|
||||
#if (OS_MUTEX_OBJ_MEM != 0)
|
||||
|
||||
#if (OS_MUTEX_NUM == 0)
|
||||
#error "Invalid number of Mutex objects!"
|
||||
#endif
|
||||
|
||||
// Mutex Control Blocks
|
||||
static osRtxMutex_t os_mutex_cb[OS_MUTEX_NUM] \
|
||||
__attribute__((section(".bss.os.mutex.cb")));
|
||||
|
||||
// Memory Pool for Mutex Control Blocks
|
||||
static osRtxMpInfo_t os_mpi_mutex \
|
||||
__attribute__((section(".data.os.mutex.mpi"))) =
|
||||
{ (uint32_t)OS_MUTEX_NUM, 0U, (uint32_t)osRtxMutexCbSize, &os_mutex_cb[0], NULL, NULL };
|
||||
|
||||
#endif // (OS_MUTEX_OBJ_MEM != 0)
|
||||
|
||||
|
||||
// Semaphore Configuration
|
||||
// =======================
|
||||
|
||||
#if (OS_SEMAPHORE_OBJ_MEM != 0)
|
||||
|
||||
#if (OS_SEMAPHORE_NUM == 0)
|
||||
#error "Invalid number of Semaphore objects!"
|
||||
#endif
|
||||
|
||||
// Semaphore Control Blocks
|
||||
static osRtxSemaphore_t os_semaphore_cb[OS_SEMAPHORE_NUM] \
|
||||
__attribute__((section(".bss.os.semaphore.cb")));
|
||||
|
||||
// Memory Pool for Semaphore Control Blocks
|
||||
static osRtxMpInfo_t os_mpi_semaphore \
|
||||
__attribute__((section(".data.os.semaphore.mpi"))) =
|
||||
{ (uint32_t)OS_SEMAPHORE_NUM, 0U, (uint32_t)osRtxSemaphoreCbSize, &os_semaphore_cb[0], NULL, NULL };
|
||||
|
||||
#endif // (OS_SEMAPHORE_OBJ_MEM != 0)
|
||||
|
||||
|
||||
// Memory Pool Configuration
|
||||
// =========================
|
||||
|
||||
#if (OS_MEMPOOL_OBJ_MEM != 0)
|
||||
|
||||
#if (OS_MEMPOOL_NUM == 0)
|
||||
#error "Invalid number of Memory Pool objects!"
|
||||
#endif
|
||||
|
||||
// Memory Pool Control Blocks
|
||||
static osRtxMemoryPool_t os_mp_cb[OS_MEMPOOL_NUM] \
|
||||
__attribute__((section(".bss.os.mempool.cb")));
|
||||
|
||||
// Memory Pool for Memory Pool Control Blocks
|
||||
static osRtxMpInfo_t os_mpi_mp \
|
||||
__attribute__((section(".data.os.mempool.mpi"))) =
|
||||
{ (uint32_t)OS_MEMPOOL_NUM, 0U, (uint32_t)osRtxMemoryPoolCbSize, &os_mp_cb[0], NULL, NULL };
|
||||
|
||||
// Memory Pool for Memory Pool Data Storage
|
||||
#if (OS_MEMPOOL_DATA_SIZE != 0)
|
||||
#if ((OS_MEMPOOL_DATA_SIZE % 8) != 0)
|
||||
#error "Invalid Data Memory size for Memory Pools!"
|
||||
#endif
|
||||
static uint64_t os_mp_data[2 + OS_MEMPOOL_NUM + (OS_MEMPOOL_DATA_SIZE/8)] \
|
||||
__attribute__((section(".bss.os.mempool.mem")));
|
||||
#endif
|
||||
|
||||
#endif // (OS_MEMPOOL_OBJ_MEM != 0)
|
||||
|
||||
|
||||
// Message Queue Configuration
|
||||
// ===========================
|
||||
|
||||
#if (OS_MSGQUEUE_OBJ_MEM != 0)
|
||||
|
||||
#if (OS_MSGQUEUE_NUM == 0)
|
||||
#error "Invalid number of Message Queue objects!"
|
||||
#endif
|
||||
|
||||
// Message Queue Control Blocks
|
||||
static osRtxMessageQueue_t os_mq_cb[OS_MSGQUEUE_NUM] \
|
||||
__attribute__((section(".bss.os.msgqueue.cb")));
|
||||
|
||||
// Memory Pool for Message Queue Control Blocks
|
||||
static osRtxMpInfo_t os_mpi_mq \
|
||||
__attribute__((section(".data.os.msgqueue.mpi"))) =
|
||||
{ (uint32_t)OS_MSGQUEUE_NUM, 0U, (uint32_t)osRtxMessageQueueCbSize, &os_mq_cb[0], NULL, NULL };
|
||||
|
||||
// Memory Pool for Message Queue Data Storage
|
||||
#if (OS_MSGQUEUE_DATA_SIZE != 0)
|
||||
#if ((OS_MSGQUEUE_DATA_SIZE % 8) != 0)
|
||||
#error "Invalid Data Memory size for Message Queues!"
|
||||
#endif
|
||||
static uint64_t os_mq_data[2 + OS_MSGQUEUE_NUM + (OS_MSGQUEUE_DATA_SIZE/8)] \
|
||||
__attribute__((section(".bss.os.msgqueue.mem")));
|
||||
#endif
|
||||
|
||||
#endif // (OS_MSGQUEUE_OBJ_MEM != 0)
|
||||
|
||||
|
||||
// Event Recorder Configuration
|
||||
// ============================
|
||||
|
||||
#if (defined(OS_EVR_INIT) && (OS_EVR_INIT != 0))
|
||||
|
||||
// Initial Thread configuration covered also Thread Flags and Generic Wait
|
||||
#if defined(OS_EVR_THREAD_FILTER)
|
||||
#if !defined(OS_EVR_THFLAGS_FILTER)
|
||||
#define OS_EVR_THFLAGS_FILTER OS_EVR_THREAD_FILTER
|
||||
#endif
|
||||
#if !defined(OS_EVR_WAIT_FILTER)
|
||||
#define OS_EVR_WAIT_FILTER OS_EVR_THREAD_FILTER
|
||||
#endif
|
||||
#endif
|
||||
|
||||
// Migrate initial filter configuration
|
||||
#if defined(OS_EVR_MEMORY_FILTER)
|
||||
#define OS_EVR_MEMORY_LEVEL (((OS_EVR_MEMORY_FILTER & 0x80U) != 0U) ? (OS_EVR_MEMORY_FILTER & 0x0FU) : 0U)
|
||||
#endif
|
||||
#if defined(OS_EVR_KERNEL_FILTER)
|
||||
#define OS_EVR_KERNEL_LEVEL (((OS_EVR_KERNEL_FILTER & 0x80U) != 0U) ? (OS_EVR_KERNEL_FILTER & 0x0FU) : 0U)
|
||||
#endif
|
||||
#if defined(OS_EVR_THREAD_FILTER)
|
||||
#define OS_EVR_THREAD_LEVEL (((OS_EVR_THREAD_FILTER & 0x80U) != 0U) ? (OS_EVR_THREAD_FILTER & 0x0FU) : 0U)
|
||||
#endif
|
||||
#if defined(OS_EVR_WAIT_FILTER)
|
||||
#define OS_EVR_WAIT_LEVEL (((OS_EVR_WAIT_FILTER & 0x80U) != 0U) ? (OS_EVR_WAIT_FILTER & 0x0FU) : 0U)
|
||||
#endif
|
||||
#if defined(OS_EVR_THFLAGS_FILTER)
|
||||
#define OS_EVR_THFLAGS_LEVEL (((OS_EVR_THFLAGS_FILTER & 0x80U) != 0U) ? (OS_EVR_THFLAGS_FILTER & 0x0FU) : 0U)
|
||||
#endif
|
||||
#if defined(OS_EVR_EVFLAGS_FILTER)
|
||||
#define OS_EVR_EVFLAGS_LEVEL (((OS_EVR_EVFLAGS_FILTER & 0x80U) != 0U) ? (OS_EVR_EVFLAGS_FILTER & 0x0FU) : 0U)
|
||||
#endif
|
||||
#if defined(OS_EVR_TIMER_FILTER)
|
||||
#define OS_EVR_TIMER_LEVEL (((OS_EVR_TIMER_FILTER & 0x80U) != 0U) ? (OS_EVR_TIMER_FILTER & 0x0FU) : 0U)
|
||||
#endif
|
||||
#if defined(OS_EVR_MUTEX_FILTER)
|
||||
#define OS_EVR_MUTEX_LEVEL (((OS_EVR_MUTEX_FILTER & 0x80U) != 0U) ? (OS_EVR_MUTEX_FILTER & 0x0FU) : 0U)
|
||||
#endif
|
||||
#if defined(OS_EVR_SEMAPHORE_FILTER)
|
||||
#define OS_EVR_SEMAPHORE_LEVEL (((OS_EVR_SEMAPHORE_FILTER & 0x80U) != 0U) ? (OS_EVR_SEMAPHORE_FILTER & 0x0FU) : 0U)
|
||||
#endif
|
||||
#if defined(OS_EVR_MEMPOOL_FILTER)
|
||||
#define OS_EVR_MEMPOOL_LEVEL (((OS_EVR_MEMPOOL_FILTER & 0x80U) != 0U) ? (OS_EVR_MEMPOOL_FILTER & 0x0FU) : 0U)
|
||||
#endif
|
||||
#if defined(OS_EVR_MSGQUEUE_FILTER)
|
||||
#define OS_EVR_MSGQUEUE_LEVEL (((OS_EVR_MSGQUEUE_FILTER & 0x80U) != 0U) ? (OS_EVR_MSGQUEUE_FILTER & 0x0FU) : 0U)
|
||||
#endif
|
||||
|
||||
#if defined(RTE_Compiler_EventRecorder)
|
||||
|
||||
// Event Recorder Initialize
|
||||
__STATIC_INLINE void evr_initialize (void) {
|
||||
|
||||
(void)EventRecorderInitialize(OS_EVR_LEVEL, (uint32_t)OS_EVR_START);
|
||||
|
||||
(void)EventRecorderEnable(OS_EVR_MEMORY_LEVEL, EvtRtxMemoryNo, EvtRtxMemoryNo);
|
||||
(void)EventRecorderEnable(OS_EVR_KERNEL_LEVEL, EvtRtxKernelNo, EvtRtxKernelNo);
|
||||
(void)EventRecorderEnable(OS_EVR_THREAD_LEVEL, EvtRtxThreadNo, EvtRtxThreadNo);
|
||||
(void)EventRecorderEnable(OS_EVR_WAIT_LEVEL, EvtRtxWaitNo, EvtRtxWaitNo);
|
||||
(void)EventRecorderEnable(OS_EVR_THFLAGS_LEVEL, EvtRtxThreadFlagsNo, EvtRtxThreadFlagsNo);
|
||||
(void)EventRecorderEnable(OS_EVR_EVFLAGS_LEVEL, EvtRtxEventFlagsNo, EvtRtxEventFlagsNo);
|
||||
(void)EventRecorderEnable(OS_EVR_TIMER_LEVEL, EvtRtxTimerNo, EvtRtxTimerNo);
|
||||
(void)EventRecorderEnable(OS_EVR_MUTEX_LEVEL, EvtRtxMutexNo, EvtRtxMutexNo);
|
||||
(void)EventRecorderEnable(OS_EVR_SEMAPHORE_LEVEL, EvtRtxSemaphoreNo, EvtRtxSemaphoreNo);
|
||||
(void)EventRecorderEnable(OS_EVR_MEMPOOL_LEVEL, EvtRtxMemoryPoolNo, EvtRtxMemoryPoolNo);
|
||||
(void)EventRecorderEnable(OS_EVR_MSGQUEUE_LEVEL, EvtRtxMessageQueueNo, EvtRtxMessageQueueNo);
|
||||
}
|
||||
|
||||
#else
|
||||
#warning "Event Recorder cannot be initialized (Event Recorder component is not selected)!"
|
||||
#define evr_initialize()
|
||||
#endif
|
||||
|
||||
#endif // (OS_EVR_INIT != 0)
|
||||
|
||||
|
||||
// OS Configuration
|
||||
// ================
|
||||
|
||||
|
||||
const osRtxConfig_t osRtxConfig \
|
||||
__USED \
|
||||
__attribute__((section(".rodata"))) =
|
||||
{
|
||||
//lint -e{835} "Zero argument to operator"
|
||||
0U // Flags
|
||||
#if (OS_PRIVILEGE_MODE != 0)
|
||||
| osRtxConfigPrivilegedMode
|
||||
#endif
|
||||
#if (OS_STACK_CHECK != 0)
|
||||
| osRtxConfigStackCheck
|
||||
#endif
|
||||
#if (OS_STACK_WATERMARK != 0)
|
||||
| osRtxConfigStackWatermark
|
||||
#endif
|
||||
,
|
||||
(uint32_t)OS_TICK_FREQ,
|
||||
#if (OS_ROBIN_ENABLE != 0)
|
||||
(uint32_t)OS_ROBIN_TIMEOUT,
|
||||
#else
|
||||
0U,
|
||||
#endif
|
||||
{ &os_isr_queue[0], (uint16_t)(sizeof(os_isr_queue)/sizeof(void *)), 0U },
|
||||
{
|
||||
// Memory Pools (Variable Block Size)
|
||||
#if ((OS_THREAD_OBJ_MEM != 0) && (OS_THREAD_USER_STACK_SIZE != 0))
|
||||
&os_thread_stack[0], sizeof(os_thread_stack),
|
||||
#else
|
||||
NULL, 0U,
|
||||
#endif
|
||||
#if ((OS_MEMPOOL_OBJ_MEM != 0) && (OS_MEMPOOL_DATA_SIZE != 0))
|
||||
&os_mp_data[0], sizeof(os_mp_data),
|
||||
#else
|
||||
NULL, 0U,
|
||||
#endif
|
||||
#if ((OS_MSGQUEUE_OBJ_MEM != 0) && (OS_MSGQUEUE_DATA_SIZE != 0))
|
||||
&os_mq_data[0], sizeof(os_mq_data),
|
||||
#else
|
||||
NULL, 0U,
|
||||
#endif
|
||||
#if (OS_DYNAMIC_MEM_SIZE != 0)
|
||||
&os_mem[0], (uint32_t)OS_DYNAMIC_MEM_SIZE,
|
||||
#else
|
||||
NULL, 0U
|
||||
#endif
|
||||
},
|
||||
{
|
||||
// Memory Pools (Fixed Block Size)
|
||||
#if (OS_THREAD_OBJ_MEM != 0)
|
||||
#if (OS_THREAD_DEF_STACK_NUM != 0)
|
||||
&os_mpi_def_stack,
|
||||
#else
|
||||
NULL,
|
||||
#endif
|
||||
&os_mpi_thread,
|
||||
#else
|
||||
NULL,
|
||||
NULL,
|
||||
#endif
|
||||
#if (OS_TIMER_OBJ_MEM != 0)
|
||||
&os_mpi_timer,
|
||||
#else
|
||||
NULL,
|
||||
#endif
|
||||
#if (OS_EVFLAGS_OBJ_MEM != 0)
|
||||
&os_mpi_ef,
|
||||
#else
|
||||
NULL,
|
||||
#endif
|
||||
#if (OS_MUTEX_OBJ_MEM != 0)
|
||||
&os_mpi_mutex,
|
||||
#else
|
||||
NULL,
|
||||
#endif
|
||||
#if (OS_SEMAPHORE_OBJ_MEM != 0)
|
||||
&os_mpi_semaphore,
|
||||
#else
|
||||
NULL,
|
||||
#endif
|
||||
#if (OS_MEMPOOL_OBJ_MEM != 0)
|
||||
&os_mpi_mp,
|
||||
#else
|
||||
NULL,
|
||||
#endif
|
||||
#if (OS_MSGQUEUE_OBJ_MEM != 0)
|
||||
&os_mpi_mq,
|
||||
#else
|
||||
NULL,
|
||||
#endif
|
||||
},
|
||||
(uint32_t)OS_STACK_SIZE,
|
||||
&os_idle_thread_attr,
|
||||
#if ((OS_TIMER_THREAD_STACK_SIZE != 0) && (OS_TIMER_CB_QUEUE != 0))
|
||||
&os_timer_thread_attr,
|
||||
&os_timer_mq_attr,
|
||||
(uint32_t)OS_TIMER_CB_QUEUE
|
||||
#else
|
||||
NULL,
|
||||
NULL,
|
||||
0U
|
||||
#endif
|
||||
};
|
||||
|
||||
|
||||
// Non weak reference to library irq module
|
||||
//lint -esym(526,irqRtxLib) "Defined by Exception handlers"
|
||||
//lint -esym(714,irqRtxLibRef) "Non weak reference"
|
||||
//lint -esym(765,irqRtxLibRef) "Global scope"
|
||||
extern uint8_t irqRtxLib;
|
||||
extern const uint8_t *irqRtxLibRef;
|
||||
const uint8_t *irqRtxLibRef = &irqRtxLib;
|
||||
|
||||
// Default User SVC Table
|
||||
//lint -esym(714,osRtxUserSVC) "Referenced by Exception handlers"
|
||||
//lint -esym(765,osRtxUserSVC) "Global scope"
|
||||
//lint -e{9067} "extern array declared without size"
|
||||
extern void * const osRtxUserSVC[];
|
||||
__WEAK void * const osRtxUserSVC[1] = { (void *)0 };
|
||||
|
||||
|
||||
// OS Sections
|
||||
// ===========
|
||||
|
||||
#if defined(__CC_ARM) || \
|
||||
(defined(__ARMCC_VERSION) && (__ARMCC_VERSION >= 6010050))
|
||||
static uint32_t __os_thread_cb_start__ __attribute__((weakref(".bss.os.thread.cb$$Base"))); //lint -esym(728,__os_thread_cb_start__)
|
||||
static uint32_t __os_thread_cb_end__ __attribute__((weakref(".bss.os.thread.cb$$Limit"))); //lint -esym(728,__os_thread_cb_end__)
|
||||
static uint32_t __os_timer_cb_start__ __attribute__((weakref(".bss.os.timer.cb$$Base"))); //lint -esym(728,__os_timer_cb_start__)
|
||||
static uint32_t __os_timer_cb_end__ __attribute__((weakref(".bss.os.timer.cb$$Limit"))); //lint -esym(728,__os_timer_cb_end__)
|
||||
static uint32_t __os_evflags_cb_start__ __attribute__((weakref(".bss.os.evflags.cb$$Base"))); //lint -esym(728,__os_evflags_cb_start__)
|
||||
static uint32_t __os_evflags_cb_end__ __attribute__((weakref(".bss.os.evflags.cb$$Limit"))); //lint -esym(728,__os_evflags_cb_end__)
|
||||
static uint32_t __os_mutex_cb_start__ __attribute__((weakref(".bss.os.mutex.cb$$Base"))); //lint -esym(728,__os_mutex_cb_start__)
|
||||
static uint32_t __os_mutex_cb_end__ __attribute__((weakref(".bss.os.mutex.cb$$Limit"))); //lint -esym(728,__os_mutex_cb_end__)
|
||||
static uint32_t __os_semaphore_cb_start__ __attribute__((weakref(".bss.os.semaphore.cb$$Base"))); //lint -esym(728,__os_semaphore_cb_start__)
|
||||
static uint32_t __os_semaphore_cb_end__ __attribute__((weakref(".bss.os.semaphore.cb$$Limit"))); //lint -esym(728,__os_semaphore_cb_end__)
|
||||
static uint32_t __os_mempool_cb_start__ __attribute__((weakref(".bss.os.mempool.cb$$Base"))); //lint -esym(728,__os_mempool_cb_start__)
|
||||
static uint32_t __os_mempool_cb_end__ __attribute__((weakref(".bss.os.mempool.cb$$Limit"))); //lint -esym(728,__os_mempool_cb_end__)
|
||||
static uint32_t __os_msgqueue_cb_start__ __attribute__((weakref(".bss.os.msgqueue.cb$$Base"))); //lint -esym(728,__os_msgqueue_cb_start__)
|
||||
static uint32_t __os_msgqueue_cb_end__ __attribute__((weakref(".bss.os.msgqueue.cb$$Limit"))); //lint -esym(728,__os_msgqueue_cb_end__)
|
||||
#else
|
||||
extern uint32_t __os_thread_cb_start__ __attribute__((weak));
|
||||
extern uint32_t __os_thread_cb_end__ __attribute__((weak));
|
||||
extern uint32_t __os_timer_cb_start__ __attribute__((weak));
|
||||
extern uint32_t __os_timer_cb_end__ __attribute__((weak));
|
||||
extern uint32_t __os_evflags_cb_start__ __attribute__((weak));
|
||||
extern uint32_t __os_evflags_cb_end__ __attribute__((weak));
|
||||
extern uint32_t __os_mutex_cb_start__ __attribute__((weak));
|
||||
extern uint32_t __os_mutex_cb_end__ __attribute__((weak));
|
||||
extern uint32_t __os_semaphore_cb_start__ __attribute__((weak));
|
||||
extern uint32_t __os_semaphore_cb_end__ __attribute__((weak));
|
||||
extern uint32_t __os_mempool_cb_start__ __attribute__((weak));
|
||||
extern uint32_t __os_mempool_cb_end__ __attribute__((weak));
|
||||
extern uint32_t __os_msgqueue_cb_start__ __attribute__((weak));
|
||||
extern uint32_t __os_msgqueue_cb_end__ __attribute__((weak));
|
||||
#endif
|
||||
|
||||
//lint -e{9067} "extern array declared without size"
|
||||
extern const uint32_t * const os_cb_sections[];
|
||||
|
||||
//lint -esym(714,os_cb_sections) "Referenced by debugger"
|
||||
//lint -esym(765,os_cb_sections) "Global scope"
|
||||
const uint32_t * const os_cb_sections[] \
|
||||
__USED \
|
||||
__attribute__((section(".rodata"))) =
|
||||
{
|
||||
&__os_thread_cb_start__,
|
||||
&__os_thread_cb_end__,
|
||||
&__os_timer_cb_start__,
|
||||
&__os_timer_cb_end__,
|
||||
&__os_evflags_cb_start__,
|
||||
&__os_evflags_cb_end__,
|
||||
&__os_mutex_cb_start__,
|
||||
&__os_mutex_cb_end__,
|
||||
&__os_semaphore_cb_start__,
|
||||
&__os_semaphore_cb_end__,
|
||||
&__os_mempool_cb_start__,
|
||||
&__os_mempool_cb_end__,
|
||||
&__os_msgqueue_cb_start__,
|
||||
&__os_msgqueue_cb_end__
|
||||
};
|
||||
|
||||
|
||||
// OS Initialization
|
||||
// =================
|
||||
|
||||
#if defined(__CC_ARM) || \
|
||||
(defined(__ARMCC_VERSION) && (__ARMCC_VERSION >= 6010050))
|
||||
|
||||
#ifndef __MICROLIB
|
||||
//lint -esym(714,_platform_post_stackheap_init) "Referenced by C library"
|
||||
//lint -esym(765,_platform_post_stackheap_init) "Global scope"
|
||||
extern void _platform_post_stackheap_init (void);
|
||||
__WEAK void _platform_post_stackheap_init (void) {
|
||||
(void)osKernelInitialize();
|
||||
}
|
||||
#endif
|
||||
|
||||
#elif defined(__GNUC__)
|
||||
|
||||
extern void software_init_hook (void);
|
||||
__WEAK void software_init_hook (void) {
|
||||
(void)osKernelInitialize();
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
// OS Hooks
|
||||
// ========
|
||||
|
||||
// RTOS Kernel Pre-Initialization Hook
|
||||
#if (defined(OS_EVR_INIT) && (OS_EVR_INIT != 0))
|
||||
void osRtxKernelPreInit (void);
|
||||
void osRtxKernelPreInit (void) {
|
||||
if (osKernelGetState() == osKernelInactive) {
|
||||
evr_initialize();
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
// C/C++ Standard Library Multithreading Interface
|
||||
// ===============================================
|
||||
|
||||
#if ( !defined(RTX_NO_MULTITHREAD_CLIB) && \
|
||||
( defined(__CC_ARM) || \
|
||||
(defined(__ARMCC_VERSION) && (__ARMCC_VERSION >= 6010050))) && \
|
||||
!defined(__MICROLIB))
|
||||
|
||||
#define LIBSPACE_SIZE 96
|
||||
|
||||
//lint -esym(714,__user_perthread_libspace,_mutex_*) "Referenced by C library"
|
||||
//lint -esym(765,__user_perthread_libspace,_mutex_*) "Global scope"
|
||||
//lint -esym(9003, os_libspace*) "variables 'os_libspace*' defined at module scope"
|
||||
|
||||
// Memory for libspace
|
||||
static uint32_t os_libspace[OS_THREAD_LIBSPACE_NUM+1][LIBSPACE_SIZE/4] \
|
||||
__attribute__((section(".bss.os.libspace")));
|
||||
|
||||
// Thread IDs for libspace
|
||||
static osThreadId_t os_libspace_id[OS_THREAD_LIBSPACE_NUM] \
|
||||
__attribute__((section(".bss.os.libspace")));
|
||||
|
||||
// Check if Kernel has been started
|
||||
static uint32_t os_kernel_is_active (void) {
|
||||
static uint8_t os_kernel_active = 0U;
|
||||
|
||||
if (os_kernel_active == 0U) {
|
||||
if (osKernelGetState() > osKernelReady) {
|
||||
os_kernel_active = 1U;
|
||||
}
|
||||
}
|
||||
return (uint32_t)os_kernel_active;
|
||||
}
|
||||
|
||||
// Provide libspace for current thread
|
||||
void *__user_perthread_libspace (void);
|
||||
void *__user_perthread_libspace (void) {
|
||||
osThreadId_t id;
|
||||
uint32_t n;
|
||||
|
||||
if (os_kernel_is_active() != 0U) {
|
||||
id = osThreadGetId();
|
||||
for (n = 0U; n < (uint32_t)OS_THREAD_LIBSPACE_NUM; n++) {
|
||||
if (os_libspace_id[n] == NULL) {
|
||||
os_libspace_id[n] = id;
|
||||
}
|
||||
if (os_libspace_id[n] == id) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (n == (uint32_t)OS_THREAD_LIBSPACE_NUM) {
|
||||
(void)osRtxErrorNotify(osRtxErrorClibSpace, id);
|
||||
}
|
||||
} else {
|
||||
n = OS_THREAD_LIBSPACE_NUM;
|
||||
}
|
||||
|
||||
//lint -e{9087} "cast between pointers to different object types"
|
||||
return (void *)&os_libspace[n][0];
|
||||
}
|
||||
|
||||
// Mutex identifier
|
||||
typedef void *mutex;
|
||||
|
||||
//lint -save "Function prototypes defined in C library"
|
||||
//lint -e970 "Use of 'int' outside of a typedef"
|
||||
//lint -e818 "Pointer 'm' could be declared as pointing to const"
|
||||
|
||||
// Initialize mutex
|
||||
__USED
|
||||
int _mutex_initialize(mutex *m);
|
||||
int _mutex_initialize(mutex *m) {
|
||||
int result;
|
||||
|
||||
*m = osMutexNew(NULL);
|
||||
if (*m != NULL) {
|
||||
result = 1;
|
||||
} else {
|
||||
result = 0;
|
||||
(void)osRtxErrorNotify(osRtxErrorClibMutex, m);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
// Acquire mutex
|
||||
__USED
|
||||
void _mutex_acquire(mutex *m);
|
||||
void _mutex_acquire(mutex *m) {
|
||||
if (os_kernel_is_active() != 0U) {
|
||||
(void)osMutexAcquire(*m, osWaitForever);
|
||||
}
|
||||
}
|
||||
|
||||
// Release mutex
|
||||
__USED
|
||||
void _mutex_release(mutex *m);
|
||||
void _mutex_release(mutex *m) {
|
||||
if (os_kernel_is_active() != 0U) {
|
||||
(void)osMutexRelease(*m);
|
||||
}
|
||||
}
|
||||
|
||||
// Free mutex
|
||||
__USED
|
||||
void _mutex_free(mutex *m);
|
||||
void _mutex_free(mutex *m) {
|
||||
(void)osMutexDelete(*m);
|
||||
}
|
||||
|
||||
//lint -restore
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,218 @@
|
||||
/*
|
||||
* Copyright (c) 2013-2020 Arm Limited. All rights reserved.
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the License); you may
|
||||
* not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an AS IS BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
* -----------------------------------------------------------------------------
|
||||
*
|
||||
* Project: CMSIS-RTOS RTX
|
||||
* Title: RTX Library definitions
|
||||
*
|
||||
* -----------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
#ifndef RTX_LIB_H_
|
||||
#define RTX_LIB_H_
|
||||
|
||||
#include <string.h>
|
||||
#include "rtx_core_c.h" // Cortex core definitions
|
||||
#if ((defined(__ARM_ARCH_8M_BASE__) && (__ARM_ARCH_8M_BASE__ != 0)) || \
|
||||
(defined(__ARM_ARCH_8M_MAIN__) && (__ARM_ARCH_8M_MAIN__ != 0)) || \
|
||||
(defined(__ARM_ARCH_8_1M_MAIN__) && (__ARM_ARCH_8_1M_MAIN__ != 0)))
|
||||
#include "tz_context.h" // TrustZone Context API
|
||||
#endif
|
||||
#include "os_tick.h" // CMSIS OS Tick API
|
||||
#include "cmsis_os2.h" // CMSIS RTOS API
|
||||
#include "RTX_Config.h" // RTX Configuration
|
||||
#include "rtx_os.h" // RTX OS definitions
|
||||
#include "rtx_evr.h" // RTX Event Recorder definitions
|
||||
|
||||
|
||||
// ==== Library defines ====
|
||||
|
||||
#define os_thread_t osRtxThread_t
|
||||
#define os_timer_t osRtxTimer_t
|
||||
#define os_timer_finfo_t osRtxTimerFinfo_t
|
||||
#define os_event_flags_t osRtxEventFlags_t
|
||||
#define os_mutex_t osRtxMutex_t
|
||||
#define os_semaphore_t osRtxSemaphore_t
|
||||
#define os_mp_info_t osRtxMpInfo_t
|
||||
#define os_memory_pool_t osRtxMemoryPool_t
|
||||
#define os_message_t osRtxMessage_t
|
||||
#define os_message_queue_t osRtxMessageQueue_t
|
||||
#define os_object_t osRtxObject_t
|
||||
|
||||
// ==== Inline functions ====
|
||||
|
||||
// Thread ID
|
||||
__STATIC_INLINE os_thread_t *osRtxThreadId (osThreadId_t thread_id) {
|
||||
//lint -e{9079} -e{9087} "cast from pointer to void to pointer to object type" [MISRA Note 2]
|
||||
return ((os_thread_t *)thread_id);
|
||||
}
|
||||
// Timer ID
|
||||
__STATIC_INLINE os_timer_t *osRtxTimerId (osTimerId_t timer_id) {
|
||||
//lint -e{9079} -e{9087} "cast from pointer to void to pointer to object type" [MISRA Note 2]
|
||||
return ((os_timer_t *)timer_id);
|
||||
}
|
||||
// Event Flags ID
|
||||
__STATIC_INLINE os_event_flags_t *osRtxEventFlagsId (osEventFlagsId_t ef_id) {
|
||||
//lint -e{9079} -e{9087} "cast from pointer to void to pointer to object type" [MISRA Note 2]
|
||||
return ((os_event_flags_t *)ef_id);
|
||||
}
|
||||
// Mutex ID
|
||||
__STATIC_INLINE os_mutex_t *osRtxMutexId (osMutexId_t mutex_id) {
|
||||
//lint -e{9079} -e{9087} "cast from pointer to void to pointer to object type" [MISRA Note 2]
|
||||
return ((os_mutex_t *)mutex_id);
|
||||
}
|
||||
// Semaphore ID
|
||||
__STATIC_INLINE os_semaphore_t *osRtxSemaphoreId (osSemaphoreId_t semaphore_id) {
|
||||
//lint -e{9079} -e{9087} "cast from pointer to void to pointer to object type" [MISRA Note 2]
|
||||
return ((os_semaphore_t *)semaphore_id);
|
||||
}
|
||||
// Memory Pool ID
|
||||
__STATIC_INLINE os_memory_pool_t *osRtxMemoryPoolId (osMemoryPoolId_t mp_id) {
|
||||
//lint -e{9079} -e{9087} "cast from pointer to void to pointer to object type" [MISRA Note 2]
|
||||
return ((os_memory_pool_t *)mp_id);
|
||||
}
|
||||
// Message Queue ID
|
||||
__STATIC_INLINE os_message_queue_t *osRtxMessageQueueId (osMessageQueueId_t mq_id) {
|
||||
//lint -e{9079} -e{9087} "cast from pointer to void to pointer to object type" [MISRA Note 2]
|
||||
return ((os_message_queue_t *)mq_id);
|
||||
}
|
||||
|
||||
// Generic Object
|
||||
__STATIC_INLINE os_object_t *osRtxObject (void *object) {
|
||||
//lint -e{9079} -e{9087} "cast from pointer to void to pointer to object type" [MISRA Note 3]
|
||||
return ((os_object_t *)object);
|
||||
}
|
||||
|
||||
// Thread Object
|
||||
__STATIC_INLINE os_thread_t *osRtxThreadObject (os_object_t *object) {
|
||||
//lint -e{740} -e{826} -e{9087} "cast from pointer to generic object to specific object" [MISRA Note 4]
|
||||
return ((os_thread_t *)object);
|
||||
}
|
||||
// Timer Object
|
||||
__STATIC_INLINE os_timer_t *osRtxTimerObject (os_object_t *object) {
|
||||
//lint -e{740} -e{826} -e{9087} "cast from pointer to generic object to specific object" [MISRA Note 4]
|
||||
return ((os_timer_t *)object);
|
||||
}
|
||||
// Event Flags Object
|
||||
__STATIC_INLINE os_event_flags_t *osRtxEventFlagsObject (os_object_t *object) {
|
||||
//lint -e{740} -e{826} -e{9087} "cast from pointer to generic object to specific object" [MISRA Note 4]
|
||||
return ((os_event_flags_t *)object);
|
||||
}
|
||||
// Mutex Object
|
||||
__STATIC_INLINE os_mutex_t *osRtxMutexObject (os_object_t *object) {
|
||||
//lint -e{740} -e{826} -e{9087} "cast from pointer to generic object to specific object" [MISRA Note 4]
|
||||
return ((os_mutex_t *)object);
|
||||
}
|
||||
// Semaphore Object
|
||||
__STATIC_INLINE os_semaphore_t *osRtxSemaphoreObject (os_object_t *object) {
|
||||
//lint -e{740} -e{826} -e{9087} "cast from pointer to generic object to specific object" [MISRA Note 4]
|
||||
return ((os_semaphore_t *)object);
|
||||
}
|
||||
// Memory Pool Object
|
||||
__STATIC_INLINE os_memory_pool_t *osRtxMemoryPoolObject (os_object_t *object) {
|
||||
//lint -e{740} -e{826} -e{9087} "cast from pointer to generic object to specific object" [MISRA Note 4]
|
||||
return ((os_memory_pool_t *)object);
|
||||
}
|
||||
// Message Queue Object
|
||||
__STATIC_INLINE os_message_queue_t *osRtxMessageQueueObject (os_object_t *object) {
|
||||
//lint -e{740} -e{826} -e{9087} "cast from pointer to generic object to specific object" [MISRA Note 4]
|
||||
return ((os_message_queue_t *)object);
|
||||
}
|
||||
// Message Object
|
||||
__STATIC_INLINE os_message_t *osRtxMessageObject (os_object_t *object) {
|
||||
//lint -e{740} -e{826} -e{9087} "cast from pointer to generic object to specific object" [MISRA Note 4]
|
||||
return ((os_message_t *)object);
|
||||
}
|
||||
|
||||
// Kernel State
|
||||
__STATIC_INLINE osKernelState_t osRtxKernelState (void) {
|
||||
//lint -e{9030} -e{9034} "cast to enum"
|
||||
return ((osKernelState_t)(osRtxInfo.kernel.state));
|
||||
}
|
||||
|
||||
// Thread State
|
||||
__STATIC_INLINE osThreadState_t osRtxThreadState (const os_thread_t *thread) {
|
||||
uint8_t state = thread->state & osRtxThreadStateMask;
|
||||
//lint -e{9030} -e{9034} "cast to enum"
|
||||
return ((osThreadState_t)state);
|
||||
}
|
||||
|
||||
// Thread Priority
|
||||
__STATIC_INLINE osPriority_t osRtxThreadPriority (const os_thread_t *thread) {
|
||||
//lint -e{9030} -e{9034} "cast to enum"
|
||||
return ((osPriority_t)thread->priority);
|
||||
}
|
||||
|
||||
// Kernel Get State
|
||||
__STATIC_INLINE uint8_t osRtxKernelGetState (void) {
|
||||
return osRtxInfo.kernel.state;
|
||||
}
|
||||
|
||||
// Thread Get/Set Running
|
||||
__STATIC_INLINE os_thread_t *osRtxThreadGetRunning (void) {
|
||||
return osRtxInfo.thread.run.curr;
|
||||
}
|
||||
__STATIC_INLINE void osRtxThreadSetRunning (os_thread_t *thread) {
|
||||
osRtxInfo.thread.run.curr = thread;
|
||||
}
|
||||
|
||||
|
||||
// ==== Library functions ====
|
||||
|
||||
// Kernel Library functions
|
||||
extern void osRtxKernelPreInit (void);
|
||||
|
||||
// Thread Library functions
|
||||
extern void osRtxThreadListPut (os_object_t *object, os_thread_t *thread);
|
||||
extern os_thread_t *osRtxThreadListGet (os_object_t *object);
|
||||
extern void osRtxThreadListSort (os_thread_t *thread);
|
||||
extern void osRtxThreadListRemove (os_thread_t *thread);
|
||||
extern void osRtxThreadReadyPut (os_thread_t *thread);
|
||||
extern void osRtxThreadDelayTick (void);
|
||||
extern uint32_t *osRtxThreadRegPtr (const os_thread_t *thread);
|
||||
extern void osRtxThreadSwitch (os_thread_t *thread);
|
||||
extern void osRtxThreadDispatch (os_thread_t *thread);
|
||||
extern void osRtxThreadWaitExit (os_thread_t *thread, uint32_t ret_val, bool_t dispatch);
|
||||
extern bool_t osRtxThreadWaitEnter (uint8_t state, uint32_t timeout);
|
||||
extern void osRtxThreadStackCheck (void);
|
||||
extern bool_t osRtxThreadStartup (void);
|
||||
|
||||
// Timer Library functions
|
||||
extern void osRtxTimerThread (void *argument);
|
||||
|
||||
// Mutex Library functions
|
||||
extern void osRtxMutexOwnerRelease (os_mutex_t *mutex_list);
|
||||
extern void osRtxMutexOwnerRestore (const os_mutex_t *mutex, const os_thread_t *thread_wakeup);
|
||||
|
||||
// Memory Heap Library functions
|
||||
extern uint32_t osRtxMemoryInit (void *mem, uint32_t size);
|
||||
extern void *osRtxMemoryAlloc(void *mem, uint32_t size, uint32_t type);
|
||||
extern uint32_t osRtxMemoryFree (void *mem, void *block);
|
||||
|
||||
// Memory Pool Library functions
|
||||
extern uint32_t osRtxMemoryPoolInit (os_mp_info_t *mp_info, uint32_t block_count, uint32_t block_size, void *block_mem);
|
||||
extern void *osRtxMemoryPoolAlloc (os_mp_info_t *mp_info);
|
||||
extern osStatus_t osRtxMemoryPoolFree (os_mp_info_t *mp_info, void *block);
|
||||
|
||||
// System Library functions
|
||||
extern void osRtxTick_Handler (void);
|
||||
extern void osRtxPendSV_Handler (void);
|
||||
extern void osRtxPostProcess (os_object_t *object);
|
||||
|
||||
|
||||
#endif // RTX_LIB_H_
|
||||
@@ -0,0 +1,218 @@
|
||||
/*
|
||||
* Copyright (c) 2013-2018 Arm Limited. All rights reserved.
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the License); you may
|
||||
* not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an AS IS BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
* -----------------------------------------------------------------------------
|
||||
*
|
||||
* Project: CMSIS-RTOS RTX
|
||||
* Title: Memory functions
|
||||
*
|
||||
* -----------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
#include "rtx_lib.h"
|
||||
|
||||
|
||||
// Memory Pool Header structure
|
||||
typedef struct {
|
||||
uint32_t size; // Memory Pool size
|
||||
uint32_t used; // Used Memory
|
||||
} mem_head_t;
|
||||
|
||||
// Memory Block Header structure
|
||||
typedef struct mem_block_s {
|
||||
struct mem_block_s *next; // Next Memory Block in list
|
||||
uint32_t info; // Block Info or max used Memory (in last block)
|
||||
} mem_block_t;
|
||||
|
||||
// Memory Block Info: Length = <31:2>:'00', Type = <1:0>
|
||||
#define MB_INFO_LEN_MASK 0xFFFFFFFCU // Length mask
|
||||
#define MB_INFO_TYPE_MASK 0x00000003U // Type mask
|
||||
|
||||
// Memory Head Pointer
|
||||
__STATIC_INLINE mem_head_t *MemHeadPtr (void *mem) {
|
||||
//lint -e{9079} -e{9087} "conversion from pointer to void to pointer to other type" [MISRA Note 6]
|
||||
return ((mem_head_t *)mem);
|
||||
}
|
||||
|
||||
// Memory Block Pointer
|
||||
__STATIC_INLINE mem_block_t *MemBlockPtr (void *mem, uint32_t offset) {
|
||||
uint32_t addr;
|
||||
mem_block_t *ptr;
|
||||
|
||||
//lint --e{923} --e{9078} "cast between pointer and unsigned int" [MISRA Note 8]
|
||||
addr = (uint32_t)mem + offset;
|
||||
ptr = (mem_block_t *)addr;
|
||||
|
||||
return ptr;
|
||||
}
|
||||
|
||||
|
||||
// ==== Library functions ====
|
||||
|
||||
/// Initialize Memory Pool with variable block size.
|
||||
/// \param[in] mem pointer to memory pool.
|
||||
/// \param[in] size size of a memory pool in bytes.
|
||||
/// \return 1 - success, 0 - failure.
|
||||
__WEAK uint32_t osRtxMemoryInit (void *mem, uint32_t size) {
|
||||
mem_head_t *head;
|
||||
mem_block_t *ptr;
|
||||
|
||||
// Check parameters
|
||||
//lint -e{923} "cast from pointer to unsigned int" [MISRA Note 7]
|
||||
if ((mem == NULL) || (((uint32_t)mem & 7U) != 0U) || ((size & 7U) != 0U) ||
|
||||
(size < (sizeof(mem_head_t) + (2U*sizeof(mem_block_t))))) {
|
||||
EvrRtxMemoryInit(mem, size, 0U);
|
||||
//lint -e{904} "Return statement before end of function" [MISRA Note 1]
|
||||
return 0U;
|
||||
}
|
||||
|
||||
// Initialize memory pool header
|
||||
head = MemHeadPtr(mem);
|
||||
head->size = size;
|
||||
head->used = sizeof(mem_head_t) + sizeof(mem_block_t);
|
||||
|
||||
// Initialize first and last block header
|
||||
ptr = MemBlockPtr(mem, sizeof(mem_head_t));
|
||||
ptr->next = MemBlockPtr(mem, size - sizeof(mem_block_t));
|
||||
ptr->next->next = NULL;
|
||||
ptr->next->info = sizeof(mem_head_t) + sizeof(mem_block_t);
|
||||
ptr->info = 0U;
|
||||
|
||||
EvrRtxMemoryInit(mem, size, 1U);
|
||||
|
||||
return 1U;
|
||||
}
|
||||
|
||||
/// Allocate a memory block from a Memory Pool.
|
||||
/// \param[in] mem pointer to memory pool.
|
||||
/// \param[in] size size of a memory block in bytes.
|
||||
/// \param[in] type memory block type: 0 - generic, 1 - control block
|
||||
/// \return allocated memory block or NULL in case of no memory is available.
|
||||
__WEAK void *osRtxMemoryAlloc (void *mem, uint32_t size, uint32_t type) {
|
||||
mem_block_t *ptr;
|
||||
mem_block_t *p, *p_new;
|
||||
uint32_t block_size;
|
||||
uint32_t hole_size;
|
||||
|
||||
// Check parameters
|
||||
if ((mem == NULL) || (size == 0U) || ((type & ~MB_INFO_TYPE_MASK) != 0U)) {
|
||||
EvrRtxMemoryAlloc(mem, size, type, NULL);
|
||||
//lint -e{904} "Return statement before end of function" [MISRA Note 1]
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// Add block header to size
|
||||
block_size = size + sizeof(mem_block_t);
|
||||
// Make sure that block is 8-byte aligned
|
||||
block_size = (block_size + 7U) & ~((uint32_t)7U);
|
||||
|
||||
// Search for hole big enough
|
||||
p = MemBlockPtr(mem, sizeof(mem_head_t));
|
||||
for (;;) {
|
||||
//lint -e{923} -e{9078} "cast from pointer to unsigned int"
|
||||
hole_size = (uint32_t)p->next - (uint32_t)p;
|
||||
hole_size -= p->info & MB_INFO_LEN_MASK;
|
||||
if (hole_size >= block_size) {
|
||||
// Hole found
|
||||
break;
|
||||
}
|
||||
p = p->next;
|
||||
if (p->next == NULL) {
|
||||
// Failed (end of list)
|
||||
EvrRtxMemoryAlloc(mem, size, type, NULL);
|
||||
//lint -e{904} "Return statement before end of function" [MISRA Note 1]
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
// Update used memory
|
||||
(MemHeadPtr(mem))->used += block_size;
|
||||
|
||||
// Update max used memory
|
||||
p_new = MemBlockPtr(mem, (MemHeadPtr(mem))->size - sizeof(mem_block_t));
|
||||
if (p_new->info < (MemHeadPtr(mem))->used) {
|
||||
p_new->info = (MemHeadPtr(mem))->used;
|
||||
}
|
||||
|
||||
// Allocate block
|
||||
if (p->info == 0U) {
|
||||
// No block allocated, set info of first element
|
||||
p->info = block_size | type;
|
||||
ptr = MemBlockPtr(p, sizeof(mem_block_t));
|
||||
} else {
|
||||
// Insert new element into the list
|
||||
p_new = MemBlockPtr(p, p->info & MB_INFO_LEN_MASK);
|
||||
p_new->next = p->next;
|
||||
p_new->info = block_size | type;
|
||||
p->next = p_new;
|
||||
ptr = MemBlockPtr(p_new, sizeof(mem_block_t));
|
||||
}
|
||||
|
||||
EvrRtxMemoryAlloc(mem, size, type, ptr);
|
||||
|
||||
return ptr;
|
||||
}
|
||||
|
||||
/// Return an allocated memory block back to a Memory Pool.
|
||||
/// \param[in] mem pointer to memory pool.
|
||||
/// \param[in] block memory block to be returned to the memory pool.
|
||||
/// \return 1 - success, 0 - failure.
|
||||
__WEAK uint32_t osRtxMemoryFree (void *mem, void *block) {
|
||||
const mem_block_t *ptr;
|
||||
mem_block_t *p, *p_prev;
|
||||
|
||||
// Check parameters
|
||||
if ((mem == NULL) || (block == NULL)) {
|
||||
EvrRtxMemoryFree(mem, block, 0U);
|
||||
//lint -e{904} "Return statement before end of function" [MISRA Note 1]
|
||||
return 0U;
|
||||
}
|
||||
|
||||
// Memory block header
|
||||
ptr = MemBlockPtr(block, 0U);
|
||||
ptr--;
|
||||
|
||||
// Search for block header
|
||||
p_prev = NULL;
|
||||
p = MemBlockPtr(mem, sizeof(mem_head_t));
|
||||
while (p != ptr) {
|
||||
p_prev = p;
|
||||
p = p->next;
|
||||
if (p == NULL) {
|
||||
// Not found
|
||||
EvrRtxMemoryFree(mem, block, 0U);
|
||||
//lint -e{904} "Return statement before end of function" [MISRA Note 1]
|
||||
return 0U;
|
||||
}
|
||||
}
|
||||
|
||||
// Update used memory
|
||||
(MemHeadPtr(mem))->used -= p->info & MB_INFO_LEN_MASK;
|
||||
|
||||
// Free block
|
||||
if (p_prev == NULL) {
|
||||
// Release first block, only set info to 0
|
||||
p->info = 0U;
|
||||
} else {
|
||||
// Discard block from chained list
|
||||
p_prev->next = p->next;
|
||||
}
|
||||
|
||||
EvrRtxMemoryFree(mem, block, 1U);
|
||||
|
||||
return 1U;
|
||||
}
|
||||
@@ -0,0 +1,705 @@
|
||||
/*
|
||||
* Copyright (c) 2013-2018 Arm Limited. All rights reserved.
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the License); you may
|
||||
* not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an AS IS BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
* -----------------------------------------------------------------------------
|
||||
*
|
||||
* Project: CMSIS-RTOS RTX
|
||||
* Title: Memory Pool functions
|
||||
*
|
||||
* -----------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
#include "rtx_lib.h"
|
||||
|
||||
|
||||
// OS Runtime Object Memory Usage
|
||||
#if ((defined(OS_OBJ_MEM_USAGE) && (OS_OBJ_MEM_USAGE != 0)))
|
||||
osRtxObjectMemUsage_t osRtxMemoryPoolMemUsage \
|
||||
__attribute__((section(".data.os.mempool.obj"))) =
|
||||
{ 0U, 0U, 0U };
|
||||
#endif
|
||||
|
||||
|
||||
// ==== Library functions ====
|
||||
|
||||
/// Initialize Memory Pool.
|
||||
/// \param[in] mp_info memory pool info.
|
||||
/// \param[in] block_count maximum number of memory blocks in memory pool.
|
||||
/// \param[in] block_size size of a memory block in bytes.
|
||||
/// \param[in] block_mem pointer to memory for block storage.
|
||||
/// \return 1 - success, 0 - failure.
|
||||
uint32_t osRtxMemoryPoolInit (os_mp_info_t *mp_info, uint32_t block_count, uint32_t block_size, void *block_mem) {
|
||||
//lint --e{9079} --e{9087} "conversion from pointer to void to pointer to other type" [MISRA Note 6]
|
||||
void *mem;
|
||||
void *block;
|
||||
|
||||
// Check parameters
|
||||
if ((mp_info == NULL) || (block_count == 0U) || (block_size == 0U) || (block_mem == NULL)) {
|
||||
//lint -e{904} "Return statement before end of function" [MISRA Note 1]
|
||||
return 0U;
|
||||
}
|
||||
|
||||
// Initialize information structure
|
||||
mp_info->max_blocks = block_count;
|
||||
mp_info->used_blocks = 0U;
|
||||
mp_info->block_size = block_size;
|
||||
mp_info->block_base = block_mem;
|
||||
mp_info->block_free = block_mem;
|
||||
mp_info->block_lim = &(((uint8_t *)block_mem)[block_count * block_size]);
|
||||
|
||||
EvrRtxMemoryBlockInit(mp_info, block_count, block_size, block_mem);
|
||||
|
||||
// Link all free blocks
|
||||
mem = block_mem;
|
||||
while (--block_count != 0U) {
|
||||
block = &((uint8_t *)mem)[block_size];
|
||||
*((void **)mem) = block;
|
||||
mem = block;
|
||||
}
|
||||
*((void **)mem) = NULL;
|
||||
|
||||
return 1U;
|
||||
}
|
||||
|
||||
/// Allocate a memory block from a Memory Pool.
|
||||
/// \param[in] mp_info memory pool info.
|
||||
/// \return address of the allocated memory block or NULL in case of no memory is available.
|
||||
void *osRtxMemoryPoolAlloc (os_mp_info_t *mp_info) {
|
||||
#if (EXCLUSIVE_ACCESS == 0)
|
||||
uint32_t primask = __get_PRIMASK();
|
||||
#endif
|
||||
void *block;
|
||||
|
||||
if (mp_info == NULL) {
|
||||
EvrRtxMemoryBlockAlloc(NULL, NULL);
|
||||
//lint -e{904} "Return statement before end of function" [MISRA Note 1]
|
||||
return NULL;
|
||||
}
|
||||
|
||||
#if (EXCLUSIVE_ACCESS == 0)
|
||||
__disable_irq();
|
||||
|
||||
block = mp_info->block_free;
|
||||
if (block != NULL) {
|
||||
//lint --e{9079} --e{9087} "conversion from pointer to void to pointer to other type"
|
||||
mp_info->block_free = *((void **)block);
|
||||
mp_info->used_blocks++;
|
||||
}
|
||||
|
||||
if (primask == 0U) {
|
||||
__enable_irq();
|
||||
}
|
||||
#else
|
||||
block = atomic_link_get(&mp_info->block_free);
|
||||
if (block != NULL) {
|
||||
(void)atomic_inc32(&mp_info->used_blocks);
|
||||
}
|
||||
#endif
|
||||
|
||||
EvrRtxMemoryBlockAlloc(mp_info, block);
|
||||
|
||||
return block;
|
||||
}
|
||||
|
||||
/// Return an allocated memory block back to a Memory Pool.
|
||||
/// \param[in] mp_info memory pool info.
|
||||
/// \param[in] block address of the allocated memory block to be returned to the memory pool.
|
||||
/// \return status code that indicates the execution status of the function.
|
||||
osStatus_t osRtxMemoryPoolFree (os_mp_info_t *mp_info, void *block) {
|
||||
#if (EXCLUSIVE_ACCESS == 0)
|
||||
uint32_t primask = __get_PRIMASK();
|
||||
#endif
|
||||
|
||||
//lint -e{946} "Relational operator applied to pointers"
|
||||
if ((mp_info == NULL) || (block < mp_info->block_base) || (block >= mp_info->block_lim)) {
|
||||
EvrRtxMemoryBlockFree(mp_info, block, (int32_t)osErrorParameter);
|
||||
//lint -e{904} "Return statement before end of function" [MISRA Note 1]
|
||||
return osErrorParameter;
|
||||
}
|
||||
|
||||
#if (EXCLUSIVE_ACCESS == 0)
|
||||
__disable_irq();
|
||||
|
||||
//lint --e{9079} --e{9087} "conversion from pointer to void to pointer to other type"
|
||||
*((void **)block) = mp_info->block_free;
|
||||
mp_info->block_free = block;
|
||||
mp_info->used_blocks--;
|
||||
|
||||
if (primask == 0U) {
|
||||
__enable_irq();
|
||||
}
|
||||
#else
|
||||
atomic_link_put(&mp_info->block_free, block);
|
||||
(void)atomic_dec32(&mp_info->used_blocks);
|
||||
#endif
|
||||
|
||||
EvrRtxMemoryBlockFree(mp_info, block, (int32_t)osOK);
|
||||
|
||||
return osOK;
|
||||
}
|
||||
|
||||
|
||||
// ==== Post ISR processing ====
|
||||
|
||||
/// Memory Pool post ISR processing.
|
||||
/// \param[in] mp memory pool object.
|
||||
static void osRtxMemoryPoolPostProcess (os_memory_pool_t *mp) {
|
||||
void *block;
|
||||
os_thread_t *thread;
|
||||
|
||||
// Check if Thread is waiting to allocate memory
|
||||
if (mp->thread_list != NULL) {
|
||||
// Allocate memory
|
||||
block = osRtxMemoryPoolAlloc(&mp->mp_info);
|
||||
if (block != NULL) {
|
||||
// Wakeup waiting Thread with highest Priority
|
||||
thread = osRtxThreadListGet(osRtxObject(mp));
|
||||
//lint -e{923} "cast from pointer to unsigned int"
|
||||
osRtxThreadWaitExit(thread, (uint32_t)block, FALSE);
|
||||
EvrRtxMemoryPoolAllocated(mp, block);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// ==== Service Calls ====
|
||||
|
||||
/// Create and Initialize a Memory Pool object.
|
||||
/// \note API identical to osMemoryPoolNew
|
||||
static osMemoryPoolId_t svcRtxMemoryPoolNew (uint32_t block_count, uint32_t block_size, const osMemoryPoolAttr_t *attr) {
|
||||
os_memory_pool_t *mp;
|
||||
void *mp_mem;
|
||||
uint32_t mp_size;
|
||||
uint32_t b_count;
|
||||
uint32_t b_size;
|
||||
uint32_t size;
|
||||
uint8_t flags;
|
||||
const char *name;
|
||||
|
||||
// Check parameters
|
||||
if ((block_count == 0U) || (block_size == 0U)) {
|
||||
EvrRtxMemoryPoolError(NULL, (int32_t)osErrorParameter);
|
||||
//lint -e{904} "Return statement before end of function" [MISRA Note 1]
|
||||
return NULL;
|
||||
}
|
||||
b_count = block_count;
|
||||
b_size = (block_size + 3U) & ~3UL;
|
||||
if ((__CLZ(b_count) + __CLZ(b_size)) < 32U) {
|
||||
EvrRtxMemoryPoolError(NULL, (int32_t)osErrorParameter);
|
||||
//lint -e{904} "Return statement before end of function" [MISRA Note 1]
|
||||
return NULL;
|
||||
}
|
||||
|
||||
size = b_count * b_size;
|
||||
|
||||
// Process attributes
|
||||
if (attr != NULL) {
|
||||
name = attr->name;
|
||||
//lint -e{9079} "conversion from pointer to void to pointer to other type" [MISRA Note 6]
|
||||
mp = attr->cb_mem;
|
||||
//lint -e{9079} "conversion from pointer to void to pointer to other type" [MISRA Note 6]
|
||||
mp_mem = attr->mp_mem;
|
||||
mp_size = attr->mp_size;
|
||||
if (mp != NULL) {
|
||||
//lint -e(923) -e(9078) "cast from pointer to unsigned int" [MISRA Note 7]
|
||||
if ((((uint32_t)mp & 3U) != 0U) || (attr->cb_size < sizeof(os_memory_pool_t))) {
|
||||
EvrRtxMemoryPoolError(NULL, osRtxErrorInvalidControlBlock);
|
||||
//lint -e{904} "Return statement before end of function" [MISRA Note 1]
|
||||
return NULL;
|
||||
}
|
||||
} else {
|
||||
if (attr->cb_size != 0U) {
|
||||
EvrRtxMemoryPoolError(NULL, osRtxErrorInvalidControlBlock);
|
||||
//lint -e{904} "Return statement before end of function" [MISRA Note 1]
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
if (mp_mem != NULL) {
|
||||
//lint -e(923) -e(9078) "cast from pointer to unsigned int" [MISRA Note 7]
|
||||
if ((((uint32_t)mp_mem & 3U) != 0U) || (mp_size < size)) {
|
||||
EvrRtxMemoryPoolError(NULL, osRtxErrorInvalidDataMemory);
|
||||
//lint -e{904} "Return statement before end of function" [MISRA Note 1]
|
||||
return NULL;
|
||||
}
|
||||
} else {
|
||||
if (mp_size != 0U) {
|
||||
EvrRtxMemoryPoolError(NULL, osRtxErrorInvalidDataMemory);
|
||||
//lint -e{904} "Return statement before end of function" [MISRA Note 1]
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
name = NULL;
|
||||
mp = NULL;
|
||||
mp_mem = NULL;
|
||||
}
|
||||
|
||||
// Allocate object memory if not provided
|
||||
if (mp == NULL) {
|
||||
if (osRtxInfo.mpi.memory_pool != NULL) {
|
||||
//lint -e{9079} "conversion from pointer to void to pointer to other type" [MISRA Note 5]
|
||||
mp = osRtxMemoryPoolAlloc(osRtxInfo.mpi.memory_pool);
|
||||
} else {
|
||||
//lint -e{9079} "conversion from pointer to void to pointer to other type" [MISRA Note 5]
|
||||
mp = osRtxMemoryAlloc(osRtxInfo.mem.common, sizeof(os_memory_pool_t), 1U);
|
||||
}
|
||||
#if (defined(OS_OBJ_MEM_USAGE) && (OS_OBJ_MEM_USAGE != 0))
|
||||
if (mp != NULL) {
|
||||
uint32_t used;
|
||||
osRtxMemoryPoolMemUsage.cnt_alloc++;
|
||||
used = osRtxMemoryPoolMemUsage.cnt_alloc - osRtxMemoryPoolMemUsage.cnt_free;
|
||||
if (osRtxMemoryPoolMemUsage.max_used < used) {
|
||||
osRtxMemoryPoolMemUsage.max_used = used;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
flags = osRtxFlagSystemObject;
|
||||
} else {
|
||||
flags = 0U;
|
||||
}
|
||||
|
||||
// Allocate data memory if not provided
|
||||
if ((mp != NULL) && (mp_mem == NULL)) {
|
||||
//lint -e{9079} "conversion from pointer to void to pointer to other type" [MISRA Note 5]
|
||||
mp_mem = osRtxMemoryAlloc(osRtxInfo.mem.mp_data, size, 0U);
|
||||
if (mp_mem == NULL) {
|
||||
if ((flags & osRtxFlagSystemObject) != 0U) {
|
||||
if (osRtxInfo.mpi.memory_pool != NULL) {
|
||||
(void)osRtxMemoryPoolFree(osRtxInfo.mpi.memory_pool, mp);
|
||||
} else {
|
||||
(void)osRtxMemoryFree(osRtxInfo.mem.common, mp);
|
||||
}
|
||||
#if (defined(OS_OBJ_MEM_USAGE) && (OS_OBJ_MEM_USAGE != 0))
|
||||
osRtxMemoryPoolMemUsage.cnt_free++;
|
||||
#endif
|
||||
}
|
||||
mp = NULL;
|
||||
} else {
|
||||
memset(mp_mem, 0, size);
|
||||
}
|
||||
flags |= osRtxFlagSystemMemory;
|
||||
}
|
||||
|
||||
if (mp != NULL) {
|
||||
// Initialize control block
|
||||
mp->id = osRtxIdMemoryPool;
|
||||
mp->flags = flags;
|
||||
mp->name = name;
|
||||
mp->thread_list = NULL;
|
||||
(void)osRtxMemoryPoolInit(&mp->mp_info, b_count, b_size, mp_mem);
|
||||
|
||||
// Register post ISR processing function
|
||||
osRtxInfo.post_process.memory_pool = osRtxMemoryPoolPostProcess;
|
||||
|
||||
EvrRtxMemoryPoolCreated(mp, mp->name);
|
||||
} else {
|
||||
EvrRtxMemoryPoolError(NULL, (int32_t)osErrorNoMemory);
|
||||
}
|
||||
|
||||
return mp;
|
||||
}
|
||||
|
||||
/// Get name of a Memory Pool object.
|
||||
/// \note API identical to osMemoryPoolGetName
|
||||
static const char *svcRtxMemoryPoolGetName (osMemoryPoolId_t mp_id) {
|
||||
os_memory_pool_t *mp = osRtxMemoryPoolId(mp_id);
|
||||
|
||||
// Check parameters
|
||||
if ((mp == NULL) || (mp->id != osRtxIdMemoryPool)) {
|
||||
EvrRtxMemoryPoolGetName(mp, NULL);
|
||||
//lint -e{904} "Return statement before end of function" [MISRA Note 1]
|
||||
return NULL;
|
||||
}
|
||||
|
||||
EvrRtxMemoryPoolGetName(mp, mp->name);
|
||||
|
||||
return mp->name;
|
||||
}
|
||||
|
||||
/// Allocate a memory block from a Memory Pool.
|
||||
/// \note API identical to osMemoryPoolAlloc
|
||||
static void *svcRtxMemoryPoolAlloc (osMemoryPoolId_t mp_id, uint32_t timeout) {
|
||||
os_memory_pool_t *mp = osRtxMemoryPoolId(mp_id);
|
||||
void *block;
|
||||
|
||||
// Check parameters
|
||||
if ((mp == NULL) || (mp->id != osRtxIdMemoryPool)) {
|
||||
EvrRtxMemoryPoolError(mp, (int32_t)osErrorParameter);
|
||||
//lint -e{904} "Return statement before end of function" [MISRA Note 1]
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// Allocate memory
|
||||
block = osRtxMemoryPoolAlloc(&mp->mp_info);
|
||||
if (block != NULL) {
|
||||
EvrRtxMemoryPoolAllocated(mp, block);
|
||||
} else {
|
||||
// No memory available
|
||||
if (timeout != 0U) {
|
||||
EvrRtxMemoryPoolAllocPending(mp, timeout);
|
||||
// Suspend current Thread
|
||||
if (osRtxThreadWaitEnter(osRtxThreadWaitingMemoryPool, timeout)) {
|
||||
osRtxThreadListPut(osRtxObject(mp), osRtxThreadGetRunning());
|
||||
} else {
|
||||
EvrRtxMemoryPoolAllocTimeout(mp);
|
||||
}
|
||||
} else {
|
||||
EvrRtxMemoryPoolAllocFailed(mp);
|
||||
}
|
||||
}
|
||||
|
||||
return block;
|
||||
}
|
||||
|
||||
/// Return an allocated memory block back to a Memory Pool.
|
||||
/// \note API identical to osMemoryPoolFree
|
||||
static osStatus_t svcRtxMemoryPoolFree (osMemoryPoolId_t mp_id, void *block) {
|
||||
os_memory_pool_t *mp = osRtxMemoryPoolId(mp_id);
|
||||
void *block0;
|
||||
os_thread_t *thread;
|
||||
osStatus_t status;
|
||||
|
||||
// Check parameters
|
||||
if ((mp == NULL) || (mp->id != osRtxIdMemoryPool)) {
|
||||
EvrRtxMemoryPoolError(mp, (int32_t)osErrorParameter);
|
||||
//lint -e{904} "Return statement before end of function" [MISRA Note 1]
|
||||
return osErrorParameter;
|
||||
}
|
||||
|
||||
// Free memory
|
||||
status = osRtxMemoryPoolFree(&mp->mp_info, block);
|
||||
if (status == osOK) {
|
||||
EvrRtxMemoryPoolDeallocated(mp, block);
|
||||
// Check if Thread is waiting to allocate memory
|
||||
if (mp->thread_list != NULL) {
|
||||
// Allocate memory
|
||||
block0 = osRtxMemoryPoolAlloc(&mp->mp_info);
|
||||
if (block0 != NULL) {
|
||||
// Wakeup waiting Thread with highest Priority
|
||||
thread = osRtxThreadListGet(osRtxObject(mp));
|
||||
//lint -e{923} "cast from pointer to unsigned int"
|
||||
osRtxThreadWaitExit(thread, (uint32_t)block0, TRUE);
|
||||
EvrRtxMemoryPoolAllocated(mp, block0);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
EvrRtxMemoryPoolFreeFailed(mp, block);
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
/// Get maximum number of memory blocks in a Memory Pool.
|
||||
/// \note API identical to osMemoryPoolGetCapacity
|
||||
static uint32_t svcRtxMemoryPoolGetCapacity (osMemoryPoolId_t mp_id) {
|
||||
os_memory_pool_t *mp = osRtxMemoryPoolId(mp_id);
|
||||
|
||||
// Check parameters
|
||||
if ((mp == NULL) || (mp->id != osRtxIdMemoryPool)) {
|
||||
EvrRtxMemoryPoolGetCapacity(mp, 0U);
|
||||
//lint -e{904} "Return statement before end of function" [MISRA Note 1]
|
||||
return 0U;
|
||||
}
|
||||
|
||||
EvrRtxMemoryPoolGetCapacity(mp, mp->mp_info.max_blocks);
|
||||
|
||||
return mp->mp_info.max_blocks;
|
||||
}
|
||||
|
||||
/// Get memory block size in a Memory Pool.
|
||||
/// \note API identical to osMemoryPoolGetBlockSize
|
||||
static uint32_t svcRtxMemoryPoolGetBlockSize (osMemoryPoolId_t mp_id) {
|
||||
os_memory_pool_t *mp = osRtxMemoryPoolId(mp_id);
|
||||
|
||||
// Check parameters
|
||||
if ((mp == NULL) || (mp->id != osRtxIdMemoryPool)) {
|
||||
EvrRtxMemoryPoolGetBlockSize(mp, 0U);
|
||||
//lint -e{904} "Return statement before end of function" [MISRA Note 1]
|
||||
return 0U;
|
||||
}
|
||||
|
||||
EvrRtxMemoryPoolGetBlockSize(mp, mp->mp_info.block_size);
|
||||
|
||||
return mp->mp_info.block_size;
|
||||
}
|
||||
|
||||
/// Get number of memory blocks used in a Memory Pool.
|
||||
/// \note API identical to osMemoryPoolGetCount
|
||||
static uint32_t svcRtxMemoryPoolGetCount (osMemoryPoolId_t mp_id) {
|
||||
os_memory_pool_t *mp = osRtxMemoryPoolId(mp_id);
|
||||
|
||||
// Check parameters
|
||||
if ((mp == NULL) || (mp->id != osRtxIdMemoryPool)) {
|
||||
EvrRtxMemoryPoolGetCount(mp, 0U);
|
||||
//lint -e{904} "Return statement before end of function" [MISRA Note 1]
|
||||
return 0U;
|
||||
}
|
||||
|
||||
EvrRtxMemoryPoolGetCount(mp, mp->mp_info.used_blocks);
|
||||
|
||||
return mp->mp_info.used_blocks;
|
||||
}
|
||||
|
||||
/// Get number of memory blocks available in a Memory Pool.
|
||||
/// \note API identical to osMemoryPoolGetSpace
|
||||
static uint32_t svcRtxMemoryPoolGetSpace (osMemoryPoolId_t mp_id) {
|
||||
os_memory_pool_t *mp = osRtxMemoryPoolId(mp_id);
|
||||
|
||||
// Check parameters
|
||||
if ((mp == NULL) || (mp->id != osRtxIdMemoryPool)) {
|
||||
EvrRtxMemoryPoolGetSpace(mp, 0U);
|
||||
//lint -e{904} "Return statement before end of function" [MISRA Note 1]
|
||||
return 0U;
|
||||
}
|
||||
|
||||
EvrRtxMemoryPoolGetSpace(mp, mp->mp_info.max_blocks - mp->mp_info.used_blocks);
|
||||
|
||||
return (mp->mp_info.max_blocks - mp->mp_info.used_blocks);
|
||||
}
|
||||
|
||||
/// Delete a Memory Pool object.
|
||||
/// \note API identical to osMemoryPoolDelete
|
||||
static osStatus_t svcRtxMemoryPoolDelete (osMemoryPoolId_t mp_id) {
|
||||
os_memory_pool_t *mp = osRtxMemoryPoolId(mp_id);
|
||||
os_thread_t *thread;
|
||||
|
||||
// Check parameters
|
||||
if ((mp == NULL) || (mp->id != osRtxIdMemoryPool)) {
|
||||
EvrRtxMemoryPoolError(mp, (int32_t)osErrorParameter);
|
||||
//lint -e{904} "Return statement before end of function" [MISRA Note 1]
|
||||
return osErrorParameter;
|
||||
}
|
||||
|
||||
// Unblock waiting threads
|
||||
if (mp->thread_list != NULL) {
|
||||
do {
|
||||
thread = osRtxThreadListGet(osRtxObject(mp));
|
||||
osRtxThreadWaitExit(thread, 0U, FALSE);
|
||||
} while (mp->thread_list != NULL);
|
||||
osRtxThreadDispatch(NULL);
|
||||
}
|
||||
|
||||
// Mark object as invalid
|
||||
mp->id = osRtxIdInvalid;
|
||||
|
||||
// Free data memory
|
||||
if ((mp->flags & osRtxFlagSystemMemory) != 0U) {
|
||||
(void)osRtxMemoryFree(osRtxInfo.mem.mp_data, mp->mp_info.block_base);
|
||||
}
|
||||
|
||||
// Free object memory
|
||||
if ((mp->flags & osRtxFlagSystemObject) != 0U) {
|
||||
if (osRtxInfo.mpi.memory_pool != NULL) {
|
||||
(void)osRtxMemoryPoolFree(osRtxInfo.mpi.memory_pool, mp);
|
||||
} else {
|
||||
(void)osRtxMemoryFree(osRtxInfo.mem.common, mp);
|
||||
}
|
||||
#if (defined(OS_OBJ_MEM_USAGE) && (OS_OBJ_MEM_USAGE != 0))
|
||||
osRtxMemoryPoolMemUsage.cnt_free++;
|
||||
#endif
|
||||
}
|
||||
|
||||
EvrRtxMemoryPoolDestroyed(mp);
|
||||
|
||||
return osOK;
|
||||
}
|
||||
|
||||
// Service Calls definitions
|
||||
//lint ++flb "Library Begin" [MISRA Note 11]
|
||||
SVC0_3(MemoryPoolNew, osMemoryPoolId_t, uint32_t, uint32_t, const osMemoryPoolAttr_t *)
|
||||
SVC0_1(MemoryPoolGetName, const char *, osMemoryPoolId_t)
|
||||
SVC0_2(MemoryPoolAlloc, void *, osMemoryPoolId_t, uint32_t)
|
||||
SVC0_2(MemoryPoolFree, osStatus_t, osMemoryPoolId_t, void *)
|
||||
SVC0_1(MemoryPoolGetCapacity, uint32_t, osMemoryPoolId_t)
|
||||
SVC0_1(MemoryPoolGetBlockSize, uint32_t, osMemoryPoolId_t)
|
||||
SVC0_1(MemoryPoolGetCount, uint32_t, osMemoryPoolId_t)
|
||||
SVC0_1(MemoryPoolGetSpace, uint32_t, osMemoryPoolId_t)
|
||||
SVC0_1(MemoryPoolDelete, osStatus_t, osMemoryPoolId_t)
|
||||
//lint --flb "Library End"
|
||||
|
||||
|
||||
// ==== ISR Calls ====
|
||||
|
||||
/// Allocate a memory block from a Memory Pool.
|
||||
/// \note API identical to osMemoryPoolAlloc
|
||||
__STATIC_INLINE
|
||||
void *isrRtxMemoryPoolAlloc (osMemoryPoolId_t mp_id, uint32_t timeout) {
|
||||
os_memory_pool_t *mp = osRtxMemoryPoolId(mp_id);
|
||||
void *block;
|
||||
|
||||
// Check parameters
|
||||
if ((mp == NULL) || (mp->id != osRtxIdMemoryPool) || (timeout != 0U)) {
|
||||
EvrRtxMemoryPoolError(mp, (int32_t)osErrorParameter);
|
||||
//lint -e{904} "Return statement before end of function" [MISRA Note 1]
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// Allocate memory
|
||||
block = osRtxMemoryPoolAlloc(&mp->mp_info);
|
||||
if (block == NULL) {
|
||||
EvrRtxMemoryPoolAllocFailed(mp);
|
||||
} else {
|
||||
EvrRtxMemoryPoolAllocated(mp, block);
|
||||
}
|
||||
|
||||
return block;
|
||||
}
|
||||
|
||||
/// Return an allocated memory block back to a Memory Pool.
|
||||
/// \note API identical to osMemoryPoolFree
|
||||
__STATIC_INLINE
|
||||
osStatus_t isrRtxMemoryPoolFree (osMemoryPoolId_t mp_id, void *block) {
|
||||
os_memory_pool_t *mp = osRtxMemoryPoolId(mp_id);
|
||||
osStatus_t status;
|
||||
|
||||
// Check parameters
|
||||
if ((mp == NULL) || (mp->id != osRtxIdMemoryPool)) {
|
||||
EvrRtxMemoryPoolError(mp, (int32_t)osErrorParameter);
|
||||
//lint -e{904} "Return statement before end of function" [MISRA Note 1]
|
||||
return osErrorParameter;
|
||||
}
|
||||
|
||||
// Free memory
|
||||
status = osRtxMemoryPoolFree(&mp->mp_info, block);
|
||||
if (status == osOK) {
|
||||
// Register post ISR processing
|
||||
osRtxPostProcess(osRtxObject(mp));
|
||||
EvrRtxMemoryPoolDeallocated(mp, block);
|
||||
} else {
|
||||
EvrRtxMemoryPoolFreeFailed(mp, block);
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
|
||||
// ==== Public API ====
|
||||
|
||||
/// Create and Initialize a Memory Pool object.
|
||||
osMemoryPoolId_t osMemoryPoolNew (uint32_t block_count, uint32_t block_size, const osMemoryPoolAttr_t *attr) {
|
||||
osMemoryPoolId_t mp_id;
|
||||
|
||||
EvrRtxMemoryPoolNew(block_count, block_size, attr);
|
||||
if (IsIrqMode() || IsIrqMasked()) {
|
||||
EvrRtxMemoryPoolError(NULL, (int32_t)osErrorISR);
|
||||
mp_id = NULL;
|
||||
} else {
|
||||
mp_id = __svcMemoryPoolNew(block_count, block_size, attr);
|
||||
}
|
||||
return mp_id;
|
||||
}
|
||||
|
||||
/// Get name of a Memory Pool object.
|
||||
const char *osMemoryPoolGetName (osMemoryPoolId_t mp_id) {
|
||||
const char *name;
|
||||
|
||||
if (IsIrqMode() || IsIrqMasked()) {
|
||||
EvrRtxMemoryPoolGetName(mp_id, NULL);
|
||||
name = NULL;
|
||||
} else {
|
||||
name = __svcMemoryPoolGetName(mp_id);
|
||||
}
|
||||
return name;
|
||||
}
|
||||
|
||||
/// Allocate a memory block from a Memory Pool.
|
||||
void *osMemoryPoolAlloc (osMemoryPoolId_t mp_id, uint32_t timeout) {
|
||||
void *memory;
|
||||
|
||||
EvrRtxMemoryPoolAlloc(mp_id, timeout);
|
||||
if (IsIrqMode() || IsIrqMasked()) {
|
||||
memory = isrRtxMemoryPoolAlloc(mp_id, timeout);
|
||||
} else {
|
||||
memory = __svcMemoryPoolAlloc(mp_id, timeout);
|
||||
}
|
||||
return memory;
|
||||
}
|
||||
|
||||
/// Return an allocated memory block back to a Memory Pool.
|
||||
osStatus_t osMemoryPoolFree (osMemoryPoolId_t mp_id, void *block) {
|
||||
osStatus_t status;
|
||||
|
||||
EvrRtxMemoryPoolFree(mp_id, block);
|
||||
if (IsIrqMode() || IsIrqMasked()) {
|
||||
status = isrRtxMemoryPoolFree(mp_id, block);
|
||||
} else {
|
||||
status = __svcMemoryPoolFree(mp_id, block);
|
||||
}
|
||||
return status;
|
||||
}
|
||||
|
||||
/// Get maximum number of memory blocks in a Memory Pool.
|
||||
uint32_t osMemoryPoolGetCapacity (osMemoryPoolId_t mp_id) {
|
||||
uint32_t capacity;
|
||||
|
||||
if (IsIrqMode() || IsIrqMasked()) {
|
||||
capacity = svcRtxMemoryPoolGetCapacity(mp_id);
|
||||
} else {
|
||||
capacity = __svcMemoryPoolGetCapacity(mp_id);
|
||||
}
|
||||
return capacity;
|
||||
}
|
||||
|
||||
/// Get memory block size in a Memory Pool.
|
||||
uint32_t osMemoryPoolGetBlockSize (osMemoryPoolId_t mp_id) {
|
||||
uint32_t block_size;
|
||||
|
||||
if (IsIrqMode() || IsIrqMasked()) {
|
||||
block_size = svcRtxMemoryPoolGetBlockSize(mp_id);
|
||||
} else {
|
||||
block_size = __svcMemoryPoolGetBlockSize(mp_id);
|
||||
}
|
||||
return block_size;
|
||||
}
|
||||
|
||||
/// Get number of memory blocks used in a Memory Pool.
|
||||
uint32_t osMemoryPoolGetCount (osMemoryPoolId_t mp_id) {
|
||||
uint32_t count;
|
||||
|
||||
if (IsIrqMode() || IsIrqMasked()) {
|
||||
count = svcRtxMemoryPoolGetCount(mp_id);
|
||||
} else {
|
||||
count = __svcMemoryPoolGetCount(mp_id);
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
/// Get number of memory blocks available in a Memory Pool.
|
||||
uint32_t osMemoryPoolGetSpace (osMemoryPoolId_t mp_id) {
|
||||
uint32_t space;
|
||||
|
||||
if (IsIrqMode() || IsIrqMasked()) {
|
||||
space = svcRtxMemoryPoolGetSpace(mp_id);
|
||||
} else {
|
||||
space = __svcMemoryPoolGetSpace(mp_id);
|
||||
}
|
||||
return space;
|
||||
}
|
||||
|
||||
/// Delete a Memory Pool object.
|
||||
osStatus_t osMemoryPoolDelete (osMemoryPoolId_t mp_id) {
|
||||
osStatus_t status;
|
||||
|
||||
EvrRtxMemoryPoolDelete(mp_id);
|
||||
if (IsIrqMode() || IsIrqMasked()) {
|
||||
EvrRtxMemoryPoolError(mp_id, (int32_t)osErrorISR);
|
||||
status = osErrorISR;
|
||||
} else {
|
||||
status = __svcMemoryPoolDelete(mp_id);
|
||||
}
|
||||
return status;
|
||||
}
|
||||
@@ -0,0 +1,948 @@
|
||||
/*
|
||||
* Copyright (c) 2013-2019 Arm Limited. All rights reserved.
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the License); you may
|
||||
* not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an AS IS BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
* -----------------------------------------------------------------------------
|
||||
*
|
||||
* Project: CMSIS-RTOS RTX
|
||||
* Title: Message Queue functions
|
||||
*
|
||||
* -----------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
#include "rtx_lib.h"
|
||||
|
||||
|
||||
// OS Runtime Object Memory Usage
|
||||
#if ((defined(OS_OBJ_MEM_USAGE) && (OS_OBJ_MEM_USAGE != 0)))
|
||||
osRtxObjectMemUsage_t osRtxMessageQueueMemUsage \
|
||||
__attribute__((section(".data.os.msgqueue.obj"))) =
|
||||
{ 0U, 0U, 0U };
|
||||
#endif
|
||||
|
||||
|
||||
// ==== Helper functions ====
|
||||
|
||||
/// Put a Message into Queue sorted by Priority (Highest at Head).
|
||||
/// \param[in] mq message queue object.
|
||||
/// \param[in] msg message object.
|
||||
static void MessageQueuePut (os_message_queue_t *mq, os_message_t *msg) {
|
||||
#if (EXCLUSIVE_ACCESS == 0)
|
||||
uint32_t primask = __get_PRIMASK();
|
||||
#endif
|
||||
os_message_t *prev, *next;
|
||||
|
||||
if (mq->msg_last != NULL) {
|
||||
prev = mq->msg_last;
|
||||
next = NULL;
|
||||
while ((prev != NULL) && (prev->priority < msg->priority)) {
|
||||
next = prev;
|
||||
prev = prev->prev;
|
||||
}
|
||||
msg->prev = prev;
|
||||
msg->next = next;
|
||||
if (prev != NULL) {
|
||||
prev->next = msg;
|
||||
} else {
|
||||
mq->msg_first = msg;
|
||||
}
|
||||
if (next != NULL) {
|
||||
next->prev = msg;
|
||||
} else {
|
||||
mq->msg_last = msg;
|
||||
}
|
||||
} else {
|
||||
msg->prev = NULL;
|
||||
msg->next = NULL;
|
||||
mq->msg_first= msg;
|
||||
mq->msg_last = msg;
|
||||
}
|
||||
|
||||
#if (EXCLUSIVE_ACCESS == 0)
|
||||
__disable_irq();
|
||||
|
||||
mq->msg_count++;
|
||||
|
||||
if (primask == 0U) {
|
||||
__enable_irq();
|
||||
}
|
||||
#else
|
||||
(void)atomic_inc32(&mq->msg_count);
|
||||
#endif
|
||||
}
|
||||
|
||||
/// Get a Message from Queue with Highest Priority.
|
||||
/// \param[in] mq message queue object.
|
||||
/// \return message object or NULL.
|
||||
static os_message_t *MessageQueueGet (os_message_queue_t *mq) {
|
||||
#if (EXCLUSIVE_ACCESS == 0)
|
||||
uint32_t primask = __get_PRIMASK();
|
||||
#endif
|
||||
os_message_t *msg;
|
||||
uint32_t count;
|
||||
uint8_t flags;
|
||||
|
||||
#if (EXCLUSIVE_ACCESS == 0)
|
||||
__disable_irq();
|
||||
|
||||
count = mq->msg_count;
|
||||
if (count != 0U) {
|
||||
mq->msg_count--;
|
||||
}
|
||||
|
||||
if (primask == 0U) {
|
||||
__enable_irq();
|
||||
}
|
||||
#else
|
||||
count = atomic_dec32_nz(&mq->msg_count);
|
||||
#endif
|
||||
|
||||
if (count != 0U) {
|
||||
msg = mq->msg_first;
|
||||
|
||||
while (msg != NULL) {
|
||||
#if (EXCLUSIVE_ACCESS == 0)
|
||||
__disable_irq();
|
||||
|
||||
flags = msg->flags;
|
||||
msg->flags = 1U;
|
||||
|
||||
if (primask == 0U) {
|
||||
__enable_irq();
|
||||
}
|
||||
#else
|
||||
flags = atomic_wr8(&msg->flags, 1U);
|
||||
#endif
|
||||
if (flags == 0U) {
|
||||
break;
|
||||
}
|
||||
msg = msg->next;
|
||||
}
|
||||
} else {
|
||||
msg = NULL;
|
||||
}
|
||||
|
||||
return msg;
|
||||
}
|
||||
|
||||
/// Remove a Message from Queue
|
||||
/// \param[in] mq message queue object.
|
||||
/// \param[in] msg message object.
|
||||
static void MessageQueueRemove (os_message_queue_t *mq, const os_message_t *msg) {
|
||||
|
||||
if (msg->prev != NULL) {
|
||||
msg->prev->next = msg->next;
|
||||
} else {
|
||||
mq->msg_first = msg->next;
|
||||
}
|
||||
if (msg->next != NULL) {
|
||||
msg->next->prev = msg->prev;
|
||||
} else {
|
||||
mq->msg_last = msg->prev;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// ==== Post ISR processing ====
|
||||
|
||||
/// Message Queue post ISR processing.
|
||||
/// \param[in] msg message object.
|
||||
static void osRtxMessageQueuePostProcess (os_message_t *msg) {
|
||||
os_message_queue_t *mq;
|
||||
os_message_t *msg0;
|
||||
os_thread_t *thread;
|
||||
const uint32_t *reg;
|
||||
const void *ptr_src;
|
||||
void *ptr_dst;
|
||||
|
||||
if (msg->flags != 0U) {
|
||||
// Remove Message
|
||||
//lint -e{9079} -e{9087} "cast between pointers to different object types"
|
||||
mq = *((os_message_queue_t **)(void *)&msg[1]);
|
||||
MessageQueueRemove(mq, msg);
|
||||
// Free memory
|
||||
msg->id = osRtxIdInvalid;
|
||||
(void)osRtxMemoryPoolFree(&mq->mp_info, msg);
|
||||
// Check if Thread is waiting to send a Message
|
||||
if (mq->thread_list != NULL) {
|
||||
// Try to allocate memory
|
||||
//lint -e{9079} "conversion from pointer to void to pointer to other type" [MISRA Note 5]
|
||||
msg0 = osRtxMemoryPoolAlloc(&mq->mp_info);
|
||||
if (msg0 != NULL) {
|
||||
// Wakeup waiting Thread with highest Priority
|
||||
thread = osRtxThreadListGet(osRtxObject(mq));
|
||||
osRtxThreadWaitExit(thread, (uint32_t)osOK, FALSE);
|
||||
// Copy Message (R2: const void *msg_ptr, R3: uint8_t msg_prio)
|
||||
reg = osRtxThreadRegPtr(thread);
|
||||
//lint -e{923} "cast from unsigned int to pointer"
|
||||
ptr_src = (const void *)reg[2];
|
||||
memcpy(&msg0[1], ptr_src, mq->msg_size);
|
||||
// Store Message into Queue
|
||||
msg0->id = osRtxIdMessage;
|
||||
msg0->flags = 0U;
|
||||
msg0->priority = (uint8_t)reg[3];
|
||||
MessageQueuePut(mq, msg0);
|
||||
EvrRtxMessageQueueInserted(mq, ptr_src);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// New Message
|
||||
//lint -e{9079} -e{9087} "cast between pointers to different object types"
|
||||
mq = (void *)msg->next;
|
||||
//lint -e{9087} "cast between pointers to different object types"
|
||||
ptr_src = (const void *)msg->prev;
|
||||
// Check if Thread is waiting to receive a Message
|
||||
if ((mq->thread_list != NULL) && (mq->thread_list->state == osRtxThreadWaitingMessageGet)) {
|
||||
EvrRtxMessageQueueInserted(mq, ptr_src);
|
||||
// Wakeup waiting Thread with highest Priority
|
||||
thread = osRtxThreadListGet(osRtxObject(mq));
|
||||
osRtxThreadWaitExit(thread, (uint32_t)osOK, FALSE);
|
||||
// Copy Message (R2: void *msg_ptr, R3: uint8_t *msg_prio)
|
||||
reg = osRtxThreadRegPtr(thread);
|
||||
//lint -e{923} "cast from unsigned int to pointer"
|
||||
ptr_dst = (void *)reg[2];
|
||||
memcpy(ptr_dst, &msg[1], mq->msg_size);
|
||||
if (reg[3] != 0U) {
|
||||
//lint -e{923} -e{9078} "cast from unsigned int to pointer"
|
||||
*((uint8_t *)reg[3]) = msg->priority;
|
||||
}
|
||||
EvrRtxMessageQueueRetrieved(mq, ptr_dst);
|
||||
// Free memory
|
||||
msg->id = osRtxIdInvalid;
|
||||
(void)osRtxMemoryPoolFree(&mq->mp_info, msg);
|
||||
} else {
|
||||
EvrRtxMessageQueueInserted(mq, ptr_src);
|
||||
MessageQueuePut(mq, msg);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// ==== Service Calls ====
|
||||
|
||||
/// Create and Initialize a Message Queue object.
|
||||
/// \note API identical to osMessageQueueNew
|
||||
static osMessageQueueId_t svcRtxMessageQueueNew (uint32_t msg_count, uint32_t msg_size, const osMessageQueueAttr_t *attr) {
|
||||
os_message_queue_t *mq;
|
||||
void *mq_mem;
|
||||
uint32_t mq_size;
|
||||
uint32_t block_size;
|
||||
uint32_t size;
|
||||
uint8_t flags;
|
||||
const char *name;
|
||||
|
||||
// Check parameters
|
||||
if ((msg_count == 0U) || (msg_size == 0U)) {
|
||||
EvrRtxMessageQueueError(NULL, (int32_t)osErrorParameter);
|
||||
//lint -e{904} "Return statement before end of function" [MISRA Note 1]
|
||||
return NULL;
|
||||
}
|
||||
block_size = ((msg_size + 3U) & ~3UL) + sizeof(os_message_t);
|
||||
if ((__CLZ(msg_count) + __CLZ(block_size)) < 32U) {
|
||||
EvrRtxMessageQueueError(NULL, (int32_t)osErrorParameter);
|
||||
//lint -e{904} "Return statement before end of function" [MISRA Note 1]
|
||||
return NULL;
|
||||
}
|
||||
|
||||
size = msg_count * block_size;
|
||||
|
||||
// Process attributes
|
||||
if (attr != NULL) {
|
||||
name = attr->name;
|
||||
//lint -e{9079} "conversion from pointer to void to pointer to other type" [MISRA Note 6]
|
||||
mq = attr->cb_mem;
|
||||
//lint -e{9079} "conversion from pointer to void to pointer to other type" [MISRA Note 6]
|
||||
mq_mem = attr->mq_mem;
|
||||
mq_size = attr->mq_size;
|
||||
if (mq != NULL) {
|
||||
//lint -e(923) -e(9078) "cast from pointer to unsigned int" [MISRA Note 7]
|
||||
if ((((uint32_t)mq & 3U) != 0U) || (attr->cb_size < sizeof(os_message_queue_t))) {
|
||||
EvrRtxMessageQueueError(NULL, osRtxErrorInvalidControlBlock);
|
||||
//lint -e{904} "Return statement before end of function" [MISRA Note 1]
|
||||
return NULL;
|
||||
}
|
||||
} else {
|
||||
if (attr->cb_size != 0U) {
|
||||
EvrRtxMessageQueueError(NULL, osRtxErrorInvalidControlBlock);
|
||||
//lint -e{904} "Return statement before end of function" [MISRA Note 1]
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
if (mq_mem != NULL) {
|
||||
//lint -e(923) -e(9078) "cast from pointer to unsigned int" [MISRA Note 7]
|
||||
if ((((uint32_t)mq_mem & 3U) != 0U) || (mq_size < size)) {
|
||||
EvrRtxMessageQueueError(NULL, osRtxErrorInvalidDataMemory);
|
||||
//lint -e{904} "Return statement before end of function" [MISRA Note 1]
|
||||
return NULL;
|
||||
}
|
||||
} else {
|
||||
if (mq_size != 0U) {
|
||||
EvrRtxMessageQueueError(NULL, osRtxErrorInvalidDataMemory);
|
||||
//lint -e{904} "Return statement before end of function" [MISRA Note 1]
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
name = NULL;
|
||||
mq = NULL;
|
||||
mq_mem = NULL;
|
||||
}
|
||||
|
||||
// Allocate object memory if not provided
|
||||
if (mq == NULL) {
|
||||
if (osRtxInfo.mpi.message_queue != NULL) {
|
||||
//lint -e{9079} "conversion from pointer to void to pointer to other type" [MISRA Note 5]
|
||||
mq = osRtxMemoryPoolAlloc(osRtxInfo.mpi.message_queue);
|
||||
} else {
|
||||
//lint -e{9079} "conversion from pointer to void to pointer to other type" [MISRA Note 5]
|
||||
mq = osRtxMemoryAlloc(osRtxInfo.mem.common, sizeof(os_message_queue_t), 1U);
|
||||
}
|
||||
#if (defined(OS_OBJ_MEM_USAGE) && (OS_OBJ_MEM_USAGE != 0))
|
||||
if (mq != NULL) {
|
||||
uint32_t used;
|
||||
osRtxMessageQueueMemUsage.cnt_alloc++;
|
||||
used = osRtxMessageQueueMemUsage.cnt_alloc - osRtxMessageQueueMemUsage.cnt_free;
|
||||
if (osRtxMessageQueueMemUsage.max_used < used) {
|
||||
osRtxMessageQueueMemUsage.max_used = used;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
flags = osRtxFlagSystemObject;
|
||||
} else {
|
||||
flags = 0U;
|
||||
}
|
||||
|
||||
// Allocate data memory if not provided
|
||||
if ((mq != NULL) && (mq_mem == NULL)) {
|
||||
//lint -e{9079} "conversion from pointer to void to pointer to other type" [MISRA Note 5]
|
||||
mq_mem = osRtxMemoryAlloc(osRtxInfo.mem.mq_data, size, 0U);
|
||||
if (mq_mem == NULL) {
|
||||
if ((flags & osRtxFlagSystemObject) != 0U) {
|
||||
if (osRtxInfo.mpi.message_queue != NULL) {
|
||||
(void)osRtxMemoryPoolFree(osRtxInfo.mpi.message_queue, mq);
|
||||
} else {
|
||||
(void)osRtxMemoryFree(osRtxInfo.mem.common, mq);
|
||||
}
|
||||
#if (defined(OS_OBJ_MEM_USAGE) && (OS_OBJ_MEM_USAGE != 0))
|
||||
osRtxMessageQueueMemUsage.cnt_free++;
|
||||
#endif
|
||||
}
|
||||
mq = NULL;
|
||||
} else {
|
||||
memset(mq_mem, 0, size);
|
||||
}
|
||||
flags |= osRtxFlagSystemMemory;
|
||||
}
|
||||
|
||||
if (mq != NULL) {
|
||||
// Initialize control block
|
||||
mq->id = osRtxIdMessageQueue;
|
||||
mq->flags = flags;
|
||||
mq->name = name;
|
||||
mq->thread_list = NULL;
|
||||
mq->msg_size = msg_size;
|
||||
mq->msg_count = 0U;
|
||||
mq->msg_first = NULL;
|
||||
mq->msg_last = NULL;
|
||||
(void)osRtxMemoryPoolInit(&mq->mp_info, msg_count, block_size, mq_mem);
|
||||
|
||||
// Register post ISR processing function
|
||||
osRtxInfo.post_process.message = osRtxMessageQueuePostProcess;
|
||||
|
||||
EvrRtxMessageQueueCreated(mq, mq->name);
|
||||
} else {
|
||||
EvrRtxMessageQueueError(NULL, (int32_t)osErrorNoMemory);
|
||||
}
|
||||
|
||||
return mq;
|
||||
}
|
||||
|
||||
/// Get name of a Message Queue object.
|
||||
/// \note API identical to osMessageQueueGetName
|
||||
static const char *svcRtxMessageQueueGetName (osMessageQueueId_t mq_id) {
|
||||
os_message_queue_t *mq = osRtxMessageQueueId(mq_id);
|
||||
|
||||
// Check parameters
|
||||
if ((mq == NULL) || (mq->id != osRtxIdMessageQueue)) {
|
||||
EvrRtxMessageQueueGetName(mq, NULL);
|
||||
//lint -e{904} "Return statement before end of function" [MISRA Note 1]
|
||||
return NULL;
|
||||
}
|
||||
|
||||
EvrRtxMessageQueueGetName(mq, mq->name);
|
||||
|
||||
return mq->name;
|
||||
}
|
||||
|
||||
/// Put a Message into a Queue or timeout if Queue is full.
|
||||
/// \note API identical to osMessageQueuePut
|
||||
static osStatus_t svcRtxMessageQueuePut (osMessageQueueId_t mq_id, const void *msg_ptr, uint8_t msg_prio, uint32_t timeout) {
|
||||
os_message_queue_t *mq = osRtxMessageQueueId(mq_id);
|
||||
os_message_t *msg;
|
||||
os_thread_t *thread;
|
||||
uint32_t *reg;
|
||||
void *ptr;
|
||||
osStatus_t status;
|
||||
|
||||
// Check parameters
|
||||
if ((mq == NULL) || (mq->id != osRtxIdMessageQueue) || (msg_ptr == NULL)) {
|
||||
EvrRtxMessageQueueError(mq, (int32_t)osErrorParameter);
|
||||
//lint -e{904} "Return statement before end of function" [MISRA Note 1]
|
||||
return osErrorParameter;
|
||||
}
|
||||
|
||||
// Check if Thread is waiting to receive a Message
|
||||
if ((mq->thread_list != NULL) && (mq->thread_list->state == osRtxThreadWaitingMessageGet)) {
|
||||
EvrRtxMessageQueueInserted(mq, msg_ptr);
|
||||
// Wakeup waiting Thread with highest Priority
|
||||
thread = osRtxThreadListGet(osRtxObject(mq));
|
||||
osRtxThreadWaitExit(thread, (uint32_t)osOK, TRUE);
|
||||
// Copy Message (R2: void *msg_ptr, R3: uint8_t *msg_prio)
|
||||
reg = osRtxThreadRegPtr(thread);
|
||||
//lint -e{923} "cast from unsigned int to pointer"
|
||||
ptr = (void *)reg[2];
|
||||
memcpy(ptr, msg_ptr, mq->msg_size);
|
||||
if (reg[3] != 0U) {
|
||||
//lint -e{923} -e{9078} "cast from unsigned int to pointer"
|
||||
*((uint8_t *)reg[3]) = msg_prio;
|
||||
}
|
||||
EvrRtxMessageQueueRetrieved(mq, ptr);
|
||||
status = osOK;
|
||||
} else {
|
||||
// Try to allocate memory
|
||||
//lint -e{9079} "conversion from pointer to void to pointer to other type" [MISRA Note 5]
|
||||
msg = osRtxMemoryPoolAlloc(&mq->mp_info);
|
||||
if (msg != NULL) {
|
||||
// Copy Message
|
||||
memcpy(&msg[1], msg_ptr, mq->msg_size);
|
||||
// Put Message into Queue
|
||||
msg->id = osRtxIdMessage;
|
||||
msg->flags = 0U;
|
||||
msg->priority = msg_prio;
|
||||
MessageQueuePut(mq, msg);
|
||||
EvrRtxMessageQueueInserted(mq, msg_ptr);
|
||||
status = osOK;
|
||||
} else {
|
||||
// No memory available
|
||||
if (timeout != 0U) {
|
||||
EvrRtxMessageQueuePutPending(mq, msg_ptr, timeout);
|
||||
// Suspend current Thread
|
||||
if (osRtxThreadWaitEnter(osRtxThreadWaitingMessagePut, timeout)) {
|
||||
osRtxThreadListPut(osRtxObject(mq), osRtxThreadGetRunning());
|
||||
// Save arguments (R2: const void *msg_ptr, R3: uint8_t msg_prio)
|
||||
//lint -e{923} -e{9078} "cast from unsigned int to pointer"
|
||||
reg = (uint32_t *)(__get_PSP());
|
||||
//lint -e{923} -e{9078} "cast from pointer to unsigned int"
|
||||
reg[2] = (uint32_t)msg_ptr;
|
||||
//lint -e{923} -e{9078} "cast from pointer to unsigned int"
|
||||
reg[3] = (uint32_t)msg_prio;
|
||||
} else {
|
||||
EvrRtxMessageQueuePutTimeout(mq);
|
||||
}
|
||||
status = osErrorTimeout;
|
||||
} else {
|
||||
EvrRtxMessageQueueNotInserted(mq, msg_ptr);
|
||||
status = osErrorResource;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
/// Get a Message from a Queue or timeout if Queue is empty.
|
||||
/// \note API identical to osMessageQueueGet
|
||||
static osStatus_t svcRtxMessageQueueGet (osMessageQueueId_t mq_id, void *msg_ptr, uint8_t *msg_prio, uint32_t timeout) {
|
||||
os_message_queue_t *mq = osRtxMessageQueueId(mq_id);
|
||||
os_message_t *msg;
|
||||
os_thread_t *thread;
|
||||
uint32_t *reg;
|
||||
const void *ptr;
|
||||
osStatus_t status;
|
||||
|
||||
// Check parameters
|
||||
if ((mq == NULL) || (mq->id != osRtxIdMessageQueue) || (msg_ptr == NULL)) {
|
||||
EvrRtxMessageQueueError(mq, (int32_t)osErrorParameter);
|
||||
//lint -e{904} "Return statement before end of function" [MISRA Note 1]
|
||||
return osErrorParameter;
|
||||
}
|
||||
|
||||
// Get Message from Queue
|
||||
msg = MessageQueueGet(mq);
|
||||
if (msg != NULL) {
|
||||
MessageQueueRemove(mq, msg);
|
||||
// Copy Message
|
||||
memcpy(msg_ptr, &msg[1], mq->msg_size);
|
||||
if (msg_prio != NULL) {
|
||||
*msg_prio = msg->priority;
|
||||
}
|
||||
EvrRtxMessageQueueRetrieved(mq, msg_ptr);
|
||||
// Free memory
|
||||
msg->id = osRtxIdInvalid;
|
||||
(void)osRtxMemoryPoolFree(&mq->mp_info, msg);
|
||||
// Check if Thread is waiting to send a Message
|
||||
if (mq->thread_list != NULL) {
|
||||
// Try to allocate memory
|
||||
//lint -e{9079} "conversion from pointer to void to pointer to other type" [MISRA Note 5]
|
||||
msg = osRtxMemoryPoolAlloc(&mq->mp_info);
|
||||
if (msg != NULL) {
|
||||
// Wakeup waiting Thread with highest Priority
|
||||
thread = osRtxThreadListGet(osRtxObject(mq));
|
||||
osRtxThreadWaitExit(thread, (uint32_t)osOK, TRUE);
|
||||
// Copy Message (R2: const void *msg_ptr, R3: uint8_t msg_prio)
|
||||
reg = osRtxThreadRegPtr(thread);
|
||||
//lint -e{923} "cast from unsigned int to pointer"
|
||||
ptr = (const void *)reg[2];
|
||||
memcpy(&msg[1], ptr, mq->msg_size);
|
||||
// Store Message into Queue
|
||||
msg->id = osRtxIdMessage;
|
||||
msg->flags = 0U;
|
||||
msg->priority = (uint8_t)reg[3];
|
||||
MessageQueuePut(mq, msg);
|
||||
EvrRtxMessageQueueInserted(mq, ptr);
|
||||
}
|
||||
}
|
||||
status = osOK;
|
||||
} else {
|
||||
// No Message available
|
||||
if (timeout != 0U) {
|
||||
EvrRtxMessageQueueGetPending(mq, msg_ptr, timeout);
|
||||
// Suspend current Thread
|
||||
if (osRtxThreadWaitEnter(osRtxThreadWaitingMessageGet, timeout)) {
|
||||
osRtxThreadListPut(osRtxObject(mq), osRtxThreadGetRunning());
|
||||
// Save arguments (R2: void *msg_ptr, R3: uint8_t *msg_prio)
|
||||
//lint -e{923} -e{9078} "cast from unsigned int to pointer"
|
||||
reg = (uint32_t *)(__get_PSP());
|
||||
//lint -e{923} -e{9078} "cast from pointer to unsigned int"
|
||||
reg[2] = (uint32_t)msg_ptr;
|
||||
//lint -e{923} -e{9078} "cast from pointer to unsigned int"
|
||||
reg[3] = (uint32_t)msg_prio;
|
||||
} else {
|
||||
EvrRtxMessageQueueGetTimeout(mq);
|
||||
}
|
||||
status = osErrorTimeout;
|
||||
} else {
|
||||
EvrRtxMessageQueueNotRetrieved(mq, msg_ptr);
|
||||
status = osErrorResource;
|
||||
}
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
/// Get maximum number of messages in a Message Queue.
|
||||
/// \note API identical to osMessageQueueGetCapacity
|
||||
static uint32_t svcRtxMessageQueueGetCapacity (osMessageQueueId_t mq_id) {
|
||||
os_message_queue_t *mq = osRtxMessageQueueId(mq_id);
|
||||
|
||||
// Check parameters
|
||||
if ((mq == NULL) || (mq->id != osRtxIdMessageQueue)) {
|
||||
EvrRtxMessageQueueGetCapacity(mq, 0U);
|
||||
//lint -e{904} "Return statement before end of function" [MISRA Note 1]
|
||||
return 0U;
|
||||
}
|
||||
|
||||
EvrRtxMessageQueueGetCapacity(mq, mq->mp_info.max_blocks);
|
||||
|
||||
return mq->mp_info.max_blocks;
|
||||
}
|
||||
|
||||
/// Get maximum message size in a Memory Pool.
|
||||
/// \note API identical to osMessageQueueGetMsgSize
|
||||
static uint32_t svcRtxMessageQueueGetMsgSize (osMessageQueueId_t mq_id) {
|
||||
os_message_queue_t *mq = osRtxMessageQueueId(mq_id);
|
||||
|
||||
// Check parameters
|
||||
if ((mq == NULL) || (mq->id != osRtxIdMessageQueue)) {
|
||||
EvrRtxMessageQueueGetMsgSize(mq, 0U);
|
||||
//lint -e{904} "Return statement before end of function" [MISRA Note 1]
|
||||
return 0U;
|
||||
}
|
||||
|
||||
EvrRtxMessageQueueGetMsgSize(mq, mq->msg_size);
|
||||
|
||||
return mq->msg_size;
|
||||
}
|
||||
|
||||
/// Get number of queued messages in a Message Queue.
|
||||
/// \note API identical to osMessageQueueGetCount
|
||||
static uint32_t svcRtxMessageQueueGetCount (osMessageQueueId_t mq_id) {
|
||||
os_message_queue_t *mq = osRtxMessageQueueId(mq_id);
|
||||
|
||||
// Check parameters
|
||||
if ((mq == NULL) || (mq->id != osRtxIdMessageQueue)) {
|
||||
EvrRtxMessageQueueGetCount(mq, 0U);
|
||||
//lint -e{904} "Return statement before end of function" [MISRA Note 1]
|
||||
return 0U;
|
||||
}
|
||||
|
||||
EvrRtxMessageQueueGetCount(mq, mq->msg_count);
|
||||
|
||||
return mq->msg_count;
|
||||
}
|
||||
|
||||
/// Get number of available slots for messages in a Message Queue.
|
||||
/// \note API identical to osMessageQueueGetSpace
|
||||
static uint32_t svcRtxMessageQueueGetSpace (osMessageQueueId_t mq_id) {
|
||||
os_message_queue_t *mq = osRtxMessageQueueId(mq_id);
|
||||
|
||||
// Check parameters
|
||||
if ((mq == NULL) || (mq->id != osRtxIdMessageQueue)) {
|
||||
EvrRtxMessageQueueGetSpace(mq, 0U);
|
||||
//lint -e{904} "Return statement before end of function" [MISRA Note 1]
|
||||
return 0U;
|
||||
}
|
||||
|
||||
EvrRtxMessageQueueGetSpace(mq, mq->mp_info.max_blocks - mq->msg_count);
|
||||
|
||||
return (mq->mp_info.max_blocks - mq->msg_count);
|
||||
}
|
||||
|
||||
/// Reset a Message Queue to initial empty state.
|
||||
/// \note API identical to osMessageQueueReset
|
||||
static osStatus_t svcRtxMessageQueueReset (osMessageQueueId_t mq_id) {
|
||||
os_message_queue_t *mq = osRtxMessageQueueId(mq_id);
|
||||
os_message_t *msg;
|
||||
os_thread_t *thread;
|
||||
const uint32_t *reg;
|
||||
const void *ptr;
|
||||
|
||||
// Check parameters
|
||||
if ((mq == NULL) || (mq->id != osRtxIdMessageQueue)) {
|
||||
EvrRtxMessageQueueError(mq, (int32_t)osErrorParameter);
|
||||
//lint -e{904} "Return statement before end of function" [MISRA Note 1]
|
||||
return osErrorParameter;
|
||||
}
|
||||
|
||||
// Remove Messages from Queue
|
||||
for (;;) {
|
||||
// Get Message from Queue
|
||||
msg = MessageQueueGet(mq);
|
||||
if (msg == NULL) {
|
||||
break;
|
||||
}
|
||||
MessageQueueRemove(mq, msg);
|
||||
EvrRtxMessageQueueRetrieved(mq, NULL);
|
||||
// Free memory
|
||||
msg->id = osRtxIdInvalid;
|
||||
(void)osRtxMemoryPoolFree(&mq->mp_info, msg);
|
||||
}
|
||||
|
||||
// Check if Threads are waiting to send Messages
|
||||
if ((mq->thread_list != NULL) && (mq->thread_list->state == osRtxThreadWaitingMessagePut)) {
|
||||
do {
|
||||
// Try to allocate memory
|
||||
//lint -e{9079} "conversion from pointer to void to pointer to other type" [MISRA Note 5]
|
||||
msg = osRtxMemoryPoolAlloc(&mq->mp_info);
|
||||
if (msg != NULL) {
|
||||
// Wakeup waiting Thread with highest Priority
|
||||
thread = osRtxThreadListGet(osRtxObject(mq));
|
||||
osRtxThreadWaitExit(thread, (uint32_t)osOK, FALSE);
|
||||
// Copy Message (R2: const void *msg_ptr, R3: uint8_t msg_prio)
|
||||
reg = osRtxThreadRegPtr(thread);
|
||||
//lint -e{923} "cast from unsigned int to pointer"
|
||||
ptr = (const void *)reg[2];
|
||||
memcpy(&msg[1], ptr, mq->msg_size);
|
||||
// Store Message into Queue
|
||||
msg->id = osRtxIdMessage;
|
||||
msg->flags = 0U;
|
||||
msg->priority = (uint8_t)reg[3];
|
||||
MessageQueuePut(mq, msg);
|
||||
EvrRtxMessageQueueInserted(mq, ptr);
|
||||
}
|
||||
} while ((msg != NULL) && (mq->thread_list != NULL));
|
||||
osRtxThreadDispatch(NULL);
|
||||
}
|
||||
|
||||
EvrRtxMessageQueueResetDone(mq);
|
||||
|
||||
return osOK;
|
||||
}
|
||||
|
||||
/// Delete a Message Queue object.
|
||||
/// \note API identical to osMessageQueueDelete
|
||||
static osStatus_t svcRtxMessageQueueDelete (osMessageQueueId_t mq_id) {
|
||||
os_message_queue_t *mq = osRtxMessageQueueId(mq_id);
|
||||
os_thread_t *thread;
|
||||
|
||||
// Check parameters
|
||||
if ((mq == NULL) || (mq->id != osRtxIdMessageQueue)) {
|
||||
EvrRtxMessageQueueError(mq, (int32_t)osErrorParameter);
|
||||
//lint -e{904} "Return statement before end of function" [MISRA Note 1]
|
||||
return osErrorParameter;
|
||||
}
|
||||
|
||||
// Unblock waiting threads
|
||||
if (mq->thread_list != NULL) {
|
||||
do {
|
||||
thread = osRtxThreadListGet(osRtxObject(mq));
|
||||
osRtxThreadWaitExit(thread, (uint32_t)osErrorResource, FALSE);
|
||||
} while (mq->thread_list != NULL);
|
||||
osRtxThreadDispatch(NULL);
|
||||
}
|
||||
|
||||
// Mark object as invalid
|
||||
mq->id = osRtxIdInvalid;
|
||||
|
||||
// Free data memory
|
||||
if ((mq->flags & osRtxFlagSystemMemory) != 0U) {
|
||||
(void)osRtxMemoryFree(osRtxInfo.mem.mq_data, mq->mp_info.block_base);
|
||||
}
|
||||
|
||||
// Free object memory
|
||||
if ((mq->flags & osRtxFlagSystemObject) != 0U) {
|
||||
if (osRtxInfo.mpi.message_queue != NULL) {
|
||||
(void)osRtxMemoryPoolFree(osRtxInfo.mpi.message_queue, mq);
|
||||
} else {
|
||||
(void)osRtxMemoryFree(osRtxInfo.mem.common, mq);
|
||||
}
|
||||
#if (defined(OS_OBJ_MEM_USAGE) && (OS_OBJ_MEM_USAGE != 0))
|
||||
osRtxMessageQueueMemUsage.cnt_free++;
|
||||
#endif
|
||||
}
|
||||
|
||||
EvrRtxMessageQueueDestroyed(mq);
|
||||
|
||||
return osOK;
|
||||
}
|
||||
|
||||
// Service Calls definitions
|
||||
//lint ++flb "Library Begin" [MISRA Note 11]
|
||||
SVC0_3(MessageQueueNew, osMessageQueueId_t, uint32_t, uint32_t, const osMessageQueueAttr_t *)
|
||||
SVC0_1(MessageQueueGetName, const char *, osMessageQueueId_t)
|
||||
SVC0_4(MessageQueuePut, osStatus_t, osMessageQueueId_t, const void *, uint8_t, uint32_t)
|
||||
SVC0_4(MessageQueueGet, osStatus_t, osMessageQueueId_t, void *, uint8_t *, uint32_t)
|
||||
SVC0_1(MessageQueueGetCapacity, uint32_t, osMessageQueueId_t)
|
||||
SVC0_1(MessageQueueGetMsgSize, uint32_t, osMessageQueueId_t)
|
||||
SVC0_1(MessageQueueGetCount, uint32_t, osMessageQueueId_t)
|
||||
SVC0_1(MessageQueueGetSpace, uint32_t, osMessageQueueId_t)
|
||||
SVC0_1(MessageQueueReset, osStatus_t, osMessageQueueId_t)
|
||||
SVC0_1(MessageQueueDelete, osStatus_t, osMessageQueueId_t)
|
||||
//lint --flb "Library End"
|
||||
|
||||
|
||||
// ==== ISR Calls ====
|
||||
|
||||
/// Put a Message into a Queue or timeout if Queue is full.
|
||||
/// \note API identical to osMessageQueuePut
|
||||
__STATIC_INLINE
|
||||
osStatus_t isrRtxMessageQueuePut (osMessageQueueId_t mq_id, const void *msg_ptr, uint8_t msg_prio, uint32_t timeout) {
|
||||
os_message_queue_t *mq = osRtxMessageQueueId(mq_id);
|
||||
os_message_t *msg;
|
||||
osStatus_t status;
|
||||
|
||||
// Check parameters
|
||||
if ((mq == NULL) || (mq->id != osRtxIdMessageQueue) || (msg_ptr == NULL) || (timeout != 0U)) {
|
||||
EvrRtxMessageQueueError(mq, (int32_t)osErrorParameter);
|
||||
//lint -e{904} "Return statement before end of function" [MISRA Note 1]
|
||||
return osErrorParameter;
|
||||
}
|
||||
|
||||
// Try to allocate memory
|
||||
//lint -e{9079} "conversion from pointer to void to pointer to other type" [MISRA Note 5]
|
||||
msg = osRtxMemoryPoolAlloc(&mq->mp_info);
|
||||
if (msg != NULL) {
|
||||
// Copy Message
|
||||
memcpy(&msg[1], msg_ptr, mq->msg_size);
|
||||
msg->id = osRtxIdMessage;
|
||||
msg->flags = 0U;
|
||||
msg->priority = msg_prio;
|
||||
// Register post ISR processing
|
||||
//lint -e{9079} -e{9087} "cast between pointers to different object types"
|
||||
*((const void **)(void *)&msg->prev) = msg_ptr;
|
||||
//lint -e{9079} -e{9087} "cast between pointers to different object types"
|
||||
*( (void **) &msg->next) = mq;
|
||||
osRtxPostProcess(osRtxObject(msg));
|
||||
EvrRtxMessageQueueInsertPending(mq, msg_ptr);
|
||||
status = osOK;
|
||||
} else {
|
||||
// No memory available
|
||||
EvrRtxMessageQueueNotInserted(mq, msg_ptr);
|
||||
status = osErrorResource;
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
/// Get a Message from a Queue or timeout if Queue is empty.
|
||||
/// \note API identical to osMessageQueueGet
|
||||
__STATIC_INLINE
|
||||
osStatus_t isrRtxMessageQueueGet (osMessageQueueId_t mq_id, void *msg_ptr, uint8_t *msg_prio, uint32_t timeout) {
|
||||
os_message_queue_t *mq = osRtxMessageQueueId(mq_id);
|
||||
os_message_t *msg;
|
||||
osStatus_t status;
|
||||
|
||||
// Check parameters
|
||||
if ((mq == NULL) || (mq->id != osRtxIdMessageQueue) || (msg_ptr == NULL) || (timeout != 0U)) {
|
||||
EvrRtxMessageQueueError(mq, (int32_t)osErrorParameter);
|
||||
//lint -e{904} "Return statement before end of function" [MISRA Note 1]
|
||||
return osErrorParameter;
|
||||
}
|
||||
|
||||
// Get Message from Queue
|
||||
msg = MessageQueueGet(mq);
|
||||
if (msg != NULL) {
|
||||
// Copy Message
|
||||
memcpy(msg_ptr, &msg[1], mq->msg_size);
|
||||
if (msg_prio != NULL) {
|
||||
*msg_prio = msg->priority;
|
||||
}
|
||||
// Register post ISR processing
|
||||
//lint -e{9079} -e{9087} "cast between pointers to different object types"
|
||||
*((os_message_queue_t **)(void *)&msg[1]) = mq;
|
||||
osRtxPostProcess(osRtxObject(msg));
|
||||
EvrRtxMessageQueueRetrieved(mq, msg_ptr);
|
||||
status = osOK;
|
||||
} else {
|
||||
// No Message available
|
||||
EvrRtxMessageQueueNotRetrieved(mq, msg_ptr);
|
||||
status = osErrorResource;
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
|
||||
// ==== Public API ====
|
||||
|
||||
/// Create and Initialize a Message Queue object.
|
||||
osMessageQueueId_t osMessageQueueNew (uint32_t msg_count, uint32_t msg_size, const osMessageQueueAttr_t *attr) {
|
||||
osMessageQueueId_t mq_id;
|
||||
|
||||
EvrRtxMessageQueueNew(msg_count, msg_size, attr);
|
||||
if (IsIrqMode() || IsIrqMasked()) {
|
||||
EvrRtxMessageQueueError(NULL, (int32_t)osErrorISR);
|
||||
mq_id = NULL;
|
||||
} else {
|
||||
mq_id = __svcMessageQueueNew(msg_count, msg_size, attr);
|
||||
}
|
||||
return mq_id;
|
||||
}
|
||||
|
||||
/// Get name of a Message Queue object.
|
||||
const char *osMessageQueueGetName (osMessageQueueId_t mq_id) {
|
||||
const char *name;
|
||||
|
||||
if (IsIrqMode() || IsIrqMasked()) {
|
||||
EvrRtxMessageQueueGetName(mq_id, NULL);
|
||||
name = NULL;
|
||||
} else {
|
||||
name = __svcMessageQueueGetName(mq_id);
|
||||
}
|
||||
return name;
|
||||
}
|
||||
|
||||
/// Put a Message into a Queue or timeout if Queue is full.
|
||||
osStatus_t osMessageQueuePut (osMessageQueueId_t mq_id, const void *msg_ptr, uint8_t msg_prio, uint32_t timeout) {
|
||||
osStatus_t status;
|
||||
|
||||
EvrRtxMessageQueuePut(mq_id, msg_ptr, msg_prio, timeout);
|
||||
if (IsIrqMode() || IsIrqMasked()) {
|
||||
status = isrRtxMessageQueuePut(mq_id, msg_ptr, msg_prio, timeout);
|
||||
} else {
|
||||
status = __svcMessageQueuePut(mq_id, msg_ptr, msg_prio, timeout);
|
||||
}
|
||||
return status;
|
||||
}
|
||||
|
||||
/// Get a Message from a Queue or timeout if Queue is empty.
|
||||
osStatus_t osMessageQueueGet (osMessageQueueId_t mq_id, void *msg_ptr, uint8_t *msg_prio, uint32_t timeout) {
|
||||
osStatus_t status;
|
||||
|
||||
EvrRtxMessageQueueGet(mq_id, msg_ptr, msg_prio, timeout);
|
||||
if (IsIrqMode() || IsIrqMasked()) {
|
||||
status = isrRtxMessageQueueGet(mq_id, msg_ptr, msg_prio, timeout);
|
||||
} else {
|
||||
status = __svcMessageQueueGet(mq_id, msg_ptr, msg_prio, timeout);
|
||||
}
|
||||
return status;
|
||||
}
|
||||
|
||||
/// Get maximum number of messages in a Message Queue.
|
||||
uint32_t osMessageQueueGetCapacity (osMessageQueueId_t mq_id) {
|
||||
uint32_t capacity;
|
||||
|
||||
if (IsIrqMode() || IsIrqMasked()) {
|
||||
capacity = svcRtxMessageQueueGetCapacity(mq_id);
|
||||
} else {
|
||||
capacity = __svcMessageQueueGetCapacity(mq_id);
|
||||
}
|
||||
return capacity;
|
||||
}
|
||||
|
||||
/// Get maximum message size in a Memory Pool.
|
||||
uint32_t osMessageQueueGetMsgSize (osMessageQueueId_t mq_id) {
|
||||
uint32_t msg_size;
|
||||
|
||||
if (IsIrqMode() || IsIrqMasked()) {
|
||||
msg_size = svcRtxMessageQueueGetMsgSize(mq_id);
|
||||
} else {
|
||||
msg_size = __svcMessageQueueGetMsgSize(mq_id);
|
||||
}
|
||||
return msg_size;
|
||||
}
|
||||
|
||||
/// Get number of queued messages in a Message Queue.
|
||||
uint32_t osMessageQueueGetCount (osMessageQueueId_t mq_id) {
|
||||
uint32_t count;
|
||||
|
||||
if (IsIrqMode() || IsIrqMasked()) {
|
||||
count = svcRtxMessageQueueGetCount(mq_id);
|
||||
} else {
|
||||
count = __svcMessageQueueGetCount(mq_id);
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
/// Get number of available slots for messages in a Message Queue.
|
||||
uint32_t osMessageQueueGetSpace (osMessageQueueId_t mq_id) {
|
||||
uint32_t space;
|
||||
|
||||
if (IsIrqMode() || IsIrqMasked()) {
|
||||
space = svcRtxMessageQueueGetSpace(mq_id);
|
||||
} else {
|
||||
space = __svcMessageQueueGetSpace(mq_id);
|
||||
}
|
||||
return space;
|
||||
}
|
||||
|
||||
/// Reset a Message Queue to initial empty state.
|
||||
osStatus_t osMessageQueueReset (osMessageQueueId_t mq_id) {
|
||||
osStatus_t status;
|
||||
|
||||
EvrRtxMessageQueueReset(mq_id);
|
||||
if (IsIrqMode() || IsIrqMasked()) {
|
||||
EvrRtxMessageQueueError(mq_id, (int32_t)osErrorISR);
|
||||
status = osErrorISR;
|
||||
} else {
|
||||
status = __svcMessageQueueReset(mq_id);
|
||||
}
|
||||
return status;
|
||||
}
|
||||
|
||||
/// Delete a Message Queue object.
|
||||
osStatus_t osMessageQueueDelete (osMessageQueueId_t mq_id) {
|
||||
osStatus_t status;
|
||||
|
||||
EvrRtxMessageQueueDelete(mq_id);
|
||||
if (IsIrqMode() || IsIrqMasked()) {
|
||||
EvrRtxMessageQueueError(mq_id, (int32_t)osErrorISR);
|
||||
status = osErrorISR;
|
||||
} else {
|
||||
status = __svcMessageQueueDelete(mq_id);
|
||||
}
|
||||
return status;
|
||||
}
|
||||
@@ -0,0 +1,570 @@
|
||||
/*
|
||||
* Copyright (c) 2013-2019 Arm Limited. All rights reserved.
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the License); you may
|
||||
* not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an AS IS BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
* -----------------------------------------------------------------------------
|
||||
*
|
||||
* Project: CMSIS-RTOS RTX
|
||||
* Title: Mutex functions
|
||||
*
|
||||
* -----------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
#include "rtx_lib.h"
|
||||
|
||||
|
||||
// OS Runtime Object Memory Usage
|
||||
#if ((defined(OS_OBJ_MEM_USAGE) && (OS_OBJ_MEM_USAGE != 0)))
|
||||
osRtxObjectMemUsage_t osRtxMutexMemUsage \
|
||||
__attribute__((section(".data.os.mutex.obj"))) =
|
||||
{ 0U, 0U, 0U };
|
||||
#endif
|
||||
|
||||
|
||||
// ==== Library functions ====
|
||||
|
||||
/// Release Mutex list when owner Thread terminates.
|
||||
/// \param[in] mutex_list mutex list.
|
||||
void osRtxMutexOwnerRelease (os_mutex_t *mutex_list) {
|
||||
os_mutex_t *mutex;
|
||||
os_mutex_t *mutex_next;
|
||||
os_thread_t *thread;
|
||||
|
||||
mutex = mutex_list;
|
||||
while (mutex != NULL) {
|
||||
mutex_next = mutex->owner_next;
|
||||
// Check if Mutex is Robust
|
||||
if ((mutex->attr & osMutexRobust) != 0U) {
|
||||
// Clear Lock counter
|
||||
mutex->lock = 0U;
|
||||
EvrRtxMutexReleased(mutex, 0U);
|
||||
// Check if Thread is waiting for a Mutex
|
||||
if (mutex->thread_list != NULL) {
|
||||
// Wakeup waiting Thread with highest Priority
|
||||
thread = osRtxThreadListGet(osRtxObject(mutex));
|
||||
osRtxThreadWaitExit(thread, (uint32_t)osOK, FALSE);
|
||||
// Thread is the new Mutex owner
|
||||
mutex->owner_thread = thread;
|
||||
mutex->owner_prev = NULL;
|
||||
mutex->owner_next = thread->mutex_list;
|
||||
if (thread->mutex_list != NULL) {
|
||||
thread->mutex_list->owner_prev = mutex;
|
||||
}
|
||||
thread->mutex_list = mutex;
|
||||
mutex->lock = 1U;
|
||||
EvrRtxMutexAcquired(mutex, 1U);
|
||||
}
|
||||
}
|
||||
mutex = mutex_next;
|
||||
}
|
||||
}
|
||||
|
||||
/// Restore Mutex owner Thread priority.
|
||||
/// \param[in] mutex mutex object.
|
||||
/// \param[in] thread_wakeup thread wakeup object.
|
||||
void osRtxMutexOwnerRestore (const os_mutex_t *mutex, const os_thread_t *thread_wakeup) {
|
||||
const os_mutex_t *mutex0;
|
||||
os_thread_t *thread;
|
||||
os_thread_t *thread0;
|
||||
int8_t priority;
|
||||
|
||||
// Restore owner Thread priority
|
||||
if ((mutex->attr & osMutexPrioInherit) != 0U) {
|
||||
thread = mutex->owner_thread;
|
||||
priority = thread->priority_base;
|
||||
mutex0 = thread->mutex_list;
|
||||
// Check Mutexes owned by Thread
|
||||
do {
|
||||
// Check Threads waiting for Mutex
|
||||
thread0 = mutex0->thread_list;
|
||||
if (thread0 == thread_wakeup) {
|
||||
// Skip thread that is waken-up
|
||||
thread0 = thread0->thread_next;
|
||||
}
|
||||
if ((thread0 != NULL) && (thread0->priority > priority)) {
|
||||
// Higher priority Thread is waiting for Mutex
|
||||
priority = thread0->priority;
|
||||
}
|
||||
mutex0 = mutex0->owner_next;
|
||||
} while (mutex0 != NULL);
|
||||
if (thread->priority != priority) {
|
||||
thread->priority = priority;
|
||||
osRtxThreadListSort(thread);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// ==== Service Calls ====
|
||||
|
||||
/// Create and Initialize a Mutex object.
|
||||
/// \note API identical to osMutexNew
|
||||
static osMutexId_t svcRtxMutexNew (const osMutexAttr_t *attr) {
|
||||
os_mutex_t *mutex;
|
||||
uint32_t attr_bits;
|
||||
uint8_t flags;
|
||||
const char *name;
|
||||
|
||||
// Process attributes
|
||||
if (attr != NULL) {
|
||||
name = attr->name;
|
||||
attr_bits = attr->attr_bits;
|
||||
//lint -e{9079} "conversion from pointer to void to pointer to other type" [MISRA Note 6]
|
||||
mutex = attr->cb_mem;
|
||||
if (mutex != NULL) {
|
||||
//lint -e(923) -e(9078) "cast from pointer to unsigned int" [MISRA Note 7]
|
||||
if ((((uint32_t)mutex & 3U) != 0U) || (attr->cb_size < sizeof(os_mutex_t))) {
|
||||
EvrRtxMutexError(NULL, osRtxErrorInvalidControlBlock);
|
||||
//lint -e{904} "Return statement before end of function" [MISRA Note 1]
|
||||
return NULL;
|
||||
}
|
||||
} else {
|
||||
if (attr->cb_size != 0U) {
|
||||
EvrRtxMutexError(NULL, osRtxErrorInvalidControlBlock);
|
||||
//lint -e{904} "Return statement before end of function" [MISRA Note 1]
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
name = NULL;
|
||||
attr_bits = 0U;
|
||||
mutex = NULL;
|
||||
}
|
||||
|
||||
// Allocate object memory if not provided
|
||||
if (mutex == NULL) {
|
||||
if (osRtxInfo.mpi.mutex != NULL) {
|
||||
//lint -e{9079} "conversion from pointer to void to pointer to other type" [MISRA Note 5]
|
||||
mutex = osRtxMemoryPoolAlloc(osRtxInfo.mpi.mutex);
|
||||
} else {
|
||||
//lint -e{9079} "conversion from pointer to void to pointer to other type" [MISRA Note 5]
|
||||
mutex = osRtxMemoryAlloc(osRtxInfo.mem.common, sizeof(os_mutex_t), 1U);
|
||||
}
|
||||
#if (defined(OS_OBJ_MEM_USAGE) && (OS_OBJ_MEM_USAGE != 0))
|
||||
if (mutex != NULL) {
|
||||
uint32_t used;
|
||||
osRtxMutexMemUsage.cnt_alloc++;
|
||||
used = osRtxMutexMemUsage.cnt_alloc - osRtxMutexMemUsage.cnt_free;
|
||||
if (osRtxMutexMemUsage.max_used < used) {
|
||||
osRtxMutexMemUsage.max_used = used;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
flags = osRtxFlagSystemObject;
|
||||
} else {
|
||||
flags = 0U;
|
||||
}
|
||||
|
||||
if (mutex != NULL) {
|
||||
// Initialize control block
|
||||
mutex->id = osRtxIdMutex;
|
||||
mutex->flags = flags;
|
||||
mutex->attr = (uint8_t)attr_bits;
|
||||
mutex->name = name;
|
||||
mutex->thread_list = NULL;
|
||||
mutex->owner_thread = NULL;
|
||||
mutex->owner_prev = NULL;
|
||||
mutex->owner_next = NULL;
|
||||
mutex->lock = 0U;
|
||||
|
||||
EvrRtxMutexCreated(mutex, mutex->name);
|
||||
} else {
|
||||
EvrRtxMutexError(NULL, (int32_t)osErrorNoMemory);
|
||||
}
|
||||
|
||||
return mutex;
|
||||
}
|
||||
|
||||
/// Get name of a Mutex object.
|
||||
/// \note API identical to osMutexGetName
|
||||
static const char *svcRtxMutexGetName (osMutexId_t mutex_id) {
|
||||
os_mutex_t *mutex = osRtxMutexId(mutex_id);
|
||||
|
||||
// Check parameters
|
||||
if ((mutex == NULL) || (mutex->id != osRtxIdMutex)) {
|
||||
EvrRtxMutexGetName(mutex, NULL);
|
||||
//lint -e{904} "Return statement before end of function" [MISRA Note 1]
|
||||
return NULL;
|
||||
}
|
||||
|
||||
EvrRtxMutexGetName(mutex, mutex->name);
|
||||
|
||||
return mutex->name;
|
||||
}
|
||||
|
||||
/// Acquire a Mutex or timeout if it is locked.
|
||||
/// \note API identical to osMutexAcquire
|
||||
static osStatus_t svcRtxMutexAcquire (osMutexId_t mutex_id, uint32_t timeout) {
|
||||
os_mutex_t *mutex = osRtxMutexId(mutex_id);
|
||||
os_thread_t *thread;
|
||||
osStatus_t status;
|
||||
|
||||
// Check running thread
|
||||
thread = osRtxThreadGetRunning();
|
||||
if (thread == NULL) {
|
||||
EvrRtxMutexError(mutex, osRtxErrorKernelNotRunning);
|
||||
//lint -e{904} "Return statement before end of function" [MISRA Note 1]
|
||||
return osError;
|
||||
}
|
||||
|
||||
// Check parameters
|
||||
if ((mutex == NULL) || (mutex->id != osRtxIdMutex)) {
|
||||
EvrRtxMutexError(mutex, (int32_t)osErrorParameter);
|
||||
//lint -e{904} "Return statement before end of function" [MISRA Note 1]
|
||||
return osErrorParameter;
|
||||
}
|
||||
|
||||
// Check if Mutex is not locked
|
||||
if (mutex->lock == 0U) {
|
||||
// Acquire Mutex
|
||||
mutex->owner_thread = thread;
|
||||
mutex->owner_prev = NULL;
|
||||
mutex->owner_next = thread->mutex_list;
|
||||
if (thread->mutex_list != NULL) {
|
||||
thread->mutex_list->owner_prev = mutex;
|
||||
}
|
||||
thread->mutex_list = mutex;
|
||||
mutex->lock = 1U;
|
||||
EvrRtxMutexAcquired(mutex, mutex->lock);
|
||||
status = osOK;
|
||||
} else {
|
||||
// Check if Mutex is recursive and running Thread is the owner
|
||||
if (((mutex->attr & osMutexRecursive) != 0U) && (mutex->owner_thread == thread)) {
|
||||
// Try to increment lock counter
|
||||
if (mutex->lock == osRtxMutexLockLimit) {
|
||||
EvrRtxMutexError(mutex, osRtxErrorMutexLockLimit);
|
||||
status = osErrorResource;
|
||||
} else {
|
||||
mutex->lock++;
|
||||
EvrRtxMutexAcquired(mutex, mutex->lock);
|
||||
status = osOK;
|
||||
}
|
||||
} else {
|
||||
// Check if timeout is specified
|
||||
if (timeout != 0U) {
|
||||
// Check if Priority inheritance protocol is enabled
|
||||
if ((mutex->attr & osMutexPrioInherit) != 0U) {
|
||||
// Raise priority of owner Thread if lower than priority of running Thread
|
||||
if (mutex->owner_thread->priority < thread->priority) {
|
||||
mutex->owner_thread->priority = thread->priority;
|
||||
osRtxThreadListSort(mutex->owner_thread);
|
||||
}
|
||||
}
|
||||
EvrRtxMutexAcquirePending(mutex, timeout);
|
||||
// Suspend current Thread
|
||||
if (osRtxThreadWaitEnter(osRtxThreadWaitingMutex, timeout)) {
|
||||
osRtxThreadListPut(osRtxObject(mutex), thread);
|
||||
} else {
|
||||
EvrRtxMutexAcquireTimeout(mutex);
|
||||
}
|
||||
status = osErrorTimeout;
|
||||
} else {
|
||||
EvrRtxMutexNotAcquired(mutex);
|
||||
status = osErrorResource;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
/// Release a Mutex that was acquired by osMutexAcquire.
|
||||
/// \note API identical to osMutexRelease
|
||||
static osStatus_t svcRtxMutexRelease (osMutexId_t mutex_id) {
|
||||
os_mutex_t *mutex = osRtxMutexId(mutex_id);
|
||||
const os_mutex_t *mutex0;
|
||||
os_thread_t *thread;
|
||||
int8_t priority;
|
||||
|
||||
// Check running thread
|
||||
thread = osRtxThreadGetRunning();
|
||||
if (thread == NULL) {
|
||||
EvrRtxMutexError(mutex, osRtxErrorKernelNotRunning);
|
||||
//lint -e{904} "Return statement before end of function" [MISRA Note 1]
|
||||
return osError;
|
||||
}
|
||||
|
||||
// Check parameters
|
||||
if ((mutex == NULL) || (mutex->id != osRtxIdMutex)) {
|
||||
EvrRtxMutexError(mutex, (int32_t)osErrorParameter);
|
||||
//lint -e{904} "Return statement before end of function" [MISRA Note 1]
|
||||
return osErrorParameter;
|
||||
}
|
||||
|
||||
// Check if Mutex is not locked
|
||||
if (mutex->lock == 0U) {
|
||||
EvrRtxMutexError(mutex, osRtxErrorMutexNotLocked);
|
||||
//lint -e{904} "Return statement before end of function" [MISRA Note 1]
|
||||
return osErrorResource;
|
||||
}
|
||||
|
||||
// Check if running Thread is not the owner
|
||||
if (mutex->owner_thread != thread) {
|
||||
EvrRtxMutexError(mutex, osRtxErrorMutexNotOwned);
|
||||
//lint -e{904} "Return statement before end of function" [MISRA Note 1]
|
||||
return osErrorResource;
|
||||
}
|
||||
|
||||
// Decrement Lock counter
|
||||
mutex->lock--;
|
||||
EvrRtxMutexReleased(mutex, mutex->lock);
|
||||
|
||||
// Check Lock counter
|
||||
if (mutex->lock == 0U) {
|
||||
|
||||
// Remove Mutex from Thread owner list
|
||||
if (mutex->owner_next != NULL) {
|
||||
mutex->owner_next->owner_prev = mutex->owner_prev;
|
||||
}
|
||||
if (mutex->owner_prev != NULL) {
|
||||
mutex->owner_prev->owner_next = mutex->owner_next;
|
||||
} else {
|
||||
thread->mutex_list = mutex->owner_next;
|
||||
}
|
||||
|
||||
// Restore running Thread priority
|
||||
if ((mutex->attr & osMutexPrioInherit) != 0U) {
|
||||
priority = thread->priority_base;
|
||||
mutex0 = thread->mutex_list;
|
||||
// Check mutexes owned by running Thread
|
||||
while (mutex0 != NULL) {
|
||||
if ((mutex0->thread_list != NULL) && (mutex0->thread_list->priority > priority)) {
|
||||
// Higher priority Thread is waiting for Mutex
|
||||
priority = mutex0->thread_list->priority;
|
||||
}
|
||||
mutex0 = mutex0->owner_next;
|
||||
}
|
||||
thread->priority = priority;
|
||||
}
|
||||
|
||||
// Check if Thread is waiting for a Mutex
|
||||
if (mutex->thread_list != NULL) {
|
||||
// Wakeup waiting Thread with highest Priority
|
||||
thread = osRtxThreadListGet(osRtxObject(mutex));
|
||||
osRtxThreadWaitExit(thread, (uint32_t)osOK, FALSE);
|
||||
// Thread is the new Mutex owner
|
||||
mutex->owner_thread = thread;
|
||||
mutex->owner_prev = NULL;
|
||||
mutex->owner_next = thread->mutex_list;
|
||||
if (thread->mutex_list != NULL) {
|
||||
thread->mutex_list->owner_prev = mutex;
|
||||
}
|
||||
thread->mutex_list = mutex;
|
||||
mutex->lock = 1U;
|
||||
EvrRtxMutexAcquired(mutex, 1U);
|
||||
}
|
||||
|
||||
osRtxThreadDispatch(NULL);
|
||||
}
|
||||
|
||||
return osOK;
|
||||
}
|
||||
|
||||
/// Get Thread which owns a Mutex object.
|
||||
/// \note API identical to osMutexGetOwner
|
||||
static osThreadId_t svcRtxMutexGetOwner (osMutexId_t mutex_id) {
|
||||
os_mutex_t *mutex = osRtxMutexId(mutex_id);
|
||||
|
||||
// Check parameters
|
||||
if ((mutex == NULL) || (mutex->id != osRtxIdMutex)) {
|
||||
EvrRtxMutexGetOwner(mutex, NULL);
|
||||
//lint -e{904} "Return statement before end of function" [MISRA Note 1]
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// Check if Mutex is not locked
|
||||
if (mutex->lock == 0U) {
|
||||
EvrRtxMutexGetOwner(mutex, NULL);
|
||||
//lint -e{904} "Return statement before end of function" [MISRA Note 1]
|
||||
return NULL;
|
||||
}
|
||||
|
||||
EvrRtxMutexGetOwner(mutex, mutex->owner_thread);
|
||||
|
||||
return mutex->owner_thread;
|
||||
}
|
||||
|
||||
/// Delete a Mutex object.
|
||||
/// \note API identical to osMutexDelete
|
||||
static osStatus_t svcRtxMutexDelete (osMutexId_t mutex_id) {
|
||||
os_mutex_t *mutex = osRtxMutexId(mutex_id);
|
||||
const os_mutex_t *mutex0;
|
||||
os_thread_t *thread;
|
||||
int8_t priority;
|
||||
|
||||
// Check parameters
|
||||
if ((mutex == NULL) || (mutex->id != osRtxIdMutex)) {
|
||||
EvrRtxMutexError(mutex, (int32_t)osErrorParameter);
|
||||
//lint -e{904} "Return statement before end of function" [MISRA Note 1]
|
||||
return osErrorParameter;
|
||||
}
|
||||
|
||||
// Check if Mutex is locked
|
||||
if (mutex->lock != 0U) {
|
||||
|
||||
thread = mutex->owner_thread;
|
||||
|
||||
// Remove Mutex from Thread owner list
|
||||
if (mutex->owner_next != NULL) {
|
||||
mutex->owner_next->owner_prev = mutex->owner_prev;
|
||||
}
|
||||
if (mutex->owner_prev != NULL) {
|
||||
mutex->owner_prev->owner_next = mutex->owner_next;
|
||||
} else {
|
||||
thread->mutex_list = mutex->owner_next;
|
||||
}
|
||||
|
||||
// Restore owner Thread priority
|
||||
if ((mutex->attr & osMutexPrioInherit) != 0U) {
|
||||
priority = thread->priority_base;
|
||||
mutex0 = thread->mutex_list;
|
||||
// Check Mutexes owned by Thread
|
||||
while (mutex0 != NULL) {
|
||||
if ((mutex0->thread_list != NULL) && (mutex0->thread_list->priority > priority)) {
|
||||
// Higher priority Thread is waiting for Mutex
|
||||
priority = mutex0->thread_list->priority;
|
||||
}
|
||||
mutex0 = mutex0->owner_next;
|
||||
}
|
||||
if (thread->priority != priority) {
|
||||
thread->priority = priority;
|
||||
osRtxThreadListSort(thread);
|
||||
}
|
||||
}
|
||||
|
||||
// Unblock waiting threads
|
||||
while (mutex->thread_list != NULL) {
|
||||
thread = osRtxThreadListGet(osRtxObject(mutex));
|
||||
osRtxThreadWaitExit(thread, (uint32_t)osErrorResource, FALSE);
|
||||
}
|
||||
|
||||
osRtxThreadDispatch(NULL);
|
||||
}
|
||||
|
||||
// Mark object as invalid
|
||||
mutex->id = osRtxIdInvalid;
|
||||
|
||||
// Free object memory
|
||||
if ((mutex->flags & osRtxFlagSystemObject) != 0U) {
|
||||
if (osRtxInfo.mpi.mutex != NULL) {
|
||||
(void)osRtxMemoryPoolFree(osRtxInfo.mpi.mutex, mutex);
|
||||
} else {
|
||||
(void)osRtxMemoryFree(osRtxInfo.mem.common, mutex);
|
||||
}
|
||||
#if (defined(OS_OBJ_MEM_USAGE) && (OS_OBJ_MEM_USAGE != 0))
|
||||
osRtxMutexMemUsage.cnt_free++;
|
||||
#endif
|
||||
}
|
||||
|
||||
EvrRtxMutexDestroyed(mutex);
|
||||
|
||||
return osOK;
|
||||
}
|
||||
|
||||
// Service Calls definitions
|
||||
//lint ++flb "Library Begin" [MISRA Note 11]
|
||||
SVC0_1(MutexNew, osMutexId_t, const osMutexAttr_t *)
|
||||
SVC0_1(MutexGetName, const char *, osMutexId_t)
|
||||
SVC0_2(MutexAcquire, osStatus_t, osMutexId_t, uint32_t)
|
||||
SVC0_1(MutexRelease, osStatus_t, osMutexId_t)
|
||||
SVC0_1(MutexGetOwner, osThreadId_t, osMutexId_t)
|
||||
SVC0_1(MutexDelete, osStatus_t, osMutexId_t)
|
||||
//lint --flb "Library End"
|
||||
|
||||
|
||||
// ==== Public API ====
|
||||
|
||||
/// Create and Initialize a Mutex object.
|
||||
osMutexId_t osMutexNew (const osMutexAttr_t *attr) {
|
||||
osMutexId_t mutex_id;
|
||||
|
||||
EvrRtxMutexNew(attr);
|
||||
if (IsIrqMode() || IsIrqMasked()) {
|
||||
EvrRtxMutexError(NULL, (int32_t)osErrorISR);
|
||||
mutex_id = NULL;
|
||||
} else {
|
||||
mutex_id = __svcMutexNew(attr);
|
||||
}
|
||||
return mutex_id;
|
||||
}
|
||||
|
||||
/// Get name of a Mutex object.
|
||||
const char *osMutexGetName (osMutexId_t mutex_id) {
|
||||
const char *name;
|
||||
|
||||
if (IsIrqMode() || IsIrqMasked()) {
|
||||
EvrRtxMutexGetName(mutex_id, NULL);
|
||||
name = NULL;
|
||||
} else {
|
||||
name = __svcMutexGetName(mutex_id);
|
||||
}
|
||||
return name;
|
||||
}
|
||||
|
||||
/// Acquire a Mutex or timeout if it is locked.
|
||||
osStatus_t osMutexAcquire (osMutexId_t mutex_id, uint32_t timeout) {
|
||||
osStatus_t status;
|
||||
|
||||
EvrRtxMutexAcquire(mutex_id, timeout);
|
||||
if (IsIrqMode() || IsIrqMasked()) {
|
||||
EvrRtxMutexError(mutex_id, (int32_t)osErrorISR);
|
||||
status = osErrorISR;
|
||||
} else {
|
||||
status = __svcMutexAcquire(mutex_id, timeout);
|
||||
}
|
||||
return status;
|
||||
}
|
||||
|
||||
/// Release a Mutex that was acquired by \ref osMutexAcquire.
|
||||
osStatus_t osMutexRelease (osMutexId_t mutex_id) {
|
||||
osStatus_t status;
|
||||
|
||||
EvrRtxMutexRelease(mutex_id);
|
||||
if (IsIrqMode() || IsIrqMasked()) {
|
||||
EvrRtxMutexError(mutex_id, (int32_t)osErrorISR);
|
||||
status = osErrorISR;
|
||||
} else {
|
||||
status = __svcMutexRelease(mutex_id);
|
||||
}
|
||||
return status;
|
||||
}
|
||||
|
||||
/// Get Thread which owns a Mutex object.
|
||||
osThreadId_t osMutexGetOwner (osMutexId_t mutex_id) {
|
||||
osThreadId_t thread;
|
||||
|
||||
if (IsIrqMode() || IsIrqMasked()) {
|
||||
EvrRtxMutexGetOwner(mutex_id, NULL);
|
||||
thread = NULL;
|
||||
} else {
|
||||
thread = __svcMutexGetOwner(mutex_id);
|
||||
}
|
||||
return thread;
|
||||
}
|
||||
|
||||
/// Delete a Mutex object.
|
||||
osStatus_t osMutexDelete (osMutexId_t mutex_id) {
|
||||
osStatus_t status;
|
||||
|
||||
EvrRtxMutexDelete(mutex_id);
|
||||
if (IsIrqMode() || IsIrqMasked()) {
|
||||
EvrRtxMutexError(mutex_id, (int32_t)osErrorISR);
|
||||
status = osErrorISR;
|
||||
} else {
|
||||
status = __svcMutexDelete(mutex_id);
|
||||
}
|
||||
return status;
|
||||
}
|
||||
@@ -0,0 +1,507 @@
|
||||
/*
|
||||
* Copyright (c) 2013-2018 Arm Limited. All rights reserved.
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the License); you may
|
||||
* not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an AS IS BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
* -----------------------------------------------------------------------------
|
||||
*
|
||||
* Project: CMSIS-RTOS RTX
|
||||
* Title: Semaphore functions
|
||||
*
|
||||
* -----------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
#include "rtx_lib.h"
|
||||
|
||||
|
||||
// OS Runtime Object Memory Usage
|
||||
#if ((defined(OS_OBJ_MEM_USAGE) && (OS_OBJ_MEM_USAGE != 0)))
|
||||
osRtxObjectMemUsage_t osRtxSemaphoreMemUsage \
|
||||
__attribute__((section(".data.os.semaphore.obj"))) =
|
||||
{ 0U, 0U, 0U };
|
||||
#endif
|
||||
|
||||
|
||||
// ==== Helper functions ====
|
||||
|
||||
/// Decrement Semaphore tokens.
|
||||
/// \param[in] semaphore semaphore object.
|
||||
/// \return 1 - success, 0 - failure.
|
||||
static uint32_t SemaphoreTokenDecrement (os_semaphore_t *semaphore) {
|
||||
#if (EXCLUSIVE_ACCESS == 0)
|
||||
uint32_t primask = __get_PRIMASK();
|
||||
#endif
|
||||
uint32_t ret;
|
||||
|
||||
#if (EXCLUSIVE_ACCESS == 0)
|
||||
__disable_irq();
|
||||
|
||||
if (semaphore->tokens != 0U) {
|
||||
semaphore->tokens--;
|
||||
ret = 1U;
|
||||
} else {
|
||||
ret = 0U;
|
||||
}
|
||||
|
||||
if (primask == 0U) {
|
||||
__enable_irq();
|
||||
}
|
||||
#else
|
||||
if (atomic_dec16_nz(&semaphore->tokens) != 0U) {
|
||||
ret = 1U;
|
||||
} else {
|
||||
ret = 0U;
|
||||
}
|
||||
#endif
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/// Increment Semaphore tokens.
|
||||
/// \param[in] semaphore semaphore object.
|
||||
/// \return 1 - success, 0 - failure.
|
||||
static uint32_t SemaphoreTokenIncrement (os_semaphore_t *semaphore) {
|
||||
#if (EXCLUSIVE_ACCESS == 0)
|
||||
uint32_t primask = __get_PRIMASK();
|
||||
#endif
|
||||
uint32_t ret;
|
||||
|
||||
#if (EXCLUSIVE_ACCESS == 0)
|
||||
__disable_irq();
|
||||
|
||||
if (semaphore->tokens < semaphore->max_tokens) {
|
||||
semaphore->tokens++;
|
||||
ret = 1U;
|
||||
} else {
|
||||
ret = 0U;
|
||||
}
|
||||
|
||||
if (primask == 0U) {
|
||||
__enable_irq();
|
||||
}
|
||||
#else
|
||||
if (atomic_inc16_lt(&semaphore->tokens, semaphore->max_tokens) < semaphore->max_tokens) {
|
||||
ret = 1U;
|
||||
} else {
|
||||
ret = 0U;
|
||||
}
|
||||
#endif
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
// ==== Post ISR processing ====
|
||||
|
||||
/// Semaphore post ISR processing.
|
||||
/// \param[in] semaphore semaphore object.
|
||||
static void osRtxSemaphorePostProcess (os_semaphore_t *semaphore) {
|
||||
os_thread_t *thread;
|
||||
|
||||
// Check if Thread is waiting for a token
|
||||
if (semaphore->thread_list != NULL) {
|
||||
// Try to acquire token
|
||||
if (SemaphoreTokenDecrement(semaphore) != 0U) {
|
||||
// Wakeup waiting Thread with highest Priority
|
||||
thread = osRtxThreadListGet(osRtxObject(semaphore));
|
||||
osRtxThreadWaitExit(thread, (uint32_t)osOK, FALSE);
|
||||
EvrRtxSemaphoreAcquired(semaphore, semaphore->tokens);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// ==== Service Calls ====
|
||||
|
||||
/// Create and Initialize a Semaphore object.
|
||||
/// \note API identical to osSemaphoreNew
|
||||
static osSemaphoreId_t svcRtxSemaphoreNew (uint32_t max_count, uint32_t initial_count, const osSemaphoreAttr_t *attr) {
|
||||
os_semaphore_t *semaphore;
|
||||
uint8_t flags;
|
||||
const char *name;
|
||||
|
||||
// Check parameters
|
||||
if ((max_count == 0U) || (max_count > osRtxSemaphoreTokenLimit) || (initial_count > max_count)) {
|
||||
EvrRtxSemaphoreError(NULL, (int32_t)osErrorParameter);
|
||||
//lint -e{904} "Return statement before end of function" [MISRA Note 1]
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// Process attributes
|
||||
if (attr != NULL) {
|
||||
name = attr->name;
|
||||
//lint -e{9079} "conversion from pointer to void to pointer to other type" [MISRA Note 6]
|
||||
semaphore = attr->cb_mem;
|
||||
if (semaphore != NULL) {
|
||||
//lint -e(923) -e(9078) "cast from pointer to unsigned int" [MISRA Note 7]
|
||||
if ((((uint32_t)semaphore & 3U) != 0U) || (attr->cb_size < sizeof(os_semaphore_t))) {
|
||||
EvrRtxSemaphoreError(NULL, osRtxErrorInvalidControlBlock);
|
||||
//lint -e{904} "Return statement before end of function" [MISRA Note 1]
|
||||
return NULL;
|
||||
}
|
||||
} else {
|
||||
if (attr->cb_size != 0U) {
|
||||
EvrRtxSemaphoreError(NULL, osRtxErrorInvalidControlBlock);
|
||||
//lint -e{904} "Return statement before end of function" [MISRA Note 1]
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
name = NULL;
|
||||
semaphore = NULL;
|
||||
}
|
||||
|
||||
// Allocate object memory if not provided
|
||||
if (semaphore == NULL) {
|
||||
if (osRtxInfo.mpi.semaphore != NULL) {
|
||||
//lint -e{9079} "conversion from pointer to void to pointer to other type" [MISRA Note 5]
|
||||
semaphore = osRtxMemoryPoolAlloc(osRtxInfo.mpi.semaphore);
|
||||
} else {
|
||||
//lint -e{9079} "conversion from pointer to void to pointer to other type" [MISRA Note 5]
|
||||
semaphore = osRtxMemoryAlloc(osRtxInfo.mem.common, sizeof(os_semaphore_t), 1U);
|
||||
}
|
||||
#if (defined(OS_OBJ_MEM_USAGE) && (OS_OBJ_MEM_USAGE != 0))
|
||||
if (semaphore != NULL) {
|
||||
uint32_t used;
|
||||
osRtxSemaphoreMemUsage.cnt_alloc++;
|
||||
used = osRtxSemaphoreMemUsage.cnt_alloc - osRtxSemaphoreMemUsage.cnt_free;
|
||||
if (osRtxSemaphoreMemUsage.max_used < used) {
|
||||
osRtxSemaphoreMemUsage.max_used = used;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
flags = osRtxFlagSystemObject;
|
||||
} else {
|
||||
flags = 0U;
|
||||
}
|
||||
|
||||
if (semaphore != NULL) {
|
||||
// Initialize control block
|
||||
semaphore->id = osRtxIdSemaphore;
|
||||
semaphore->flags = flags;
|
||||
semaphore->name = name;
|
||||
semaphore->thread_list = NULL;
|
||||
semaphore->tokens = (uint16_t)initial_count;
|
||||
semaphore->max_tokens = (uint16_t)max_count;
|
||||
|
||||
// Register post ISR processing function
|
||||
osRtxInfo.post_process.semaphore = osRtxSemaphorePostProcess;
|
||||
|
||||
EvrRtxSemaphoreCreated(semaphore, semaphore->name);
|
||||
} else {
|
||||
EvrRtxSemaphoreError(NULL,(int32_t)osErrorNoMemory);
|
||||
}
|
||||
|
||||
return semaphore;
|
||||
}
|
||||
|
||||
/// Get name of a Semaphore object.
|
||||
/// \note API identical to osSemaphoreGetName
|
||||
static const char *svcRtxSemaphoreGetName (osSemaphoreId_t semaphore_id) {
|
||||
os_semaphore_t *semaphore = osRtxSemaphoreId(semaphore_id);
|
||||
|
||||
// Check parameters
|
||||
if ((semaphore == NULL) || (semaphore->id != osRtxIdSemaphore)) {
|
||||
EvrRtxSemaphoreGetName(semaphore, NULL);
|
||||
//lint -e{904} "Return statement before end of function" [MISRA Note 1]
|
||||
return NULL;
|
||||
}
|
||||
|
||||
EvrRtxSemaphoreGetName(semaphore, semaphore->name);
|
||||
|
||||
return semaphore->name;
|
||||
}
|
||||
|
||||
/// Acquire a Semaphore token or timeout if no tokens are available.
|
||||
/// \note API identical to osSemaphoreAcquire
|
||||
static osStatus_t svcRtxSemaphoreAcquire (osSemaphoreId_t semaphore_id, uint32_t timeout) {
|
||||
os_semaphore_t *semaphore = osRtxSemaphoreId(semaphore_id);
|
||||
osStatus_t status;
|
||||
|
||||
// Check parameters
|
||||
if ((semaphore == NULL) || (semaphore->id != osRtxIdSemaphore)) {
|
||||
EvrRtxSemaphoreError(semaphore, (int32_t)osErrorParameter);
|
||||
//lint -e{904} "Return statement before end of function" [MISRA Note 1]
|
||||
return osErrorParameter;
|
||||
}
|
||||
|
||||
// Try to acquire token
|
||||
if (SemaphoreTokenDecrement(semaphore) != 0U) {
|
||||
EvrRtxSemaphoreAcquired(semaphore, semaphore->tokens);
|
||||
status = osOK;
|
||||
} else {
|
||||
// No token available
|
||||
if (timeout != 0U) {
|
||||
EvrRtxSemaphoreAcquirePending(semaphore, timeout);
|
||||
// Suspend current Thread
|
||||
if (osRtxThreadWaitEnter(osRtxThreadWaitingSemaphore, timeout)) {
|
||||
osRtxThreadListPut(osRtxObject(semaphore), osRtxThreadGetRunning());
|
||||
} else {
|
||||
EvrRtxSemaphoreAcquireTimeout(semaphore);
|
||||
}
|
||||
status = osErrorTimeout;
|
||||
} else {
|
||||
EvrRtxSemaphoreNotAcquired(semaphore);
|
||||
status = osErrorResource;
|
||||
}
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
/// Release a Semaphore token that was acquired by osSemaphoreAcquire.
|
||||
/// \note API identical to osSemaphoreRelease
|
||||
static osStatus_t svcRtxSemaphoreRelease (osSemaphoreId_t semaphore_id) {
|
||||
os_semaphore_t *semaphore = osRtxSemaphoreId(semaphore_id);
|
||||
os_thread_t *thread;
|
||||
osStatus_t status;
|
||||
|
||||
// Check parameters
|
||||
if ((semaphore == NULL) || (semaphore->id != osRtxIdSemaphore)) {
|
||||
EvrRtxSemaphoreError(semaphore, (int32_t)osErrorParameter);
|
||||
//lint -e{904} "Return statement before end of function" [MISRA Note 1]
|
||||
return osErrorParameter;
|
||||
}
|
||||
|
||||
// Check if Thread is waiting for a token
|
||||
if (semaphore->thread_list != NULL) {
|
||||
EvrRtxSemaphoreReleased(semaphore, semaphore->tokens);
|
||||
// Wakeup waiting Thread with highest Priority
|
||||
thread = osRtxThreadListGet(osRtxObject(semaphore));
|
||||
osRtxThreadWaitExit(thread, (uint32_t)osOK, TRUE);
|
||||
EvrRtxSemaphoreAcquired(semaphore, semaphore->tokens);
|
||||
status = osOK;
|
||||
} else {
|
||||
// Try to release token
|
||||
if (SemaphoreTokenIncrement(semaphore) != 0U) {
|
||||
EvrRtxSemaphoreReleased(semaphore, semaphore->tokens);
|
||||
status = osOK;
|
||||
} else {
|
||||
EvrRtxSemaphoreError(semaphore, osRtxErrorSemaphoreCountLimit);
|
||||
status = osErrorResource;
|
||||
}
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
/// Get current Semaphore token count.
|
||||
/// \note API identical to osSemaphoreGetCount
|
||||
static uint32_t svcRtxSemaphoreGetCount (osSemaphoreId_t semaphore_id) {
|
||||
os_semaphore_t *semaphore = osRtxSemaphoreId(semaphore_id);
|
||||
|
||||
// Check parameters
|
||||
if ((semaphore == NULL) || (semaphore->id != osRtxIdSemaphore)) {
|
||||
EvrRtxSemaphoreGetCount(semaphore, 0U);
|
||||
//lint -e{904} "Return statement before end of function" [MISRA Note 1]
|
||||
return 0U;
|
||||
}
|
||||
|
||||
EvrRtxSemaphoreGetCount(semaphore, semaphore->tokens);
|
||||
|
||||
return semaphore->tokens;
|
||||
}
|
||||
|
||||
/// Delete a Semaphore object.
|
||||
/// \note API identical to osSemaphoreDelete
|
||||
static osStatus_t svcRtxSemaphoreDelete (osSemaphoreId_t semaphore_id) {
|
||||
os_semaphore_t *semaphore = osRtxSemaphoreId(semaphore_id);
|
||||
os_thread_t *thread;
|
||||
|
||||
// Check parameters
|
||||
if ((semaphore == NULL) || (semaphore->id != osRtxIdSemaphore)) {
|
||||
EvrRtxSemaphoreError(semaphore, (int32_t)osErrorParameter);
|
||||
//lint -e{904} "Return statement before end of function" [MISRA Note 1]
|
||||
return osErrorParameter;
|
||||
}
|
||||
|
||||
// Unblock waiting threads
|
||||
if (semaphore->thread_list != NULL) {
|
||||
do {
|
||||
thread = osRtxThreadListGet(osRtxObject(semaphore));
|
||||
osRtxThreadWaitExit(thread, (uint32_t)osErrorResource, FALSE);
|
||||
} while (semaphore->thread_list != NULL);
|
||||
osRtxThreadDispatch(NULL);
|
||||
}
|
||||
|
||||
// Mark object as invalid
|
||||
semaphore->id = osRtxIdInvalid;
|
||||
|
||||
// Free object memory
|
||||
if ((semaphore->flags & osRtxFlagSystemObject) != 0U) {
|
||||
if (osRtxInfo.mpi.semaphore != NULL) {
|
||||
(void)osRtxMemoryPoolFree(osRtxInfo.mpi.semaphore, semaphore);
|
||||
} else {
|
||||
(void)osRtxMemoryFree(osRtxInfo.mem.common, semaphore);
|
||||
}
|
||||
#if (defined(OS_OBJ_MEM_USAGE) && (OS_OBJ_MEM_USAGE != 0))
|
||||
osRtxSemaphoreMemUsage.cnt_free++;
|
||||
#endif
|
||||
}
|
||||
|
||||
EvrRtxSemaphoreDestroyed(semaphore);
|
||||
|
||||
return osOK;
|
||||
}
|
||||
|
||||
// Service Calls definitions
|
||||
//lint ++flb "Library Begin" [MISRA Note 11]
|
||||
SVC0_3(SemaphoreNew, osSemaphoreId_t, uint32_t, uint32_t, const osSemaphoreAttr_t *)
|
||||
SVC0_1(SemaphoreGetName, const char *, osSemaphoreId_t)
|
||||
SVC0_2(SemaphoreAcquire, osStatus_t, osSemaphoreId_t, uint32_t)
|
||||
SVC0_1(SemaphoreRelease, osStatus_t, osSemaphoreId_t)
|
||||
SVC0_1(SemaphoreGetCount, uint32_t, osSemaphoreId_t)
|
||||
SVC0_1(SemaphoreDelete, osStatus_t, osSemaphoreId_t)
|
||||
//lint --flb "Library End"
|
||||
|
||||
|
||||
// ==== ISR Calls ====
|
||||
|
||||
/// Acquire a Semaphore token or timeout if no tokens are available.
|
||||
/// \note API identical to osSemaphoreAcquire
|
||||
__STATIC_INLINE
|
||||
osStatus_t isrRtxSemaphoreAcquire (osSemaphoreId_t semaphore_id, uint32_t timeout) {
|
||||
os_semaphore_t *semaphore = osRtxSemaphoreId(semaphore_id);
|
||||
osStatus_t status;
|
||||
|
||||
// Check parameters
|
||||
if ((semaphore == NULL) || (semaphore->id != osRtxIdSemaphore) || (timeout != 0U)) {
|
||||
EvrRtxSemaphoreError(semaphore, (int32_t)osErrorParameter);
|
||||
//lint -e{904} "Return statement before end of function" [MISRA Note 1]
|
||||
return osErrorParameter;
|
||||
}
|
||||
|
||||
// Try to acquire token
|
||||
if (SemaphoreTokenDecrement(semaphore) != 0U) {
|
||||
EvrRtxSemaphoreAcquired(semaphore, semaphore->tokens);
|
||||
status = osOK;
|
||||
} else {
|
||||
// No token available
|
||||
EvrRtxSemaphoreNotAcquired(semaphore);
|
||||
status = osErrorResource;
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
/// Release a Semaphore token that was acquired by osSemaphoreAcquire.
|
||||
/// \note API identical to osSemaphoreRelease
|
||||
__STATIC_INLINE
|
||||
osStatus_t isrRtxSemaphoreRelease (osSemaphoreId_t semaphore_id) {
|
||||
os_semaphore_t *semaphore = osRtxSemaphoreId(semaphore_id);
|
||||
osStatus_t status;
|
||||
|
||||
// Check parameters
|
||||
if ((semaphore == NULL) || (semaphore->id != osRtxIdSemaphore)) {
|
||||
EvrRtxSemaphoreError(semaphore, (int32_t)osErrorParameter);
|
||||
//lint -e{904} "Return statement before end of function" [MISRA Note 1]
|
||||
return osErrorParameter;
|
||||
}
|
||||
|
||||
// Try to release token
|
||||
if (SemaphoreTokenIncrement(semaphore) != 0U) {
|
||||
// Register post ISR processing
|
||||
osRtxPostProcess(osRtxObject(semaphore));
|
||||
EvrRtxSemaphoreReleased(semaphore, semaphore->tokens);
|
||||
status = osOK;
|
||||
} else {
|
||||
EvrRtxSemaphoreError(semaphore, osRtxErrorSemaphoreCountLimit);
|
||||
status = osErrorResource;
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
|
||||
// ==== Public API ====
|
||||
|
||||
/// Create and Initialize a Semaphore object.
|
||||
osSemaphoreId_t osSemaphoreNew (uint32_t max_count, uint32_t initial_count, const osSemaphoreAttr_t *attr) {
|
||||
osSemaphoreId_t semaphore_id;
|
||||
|
||||
EvrRtxSemaphoreNew(max_count, initial_count, attr);
|
||||
if (IsIrqMode() || IsIrqMasked()) {
|
||||
EvrRtxSemaphoreError(NULL, (int32_t)osErrorISR);
|
||||
semaphore_id = NULL;
|
||||
} else {
|
||||
semaphore_id = __svcSemaphoreNew(max_count, initial_count, attr);
|
||||
}
|
||||
return semaphore_id;
|
||||
}
|
||||
|
||||
/// Get name of a Semaphore object.
|
||||
const char *osSemaphoreGetName (osSemaphoreId_t semaphore_id) {
|
||||
const char *name;
|
||||
|
||||
if (IsIrqMode() || IsIrqMasked()) {
|
||||
EvrRtxSemaphoreGetName(semaphore_id, NULL);
|
||||
name = NULL;
|
||||
} else {
|
||||
name = __svcSemaphoreGetName(semaphore_id);
|
||||
}
|
||||
return name;
|
||||
}
|
||||
|
||||
/// Acquire a Semaphore token or timeout if no tokens are available.
|
||||
osStatus_t osSemaphoreAcquire (osSemaphoreId_t semaphore_id, uint32_t timeout) {
|
||||
osStatus_t status;
|
||||
|
||||
EvrRtxSemaphoreAcquire(semaphore_id, timeout);
|
||||
if (IsIrqMode() || IsIrqMasked()) {
|
||||
status = isrRtxSemaphoreAcquire(semaphore_id, timeout);
|
||||
} else {
|
||||
status = __svcSemaphoreAcquire(semaphore_id, timeout);
|
||||
}
|
||||
return status;
|
||||
}
|
||||
|
||||
/// Release a Semaphore token that was acquired by osSemaphoreAcquire.
|
||||
osStatus_t osSemaphoreRelease (osSemaphoreId_t semaphore_id) {
|
||||
osStatus_t status;
|
||||
|
||||
EvrRtxSemaphoreRelease(semaphore_id);
|
||||
if (IsIrqMode() || IsIrqMasked()) {
|
||||
status = isrRtxSemaphoreRelease(semaphore_id);
|
||||
} else {
|
||||
status = __svcSemaphoreRelease(semaphore_id);
|
||||
}
|
||||
return status;
|
||||
}
|
||||
|
||||
/// Get current Semaphore token count.
|
||||
uint32_t osSemaphoreGetCount (osSemaphoreId_t semaphore_id) {
|
||||
uint32_t count;
|
||||
|
||||
if (IsIrqMode() || IsIrqMasked()) {
|
||||
count = svcRtxSemaphoreGetCount(semaphore_id);
|
||||
} else {
|
||||
count = __svcSemaphoreGetCount(semaphore_id);
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
/// Delete a Semaphore object.
|
||||
osStatus_t osSemaphoreDelete (osSemaphoreId_t semaphore_id) {
|
||||
osStatus_t status;
|
||||
|
||||
EvrRtxSemaphoreDelete(semaphore_id);
|
||||
if (IsIrqMode() || IsIrqMasked()) {
|
||||
EvrRtxSemaphoreError(semaphore_id, (int32_t)osErrorISR);
|
||||
status = osErrorISR;
|
||||
} else {
|
||||
status = __svcSemaphoreDelete(semaphore_id);
|
||||
}
|
||||
return status;
|
||||
}
|
||||
@@ -0,0 +1,213 @@
|
||||
/*
|
||||
* Copyright (c) 2013-2019 Arm Limited. All rights reserved.
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the License); you may
|
||||
* not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an AS IS BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
* -----------------------------------------------------------------------------
|
||||
*
|
||||
* Project: CMSIS-RTOS RTX
|
||||
* Title: System functions
|
||||
*
|
||||
* -----------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
#include "rtx_lib.h"
|
||||
|
||||
|
||||
// ==== Helper functions ====
|
||||
|
||||
/// Put Object into ISR Queue.
|
||||
/// \param[in] object object.
|
||||
/// \return 1 - success, 0 - failure.
|
||||
static uint32_t isr_queue_put (os_object_t *object) {
|
||||
#if (EXCLUSIVE_ACCESS == 0)
|
||||
uint32_t primask = __get_PRIMASK();
|
||||
#else
|
||||
uint32_t n;
|
||||
#endif
|
||||
uint16_t max;
|
||||
uint32_t ret;
|
||||
|
||||
max = osRtxInfo.isr_queue.max;
|
||||
|
||||
#if (EXCLUSIVE_ACCESS == 0)
|
||||
__disable_irq();
|
||||
|
||||
if (osRtxInfo.isr_queue.cnt < max) {
|
||||
osRtxInfo.isr_queue.cnt++;
|
||||
osRtxInfo.isr_queue.data[osRtxInfo.isr_queue.in] = object;
|
||||
if (++osRtxInfo.isr_queue.in == max) {
|
||||
osRtxInfo.isr_queue.in = 0U;
|
||||
}
|
||||
ret = 1U;
|
||||
} else {
|
||||
ret = 0U;
|
||||
}
|
||||
|
||||
if (primask == 0U) {
|
||||
__enable_irq();
|
||||
}
|
||||
#else
|
||||
if (atomic_inc16_lt(&osRtxInfo.isr_queue.cnt, max) < max) {
|
||||
n = atomic_inc16_lim(&osRtxInfo.isr_queue.in, max);
|
||||
osRtxInfo.isr_queue.data[n] = object;
|
||||
ret = 1U;
|
||||
} else {
|
||||
ret = 0U;
|
||||
}
|
||||
#endif
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/// Get Object from ISR Queue.
|
||||
/// \return object or NULL.
|
||||
static os_object_t *isr_queue_get (void) {
|
||||
#if (EXCLUSIVE_ACCESS != 0)
|
||||
uint32_t n;
|
||||
#endif
|
||||
uint16_t max;
|
||||
os_object_t *ret;
|
||||
|
||||
max = osRtxInfo.isr_queue.max;
|
||||
|
||||
#if (EXCLUSIVE_ACCESS == 0)
|
||||
__disable_irq();
|
||||
|
||||
if (osRtxInfo.isr_queue.cnt != 0U) {
|
||||
osRtxInfo.isr_queue.cnt--;
|
||||
ret = osRtxObject(osRtxInfo.isr_queue.data[osRtxInfo.isr_queue.out]);
|
||||
if (++osRtxInfo.isr_queue.out == max) {
|
||||
osRtxInfo.isr_queue.out = 0U;
|
||||
}
|
||||
} else {
|
||||
ret = NULL;
|
||||
}
|
||||
|
||||
__enable_irq();
|
||||
#else
|
||||
if (atomic_dec16_nz(&osRtxInfo.isr_queue.cnt) != 0U) {
|
||||
n = atomic_inc16_lim(&osRtxInfo.isr_queue.out, max);
|
||||
ret = osRtxObject(osRtxInfo.isr_queue.data[n]);
|
||||
} else {
|
||||
ret = NULL;
|
||||
}
|
||||
#endif
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
// ==== Library Functions ====
|
||||
|
||||
/// Tick Handler.
|
||||
//lint -esym(714,osRtxTick_Handler) "Referenced by Exception handlers"
|
||||
//lint -esym(759,osRtxTick_Handler) "Prototype in header"
|
||||
//lint -esym(765,osRtxTick_Handler) "Global scope"
|
||||
void osRtxTick_Handler (void) {
|
||||
os_thread_t *thread;
|
||||
|
||||
OS_Tick_AcknowledgeIRQ();
|
||||
osRtxInfo.kernel.tick++;
|
||||
|
||||
// Process Timers
|
||||
if (osRtxInfo.timer.tick != NULL) {
|
||||
osRtxInfo.timer.tick();
|
||||
}
|
||||
|
||||
// Process Thread Delays
|
||||
osRtxThreadDelayTick();
|
||||
|
||||
osRtxThreadDispatch(NULL);
|
||||
|
||||
// Check Round Robin timeout
|
||||
if (osRtxInfo.thread.robin.timeout != 0U) {
|
||||
if (osRtxInfo.thread.robin.thread != osRtxInfo.thread.run.next) {
|
||||
// Reset Round Robin
|
||||
osRtxInfo.thread.robin.thread = osRtxInfo.thread.run.next;
|
||||
osRtxInfo.thread.robin.tick = osRtxInfo.thread.robin.timeout;
|
||||
} else {
|
||||
if (osRtxInfo.thread.robin.tick != 0U) {
|
||||
osRtxInfo.thread.robin.tick--;
|
||||
}
|
||||
if (osRtxInfo.thread.robin.tick == 0U) {
|
||||
// Round Robin Timeout
|
||||
if (osRtxKernelGetState() == osRtxKernelRunning) {
|
||||
thread = osRtxInfo.thread.ready.thread_list;
|
||||
if ((thread != NULL) && (thread->priority == osRtxInfo.thread.robin.thread->priority)) {
|
||||
osRtxThreadListRemove(thread);
|
||||
osRtxThreadReadyPut(osRtxInfo.thread.robin.thread);
|
||||
EvrRtxThreadPreempted(osRtxInfo.thread.robin.thread);
|
||||
osRtxThreadSwitch(thread);
|
||||
osRtxInfo.thread.robin.thread = thread;
|
||||
osRtxInfo.thread.robin.tick = osRtxInfo.thread.robin.timeout;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Pending Service Call Handler.
|
||||
//lint -esym(714,osRtxPendSV_Handler) "Referenced by Exception handlers"
|
||||
//lint -esym(759,osRtxPendSV_Handler) "Prototype in header"
|
||||
//lint -esym(765,osRtxPendSV_Handler) "Global scope"
|
||||
void osRtxPendSV_Handler (void) {
|
||||
os_object_t *object;
|
||||
|
||||
for (;;) {
|
||||
object = isr_queue_get();
|
||||
if (object == NULL) {
|
||||
break;
|
||||
}
|
||||
switch (object->id) {
|
||||
case osRtxIdThread:
|
||||
osRtxInfo.post_process.thread(osRtxThreadObject(object));
|
||||
break;
|
||||
case osRtxIdEventFlags:
|
||||
osRtxInfo.post_process.event_flags(osRtxEventFlagsObject(object));
|
||||
break;
|
||||
case osRtxIdSemaphore:
|
||||
osRtxInfo.post_process.semaphore(osRtxSemaphoreObject(object));
|
||||
break;
|
||||
case osRtxIdMemoryPool:
|
||||
osRtxInfo.post_process.memory_pool(osRtxMemoryPoolObject(object));
|
||||
break;
|
||||
case osRtxIdMessage:
|
||||
osRtxInfo.post_process.message(osRtxMessageObject(object));
|
||||
break;
|
||||
default:
|
||||
// Should never come here
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
osRtxThreadDispatch(NULL);
|
||||
}
|
||||
|
||||
/// Register post ISR processing.
|
||||
/// \param[in] object generic object.
|
||||
void osRtxPostProcess (os_object_t *object) {
|
||||
|
||||
if (isr_queue_put(object) != 0U) {
|
||||
if (osRtxInfo.kernel.blocked == 0U) {
|
||||
SetPendSV();
|
||||
} else {
|
||||
osRtxInfo.kernel.pendSV = 1U;
|
||||
}
|
||||
} else {
|
||||
(void)osRtxErrorNotify(osRtxErrorISRQueueOverflow, object);
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,459 @@
|
||||
/*
|
||||
* Copyright (c) 2013-2019 Arm Limited. All rights reserved.
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the License); you may
|
||||
* not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an AS IS BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
* -----------------------------------------------------------------------------
|
||||
*
|
||||
* Project: CMSIS-RTOS RTX
|
||||
* Title: Timer functions
|
||||
*
|
||||
* -----------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
#include "rtx_lib.h"
|
||||
|
||||
|
||||
// OS Runtime Object Memory Usage
|
||||
#if ((defined(OS_OBJ_MEM_USAGE) && (OS_OBJ_MEM_USAGE != 0)))
|
||||
osRtxObjectMemUsage_t osRtxTimerMemUsage \
|
||||
__attribute__((section(".data.os.timer.obj"))) =
|
||||
{ 0U, 0U, 0U };
|
||||
#endif
|
||||
|
||||
|
||||
// ==== Helper functions ====
|
||||
|
||||
/// Insert Timer into the Timer List sorted by Time.
|
||||
/// \param[in] timer timer object.
|
||||
/// \param[in] tick timer tick.
|
||||
static void TimerInsert (os_timer_t *timer, uint32_t tick) {
|
||||
os_timer_t *prev, *next;
|
||||
|
||||
prev = NULL;
|
||||
next = osRtxInfo.timer.list;
|
||||
while ((next != NULL) && (next->tick <= tick)) {
|
||||
tick -= next->tick;
|
||||
prev = next;
|
||||
next = next->next;
|
||||
}
|
||||
timer->tick = tick;
|
||||
timer->prev = prev;
|
||||
timer->next = next;
|
||||
if (next != NULL) {
|
||||
next->tick -= timer->tick;
|
||||
next->prev = timer;
|
||||
}
|
||||
if (prev != NULL) {
|
||||
prev->next = timer;
|
||||
} else {
|
||||
osRtxInfo.timer.list = timer;
|
||||
}
|
||||
}
|
||||
|
||||
/// Remove Timer from the Timer List.
|
||||
/// \param[in] timer timer object.
|
||||
static void TimerRemove (const os_timer_t *timer) {
|
||||
|
||||
if (timer->next != NULL) {
|
||||
timer->next->tick += timer->tick;
|
||||
timer->next->prev = timer->prev;
|
||||
}
|
||||
if (timer->prev != NULL) {
|
||||
timer->prev->next = timer->next;
|
||||
} else {
|
||||
osRtxInfo.timer.list = timer->next;
|
||||
}
|
||||
}
|
||||
|
||||
/// Unlink Timer from the Timer List Head.
|
||||
/// \param[in] timer timer object.
|
||||
static void TimerUnlink (const os_timer_t *timer) {
|
||||
|
||||
if (timer->next != NULL) {
|
||||
timer->next->prev = timer->prev;
|
||||
}
|
||||
osRtxInfo.timer.list = timer->next;
|
||||
}
|
||||
|
||||
|
||||
// ==== Library functions ====
|
||||
|
||||
/// Timer Tick (called each SysTick).
|
||||
static void osRtxTimerTick (void) {
|
||||
os_timer_t *timer;
|
||||
osStatus_t status;
|
||||
|
||||
timer = osRtxInfo.timer.list;
|
||||
if (timer == NULL) {
|
||||
//lint -e{904} "Return statement before end of function" [MISRA Note 1]
|
||||
return;
|
||||
}
|
||||
|
||||
timer->tick--;
|
||||
while ((timer != NULL) && (timer->tick == 0U)) {
|
||||
TimerUnlink(timer);
|
||||
status = osMessageQueuePut(osRtxInfo.timer.mq, &timer->finfo, 0U, 0U);
|
||||
if (status != osOK) {
|
||||
(void)osRtxErrorNotify(osRtxErrorTimerQueueOverflow, timer);
|
||||
}
|
||||
if (timer->type == osRtxTimerPeriodic) {
|
||||
TimerInsert(timer, timer->load);
|
||||
} else {
|
||||
timer->state = osRtxTimerStopped;
|
||||
}
|
||||
timer = osRtxInfo.timer.list;
|
||||
}
|
||||
}
|
||||
|
||||
/// Timer Thread
|
||||
__WEAK __NO_RETURN void osRtxTimerThread (void *argument) {
|
||||
os_timer_finfo_t finfo;
|
||||
osStatus_t status;
|
||||
(void) argument;
|
||||
|
||||
osRtxInfo.timer.mq = osRtxMessageQueueId(
|
||||
osMessageQueueNew(osRtxConfig.timer_mq_mcnt, sizeof(os_timer_finfo_t), osRtxConfig.timer_mq_attr)
|
||||
);
|
||||
osRtxInfo.timer.tick = osRtxTimerTick;
|
||||
|
||||
for (;;) {
|
||||
//lint -e{934} "Taking address of near auto variable"
|
||||
status = osMessageQueueGet(osRtxInfo.timer.mq, &finfo, NULL, osWaitForever);
|
||||
if (status == osOK) {
|
||||
EvrRtxTimerCallback(finfo.func, finfo.arg);
|
||||
(finfo.func)(finfo.arg);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ==== Service Calls ====
|
||||
|
||||
/// Create and Initialize a timer.
|
||||
/// \note API identical to osTimerNew
|
||||
static osTimerId_t svcRtxTimerNew (osTimerFunc_t func, osTimerType_t type, void *argument, const osTimerAttr_t *attr) {
|
||||
os_timer_t *timer;
|
||||
uint8_t flags;
|
||||
const char *name;
|
||||
|
||||
// Check parameters
|
||||
if ((func == NULL) || ((type != osTimerOnce) && (type != osTimerPeriodic))) {
|
||||
EvrRtxTimerError(NULL, (int32_t)osErrorParameter);
|
||||
//lint -e{904} "Return statement before end of function" [MISRA Note 1]
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// Process attributes
|
||||
if (attr != NULL) {
|
||||
name = attr->name;
|
||||
//lint -e{9079} "conversion from pointer to void to pointer to other type" [MISRA Note 6]
|
||||
timer = attr->cb_mem;
|
||||
if (timer != NULL) {
|
||||
//lint -e(923) -e(9078) "cast from pointer to unsigned int" [MISRA Note 7]
|
||||
if ((((uint32_t)timer & 3U) != 0U) || (attr->cb_size < sizeof(os_timer_t))) {
|
||||
EvrRtxTimerError(NULL, osRtxErrorInvalidControlBlock);
|
||||
//lint -e{904} "Return statement before end of function" [MISRA Note 1]
|
||||
return NULL;
|
||||
}
|
||||
} else {
|
||||
if (attr->cb_size != 0U) {
|
||||
EvrRtxTimerError(NULL, osRtxErrorInvalidControlBlock);
|
||||
//lint -e{904} "Return statement before end of function" [MISRA Note 1]
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
name = NULL;
|
||||
timer = NULL;
|
||||
}
|
||||
|
||||
// Allocate object memory if not provided
|
||||
if (timer == NULL) {
|
||||
if (osRtxInfo.mpi.timer != NULL) {
|
||||
//lint -e{9079} "conversion from pointer to void to pointer to other type" [MISRA Note 5]
|
||||
timer = osRtxMemoryPoolAlloc(osRtxInfo.mpi.timer);
|
||||
} else {
|
||||
//lint -e{9079} "conversion from pointer to void to pointer to other type" [MISRA Note 5]
|
||||
timer = osRtxMemoryAlloc(osRtxInfo.mem.common, sizeof(os_timer_t), 1U);
|
||||
}
|
||||
#if (defined(OS_OBJ_MEM_USAGE) && (OS_OBJ_MEM_USAGE != 0))
|
||||
if (timer != NULL) {
|
||||
uint32_t used;
|
||||
osRtxTimerMemUsage.cnt_alloc++;
|
||||
used = osRtxTimerMemUsage.cnt_alloc - osRtxTimerMemUsage.cnt_free;
|
||||
if (osRtxTimerMemUsage.max_used < used) {
|
||||
osRtxTimerMemUsage.max_used = used;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
flags = osRtxFlagSystemObject;
|
||||
} else {
|
||||
flags = 0U;
|
||||
}
|
||||
|
||||
if (timer != NULL) {
|
||||
// Initialize control block
|
||||
timer->id = osRtxIdTimer;
|
||||
timer->state = osRtxTimerStopped;
|
||||
timer->flags = flags;
|
||||
timer->type = (uint8_t)type;
|
||||
timer->name = name;
|
||||
timer->prev = NULL;
|
||||
timer->next = NULL;
|
||||
timer->tick = 0U;
|
||||
timer->load = 0U;
|
||||
timer->finfo.func = func;
|
||||
timer->finfo.arg = argument;
|
||||
|
||||
EvrRtxTimerCreated(timer, timer->name);
|
||||
} else {
|
||||
EvrRtxTimerError(NULL, (int32_t)osErrorNoMemory);
|
||||
}
|
||||
|
||||
return timer;
|
||||
}
|
||||
|
||||
/// Get name of a timer.
|
||||
/// \note API identical to osTimerGetName
|
||||
static const char *svcRtxTimerGetName (osTimerId_t timer_id) {
|
||||
os_timer_t *timer = osRtxTimerId(timer_id);
|
||||
|
||||
// Check parameters
|
||||
if ((timer == NULL) || (timer->id != osRtxIdTimer)) {
|
||||
EvrRtxTimerGetName(timer, NULL);
|
||||
//lint -e{904} "Return statement before end of function" [MISRA Note 1]
|
||||
return NULL;
|
||||
}
|
||||
|
||||
EvrRtxTimerGetName(timer, timer->name);
|
||||
|
||||
return timer->name;
|
||||
}
|
||||
|
||||
/// Start or restart a timer.
|
||||
/// \note API identical to osTimerStart
|
||||
static osStatus_t svcRtxTimerStart (osTimerId_t timer_id, uint32_t ticks) {
|
||||
os_timer_t *timer = osRtxTimerId(timer_id);
|
||||
|
||||
// Check parameters
|
||||
if ((timer == NULL) || (timer->id != osRtxIdTimer) || (ticks == 0U)) {
|
||||
EvrRtxTimerError(timer, (int32_t)osErrorParameter);
|
||||
//lint -e{904} "Return statement before end of function" [MISRA Note 1]
|
||||
return osErrorParameter;
|
||||
}
|
||||
|
||||
if (timer->state == osRtxTimerRunning) {
|
||||
TimerRemove(timer);
|
||||
} else {
|
||||
if (osRtxInfo.timer.tick == NULL) {
|
||||
EvrRtxTimerError(timer, (int32_t)osErrorResource);
|
||||
//lint -e{904} "Return statement before end of function" [MISRA Note 1]
|
||||
return osErrorResource;
|
||||
} else {
|
||||
timer->state = osRtxTimerRunning;
|
||||
timer->load = ticks;
|
||||
}
|
||||
}
|
||||
|
||||
TimerInsert(timer, ticks);
|
||||
|
||||
EvrRtxTimerStarted(timer);
|
||||
|
||||
return osOK;
|
||||
}
|
||||
|
||||
/// Stop a timer.
|
||||
/// \note API identical to osTimerStop
|
||||
static osStatus_t svcRtxTimerStop (osTimerId_t timer_id) {
|
||||
os_timer_t *timer = osRtxTimerId(timer_id);
|
||||
|
||||
// Check parameters
|
||||
if ((timer == NULL) || (timer->id != osRtxIdTimer)) {
|
||||
EvrRtxTimerError(timer, (int32_t)osErrorParameter);
|
||||
//lint -e{904} "Return statement before end of function" [MISRA Note 1]
|
||||
return osErrorParameter;
|
||||
}
|
||||
|
||||
// Check object state
|
||||
if (timer->state != osRtxTimerRunning) {
|
||||
EvrRtxTimerError(timer, (int32_t)osErrorResource);
|
||||
//lint -e{904} "Return statement before end of function" [MISRA Note 1]
|
||||
return osErrorResource;
|
||||
}
|
||||
|
||||
timer->state = osRtxTimerStopped;
|
||||
|
||||
TimerRemove(timer);
|
||||
|
||||
EvrRtxTimerStopped(timer);
|
||||
|
||||
return osOK;
|
||||
}
|
||||
|
||||
/// Check if a timer is running.
|
||||
/// \note API identical to osTimerIsRunning
|
||||
static uint32_t svcRtxTimerIsRunning (osTimerId_t timer_id) {
|
||||
os_timer_t *timer = osRtxTimerId(timer_id);
|
||||
uint32_t is_running;
|
||||
|
||||
// Check parameters
|
||||
if ((timer == NULL) || (timer->id != osRtxIdTimer)) {
|
||||
EvrRtxTimerIsRunning(timer, 0U);
|
||||
//lint -e{904} "Return statement before end of function" [MISRA Note 1]
|
||||
return 0U;
|
||||
}
|
||||
|
||||
if (timer->state == osRtxTimerRunning) {
|
||||
EvrRtxTimerIsRunning(timer, 1U);
|
||||
is_running = 1U;
|
||||
} else {
|
||||
EvrRtxTimerIsRunning(timer, 0U);
|
||||
is_running = 0;
|
||||
}
|
||||
|
||||
return is_running;
|
||||
}
|
||||
|
||||
/// Delete a timer.
|
||||
/// \note API identical to osTimerDelete
|
||||
static osStatus_t svcRtxTimerDelete (osTimerId_t timer_id) {
|
||||
os_timer_t *timer = osRtxTimerId(timer_id);
|
||||
|
||||
// Check parameters
|
||||
if ((timer == NULL) || (timer->id != osRtxIdTimer)) {
|
||||
EvrRtxTimerError(timer, (int32_t)osErrorParameter);
|
||||
//lint -e{904} "Return statement before end of function" [MISRA Note 1]
|
||||
return osErrorParameter;
|
||||
}
|
||||
|
||||
if (timer->state == osRtxTimerRunning) {
|
||||
TimerRemove(timer);
|
||||
}
|
||||
|
||||
// Mark object as inactive and invalid
|
||||
timer->state = osRtxTimerInactive;
|
||||
timer->id = osRtxIdInvalid;
|
||||
|
||||
// Free object memory
|
||||
if ((timer->flags & osRtxFlagSystemObject) != 0U) {
|
||||
if (osRtxInfo.mpi.timer != NULL) {
|
||||
(void)osRtxMemoryPoolFree(osRtxInfo.mpi.timer, timer);
|
||||
} else {
|
||||
(void)osRtxMemoryFree(osRtxInfo.mem.common, timer);
|
||||
}
|
||||
#if (defined(OS_OBJ_MEM_USAGE) && (OS_OBJ_MEM_USAGE != 0))
|
||||
osRtxTimerMemUsage.cnt_free++;
|
||||
#endif
|
||||
}
|
||||
|
||||
EvrRtxTimerDestroyed(timer);
|
||||
|
||||
return osOK;
|
||||
}
|
||||
|
||||
// Service Calls definitions
|
||||
//lint ++flb "Library Begin" [MISRA Note 11]
|
||||
SVC0_4(TimerNew, osTimerId_t, osTimerFunc_t, osTimerType_t, void *, const osTimerAttr_t *)
|
||||
SVC0_1(TimerGetName, const char *, osTimerId_t)
|
||||
SVC0_2(TimerStart, osStatus_t, osTimerId_t, uint32_t)
|
||||
SVC0_1(TimerStop, osStatus_t, osTimerId_t)
|
||||
SVC0_1(TimerIsRunning, uint32_t, osTimerId_t)
|
||||
SVC0_1(TimerDelete, osStatus_t, osTimerId_t)
|
||||
//lint --flb "Library End"
|
||||
|
||||
|
||||
// ==== Public API ====
|
||||
|
||||
/// Create and Initialize a timer.
|
||||
osTimerId_t osTimerNew (osTimerFunc_t func, osTimerType_t type, void *argument, const osTimerAttr_t *attr) {
|
||||
osTimerId_t timer_id;
|
||||
|
||||
EvrRtxTimerNew(func, type, argument, attr);
|
||||
if (IsIrqMode() || IsIrqMasked()) {
|
||||
EvrRtxTimerError(NULL, (int32_t)osErrorISR);
|
||||
timer_id = NULL;
|
||||
} else {
|
||||
timer_id = __svcTimerNew(func, type, argument, attr);
|
||||
}
|
||||
return timer_id;
|
||||
}
|
||||
|
||||
/// Get name of a timer.
|
||||
const char *osTimerGetName (osTimerId_t timer_id) {
|
||||
const char *name;
|
||||
|
||||
if (IsIrqMode() || IsIrqMasked()) {
|
||||
EvrRtxTimerGetName(timer_id, NULL);
|
||||
name = NULL;
|
||||
} else {
|
||||
name = __svcTimerGetName(timer_id);
|
||||
}
|
||||
return name;
|
||||
}
|
||||
|
||||
/// Start or restart a timer.
|
||||
osStatus_t osTimerStart (osTimerId_t timer_id, uint32_t ticks) {
|
||||
osStatus_t status;
|
||||
|
||||
EvrRtxTimerStart(timer_id, ticks);
|
||||
if (IsIrqMode() || IsIrqMasked()) {
|
||||
EvrRtxTimerError(timer_id, (int32_t)osErrorISR);
|
||||
status = osErrorISR;
|
||||
} else {
|
||||
status = __svcTimerStart(timer_id, ticks);
|
||||
}
|
||||
return status;
|
||||
}
|
||||
|
||||
/// Stop a timer.
|
||||
osStatus_t osTimerStop (osTimerId_t timer_id) {
|
||||
osStatus_t status;
|
||||
|
||||
EvrRtxTimerStop(timer_id);
|
||||
if (IsIrqMode() || IsIrqMasked()) {
|
||||
EvrRtxTimerError(timer_id, (int32_t)osErrorISR);
|
||||
status = osErrorISR;
|
||||
} else {
|
||||
status = __svcTimerStop(timer_id);
|
||||
}
|
||||
return status;
|
||||
}
|
||||
|
||||
/// Check if a timer is running.
|
||||
uint32_t osTimerIsRunning (osTimerId_t timer_id) {
|
||||
uint32_t is_running;
|
||||
|
||||
if (IsIrqMode() || IsIrqMasked()) {
|
||||
EvrRtxTimerIsRunning(timer_id, 0U);
|
||||
is_running = 0U;
|
||||
} else {
|
||||
is_running = __svcTimerIsRunning(timer_id);
|
||||
}
|
||||
return is_running;
|
||||
}
|
||||
|
||||
/// Delete a timer.
|
||||
osStatus_t osTimerDelete (osTimerId_t timer_id) {
|
||||
osStatus_t status;
|
||||
|
||||
EvrRtxTimerDelete(timer_id);
|
||||
if (IsIrqMode() || IsIrqMasked()) {
|
||||
EvrRtxTimerError(timer_id, (int32_t)osErrorISR);
|
||||
status = osErrorISR;
|
||||
} else {
|
||||
status = __svcTimerDelete(timer_id);
|
||||
}
|
||||
return status;
|
||||
}
|
||||
@@ -0,0 +1,51 @@
|
||||
#include "cmsis_os2.h" // CMSIS RTOS header file
|
||||
|
||||
/*----------------------------------------------------------------------------
|
||||
* Event Flags creation & usage
|
||||
*---------------------------------------------------------------------------*/
|
||||
|
||||
#define FLAGS_MSK1 0x00000001U
|
||||
|
||||
osEventFlagsId_t evt_id; // event flasg id
|
||||
|
||||
osThreadId_t tid_Thread_EventSender; // thread id 1
|
||||
osThreadId_t tid_Thread_EventReceiver; // thread id 2
|
||||
|
||||
void Thread_EventSender (void *argument); // thread function 1
|
||||
void Thread_EventReceiver (void *argument); // thread function 2
|
||||
|
||||
int Init_Events (void) {
|
||||
|
||||
evt_id = osEventFlagsNew(NULL);
|
||||
if (evt_id == NULL) {
|
||||
; // Event Flags object not created, handle failure
|
||||
}
|
||||
|
||||
tid_Thread_EventSender = osThreadNew(Thread_EventSender, NULL, NULL);
|
||||
if (tid_Thread_EventSender == NULL) {
|
||||
return(-1);
|
||||
}
|
||||
tid_Thread_EventReceiver = osThreadNew(Thread_EventReceiver, NULL, NULL);
|
||||
if (tid_Thread_EventReceiver == NULL) {
|
||||
return(-1);
|
||||
}
|
||||
|
||||
return(0);
|
||||
}
|
||||
|
||||
void Thread_EventSender (void *argument) {
|
||||
|
||||
while (1) {
|
||||
osEventFlagsSet(evt_id, FLAGS_MSK1);
|
||||
osThreadYield(); // suspend thread
|
||||
}
|
||||
}
|
||||
|
||||
void Thread_EventReceiver (void *argument) {
|
||||
uint32_t flags;
|
||||
|
||||
while (1) {
|
||||
flags = osEventFlagsWait(evt_id, FLAGS_MSK1, osFlagsWaitAny, osWaitForever);
|
||||
//handle event
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,62 @@
|
||||
#include "cmsis_os2.h" // CMSIS RTOS header file
|
||||
|
||||
/*----------------------------------------------------------------------------
|
||||
* Memory Pool creation & usage
|
||||
*---------------------------------------------------------------------------*/
|
||||
|
||||
#define MEMPOOL_OBJECTS 16 // number of Memory Pool Objects
|
||||
|
||||
typedef struct { // object data type
|
||||
uint8_t Buf[32];
|
||||
uint8_t Idx;
|
||||
} MEM_BLOCK_t;
|
||||
|
||||
osMemoryPoolId_t mpid_MemPool; // memory pool id
|
||||
|
||||
osThreadId_t tid_Thread_MemPool; // thread id
|
||||
|
||||
void Thread_MemPool (void *argument); // thread function
|
||||
|
||||
int Init_MemPool (void) {
|
||||
|
||||
mpid_MemPool = osMemoryPoolNew(MEMPOOL_OBJECTS, sizeof(MEM_BLOCK_t), NULL);
|
||||
if (mpid_MemPool == NULL) {
|
||||
; // MemPool object not created, handle failure
|
||||
}
|
||||
|
||||
tid_Thread_MemPool = osThreadNew(Thread_MemPool, NULL, NULL);
|
||||
if (tid_Thread_MemPool == NULL) {
|
||||
return(-1);
|
||||
}
|
||||
|
||||
return(0);
|
||||
}
|
||||
|
||||
void Thread_MemPool (void *argument) {
|
||||
MEM_BLOCK_t *pMem;
|
||||
osStatus_t status;
|
||||
|
||||
while (1) {
|
||||
; // Insert thread code here...
|
||||
|
||||
pMem = (MEM_BLOCK_t *)osMemoryPoolAlloc(mpid_MemPool, 0U); // get Mem Block
|
||||
if (pMem != NULL) { // Mem Block was available
|
||||
pMem->Buf[0] = 0x55U; // do some work...
|
||||
pMem->Idx = 0U;
|
||||
|
||||
status = osMemoryPoolFree(mpid_MemPool, pMem); // free mem block
|
||||
switch (status) {
|
||||
case osOK:
|
||||
break;
|
||||
case osErrorParameter:
|
||||
break;
|
||||
case osErrorNoMemory:
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
osThreadYield(); // suspend thread
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,64 @@
|
||||
#include "cmsis_os2.h" // CMSIS RTOS header file
|
||||
|
||||
/*----------------------------------------------------------------------------
|
||||
* Message Queue creation & usage
|
||||
*---------------------------------------------------------------------------*/
|
||||
|
||||
#define MSGQUEUE_OBJECTS 16 // number of Message Queue Objects
|
||||
|
||||
typedef struct { // object data type
|
||||
uint8_t Buf[32];
|
||||
uint8_t Idx;
|
||||
} MSGQUEUE_OBJ_t;
|
||||
|
||||
osMessageQueueId_t mid_MsgQueue; // message queue id
|
||||
|
||||
osThreadId_t tid_Thread_MsgQueue1; // thread id 1
|
||||
osThreadId_t tid_Thread_MsgQueue2; // thread id 2
|
||||
|
||||
void Thread_MsgQueue1 (void *argument); // thread function 1
|
||||
void Thread_MsgQueue2 (void *argument); // thread function 2
|
||||
|
||||
int Init_MsgQueue (void) {
|
||||
|
||||
mid_MsgQueue = osMessageQueueNew(MSGQUEUE_OBJECTS, sizeof(MSGQUEUE_OBJ_t), NULL);
|
||||
if (mid_MsgQueue == NULL) {
|
||||
; // Message Queue object not created, handle failure
|
||||
}
|
||||
|
||||
tid_Thread_MsgQueue1 = osThreadNew(Thread_MsgQueue1, NULL, NULL);
|
||||
if (tid_Thread_MsgQueue1 == NULL) {
|
||||
return(-1);
|
||||
}
|
||||
tid_Thread_MsgQueue2 = osThreadNew(Thread_MsgQueue2, NULL, NULL);
|
||||
if (tid_Thread_MsgQueue2 == NULL) {
|
||||
return(-1);
|
||||
}
|
||||
|
||||
return(0);
|
||||
}
|
||||
|
||||
void Thread_MsgQueue1 (void *argument) {
|
||||
MSGQUEUE_OBJ_t msg;
|
||||
|
||||
while (1) {
|
||||
; // Insert thread code here...
|
||||
msg.Buf[0] = 0x55U; // do some work...
|
||||
msg.Idx = 0U;
|
||||
osMessageQueuePut(mid_MsgQueue, &msg, 0U, 0U);
|
||||
osThreadYield(); // suspend thread
|
||||
}
|
||||
}
|
||||
|
||||
void Thread_MsgQueue2 (void *argument) {
|
||||
MSGQUEUE_OBJ_t msg;
|
||||
osStatus_t status;
|
||||
|
||||
while (1) {
|
||||
; // Insert thread code here...
|
||||
status = osMessageQueueGet(mid_MsgQueue, &msg, NULL, 0U); // wait for message
|
||||
if (status == osOK) {
|
||||
; // process data
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,52 @@
|
||||
#include "cmsis_os2.h" // CMSIS RTOS header file
|
||||
|
||||
/*----------------------------------------------------------------------------
|
||||
* Mutex creation & usage
|
||||
*---------------------------------------------------------------------------*/
|
||||
|
||||
osMutexId_t mid_Mutex; // mutex id
|
||||
|
||||
osThreadId_t tid_Thread_Mutex; // thread id
|
||||
|
||||
void Thread_Mutex (void *argument); // thread function
|
||||
|
||||
int Init_Mutex (void) {
|
||||
|
||||
mid_Mutex = osMutexNew(NULL);
|
||||
if (mid_Mutex == NULL) {
|
||||
; // Mutex object not created, handle failure
|
||||
}
|
||||
|
||||
tid_Thread_Mutex = osThreadNew(Thread_Mutex, NULL, NULL);
|
||||
if (tid_Thread_Mutex == NULL) {
|
||||
return(-1);
|
||||
}
|
||||
|
||||
return(0);
|
||||
}
|
||||
|
||||
void Thread_Mutex (void *argument) {
|
||||
osStatus_t status;
|
||||
|
||||
while (1) {
|
||||
; // Insert thread code here...
|
||||
|
||||
status = osMutexAcquire(mid_Mutex, 0U);
|
||||
switch (status) {
|
||||
case osOK:
|
||||
; // Use protected code here...
|
||||
osMutexRelease(mid_Mutex);
|
||||
break;
|
||||
case osErrorResource:
|
||||
break;
|
||||
case osErrorParameter:
|
||||
break;
|
||||
case osErrorISR:
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
osThreadYield(); // suspend thread
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
#include "cmsis_os2.h" // CMSIS RTOS header file
|
||||
|
||||
/*----------------------------------------------------------------------------
|
||||
* Semaphore creation & usage
|
||||
*---------------------------------------------------------------------------*/
|
||||
|
||||
osSemaphoreId_t sid_Semaphore; // semaphore id
|
||||
|
||||
osThreadId_t tid_Thread_Semaphore; // thread id
|
||||
|
||||
void Thread_Semaphore (void *argument); // thread function
|
||||
|
||||
int Init_Semaphore (void) {
|
||||
|
||||
sid_Semaphore = osSemaphoreNew(2U, 2U, NULL);
|
||||
if (sid_Semaphore == NULL) {
|
||||
; // Semaphore object not created, handle failure
|
||||
}
|
||||
|
||||
tid_Thread_Semaphore = osThreadNew(Thread_Semaphore, NULL, NULL);
|
||||
if (tid_Thread_Semaphore == NULL) {
|
||||
return(-1);
|
||||
}
|
||||
|
||||
return(0);
|
||||
}
|
||||
|
||||
void Thread_Semaphore (void *argument) {
|
||||
int32_t val;
|
||||
|
||||
while (1) {
|
||||
; // Insert thread code here...
|
||||
|
||||
val = osSemaphoreAcquire(sid_Semaphore, 10U); // wait 10 mSec
|
||||
switch (val) {
|
||||
case osOK:
|
||||
; // Use protected code here...
|
||||
osSemaphoreRelease(sid_Semaphore); // return a token back to a semaphore
|
||||
break;
|
||||
case osErrorResource:
|
||||
break;
|
||||
case osErrorParameter:
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
osThreadYield(); // suspend thread
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
#include "cmsis_os2.h" // CMSIS RTOS header file
|
||||
|
||||
/*----------------------------------------------------------------------------
|
||||
* Thread 1 'Thread_Name': Sample thread
|
||||
*---------------------------------------------------------------------------*/
|
||||
|
||||
osThreadId_t tid_Thread; // thread id
|
||||
|
||||
void Thread (void *argument); // thread function
|
||||
|
||||
int Init_Thread (void) {
|
||||
|
||||
tid_Thread = osThreadNew(Thread, NULL, NULL);
|
||||
if (tid_Thread == NULL) {
|
||||
return(-1);
|
||||
}
|
||||
|
||||
return(0);
|
||||
}
|
||||
|
||||
void Thread (void *argument) {
|
||||
|
||||
while (1) {
|
||||
; // Insert thread code here...
|
||||
osThreadYield(); // suspend thread
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,51 @@
|
||||
#include "cmsis_os2.h" // CMSIS RTOS header file
|
||||
|
||||
/*----------------------------------------------------------------------------
|
||||
* Timer: Sample timer functions
|
||||
*---------------------------------------------------------------------------*/
|
||||
|
||||
/*----- One-Shoot Timer Example -----*/
|
||||
osTimerId_t tim_id1; // timer id
|
||||
static uint32_t exec1; // argument for the timer call back function
|
||||
|
||||
// One-Shoot Timer Function
|
||||
static void Timer1_Callback (void const *arg) {
|
||||
// add user code here
|
||||
}
|
||||
|
||||
/*----- Periodic Timer Example -----*/
|
||||
osTimerId_t tim_id2; // timer id
|
||||
static uint32_t exec2; // argument for the timer call back function
|
||||
|
||||
// Periodic Timer Function
|
||||
static void Timer2_Callback (void const *arg) {
|
||||
// add user code here
|
||||
}
|
||||
|
||||
// Example: Create and Start timers
|
||||
int Init_Timers (void) {
|
||||
osStatus_t status; // function return status
|
||||
|
||||
// Create one-shoot timer
|
||||
exec1 = 1U;
|
||||
tim_id1 = osTimerNew((osTimerFunc_t)&Timer1_Callback, osTimerOnce, &exec1, NULL);
|
||||
if (tim_id1 != NULL) { // One-shot timer created
|
||||
// start timer with delay 100ms
|
||||
status = osTimerStart(tim_id1, 100U);
|
||||
if (status != osOK) {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
// Create periodic timer
|
||||
exec2 = 2U;
|
||||
tim_id2 = osTimerNew((osTimerFunc_t)&Timer2_Callback, osTimerPeriodic, &exec2, NULL);
|
||||
if (tim_id2 != NULL) { // Periodic timer created
|
||||
// start timer with periodic 1000ms interval
|
||||
status = osTimerStart(tim_id2, 1000U);
|
||||
if (status != osOK) {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
/*----------------------------------------------------------------------------
|
||||
* CMSIS-RTOS 'main' function template
|
||||
*---------------------------------------------------------------------------*/
|
||||
|
||||
#include "RTE_Components.h"
|
||||
#include CMSIS_device_header
|
||||
#include "cmsis_os2.h"
|
||||
|
||||
/*----------------------------------------------------------------------------
|
||||
* Application main thread
|
||||
*---------------------------------------------------------------------------*/
|
||||
__NO_RETURN static void app_main (void *argument) {
|
||||
(void)argument;
|
||||
// ...
|
||||
for (;;) {}
|
||||
}
|
||||
|
||||
int main (void) {
|
||||
|
||||
// System Initialization
|
||||
SystemCoreClockUpdate();
|
||||
// ...
|
||||
|
||||
osKernelInitialize(); // Initialize CMSIS-RTOS
|
||||
osThreadNew(app_main, NULL, NULL); // Create application main thread
|
||||
osKernelStart(); // Start thread execution
|
||||
for (;;) {}
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
/*
|
||||
* Copyright (c) 2013-2018 Arm Limited. All rights reserved.
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the License); you may
|
||||
* not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an AS IS BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
* -----------------------------------------------------------------------------
|
||||
*
|
||||
* Project: CMSIS-RTOS RTX
|
||||
* Title: SVC User Table
|
||||
*
|
||||
* -----------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
#define USER_SVC_COUNT 0 // Number of user SVC functions
|
||||
|
||||
extern void * const osRtxUserSVC[1+USER_SVC_COUNT];
|
||||
void * const osRtxUserSVC[1+USER_SVC_COUNT] = {
|
||||
(void *)USER_SVC_COUNT,
|
||||
//(void *)user_function1,
|
||||
// ...
|
||||
};
|
||||
@@ -0,0 +1,133 @@
|
||||
/**************************************************************************//**
|
||||
* @file os_systick.c
|
||||
* @brief CMSIS OS Tick SysTick implementation
|
||||
* @version V1.0.2
|
||||
* @date 6. March 2020
|
||||
******************************************************************************/
|
||||
/*
|
||||
* Copyright (c) 2017-2020 ARM Limited. All rights reserved.
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the License); you may
|
||||
* not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an AS IS BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include "os_tick.h"
|
||||
|
||||
//lint -emacro((923,9078),SCB,SysTick) "cast from unsigned long to pointer"
|
||||
#include "RTE_Components.h"
|
||||
#include CMSIS_device_header
|
||||
|
||||
#ifdef SysTick
|
||||
|
||||
#ifndef SYSTICK_IRQ_PRIORITY
|
||||
#define SYSTICK_IRQ_PRIORITY 0xFFU
|
||||
#endif
|
||||
|
||||
static uint8_t PendST;
|
||||
|
||||
// Setup OS Tick.
|
||||
__WEAK int32_t OS_Tick_Setup (uint32_t freq, IRQHandler_t handler) {
|
||||
uint32_t load;
|
||||
(void)handler;
|
||||
|
||||
if (freq == 0U) {
|
||||
//lint -e{904} "Return statement before end of function"
|
||||
return (-1);
|
||||
}
|
||||
|
||||
load = (SystemCoreClock / freq) - 1U;
|
||||
if (load > 0x00FFFFFFU) {
|
||||
//lint -e{904} "Return statement before end of function"
|
||||
return (-1);
|
||||
}
|
||||
|
||||
// Set SysTick Interrupt Priority
|
||||
#if ((defined(__ARM_ARCH_8M_MAIN__) && (__ARM_ARCH_8M_MAIN__ != 0)) || \
|
||||
(defined(__ARM_ARCH_8_1M_MAIN__) && (__ARM_ARCH_8_1M_MAIN__ != 0)) || \
|
||||
(defined(__CORTEX_M) && (__CORTEX_M == 7U)))
|
||||
SCB->SHPR[11] = SYSTICK_IRQ_PRIORITY;
|
||||
#elif (defined(__ARM_ARCH_8M_BASE__) && (__ARM_ARCH_8M_BASE__ != 0))
|
||||
SCB->SHPR[1] |= ((uint32_t)SYSTICK_IRQ_PRIORITY << 24);
|
||||
#elif ((defined(__ARM_ARCH_7M__) && (__ARM_ARCH_7M__ != 0)) || \
|
||||
(defined(__ARM_ARCH_7EM__) && (__ARM_ARCH_7EM__ != 0)))
|
||||
SCB->SHP[11] = SYSTICK_IRQ_PRIORITY;
|
||||
#elif (defined(__ARM_ARCH_6M__) && (__ARM_ARCH_6M__ != 0))
|
||||
SCB->SHP[1] |= ((uint32_t)SYSTICK_IRQ_PRIORITY << 24);
|
||||
#else
|
||||
#error "Unknown ARM Core!"
|
||||
#endif
|
||||
|
||||
SysTick->CTRL = SysTick_CTRL_CLKSOURCE_Msk | SysTick_CTRL_TICKINT_Msk;
|
||||
SysTick->LOAD = load;
|
||||
SysTick->VAL = 0U;
|
||||
|
||||
PendST = 0U;
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
/// Enable OS Tick.
|
||||
__WEAK void OS_Tick_Enable (void) {
|
||||
|
||||
if (PendST != 0U) {
|
||||
PendST = 0U;
|
||||
SCB->ICSR = SCB_ICSR_PENDSTSET_Msk;
|
||||
}
|
||||
|
||||
SysTick->CTRL |= SysTick_CTRL_ENABLE_Msk;
|
||||
}
|
||||
|
||||
/// Disable OS Tick.
|
||||
__WEAK void OS_Tick_Disable (void) {
|
||||
|
||||
SysTick->CTRL &= ~SysTick_CTRL_ENABLE_Msk;
|
||||
|
||||
if ((SCB->ICSR & SCB_ICSR_PENDSTSET_Msk) != 0U) {
|
||||
SCB->ICSR = SCB_ICSR_PENDSTCLR_Msk;
|
||||
PendST = 1U;
|
||||
}
|
||||
}
|
||||
|
||||
// Acknowledge OS Tick IRQ.
|
||||
__WEAK void OS_Tick_AcknowledgeIRQ (void) {
|
||||
(void)SysTick->CTRL;
|
||||
}
|
||||
|
||||
// Get OS Tick IRQ number.
|
||||
__WEAK int32_t OS_Tick_GetIRQn (void) {
|
||||
return ((int32_t)SysTick_IRQn);
|
||||
}
|
||||
|
||||
// Get OS Tick clock.
|
||||
__WEAK uint32_t OS_Tick_GetClock (void) {
|
||||
return (SystemCoreClock);
|
||||
}
|
||||
|
||||
// Get OS Tick interval.
|
||||
__WEAK uint32_t OS_Tick_GetInterval (void) {
|
||||
return (SysTick->LOAD + 1U);
|
||||
}
|
||||
|
||||
// Get OS Tick count value.
|
||||
__WEAK uint32_t OS_Tick_GetCount (void) {
|
||||
uint32_t load = SysTick->LOAD;
|
||||
return (load - SysTick->VAL);
|
||||
}
|
||||
|
||||
// Get OS Tick overflow status.
|
||||
__WEAK uint32_t OS_Tick_GetOverflow (void) {
|
||||
return ((SysTick->CTRL >> 16) & 1U);
|
||||
}
|
||||
|
||||
#endif // SysTick
|
||||
@@ -0,0 +1,187 @@
|
||||
/**************************************************************************//**
|
||||
* @file os_tick_gtim.c
|
||||
* @brief CMSIS OS Tick implementation for Generic Timer
|
||||
* @version V1.0.1
|
||||
* @date 24. November 2017
|
||||
******************************************************************************/
|
||||
/*
|
||||
* Copyright (c) 2017 ARM Limited. All rights reserved.
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the License); you may
|
||||
* not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an AS IS BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include "os_tick.h"
|
||||
#include "irq_ctrl.h"
|
||||
|
||||
#include "RTE_Components.h"
|
||||
#include CMSIS_device_header
|
||||
|
||||
#ifndef GTIM_IRQ_PRIORITY
|
||||
#define GTIM_IRQ_PRIORITY 0xFFU
|
||||
#endif
|
||||
|
||||
#ifndef GTIM_IRQ_NUM
|
||||
#define GTIM_IRQ_NUM SecurePhyTimer_IRQn
|
||||
#endif
|
||||
|
||||
// Timer interrupt pending flag
|
||||
static uint8_t GTIM_PendIRQ;
|
||||
|
||||
// Timer tick frequency
|
||||
static uint32_t GTIM_Clock;
|
||||
|
||||
// Timer load value
|
||||
static uint32_t GTIM_Load;
|
||||
|
||||
// Setup OS Tick.
|
||||
int32_t OS_Tick_Setup (uint32_t freq, IRQHandler_t handler) {
|
||||
uint32_t prio, bits;
|
||||
|
||||
if (freq == 0U) {
|
||||
return (-1);
|
||||
}
|
||||
|
||||
GTIM_PendIRQ = 0U;
|
||||
|
||||
// Get timer clock
|
||||
#ifdef SCTR_BASE
|
||||
GTIM_Clock = *(uint32_t*)(SCTR_BASE+0x20);
|
||||
#else
|
||||
// FVP REFCLK CNTControl 100MHz
|
||||
GTIM_Clock = 100000000UL;
|
||||
#endif
|
||||
|
||||
PL1_SetCounterFrequency(GTIM_Clock);
|
||||
|
||||
// Calculate load value
|
||||
GTIM_Load = (GTIM_Clock / freq) - 1U;
|
||||
|
||||
// Disable Generic Timer and set load value
|
||||
PL1_SetControl(0U);
|
||||
PL1_SetLoadValue(GTIM_Load);
|
||||
|
||||
// Disable corresponding IRQ
|
||||
IRQ_Disable(GTIM_IRQ_NUM);
|
||||
IRQ_ClearPending(GTIM_IRQ_NUM);
|
||||
|
||||
// Determine number of implemented priority bits
|
||||
IRQ_SetPriority(GTIM_IRQ_NUM, 0xFFU);
|
||||
|
||||
prio = IRQ_GetPriority(GTIM_IRQ_NUM);
|
||||
|
||||
// At least bits [7:4] must be implemented
|
||||
if ((prio & 0xF0U) == 0U) {
|
||||
return (-1);
|
||||
}
|
||||
|
||||
for (bits = 0; bits < 4; bits++) {
|
||||
if ((prio & 0x01) != 0) {
|
||||
break;
|
||||
}
|
||||
prio >>= 1;
|
||||
}
|
||||
|
||||
// Adjust configured priority to the number of implemented priority bits
|
||||
prio = (GTIM_IRQ_PRIORITY << bits) & 0xFFUL;
|
||||
|
||||
// Set Private Timer interrupt priority
|
||||
IRQ_SetPriority(GTIM_IRQ_NUM, prio-1U);
|
||||
|
||||
// Set edge-triggered IRQ
|
||||
IRQ_SetMode(GTIM_IRQ_NUM, IRQ_MODE_TRIG_EDGE);
|
||||
|
||||
// Register tick interrupt handler function
|
||||
IRQ_SetHandler(GTIM_IRQ_NUM, handler);
|
||||
|
||||
// Enable corresponding interrupt
|
||||
IRQ_Enable(GTIM_IRQ_NUM);
|
||||
|
||||
// Enable system counter and timer control
|
||||
#ifdef SCTR_BASE
|
||||
*(uint32_t*)SCTR_BASE |= 3U;
|
||||
#endif
|
||||
|
||||
// Enable timer control
|
||||
PL1_SetControl(1U);
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
/// Enable OS Tick.
|
||||
void OS_Tick_Enable (void) {
|
||||
uint32_t ctrl;
|
||||
|
||||
// Set pending interrupt if flag set
|
||||
if (GTIM_PendIRQ != 0U) {
|
||||
GTIM_PendIRQ = 0U;
|
||||
IRQ_SetPending (GTIM_IRQ_NUM);
|
||||
}
|
||||
|
||||
// Start the Private Timer
|
||||
ctrl = PL1_GetControl();
|
||||
// Set bit: Timer enable
|
||||
ctrl |= 1U;
|
||||
PL1_SetControl(ctrl);
|
||||
}
|
||||
|
||||
/// Disable OS Tick.
|
||||
void OS_Tick_Disable (void) {
|
||||
uint32_t ctrl;
|
||||
|
||||
// Stop the Private Timer
|
||||
ctrl = PL1_GetControl();
|
||||
// Clear bit: Timer enable
|
||||
ctrl &= ~1U;
|
||||
PL1_SetControl(ctrl);
|
||||
|
||||
// Remember pending interrupt flag
|
||||
if (IRQ_GetPending(GTIM_IRQ_NUM) != 0) {
|
||||
IRQ_ClearPending(GTIM_IRQ_NUM);
|
||||
GTIM_PendIRQ = 1U;
|
||||
}
|
||||
}
|
||||
|
||||
// Acknowledge OS Tick IRQ.
|
||||
void OS_Tick_AcknowledgeIRQ (void) {
|
||||
IRQ_ClearPending (GTIM_IRQ_NUM);
|
||||
PL1_SetLoadValue(GTIM_Load);
|
||||
}
|
||||
|
||||
// Get OS Tick IRQ number.
|
||||
int32_t OS_Tick_GetIRQn (void) {
|
||||
return (GTIM_IRQ_NUM);
|
||||
}
|
||||
|
||||
// Get OS Tick clock.
|
||||
uint32_t OS_Tick_GetClock (void) {
|
||||
return (GTIM_Clock);
|
||||
}
|
||||
|
||||
// Get OS Tick interval.
|
||||
uint32_t OS_Tick_GetInterval (void) {
|
||||
return (GTIM_Load + 1U);
|
||||
}
|
||||
|
||||
// Get OS Tick count value.
|
||||
uint32_t OS_Tick_GetCount (void) {
|
||||
return (GTIM_Load - PL1_GetCurrentValue());
|
||||
}
|
||||
|
||||
// Get OS Tick overflow status.
|
||||
uint32_t OS_Tick_GetOverflow (void) {
|
||||
CNTP_CTL_Type cntp_ctl;
|
||||
cntp_ctl.w = PL1_GetControl();
|
||||
return (cntp_ctl.b.ISTATUS);
|
||||
}
|
||||
@@ -0,0 +1,165 @@
|
||||
/**************************************************************************//**
|
||||
* @file os_tick_ptim.c
|
||||
* @brief CMSIS OS Tick implementation for Private Timer
|
||||
* @version V1.0.2
|
||||
* @date 02. March 2018
|
||||
******************************************************************************/
|
||||
/*
|
||||
* Copyright (c) 2017-2018 Arm Limited. All rights reserved.
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the License); you may
|
||||
* not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an AS IS BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include "RTE_Components.h"
|
||||
#include CMSIS_device_header
|
||||
|
||||
#if defined(PTIM)
|
||||
|
||||
#include "os_tick.h"
|
||||
#include "irq_ctrl.h"
|
||||
|
||||
#ifndef PTIM_IRQ_PRIORITY
|
||||
#define PTIM_IRQ_PRIORITY 0xFFU
|
||||
#endif
|
||||
|
||||
static uint8_t PTIM_PendIRQ; // Timer interrupt pending flag
|
||||
|
||||
// Setup OS Tick.
|
||||
int32_t OS_Tick_Setup (uint32_t freq, IRQHandler_t handler) {
|
||||
uint32_t load;
|
||||
uint32_t prio;
|
||||
uint32_t bits;
|
||||
|
||||
if (freq == 0U) {
|
||||
return (-1);
|
||||
}
|
||||
|
||||
PTIM_PendIRQ = 0U;
|
||||
|
||||
// Private Timer runs with the system frequency
|
||||
load = (SystemCoreClock / freq) - 1U;
|
||||
|
||||
// Disable Private Timer and set load value
|
||||
PTIM_SetControl (0U);
|
||||
PTIM_SetLoadValue (load);
|
||||
|
||||
// Disable corresponding IRQ
|
||||
IRQ_Disable (PrivTimer_IRQn);
|
||||
IRQ_ClearPending(PrivTimer_IRQn);
|
||||
|
||||
// Determine number of implemented priority bits
|
||||
IRQ_SetPriority (PrivTimer_IRQn, 0xFFU);
|
||||
|
||||
prio = IRQ_GetPriority (PrivTimer_IRQn);
|
||||
|
||||
// At least bits [7:4] must be implemented
|
||||
if ((prio & 0xF0U) == 0U) {
|
||||
return (-1);
|
||||
}
|
||||
|
||||
for (bits = 0; bits < 4; bits++) {
|
||||
if ((prio & 0x01) != 0) {
|
||||
break;
|
||||
}
|
||||
prio >>= 1;
|
||||
}
|
||||
|
||||
// Adjust configured priority to the number of implemented priority bits
|
||||
prio = (PTIM_IRQ_PRIORITY << bits) & 0xFFUL;
|
||||
|
||||
// Set Private Timer interrupt priority
|
||||
IRQ_SetPriority(PrivTimer_IRQn, prio-1U);
|
||||
|
||||
// Set edge-triggered IRQ
|
||||
IRQ_SetMode(PrivTimer_IRQn, IRQ_MODE_TRIG_EDGE);
|
||||
|
||||
// Register tick interrupt handler function
|
||||
IRQ_SetHandler(PrivTimer_IRQn, handler);
|
||||
|
||||
// Enable corresponding interrupt
|
||||
IRQ_Enable (PrivTimer_IRQn);
|
||||
|
||||
// Set bits: IRQ enable and Auto reload
|
||||
PTIM_SetControl (0x06U);
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
/// Enable OS Tick.
|
||||
void OS_Tick_Enable (void) {
|
||||
uint32_t ctrl;
|
||||
|
||||
// Set pending interrupt if flag set
|
||||
if (PTIM_PendIRQ != 0U) {
|
||||
PTIM_PendIRQ = 0U;
|
||||
IRQ_SetPending (PrivTimer_IRQn);
|
||||
}
|
||||
|
||||
// Start the Private Timer
|
||||
ctrl = PTIM_GetControl();
|
||||
// Set bit: Timer enable
|
||||
ctrl |= 1U;
|
||||
PTIM_SetControl (ctrl);
|
||||
}
|
||||
|
||||
/// Disable OS Tick.
|
||||
void OS_Tick_Disable (void) {
|
||||
uint32_t ctrl;
|
||||
|
||||
// Stop the Private Timer
|
||||
ctrl = PTIM_GetControl();
|
||||
// Clear bit: Timer enable
|
||||
ctrl &= ~1U;
|
||||
PTIM_SetControl (ctrl);
|
||||
|
||||
// Remember pending interrupt flag
|
||||
if (IRQ_GetPending(PrivTimer_IRQn) != 0) {
|
||||
IRQ_ClearPending (PrivTimer_IRQn);
|
||||
PTIM_PendIRQ = 1U;
|
||||
}
|
||||
}
|
||||
|
||||
// Acknowledge OS Tick IRQ.
|
||||
void OS_Tick_AcknowledgeIRQ (void) {
|
||||
PTIM_ClearEventFlag();
|
||||
}
|
||||
|
||||
// Get OS Tick IRQ number.
|
||||
int32_t OS_Tick_GetIRQn (void) {
|
||||
return (PrivTimer_IRQn);
|
||||
}
|
||||
|
||||
// Get OS Tick clock.
|
||||
uint32_t OS_Tick_GetClock (void) {
|
||||
return (SystemCoreClock);
|
||||
}
|
||||
|
||||
// Get OS Tick interval.
|
||||
uint32_t OS_Tick_GetInterval (void) {
|
||||
return (PTIM_GetLoadValue() + 1U);
|
||||
}
|
||||
|
||||
// Get OS Tick count value.
|
||||
uint32_t OS_Tick_GetCount (void) {
|
||||
uint32_t load = PTIM_GetLoadValue();
|
||||
return (load - PTIM_GetCurrentValue());
|
||||
}
|
||||
|
||||
// Get OS Tick overflow status.
|
||||
uint32_t OS_Tick_GetOverflow (void) {
|
||||
return (PTIM->ISR & 1);
|
||||
}
|
||||
|
||||
#endif // PTIM
|
||||
@@ -0,0 +1,922 @@
|
||||
/*
|
||||
* Copyright (c) 2013-2018 Arm Limited. All rights reserved.
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the License); you may
|
||||
* not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an AS IS BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
* ----------------------------------------------------------------------
|
||||
*
|
||||
* $Date: 18. June 2018
|
||||
* $Revision: V2.1.3
|
||||
*
|
||||
* Project: CMSIS-RTOS API
|
||||
* Title: cmsis_os.h template header file
|
||||
*
|
||||
* Version 0.02
|
||||
* Initial Proposal Phase
|
||||
* Version 0.03
|
||||
* osKernelStart added, optional feature: main started as thread
|
||||
* osSemaphores have standard behavior
|
||||
* osTimerCreate does not start the timer, added osTimerStart
|
||||
* osThreadPass is renamed to osThreadYield
|
||||
* Version 1.01
|
||||
* Support for C++ interface
|
||||
* - const attribute removed from the osXxxxDef_t typedefs
|
||||
* - const attribute added to the osXxxxDef macros
|
||||
* Added: osTimerDelete, osMutexDelete, osSemaphoreDelete
|
||||
* Added: osKernelInitialize
|
||||
* Version 1.02
|
||||
* Control functions for short timeouts in microsecond resolution:
|
||||
* Added: osKernelSysTick, osKernelSysTickFrequency, osKernelSysTickMicroSec
|
||||
* Removed: osSignalGet
|
||||
* Version 2.0.0
|
||||
* OS objects creation without macros (dynamic creation and resource allocation):
|
||||
* - added: osXxxxNew functions which replace osXxxxCreate
|
||||
* - added: osXxxxAttr_t structures
|
||||
* - deprecated: osXxxxCreate functions, osXxxxDef_t structures
|
||||
* - deprecated: osXxxxDef and osXxxx macros
|
||||
* osStatus codes simplified and renamed to osStatus_t
|
||||
* osEvent return structure deprecated
|
||||
* Kernel:
|
||||
* - added: osKernelInfo_t and osKernelGetInfo
|
||||
* - added: osKernelState_t and osKernelGetState (replaces osKernelRunning)
|
||||
* - added: osKernelLock, osKernelUnlock
|
||||
* - added: osKernelSuspend, osKernelResume
|
||||
* - added: osKernelGetTickCount, osKernelGetTickFreq
|
||||
* - renamed osKernelSysTick to osKernelGetSysTimerCount
|
||||
* - replaced osKernelSysTickFrequency with osKernelGetSysTimerFreq
|
||||
* - deprecated osKernelSysTickMicroSec
|
||||
* Thread:
|
||||
* - extended number of thread priorities
|
||||
* - renamed osPrioriry to osPrioriry_t
|
||||
* - replaced osThreadCreate with osThreadNew
|
||||
* - added: osThreadGetName
|
||||
* - added: osThreadState_t and osThreadGetState
|
||||
* - added: osThreadGetStackSize, osThreadGetStackSpace
|
||||
* - added: osThreadSuspend, osThreadResume
|
||||
* - added: osThreadJoin, osThreadDetach, osThreadExit
|
||||
* - added: osThreadGetCount, osThreadEnumerate
|
||||
* - added: Thread Flags (moved from Signals)
|
||||
* Signals:
|
||||
* - renamed osSignals to osThreadFlags (moved to Thread Flags)
|
||||
* - changed return value of Set/Clear/Wait functions
|
||||
* - Clear function limited to current running thread
|
||||
* - extended Wait function (options)
|
||||
* - added: osThreadFlagsGet
|
||||
* Event Flags:
|
||||
* - added new independent object for handling Event Flags
|
||||
* Delay and Wait functions:
|
||||
* - added: osDelayUntil
|
||||
* - deprecated: osWait
|
||||
* Timer:
|
||||
* - replaced osTimerCreate with osTimerNew
|
||||
* - added: osTimerGetName, osTimerIsRunning
|
||||
* Mutex:
|
||||
* - extended: attributes (Recursive, Priority Inherit, Robust)
|
||||
* - replaced osMutexCreate with osMutexNew
|
||||
* - renamed osMutexWait to osMutexAcquire
|
||||
* - added: osMutexGetName, osMutexGetOwner
|
||||
* Semaphore:
|
||||
* - extended: maximum and initial token count
|
||||
* - replaced osSemaphoreCreate with osSemaphoreNew
|
||||
* - renamed osSemaphoreWait to osSemaphoreAcquire (changed return value)
|
||||
* - added: osSemaphoreGetName, osSemaphoreGetCount
|
||||
* Memory Pool:
|
||||
* - using osMemoryPool prefix instead of osPool
|
||||
* - replaced osPoolCreate with osMemoryPoolNew
|
||||
* - extended osMemoryPoolAlloc (timeout)
|
||||
* - added: osMemoryPoolGetName
|
||||
* - added: osMemoryPoolGetCapacity, osMemoryPoolGetBlockSize
|
||||
* - added: osMemoryPoolGetCount, osMemoryPoolGetSpace
|
||||
* - added: osMemoryPoolDelete
|
||||
* - deprecated: osPoolCAlloc
|
||||
* Message Queue:
|
||||
* - extended: fixed size message instead of a single 32-bit value
|
||||
* - using osMessageQueue prefix instead of osMessage
|
||||
* - replaced osMessageCreate with osMessageQueueNew
|
||||
* - updated: osMessageQueuePut, osMessageQueueGet
|
||||
* - added: osMessageQueueGetName
|
||||
* - added: osMessageQueueGetCapacity, osMessageQueueGetMsgSize
|
||||
* - added: osMessageQueueGetCount, osMessageQueueGetSpace
|
||||
* - added: osMessageQueueReset, osMessageQueueDelete
|
||||
* Mail Queue:
|
||||
* - deprecated (superseded by extended Message Queue functionality)
|
||||
* Version 2.1.0
|
||||
* Support for critical and uncritical sections (nesting safe):
|
||||
* - updated: osKernelLock, osKernelUnlock
|
||||
* - added: osKernelRestoreLock
|
||||
* Updated Thread and Event Flags:
|
||||
* - changed flags parameter and return type from int32_t to uint32_t
|
||||
* Version 2.1.1
|
||||
* Additional functions allowed to be called from Interrupt Service Routines:
|
||||
* - osKernelGetTickCount, osKernelGetTickFreq
|
||||
* Changed Kernel Tick type to uint32_t:
|
||||
* - updated: osKernelGetTickCount, osDelayUntil
|
||||
* Version 2.1.2
|
||||
* Additional functions allowed to be called from Interrupt Service Routines:
|
||||
* - osKernelGetInfo, osKernelGetState
|
||||
* Version 2.1.3
|
||||
* Additional functions allowed to be called from Interrupt Service Routines:
|
||||
* - osThreadGetId
|
||||
*---------------------------------------------------------------------------*/
|
||||
|
||||
#ifndef CMSIS_OS_H_
|
||||
#define CMSIS_OS_H_
|
||||
|
||||
/// \b osCMSIS identifies the CMSIS-RTOS API version.
|
||||
#define osCMSIS 0x20001U ///< API version (main[31:16].sub[15:0])
|
||||
|
||||
/// \note CAN BE CHANGED: \b osCMSIS_KERNEL identifies the underlying RTOS kernel and version number.
|
||||
#define osCMSIS_KERNEL 0x10000U ///< RTOS identification and version (main[31:16].sub[15:0])
|
||||
|
||||
/// \note CAN BE CHANGED: \b osKernelSystemId identifies the underlying RTOS kernel.
|
||||
#define osKernelSystemId "KERNEL V1.0" ///< RTOS identification string
|
||||
|
||||
/// \note CAN BE CHANGED: \b osFeature_xxx identifies RTOS features.
|
||||
#define osFeature_MainThread 0 ///< main thread 1=main can be thread, 0=not available
|
||||
#define osFeature_Signals 16U ///< maximum number of Signal Flags available per thread
|
||||
#define osFeature_Semaphore 65535U ///< maximum count for \ref osSemaphoreCreate function
|
||||
#define osFeature_Wait 0 ///< osWait function: 1=available, 0=not available
|
||||
#define osFeature_SysTick 1 ///< osKernelSysTick functions: 1=available, 0=not available
|
||||
#define osFeature_Pool 1 ///< Memory Pools: 1=available, 0=not available
|
||||
#define osFeature_MessageQ 1 ///< Message Queues: 1=available, 0=not available
|
||||
#define osFeature_MailQ 1 ///< Mail Queues: 1=available, 0=not available
|
||||
|
||||
#if (osCMSIS >= 0x20000U)
|
||||
#include "cmsis_os2.h"
|
||||
#else
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C"
|
||||
{
|
||||
#endif
|
||||
|
||||
|
||||
// ==== Enumerations, structures, defines ====
|
||||
|
||||
/// Priority values.
|
||||
#if (osCMSIS < 0x20000U)
|
||||
typedef enum {
|
||||
osPriorityIdle = -3, ///< Priority: idle (lowest)
|
||||
osPriorityLow = -2, ///< Priority: low
|
||||
osPriorityBelowNormal = -1, ///< Priority: below normal
|
||||
osPriorityNormal = 0, ///< Priority: normal (default)
|
||||
osPriorityAboveNormal = +1, ///< Priority: above normal
|
||||
osPriorityHigh = +2, ///< Priority: high
|
||||
osPriorityRealtime = +3, ///< Priority: realtime (highest)
|
||||
osPriorityError = 0x84, ///< System cannot determine priority or illegal priority.
|
||||
osPriorityReserved = 0x7FFFFFFF ///< Prevents enum down-size compiler optimization.
|
||||
} osPriority;
|
||||
#else
|
||||
#define osPriority osPriority_t
|
||||
#endif
|
||||
|
||||
/// Entry point of a thread.
|
||||
typedef void (*os_pthread) (void const *argument);
|
||||
|
||||
/// Entry point of a timer call back function.
|
||||
typedef void (*os_ptimer) (void const *argument);
|
||||
|
||||
/// Timer type.
|
||||
#if (osCMSIS < 0x20000U)
|
||||
typedef enum {
|
||||
osTimerOnce = 0, ///< One-shot timer.
|
||||
osTimerPeriodic = 1 ///< Repeating timer.
|
||||
} os_timer_type;
|
||||
#else
|
||||
#define os_timer_type osTimerType_t
|
||||
#endif
|
||||
|
||||
/// Timeout value.
|
||||
#define osWaitForever 0xFFFFFFFFU ///< Wait forever timeout value.
|
||||
|
||||
/// Status code values returned by CMSIS-RTOS functions.
|
||||
#if (osCMSIS < 0x20000U)
|
||||
typedef enum {
|
||||
osOK = 0, ///< Function completed; no error or event occurred.
|
||||
osEventSignal = 0x08, ///< Function completed; signal event occurred.
|
||||
osEventMessage = 0x10, ///< Function completed; message event occurred.
|
||||
osEventMail = 0x20, ///< Function completed; mail event occurred.
|
||||
osEventTimeout = 0x40, ///< Function completed; timeout occurred.
|
||||
osErrorParameter = 0x80, ///< Parameter error: a mandatory parameter was missing or specified an incorrect object.
|
||||
osErrorResource = 0x81, ///< Resource not available: a specified resource was not available.
|
||||
osErrorTimeoutResource = 0xC1, ///< Resource not available within given time: a specified resource was not available within the timeout period.
|
||||
osErrorISR = 0x82, ///< Not allowed in ISR context: the function cannot be called from interrupt service routines.
|
||||
osErrorISRRecursive = 0x83, ///< Function called multiple times from ISR with same object.
|
||||
osErrorPriority = 0x84, ///< System cannot determine priority or thread has illegal priority.
|
||||
osErrorNoMemory = 0x85, ///< System is out of memory: it was impossible to allocate or reserve memory for the operation.
|
||||
osErrorValue = 0x86, ///< Value of a parameter is out of range.
|
||||
osErrorOS = 0xFF, ///< Unspecified RTOS error: run-time error but no other error message fits.
|
||||
osStatusReserved = 0x7FFFFFFF ///< Prevents enum down-size compiler optimization.
|
||||
} osStatus;
|
||||
#else
|
||||
typedef int32_t osStatus;
|
||||
#define osEventSignal (0x08)
|
||||
#define osEventMessage (0x10)
|
||||
#define osEventMail (0x20)
|
||||
#define osEventTimeout (0x40)
|
||||
#define osErrorOS osError
|
||||
#define osErrorTimeoutResource osErrorTimeout
|
||||
#define osErrorISRRecursive (-126)
|
||||
#define osErrorValue (-127)
|
||||
#define osErrorPriority (-128)
|
||||
#endif
|
||||
|
||||
|
||||
// >>> the following data type definitions may be adapted towards a specific RTOS
|
||||
|
||||
/// Thread ID identifies the thread.
|
||||
/// \note CAN BE CHANGED: \b implementation specific in every CMSIS-RTOS.
|
||||
#if (osCMSIS < 0x20000U)
|
||||
typedef void *osThreadId;
|
||||
#else
|
||||
#define osThreadId osThreadId_t
|
||||
#endif
|
||||
|
||||
/// Timer ID identifies the timer.
|
||||
/// \note CAN BE CHANGED: \b implementation specific in every CMSIS-RTOS.
|
||||
#if (osCMSIS < 0x20000U)
|
||||
typedef void *osTimerId;
|
||||
#else
|
||||
#define osTimerId osTimerId_t
|
||||
#endif
|
||||
|
||||
/// Mutex ID identifies the mutex.
|
||||
/// \note CAN BE CHANGED: \b implementation specific in every CMSIS-RTOS.
|
||||
#if (osCMSIS < 0x20000U)
|
||||
typedef void *osMutexId;
|
||||
#else
|
||||
#define osMutexId osMutexId_t
|
||||
#endif
|
||||
|
||||
/// Semaphore ID identifies the semaphore.
|
||||
/// \note CAN BE CHANGED: \b implementation specific in every CMSIS-RTOS.
|
||||
#if (osCMSIS < 0x20000U)
|
||||
typedef void *osSemaphoreId;
|
||||
#else
|
||||
#define osSemaphoreId osSemaphoreId_t
|
||||
#endif
|
||||
|
||||
/// Pool ID identifies the memory pool.
|
||||
/// \note CAN BE CHANGED: \b implementation specific in every CMSIS-RTOS.
|
||||
typedef void *osPoolId;
|
||||
|
||||
/// Message ID identifies the message queue.
|
||||
/// \note CAN BE CHANGED: \b implementation specific in every CMSIS-RTOS.
|
||||
typedef void *osMessageQId;
|
||||
|
||||
/// Mail ID identifies the mail queue.
|
||||
/// \note CAN BE CHANGED: \b implementation specific in every CMSIS-RTOS.
|
||||
typedef void *osMailQId;
|
||||
|
||||
|
||||
/// Thread Definition structure contains startup information of a thread.
|
||||
/// \note CAN BE CHANGED: \b os_thread_def is implementation specific in every CMSIS-RTOS.
|
||||
#if (osCMSIS < 0x20000U)
|
||||
typedef struct os_thread_def {
|
||||
os_pthread pthread; ///< start address of thread function
|
||||
osPriority tpriority; ///< initial thread priority
|
||||
uint32_t instances; ///< maximum number of instances of that thread function
|
||||
uint32_t stacksize; ///< stack size requirements in bytes; 0 is default stack size
|
||||
} osThreadDef_t;
|
||||
#else
|
||||
typedef struct os_thread_def {
|
||||
os_pthread pthread; ///< start address of thread function
|
||||
osThreadAttr_t attr; ///< thread attributes
|
||||
} osThreadDef_t;
|
||||
#endif
|
||||
|
||||
/// Timer Definition structure contains timer parameters.
|
||||
/// \note CAN BE CHANGED: \b os_timer_def is implementation specific in every CMSIS-RTOS.
|
||||
#if (osCMSIS < 0x20000U)
|
||||
typedef struct os_timer_def {
|
||||
os_ptimer ptimer; ///< start address of a timer function
|
||||
} osTimerDef_t;
|
||||
#else
|
||||
typedef struct os_timer_def {
|
||||
os_ptimer ptimer; ///< start address of a timer function
|
||||
osTimerAttr_t attr; ///< timer attributes
|
||||
} osTimerDef_t;
|
||||
#endif
|
||||
|
||||
/// Mutex Definition structure contains setup information for a mutex.
|
||||
/// \note CAN BE CHANGED: \b os_mutex_def is implementation specific in every CMSIS-RTOS.
|
||||
#if (osCMSIS < 0x20000U)
|
||||
typedef struct os_mutex_def {
|
||||
uint32_t dummy; ///< dummy value
|
||||
} osMutexDef_t;
|
||||
#else
|
||||
#define osMutexDef_t osMutexAttr_t
|
||||
#endif
|
||||
|
||||
/// Semaphore Definition structure contains setup information for a semaphore.
|
||||
/// \note CAN BE CHANGED: \b os_semaphore_def is implementation specific in every CMSIS-RTOS.
|
||||
#if (osCMSIS < 0x20000U)
|
||||
typedef struct os_semaphore_def {
|
||||
uint32_t dummy; ///< dummy value
|
||||
} osSemaphoreDef_t;
|
||||
#else
|
||||
#define osSemaphoreDef_t osSemaphoreAttr_t
|
||||
#endif
|
||||
|
||||
/// Definition structure for memory block allocation.
|
||||
/// \note CAN BE CHANGED: \b os_pool_def is implementation specific in every CMSIS-RTOS.
|
||||
#if (osCMSIS < 0x20000U)
|
||||
typedef struct os_pool_def {
|
||||
uint32_t pool_sz; ///< number of items (elements) in the pool
|
||||
uint32_t item_sz; ///< size of an item
|
||||
void *pool; ///< pointer to memory for pool
|
||||
} osPoolDef_t;
|
||||
#else
|
||||
typedef struct os_pool_def {
|
||||
uint32_t pool_sz; ///< number of items (elements) in the pool
|
||||
uint32_t item_sz; ///< size of an item
|
||||
osMemoryPoolAttr_t attr; ///< memory pool attributes
|
||||
} osPoolDef_t;
|
||||
#endif
|
||||
|
||||
/// Definition structure for message queue.
|
||||
/// \note CAN BE CHANGED: \b os_messageQ_def is implementation specific in every CMSIS-RTOS.
|
||||
#if (osCMSIS < 0x20000U)
|
||||
typedef struct os_messageQ_def {
|
||||
uint32_t queue_sz; ///< number of elements in the queue
|
||||
void *pool; ///< memory array for messages
|
||||
} osMessageQDef_t;
|
||||
#else
|
||||
typedef struct os_messageQ_def {
|
||||
uint32_t queue_sz; ///< number of elements in the queue
|
||||
osMessageQueueAttr_t attr; ///< message queue attributes
|
||||
} osMessageQDef_t;
|
||||
#endif
|
||||
|
||||
/// Definition structure for mail queue.
|
||||
/// \note CAN BE CHANGED: \b os_mailQ_def is implementation specific in every CMSIS-RTOS.
|
||||
#if (osCMSIS < 0x20000U)
|
||||
typedef struct os_mailQ_def {
|
||||
uint32_t queue_sz; ///< number of elements in the queue
|
||||
uint32_t item_sz; ///< size of an item
|
||||
void *pool; ///< memory array for mail
|
||||
} osMailQDef_t;
|
||||
#else
|
||||
typedef struct os_mailQ_def {
|
||||
uint32_t queue_sz; ///< number of elements in the queue
|
||||
uint32_t item_sz; ///< size of an item
|
||||
void *mail; ///< pointer to mail
|
||||
osMemoryPoolAttr_t mp_attr; ///< memory pool attributes
|
||||
osMessageQueueAttr_t mq_attr; ///< message queue attributes
|
||||
} osMailQDef_t;
|
||||
#endif
|
||||
|
||||
|
||||
/// Event structure contains detailed information about an event.
|
||||
typedef struct {
|
||||
osStatus status; ///< status code: event or error information
|
||||
union {
|
||||
uint32_t v; ///< message as 32-bit value
|
||||
void *p; ///< message or mail as void pointer
|
||||
int32_t signals; ///< signal flags
|
||||
} value; ///< event value
|
||||
union {
|
||||
osMailQId mail_id; ///< mail id obtained by \ref osMailCreate
|
||||
osMessageQId message_id; ///< message id obtained by \ref osMessageCreate
|
||||
} def; ///< event definition
|
||||
} osEvent;
|
||||
|
||||
|
||||
// ==== Kernel Management Functions ====
|
||||
|
||||
/// Initialize the RTOS Kernel for creating objects.
|
||||
/// \return status code that indicates the execution status of the function.
|
||||
#if (osCMSIS < 0x20000U)
|
||||
osStatus osKernelInitialize (void);
|
||||
#endif
|
||||
|
||||
/// Start the RTOS Kernel scheduler.
|
||||
/// \return status code that indicates the execution status of the function.
|
||||
#if (osCMSIS < 0x20000U)
|
||||
osStatus osKernelStart (void);
|
||||
#endif
|
||||
|
||||
/// Check if the RTOS kernel is already started.
|
||||
/// \return 0 RTOS is not started, 1 RTOS is started.
|
||||
#if (osCMSIS < 0x20000U)
|
||||
int32_t osKernelRunning(void);
|
||||
#endif
|
||||
|
||||
#if (defined(osFeature_SysTick) && (osFeature_SysTick != 0)) // System Timer available
|
||||
|
||||
/// Get the RTOS kernel system timer counter.
|
||||
/// \return RTOS kernel system timer as 32-bit value
|
||||
#if (osCMSIS < 0x20000U)
|
||||
uint32_t osKernelSysTick (void);
|
||||
#else
|
||||
#define osKernelSysTick osKernelGetSysTimerCount
|
||||
#endif
|
||||
|
||||
/// The RTOS kernel system timer frequency in Hz.
|
||||
/// \note Reflects the system timer setting and is typically defined in a configuration file.
|
||||
#if (osCMSIS < 0x20000U)
|
||||
#define osKernelSysTickFrequency 100000000
|
||||
#endif
|
||||
|
||||
/// Convert a microseconds value to a RTOS kernel system timer value.
|
||||
/// \param microsec time value in microseconds.
|
||||
/// \return time value normalized to the \ref osKernelSysTickFrequency
|
||||
#if (osCMSIS < 0x20000U)
|
||||
#define osKernelSysTickMicroSec(microsec) (((uint64_t)microsec * (osKernelSysTickFrequency)) / 1000000)
|
||||
#else
|
||||
#define osKernelSysTickMicroSec(microsec) (((uint64_t)microsec * osKernelGetSysTimerFreq()) / 1000000)
|
||||
#endif
|
||||
|
||||
#endif // System Timer available
|
||||
|
||||
|
||||
// ==== Thread Management Functions ====
|
||||
|
||||
/// Create a Thread Definition with function, priority, and stack requirements.
|
||||
/// \param name name of the thread function.
|
||||
/// \param priority initial priority of the thread function.
|
||||
/// \param instances number of possible thread instances.
|
||||
/// \param stacksz stack size (in bytes) requirements for the thread function.
|
||||
/// \note CAN BE CHANGED: The parameters to \b osThreadDef shall be consistent but the
|
||||
/// macro body is implementation specific in every CMSIS-RTOS.
|
||||
#if defined (osObjectsExternal) // object is external
|
||||
#define osThreadDef(name, priority, instances, stacksz) \
|
||||
extern const osThreadDef_t os_thread_def_##name
|
||||
#else // define the object
|
||||
#if (osCMSIS < 0x20000U)
|
||||
#define osThreadDef(name, priority, instances, stacksz) \
|
||||
const osThreadDef_t os_thread_def_##name = \
|
||||
{ (name), (priority), (instances), (stacksz) }
|
||||
#else
|
||||
#define osThreadDef(name, priority, instances, stacksz) \
|
||||
const osThreadDef_t os_thread_def_##name = \
|
||||
{ (name), \
|
||||
{ NULL, osThreadDetached, NULL, 0U, NULL, 8*((stacksz+7)/8), (priority), 0U, 0U } }
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/// Access a Thread definition.
|
||||
/// \param name name of the thread definition object.
|
||||
/// \note CAN BE CHANGED: The parameter to \b osThread shall be consistent but the
|
||||
/// macro body is implementation specific in every CMSIS-RTOS.
|
||||
#define osThread(name) \
|
||||
&os_thread_def_##name
|
||||
|
||||
/// Create a thread and add it to Active Threads and set it to state READY.
|
||||
/// \param[in] thread_def thread definition referenced with \ref osThread.
|
||||
/// \param[in] argument pointer that is passed to the thread function as start argument.
|
||||
/// \return thread ID for reference by other functions or NULL in case of error.
|
||||
osThreadId osThreadCreate (const osThreadDef_t *thread_def, void *argument);
|
||||
|
||||
/// Return the thread ID of the current running thread.
|
||||
/// \return thread ID for reference by other functions or NULL in case of error.
|
||||
#if (osCMSIS < 0x20000U)
|
||||
osThreadId osThreadGetId (void);
|
||||
#endif
|
||||
|
||||
/// Change priority of a thread.
|
||||
/// \param[in] thread_id thread ID obtained by \ref osThreadCreate or \ref osThreadGetId.
|
||||
/// \param[in] priority new priority value for the thread function.
|
||||
/// \return status code that indicates the execution status of the function.
|
||||
#if (osCMSIS < 0x20000U)
|
||||
osStatus osThreadSetPriority (osThreadId thread_id, osPriority priority);
|
||||
#endif
|
||||
|
||||
/// Get current priority of a thread.
|
||||
/// \param[in] thread_id thread ID obtained by \ref osThreadCreate or \ref osThreadGetId.
|
||||
/// \return current priority value of the specified thread.
|
||||
#if (osCMSIS < 0x20000U)
|
||||
osPriority osThreadGetPriority (osThreadId thread_id);
|
||||
#endif
|
||||
|
||||
/// Pass control to next thread that is in state \b READY.
|
||||
/// \return status code that indicates the execution status of the function.
|
||||
#if (osCMSIS < 0x20000U)
|
||||
osStatus osThreadYield (void);
|
||||
#endif
|
||||
|
||||
/// Terminate execution of a thread.
|
||||
/// \param[in] thread_id thread ID obtained by \ref osThreadCreate or \ref osThreadGetId.
|
||||
/// \return status code that indicates the execution status of the function.
|
||||
#if (osCMSIS < 0x20000U)
|
||||
osStatus osThreadTerminate (osThreadId thread_id);
|
||||
#endif
|
||||
|
||||
|
||||
// ==== Signal Management ====
|
||||
|
||||
/// Set the specified Signal Flags of an active thread.
|
||||
/// \param[in] thread_id thread ID obtained by \ref osThreadCreate or \ref osThreadGetId.
|
||||
/// \param[in] signals specifies the signal flags of the thread that should be set.
|
||||
/// \return previous signal flags of the specified thread or 0x80000000 in case of incorrect parameters.
|
||||
int32_t osSignalSet (osThreadId thread_id, int32_t signals);
|
||||
|
||||
/// Clear the specified Signal Flags of an active thread.
|
||||
/// \param[in] thread_id thread ID obtained by \ref osThreadCreate or \ref osThreadGetId.
|
||||
/// \param[in] signals specifies the signal flags of the thread that shall be cleared.
|
||||
/// \return previous signal flags of the specified thread or 0x80000000 in case of incorrect parameters or call from ISR.
|
||||
int32_t osSignalClear (osThreadId thread_id, int32_t signals);
|
||||
|
||||
/// Wait for one or more Signal Flags to become signaled for the current \b RUNNING thread.
|
||||
/// \param[in] signals wait until all specified signal flags set or 0 for any single signal flag.
|
||||
/// \param[in] millisec \ref CMSIS_RTOS_TimeOutValue or 0 in case of no time-out.
|
||||
/// \return event flag information or error code.
|
||||
osEvent osSignalWait (int32_t signals, uint32_t millisec);
|
||||
|
||||
|
||||
// ==== Generic Wait Functions ====
|
||||
|
||||
/// Wait for Timeout (Time Delay).
|
||||
/// \param[in] millisec \ref CMSIS_RTOS_TimeOutValue "time delay" value
|
||||
/// \return status code that indicates the execution status of the function.
|
||||
#if (osCMSIS < 0x20000U)
|
||||
osStatus osDelay (uint32_t millisec);
|
||||
#endif
|
||||
|
||||
#if (defined (osFeature_Wait) && (osFeature_Wait != 0)) // Generic Wait available
|
||||
|
||||
/// Wait for Signal, Message, Mail, or Timeout.
|
||||
/// \param[in] millisec \ref CMSIS_RTOS_TimeOutValue or 0 in case of no time-out
|
||||
/// \return event that contains signal, message, or mail information or error code.
|
||||
osEvent osWait (uint32_t millisec);
|
||||
|
||||
#endif // Generic Wait available
|
||||
|
||||
|
||||
// ==== Timer Management Functions ====
|
||||
|
||||
/// Define a Timer object.
|
||||
/// \param name name of the timer object.
|
||||
/// \param function name of the timer call back function.
|
||||
/// \note CAN BE CHANGED: The parameter to \b osTimerDef shall be consistent but the
|
||||
/// macro body is implementation specific in every CMSIS-RTOS.
|
||||
#if defined (osObjectsExternal) // object is external
|
||||
#define osTimerDef(name, function) \
|
||||
extern const osTimerDef_t os_timer_def_##name
|
||||
#else // define the object
|
||||
#if (osCMSIS < 0x20000U)
|
||||
#define osTimerDef(name, function) \
|
||||
const osTimerDef_t os_timer_def_##name = { (function) }
|
||||
#else
|
||||
#define osTimerDef(name, function) \
|
||||
const osTimerDef_t os_timer_def_##name = \
|
||||
{ (function), { NULL, 0U, NULL, 0U } }
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/// Access a Timer definition.
|
||||
/// \param name name of the timer object.
|
||||
/// \note CAN BE CHANGED: The parameter to \b osTimer shall be consistent but the
|
||||
/// macro body is implementation specific in every CMSIS-RTOS.
|
||||
#define osTimer(name) \
|
||||
&os_timer_def_##name
|
||||
|
||||
/// Create and Initialize a timer.
|
||||
/// \param[in] timer_def timer object referenced with \ref osTimer.
|
||||
/// \param[in] type osTimerOnce for one-shot or osTimerPeriodic for periodic behavior.
|
||||
/// \param[in] argument argument to the timer call back function.
|
||||
/// \return timer ID for reference by other functions or NULL in case of error.
|
||||
osTimerId osTimerCreate (const osTimerDef_t *timer_def, os_timer_type type, void *argument);
|
||||
|
||||
/// Start or restart a timer.
|
||||
/// \param[in] timer_id timer ID obtained by \ref osTimerCreate.
|
||||
/// \param[in] millisec \ref CMSIS_RTOS_TimeOutValue "time delay" value of the timer.
|
||||
/// \return status code that indicates the execution status of the function.
|
||||
#if (osCMSIS < 0x20000U)
|
||||
osStatus osTimerStart (osTimerId timer_id, uint32_t millisec);
|
||||
#endif
|
||||
|
||||
/// Stop a timer.
|
||||
/// \param[in] timer_id timer ID obtained by \ref osTimerCreate.
|
||||
/// \return status code that indicates the execution status of the function.
|
||||
#if (osCMSIS < 0x20000U)
|
||||
osStatus osTimerStop (osTimerId timer_id);
|
||||
#endif
|
||||
|
||||
/// Delete a timer.
|
||||
/// \param[in] timer_id timer ID obtained by \ref osTimerCreate.
|
||||
/// \return status code that indicates the execution status of the function.
|
||||
#if (osCMSIS < 0x20000U)
|
||||
osStatus osTimerDelete (osTimerId timer_id);
|
||||
#endif
|
||||
|
||||
|
||||
// ==== Mutex Management Functions ====
|
||||
|
||||
/// Define a Mutex.
|
||||
/// \param name name of the mutex object.
|
||||
/// \note CAN BE CHANGED: The parameter to \b osMutexDef shall be consistent but the
|
||||
/// macro body is implementation specific in every CMSIS-RTOS.
|
||||
#if defined (osObjectsExternal) // object is external
|
||||
#define osMutexDef(name) \
|
||||
extern const osMutexDef_t os_mutex_def_##name
|
||||
#else // define the object
|
||||
#if (osCMSIS < 0x20000U)
|
||||
#define osMutexDef(name) \
|
||||
const osMutexDef_t os_mutex_def_##name = { 0 }
|
||||
#else
|
||||
#define osMutexDef(name) \
|
||||
const osMutexDef_t os_mutex_def_##name = \
|
||||
{ NULL, osMutexRecursive | osMutexPrioInherit | osMutexRobust, NULL, 0U }
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/// Access a Mutex definition.
|
||||
/// \param name name of the mutex object.
|
||||
/// \note CAN BE CHANGED: The parameter to \b osMutex shall be consistent but the
|
||||
/// macro body is implementation specific in every CMSIS-RTOS.
|
||||
#define osMutex(name) \
|
||||
&os_mutex_def_##name
|
||||
|
||||
/// Create and Initialize a Mutex object.
|
||||
/// \param[in] mutex_def mutex definition referenced with \ref osMutex.
|
||||
/// \return mutex ID for reference by other functions or NULL in case of error.
|
||||
osMutexId osMutexCreate (const osMutexDef_t *mutex_def);
|
||||
|
||||
/// Wait until a Mutex becomes available.
|
||||
/// \param[in] mutex_id mutex ID obtained by \ref osMutexCreate.
|
||||
/// \param[in] millisec \ref CMSIS_RTOS_TimeOutValue or 0 in case of no time-out.
|
||||
/// \return status code that indicates the execution status of the function.
|
||||
#if (osCMSIS < 0x20000U)
|
||||
osStatus osMutexWait (osMutexId mutex_id, uint32_t millisec);
|
||||
#else
|
||||
#define osMutexWait osMutexAcquire
|
||||
#endif
|
||||
|
||||
/// Release a Mutex that was obtained by \ref osMutexWait.
|
||||
/// \param[in] mutex_id mutex ID obtained by \ref osMutexCreate.
|
||||
/// \return status code that indicates the execution status of the function.
|
||||
#if (osCMSIS < 0x20000U)
|
||||
osStatus osMutexRelease (osMutexId mutex_id);
|
||||
#endif
|
||||
|
||||
/// Delete a Mutex object.
|
||||
/// \param[in] mutex_id mutex ID obtained by \ref osMutexCreate.
|
||||
/// \return status code that indicates the execution status of the function.
|
||||
#if (osCMSIS < 0x20000U)
|
||||
osStatus osMutexDelete (osMutexId mutex_id);
|
||||
#endif
|
||||
|
||||
|
||||
// ==== Semaphore Management Functions ====
|
||||
|
||||
#if (defined (osFeature_Semaphore) && (osFeature_Semaphore != 0U)) // Semaphore available
|
||||
|
||||
/// Define a Semaphore object.
|
||||
/// \param name name of the semaphore object.
|
||||
/// \note CAN BE CHANGED: The parameter to \b osSemaphoreDef shall be consistent but the
|
||||
/// macro body is implementation specific in every CMSIS-RTOS.
|
||||
#if defined (osObjectsExternal) // object is external
|
||||
#define osSemaphoreDef(name) \
|
||||
extern const osSemaphoreDef_t os_semaphore_def_##name
|
||||
#else // define the object
|
||||
#if (osCMSIS < 0x20000U)
|
||||
#define osSemaphoreDef(name) \
|
||||
const osSemaphoreDef_t os_semaphore_def_##name = { 0 }
|
||||
#else
|
||||
#define osSemaphoreDef(name) \
|
||||
const osSemaphoreDef_t os_semaphore_def_##name = \
|
||||
{ NULL, 0U, NULL, 0U }
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/// Access a Semaphore definition.
|
||||
/// \param name name of the semaphore object.
|
||||
/// \note CAN BE CHANGED: The parameter to \b osSemaphore shall be consistent but the
|
||||
/// macro body is implementation specific in every CMSIS-RTOS.
|
||||
#define osSemaphore(name) \
|
||||
&os_semaphore_def_##name
|
||||
|
||||
/// Create and Initialize a Semaphore object.
|
||||
/// \param[in] semaphore_def semaphore definition referenced with \ref osSemaphore.
|
||||
/// \param[in] count maximum and initial number of available tokens.
|
||||
/// \return semaphore ID for reference by other functions or NULL in case of error.
|
||||
osSemaphoreId osSemaphoreCreate (const osSemaphoreDef_t *semaphore_def, int32_t count);
|
||||
|
||||
/// Wait until a Semaphore token becomes available.
|
||||
/// \param[in] semaphore_id semaphore object referenced with \ref osSemaphoreCreate.
|
||||
/// \param[in] millisec \ref CMSIS_RTOS_TimeOutValue or 0 in case of no time-out.
|
||||
/// \return number of available tokens, or -1 in case of incorrect parameters.
|
||||
int32_t osSemaphoreWait (osSemaphoreId semaphore_id, uint32_t millisec);
|
||||
|
||||
/// Release a Semaphore token.
|
||||
/// \param[in] semaphore_id semaphore object referenced with \ref osSemaphoreCreate.
|
||||
/// \return status code that indicates the execution status of the function.
|
||||
#if (osCMSIS < 0x20000U)
|
||||
osStatus osSemaphoreRelease (osSemaphoreId semaphore_id);
|
||||
#endif
|
||||
|
||||
/// Delete a Semaphore object.
|
||||
/// \param[in] semaphore_id semaphore object referenced with \ref osSemaphoreCreate.
|
||||
/// \return status code that indicates the execution status of the function.
|
||||
#if (osCMSIS < 0x20000U)
|
||||
osStatus osSemaphoreDelete (osSemaphoreId semaphore_id);
|
||||
#endif
|
||||
|
||||
#endif // Semaphore available
|
||||
|
||||
|
||||
// ==== Memory Pool Management Functions ====
|
||||
|
||||
#if (defined(osFeature_Pool) && (osFeature_Pool != 0)) // Memory Pool available
|
||||
|
||||
/// \brief Define a Memory Pool.
|
||||
/// \param name name of the memory pool.
|
||||
/// \param no maximum number of blocks (objects) in the memory pool.
|
||||
/// \param type data type of a single block (object).
|
||||
/// \note CAN BE CHANGED: The parameter to \b osPoolDef shall be consistent but the
|
||||
/// macro body is implementation specific in every CMSIS-RTOS.
|
||||
#if defined (osObjectsExternal) // object is external
|
||||
#define osPoolDef(name, no, type) \
|
||||
extern const osPoolDef_t os_pool_def_##name
|
||||
#else // define the object
|
||||
#if (osCMSIS < 0x20000U)
|
||||
#define osPoolDef(name, no, type) \
|
||||
const osPoolDef_t os_pool_def_##name = \
|
||||
{ (no), sizeof(type), NULL }
|
||||
#else
|
||||
#define osPoolDef(name, no, type) \
|
||||
const osPoolDef_t os_pool_def_##name = \
|
||||
{ (no), sizeof(type), { NULL, 0U, NULL, 0U, NULL, 0U } }
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/// \brief Access a Memory Pool definition.
|
||||
/// \param name name of the memory pool
|
||||
/// \note CAN BE CHANGED: The parameter to \b osPool shall be consistent but the
|
||||
/// macro body is implementation specific in every CMSIS-RTOS.
|
||||
#define osPool(name) \
|
||||
&os_pool_def_##name
|
||||
|
||||
/// Create and Initialize a Memory Pool object.
|
||||
/// \param[in] pool_def memory pool definition referenced with \ref osPool.
|
||||
/// \return memory pool ID for reference by other functions or NULL in case of error.
|
||||
osPoolId osPoolCreate (const osPoolDef_t *pool_def);
|
||||
|
||||
/// Allocate a memory block from a Memory Pool.
|
||||
/// \param[in] pool_id memory pool ID obtain referenced with \ref osPoolCreate.
|
||||
/// \return address of the allocated memory block or NULL in case of no memory available.
|
||||
void *osPoolAlloc (osPoolId pool_id);
|
||||
|
||||
/// Allocate a memory block from a Memory Pool and set memory block to zero.
|
||||
/// \param[in] pool_id memory pool ID obtain referenced with \ref osPoolCreate.
|
||||
/// \return address of the allocated memory block or NULL in case of no memory available.
|
||||
void *osPoolCAlloc (osPoolId pool_id);
|
||||
|
||||
/// Return an allocated memory block back to a Memory Pool.
|
||||
/// \param[in] pool_id memory pool ID obtain referenced with \ref osPoolCreate.
|
||||
/// \param[in] block address of the allocated memory block to be returned to the memory pool.
|
||||
/// \return status code that indicates the execution status of the function.
|
||||
osStatus osPoolFree (osPoolId pool_id, void *block);
|
||||
|
||||
#endif // Memory Pool available
|
||||
|
||||
|
||||
// ==== Message Queue Management Functions ====
|
||||
|
||||
#if (defined(osFeature_MessageQ) && (osFeature_MessageQ != 0)) // Message Queue available
|
||||
|
||||
/// \brief Create a Message Queue Definition.
|
||||
/// \param name name of the queue.
|
||||
/// \param queue_sz maximum number of messages in the queue.
|
||||
/// \param type data type of a single message element (for debugger).
|
||||
/// \note CAN BE CHANGED: The parameter to \b osMessageQDef shall be consistent but the
|
||||
/// macro body is implementation specific in every CMSIS-RTOS.
|
||||
#if defined (osObjectsExternal) // object is external
|
||||
#define osMessageQDef(name, queue_sz, type) \
|
||||
extern const osMessageQDef_t os_messageQ_def_##name
|
||||
#else // define the object
|
||||
#if (osCMSIS < 0x20000U)
|
||||
#define osMessageQDef(name, queue_sz, type) \
|
||||
const osMessageQDef_t os_messageQ_def_##name = \
|
||||
{ (queue_sz), NULL }
|
||||
#else
|
||||
#define osMessageQDef(name, queue_sz, type) \
|
||||
const osMessageQDef_t os_messageQ_def_##name = \
|
||||
{ (queue_sz), { NULL, 0U, NULL, 0U, NULL, 0U } }
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/// \brief Access a Message Queue Definition.
|
||||
/// \param name name of the queue
|
||||
/// \note CAN BE CHANGED: The parameter to \b osMessageQ shall be consistent but the
|
||||
/// macro body is implementation specific in every CMSIS-RTOS.
|
||||
#define osMessageQ(name) \
|
||||
&os_messageQ_def_##name
|
||||
|
||||
/// Create and Initialize a Message Queue object.
|
||||
/// \param[in] queue_def message queue definition referenced with \ref osMessageQ.
|
||||
/// \param[in] thread_id thread ID (obtained by \ref osThreadCreate or \ref osThreadGetId) or NULL.
|
||||
/// \return message queue ID for reference by other functions or NULL in case of error.
|
||||
osMessageQId osMessageCreate (const osMessageQDef_t *queue_def, osThreadId thread_id);
|
||||
|
||||
/// Put a Message to a Queue.
|
||||
/// \param[in] queue_id message queue ID obtained with \ref osMessageCreate.
|
||||
/// \param[in] info message information.
|
||||
/// \param[in] millisec \ref CMSIS_RTOS_TimeOutValue or 0 in case of no time-out.
|
||||
/// \return status code that indicates the execution status of the function.
|
||||
osStatus osMessagePut (osMessageQId queue_id, uint32_t info, uint32_t millisec);
|
||||
|
||||
/// Get a Message from a Queue or timeout if Queue is empty.
|
||||
/// \param[in] queue_id message queue ID obtained with \ref osMessageCreate.
|
||||
/// \param[in] millisec \ref CMSIS_RTOS_TimeOutValue or 0 in case of no time-out.
|
||||
/// \return event information that includes status code.
|
||||
osEvent osMessageGet (osMessageQId queue_id, uint32_t millisec);
|
||||
|
||||
#endif // Message Queue available
|
||||
|
||||
|
||||
// ==== Mail Queue Management Functions ====
|
||||
|
||||
#if (defined(osFeature_MailQ) && (osFeature_MailQ != 0)) // Mail Queue available
|
||||
|
||||
/// \brief Create a Mail Queue Definition.
|
||||
/// \param name name of the queue.
|
||||
/// \param queue_sz maximum number of mails in the queue.
|
||||
/// \param type data type of a single mail element.
|
||||
/// \note CAN BE CHANGED: The parameter to \b osMailQDef shall be consistent but the
|
||||
/// macro body is implementation specific in every CMSIS-RTOS.
|
||||
#if defined (osObjectsExternal) // object is external
|
||||
#define osMailQDef(name, queue_sz, type) \
|
||||
extern const osMailQDef_t os_mailQ_def_##name
|
||||
#else // define the object
|
||||
#if (osCMSIS < 0x20000U)
|
||||
#define osMailQDef(name, queue_sz, type) \
|
||||
const osMailQDef_t os_mailQ_def_##name = \
|
||||
{ (queue_sz), sizeof(type), NULL }
|
||||
#else
|
||||
#define osMailQDef(name, queue_sz, type) \
|
||||
static void *os_mail_p_##name[2]; \
|
||||
const osMailQDef_t os_mailQ_def_##name = \
|
||||
{ (queue_sz), sizeof(type), (&os_mail_p_##name), \
|
||||
{ NULL, 0U, NULL, 0U, NULL, 0U }, \
|
||||
{ NULL, 0U, NULL, 0U, NULL, 0U } }
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/// \brief Access a Mail Queue Definition.
|
||||
/// \param name name of the queue
|
||||
/// \note CAN BE CHANGED: The parameter to \b osMailQ shall be consistent but the
|
||||
/// macro body is implementation specific in every CMSIS-RTOS.
|
||||
#define osMailQ(name) \
|
||||
&os_mailQ_def_##name
|
||||
|
||||
/// Create and Initialize a Mail Queue object.
|
||||
/// \param[in] queue_def mail queue definition referenced with \ref osMailQ.
|
||||
/// \param[in] thread_id thread ID (obtained by \ref osThreadCreate or \ref osThreadGetId) or NULL.
|
||||
/// \return mail queue ID for reference by other functions or NULL in case of error.
|
||||
osMailQId osMailCreate (const osMailQDef_t *queue_def, osThreadId thread_id);
|
||||
|
||||
/// Allocate a memory block for mail from a mail memory pool.
|
||||
/// \param[in] queue_id mail queue ID obtained with \ref osMailCreate.
|
||||
/// \param[in] millisec \ref CMSIS_RTOS_TimeOutValue or 0 in case of no time-out
|
||||
/// \return pointer to memory block that can be filled with mail or NULL in case of error.
|
||||
void *osMailAlloc (osMailQId queue_id, uint32_t millisec);
|
||||
|
||||
/// Allocate a memory block for mail from a mail memory pool and set memory block to zero.
|
||||
/// \param[in] queue_id mail queue ID obtained with \ref osMailCreate.
|
||||
/// \param[in] millisec \ref CMSIS_RTOS_TimeOutValue or 0 in case of no time-out
|
||||
/// \return pointer to memory block that can be filled with mail or NULL in case of error.
|
||||
void *osMailCAlloc (osMailQId queue_id, uint32_t millisec);
|
||||
|
||||
/// Put a Mail into a Queue.
|
||||
/// \param[in] queue_id mail queue ID obtained with \ref osMailCreate.
|
||||
/// \param[in] mail pointer to memory with mail to put into a queue.
|
||||
/// \return status code that indicates the execution status of the function.
|
||||
osStatus osMailPut (osMailQId queue_id, const void *mail);
|
||||
|
||||
/// Get a Mail from a Queue or timeout if Queue is empty.
|
||||
/// \param[in] queue_id mail queue ID obtained with \ref osMailCreate.
|
||||
/// \param[in] millisec \ref CMSIS_RTOS_TimeOutValue or 0 in case of no time-out.
|
||||
/// \return event information that includes status code.
|
||||
osEvent osMailGet (osMailQId queue_id, uint32_t millisec);
|
||||
|
||||
/// Free a memory block by returning it to a mail memory pool.
|
||||
/// \param[in] queue_id mail queue ID obtained with \ref osMailCreate.
|
||||
/// \param[in] mail pointer to memory block that was obtained with \ref osMailGet.
|
||||
/// \return status code that indicates the execution status of the function.
|
||||
osStatus osMailFree (osMailQId queue_id, void *mail);
|
||||
|
||||
#endif // Mail Queue available
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif // CMSIS_OS_H_
|
||||
@@ -0,0 +1,361 @@
|
||||
/*
|
||||
* Copyright (c) 2013-2017 ARM Limited. All rights reserved.
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the License); you may
|
||||
* not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an AS IS BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
* ----------------------------------------------------------------------
|
||||
*
|
||||
* $Date: 10. January 2017
|
||||
* $Revision: V1.2
|
||||
*
|
||||
* Project: CMSIS-RTOS API V1
|
||||
* Title: cmsis_os_v1.c V1 module file
|
||||
*---------------------------------------------------------------------------*/
|
||||
|
||||
#include <string.h>
|
||||
#include "cmsis_os.h"
|
||||
|
||||
#if (osCMSIS >= 0x20000U)
|
||||
|
||||
|
||||
// Thread
|
||||
osThreadId osThreadCreate (const osThreadDef_t *thread_def, void *argument) {
|
||||
|
||||
if (thread_def == NULL) {
|
||||
return (osThreadId)NULL;
|
||||
}
|
||||
return osThreadNew((osThreadFunc_t)thread_def->pthread, argument, &thread_def->attr);
|
||||
}
|
||||
|
||||
|
||||
// Signals
|
||||
|
||||
#define SignalMask ((1U<<osFeature_Signals)-1U)
|
||||
|
||||
int32_t osSignalSet (osThreadId thread_id, int32_t signals) {
|
||||
uint32_t flags;
|
||||
|
||||
flags = osThreadFlagsSet(thread_id, (uint32_t)signals);
|
||||
if ((flags & 0x80000000U) != 0U) {
|
||||
return ((int32_t)0x80000000U);
|
||||
}
|
||||
return ((int32_t)(flags & ~((uint32_t)signals)));
|
||||
}
|
||||
|
||||
int32_t osSignalClear (osThreadId thread_id, int32_t signals) {
|
||||
uint32_t flags;
|
||||
|
||||
if (thread_id != osThreadGetId()) {
|
||||
return ((int32_t)0x80000000U);
|
||||
}
|
||||
flags = osThreadFlagsClear((uint32_t)signals);
|
||||
if ((flags & 0x80000000U) != 0U) {
|
||||
return ((int32_t)0x80000000U);
|
||||
}
|
||||
return ((int32_t)flags);
|
||||
}
|
||||
|
||||
osEvent osSignalWait (int32_t signals, uint32_t millisec) {
|
||||
osEvent event;
|
||||
uint32_t flags;
|
||||
|
||||
if (signals != 0) {
|
||||
flags = osThreadFlagsWait((uint32_t)signals, osFlagsWaitAll, millisec);
|
||||
} else {
|
||||
flags = osThreadFlagsWait(SignalMask, osFlagsWaitAny, millisec);
|
||||
}
|
||||
if ((flags > 0U) && (flags < 0x80000000U)) {
|
||||
event.status = osEventSignal;
|
||||
event.value.signals = (int32_t)flags;
|
||||
} else {
|
||||
switch ((int32_t)flags) {
|
||||
case osErrorResource:
|
||||
event.status = osOK;
|
||||
break;
|
||||
case osErrorTimeout:
|
||||
event.status = osEventTimeout;
|
||||
break;
|
||||
case osErrorParameter:
|
||||
event.status = osErrorValue;
|
||||
break;
|
||||
default:
|
||||
event.status = (osStatus)flags;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return event;
|
||||
}
|
||||
|
||||
|
||||
// Timer
|
||||
osTimerId osTimerCreate (const osTimerDef_t *timer_def, os_timer_type type, void *argument) {
|
||||
|
||||
if (timer_def == NULL) {
|
||||
return (osTimerId)NULL;
|
||||
}
|
||||
return osTimerNew((osTimerFunc_t)timer_def->ptimer, type, argument, &timer_def->attr);
|
||||
}
|
||||
|
||||
|
||||
// Mutex
|
||||
osMutexId osMutexCreate (const osMutexDef_t *mutex_def) {
|
||||
|
||||
if (mutex_def == NULL) {
|
||||
return (osMutexId)NULL;
|
||||
}
|
||||
return osMutexNew(mutex_def);
|
||||
}
|
||||
|
||||
|
||||
// Semaphore
|
||||
|
||||
#if (defined (osFeature_Semaphore) && (osFeature_Semaphore != 0U))
|
||||
|
||||
osSemaphoreId osSemaphoreCreate (const osSemaphoreDef_t *semaphore_def, int32_t count) {
|
||||
|
||||
if (semaphore_def == NULL) {
|
||||
return (osSemaphoreId)NULL;
|
||||
}
|
||||
return osSemaphoreNew((uint32_t)count, (uint32_t)count, semaphore_def);
|
||||
}
|
||||
|
||||
int32_t osSemaphoreWait (osSemaphoreId semaphore_id, uint32_t millisec) {
|
||||
osStatus_t status;
|
||||
uint32_t count;
|
||||
|
||||
status = osSemaphoreAcquire(semaphore_id, millisec);
|
||||
switch (status) {
|
||||
case osOK:
|
||||
count = osSemaphoreGetCount(semaphore_id);
|
||||
return ((int32_t)count + 1);
|
||||
case osErrorResource:
|
||||
case osErrorTimeout:
|
||||
return 0;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
#endif // Semaphore
|
||||
|
||||
|
||||
// Memory Pool
|
||||
|
||||
#if (defined(osFeature_Pool) && (osFeature_Pool != 0))
|
||||
|
||||
osPoolId osPoolCreate (const osPoolDef_t *pool_def) {
|
||||
|
||||
if (pool_def == NULL) {
|
||||
return (osPoolId)NULL;
|
||||
}
|
||||
return ((osPoolId)(osMemoryPoolNew(pool_def->pool_sz, pool_def->item_sz, &pool_def->attr)));
|
||||
}
|
||||
|
||||
void *osPoolAlloc (osPoolId pool_id) {
|
||||
return osMemoryPoolAlloc((osMemoryPoolId_t)pool_id, 0U);
|
||||
}
|
||||
|
||||
void *osPoolCAlloc (osPoolId pool_id) {
|
||||
void *block;
|
||||
uint32_t block_size;
|
||||
|
||||
block_size = osMemoryPoolGetBlockSize((osMemoryPoolId_t)pool_id);
|
||||
if (block_size == 0U) {
|
||||
return NULL;
|
||||
}
|
||||
block = osMemoryPoolAlloc((osMemoryPoolId_t)pool_id, 0U);
|
||||
if (block != NULL) {
|
||||
memset(block, 0, block_size);
|
||||
}
|
||||
return block;
|
||||
}
|
||||
|
||||
osStatus osPoolFree (osPoolId pool_id, void *block) {
|
||||
return osMemoryPoolFree((osMemoryPoolId_t)pool_id, block);
|
||||
}
|
||||
|
||||
#endif // Memory Pool
|
||||
|
||||
|
||||
// Message Queue
|
||||
|
||||
#if (defined(osFeature_MessageQ) && (osFeature_MessageQ != 0))
|
||||
|
||||
osMessageQId osMessageCreate (const osMessageQDef_t *queue_def, osThreadId thread_id) {
|
||||
(void)thread_id;
|
||||
|
||||
if (queue_def == NULL) {
|
||||
return (osMessageQId)NULL;
|
||||
}
|
||||
return ((osMessageQId)(osMessageQueueNew(queue_def->queue_sz, sizeof(uint32_t), &queue_def->attr)));
|
||||
}
|
||||
|
||||
osStatus osMessagePut (osMessageQId queue_id, uint32_t info, uint32_t millisec) {
|
||||
return osMessageQueuePut((osMessageQueueId_t)queue_id, &info, 0U, millisec);
|
||||
}
|
||||
|
||||
osEvent osMessageGet (osMessageQId queue_id, uint32_t millisec) {
|
||||
osStatus_t status;
|
||||
osEvent event;
|
||||
uint32_t message;
|
||||
|
||||
status = osMessageQueueGet((osMessageQueueId_t)queue_id, &message, NULL, millisec);
|
||||
switch (status) {
|
||||
case osOK:
|
||||
event.status = osEventMessage;
|
||||
event.value.v = message;
|
||||
break;
|
||||
case osErrorResource:
|
||||
event.status = osOK;
|
||||
break;
|
||||
case osErrorTimeout:
|
||||
event.status = osEventTimeout;
|
||||
break;
|
||||
default:
|
||||
event.status = status;
|
||||
break;
|
||||
}
|
||||
return event;
|
||||
}
|
||||
|
||||
#endif // Message Queue
|
||||
|
||||
|
||||
// Mail Queue
|
||||
|
||||
#if (defined(osFeature_MailQ) && (osFeature_MailQ != 0))
|
||||
|
||||
typedef struct os_mail_queue_s {
|
||||
osMemoryPoolId_t mp_id;
|
||||
osMessageQueueId_t mq_id;
|
||||
} os_mail_queue_t;
|
||||
|
||||
osMailQId osMailCreate (const osMailQDef_t *queue_def, osThreadId thread_id) {
|
||||
os_mail_queue_t *ptr;
|
||||
(void)thread_id;
|
||||
|
||||
if (queue_def == NULL) {
|
||||
return (osMailQId)NULL;
|
||||
}
|
||||
|
||||
ptr = queue_def->mail;
|
||||
if (ptr == NULL) {
|
||||
return (osMailQId)NULL;
|
||||
}
|
||||
|
||||
ptr->mp_id = osMemoryPoolNew (queue_def->queue_sz, queue_def->item_sz, &queue_def->mp_attr);
|
||||
ptr->mq_id = osMessageQueueNew(queue_def->queue_sz, sizeof(void *), &queue_def->mq_attr);
|
||||
if ((ptr->mp_id == (osMemoryPoolId_t)NULL) || (ptr->mq_id == (osMessageQueueId_t)NULL)) {
|
||||
if (ptr->mp_id != (osMemoryPoolId_t)NULL) {
|
||||
osMemoryPoolDelete(ptr->mp_id);
|
||||
}
|
||||
if (ptr->mq_id != (osMessageQueueId_t)NULL) {
|
||||
osMessageQueueDelete(ptr->mq_id);
|
||||
}
|
||||
return (osMailQId)NULL;
|
||||
}
|
||||
|
||||
return (osMailQId)ptr;
|
||||
}
|
||||
|
||||
void *osMailAlloc (osMailQId queue_id, uint32_t millisec) {
|
||||
os_mail_queue_t *ptr = (os_mail_queue_t *)queue_id;
|
||||
|
||||
if (ptr == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
return osMemoryPoolAlloc(ptr->mp_id, millisec);
|
||||
}
|
||||
|
||||
void *osMailCAlloc (osMailQId queue_id, uint32_t millisec) {
|
||||
os_mail_queue_t *ptr = (os_mail_queue_t *)queue_id;
|
||||
void *block;
|
||||
uint32_t block_size;
|
||||
|
||||
if (ptr == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
block_size = osMemoryPoolGetBlockSize(ptr->mp_id);
|
||||
if (block_size == 0U) {
|
||||
return NULL;
|
||||
}
|
||||
block = osMemoryPoolAlloc(ptr->mp_id, millisec);
|
||||
if (block != NULL) {
|
||||
memset(block, 0, block_size);
|
||||
}
|
||||
|
||||
return block;
|
||||
|
||||
}
|
||||
|
||||
osStatus osMailPut (osMailQId queue_id, const void *mail) {
|
||||
os_mail_queue_t *ptr = (os_mail_queue_t *)queue_id;
|
||||
|
||||
if (ptr == NULL) {
|
||||
return osErrorParameter;
|
||||
}
|
||||
if (mail == NULL) {
|
||||
return osErrorValue;
|
||||
}
|
||||
return osMessageQueuePut(ptr->mq_id, &mail, 0U, 0U);
|
||||
}
|
||||
|
||||
osEvent osMailGet (osMailQId queue_id, uint32_t millisec) {
|
||||
os_mail_queue_t *ptr = (os_mail_queue_t *)queue_id;
|
||||
osStatus_t status;
|
||||
osEvent event;
|
||||
void *mail;
|
||||
|
||||
if (ptr == NULL) {
|
||||
event.status = osErrorParameter;
|
||||
return event;
|
||||
}
|
||||
|
||||
status = osMessageQueueGet(ptr->mq_id, &mail, NULL, millisec);
|
||||
switch (status) {
|
||||
case osOK:
|
||||
event.status = osEventMail;
|
||||
event.value.p = mail;
|
||||
break;
|
||||
case osErrorResource:
|
||||
event.status = osOK;
|
||||
break;
|
||||
case osErrorTimeout:
|
||||
event.status = osEventTimeout;
|
||||
break;
|
||||
default:
|
||||
event.status = status;
|
||||
break;
|
||||
}
|
||||
return event;
|
||||
}
|
||||
|
||||
osStatus osMailFree (osMailQId queue_id, void *mail) {
|
||||
os_mail_queue_t *ptr = (os_mail_queue_t *)queue_id;
|
||||
|
||||
if (ptr == NULL) {
|
||||
return osErrorParameter;
|
||||
}
|
||||
if (mail == NULL) {
|
||||
return osErrorValue;
|
||||
}
|
||||
return osMemoryPoolFree(ptr->mp_id, mail);
|
||||
}
|
||||
|
||||
#endif // Mail Queue
|
||||
|
||||
|
||||
#endif // osCMSIS
|
||||
Reference in New Issue
Block a user