ADC: atomic.h Source File

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