add lib/CMSIS_5 v5.7 locally

This commit is contained in:
hathach
2021-03-02 11:02:16 +07:00
parent 7afaae7ffc
commit 42ff88bdaf
103 changed files with 81252 additions and 0 deletions
+756
View File
@@ -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_
+71
View File
@@ -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,
// ...
};
+133
View File
@@ -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
+922
View File
@@ -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