7 changed files with 817 additions and 9 deletions
-
12.cproject
-
2.settings/stm32cubeide.project.prefs
-
423Core/ThreadSafe/newlib_lock_glue.c
-
375Core/ThreadSafe/stm32_lock.h
-
4STM32F407VETX_FLASH.ld
-
4STM32F407VETX_RAM.ld
-
6dbdb_liquid_path_control_v2.ioc
@ -1,5 +1,5 @@ |
|||||
635E684B79701B039C64EA45C3F84D30=C8B026EBE17C208F17FB66CE4235156C |
635E684B79701B039C64EA45C3F84D30=C8B026EBE17C208F17FB66CE4235156C |
||||
66BE74F758C12D739921AEA421D593D3=1 |
66BE74F758C12D739921AEA421D593D3=1 |
||||
8DF89ED150041C4CBC7CB9A9CAA90856=807DDB2C2702E438DB0EBF3D5AA6AB41 |
8DF89ED150041C4CBC7CB9A9CAA90856=807DDB2C2702E438DB0EBF3D5AA6AB41 |
||||
DC22A860405A8BF2F2C095E5B6529F12=D3CF7BFAB9D98A63886F1AE7AFAEA0B9 |
|
||||
|
DC22A860405A8BF2F2C095E5B6529F12=1A37C75E31949FC1CF47D46CC4BFA318 |
||||
eclipse.preferences.version=1 |
eclipse.preferences.version=1 |
@ -0,0 +1,423 @@ |
|||||
|
/** |
||||
|
****************************************************************************** |
||||
|
* @file newlib_lock_glue.c |
||||
|
* @author STMicroelectronics |
||||
|
* @brief Implementation of newlib lock interface |
||||
|
* |
||||
|
* @details This file implements locking glue necessary to protect C library |
||||
|
* functions and initialization of local static objects in C++. |
||||
|
* Lock strategies are defined in stm32_lock.h that implements |
||||
|
* different level of thread-safety. |
||||
|
* |
||||
|
* For more information about which C functions need which of these |
||||
|
* low level functions, please consult the newlib libc manual, |
||||
|
* see https://sourceware.org/newlib/libc.html |
||||
|
* |
||||
|
* For more information about the one-time construction API for C++, |
||||
|
* see https://itanium-cxx-abi.github.io/cxx-abi/abi.html#once-ctor |
||||
|
* |
||||
|
****************************************************************************** |
||||
|
* @attention |
||||
|
* |
||||
|
* Copyright (c) 2023 STMicroelectronics. |
||||
|
* All rights reserved. |
||||
|
* |
||||
|
* This software is licensed under terms that can be found in the LICENSE file |
||||
|
* in the root directory of this software component. |
||||
|
* If no LICENSE file comes with this software, it is provided AS-IS. |
||||
|
* |
||||
|
****************************************************************************** |
||||
|
*/ |
||||
|
|
||||
|
#if !defined (__GNUC__) || defined (__CC_ARM) |
||||
|
#error "newlib_lock_glue.c" should be used with GNU Compilers only |
||||
|
#endif /* !defined (__GNUC__) || defined (__CC_ARM) */ |
||||
|
|
||||
|
/* Includes ------------------------------------------------------------------*/ |
||||
|
#include <cmsis_compiler.h> |
||||
|
|
||||
|
/* Private functions ---------------------------------------------------------*/ |
||||
|
|
||||
|
/** |
||||
|
* @brief Global Error_Handler |
||||
|
*/ |
||||
|
__WEAK void Error_Handler(void) |
||||
|
{ |
||||
|
/* Not used if it exists in project */ |
||||
|
while (1); |
||||
|
} |
||||
|
|
||||
|
#ifdef __SINGLE_THREAD__ |
||||
|
#warning C library is in single-threaded mode. Please take care when using C library functions in threaded contexts |
||||
|
#else |
||||
|
|
||||
|
/* Includes ------------------------------------------------------------------*/ |
||||
|
#include <newlib.h> |
||||
|
#include <stdatomic.h> |
||||
|
#include "stm32_lock.h" |
||||
|
|
||||
|
/** |
||||
|
* @defgroup _newlib_lock_functions newlib library locks |
||||
|
* @see https://sourceware.org/newlib/libc.html |
||||
|
* @{ |
||||
|
*/ |
||||
|
|
||||
|
#if __NEWLIB__ >= 3 && defined (_RETARGETABLE_LOCKING) |
||||
|
#include <errno.h> |
||||
|
#include <stdlib.h> |
||||
|
#include <sys/lock.h> |
||||
|
|
||||
|
/* Private macros ------------------------------------------------------------*/ |
||||
|
/** See struct __lock definition */ |
||||
|
#define STM32_LOCK_PARAMETER(lock) (&(lock)->lock_data) |
||||
|
|
||||
|
/* Private variables ---------------------------------------------------------*/ |
||||
|
struct __lock |
||||
|
{ |
||||
|
LockingData_t lock_data; /**< The STM32 lock instance */ |
||||
|
}; |
||||
|
|
||||
|
/** Implementing mutex from <a href="https://sourceware.org/git/?p=newlib-cygwin.git;a=blob_plain;f=newlib/libc/misc/lock.c">newlib/libc/misc/lock.c</a> */ |
||||
|
struct __lock __lock___sinit_recursive_mutex = { LOCKING_DATA_INIT }; |
||||
|
|
||||
|
/** Implementing mutex from <a href="https://sourceware.org/git/?p=newlib-cygwin.git;a=blob_plain;f=newlib/libc/misc/lock.c">newlib/libc/misc/lock.c</a> */ |
||||
|
struct __lock __lock___sfp_recursive_mutex = { LOCKING_DATA_INIT }; |
||||
|
|
||||
|
/** Implementing mutex from <a href="https://sourceware.org/git/?p=newlib-cygwin.git;a=blob_plain;f=newlib/libc/misc/lock.c">newlib/libc/misc/lock.c</a> */ |
||||
|
struct __lock __lock___atexit_recursive_mutex = { LOCKING_DATA_INIT }; |
||||
|
|
||||
|
/** Implementing mutex from <a href="https://sourceware.org/git/?p=newlib-cygwin.git;a=blob_plain;f=newlib/libc/misc/lock.c">newlib/libc/misc/lock.c</a> */ |
||||
|
struct __lock __lock___at_quick_exit_mutex = { LOCKING_DATA_INIT }; |
||||
|
|
||||
|
/** Implementing mutex from <a href="https://sourceware.org/git/?p=newlib-cygwin.git;a=blob_plain;f=newlib/libc/misc/lock.c">newlib/libc/misc/lock.c</a> */ |
||||
|
struct __lock __lock___malloc_recursive_mutex = { LOCKING_DATA_INIT }; |
||||
|
|
||||
|
/** Implementing mutex from <a href="https://sourceware.org/git/?p=newlib-cygwin.git;a=blob_plain;f=newlib/libc/misc/lock.c">newlib/libc/misc/lock.c</a> */ |
||||
|
struct __lock __lock___env_recursive_mutex = { LOCKING_DATA_INIT }; |
||||
|
|
||||
|
/** Implementing mutex from <a href="https://sourceware.org/git/?p=newlib-cygwin.git;a=blob_plain;f=newlib/libc/misc/lock.c">newlib/libc/misc/lock.c</a> */ |
||||
|
struct __lock __lock___tz_mutex = { LOCKING_DATA_INIT }; |
||||
|
|
||||
|
/** Implementing mutex from <a href="https://sourceware.org/git/?p=newlib-cygwin.git;a=blob_plain;f=newlib/libc/misc/lock.c">newlib/libc/misc/lock.c</a> */ |
||||
|
struct __lock __lock___dd_hash_mutex = { LOCKING_DATA_INIT }; |
||||
|
|
||||
|
/** Implementing mutex from <a href="https://sourceware.org/git/?p=newlib-cygwin.git;a=blob_plain;f=newlib/libc/misc/lock.c">newlib/libc/misc/lock.c</a> */ |
||||
|
struct __lock __lock___arc4random_mutex = { LOCKING_DATA_INIT }; |
||||
|
|
||||
|
/* Private functions ---------------------------------------------------------*/ |
||||
|
|
||||
|
/** |
||||
|
* @brief Initialize lock |
||||
|
* @param lock The lock |
||||
|
*/ |
||||
|
void __retarget_lock_init(_LOCK_T *lock) |
||||
|
{ |
||||
|
__retarget_lock_init_recursive(lock); |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* @brief Initialize recursive lock |
||||
|
* @param lock The lock |
||||
|
*/ |
||||
|
void __retarget_lock_init_recursive(_LOCK_T *lock) |
||||
|
{ |
||||
|
if (lock == NULL) |
||||
|
{ |
||||
|
errno = EINVAL; |
||||
|
return; |
||||
|
} |
||||
|
|
||||
|
*lock = (_LOCK_T)malloc(sizeof(struct __lock)); |
||||
|
if (*lock != NULL) |
||||
|
{ |
||||
|
stm32_lock_init(STM32_LOCK_PARAMETER(*lock)); |
||||
|
return; |
||||
|
} |
||||
|
|
||||
|
/* Unable to allocate memory */ |
||||
|
STM32_LOCK_BLOCK(); |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* @brief Close lock |
||||
|
* @param lock The lock |
||||
|
*/ |
||||
|
void __retarget_lock_close(_LOCK_T lock) |
||||
|
{ |
||||
|
__retarget_lock_close_recursive(lock); |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* @brief Close recursive lock |
||||
|
* @param lock The lock |
||||
|
*/ |
||||
|
void __retarget_lock_close_recursive(_LOCK_T lock) |
||||
|
{ |
||||
|
free(lock); |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* @brief Acquire lock |
||||
|
* @param lock The lock |
||||
|
*/ |
||||
|
void __retarget_lock_acquire(_LOCK_T lock) |
||||
|
{ |
||||
|
STM32_LOCK_BLOCK_IF_NULL_ARGUMENT(lock); |
||||
|
stm32_lock_acquire(STM32_LOCK_PARAMETER(lock)); |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* @brief Acquire recursive lock |
||||
|
* @param lock The lock |
||||
|
*/ |
||||
|
void __retarget_lock_acquire_recursive(_LOCK_T lock) |
||||
|
{ |
||||
|
STM32_LOCK_BLOCK_IF_NULL_ARGUMENT(lock); |
||||
|
stm32_lock_acquire(STM32_LOCK_PARAMETER(lock)); |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* @brief Try acquire lock |
||||
|
* @param lock The lock |
||||
|
* @return 0 always |
||||
|
*/ |
||||
|
int __retarget_lock_try_acquire(_LOCK_T lock) |
||||
|
{ |
||||
|
__retarget_lock_acquire(lock); |
||||
|
return 0; |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* @brief Try acquire recursive lock |
||||
|
* @param lock The lock |
||||
|
* @return 0 always |
||||
|
*/ |
||||
|
int __retarget_lock_try_acquire_recursive(_LOCK_T lock) |
||||
|
{ |
||||
|
__retarget_lock_acquire_recursive(lock); |
||||
|
return 0; |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* @brief Release lock |
||||
|
* @param lock The lock |
||||
|
*/ |
||||
|
void __retarget_lock_release(_LOCK_T lock) |
||||
|
{ |
||||
|
STM32_LOCK_BLOCK_IF_NULL_ARGUMENT(lock); |
||||
|
stm32_lock_release(STM32_LOCK_PARAMETER(lock)); |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* @brief Release recursive lock |
||||
|
* @param lock The lock |
||||
|
*/ |
||||
|
void __retarget_lock_release_recursive(_LOCK_T lock) |
||||
|
{ |
||||
|
STM32_LOCK_BLOCK_IF_NULL_ARGUMENT(lock); |
||||
|
stm32_lock_release(STM32_LOCK_PARAMETER(lock)); |
||||
|
} |
||||
|
|
||||
|
#else |
||||
|
#warning This makes malloc, env, and TZ calls thread-safe, not the entire newlib |
||||
|
|
||||
|
/* Includes ------------------------------------------------------------------*/ |
||||
|
#include <reent.h> |
||||
|
|
||||
|
/* Private variables ---------------------------------------------------------*/ |
||||
|
/** Mutex used in __malloc_lock and __malloc_unlock */ |
||||
|
static LockingData_t __lock___malloc_recursive_mutex = LOCKING_DATA_INIT; |
||||
|
|
||||
|
/** Mutex used in __env_lock and __env_unlock */ |
||||
|
static LockingData_t __lock___env_recursive_mutex = LOCKING_DATA_INIT; |
||||
|
|
||||
|
/** Mutex used in __tz_lock and __tz_unlock */ |
||||
|
static LockingData_t __lock___tz_mutex = LOCKING_DATA_INIT; |
||||
|
|
||||
|
/* Private functions ---------------------------------------------------------*/ |
||||
|
|
||||
|
#if __STD_C |
||||
|
|
||||
|
/** |
||||
|
* @brief Acquire malloc lock |
||||
|
* @param reent The reentrance struct |
||||
|
*/ |
||||
|
void __malloc_lock(struct _reent *reent) |
||||
|
{ |
||||
|
STM32_LOCK_UNUSED(reent); |
||||
|
stm32_lock_acquire(&__lock___malloc_recursive_mutex); |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* @brief Release malloc lock |
||||
|
* @param reent The reentrance struct |
||||
|
*/ |
||||
|
void __malloc_unlock(struct _reent *reent) |
||||
|
{ |
||||
|
STM32_LOCK_UNUSED(reent); |
||||
|
stm32_lock_release(&__lock___malloc_recursive_mutex); |
||||
|
} |
||||
|
|
||||
|
#else |
||||
|
|
||||
|
/** |
||||
|
* @brief Acquire malloc lock |
||||
|
*/ |
||||
|
void __malloc_lock() |
||||
|
{ |
||||
|
stm32_lock_acquire(&__lock___malloc_recursive_mutex); |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* @brief Release malloc lock |
||||
|
*/ |
||||
|
void __malloc_unlock() |
||||
|
{ |
||||
|
stm32_lock_release(&__lock___malloc_recursive_mutex); |
||||
|
} |
||||
|
#endif /* __STD_C */ |
||||
|
|
||||
|
/** |
||||
|
* @brief Acquire env lock |
||||
|
* @param reent The reentrance struct |
||||
|
*/ |
||||
|
void __env_lock(struct _reent *reent) |
||||
|
{ |
||||
|
STM32_LOCK_UNUSED(reent); |
||||
|
stm32_lock_acquire(&__lock___env_recursive_mutex); |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* @brief Release env lock |
||||
|
* @param reent The reentrance struct |
||||
|
*/ |
||||
|
void __env_unlock(struct _reent *reent) |
||||
|
{ |
||||
|
STM32_LOCK_UNUSED(reent); |
||||
|
stm32_lock_release(&__lock___env_recursive_mutex); |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* @brief Acquire tz lock |
||||
|
*/ |
||||
|
void __tz_lock() |
||||
|
{ |
||||
|
stm32_lock_acquire(&__lock___tz_mutex); |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* @brief Release tz lock |
||||
|
*/ |
||||
|
void __tz_unlock() |
||||
|
{ |
||||
|
stm32_lock_release(&__lock___tz_mutex); |
||||
|
} |
||||
|
|
||||
|
#endif /* __NEWLIB__ >= 3 && defined (_RETARGETABLE_LOCKING) */ |
||||
|
|
||||
|
/** |
||||
|
* @} |
||||
|
*/ |
||||
|
|
||||
|
|
||||
|
/** |
||||
|
* @defgroup __cxa_guard_ GNU C++ one-time construction API |
||||
|
* @see https://itanium-cxx-abi.github.io/cxx-abi/abi.html#once-ctor |
||||
|
* |
||||
|
* When building for C++, please make sure that <tt>-fno-threadsafe-statics</tt> is not passed to the compiler |
||||
|
* @{ |
||||
|
*/ |
||||
|
|
||||
|
/* Private typedef -----------------------------------------------------------*/ |
||||
|
/** The guard object is created by the C++ compiler and is 32 bit for ARM EABI. */ |
||||
|
typedef struct |
||||
|
{ |
||||
|
atomic_uchar initialized; /**< Indicate if object is initialized */ |
||||
|
uint8_t acquired; /**< Ensure non-recursive lock */ |
||||
|
uint16_t unused; /**< Padding */ |
||||
|
} __attribute__((packed)) CxaGuardObject_t; |
||||
|
|
||||
|
/* Private variables ---------------------------------------------------------*/ |
||||
|
/** Mutex used in __cxa_guard_acquire, __cxa_guard_release and __cxa_guard_abort */ |
||||
|
static LockingData_t __cxa_guard_mutex = LOCKING_DATA_INIT; |
||||
|
|
||||
|
/* Private functions ---------------------------------------------------------*/ |
||||
|
|
||||
|
/** |
||||
|
* @brief Acquire __cxa_guard mutex |
||||
|
* @param guard_object Guard object |
||||
|
* @return 0 if object is initialized, else initialization of object required |
||||
|
*/ |
||||
|
int __cxa_guard_acquire(CxaGuardObject_t *guard_object) |
||||
|
{ |
||||
|
STM32_LOCK_BLOCK_IF_NULL_ARGUMENT(guard_object); |
||||
|
|
||||
|
if (atomic_load(&guard_object->initialized) == 0) |
||||
|
{ |
||||
|
/* Object needs initialization, lock threading context */ |
||||
|
stm32_lock_acquire(&__cxa_guard_mutex); |
||||
|
if (atomic_load(&guard_object->initialized) == 0) |
||||
|
{ |
||||
|
/* Object needs initialization */ |
||||
|
if (guard_object->acquired) |
||||
|
{ |
||||
|
/* Object initialization already in progress */ |
||||
|
STM32_LOCK_BLOCK(); |
||||
|
} |
||||
|
|
||||
|
/* Lock acquired */ |
||||
|
guard_object->acquired = 1; |
||||
|
return 1; |
||||
|
} |
||||
|
else |
||||
|
{ |
||||
|
/* Object initialized in another thread */ |
||||
|
stm32_lock_release(&__cxa_guard_mutex); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
/* Object already initialized */ |
||||
|
return 0; |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* @brief Abort __cxa_guard mutex |
||||
|
* @param guard_object Guard object |
||||
|
*/ |
||||
|
void __cxa_guard_abort(CxaGuardObject_t *guard_object) |
||||
|
{ |
||||
|
STM32_LOCK_BLOCK_IF_NULL_ARGUMENT(guard_object); |
||||
|
|
||||
|
if (guard_object->acquired) |
||||
|
{ |
||||
|
/* Release lock */ |
||||
|
guard_object->acquired = 0; |
||||
|
stm32_lock_release(&__cxa_guard_mutex); |
||||
|
} |
||||
|
else |
||||
|
{ |
||||
|
/* Trying to release non-acquired lock */ |
||||
|
STM32_LOCK_BLOCK(); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* @brief Release __cxa_guard mutex |
||||
|
* @param guard_object Guard object |
||||
|
*/ |
||||
|
void __cxa_guard_release(CxaGuardObject_t *guard_object) |
||||
|
{ |
||||
|
STM32_LOCK_BLOCK_IF_NULL_ARGUMENT(guard_object); |
||||
|
|
||||
|
/* Object initialized */ |
||||
|
atomic_store(&guard_object->initialized, 1); |
||||
|
|
||||
|
/* Release lock */ |
||||
|
__cxa_guard_abort(guard_object); |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* @} |
||||
|
*/ |
||||
|
|
||||
|
#endif /* __SINGLE_THREAD__ */ |
@ -0,0 +1,375 @@ |
|||||
|
/** |
||||
|
****************************************************************************** |
||||
|
* @file stm32_lock.h |
||||
|
* @author STMicroelectronics |
||||
|
* @brief STMicroelectronics lock mechanisms |
||||
|
* |
||||
|
* @details |
||||
|
* This implementation supports the following strategies for handling |
||||
|
* thread-safe locks. The strategy can be explicitly selected by |
||||
|
* defining <tt>\STM32_THREAD_SAFE_STRATEGY = \<number></tt> in the project. |
||||
|
* Please look at the '<toolchain/library>_lock_glue.c' file for more details. |
||||
|
* |
||||
|
* 1. User defined thread-safe implementation. |
||||
|
* User defined solution for handling thread-safety. |
||||
|
* <br> |
||||
|
* <b>NOTE:</b> The stubs in stm32_lock_user.h needs to be implemented to gain |
||||
|
* thread-safety. |
||||
|
* |
||||
|
* 2. [<b>DEFAULT</b>] Allow lock usage from interrupts. |
||||
|
* This implementation will ensure thread-safety by disabling all interrupts |
||||
|
* during e.g. calls to malloc. |
||||
|
* <br> |
||||
|
* <b>NOTE:</b> Disabling all interrupts creates interrupt latency which |
||||
|
* might not be desired for this application! |
||||
|
* |
||||
|
* 3. Deny lock usage from interrupts. |
||||
|
* This implementation assumes single thread of execution. |
||||
|
* <br> |
||||
|
* <b>NOTE:</b> Thread-safety dependent functions will enter an infinity loop |
||||
|
* if used in interrupt context. |
||||
|
* |
||||
|
* 4. Allow lock usage from interrupts. Implemented using FreeRTOS locks. |
||||
|
* This implementation will ensure thread-safety by entering RTOS ISR capable |
||||
|
* critical sections during e.g. calls to malloc. |
||||
|
* By default this implementation supports 2 levels of recursive locking. |
||||
|
* Adding additional levels requires 4 bytes per lock per level of RAM. |
||||
|
* <br> |
||||
|
* <b>NOTE:</b> Interrupts with high priority are not disabled. This implies |
||||
|
* that the lock is not thread-safe from high priority interrupts! |
||||
|
* |
||||
|
* 5. Deny lock usage from interrupts. Implemented using FreeRTOS locks. |
||||
|
* This implementation will ensure thread-safety by suspending all tasks |
||||
|
* during e.g. calls to malloc. |
||||
|
* <br> |
||||
|
* <b>NOTE:</b> Thread-safety dependent functions will enter an infinity loop |
||||
|
* if used in interrupt context. |
||||
|
* |
||||
|
****************************************************************************** |
||||
|
* @attention |
||||
|
* |
||||
|
* Copyright (c) 2023 STMicroelectronics. |
||||
|
* All rights reserved. |
||||
|
* |
||||
|
* This software is licensed under terms that can be found in the LICENSE file |
||||
|
* in the root directory of this software component. |
||||
|
* If no LICENSE file comes with this software, it is provided AS-IS. |
||||
|
* |
||||
|
****************************************************************************** |
||||
|
*/ |
||||
|
|
||||
|
#ifndef __STM32_LOCK_H__ |
||||
|
#define __STM32_LOCK_H__ |
||||
|
|
||||
|
/* Includes ------------------------------------------------------------------*/ |
||||
|
#include <stdint.h> |
||||
|
#include <stddef.h> |
||||
|
#include <cmsis_compiler.h> |
||||
|
|
||||
|
#ifndef STM32_THREAD_SAFE_STRATEGY |
||||
|
#define STM32_THREAD_SAFE_STRATEGY 2 /**< Assume strategy 2 if not specified */ |
||||
|
#endif /* STM32_THREAD_SAFE_STRATEGY */ |
||||
|
|
||||
|
#ifdef __cplusplus |
||||
|
extern "C" { |
||||
|
#endif /* __cplusplus */ |
||||
|
|
||||
|
/* Function prototypes -------------------------------------------------------*/ |
||||
|
void Error_Handler(void); |
||||
|
|
||||
|
/* Public macros -------------------------------------------------------------*/ |
||||
|
/** Blocks execution */ |
||||
|
#define STM32_LOCK_BLOCK() \ |
||||
|
do \ |
||||
|
{ \ |
||||
|
__disable_irq(); \ |
||||
|
Error_Handler(); \ |
||||
|
while (1); \ |
||||
|
} while (0) |
||||
|
|
||||
|
/** Blocks execution if argument is NULL */ |
||||
|
#define STM32_LOCK_BLOCK_IF_NULL_ARGUMENT(x) \ |
||||
|
do \ |
||||
|
{ \ |
||||
|
if ((x) == NULL) \ |
||||
|
{ \ |
||||
|
STM32_LOCK_BLOCK(); \ |
||||
|
} \ |
||||
|
} while (0) |
||||
|
|
||||
|
/** Blocks execution if in interrupt context */ |
||||
|
#define STM32_LOCK_BLOCK_IF_INTERRUPT_CONTEXT() \ |
||||
|
do \ |
||||
|
{ \ |
||||
|
if (__get_IPSR()) \ |
||||
|
{ \ |
||||
|
STM32_LOCK_BLOCK(); \ |
||||
|
} \ |
||||
|
} while (0) |
||||
|
|
||||
|
/** Hide unused parameter warning from compiler */ |
||||
|
#define STM32_LOCK_UNUSED(var) (void)var |
||||
|
|
||||
|
/** Size of array */ |
||||
|
#define STM32_LOCK_ARRAY_SIZE(array) (sizeof(array) / sizeof((array)[0])) |
||||
|
|
||||
|
#if STM32_THREAD_SAFE_STRATEGY == 1 |
||||
|
/* |
||||
|
* User defined thread-safe implementation. |
||||
|
*/ |
||||
|
|
||||
|
/* Includes ----------------------------------------------------------------*/ |
||||
|
/** STM32 lock API version */ |
||||
|
#define STM32_LOCK_API 1 |
||||
|
#include "stm32_lock_user.h" |
||||
|
#undef STM32_LOCK_API |
||||
|
|
||||
|
#elif STM32_THREAD_SAFE_STRATEGY == 2 |
||||
|
/* |
||||
|
* Allow lock usage from interrupts. |
||||
|
*/ |
||||
|
|
||||
|
/* Private defines ---------------------------------------------------------*/ |
||||
|
/** Initialize members in instance of <code>LockingData_t</code> structure */ |
||||
|
#define LOCKING_DATA_INIT { 0, 0 } |
||||
|
|
||||
|
/* Private typedef ---------------------------------------------------------*/ |
||||
|
typedef struct |
||||
|
{ |
||||
|
uint8_t flag; /**< Backup of PRIMASK.PM at nesting level 0 */ |
||||
|
uint8_t counter; /**< Nesting level */ |
||||
|
} LockingData_t; |
||||
|
|
||||
|
/* Private functions -------------------------------------------------------*/ |
||||
|
|
||||
|
/** |
||||
|
* @brief Initialize STM32 lock |
||||
|
* @param lock The lock to init |
||||
|
*/ |
||||
|
static inline void stm32_lock_init(LockingData_t *lock) |
||||
|
{ |
||||
|
STM32_LOCK_BLOCK_IF_NULL_ARGUMENT(lock); |
||||
|
lock->flag = 0; |
||||
|
lock->counter = 0; |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* @brief Acquire STM32 lock |
||||
|
* @param lock The lock to acquire |
||||
|
*/ |
||||
|
static inline void stm32_lock_acquire(LockingData_t *lock) |
||||
|
{ |
||||
|
uint8_t flag = (uint8_t)(__get_PRIMASK() & 0x1); /* PRIMASK.PM */ |
||||
|
__disable_irq(); |
||||
|
__DSB(); |
||||
|
__ISB(); |
||||
|
STM32_LOCK_BLOCK_IF_NULL_ARGUMENT(lock); |
||||
|
if (lock->counter == 0) |
||||
|
{ |
||||
|
lock->flag = flag; |
||||
|
} |
||||
|
else if (lock->counter == UINT8_MAX) |
||||
|
{ |
||||
|
STM32_LOCK_BLOCK(); |
||||
|
} |
||||
|
lock->counter++; |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* @brief Release STM32 lock |
||||
|
* @param lock The lock to release |
||||
|
*/ |
||||
|
static inline void stm32_lock_release(LockingData_t *lock) |
||||
|
{ |
||||
|
STM32_LOCK_BLOCK_IF_NULL_ARGUMENT(lock); |
||||
|
if (lock->counter == 0) |
||||
|
{ |
||||
|
STM32_LOCK_BLOCK(); |
||||
|
} |
||||
|
lock->counter--; |
||||
|
if (lock->counter == 0 && lock->flag == 0) |
||||
|
{ |
||||
|
__enable_irq(); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
#elif STM32_THREAD_SAFE_STRATEGY == 3 |
||||
|
/* |
||||
|
* Deny lock usage from interrupts. |
||||
|
*/ |
||||
|
|
||||
|
/* Private defines ---------------------------------------------------------*/ |
||||
|
/** Initialize members in instance of <code>LockingData_t</code> structure */ |
||||
|
#define LOCKING_DATA_INIT 0 |
||||
|
|
||||
|
/* Private typedef ---------------------------------------------------------*/ |
||||
|
typedef uint8_t LockingData_t; /**< Unused */ |
||||
|
|
||||
|
/* Private functions -------------------------------------------------------*/ |
||||
|
|
||||
|
/** |
||||
|
* @brief Initialize STM32 lock |
||||
|
* @param lock The lock to init |
||||
|
*/ |
||||
|
static inline void stm32_lock_init(LockingData_t *lock) |
||||
|
{ |
||||
|
STM32_LOCK_BLOCK_IF_NULL_ARGUMENT(lock); |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* @brief Acquire STM32 lock |
||||
|
* @param lock The lock to acquire |
||||
|
*/ |
||||
|
static inline void stm32_lock_acquire(LockingData_t *lock) |
||||
|
{ |
||||
|
STM32_LOCK_BLOCK_IF_NULL_ARGUMENT(lock); |
||||
|
STM32_LOCK_BLOCK_IF_INTERRUPT_CONTEXT(); |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* @brief Release ST lock |
||||
|
* @param lock The lock to release |
||||
|
*/ |
||||
|
static inline void stm32_lock_release(LockingData_t *lock) |
||||
|
{ |
||||
|
STM32_LOCK_BLOCK_IF_NULL_ARGUMENT(lock); |
||||
|
STM32_LOCK_BLOCK_IF_INTERRUPT_CONTEXT(); |
||||
|
} |
||||
|
|
||||
|
#elif STM32_THREAD_SAFE_STRATEGY == 4 |
||||
|
/* |
||||
|
* Allow lock usage from interrupts. Implemented using FreeRTOS locks. |
||||
|
*/ |
||||
|
|
||||
|
/* Includes ----------------------------------------------------------------*/ |
||||
|
#include <FreeRTOS.h> |
||||
|
#include <task.h> |
||||
|
|
||||
|
#if defined (__GNUC__) && !defined (__CC_ARM) && configUSE_NEWLIB_REENTRANT == 0 |
||||
|
#warning Please set configUSE_NEWLIB_REENTRANT to 1 in FreeRTOSConfig.h, otherwise newlib will not be thread-safe |
||||
|
#endif /* defined (__GNUC__) && !defined (__CC_ARM) && configUSE_NEWLIB_REENTRANT == 0 */ |
||||
|
|
||||
|
/* Private defines ---------------------------------------------------------*/ |
||||
|
/** Initialize members in instance of <code>LockingData_t</code> structure */ |
||||
|
#define LOCKING_DATA_INIT { {0, 0}, 0 } |
||||
|
#define STM32_LOCK_MAX_NESTED_LEVELS 2 /**< Max nesting level of interrupts */ |
||||
|
typedef struct |
||||
|
{ |
||||
|
uint32_t basepri[STM32_LOCK_MAX_NESTED_LEVELS]; |
||||
|
uint8_t nesting_level; |
||||
|
} LockingData_t; |
||||
|
|
||||
|
/* Private macros ----------------------------------------------------------*/ |
||||
|
/** Blocks execution if reached max nesting level */ |
||||
|
#define STM32_LOCK_ASSERT_VALID_NESTING_LEVEL(lock) \ |
||||
|
do \ |
||||
|
{ \ |
||||
|
if (lock->nesting_level >= STM32_LOCK_ARRAY_SIZE(lock->basepri)) \ |
||||
|
{ \ |
||||
|
STM32_LOCK_BLOCK(); \ |
||||
|
} \ |
||||
|
} while (0) |
||||
|
|
||||
|
/* Private functions -------------------------------------------------------*/ |
||||
|
|
||||
|
/** |
||||
|
* @brief Initialize STM32 lock |
||||
|
* @param lock The lock to init |
||||
|
*/ |
||||
|
static inline void stm32_lock_init(LockingData_t *lock) |
||||
|
{ |
||||
|
STM32_LOCK_BLOCK_IF_NULL_ARGUMENT(lock); |
||||
|
for (size_t i = 0; i < STM32_LOCK_ARRAY_SIZE(lock->basepri); i++) |
||||
|
{ |
||||
|
lock->basepri[i] = 0; |
||||
|
} |
||||
|
lock->nesting_level = 0; |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* @brief Acquire STM32 lock |
||||
|
* @param lock The lock to acquire |
||||
|
*/ |
||||
|
static inline void stm32_lock_acquire(LockingData_t *lock) |
||||
|
{ |
||||
|
STM32_LOCK_BLOCK_IF_NULL_ARGUMENT(lock); |
||||
|
STM32_LOCK_ASSERT_VALID_NESTING_LEVEL(lock); |
||||
|
lock->basepri[lock->nesting_level++] = taskENTER_CRITICAL_FROM_ISR(); |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* @brief Release STM32 lock |
||||
|
* @param lock The lock to release |
||||
|
*/ |
||||
|
static inline void stm32_lock_release(LockingData_t *lock) |
||||
|
{ |
||||
|
STM32_LOCK_BLOCK_IF_NULL_ARGUMENT(lock); |
||||
|
lock->nesting_level--; |
||||
|
STM32_LOCK_ASSERT_VALID_NESTING_LEVEL(lock); |
||||
|
taskEXIT_CRITICAL_FROM_ISR(lock->basepri[lock->nesting_level]); |
||||
|
} |
||||
|
|
||||
|
#undef STM32_LOCK_ASSERT_VALID_NESTING_LEVEL |
||||
|
#undef STM32_LOCK_MAX_NESTED_LEVELS |
||||
|
|
||||
|
#elif STM32_THREAD_SAFE_STRATEGY == 5 |
||||
|
/* |
||||
|
* Deny lock usage from interrupts. Implemented using FreeRTOS locks. |
||||
|
*/ |
||||
|
|
||||
|
/* Includes ----------------------------------------------------------------*/ |
||||
|
#include <FreeRTOS.h> |
||||
|
#include <task.h> |
||||
|
#if defined (__GNUC__) && !defined (__CC_ARM) && configUSE_NEWLIB_REENTRANT == 0 |
||||
|
#warning Please set configUSE_NEWLIB_REENTRANT to 1 in FreeRTOSConfig.h, otherwise newlib will not be thread-safe |
||||
|
#endif /* defined (__GNUC__) && !defined (__CC_ARM) && configUSE_NEWLIB_REENTRANT == 0 */ |
||||
|
|
||||
|
/* Private defines ---------------------------------------------------------*/ |
||||
|
/** Initialize members in instance of <code>LockingData_t</code> structure */ |
||||
|
#define LOCKING_DATA_INIT 0 |
||||
|
|
||||
|
/* Private typedef ---------------------------------------------------------*/ |
||||
|
typedef uint8_t LockingData_t; /**< Unused */ |
||||
|
|
||||
|
/* Private functions -------------------------------------------------------*/ |
||||
|
|
||||
|
/** |
||||
|
* @brief Initialize STM32 lock |
||||
|
* @param lock The lock to init |
||||
|
*/ |
||||
|
static inline void stm32_lock_init(LockingData_t *lock) |
||||
|
{ |
||||
|
STM32_LOCK_BLOCK_IF_NULL_ARGUMENT(lock); |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* @brief Acquire STM32 lock |
||||
|
* @param lock The lock to acquire |
||||
|
*/ |
||||
|
static inline void stm32_lock_acquire(LockingData_t *lock) |
||||
|
{ |
||||
|
STM32_LOCK_BLOCK_IF_NULL_ARGUMENT(lock); |
||||
|
STM32_LOCK_BLOCK_IF_INTERRUPT_CONTEXT(); |
||||
|
vTaskSuspendAll(); |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* @brief Release STM32 lock |
||||
|
* @param lock The lock to release |
||||
|
*/ |
||||
|
static inline void stm32_lock_release(LockingData_t *lock) |
||||
|
{ |
||||
|
STM32_LOCK_BLOCK_IF_NULL_ARGUMENT(lock); |
||||
|
STM32_LOCK_BLOCK_IF_INTERRUPT_CONTEXT(); |
||||
|
xTaskResumeAll(); |
||||
|
} |
||||
|
|
||||
|
#else |
||||
|
#error Invalid STM32_THREAD_SAFE_STRATEGY specified |
||||
|
#endif /* STM32_THREAD_SAFE_STRATEGY */ |
||||
|
|
||||
|
#ifdef __cplusplus |
||||
|
} /* extern "C" */ |
||||
|
#endif /* __cplusplus */ |
||||
|
|
||||
|
#endif /* __STM32_LOCK_H__ */ |
Write
Preview
Loading…
Cancel
Save
Reference in new issue