基质喷涂
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

376 lines
12 KiB

  1. /**
  2. ******************************************************************************
  3. * @file stm32_lock.h
  4. * @author STMicroelectronics
  5. * @brief STMicroelectronics lock mechanisms
  6. *
  7. * @details
  8. * This implementation supports the following strategies for handling
  9. * thread-safe locks. The strategy can be explicitly selected by
  10. * defining <tt>\STM32_THREAD_SAFE_STRATEGY = \<number></tt> in the project.
  11. * Please look at the '<toolchain/library>_lock_glue.c' file for more details.
  12. *
  13. * 1. User defined thread-safe implementation.
  14. * User defined solution for handling thread-safety.
  15. * <br>
  16. * <b>NOTE:</b> The stubs in stm32_lock_user.h needs to be implemented to gain
  17. * thread-safety.
  18. *
  19. * 2. [<b>DEFAULT</b>] Allow lock usage from interrupts.
  20. * This implementation will ensure thread-safety by disabling all interrupts
  21. * during e.g. calls to malloc.
  22. * <br>
  23. * <b>NOTE:</b> Disabling all interrupts creates interrupt latency which
  24. * might not be desired for this application!
  25. *
  26. * 3. Deny lock usage from interrupts.
  27. * This implementation assumes single thread of execution.
  28. * <br>
  29. * <b>NOTE:</b> Thread-safety dependent functions will enter an infinity loop
  30. * if used in interrupt context.
  31. *
  32. * 4. Allow lock usage from interrupts. Implemented using FreeRTOS locks.
  33. * This implementation will ensure thread-safety by entering RTOS ISR capable
  34. * critical sections during e.g. calls to malloc.
  35. * By default this implementation supports 2 levels of recursive locking.
  36. * Adding additional levels requires 4 bytes per lock per level of RAM.
  37. * <br>
  38. * <b>NOTE:</b> Interrupts with high priority are not disabled. This implies
  39. * that the lock is not thread-safe from high priority interrupts!
  40. *
  41. * 5. Deny lock usage from interrupts. Implemented using FreeRTOS locks.
  42. * This implementation will ensure thread-safety by suspending all tasks
  43. * during e.g. calls to malloc.
  44. * <br>
  45. * <b>NOTE:</b> Thread-safety dependent functions will enter an infinity loop
  46. * if used in interrupt context.
  47. *
  48. ******************************************************************************
  49. * @attention
  50. *
  51. * <h2><center>&copy; Copyright (c) 2021 STMicroelectronics.
  52. * All rights reserved.</center></h2>
  53. *
  54. * This software component is licensed by ST under BSD 3-Clause license,
  55. * the "License"; You may not use this file except in compliance with the
  56. * License. You may obtain a copy of the License at:
  57. * opensource.org/licenses/BSD-3-Clause
  58. *
  59. ******************************************************************************
  60. */
  61. #ifndef __STM32_LOCK_H__
  62. #define __STM32_LOCK_H__
  63. /* Includes ------------------------------------------------------------------*/
  64. #include <stdint.h>
  65. #include <stddef.h>
  66. #include <cmsis_compiler.h>
  67. #ifndef STM32_THREAD_SAFE_STRATEGY
  68. #define STM32_THREAD_SAFE_STRATEGY 2 /**< Assume strategy 2 if not specified */
  69. #endif /* STM32_THREAD_SAFE_STRATEGY */
  70. #ifdef __cplusplus
  71. extern "C" {
  72. #endif /* __cplusplus */
  73. /* Function prototypes -------------------------------------------------------*/
  74. void Error_Handler(void);
  75. /* Public macros -------------------------------------------------------------*/
  76. /** Blocks execution */
  77. #define STM32_LOCK_BLOCK() \
  78. do \
  79. { \
  80. __disable_irq(); \
  81. Error_Handler(); \
  82. while (1); \
  83. } while (0)
  84. /** Blocks execution if argument is NULL */
  85. #define STM32_LOCK_BLOCK_IF_NULL_ARGUMENT(x) \
  86. do \
  87. { \
  88. if ((x) == NULL) \
  89. { \
  90. STM32_LOCK_BLOCK(); \
  91. } \
  92. } while (0)
  93. /** Blocks execution if in interrupt context */
  94. #define STM32_LOCK_BLOCK_IF_INTERRUPT_CONTEXT() \
  95. do \
  96. { \
  97. if (__get_IPSR()) \
  98. { \
  99. STM32_LOCK_BLOCK(); \
  100. } \
  101. } while (0)
  102. /** Hide unused parameter warning from compiler */
  103. #define STM32_LOCK_UNUSED(var) (void)var
  104. /** Size of array */
  105. #define STM32_LOCK_ARRAY_SIZE(array) (sizeof(array) / sizeof((array)[0]))
  106. #if STM32_THREAD_SAFE_STRATEGY == 1
  107. /*
  108. * User defined thread-safe implementation.
  109. */
  110. /* Includes ----------------------------------------------------------------*/
  111. /** STM32 lock API version */
  112. #define STM32_LOCK_API 1
  113. #include "stm32_lock_user.h"
  114. #undef STM32_LOCK_API
  115. #elif STM32_THREAD_SAFE_STRATEGY == 2
  116. /*
  117. * Allow lock usage from interrupts.
  118. */
  119. /* Private defines ---------------------------------------------------------*/
  120. /** Initialize members in instance of <code>LockingData_t</code> structure */
  121. #define LOCKING_DATA_INIT { 0, 0 }
  122. /* Private typedef ---------------------------------------------------------*/
  123. typedef struct
  124. {
  125. uint8_t flag; /**< Backup of PRIMASK.PM at nesting level 0 */
  126. uint8_t counter; /**< Nesting level */
  127. } LockingData_t;
  128. /* Private functions -------------------------------------------------------*/
  129. /**
  130. * @brief Initialize STM32 lock
  131. * @param lock The lock to init
  132. */
  133. static inline void stm32_lock_init(LockingData_t *lock)
  134. {
  135. STM32_LOCK_BLOCK_IF_NULL_ARGUMENT(lock);
  136. lock->flag = 0;
  137. lock->counter = 0;
  138. }
  139. /**
  140. * @brief Acquire STM32 lock
  141. * @param lock The lock to acquire
  142. */
  143. static inline void stm32_lock_acquire(LockingData_t *lock)
  144. {
  145. uint8_t flag = (uint8_t)(__get_PRIMASK() & 0x1); /* PRIMASK.PM */
  146. __disable_irq();
  147. __DSB();
  148. __ISB();
  149. STM32_LOCK_BLOCK_IF_NULL_ARGUMENT(lock);
  150. if (lock->counter == 0)
  151. {
  152. lock->flag = flag;
  153. }
  154. else if (lock->counter == UINT8_MAX)
  155. {
  156. STM32_LOCK_BLOCK();
  157. }
  158. lock->counter++;
  159. }
  160. /**
  161. * @brief Release STM32 lock
  162. * @param lock The lock to release
  163. */
  164. static inline void stm32_lock_release(LockingData_t *lock)
  165. {
  166. STM32_LOCK_BLOCK_IF_NULL_ARGUMENT(lock);
  167. if (lock->counter == 0)
  168. {
  169. STM32_LOCK_BLOCK();
  170. }
  171. lock->counter--;
  172. if (lock->counter == 0 && lock->flag == 0)
  173. {
  174. __enable_irq();
  175. }
  176. }
  177. #elif STM32_THREAD_SAFE_STRATEGY == 3
  178. /*
  179. * Deny lock usage from interrupts.
  180. */
  181. /* Private defines ---------------------------------------------------------*/
  182. /** Initialize members in instance of <code>LockingData_t</code> structure */
  183. #define LOCKING_DATA_INIT 0
  184. /* Private typedef ---------------------------------------------------------*/
  185. typedef uint8_t LockingData_t; /**< Unused */
  186. /* Private functions -------------------------------------------------------*/
  187. /**
  188. * @brief Initialize STM32 lock
  189. * @param lock The lock to init
  190. */
  191. static inline void stm32_lock_init(LockingData_t *lock)
  192. {
  193. STM32_LOCK_BLOCK_IF_NULL_ARGUMENT(lock);
  194. }
  195. /**
  196. * @brief Acquire STM32 lock
  197. * @param lock The lock to acquire
  198. */
  199. static inline void stm32_lock_acquire(LockingData_t *lock)
  200. {
  201. STM32_LOCK_BLOCK_IF_NULL_ARGUMENT(lock);
  202. STM32_LOCK_BLOCK_IF_INTERRUPT_CONTEXT();
  203. }
  204. /**
  205. * @brief Release ST lock
  206. * @param lock The lock to release
  207. */
  208. static inline void stm32_lock_release(LockingData_t *lock)
  209. {
  210. STM32_LOCK_BLOCK_IF_NULL_ARGUMENT(lock);
  211. STM32_LOCK_BLOCK_IF_INTERRUPT_CONTEXT();
  212. }
  213. #elif STM32_THREAD_SAFE_STRATEGY == 4
  214. /*
  215. * Allow lock usage from interrupts. Implemented using FreeRTOS locks.
  216. */
  217. /* Includes ----------------------------------------------------------------*/
  218. #include <FreeRTOS.h>
  219. #include <task.h>
  220. #if defined (__GNUC__) && !defined (__CC_ARM) && configUSE_NEWLIB_REENTRANT == 0
  221. #warning Please set configUSE_NEWLIB_REENTRANT to 1 in FreeRTOSConfig.h, otherwise newlib will not be thread-safe
  222. #endif /* defined (__GNUC__) && !defined (__CC_ARM) && configUSE_NEWLIB_REENTRANT == 0 */
  223. /* Private defines ---------------------------------------------------------*/
  224. /** Initialize members in instance of <code>LockingData_t</code> structure */
  225. #define LOCKING_DATA_INIT { {0, 0}, 0 }
  226. #define STM32_LOCK_MAX_NESTED_LEVELS 2 /**< Max nesting level of interrupts */
  227. typedef struct
  228. {
  229. uint32_t basepri[STM32_LOCK_MAX_NESTED_LEVELS];
  230. uint8_t nesting_level;
  231. } LockingData_t;
  232. /* Private macros ----------------------------------------------------------*/
  233. /** Blocks execution if reached max nesting level */
  234. #define STM32_LOCK_ASSERT_VALID_NESTING_LEVEL(lock) \
  235. do \
  236. { \
  237. if (lock->nesting_level >= STM32_LOCK_ARRAY_SIZE(lock->basepri)) \
  238. { \
  239. STM32_LOCK_BLOCK(); \
  240. } \
  241. } while (0)
  242. /* Private functions -------------------------------------------------------*/
  243. /**
  244. * @brief Initialize STM32 lock
  245. * @param lock The lock to init
  246. */
  247. static inline void stm32_lock_init(LockingData_t *lock)
  248. {
  249. STM32_LOCK_BLOCK_IF_NULL_ARGUMENT(lock);
  250. for (size_t i = 0; i < STM32_LOCK_ARRAY_SIZE(lock->basepri); i++)
  251. {
  252. lock->basepri[i] = 0;
  253. }
  254. lock->nesting_level = 0;
  255. }
  256. /**
  257. * @brief Acquire STM32 lock
  258. * @param lock The lock to acquire
  259. */
  260. static inline void stm32_lock_acquire(LockingData_t *lock)
  261. {
  262. STM32_LOCK_BLOCK_IF_NULL_ARGUMENT(lock);
  263. STM32_LOCK_ASSERT_VALID_NESTING_LEVEL(lock);
  264. lock->basepri[lock->nesting_level++] = taskENTER_CRITICAL_FROM_ISR();
  265. }
  266. /**
  267. * @brief Release STM32 lock
  268. * @param lock The lock to release
  269. */
  270. static inline void stm32_lock_release(LockingData_t *lock)
  271. {
  272. STM32_LOCK_BLOCK_IF_NULL_ARGUMENT(lock);
  273. lock->nesting_level--;
  274. STM32_LOCK_ASSERT_VALID_NESTING_LEVEL(lock);
  275. taskEXIT_CRITICAL_FROM_ISR(lock->basepri[lock->nesting_level]);
  276. }
  277. #undef STM32_LOCK_ASSERT_VALID_NESTING_LEVEL
  278. #undef STM32_LOCK_MAX_NESTED_LEVELS
  279. #elif STM32_THREAD_SAFE_STRATEGY == 5
  280. /*
  281. * Deny lock usage from interrupts. Implemented using FreeRTOS locks.
  282. */
  283. /* Includes ----------------------------------------------------------------*/
  284. #include <FreeRTOS.h>
  285. #include <task.h>
  286. #if defined (__GNUC__) && !defined (__CC_ARM) && configUSE_NEWLIB_REENTRANT == 0
  287. #warning Please set configUSE_NEWLIB_REENTRANT to 1 in FreeRTOSConfig.h, otherwise newlib will not be thread-safe
  288. #endif /* defined (__GNUC__) && !defined (__CC_ARM) && configUSE_NEWLIB_REENTRANT == 0 */
  289. /* Private defines ---------------------------------------------------------*/
  290. /** Initialize members in instance of <code>LockingData_t</code> structure */
  291. #define LOCKING_DATA_INIT 0
  292. /* Private typedef ---------------------------------------------------------*/
  293. typedef uint8_t LockingData_t; /**< Unused */
  294. /* Private functions -------------------------------------------------------*/
  295. /**
  296. * @brief Initialize STM32 lock
  297. * @param lock The lock to init
  298. */
  299. static inline void stm32_lock_init(LockingData_t *lock)
  300. {
  301. STM32_LOCK_BLOCK_IF_NULL_ARGUMENT(lock);
  302. }
  303. /**
  304. * @brief Acquire STM32 lock
  305. * @param lock The lock to acquire
  306. */
  307. static inline void stm32_lock_acquire(LockingData_t *lock)
  308. {
  309. STM32_LOCK_BLOCK_IF_NULL_ARGUMENT(lock);
  310. STM32_LOCK_BLOCK_IF_INTERRUPT_CONTEXT();
  311. vTaskSuspendAll();
  312. }
  313. /**
  314. * @brief Release STM32 lock
  315. * @param lock The lock to release
  316. */
  317. static inline void stm32_lock_release(LockingData_t *lock)
  318. {
  319. STM32_LOCK_BLOCK_IF_NULL_ARGUMENT(lock);
  320. STM32_LOCK_BLOCK_IF_INTERRUPT_CONTEXT();
  321. xTaskResumeAll();
  322. }
  323. #else
  324. #error Invalid STM32_THREAD_SAFE_STRATEGY specified
  325. #endif /* STM32_THREAD_SAFE_STRATEGY */
  326. #ifdef __cplusplus
  327. } /* extern "C" */
  328. #endif /* __cplusplus */
  329. #endif /* __STM32_LOCK_H__ */