ADC  9.2
Analog to Digital Conversor library for the Teensy 3.1/3.2 microprocessor
atomic.h
1 /* Teensy 4.x, 3.x, LC ADC library
2  * https://github.com/pedvide/ADC
3  * Copyright (c) 2020 Pedro Villanueva
4  *
5  * Permission is hereby granted, free of charge, to any person obtaining
6  * a copy of this software and associated documentation files (the
7  * "Software"), to deal in the Software without restriction, including
8  * without limitation the rights to use, copy, modify, merge, publish,
9  * distribute, sublicense, and/or sell copies of the Software, and to
10  * permit persons to whom the Software is furnished to do so, subject to
11  * the following conditions:
12  *
13  * The above copyright notice and this permission notice shall be
14  * included in all copies or substantial portions of the Software.
15  *
16  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19  * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
20  * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
21  * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
22  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
23  * SOFTWARE.
24  */
25 
26 #ifndef ADC_ATOMIC_H
27 #define ADC_ATOMIC_H
28 
29 /* int __builtin_ctz (unsigned int x):
30  Returns the number of trailing 0-bits in x,
31  starting at the least significant bit position.
32  If x is 0, the result is undefined.
33 */
34 /* int __builtin_clz (unsigned int x)
35  Returns the number of leading 0-bits in x,
36  starting at the most significant bit position.
37  If x is 0, the result is undefined.
38 */
39 /* int __builtin_popcount (unsigned int x)
40  Returns the number of 1-bits in x.
41 */
42 
43 // kinetis.h has the following types for addresses: uint32_t, uint16_t, uint8_t,
44 // int32_t, int16_t
45 
59 namespace atomic {
60 
61 #if defined(KINETISK) // Teensy 3.x
62 
69 template <typename T>
70 __attribute__((always_inline)) inline volatile T &
71 bitband_address(volatile T &reg, uint8_t bit) {
72  return (*(volatile T *)(((uint32_t)&reg - 0x40000000) * 32 + bit * 4 +
73  0x42000000));
74 }
75 
82 template <typename T>
83 __attribute__((always_inline)) inline void setBit(volatile T &reg,
84  uint8_t bit) {
85  bitband_address(reg, bit) = 1;
86 }
87 
94 template <typename T>
95 __attribute__((always_inline)) inline void setBitFlag(volatile T &reg, T flag) {
96  // 31-__builtin_clzl(flag) = gets bit number in flag
97  // __builtin_clzl works for long ints, which are guaranteed by standard to be
98  // at least 32 bit wide. there's no difference in the asm emitted.
99  bitband_address(reg, 31 - __builtin_clzl(flag)) = 1;
100  if (__builtin_popcount(flag) > 1) {
101  // __builtin_ctzl returns the number of trailing 0-bits in x, starting at
102  // the least significant bit position
103  bitband_address(reg, __builtin_ctzl(flag)) = 1;
104  }
105 }
106 
113 template <typename T>
114 __attribute__((always_inline)) inline void clearBit(volatile T &reg,
115  uint8_t bit) {
116  bitband_address(reg, bit) = 0;
117 }
118 
125 template <typename T>
126 __attribute__((always_inline)) inline void clearBitFlag(volatile T &reg,
127  T flag) {
128  bitband_address(reg, 31 - __builtin_clzl(flag)) = 0;
129  if (__builtin_popcount(flag) > 1) {
130  bitband_address(reg, __builtin_ctzl(flag)) = 0;
131  }
132 }
133 
141 template <typename T>
142 __attribute__((always_inline)) inline void changeBit(volatile T &reg,
143  uint8_t bit, bool state) {
144  bitband_address(reg, bit) = state;
145 }
146 
154 template <typename T>
155 __attribute__((always_inline)) inline void changeBitFlag(volatile T &reg,
156  T flag, T state) {
157  bitband_address(reg, __builtin_ctzl(flag)) =
158  (state >> __builtin_ctzl(flag)) & 0x1;
159  if (__builtin_popcount(flag) > 1) {
160  bitband_address(reg, 31 - __builtin_clzl(flag)) =
161  (state >> (31 - __builtin_clzl(flag))) & 0x1;
162  }
163 }
164 
172 template <typename T>
173 __attribute__((always_inline)) inline volatile bool getBit(volatile T &reg,
174  uint8_t bit) {
175  return (volatile bool)bitband_address(reg, bit);
176 }
177 
185 template <typename T>
186 __attribute__((always_inline)) inline volatile bool getBitFlag(volatile T &reg,
187  T flag) {
188  return (volatile bool)bitband_address(reg, 31 - __builtin_clzl(flag));
189 }
190 
191 #elif defined(__IMXRT1062__) // Teensy 4
192 
198 template <typename T>
199 __attribute__((always_inline)) inline void setBitFlag(volatile T &reg, T flag) {
200  __disable_irq();
201  reg |= flag;
202  __enable_irq();
203 }
204 
211 template <typename T>
212 __attribute__((always_inline)) inline void clearBitFlag(volatile T &reg,
213  T flag) {
214  __disable_irq();
215  reg &= ~flag;
216  __enable_irq();
217 }
218 
226 template <typename T>
227 __attribute__((always_inline)) inline void changeBitFlag(volatile T &reg,
228  T flag, T state) {
229  // flag can be 1 or 2 bits wide
230  // state can have one or two bits set
231  if (__builtin_popcount(flag) == 1) { // 1 bit
232  if (state) {
233  setBitFlag(reg, flag);
234  } else {
235  clearBitFlag(reg, flag);
236  }
237  } else { // 2 bits
238  // lsb first
239  if ((state >> __builtin_ctzl(flag)) & 0x1) { // lsb of state is 1
240  setBitFlag(reg, (uint32_t)(1 << __builtin_ctzl(flag)));
241  } else { // lsb is 0
242  clearBitFlag(reg, (uint32_t)(1 << __builtin_ctzl(flag)));
243  }
244  // msb
245  if ((state >> (31 - __builtin_clzl(flag))) & 0x1) { // msb of state is 1
246  setBitFlag(reg, (uint32_t)(1 << (31 - __builtin_clzl(flag))));
247  } else { // msb is 0
248  clearBitFlag(reg, (uint32_t)(1 << (31 - __builtin_clzl(flag))));
249  }
250  }
251 }
252 
260 template <typename T>
261 __attribute__((always_inline)) inline volatile bool getBitFlag(volatile T &reg,
262  T flag) {
263  return (volatile bool)((reg)&flag) >> (31 - __builtin_clzl(flag));
264 }
265 
266 #elif defined(KINETISL) // Teensy LC
267 // bit manipulation engine
268 
275 template <typename T>
276 __attribute__((always_inline)) inline void setBit(volatile T &reg,
277  uint8_t bit) {
278  // temp = *(uint32_t *)((uint32_t)(reg) | (1<<26) | (bit<<21)); // LAS
279  *(volatile T *)((uint32_t)(&reg) | (1 << 27)) = 1 << bit; // OR
280 }
281 
288 template <typename T>
289 __attribute__((always_inline)) inline void setBitFlag(volatile T &reg,
290  uint32_t flag) {
291  *(volatile T *)((uint32_t)&reg | (1 << 27)) = flag; // OR
292 }
293 
300 template <typename T>
301 __attribute__((always_inline)) inline void clearBit(volatile T &reg,
302  uint8_t bit) {
303  // temp = *(uint32_t *)((uint32_t)(reg) | (3<<27) | (bit<<21)); // LAC
304  *(volatile T *)((uint32_t)(&reg) | (1 << 26)) = ~(1 << bit); // AND
305 }
306 
313 template <typename T>
314 __attribute__((always_inline)) inline void clearBitFlag(volatile T &reg,
315  uint32_t flag) {
316  // temp = *(uint32_t *)((uint32_t)(reg) | (3<<27) | (bit<<21)); // LAC
317  *(volatile T *)((uint32_t)(&reg) | (1 << 26)) = ~flag; // AND
318 }
319 
327 template <typename T>
328 __attribute__((always_inline)) inline void changeBit(volatile T &reg,
329  uint8_t bit, bool state) {
330  // temp = *(uint32_t *)((uint32_t)(reg) | ((3-2*!!state)<<27) | (bit<<21)); //
331  // LAS/LAC
332  state ? setBit(reg, bit) : clearBit(reg, bit);
333 }
334 
342 template <typename T>
343 __attribute__((always_inline)) inline void changeBitFlag(volatile T &reg,
344  T flag, T state) {
345  // BFI, bitfield width set to __builtin_popcount(flag)
346  // least significant bit set to __builtin_ctzl(flag)
347  *(volatile T *)((uint32_t)(&reg) | (1 << 28) | (__builtin_ctzl(flag) << 23) |
348  ((__builtin_popcount(flag) - 1) << 19)) = state;
349 }
350 
358 template <typename T>
359 __attribute__((always_inline)) inline volatile bool getBit(volatile T &reg,
360  uint8_t bit) {
361  return (volatile bool)*(volatile T *)((uint32_t)(&reg) | (1 << 28) |
362  (bit << 23)); // UBFX
363 }
364 
372 template <typename T>
373 __attribute__((always_inline)) inline volatile bool getBitFlag(volatile T &reg,
374  T flag) {
375  return (volatile bool)*(
376  volatile T *)((uint32_t)(&reg) | (1 << 28) |
377  ((31 - __builtin_clzl(flag)) << 23)); // UBFX
378 }
379 
380 #endif
381 
382 } // namespace atomic
383 
384 #endif // ADC_ATOMIC_H
atomic
Atomic set, clear, change, or get bit in a register.
Definition: atomic.h:59