ADC  8.0
Analog to Digital Conversor library for the Teensy microprocessor
atomic.h
1 /* Teensy 4, 3.x, LC ADC library
2  * https://github.com/pedvide/ADC
3  * Copyright (c) 2019 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, int32_t, int16_t
44 
46 namespace atomic
47 {
49  /* Clear bit in address (make it zero), set bit (make it one), or return the value of that bit
50  * changeBitFlag can change up to 2 bits in a flag at the same time
51  * We can change this functions depending on the board.
52  * Teensy 3.x use bitband while Teensy LC has a more advanced bit manipulation engine.
53  * Teensy 4 also has bitband capabilities, but are not yet implemented, instead registers are
54  * set and cleared manually. TODO: fix this.
55  */
56  #if defined(KINETISK) // Teensy 3.x
57 
63  template<typename T>
64  __attribute__((always_inline)) inline volatile T& bitband_address(volatile T& reg, uint8_t bit) {
65  return (*(volatile T*)(((uint32_t)&reg - 0x40000000)*32 + bit*4 + 0x42000000));
66  }
67 
68  template<typename T>
69  __attribute__((always_inline)) inline void setBit(volatile T& reg, uint8_t bit) {
70  bitband_address(reg, bit) = 1;
71  }
72  template<typename T>
73  __attribute__((always_inline)) inline void setBitFlag(volatile T& reg, T flag) {
74  // 31-__builtin_clzl(flag) = gets bit number in flag
75  // __builtin_clzl works for long ints, which are guaranteed by standard to be at least 32 bit wide.
76  // there's no difference in the asm emitted.
77  bitband_address(reg, 31-__builtin_clzl(flag)) = 1;
78  if(__builtin_popcount(flag) > 1) {
79  // __builtin_ctzl returns the number of trailing 0-bits in x, starting at the least significant bit position
80  bitband_address(reg, __builtin_ctzl(flag)) = 1;
81  }
82  }
83 
84  template<typename T>
85  __attribute__((always_inline)) inline void clearBit(volatile T& reg, uint8_t bit) {
86  bitband_address(reg, bit) = 0;
87  }
88  template<typename T>
89  __attribute__((always_inline)) inline void clearBitFlag(volatile T& reg, T flag) {
90  bitband_address(reg, 31-__builtin_clzl(flag)) = 0;
91  if(__builtin_popcount(flag) > 1) {
92  bitband_address(reg, __builtin_ctzl(flag)) = 0;
93  }
94  }
95 
96  template<typename T>
97  __attribute__((always_inline)) inline void changeBit(volatile T& reg, uint8_t bit, bool state) {
98  bitband_address(reg, bit) = state;
99  }
100  template<typename T>
101  __attribute__((always_inline)) inline void changeBitFlag(volatile T& reg, T flag, T state) {
102  bitband_address(reg, __builtin_ctzl(flag)) = (state >> __builtin_ctzl(flag))&0x1;
103  if(__builtin_popcount(flag) > 1) {
104  bitband_address(reg, 31-__builtin_clzl(flag)) = (state >> (31-__builtin_clzl(flag)))&0x1;
105  }
106  }
107 
108  template<typename T>
109  __attribute__((always_inline)) inline volatile bool getBit(volatile T& reg, uint8_t bit) {
110  return (volatile bool)bitband_address(reg, bit);
111  }
112  template<typename T>
113  __attribute__((always_inline)) inline volatile bool getBitFlag(volatile T& reg, T flag) {
114  return (volatile bool)bitband_address(reg, 31-__builtin_clzl(flag));
115  }
116 
117 
118  #elif defined(__IMXRT1062__) // Teensy 4
119  template<typename T>
120  __attribute__((always_inline)) inline void setBitFlag(volatile T& reg, T flag) {
121  __disable_irq();
122  reg |= flag;
123  __enable_irq();
124  }
125 
126  template<typename T>
127  __attribute__((always_inline)) inline void clearBitFlag(volatile T& reg, T flag) {
128  __disable_irq();
129  reg &= ~flag;
130  __enable_irq();
131  }
132 
133  template<typename T>
134  __attribute__((always_inline)) inline void changeBitFlag(volatile T& reg, T flag, T state) {
135  // flag can be 1 or 2 bits wide
136  // state can have one or two bits set
137  if(__builtin_popcount(flag) == 1) { // 1 bit
138  if (state) {
139  setBitFlag(reg, flag);
140  } else {
141  clearBitFlag(reg, flag);
142  }
143  } else { // 2 bits
144  // lsb first
145  if ((state >> __builtin_ctzl(flag))&0x1) { // lsb of state is 1
146  setBitFlag(reg, (uint32_t)(1 << __builtin_ctzl(flag)));
147  } else { // lsb is 0
148  clearBitFlag(reg, (uint32_t)(1 << __builtin_ctzl(flag)));
149  }
150  // msb
151  if ((state >> (31-__builtin_clzl(flag)))&0x1) { // msb of state is 1
152  setBitFlag(reg, (uint32_t)(1 << (31-__builtin_clzl(flag))));
153  } else { // msb is 0
154  clearBitFlag(reg, (uint32_t)(1 << (31-__builtin_clzl(flag))));
155  }
156  }
157 
158  }
159 
160  template<typename T>
161  __attribute__((always_inline)) inline volatile bool getBitFlag(volatile T& reg, T flag) {
162  return (volatile bool)((reg) & flag) >> (31-__builtin_clzl(flag));
163  }
164 
165 
166 
167  #elif defined(KINETISL) // Teensy LC
168  // bit manipulation engine
169 
170  template<typename T>
171  __attribute__((always_inline)) inline void setBit(volatile T& reg, uint8_t bit) {
172  //temp = *(uint32_t *)((uint32_t)(reg) | (1<<26) | (bit<<21)); // LAS
173  *(volatile T*)((uint32_t)(&reg) | (1<<27)) = 1<<bit; // OR
174  }
175  template<typename T>
176  __attribute__((always_inline)) inline void setBitFlag(volatile T& reg, uint32_t flag) {
177  *(volatile T*)((uint32_t)&reg | (1<<27)) = flag; // OR
178  }
179 
180  template<typename T>
181  __attribute__((always_inline)) inline void clearBit(volatile T& reg, uint8_t bit) {
182  //temp = *(uint32_t *)((uint32_t)(reg) | (3<<27) | (bit<<21)); // LAC
183  *(volatile T*)((uint32_t)(&reg) | (1<<26)) = ~(1<<bit); // AND
184  }
185  template<typename T>
186  __attribute__((always_inline)) inline void clearBitFlag(volatile T& reg, uint32_t flag) {
187  //temp = *(uint32_t *)((uint32_t)(reg) | (3<<27) | (bit<<21)); // LAC
188  *(volatile T*)((uint32_t)(&reg) | (1<<26)) = ~flag; // AND
189  }
190 
191  template<typename T>
192  __attribute__((always_inline)) inline void changeBit(volatile T& reg, uint8_t bit, bool state) {
193  //temp = *(uint32_t *)((uint32_t)(reg) | ((3-2*!!state)<<27) | (bit<<21)); // LAS/LAC
194  state ? setBit(reg, bit) : clearBit(reg, bit);
195  }
196  template<typename T>
197  __attribute__((always_inline)) inline void changeBitFlag(volatile T& reg, T flag, T state) {
198  // BFI, bitfield width set to __builtin_popcount(flag)
199  // least significant bit set to __builtin_ctzl(flag)
200  *(volatile T*)((uint32_t)(&reg) | (1<<28) | (__builtin_ctzl(flag)<<23) | ((__builtin_popcount(flag)-1)<<19)) = state;
201  }
202 
203  template<typename T>
204  __attribute__((always_inline)) inline volatile bool getBit(volatile T& reg, uint8_t bit) {
205  return (volatile bool)*(volatile T *)((uint32_t)(&reg) | (1<<28) | (bit<<23) ); // UBFX
206  }
207  template<typename T>
208  __attribute__((always_inline)) inline volatile bool getBitFlag(volatile T& reg, T flag) {
209  return (volatile bool)*(volatile T *)((uint32_t)(&reg) | (1<<28) | ((31-__builtin_clzl(flag))<<23) ); // UBFX
210  }
211 
212  #endif
213 
214 }
215 
216 #endif // ADC_ATOMIC_H
atomic
Atomic set, clear, change, or get bit in a register.
Definition: atomic.h:46