• (GCC)STM32基础详解之全局资源的使用


    注:测试硬件非STM32(而是nRF52832),但是笔者认为这在所有Cortex-M3、M4单片机上是一样的情况,所以标题为了与之前系列相同而取了STM32。

    1.问题描述

    全局资源在此处通常指一个全局变量,它可以是一个全局的buf、结构体变量、指针等等。如果你的代码里只有一个while,没有使用任何RTOS或中断,那是不会存在资源竟争问题的,因为不存在打断操作,代码执行流程永远是从上到下顺序执行。(MCU上好像没有听说有使用乱序执行技术)

    之前也有遇到过相似的问题,不过没有完整记录,此次遇到就正好完整记录一下。

    代码很简单,笔者在main函数中while(1)中使用发送函数发送一段数据,使用3个变量:

    发送次数累加,发送成功一次累加,发送失败一次累加

    正常我们很容易知道:

    发送次数 = 发送成功次数 + 发送失败次数

    然后笔者使用一个定时器,每隔1秒在定时器中断回调中打印发送的次数、成功的次数、失败的次数,然后清0,但是会出现:

    发送次数 != 发送成功次数+发送失败次数

    而且相差很大。

    2.原因分析

    变量声明:

    main的循环中有:

    很简单明了的代码,调用 nrf_esb_write_payload  这个发送函数,要么成功,要么失败,所以无论如何总有:

    writeCount = writeSuccess + writeFailed

    然后笔者使用了一个定时器,定时时间为1秒,也就是1秒触发一次中断回调,然后在中断回调里对这三个变量打印,定时器配置不再赘述,直接给中断回调函数内容:

    可以看到,打印完这三个变量后,就把3个变量置0,重新开始累计。

    实际代码运行打印:

    可以看到出现异常的时候,一共发送了628886次,却失败了1253521次或是发送了1257731次,却成功2025次,失败626839次,剩余那60多万次哪去了?

    其实仔细观察,可以发现,异常的时候,均是那个异常变量没有清0,其值是此次值和上次的值相加! 

    难道是清0那行代码没有生效?

    不可能,首先只要正常打印了,它后面清0的代码也必定执行,而且如果没有清0,必定3个变量都不会清0,而且即使是在定时器中断回调执行时被其他中断抢占,在其他中断结束后,也会继续执行定时器中断。

    遇事不决,查看汇编。

    上图是中断中如何令writeCount这个变量清0。 

    上图中已经描述了变量累加以及清0是如何用汇编实现的。看到这你应该明白:

    writeCount++;

    这个看似只有一行的代码,实际用了3行汇编去实现。这就有个问题,假如在执行:

    LDR            R3, [R6] 

    这行代码后,被定时器中断打断,转而去执行了中断处理函数会发生什么?

    查看变量地址我们知道:

    writeCount这个变量其实地址是0x2000 0248,一开始

    R6 =  writeCount

    其实就是R6 = 0x2000 0248,然后

    R3 = *R6

    即R3 = *(0x2000 0248),假如此时已经发送了60 0000次了,那也就是R3 = 60 0000,这个时候定时器定时时间到了,跑去执行定时器中断处理函数,再假如此时发送成功了2000次,失败了59 8000次,那么定时器中断处理函数中会打印:

    发送60 0000次,成功2000次,失败59 8000次

    然后把writeCount、writeSuccess、writeFailed都清0了,也就是此时你再去取0x2000 0248这个地址上的值,已经变成0了,但是,在处理完定时器中断回调后,我们继续执行的是:

    ADDS           R3, #1

    STR            R3, [R6]

    因为在中断前我们已经取过 0x2000 0248这个地址上的值到R3中了,即使再回来继续执行,我们用的之前保存到R3里面的值,此时R3还是之前读进去的60 0000,继续执行则变成:

    R3 = 60 0000+1

    *(0x2000 0248) = 60 0001

    此时我们把刚清0的writeCount赋值成了60 0001!这导致我们在中断中的清0操作失效了!

    3.解决办法

    3.1原子操作

    由上一节分析我们知道了为啥清0会失败,就是因为

    writeCount++

    这个操作是分为3步执行的!假如这个操作必须完整的执行,不能拆分,那也就不存在上面的异常情况。不能拆分的操作,我们称作原子操作,在nRF的SDK中有提供原子操作的库函数,它们被放在 nrf_atomic.c中,如果你使用的是GCC编译器,那么这些函数稍作修改也同样可以运用到STM32中,因为它们都是cortex-M4内核的MCU,本质是一样的。该文件中主要函数是:

    这个函数中主要是汇编操作:

    可以看到主要使用的是ldrexstrex独占访问指令(也有叫排他访问),感兴趣的可以自行搜索。

    STM提供的原子操作:

    https://github.com/STMicroelectronics/STM32CubeF4/blob/4aba24d78fef03d797a82b258f37dbc84728bbb5/Drivers/CMSIS/Device/ST/STM32F4xx/Include/stm32f4xx.h#L230

    这里我们使用nRF的SDK中提供的原子操作函数试一下:

    经过长时间测试发现不再会出现上述问题,相关打印如下:

    但是可以看到,因为原子操作需要更多的指令,效率有所下降。 

    3.2互斥量

    互斥量常常用于多线程中访问共享资源的情况,在nRF的SDK中互斥量的实现在nrf_mtx.h中。

    其实互斥量很简单,同一时刻,互斥量只能被一个地方拥有(这个地方可以是中断处理回调或者RTOS中的任务循环函数)。当我们在任何需要修改一个共享资源的时候,先去获取一个互斥量,如果可以获取到,证明这个资源没有在被使用,如果没有获取到证明有其他修改它的地方已经获取到了。其实互斥量的实现也使用了原子操作:

    可以看到每个从互斥量操作都使用了__DMB() 这个内联汇编函数 ,它的函数原型是:

    在Cortex-M3权威指南里有:

    这个和Cortex-M的3级流水线设计息息相关,感兴趣的自行搜索。

    最后main函数类似这样:

    但是注意,如果是在RTOS中使用互斥锁很方便,但是在中断中使用互斥锁就不太好,原因如下:

    1.中断等待与死锁

    在你刚开始学习中断的时候肯定有人告诉你,中断中不能延时,这里如果是一个任务使用while等待一点问题没有,但是因为不清楚while到底会等待多久,所以这里肯定不可以使用while等待。

    其次,while在这里会造成死锁,因为假如我们在main函数中已经获取到了互斥锁,这时候被定时器中断回调打断,定时器中断就算一直等待其他地方互斥锁释放也是徒劳,因为中断回调没有执行完,永远不会转头回去继续执行main函数中的while,而main中的while那次循环执行不完,又永远不会释放互斥锁,这就陷入了死循环,也可以叫死锁。 

    2.跳过

    在这个例子中,因为中断每次进入都有一秒的间隔,这里如果获取不到就跳过,那么每次都会出现2秒才打印1次的现象,所以这里跳过也不太合理。当然,如果这是在一个会一直循环的任务里影响就很小了。

    综上所述,在中断中使用互斥量不是一个好的选择,但是如果是在RTOS的任务中会有效的多。 

    3.3关中断

    如果你使用过RTOS,你应该知道临界区,它就是保护资源的一种方式,临界区最简单的做法就是关闭中断。上述原子操作的解决思路是把操作压缩到一个不可分割的整体,是从自身出发,而关中断会让定时器这个可能打断我们操作的异常给kill掉,这是从外部出发。

    nRF的SDK中有提供打开和关闭中断的方法,在cmsis_gcc.h中有:

    而我们需要做的只是:

    这样,在操作这几个全局变量的时候就不会被定时器中断所打断,打印如下:

    可以看到,虽然有所损失,但是比原子操作耗时短得多,几乎和没有关中断差不太多。但是这儿有个问题,在笔者这个例子中关闭中断和再次开启中断中间只有一个发送函数,如果你所需要保护的区域有很多操作甚至是等待时,长时间的关闭中断很有可能带来其他问题。我们需要尽可能的把临界区弄的短一点:

    最好是只在最关键的操作使用中断的开关。当然这势必造成效率下降:

    很显然,在这个例子中,只在开头和结尾开关中断好像比分割成3次更加合理。

    3.4屏蔽中断

    Cortex-M内核很贴心的提供了可屏蔽优先级寄存器BASEPRI

    关于这个寄存器,更为详细的资料可以参考宋岩译的那本《Cortex-M3权威指南》。

    而在cmsis_gcc.h中也有设置这个寄存器的函数:

    另一个带MAX的是:

    所以我们只需要这样操作:

    和上一个关中断差不多,但是这里笔者配置的定时器中断优先级是6,而其他中断优先级都在4以上,所以这里我设置为屏蔽4及以下的中断(优先级号越大,优先级越低) 。这里如果是STM32,则需要根据所选的中断分组再判断是设置高4位的哪几位,因为STM32分抢占优先级和响应优先级,这个设置只对抢占优先级有效。而nRF只有0~7八个优先级,不分抢占和响应,所以直接设置即可,至于为什么是高4位,因为芯片设计如此。

    这里同样解决了上述问题,打印如下:

    可以看到设置此寄存器比只开关中断要耗时的多。如果我们按照上一节思路,把开关屏蔽中断分为3次,应该更加耗时:

    打印如下:

    可以看到和关闭全局中断差不多。 

    4.总结

    在使用一个共享的全局资源时,多个地方修改这个资源可能会引发问题。可以使用原子操作、互斥量、关闭中断或者屏蔽中断解决。它们各有利弊:

    1.原子操作并不一定是一条指令,而可能是很多条指令,只是通过独占访问等实现,所以原子操作可能更加耗时,对于时间敏感的地方需要衡量是否会影响功能。但是好处是它不对其他中断有影响,比如这个例子中的定时器中断,它的响应并不会被延迟。

    2.关闭所有中断简单粗暴,但在实际项目中,可能使用了很多中断,并不是所有中断都可以随意关闭,有些中断被关闭可能引发一些问题。虽然关闭期间触发的中断会在中断打开后继续执行,但是这无疑加大了中断延迟,对于一些对响应速度要求很高的中断来说,这无疑是灭顶之灾。所以关闭中断使用次数越少越好,关闭时间越短越好。

    3.屏蔽部分中断解决了一部分关闭所有中断的问题,我们可以只屏蔽那些优先级没那么高的中断,但是加重了对不同中断优先级分配的复杂度。像此例子中nRF只有0~7八种中断优先级,而STM32中屏蔽中断只能对抢占优先级生效,所以实际设置时要根据4种主次优先级分配的位数设置。

    4.互斥量在中断中使用会引起很多问题,应该在RTOS的任务中使用。

    附:

    nrf_atomic.c

    1. /**
    2. * Copyright (c) 2018 - 2019, Nordic Semiconductor ASA
    3. *
    4. * All rights reserved.
    5. *
    6. * Redistribution and use in source and binary forms, with or without modification,
    7. * are permitted provided that the following conditions are met:
    8. *
    9. * 1. Redistributions of source code must retain the above copyright notice, this
    10. * list of conditions and the following disclaimer.
    11. *
    12. * 2. Redistributions in binary form, except as embedded into a Nordic
    13. * Semiconductor ASA integrated circuit in a product or a software update for
    14. * such product, must reproduce the above copyright notice, this list of
    15. * conditions and the following disclaimer in the documentation and/or other
    16. * materials provided with the distribution.
    17. *
    18. * 3. Neither the name of Nordic Semiconductor ASA nor the names of its
    19. * contributors may be used to endorse or promote products derived from this
    20. * software without specific prior written permission.
    21. *
    22. * 4. This software, with or without modification, must only be used with a
    23. * Nordic Semiconductor ASA integrated circuit.
    24. *
    25. * 5. Any software provided in binary form under this license must not be reverse
    26. * engineered, decompiled, modified and/or disassembled.
    27. *
    28. * THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
    29. * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
    30. * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
    31. * DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE
    32. * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
    33. * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
    34. * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
    35. * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
    36. * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
    37. * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
    38. *
    39. */
    40. #include "nrf_atomic.h"
    41. #ifndef NRF_ATOMIC_USE_BUILD_IN
    42. #if (defined(__GNUC__) && defined(WIN32))
    43. #define NRF_ATOMIC_USE_BUILD_IN 1
    44. #else
    45. #define NRF_ATOMIC_USE_BUILD_IN 0
    46. #endif
    47. #endif // NRF_ATOMIC_USE_BUILD_IN
    48. #if ((__CORTEX_M >= 0x03U) || (__CORTEX_SC >= 300U))
    49. #define STREX_LDREX_PRESENT
    50. #else
    51. #include "app_util_platform.h"
    52. #endif
    53. #if (NRF_ATOMIC_USE_BUILD_IN == 0) && defined(STREX_LDREX_PRESENT)
    54. #include "nrf_atomic_internal.h"
    55. #endif
    56. uint32_t nrf_atomic_u32_fetch_store(nrf_atomic_u32_t * p_data, uint32_t value)
    57. {
    58. #if NRF_ATOMIC_USE_BUILD_IN
    59. return __atomic_exchange_n(p_data, value, __ATOMIC_SEQ_CST);
    60. #elif defined(STREX_LDREX_PRESENT)
    61. uint32_t old_val;
    62. uint32_t new_val;
    63. NRF_ATOMIC_OP(mov, old_val, new_val, p_data, value);
    64. UNUSED_PARAMETER(old_val);
    65. UNUSED_PARAMETER(new_val);
    66. return old_val;
    67. #else
    68. CRITICAL_REGION_ENTER();
    69. uint32_t old_val = *p_data;
    70. *p_data = value;
    71. CRITICAL_REGION_EXIT();
    72. return old_val;
    73. #endif //NRF_ATOMIC_USE_BUILD_IN
    74. }
    75. uint32_t nrf_atomic_u32_store(nrf_atomic_u32_t * p_data, uint32_t value)
    76. {
    77. #if NRF_ATOMIC_USE_BUILD_IN
    78. __atomic_store_n(p_data, value, __ATOMIC_SEQ_CST);
    79. return value;
    80. #elif defined(STREX_LDREX_PRESENT)
    81. uint32_t old_val;
    82. uint32_t new_val;
    83. NRF_ATOMIC_OP(mov, old_val, new_val, p_data, value);
    84. UNUSED_PARAMETER(old_val);
    85. UNUSED_PARAMETER(new_val);
    86. return new_val;
    87. #else
    88. CRITICAL_REGION_ENTER();
    89. *p_data = value;
    90. CRITICAL_REGION_EXIT();
    91. return value;
    92. #endif //NRF_ATOMIC_USE_BUILD_IN
    93. }
    94. uint32_t nrf_atomic_u32_fetch_or(nrf_atomic_u32_t * p_data, uint32_t value)
    95. {
    96. #if NRF_ATOMIC_USE_BUILD_IN
    97. return __atomic_fetch_or(p_data, value, __ATOMIC_SEQ_CST);
    98. #elif defined(STREX_LDREX_PRESENT)
    99. uint32_t old_val;
    100. uint32_t new_val;
    101. NRF_ATOMIC_OP(orr, old_val, new_val, p_data, value);
    102. UNUSED_PARAMETER(old_val);
    103. UNUSED_PARAMETER(new_val);
    104. return old_val;
    105. #else
    106. CRITICAL_REGION_ENTER();
    107. uint32_t old_val = *p_data;
    108. *p_data |= value;
    109. CRITICAL_REGION_EXIT();
    110. return old_val;
    111. #endif //NRF_ATOMIC_USE_BUILD_IN
    112. }
    113. uint32_t nrf_atomic_u32_or(nrf_atomic_u32_t * p_data, uint32_t value)
    114. {
    115. #if NRF_ATOMIC_USE_BUILD_IN
    116. return __atomic_or_fetch(p_data, value, __ATOMIC_SEQ_CST);
    117. #elif defined(STREX_LDREX_PRESENT)
    118. uint32_t old_val;
    119. uint32_t new_val;
    120. NRF_ATOMIC_OP(orr, old_val, new_val, p_data, value);
    121. UNUSED_PARAMETER(old_val);
    122. UNUSED_PARAMETER(new_val);
    123. return new_val;
    124. #else
    125. CRITICAL_REGION_ENTER();
    126. *p_data |= value;
    127. uint32_t new_value = *p_data;
    128. CRITICAL_REGION_EXIT();
    129. return new_value;
    130. #endif //NRF_ATOMIC_USE_BUILD_IN
    131. }
    132. uint32_t nrf_atomic_u32_fetch_and(nrf_atomic_u32_t * p_data, uint32_t value)
    133. {
    134. #if NRF_ATOMIC_USE_BUILD_IN
    135. return __atomic_fetch_and(p_data, value, __ATOMIC_SEQ_CST);
    136. #elif defined(STREX_LDREX_PRESENT)
    137. uint32_t old_val;
    138. uint32_t new_val;
    139. NRF_ATOMIC_OP(and, old_val, new_val, p_data, value);
    140. UNUSED_PARAMETER(old_val);
    141. UNUSED_PARAMETER(new_val);
    142. return old_val;
    143. #else
    144. CRITICAL_REGION_ENTER();
    145. uint32_t old_val = *p_data;
    146. *p_data &= value;
    147. CRITICAL_REGION_EXIT();
    148. return old_val;
    149. #endif //NRF_ATOMIC_USE_BUILD_IN
    150. }
    151. uint32_t nrf_atomic_u32_and(nrf_atomic_u32_t * p_data, uint32_t value)
    152. {
    153. #if NRF_ATOMIC_USE_BUILD_IN
    154. return __atomic_and_fetch(p_data, value, __ATOMIC_SEQ_CST);
    155. #elif defined(STREX_LDREX_PRESENT)
    156. uint32_t old_val;
    157. uint32_t new_val;
    158. NRF_ATOMIC_OP(and, old_val, new_val, p_data, value);
    159. UNUSED_PARAMETER(old_val);
    160. UNUSED_PARAMETER(new_val);
    161. return new_val;
    162. #else
    163. CRITICAL_REGION_ENTER();
    164. *p_data &= value;
    165. uint32_t new_value = *p_data;
    166. CRITICAL_REGION_EXIT();
    167. return new_value;
    168. #endif //NRF_ATOMIC_USE_BUILD_IN
    169. }
    170. uint32_t nrf_atomic_u32_fetch_xor(nrf_atomic_u32_t * p_data, uint32_t value)
    171. {
    172. #if NRF_ATOMIC_USE_BUILD_IN
    173. return __atomic_fetch_xor(p_data, value, __ATOMIC_SEQ_CST);
    174. #elif defined(STREX_LDREX_PRESENT)
    175. uint32_t old_val;
    176. uint32_t new_val;
    177. NRF_ATOMIC_OP(eor, old_val, new_val, p_data, value);
    178. UNUSED_PARAMETER(old_val);
    179. UNUSED_PARAMETER(new_val);
    180. return old_val;
    181. #else
    182. CRITICAL_REGION_ENTER();
    183. uint32_t old_val = *p_data;
    184. *p_data ^= value;
    185. CRITICAL_REGION_EXIT();
    186. return old_val;
    187. #endif //NRF_ATOMIC_USE_BUILD_IN
    188. }
    189. uint32_t nrf_atomic_u32_xor(nrf_atomic_u32_t * p_data, uint32_t value)
    190. {
    191. #if NRF_ATOMIC_USE_BUILD_IN
    192. return __atomic_xor_fetch(p_data, value, __ATOMIC_SEQ_CST);
    193. #elif defined(STREX_LDREX_PRESENT)
    194. uint32_t old_val;
    195. uint32_t new_val;
    196. NRF_ATOMIC_OP(eor, old_val, new_val, p_data, value);
    197. UNUSED_PARAMETER(old_val);
    198. UNUSED_PARAMETER(new_val);
    199. return new_val;
    200. #else
    201. CRITICAL_REGION_ENTER();
    202. *p_data ^= value;
    203. uint32_t new_value = *p_data;
    204. CRITICAL_REGION_EXIT();
    205. return new_value;
    206. #endif //NRF_ATOMIC_USE_BUILD_IN
    207. }
    208. uint32_t nrf_atomic_u32_fetch_add(nrf_atomic_u32_t * p_data, uint32_t value)
    209. {
    210. #if NRF_ATOMIC_USE_BUILD_IN
    211. return __atomic_fetch_add(p_data, value, __ATOMIC_SEQ_CST);
    212. #elif defined(STREX_LDREX_PRESENT)
    213. uint32_t old_val;
    214. uint32_t new_val;
    215. NRF_ATOMIC_OP(add, old_val, new_val, p_data, value);
    216. UNUSED_PARAMETER(old_val);
    217. UNUSED_PARAMETER(new_val);
    218. return old_val;
    219. #else
    220. CRITICAL_REGION_ENTER();
    221. uint32_t old_val = *p_data;
    222. *p_data += value;
    223. CRITICAL_REGION_EXIT();
    224. return old_val;
    225. #endif //NRF_ATOMIC_USE_BUILD_IN
    226. }
    227. uint32_t nrf_atomic_u32_add(nrf_atomic_u32_t * p_data, uint32_t value)
    228. {
    229. #if NRF_ATOMIC_USE_BUILD_IN
    230. return __atomic_add_fetch(p_data, value, __ATOMIC_SEQ_CST);
    231. #elif defined(STREX_LDREX_PRESENT)
    232. uint32_t old_val;
    233. uint32_t new_val;
    234. NRF_ATOMIC_OP(add, old_val, new_val, p_data, value);
    235. UNUSED_PARAMETER(old_val);
    236. UNUSED_PARAMETER(new_val);
    237. return new_val;
    238. #else
    239. CRITICAL_REGION_ENTER();
    240. *p_data += value;
    241. uint32_t new_value = *p_data;
    242. CRITICAL_REGION_EXIT();
    243. return new_value;
    244. #endif //NRF_ATOMIC_USE_BUILD_IN
    245. }
    246. uint32_t nrf_atomic_u32_fetch_sub(nrf_atomic_u32_t * p_data, uint32_t value)
    247. {
    248. #if NRF_ATOMIC_USE_BUILD_IN
    249. return __atomic_fetch_sub(p_data, value, __ATOMIC_SEQ_CST);
    250. #elif defined(STREX_LDREX_PRESENT)
    251. uint32_t old_val;
    252. uint32_t new_val;
    253. NRF_ATOMIC_OP(sub, old_val, new_val, p_data, value);
    254. UNUSED_PARAMETER(old_val);
    255. UNUSED_PARAMETER(new_val);
    256. return old_val;
    257. #else
    258. CRITICAL_REGION_ENTER();
    259. uint32_t old_val = *p_data;
    260. *p_data -= value;
    261. CRITICAL_REGION_EXIT();
    262. return old_val;
    263. #endif //NRF_ATOMIC_USE_BUILD_IN
    264. }
    265. uint32_t nrf_atomic_u32_sub(nrf_atomic_u32_t * p_data, uint32_t value)
    266. {
    267. #if NRF_ATOMIC_USE_BUILD_IN
    268. return __atomic_sub_fetch(p_data, value, __ATOMIC_SEQ_CST);
    269. #elif defined(STREX_LDREX_PRESENT)
    270. uint32_t old_val;
    271. uint32_t new_val;
    272. NRF_ATOMIC_OP(sub, old_val, new_val, p_data, value);
    273. UNUSED_PARAMETER(old_val);
    274. UNUSED_PARAMETER(new_val);
    275. return new_val;
    276. #else
    277. CRITICAL_REGION_ENTER();
    278. *p_data -= value;
    279. uint32_t new_value = *p_data;
    280. CRITICAL_REGION_EXIT();
    281. return new_value;
    282. #endif //NRF_ATOMIC_USE_BUILD_IN
    283. }
    284. bool nrf_atomic_u32_cmp_exch(nrf_atomic_u32_t * p_data,
    285. uint32_t * p_expected,
    286. uint32_t desired)
    287. {
    288. #if NRF_ATOMIC_USE_BUILD_IN
    289. return __atomic_compare_exchange(p_data,
    290. p_expected,
    291. &desired,
    292. 1,
    293. __ATOMIC_SEQ_CST,
    294. __ATOMIC_SEQ_CST);
    295. #elif defined(STREX_LDREX_PRESENT)
    296. return nrf_atomic_internal_cmp_exch(p_data, p_expected, desired);
    297. #else
    298. bool ret;
    299. CRITICAL_REGION_ENTER();
    300. if (*p_data == *p_expected)
    301. {
    302. *p_data = desired;
    303. ret = true;
    304. }
    305. else
    306. {
    307. *p_expected = *p_data;
    308. ret = false;
    309. }
    310. CRITICAL_REGION_EXIT();
    311. return ret;
    312. #endif
    313. }
    314. uint32_t nrf_atomic_u32_fetch_sub_hs(nrf_atomic_u32_t * p_data, uint32_t value)
    315. {
    316. #if NRF_ATOMIC_USE_BUILD_IN
    317. uint32_t expected = *p_data;
    318. uint32_t new_val;
    319. bool success;
    320. do
    321. {
    322. if (expected >= value)
    323. {
    324. new_val = expected - value;
    325. }
    326. else
    327. {
    328. new_val = expected;
    329. }
    330. success = __atomic_compare_exchange(p_data,
    331. &expected,
    332. &new_val,
    333. 1,
    334. __ATOMIC_SEQ_CST,
    335. __ATOMIC_SEQ_CST);
    336. } while(!success);
    337. return expected;
    338. #elif defined(STREX_LDREX_PRESENT)
    339. uint32_t old_val;
    340. uint32_t new_val;
    341. NRF_ATOMIC_OP(sub_hs, old_val, new_val, p_data, value);
    342. UNUSED_PARAMETER(old_val);
    343. UNUSED_PARAMETER(new_val);
    344. return old_val;
    345. #else
    346. CRITICAL_REGION_ENTER();
    347. uint32_t old_val = *p_data;
    348. *p_data -= value;
    349. CRITICAL_REGION_EXIT();
    350. return old_val;
    351. #endif //NRF_ATOMIC_USE_BUILD_IN
    352. }
    353. uint32_t nrf_atomic_u32_sub_hs(nrf_atomic_u32_t * p_data, uint32_t value)
    354. {
    355. #if NRF_ATOMIC_USE_BUILD_IN
    356. uint32_t expected = *p_data;
    357. uint32_t new_val;
    358. bool success;
    359. do
    360. {
    361. if (expected >= value)
    362. {
    363. new_val = expected - value;
    364. }
    365. else
    366. {
    367. new_val = expected;
    368. }
    369. success = __atomic_compare_exchange(p_data,
    370. &expected,
    371. &new_val,
    372. 1,
    373. __ATOMIC_SEQ_CST,
    374. __ATOMIC_SEQ_CST);
    375. } while(!success);
    376. return new_val;
    377. #elif defined(STREX_LDREX_PRESENT)
    378. uint32_t old_val;
    379. uint32_t new_val;
    380. NRF_ATOMIC_OP(sub_hs, old_val, new_val, p_data, value);
    381. UNUSED_PARAMETER(old_val);
    382. UNUSED_PARAMETER(new_val);
    383. return new_val;
    384. #else
    385. CRITICAL_REGION_ENTER();
    386. *p_data -= value;
    387. uint32_t new_value = *p_data;
    388. CRITICAL_REGION_EXIT();
    389. return new_value;
    390. #endif //NRF_ATOMIC_USE_BUILD_IN
    391. }
    392. uint32_t nrf_atomic_flag_set_fetch(nrf_atomic_flag_t * p_data)
    393. {
    394. return nrf_atomic_u32_fetch_or(p_data, 1);
    395. }
    396. uint32_t nrf_atomic_flag_set(nrf_atomic_flag_t * p_data)
    397. {
    398. return nrf_atomic_u32_or(p_data, 1);
    399. }
    400. uint32_t nrf_atomic_flag_clear_fetch(nrf_atomic_flag_t * p_data)
    401. {
    402. return nrf_atomic_u32_fetch_and(p_data, 0);
    403. }
    404. uint32_t nrf_atomic_flag_clear(nrf_atomic_flag_t * p_data)
    405. {
    406. return nrf_atomic_u32_and(p_data, 0);
    407. }

    nrf_atomic_internal.h

    1. /**
    2. * Copyright (c) 2016 - 2019, Nordic Semiconductor ASA
    3. *
    4. * All rights reserved.
    5. *
    6. * Redistribution and use in source and binary forms, with or without modification,
    7. * are permitted provided that the following conditions are met:
    8. *
    9. * 1. Redistributions of source code must retain the above copyright notice, this
    10. * list of conditions and the following disclaimer.
    11. *
    12. * 2. Redistributions in binary form, except as embedded into a Nordic
    13. * Semiconductor ASA integrated circuit in a product or a software update for
    14. * such product, must reproduce the above copyright notice, this list of
    15. * conditions and the following disclaimer in the documentation and/or other
    16. * materials provided with the distribution.
    17. *
    18. * 3. Neither the name of Nordic Semiconductor ASA nor the names of its
    19. * contributors may be used to endorse or promote products derived from this
    20. * software without specific prior written permission.
    21. *
    22. * 4. This software, with or without modification, must only be used with a
    23. * Nordic Semiconductor ASA integrated circuit.
    24. *
    25. * 5. Any software provided in binary form under this license must not be reverse
    26. * engineered, decompiled, modified and/or disassembled.
    27. *
    28. * THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
    29. * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
    30. * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
    31. * DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE
    32. * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
    33. * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
    34. * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
    35. * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
    36. * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
    37. * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
    38. *
    39. */
    40. #ifndef NRF_ATOMIC_INTERNAL_H__
    41. #define NRF_ATOMIC_INTERNAL_H__
    42. #include "sdk_common.h"
    43. #include
    44. #include
    45. #ifdef __cplusplus
    46. extern "C" {
    47. #endif
    48. /**
    49. *
    50. * @defgroup nrf_atomic_internal Atomic operations internals
    51. * @ingroup nrf_atomic
    52. * @{
    53. *
    54. */
    55. /* Only Cortex M cores > 3 support LDREX/STREX instructions*/
    56. #if ((__CORTEX_M >= 0x03U) || (__CORTEX_SC >= 300U)) == 0
    57. #error "Unsupported core version"
    58. #endif
    59. #if defined ( __CC_ARM )
    60. static __asm uint32_t nrf_atomic_internal_mov(nrf_atomic_u32_t * p_ptr,
    61. uint32_t value,
    62. uint32_t * p_new)
    63. {
    64. /* The base standard provides for passing arguments in core registers (r0-r3) and on the stack.
    65. * Registers r4 and r5 have to be saved on stack. Note that only even number of register push are
    66. * allowed. This is a requirement of the Procedure Call Standard for the ARM Architecture [AAPCS].
    67. * */
    68. push {r4, r5}
    69. mov r4, r0
    70. loop_mov
    71. ldrex r0, [r4]
    72. mov r5, r1
    73. strex r3, r5, [r4]
    74. cmp r3, #0
    75. bne loop_mov
    76. str r5, [r2]
    77. pop {r4, r5}
    78. bx lr
    79. }
    80. static __asm uint32_t nrf_atomic_internal_orr(nrf_atomic_u32_t * p_ptr,
    81. uint32_t value,
    82. uint32_t * p_new)
    83. {
    84. push {r4, r5}
    85. mov r4, r0
    86. loop_orr
    87. ldrex r0, [r4]
    88. orr r5, r0, r1
    89. strex r3, r5, [r4]
    90. cmp r3, #0
    91. bne loop_orr
    92. str r5, [r2]
    93. pop {r4, r5}
    94. bx lr
    95. }
    96. static __asm uint32_t nrf_atomic_internal_and(nrf_atomic_u32_t * p_ptr,
    97. uint32_t value,
    98. uint32_t * p_new)
    99. {
    100. push {r4, r5}
    101. mov r4, r0
    102. loop_and
    103. ldrex r0, [r4]
    104. and r5, r0, r1
    105. strex r3, r5, [r4]
    106. cmp r3, #0
    107. bne loop_and
    108. str r5, [r2]
    109. pop {r4, r5}
    110. bx lr
    111. }
    112. static __asm uint32_t nrf_atomic_internal_eor(nrf_atomic_u32_t * p_ptr,
    113. uint32_t value,
    114. uint32_t * p_new)
    115. {
    116. push {r4, r5}
    117. mov r4, r0
    118. loop_eor
    119. ldrex r0, [r4]
    120. eor r5, r0, r1
    121. strex r3, r5, [r4]
    122. cmp r3, #0
    123. bne loop_eor
    124. str r5, [r2]
    125. pop {r4, r5}
    126. bx lr
    127. }
    128. static __asm uint32_t nrf_atomic_internal_add(nrf_atomic_u32_t * p_ptr,
    129. uint32_t value,
    130. uint32_t * p_new)
    131. {
    132. push {r4, r5}
    133. mov r4, r0
    134. loop_add
    135. ldrex r0, [r4]
    136. add r5, r0, r1
    137. strex r3, r5, [r4]
    138. cmp r3, #0
    139. bne loop_add
    140. str r5, [r2]
    141. pop {r4, r5}
    142. bx lr
    143. }
    144. static __asm uint32_t nrf_atomic_internal_sub(nrf_atomic_u32_t * p_ptr,
    145. uint32_t value,
    146. uint32_t * p_new)
    147. {
    148. push {r4, r5}
    149. mov r4, r0
    150. loop_sub
    151. ldrex r0, [r4]
    152. sub r5, r0, r1
    153. strex r3, r5, [r4]
    154. cmp r3, #0
    155. bne loop_sub
    156. str r5, [r2]
    157. pop {r4, r5}
    158. bx lr
    159. }
    160. static __asm bool nrf_atomic_internal_cmp_exch(nrf_atomic_u32_t * p_data,
    161. uint32_t * p_expected,
    162. uint32_t value)
    163. {
    164. #define RET_REG r0
    165. #define P_EXPC r1
    166. #define VALUE r2
    167. #define STR_RES r3
    168. #define P_DATA r4
    169. #define EXPC_VAL r5
    170. #define ACT_VAL r6
    171. push {r4-r6}
    172. mov P_DATA, r0
    173. mov RET_REG, #0
    174. loop_cmp_exch
    175. ldrex ACT_VAL, [P_DATA]
    176. ldr EXPC_VAL, [P_EXPC]
    177. cmp ACT_VAL, EXPC_VAL
    178. ittee eq
    179. strexeq STR_RES, VALUE, [P_DATA]
    180. moveq RET_REG, #1
    181. strexne STR_RES, ACT_VAL, [P_DATA]
    182. strne ACT_VAL, [P_EXPC]
    183. cmp STR_RES, #0
    184. itt ne
    185. movne RET_REG, #0
    186. bne loop_cmp_exch
    187. pop {r4-r6}
    188. bx lr
    189. #undef RET_REG
    190. #undef P_EXPC
    191. #undef VALUE
    192. #undef STR_RES
    193. #undef P_DATA
    194. #undef EXPC_VAL
    195. #undef ACT_VAL
    196. }
    197. static __asm uint32_t nrf_atomic_internal_sub_hs(nrf_atomic_u32_t * p_ptr,
    198. uint32_t value,
    199. uint32_t * p_new)
    200. {
    201. push {r4, r5}
    202. mov r4, r0
    203. loop_sub_ge
    204. ldrex r0, [r4]
    205. cmp r0, r1
    206. ite hs
    207. subhs r5, r0, r1
    208. movlo r5, r0
    209. strex r3, r5, [r4]
    210. cmp r3, #0
    211. bne loop_sub_ge
    212. str r5, [r2]
    213. pop {r4, r5}
    214. bx lr
    215. }
    216. #define NRF_ATOMIC_OP(asm_op, old_val, new_val, ptr, value) \
    217. old_val = nrf_atomic_internal_##asm_op(ptr, value, &new_val)
    218. #elif defined ( __ICCARM__ ) || defined ( __GNUC__ )
    219. /**
    220. * @brief Atomic operation generic macro
    221. * @param[in] asm_op operation: mov, orr, and, eor, add, sub
    222. * @param[out] old_val atomic object output (uint32_t), value before operation
    223. * @param[out] new_val atomic object output (uint32_t), value after operation
    224. * @param[in] value atomic operation operand
    225. * */
    226. #define NRF_ATOMIC_OP(asm_op, old_val, new_val, ptr, value) \
    227. { \
    228. uint32_t str_res; \
    229. __ASM volatile( \
    230. "1: ldrex %["#old_val"], [%["#ptr"]]\n" \
    231. NRF_ATOMIC_OP_##asm_op(new_val, old_val, value) \
    232. " strex %[str_res], %["#new_val"], [%["#ptr"]]\n" \
    233. " teq %[str_res], #0\n" \
    234. " bne.n 1b" \
    235. : \
    236. [old_val]"=&r" (old_val), \
    237. [new_val]"=&r" (new_val), \
    238. [str_res]"=&r" (str_res) \
    239. : \
    240. [ptr]"r" (ptr), \
    241. [value]"r" (value) \
    242. : "cc"); \
    243. UNUSED_PARAMETER(str_res); \
    244. }
    245. #define NRF_ATOMIC_OP_mov(new_val, old_val, value) "mov %["#new_val"], %["#value"]\n"
    246. #define NRF_ATOMIC_OP_orr(new_val, old_val, value) "orr %["#new_val"], %["#old_val"], %["#value"]\n"
    247. #define NRF_ATOMIC_OP_and(new_val, old_val, value) "and %["#new_val"], %["#old_val"], %["#value"]\n"
    248. #define NRF_ATOMIC_OP_eor(new_val, old_val, value) "eor %["#new_val"], %["#old_val"], %["#value"]\n"
    249. #define NRF_ATOMIC_OP_add(new_val, old_val, value) "add %["#new_val"], %["#old_val"], %["#value"]\n"
    250. #define NRF_ATOMIC_OP_sub(new_val, old_val, value) "sub %["#new_val"], %["#old_val"], %["#value"]\n"
    251. #define NRF_ATOMIC_OP_sub_hs(new_val, old_val, value) \
    252. "cmp %["#old_val"], %["#value"]\n " \
    253. "ite hs\n" \
    254. "subhs %["#new_val"], %["#old_val"], %["#value"]\n" \
    255. "movlo %["#new_val"], %["#old_val"]\n"
    256. static inline bool nrf_atomic_internal_cmp_exch(nrf_atomic_u32_t * p_data,
    257. uint32_t * p_expected,
    258. uint32_t value)
    259. {
    260. bool res = false;
    261. uint32_t str_res = 0;
    262. uint32_t act_val = 0;
    263. uint32_t exp_val = 0;
    264. UNUSED_VARIABLE(str_res);
    265. UNUSED_VARIABLE(act_val);
    266. UNUSED_VARIABLE(exp_val);
    267. __ASM volatile(
    268. "1: ldrex %[act_val], [%[ptr]]\n"
    269. " ldr %[exp_val], [%[expc]]\n"
    270. " cmp %[act_val], %[exp_val]\n"
    271. " ittee eq\n"
    272. " strexeq %[str_res], %[value], [%[ptr]]\n"
    273. " moveq %[res], #1\n"
    274. " strexne %[str_res], %[act_val], [%[ptr]]\n"
    275. " strne %[act_val], [%[expc]]\n"
    276. " cmp %[str_res], #0\n"
    277. " itt ne\n"
    278. " movne %[res], #0\n"
    279. " bne.n 1b"
    280. :
    281. [res] "=&r" (res),
    282. [exp_val] "=&r" (exp_val),
    283. [act_val] "=&r" (act_val),
    284. [str_res] "=&r" (str_res)
    285. :
    286. "0" (res),
    287. "1" (exp_val),
    288. "2" (act_val),
    289. [expc] "r" (p_expected),
    290. [ptr] "r" (p_data),
    291. [value] "r" (value)
    292. : "cc");
    293. return res;
    294. }
    295. #else
    296. #error "Unsupported compiler"
    297. #endif
    298. #ifdef __cplusplus
    299. }
    300. #endif
    301. #endif /* NRF_ATOMIC_INTERNAL_H__ */
    302. /** @} */

    nrf_mtx.h

    1. /**
    2. * Copyright (c) 2015 - 2019, Nordic Semiconductor ASA
    3. *
    4. * All rights reserved.
    5. *
    6. * Redistribution and use in source and binary forms, with or without modification,
    7. * are permitted provided that the following conditions are met:
    8. *
    9. * 1. Redistributions of source code must retain the above copyright notice, this
    10. * list of conditions and the following disclaimer.
    11. *
    12. * 2. Redistributions in binary form, except as embedded into a Nordic
    13. * Semiconductor ASA integrated circuit in a product or a software update for
    14. * such product, must reproduce the above copyright notice, this list of
    15. * conditions and the following disclaimer in the documentation and/or other
    16. * materials provided with the distribution.
    17. *
    18. * 3. Neither the name of Nordic Semiconductor ASA nor the names of its
    19. * contributors may be used to endorse or promote products derived from this
    20. * software without specific prior written permission.
    21. *
    22. * 4. This software, with or without modification, must only be used with a
    23. * Nordic Semiconductor ASA integrated circuit.
    24. *
    25. * 5. Any software provided in binary form under this license must not be reverse
    26. * engineered, decompiled, modified and/or disassembled.
    27. *
    28. * THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
    29. * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
    30. * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
    31. * DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE
    32. * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
    33. * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
    34. * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
    35. * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
    36. * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
    37. * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
    38. *
    39. */
    40. /** @file
    41. * @defgroup nrf_mtx nRF Mutex
    42. * @{
    43. * @ingroup app_common
    44. * @brief Mutex used for protecting resources.
    45. *
    46. * This module provides a mutex that can be used to ensure only one context may enter a critical
    47. * section holding the lock.
    48. */
    49. #ifndef NRF_MTX_H__
    50. #define NRF_MTX_H__
    51. #include
    52. #include
    53. #include "nrf.h"
    54. #include "nrf_atomic.h"
    55. #include "nrf_assert.h"
    56. #define NRF_MTX_LOCKED 1
    57. #define NRF_MTX_UNLOCKED 0
    58. /**
    59. * @brief Mutex data type.
    60. *
    61. * All fields in this struct are internal, and should never be modified outside of the nrf_mtx_*
    62. * functions.
    63. */
    64. typedef nrf_atomic_u32_t nrf_mtx_t;
    65. /**
    66. * @brief Initialize mutex.
    67. *
    68. * This function _must_ be called before nrf_mtx_trylock() and nrf_mtx_unlock() functions.
    69. *
    70. * @param[in, out] p_mtx The mutex to be initialized.
    71. */
    72. __STATIC_INLINE void nrf_mtx_init(nrf_mtx_t * p_mtx);
    73. /**
    74. * @brief Destroy mutex.
    75. *
    76. * This function can be used in abort scenarios or when the mutex is no longer to be used.
    77. *
    78. * @param[in] p_mtx The mutex to be destroy.
    79. */
    80. __STATIC_INLINE void nrf_mtx_destroy(nrf_mtx_t * p_mtx);
    81. /**
    82. * @brief Try to lock a mutex.
    83. *
    84. * If the mutex is already held by another context, this function will return immediately.
    85. *
    86. * @param[in, out] p_mtx The mutex to be locked.
    87. * @return true if lock was acquired, false if not
    88. */
    89. __STATIC_INLINE bool nrf_mtx_trylock(nrf_mtx_t * p_mtx);
    90. /**
    91. * @brief Unlock a mutex.
    92. *
    93. * This function _must_ only be called when holding the lock. Unlocking a mutex which you do not
    94. * hold will give undefined behavior.
    95. *
    96. * @note Unlock must happen from the same context as the one used to lock the mutex.
    97. *
    98. * @param[in, out] p_mtx The mutex to be unlocked.
    99. */
    100. __STATIC_INLINE void nrf_mtx_unlock(nrf_mtx_t * p_mtx);
    101. #ifndef SUPPRESS_INLINE_IMPLEMENTATION
    102. __STATIC_INLINE void nrf_mtx_init(nrf_mtx_t * p_mtx)
    103. {
    104. ASSERT(p_mtx != NULL);
    105. *p_mtx = NRF_MTX_UNLOCKED;
    106. __DMB();
    107. }
    108. __STATIC_INLINE void nrf_mtx_destroy(nrf_mtx_t * p_mtx)
    109. {
    110. ASSERT(p_mtx != NULL);
    111. // Add memory barrier to ensure that any memory operations protected by the mutex complete
    112. // before the mutex is destroyed.
    113. __DMB();
    114. *p_mtx = NRF_MTX_UNLOCKED;
    115. }
    116. __STATIC_INLINE bool nrf_mtx_trylock(nrf_mtx_t * p_mtx)
    117. {
    118. ASSERT(p_mtx != NULL);
    119. uint32_t old_val = nrf_atomic_u32_fetch_store(p_mtx, NRF_MTX_LOCKED);
    120. // Add memory barrier to ensure that the mutex is locked before any memory operations protected
    121. // by the mutex are started.
    122. __DMB();
    123. return (old_val == NRF_MTX_UNLOCKED);
    124. }
    125. __STATIC_INLINE void nrf_mtx_unlock(nrf_mtx_t * p_mtx)
    126. {
    127. ASSERT(p_mtx != NULL);
    128. ASSERT(*p_mtx == NRF_MTX_LOCKED);
    129. // Add memory barrier to ensure that any memory operations protected by the mutex complete
    130. // before the mutex is unlocked.
    131. __DMB();
    132. *p_mtx = NRF_MTX_UNLOCKED;
    133. }
    134. #endif //SUPPRESS_INLINE_IMPLEMENTATION
    135. #endif // NRF_MTX_H__
    136. /** @} */

    nordic_common.h

    1. /**
    2. * Copyright (c) 2008 - 2019, Nordic Semiconductor ASA
    3. *
    4. * All rights reserved.
    5. *
    6. * Redistribution and use in source and binary forms, with or without modification,
    7. * are permitted provided that the following conditions are met:
    8. *
    9. * 1. Redistributions of source code must retain the above copyright notice, this
    10. * list of conditions and the following disclaimer.
    11. *
    12. * 2. Redistributions in binary form, except as embedded into a Nordic
    13. * Semiconductor ASA integrated circuit in a product or a software update for
    14. * such product, must reproduce the above copyright notice, this list of
    15. * conditions and the following disclaimer in the documentation and/or other
    16. * materials provided with the distribution.
    17. *
    18. * 3. Neither the name of Nordic Semiconductor ASA nor the names of its
    19. * contributors may be used to endorse or promote products derived from this
    20. * software without specific prior written permission.
    21. *
    22. * 4. This software, with or without modification, must only be used with a
    23. * Nordic Semiconductor ASA integrated circuit.
    24. *
    25. * 5. Any software provided in binary form under this license must not be reverse
    26. * engineered, decompiled, modified and/or disassembled.
    27. *
    28. * THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
    29. * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
    30. * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
    31. * DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE
    32. * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
    33. * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
    34. * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
    35. * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
    36. * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
    37. * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
    38. *
    39. */
    40. /** @file
    41. * @brief Common defines and macros for firmware developed by Nordic Semiconductor.
    42. */
    43. #ifndef NORDIC_COMMON_H__
    44. #define NORDIC_COMMON_H__
    45. #ifdef __cplusplus
    46. extern "C" {
    47. #endif
    48. /**
    49. * @brief Check if selected module is enabled
    50. *
    51. * This is save function for driver enable checking.
    52. * Correct from Lint point of view (not using default of undefined value).
    53. *
    54. * Usage:
    55. * @code
    56. #if NRF_MODULE_ENABLED(UART)
    57. ...
    58. #endif
    59. * @endcode
    60. *
    61. * @param module The module name.
    62. *
    63. * @retval 1 The macro _ENABLE is defined and is non-zero.
    64. * @retval 0 The macro _ENABLE is not defined or it equals zero.
    65. *
    66. * @note
    67. * This macro intentionally does not implement second expansion level.
    68. * The name of the module to be checked has to be given directly as a parameter.
    69. * And given parameter would be connected with @c _ENABLED postfix directly
    70. * without evaluating its value.
    71. */
    72. //lint -emacro(491,NRF_MODULE_ENABLED) // Suppers warning 491 "non-standard use of 'defined' preprocessor operator"
    73. #ifdef NRF_MODULE_ENABLE_ALL
    74. #warning "Do not use NRF_MODULE_ENABLE_ALL for real builds."
    75. #define NRF_MODULE_ENABLED(module) 1
    76. #else
    77. #define NRF_MODULE_ENABLED(module) \
    78. ((defined(module ## _ENABLED) && (module ## _ENABLED)) ? 1 : 0)
    79. #endif
    80. /** The upper 8 bits of a 32 bit value */
    81. //lint -emacro(572,MSB_32) // Suppress warning 572 "Excessive shift value"
    82. #define MSB_32(a) (((a) & 0xFF000000) >> 24)
    83. /** The lower 8 bits (of a 32 bit value) */
    84. #define LSB_32(a) ((a) & 0x000000FF)
    85. /** The upper 8 bits of a 16 bit value */
    86. //lint -emacro(572,MSB_16) // Suppress warning 572 "Excessive shift value"
    87. #define MSB_16(a) (((a) & 0xFF00) >> 8)
    88. /** The lower 8 bits (of a 16 bit value) */
    89. #define LSB_16(a) ((a) & 0x00FF)
    90. /** Leaves the minimum of the two 32-bit arguments */
    91. /*lint -emacro(506, MIN) */ /* Suppress "Constant value Boolean */
    92. #define MIN(a, b) ((a) < (b) ? (a) : (b))
    93. /** Leaves the maximum of the two 32-bit arguments */
    94. /*lint -emacro(506, MAX) */ /* Suppress "Constant value Boolean */
    95. #define MAX(a, b) ((a) < (b) ? (b) : (a))
    96. /**@brief Concatenates two parameters.
    97. *
    98. * It realizes two level expansion to make it sure that all the parameters
    99. * are actually expanded before gluing them together.
    100. *
    101. * @param p1 First parameter to concatenating
    102. * @param p2 Second parameter to concatenating
    103. *
    104. * @return Two parameters glued together.
    105. * They have to create correct C mnemonic in other case
    106. * preprocessor error would be generated.
    107. *
    108. * @sa CONCAT_3
    109. */
    110. #define CONCAT_2(p1, p2) CONCAT_2_(p1, p2)
    111. /** Auxiliary macro used by @ref CONCAT_2 */
    112. #define CONCAT_2_(p1, p2) p1##p2
    113. /**@brief Concatenates three parameters.
    114. *
    115. * It realizes two level expansion to make it sure that all the parameters
    116. * are actually expanded before gluing them together.
    117. *
    118. * @param p1 First parameter to concatenating
    119. * @param p2 Second parameter to concatenating
    120. * @param p3 Third parameter to concatenating
    121. *
    122. * @return Three parameters glued together.
    123. * They have to create correct C mnemonic in other case
    124. * preprocessor error would be generated.
    125. *
    126. * @sa CONCAT_2
    127. */
    128. #define CONCAT_3(p1, p2, p3) CONCAT_3_(p1, p2, p3)
    129. /** Auxiliary macro used by @ref CONCAT_3 */
    130. #define CONCAT_3_(p1, p2, p3) p1##p2##p3
    131. #define STRINGIFY_(val) #val
    132. /** Converts a macro argument into a character constant.
    133. */
    134. #define STRINGIFY(val) STRINGIFY_(val)
    135. /** Counts number of elements inside the array
    136. */
    137. #define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0]))
    138. /**@brief Set a bit in the uint32 word.
    139. *
    140. * @param[in] W Word whose bit is being set.
    141. * @param[in] B Bit number in the word to be set.
    142. */
    143. #define SET_BIT(W, B) ((W) |= (uint32_t)(1U << (B)))
    144. /**@brief Clears a bit in the uint32 word.
    145. *
    146. * @param[in] W Word whose bit is to be cleared.
    147. * @param[in] B Bit number in the word to be cleared.
    148. */
    149. #define CLR_BIT(W, B) ((W) &= (~(uint32_t)(1U << (B))))
    150. /**@brief Checks if a bit is set.
    151. *
    152. * @param[in] W Word whose bit is to be checked.
    153. * @param[in] B Bit number in the word to be checked.
    154. *
    155. * @retval 1 if bit is set.
    156. * @retval 0 if bit is not set.
    157. */
    158. #define IS_SET(W, B) (((W) >> (B)) & 1)
    159. #define BIT_0 0x01 /**< The value of bit 0 */
    160. #define BIT_1 0x02 /**< The value of bit 1 */
    161. #define BIT_2 0x04 /**< The value of bit 2 */
    162. #define BIT_3 0x08 /**< The value of bit 3 */
    163. #define BIT_4 0x10 /**< The value of bit 4 */
    164. #define BIT_5 0x20 /**< The value of bit 5 */
    165. #define BIT_6 0x40 /**< The value of bit 6 */
    166. #define BIT_7 0x80 /**< The value of bit 7 */
    167. #define BIT_8 0x0100 /**< The value of bit 8 */
    168. #define BIT_9 0x0200 /**< The value of bit 9 */
    169. #define BIT_10 0x0400 /**< The value of bit 10 */
    170. #define BIT_11 0x0800 /**< The value of bit 11 */
    171. #define BIT_12 0x1000 /**< The value of bit 12 */
    172. #define BIT_13 0x2000 /**< The value of bit 13 */
    173. #define BIT_14 0x4000 /**< The value of bit 14 */
    174. #define BIT_15 0x8000 /**< The value of bit 15 */
    175. #define BIT_16 0x00010000 /**< The value of bit 16 */
    176. #define BIT_17 0x00020000 /**< The value of bit 17 */
    177. #define BIT_18 0x00040000 /**< The value of bit 18 */
    178. #define BIT_19 0x00080000 /**< The value of bit 19 */
    179. #define BIT_20 0x00100000 /**< The value of bit 20 */
    180. #define BIT_21 0x00200000 /**< The value of bit 21 */
    181. #define BIT_22 0x00400000 /**< The value of bit 22 */
    182. #define BIT_23 0x00800000 /**< The value of bit 23 */
    183. #define BIT_24 0x01000000 /**< The value of bit 24 */
    184. #define BIT_25 0x02000000 /**< The value of bit 25 */
    185. #define BIT_26 0x04000000 /**< The value of bit 26 */
    186. #define BIT_27 0x08000000 /**< The value of bit 27 */
    187. #define BIT_28 0x10000000 /**< The value of bit 28 */
    188. #define BIT_29 0x20000000 /**< The value of bit 29 */
    189. #define BIT_30 0x40000000 /**< The value of bit 30 */
    190. #define BIT_31 0x80000000 /**< The value of bit 31 */
    191. #define UNUSED_VARIABLE(X) ((void)(X))
    192. #define UNUSED_PARAMETER(X) UNUSED_VARIABLE(X)
    193. #define UNUSED_RETURN_VALUE(X) UNUSED_VARIABLE(X)
    194. #ifdef __cplusplus
    195. }
    196. #endif
    197. #endif // NORDIC_COMMON_H__

  • 相关阅读:
    Serverless安全揭秘:架构、风险与防护措施
    ABAP:调用HTTP接口详解
    图的存储方式
    c++虚拟继承那些事
    从零开始 Spring Boot 17:MyBatis Plus 续
    持续交付探索与实践(三):指标度量体系搭建
    申请专利的好处!这份清单告诉你,为什么要申请专利?
    ubuntu 安装postgresql,增加VECTOR向量数据库插件 踏坑详细流程
    联想曝新型UEFI漏洞,影响70款数百万台笔记本电脑
    Otsu阈值分割详解
  • 原文地址:https://blog.csdn.net/qwe5959798/article/details/126176408