AVR Libc Home Page
AVR Libc Development Pages
Main Page
User Manual
Library Reference
FAQ
Alphabetical Index
Example Projects
src
avr-libc
include
util
atomic.h
Go to the documentation of this file.
1
/* Copyright (c) 2007 Dean Camera
2
All rights reserved.
3
4
Redistribution and use in source and binary forms, with or without
5
modification, are permitted provided that the following conditions are met:
6
7
* Redistributions of source code must retain the above copyright
8
notice, this list of conditions and the following disclaimer.
9
10
* Redistributions in binary form must reproduce the above copyright
11
notice, this list of conditions and the following disclaimer in
12
the documentation and/or other materials provided with the
13
distribution.
14
15
* Neither the name of the copyright holders nor the names of
16
contributors may be used to endorse or promote products derived
17
from this software without specific prior written permission.
18
19
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
20
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
23
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29
POSSIBILITY OF SUCH DAMAGE.
30
*/
31
32
/* $Id: atomic.h 2158 2010-06-10 15:48:28Z joerg_wunsch $ */
33
34
#ifndef _UTIL_ATOMIC_H_
35
#define _UTIL_ATOMIC_H_ 1
36
37
#include <
avr/io.h
>
38
#include <
avr/interrupt.h
>
39
40
#if !defined(__DOXYGEN__)
41
/* Internal helper functions. */
42
static
__inline__
uint8_t
__iSeiRetVal(
void
)
43
{
44
sei
();
45
return
1;
46
}
47
48
static
__inline__
uint8_t
__iCliRetVal(
void
)
49
{
50
cli
();
51
return
1;
52
}
53
54
static
__inline__
void
__iSeiParam(
const
uint8_t
*__s)
55
{
56
sei
();
57
__asm__
volatile
(
""
:::
"memory"
);
58
(void)__s;
59
}
60
61
static
__inline__
void
__iCliParam(
const
uint8_t
*__s)
62
{
63
cli
();
64
__asm__
volatile
(
""
:::
"memory"
);
65
(void)__s;
66
}
67
68
static
__inline__
void
__iRestore(
const
uint8_t
*__s)
69
{
70
SREG = *__s;
71
__asm__
volatile
(
""
:::
"memory"
);
72
}
73
#endif
/* !__DOXYGEN__ */
74
75
/** \file */
76
/** \defgroup util_atomic <util/atomic.h> Atomically and Non-Atomically Executed Code Blocks
77
78
\code
79
#include <util/atomic.h>
80
\endcode
81
82
\note The macros in this header file require the ISO/IEC 9899:1999
83
("ISO C99") feature of for loop variables that are declared inside
84
the for loop itself. For that reason, this header file can only
85
be used if the standard level of the compiler (option --std=) is
86
set to either \c c99 or \c gnu99.
87
88
The macros in this header file deal with code blocks that are
89
guaranteed to be excuted Atomically or Non-Atmomically. The term
90
"Atomic" in this context refers to the unability of the respective
91
code to be interrupted.
92
93
These macros operate via automatic manipulation of the Global
94
Interrupt Status (I) bit of the SREG register. Exit paths from
95
both block types are all managed automatically without the need
96
for special considerations, i. e. the interrupt status will be
97
restored to the same value it has been when entering the
98
respective block.
99
100
A typical example that requires atomic access is a 16 (or more)
101
bit variable that is shared between the main execution path and an
102
ISR. While declaring such a variable as volatile ensures that the
103
compiler will not optimize accesses to it away, it does not
104
guarantee atomic access to it. Assuming the following example:
105
106
\code
107
#include <inttypes.h>
108
#include <avr/interrupt.h>
109
#include <avr/io.h>
110
111
volatile uint16_t ctr;
112
113
ISR(TIMER1_OVF_vect)
114
{
115
ctr--;
116
}
117
118
...
119
int
120
main(void)
121
{
122
...
123
ctr = 0x200;
124
start_timer();
125
while (ctr != 0)
126
// wait
127
;
128
...
129
}
130
\endcode
131
132
There is a chance where the main context will exit its wait loop
133
when the variable \c ctr just reached the value 0xFF. This happens
134
because the compiler cannot natively access a 16-bit variable
135
atomically in an 8-bit CPU. So the variable is for example at
136
0x100, the compiler then tests the low byte for 0, which succeeds.
137
It then proceeds to test the high byte, but that moment the ISR
138
triggers, and the main context is interrupted. The ISR will
139
decrement the variable from 0x100 to 0xFF, and the main context
140
proceeds. It now tests the high byte of the variable which is
141
(now) also 0, so it concludes the variable has reached 0, and
142
terminates the loop.
143
144
Using the macros from this header file, the above code can be
145
rewritten like:
146
147
\code
148
#include <inttypes.h>
149
#include <avr/interrupt.h>
150
#include <avr/io.h>
151
#include <util/atomic.h>
152
153
volatile uint16_t ctr;
154
155
ISR(TIMER1_OVF_vect)
156
{
157
ctr--;
158
}
159
160
...
161
int
162
main(void)
163
{
164
...
165
ctr = 0x200;
166
start_timer();
167
sei();
168
uint16_t ctr_copy;
169
do
170
{
171
ATOMIC_BLOCK(ATOMIC_FORCEON)
172
{
173
ctr_copy = ctr;
174
}
175
}
176
while (ctr_copy != 0);
177
...
178
}
179
\endcode
180
181
This will install the appropriate interrupt protection before
182
accessing variable \c ctr, so it is guaranteed to be consistently
183
tested. If the global interrupt state were uncertain before
184
entering the ATOMIC_BLOCK, it should be executed with the
185
parameter ATOMIC_RESTORESTATE rather than ATOMIC_FORCEON.
186
187
See \ref optim_code_reorder for things to be taken into account
188
with respect to compiler optimizations.
189
*/
190
191
/** \def ATOMIC_BLOCK(type)
192
\ingroup util_atomic
193
194
Creates a block of code that is guaranteed to be executed
195
atomically. Upon entering the block the Global Interrupt Status
196
flag in SREG is disabled, and re-enabled upon exiting the block
197
from any exit path.
198
199
Two possible macro parameters are permitted, ATOMIC_RESTORESTATE
200
and ATOMIC_FORCEON.
201
*/
202
#if defined(__DOXYGEN__)
203
#define ATOMIC_BLOCK(type)
204
#else
205
#define ATOMIC_BLOCK(type) for ( type, __ToDo = __iCliRetVal(); \
206
__ToDo ; __ToDo = 0 )
207
#endif
/* __DOXYGEN__ */
208
209
/** \def NONATOMIC_BLOCK(type)
210
\ingroup util_atomic
211
212
Creates a block of code that is executed non-atomically. Upon
213
entering the block the Global Interrupt Status flag in SREG is
214
enabled, and disabled upon exiting the block from any exit
215
path. This is useful when nested inside ATOMIC_BLOCK sections,
216
allowing for non-atomic execution of small blocks of code while
217
maintaining the atomic access of the other sections of the parent
218
ATOMIC_BLOCK.
219
220
Two possible macro parameters are permitted,
221
NONATOMIC_RESTORESTATE and NONATOMIC_FORCEOFF.
222
*/
223
#if defined(__DOXYGEN__)
224
#define NONATOMIC_BLOCK(type)
225
#else
226
#define NONATOMIC_BLOCK(type) for ( type, __ToDo = __iSeiRetVal(); \
227
__ToDo ; __ToDo = 0 )
228
#endif
/* __DOXYGEN__ */
229
230
/** \def ATOMIC_RESTORESTATE
231
\ingroup util_atomic
232
233
This is a possible parameter for ATOMIC_BLOCK. When used, it will
234
cause the ATOMIC_BLOCK to restore the previous state of the SREG
235
register, saved before the Global Interrupt Status flag bit was
236
disabled. The net effect of this is to make the ATOMIC_BLOCK's
237
contents guaranteed atomic, without changing the state of the
238
Global Interrupt Status flag when execution of the block
239
completes.
240
*/
241
#if defined(__DOXYGEN__)
242
#define ATOMIC_RESTORESTATE
243
#else
244
#define ATOMIC_RESTORESTATE uint8_t sreg_save \
245
__attribute__((__cleanup__(__iRestore))) = SREG
246
#endif
/* __DOXYGEN__ */
247
248
/** \def ATOMIC_FORCEON
249
\ingroup util_atomic
250
251
This is a possible parameter for ATOMIC_BLOCK. When used, it will
252
cause the ATOMIC_BLOCK to force the state of the SREG register on
253
exit, enabling the Global Interrupt Status flag bit. This saves on
254
flash space as the previous value of the SREG register does not
255
need to be saved at the start of the block.
256
257
Care should be taken that ATOMIC_FORCEON is only used when it is
258
known that interrupts are enabled before the block's execution or
259
when the side effects of enabling global interrupts at the block's
260
completion are known and understood.
261
*/
262
#if defined(__DOXYGEN__)
263
#define ATOMIC_FORCEON
264
#else
265
#define ATOMIC_FORCEON uint8_t sreg_save \
266
__attribute__((__cleanup__(__iSeiParam))) = 0
267
#endif
/* __DOXYGEN__ */
268
269
/** \def NONATOMIC_RESTORESTATE
270
\ingroup util_atomic
271
272
This is a possible parameter for NONATOMIC_BLOCK. When used, it
273
will cause the NONATOMIC_BLOCK to restore the previous state of
274
the SREG register, saved before the Global Interrupt Status flag
275
bit was enabled. The net effect of this is to make the
276
NONATOMIC_BLOCK's contents guaranteed non-atomic, without changing
277
the state of the Global Interrupt Status flag when execution of
278
the block completes.
279
*/
280
#if defined(__DOXYGEN__)
281
#define NONATOMIC_RESTORESTATE
282
#else
283
#define NONATOMIC_RESTORESTATE uint8_t sreg_save \
284
__attribute__((__cleanup__(__iRestore))) = SREG
285
#endif
/* __DOXYGEN__ */
286
287
/** \def NONATOMIC_FORCEOFF
288
\ingroup util_atomic
289
290
This is a possible parameter for NONATOMIC_BLOCK. When used, it
291
will cause the NONATOMIC_BLOCK to force the state of the SREG
292
register on exit, disabling the Global Interrupt Status flag
293
bit. This saves on flash space as the previous value of the SREG
294
register does not need to be saved at the start of the block.
295
296
Care should be taken that NONATOMIC_FORCEOFF is only used when it
297
is known that interrupts are disabled before the block's execution
298
or when the side effects of disabling global interrupts at the
299
block's completion are known and understood.
300
*/
301
#if defined(__DOXYGEN__)
302
#define NONATOMIC_FORCEOFF
303
#else
304
#define NONATOMIC_FORCEOFF uint8_t sreg_save \
305
__attribute__((__cleanup__(__iCliParam))) = 0
306
#endif
/* __DOXYGEN__ */
307
308
#endif
Automatically generated by Doxygen 1.8.1.1 on Fri Aug 17 2012.