TNeo  v1.08
tn_arch_pic32_bfa.h
Go to the documentation of this file.
1 /*******************************************************************************
2  *
3  * TNeo: real-time kernel initially based on TNKernel
4  *
5  * TNKernel: copyright 2004, 2013 Yuri Tiomkin.
6  * PIC32-specific routines: copyright 2013, 2014 Anders Montonen.
7  * TNeo: copyright 2014 Dmitry Frank.
8  *
9  * TNeo was born as a thorough review and re-implementation of
10  * TNKernel. The new kernel has well-formed code, inherited bugs are fixed
11  * as well as new features being added, and it is tested carefully with
12  * unit-tests.
13  *
14  * API is changed somewhat, so it's not 100% compatible with TNKernel,
15  * hence the new name: TNeo.
16  *
17  * Permission to use, copy, modify, and distribute this software in source
18  * and binary forms and its documentation for any purpose and without fee
19  * is hereby granted, provided that the above copyright notice appear
20  * in all copies and that both that copyright notice and this permission
21  * notice appear in supporting documentation.
22  *
23  * THIS SOFTWARE IS PROVIDED BY THE DMITRY FRANK AND CONTRIBUTORS "AS IS"
24  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
26  * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL DMITRY FRANK OR CONTRIBUTORS BE
27  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
28  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
29  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
30  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
31  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
32  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
33  * THE POSSIBILITY OF SUCH DAMAGE.
34  *
35  ******************************************************************************/
36 
37 /**
38  * \file
39  *
40  * Atomic bit-field access macros for PIC24/dsPIC.
41  *
42  * Initially, the code was taken from the [article by Alex Borisov
43  * (russian)](http://www.pic24.ru/doku.php/articles/mchp/c30_atomic_access),
44  * and modified a bit.
45  *
46  * The kernel would not probably provide that kind of functionality, but
47  * the kernel itself needs it, so, it is made public so that application can
48  * use it too.
49  */
50 
51 #ifndef _TN_ARCH_PIC24_BFA_H
52 #define _TN_ARCH_PIC24_BFA_H
53 
54 
55 
56 /*******************************************************************************
57  * INCLUDED FILES
58  ******************************************************************************/
59 
60 
61 
62 #ifdef __cplusplus
63 extern "C" { /*}*/
64 #endif
65 
66 
67 /*******************************************************************************
68  * DEFINITIONS
69  ******************************************************************************/
70 
71 /* Access params */
72 
73 ///
74 /// Command for `TN_BFA()` macro: Set bits in the bit field by mask;
75 /// `...` macro param should be set to the bit mask to set.
76 #define TN_BFA_SET 0x1111
77 ///
78 /// Command for `TN_BFA()` macro: Clear bits in the bit field by mask;
79 /// `...` macro param should be set to the bit mask to clear.
80 #define TN_BFA_CLR 0x2222
81 ///
82 /// Command for `TN_BFA()` macro: Invert bits in the bit field by mask;
83 /// `...` macro param should be set to the bit mask to invert.
84 #define TN_BFA_INV 0x3333
85 ///
86 /// Command for `TN_BFA()` macro: Write bit field;
87 /// `...` macro param should be set to the value to write.
88 #define TN_BFA_WR 0xAAAA
89 ///
90 /// Command for `TN_BFA()` macro: Read bit field;
91 /// `...` macro param ignored.
92 #define TN_BFA_RD 0xBBBB
93 
94 
95 
96 /**
97  * Macro for atomic access to the structure bit field. The `BFA` acronym
98  * means Bit Field Access.
99  *
100  * @param comm
101  * command to execute:
102  * - `#TN_BFA_WR` - write bit field
103  * - `#TN_BFA_RD` - read bit field
104  * - `#TN_BFA_SET` - set bits by mask
105  * - `#TN_BFA_CLR` - clear bits by mask
106  * - `#TN_BFA_INV` - invert bits by mask
107  *
108  * @param reg_name
109  * register name (`PORTA`, `CMCON`, ...).
110  *
111  * @param field_name
112  * structure field name
113  *
114  * @param ...
115  * used if only `comm != #TN_BFA_RD`. Meaning depends on the `comm`,
116  * see comments for specific command: `#TN_BFA_WR`, etc.
117  *
118  *
119  * Usage examples:
120  *
121  * \code{.c}
122  *
123  * int a = 0x02;
124  *
125  * //-- Set third bit of the INT0IP field in the IPC0 register:
126  * // IPC0bits.INT0IP |= (1 << 2);
127  * TN_BFA(TN_BFA_SET, IPC0, INT0IP, (1 << 2));
128  *
129  * //-- Clear second bit of the INT0IP field in the IPC0 register:
130  * // IPC0bits.INT0IP &= ~(1 << 1);
131  * TN_BFA(TN_BFA_CLR, IPC0, INT0IP, (1 << 1));
132  *
133  * //-- Invert two less-significant bits of the INT0IP field
134  * // in the IPC0 register:
135  * // IPC0bits.INT0IP ^= 0x03;
136  * TN_BFA(TN_BFA_INV, IPC0, INT0IP, 0x03);
137  *
138  * //-- Write value 0x05 to the INT0IP field of the IPC0 register:
139  * // IPC0bits.INT0IP = 0x05;
140  * TN_BFA(TN_BFA_WR, IPC0, INT0IP, 0x05);
141  *
142  * //-- Write value of the variable a to the INT0IP field of the IPC0
143  * // register:
144  * // IPC0bits.INT0IP = a;
145  * TN_BFA(TN_BFA_WR, IPC0, INT0IP, a);
146  *
147  * //-- Read the value that is stored in the INT0IP field of the IPC0
148  * // register, to the int variable a:
149  * // int a = IPC0bits.INT0IP;
150  * a = TN_BFA(TN_BFA_RD, IPC0, INT0IP);
151  *
152  * \endcode
153  */
154 #define TN_BFA(comm, reg_name, field_name, ...) \
155  ({ \
156  ((comm) == TN_BFA_WR) \
157  ?({ \
158  _TN_BFA_COMM_GET(comm) v = __VA_ARGS__+0; \
159  if (_TN_BFA_FIELD_DEF(reg_name, field_name, LENGTH) == 1) { \
160  if (v & 1) { \
161  _TN_BFA_REG_DEF(reg_name, SET) = \
162  _TN_BFA_FIELD_DEF(reg_name, field_name, MASK); \
163  } else { \
164  _TN_BFA_REG_DEF(reg_name, CLR) = \
165  _TN_BFA_FIELD_DEF(reg_name, field_name, MASK); \
166  } \
167  } else { \
168  _TN_BFA_REG_DEF(reg_name, INV) = \
169  _TN_BFA_FIELD_DEF(reg_name, field_name, MASK) \
170  & \
171  ( \
172  ((v) << _TN_BFA_FIELD_DEF( \
173  reg_name, field_name, POSITION \
174  )) \
175  ^ \
176  reg_name \
177  ); \
178  } \
179  }), 0 \
180  \
181  :(((comm) == TN_BFA_INV) \
182  ?({ \
183  _TN_BFA_COMM_GET(comm) v = __VA_ARGS__+0; \
184  _TN_BFA_REG_DEF(reg_name, INV) = \
185  ( \
186  _TN_BFA_FIELD_DEF(reg_name, field_name, MASK) \
187  & \
188  ((v) << _TN_BFA_FIELD_DEF(reg_name, field_name, POSITION)) \
189  ); \
190  }), 0 \
191  \
192  :((((comm) == TN_BFA_SET) \
193  ?({ \
194  _TN_BFA_COMM_GET(comm) v = __VA_ARGS__+0; \
195  _TN_BFA_REG_DEF(reg_name, SET) = \
196  ( \
197  _TN_BFA_FIELD_DEF(reg_name, field_name, MASK) \
198  & \
199  ((v) << _TN_BFA_FIELD_DEF(reg_name, field_name, POSITION)) \
200  ); \
201  }), 0 \
202  \
203  :(((((comm) == TN_BFA_CLR) \
204  ?({ \
205  _TN_BFA_COMM_GET(comm) v = __VA_ARGS__+0; \
206  _TN_BFA_REG_DEF(reg_name, CLR) = \
207  ( \
208  _TN_BFA_FIELD_DEF(reg_name, field_name, MASK) \
209  & \
210  ((v) << _TN_BFA_FIELD_DEF(reg_name, field_name, POSITION)) \
211  ); \
212  }), 0 \
213  \
214  :({ /* TN_BFA_RD */ \
215  _TN_BFA_STRUCT_VAL(reg_name).field_name; \
216  }))))))); \
217  })
218 
219 
220 
221 /**
222  * Macro for atomic access to the structure bit field specified as a range.
223  *
224  * @param comm
225  * command to execute:
226  * - `#TN_BFA_WR` - write bit field
227  * - `#TN_BFA_RD` - read bit field
228  * - `#TN_BFA_SET` - set bits by mask
229  * - `#TN_BFA_CLR` - clear bits by mask
230  * - `#TN_BFA_INV` - invert bits by mask
231  *
232  * @param reg_name
233  * variable name (`PORTA`, `CMCON`, ...). Variable should be in the near
234  * memory (first 8 KB)
235  *
236  * @param lower
237  * number of lowest affected bit of the field
238  *
239  * @param upper
240  * number of highest affected bit of the field
241  *
242  * @param ...
243  * used if only `comm != #TN_BFA_RD`. Meaning depends on the `comm`,
244  * see comments for specific command: `#TN_BFA_WR`, etc.
245  *
246  *
247  * Usage examples:
248  *
249  * \code{.c}
250  *
251  * int a = 0x02;
252  *
253  * //-- Write constant 0xaa to the least significant byte of the TRISB
254  * // register:
255  * TN_BFAR(TN_BFA_WR, TRISB, 0, 7, 0xaa);
256  *
257  * //-- Invert least significant nibble of the most significant byte
258  * // in the register TRISB:
259  * TN_BFAR(TN_BFA_INV, TRISB, 8, 15, 0x0f);
260  *
261  * //-- Get 5 least significant bits from the register TRISB and store
262  * // result to the variable a
263  * a = TN_BFAR(TN_BFA_RD, TRISB, 0, 4);
264  *
265  * \endcode
266  *
267  */
268 #define TN_BFAR(comm, reg_name, lower, upper, ...) \
269  ({ \
270  unsigned int mask, maskl, masku; \
271  maskl = (1 << (lower)); \
272  masku = (1 << (upper)); \
273  mask = ((maskl-1) ^ (masku-1)) | maskl | masku; \
274  \
275  ((comm) == TN_BFA_WR) \
276  ?({ \
277  _TN_BFA_COMM_GET(comm) v = __VA_ARGS__+0; \
278  if ((lower) == (upper)) { \
279  if (v & 1) { \
280  _TN_BFA_REG_DEF(reg_name, SET) = mask; \
281  } else { \
282  _TN_BFA_REG_DEF(reg_name, CLR) = mask; \
283  } \
284  } else { \
285  _TN_BFA_REG_DEF(reg_name, INV) = \
286  mask \
287  & \
288  (((v) << _TN_BFA_MIN((lower), (upper))) ^ reg_name); \
289  } \
290  }), 0 \
291  \
292  :(((comm) == TN_BFA_INV) \
293  ?({ \
294  _TN_BFA_COMM_GET(comm) v = __VA_ARGS__+0; \
295  _TN_BFA_REG_DEF(reg_name, INV) = \
296  mask & ((v) << _TN_BFA_MIN((lower), (upper))); \
297  }), 0 \
298  \
299  :((((comm) == TN_BFA_SET) \
300  ?({ \
301  _TN_BFA_COMM_GET(comm) v = __VA_ARGS__+0; \
302  _TN_BFA_REG_DEF(reg_name, SET) = \
303  mask & ((v) << _TN_BFA_MIN((lower), (upper))); \
304  }), 0 \
305  \
306  :(((((comm) == TN_BFA_CLR) \
307  ?({ \
308  _TN_BFA_COMM_GET(comm) v = __VA_ARGS__+0; \
309  _TN_BFA_REG_DEF(reg_name, CLR) = \
310  mask & ((v) << _TN_BFA_MIN((lower), (upper))); \
311  }), 0 \
312  \
313  :({ /* TN_BFA_RD */ \
314  ((reg_name) & mask) >> _TN_BFA_MIN((lower), (upper)); \
315  }))))))); \
316  })
317 
318 
319 
320 //-- internal kernel macros {{{
321 #ifndef DOXYGEN_SHOULD_SKIP_THIS
322 
323 #define _TN_BFA_COMM_ERR(a) _TN_BFA_COMMAND_ERROR_##a
324 #define _TN_BFA_COMM_GET(a) _TN_BFA_COMM_ERR(a)
325 
326 typedef unsigned int _TN_BFA_COMM_GET(TN_BFA_SET);
327 typedef unsigned int _TN_BFA_COMM_GET(TN_BFA_CLR);
328 typedef unsigned int _TN_BFA_COMM_GET(TN_BFA_INV);
329 
330 typedef unsigned int _TN_BFA_COMM_GET(TN_BFA_WR);
331 typedef unsigned int _TN_BFA_COMM_GET(TN_BFA_RD);
332 
333 #define _TN_BFA_STRUCT_VAL(a) a##bits
334 #define _TN_BFA_FIELD_DEF(reg_name, field_name, def) \
335  _##reg_name##_##field_name##_##def
336 #define _TN_BFA_REG_DEF(reg_name, def) reg_name##def
337 #define _TN_BFA_MIN(a, b) ((a) < (b) ? (a) : (b))
338 
339 
340 #endif
341 // }}}
342 
343 
344 #ifdef __cplusplus
345 } /* extern "C" */
346 #endif
347 
348 #endif // _TN_ARCH_PIC24_BFA_H
349 
#define TN_BFA_SET
Command for TN_BFA() macro: Set bits in the bit field by mask; ... macro param should be set to the b...
#define TN_BFA_INV
Command for TN_BFA() macro: Invert bits in the bit field by mask; ... macro param should be set to th...
#define TN_BFA_RD
Command for TN_BFA() macro: Read bit field; ... macro param ignored.
#define TN_BFA_CLR
Command for TN_BFA() macro: Clear bits in the bit field by mask; ... macro param should be set to the...
#define TN_BFA_WR
Command for TN_BFA() macro: Write bit field; ... macro param should be set to the value to write...