AVR-LibC  2.3.0
Standard C library for AVR-GCC
 

AVR-LibC Manual

AVR-LibC Sources

Main Page

User Manual

Lib­rary Refe­rence

FAQ

Exam­ple Pro­jects

Index

Loading...
Searching...
No Matches
interrupt.h
Go to the documentation of this file.
1/* Copyright (c) 2002,2005,2007 Marek Michalkiewicz
2 Copyright (c) 2007, Dean Camera
3
4 All rights reserved.
5
6 Redistribution and use in source and binary forms, with or without
7 modification, are permitted provided that the following conditions are met:
8
9 * Redistributions of source code must retain the above copyright
10 notice, this list of conditions and the following disclaimer.
11
12 * Redistributions in binary form must reproduce the above copyright
13 notice, this list of conditions and the following disclaimer in
14 the documentation and/or other materials provided with the
15 distribution.
16
17 * Neither the name of the copyright holders nor the names of
18 contributors may be used to endorse or promote products derived
19 from this software without specific prior written permission.
20
21 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
22 AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
25 LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
26 CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
27 SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
28 INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
29 CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
30 ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
31 POSSIBILITY OF SUCH DAMAGE. */
32
33#ifndef _AVR_INTERRUPT_H_
34#define _AVR_INTERRUPT_H_
35
36#include <avr/io.h>
37
38#if !defined(__DOXYGEN__) && !defined(__STRINGIFY)
39/* Auxiliary macro for ISR_ALIAS(). */
40#define __STRINGIFY(x) #x
41#endif /* !defined(__DOXYGEN__) */
42
43/** \file */
44/**@{*/
45
46
47/** \name Global manipulation of the interrupt flag
48
49 The global interrupt flag is maintained in the I bit of the status
50 register (SREG).
51
52 Handling interrupts frequently requires attention regarding atomic
53 access to objects that could be altered by code running within an
54 interrupt context, see <util/atomic.h>.
55
56 Frequently, interrupts are being disabled for periods of time in
57 order to perform certain operations without being disturbed; see
58 \ref optim_code_reorder for things to be taken into account with
59 respect to compiler optimizations.
60*/
61
62/** \def sei()
63 \ingroup avr_interrupts
64
65 Enables interrupts by setting the global interrupt mask. This function
66 actually compiles into a single line of assembly, so there is no function
67 call overhead. However, the macro also implies a <i>memory barrier</i>
68 which can cause additional loss of optimization.
69
70 In order to implement atomic access to multi-byte objects,
71 consider using the macros from <util/atomic.h>, rather than
72 implementing them manually with cli() and sei().
73*/
74#ifdef __DOXYGEN__
75# define sei() __asm__ __volatile__ ("sei" ::: "memory")
76#else
77# define sei() __asm__ __volatile__ ("sei ; [[len=1]]" ::: "memory")
78#endif
79
80/** \def cli()
81 \ingroup avr_interrupts
82
83 Disables all interrupts by clearing the global interrupt mask. This function
84 actually compiles into a single line of assembly, so there is no function
85 call overhead. However, the macro also implies a <i>memory barrier</i>
86 which can cause additional loss of optimization.
87
88 In order to implement atomic access to multi-byte objects,
89 consider using the macros from <util/atomic.h>, rather than
90 implementing them manually with cli() and sei().
91*/
92#ifdef __DOXYGEN__
93# define cli() __asm__ __volatile__ ("cli" ::: "memory")
94#else
95# define cli() __asm__ __volatile__ ("cli ; [[len=1]]" ::: "memory")
96#endif
97
98
99/** \name Macros for writing interrupt handler functions */
100
101
102#if defined(__DOXYGEN__)
103/** \def ISR(vector [, attributes])
104 \ingroup avr_interrupts
105
106 Introduces an interrupt handler function (interrupt service
107 routine) that runs with the \c SREG.I flag unchanged
108 by default with no attributes specified.
109 (On most devices this means that global interrupts are disabled
110 upon servicing the IRQ.)
111
112 The \c attributes are optional and alter the behaviour and resultant
113 generated code of the interrupt routine. Multiple attributes may
114 be used for a single function, with a space separating each
115 attribute.
116
117 Valid attributes are #ISR_BLOCK, #ISR_NOBLOCK, #ISR_NAKED,
118 #ISR_FLATTEN, #ISR_NOICF, #ISR_NOGCCISR and ISR_ALIASOF(vect).
119
120 \c vector must be one of the
121 \ref avr_mcu_signames "interrupt vector names" that are
122 valid for the particular MCU type.
123
124 See also the #ISR_N macro for an alternative way to introduce an ISR.
125*/
126# define ISR(vector, [attributes])
127#else /* real code */
128
129#if defined (__clang__)
130# define __INTR_ATTRS __used__
131#elif (__GNUC__ == 4 && __GNUC_MINOR__ >= 1) || (__GNUC__ > 4)
132# define __INTR_ATTRS __used__, __externally_visible__
133#else /* GCC < 4.1 */
134# define __INTR_ATTRS __used__
135#endif
136
137#ifdef __cplusplus
138# define ISR(vector, ...) \
139 extern "C" void vector (void) __attribute__ ((__signal__,__INTR_ATTRS)) __VA_ARGS__; \
140 void vector (void)
141#else
142# define ISR(vector, ...) \
143 void vector (void) __attribute__ ((__signal__,__INTR_ATTRS)) __VA_ARGS__; \
144 void vector (void)
145#endif
146
147#endif /* DOXYGEN */
148
149#if defined(__DOXYGEN__)
150/** \def ISR_N(vector_num [, attributes])
151 \ingroup avr_interrupts
152
153 Introduces an interrupt handler function (interrupt service
154 routine) that runs with the \c SREG.I flag unchanged
155 by default with no attributes specified.
156 (On most devices this means that global interrupts are disabled
157 upon servicing the IRQ.)
158
159 \c vector_num must be a positive interrupt vector number that is
160 valid for the particular MCU type. For available vector numbers, see
161 for example the \ref avr_mcu_signames "MCU &rarr; Vector Names" table.
162
163 Contrary to the #ISR macro, #ISR_N does not provide a declarator for
164 the ISR. #ISR_N may be specified more than once, which can be used
165 to define aliases. For example, the following definition provides
166 an ISR for IRQ numbers 3 and 4 on an ATmega328:
167\code
168 ISR_N (PCINT0_vect_num)
169 ISR_N (PCINT1_vect_num)
170 static void my_isr_handler (void)
171 {
172 // Code
173 }
174\endcode
175 The \c attributes are optional and alter the behaviour and resultant
176 generated code of the interrupt routine. Multiple attributes may
177 be used for a single function, with a space separating each
178 attribute.
179
180 Valid attributes are #ISR_BLOCK, #ISR_NOBLOCK, #ISR_NAKED,
181 #ISR_FLATTEN, #ISR_NOICF and #ISR_NOGCCISR.
182
183\since AVR-LibC v2.3, <a href="https://gcc.gnu.org/gcc-15/changes.html#avr">GCC v15</a>
184*/
185# define ISR_N(vector_num, [attributes])
186#else /* real code */
187
188#if defined __HAVE_SIGNAL_N__
189/* Notice that "used" is implicit since v15, and that there is no requirement
190 that the handler function is externally visible. */
191#define ISR_N(N, ...) \
192 __attribute__((__signal__(N))) __VA_ARGS__
193#else /* HAVE_SIGNAL_N */
194/* When GCC does not support "signal(n)", which is the case up to v14,
195 then try to emit a helpful error message. */
196#define __ISR_N_error2(L) \
197 __attribute__((__used__,__error__( \
198 "ISR_N not supported by this version of the compiler"))) \
199 int AVR_LibC_show_error##L (int x) \
200 { \
201 __asm (".error \"ISR_N not supported by this version of the compiler\"");\
202 return x ? 1 : x * AVR_LibC_show_error##L (x - 1); \
203 }
204#define __ISR_N_error1(L) __ISR_N_error2(L)
205#define ISR_N(...) __ISR_N_error1(__LINE__)
206#endif /* HAVE_SIGNAL_N */
207#endif /* DOXYGEN ISR_N */
208
209#if defined(__DOXYGEN__)
210/** \def SIGNAL(vector)
211 \ingroup avr_interrupts
212
213 Introduces an interrupt handler function that runs with global interrupts
214 initially disabled.
215
216 This is the same as the ISR macro without optional attributes.
217 \deprecated Do not use SIGNAL() in new code. Use ISR() or ISR_N() instead.
218*/
219# define SIGNAL(vector)
220#else /* real code */
221
222#ifdef __cplusplus
223# define SIGNAL(vector) \
224 extern "C" void vector(void) __attribute__ ((__signal__, __INTR_ATTRS)); \
225 void vector (void)
226#else
227# define SIGNAL(vector) \
228 void vector (void) __attribute__ ((__signal__, __INTR_ATTRS)); \
229 void vector (void)
230#endif
231
232#endif /* DOXYGEN */
233
234#if defined(__DOXYGEN__)
235/** \def EMPTY_INTERRUPT(vector)
236 \ingroup avr_interrupts
237
238 Defines an empty interrupt handler function. This will not generate
239 any prolog or epilog code and will only return from the #ISR. Do not
240 define a function body as this will define it for you.
241 Example:
242 \code EMPTY_INTERRUPT(ADC_vect);\endcode */
243# define EMPTY_INTERRUPT(vector)
244#else /* real code */
245
246#ifdef __cplusplus
247# define EMPTY_INTERRUPT(vector) \
248 extern "C" void vector(void) __attribute__ ((__signal__,__naked__,__INTR_ATTRS)); \
249 void vector (void) { __asm__ __volatile__ ("reti" ::: "memory"); }
250#else
251# define EMPTY_INTERRUPT(vector) \
252 void vector (void) __attribute__ ((__signal__,__naked__,__INTR_ATTRS)); \
253 void vector (void) { __asm__ __volatile__ ("reti" ::: "memory"); }
254#endif
255
256#endif /* DOXYGEN */
257
258#if defined(__DOXYGEN__)
259/** \def ISR_ALIAS(vector, target_vector)
260 \ingroup avr_interrupts
261
262 Aliases a given vector to another one in the same manner as the
263 ISR_ALIASOF attribute for the ISR() macro.
264
265 \note This macro creates a trampoline function for the aliased
266 macro. This will result in a two cycle penalty for the aliased
267 vector compared to the ISR the vector is aliased to, due to the
268 JMP/RJMP opcode used.
269
270 \deprecated
271 For new code, the use of ISR(..., ISR_ALIASOF(...)) or #ISR_N is
272 recommended. Notice that using #ISR_N does \e not impose a
273 JMP/RJMP overhead.
274
275 Example:
276 \code
277 ISR (INT0_vect)
278 {
279 PORTB = 42;
280 }
281
282 ISR_ALIAS (INT1_vect, INT0_vect);
283
284 // Alternative using ISR_N
285
286 ISR_N (INT0_vect_num)
287 ISR_N (INT1_vect_num)
288 static void my_int01_handler (void)
289 {
290 PORTB = 42;
291 }
292
293 // or
294
295 ISR (INT0_vect,
296 [attributes]
297 ISR_N (INT1_vect_num))
298 {
299 PORTB = 42;
300 }
301 \endcode
302*/
303# define ISR_ALIAS(vector, target_vector)
304#else /* real code */
305
306#ifdef __cplusplus
307# define ISR_ALIAS(vector, tgt) extern "C" void vector (void) \
308 __attribute__((__signal__, __naked__, __INTR_ATTRS)); \
309 void vector (void) { __asm__ __volatile__ ("%~jmp " __STRINGIFY(tgt) ::); }
310#else /* !__cplusplus */
311# define ISR_ALIAS(vector, tgt) void vector (void) \
312 __attribute__((__signal__, __naked__, __INTR_ATTRS)); \
313 void vector (void) { __asm__ __volatile__ ("%~jmp " __STRINGIFY(tgt) ::); }
314#endif /* __cplusplus */
315
316#endif /* DOXYGEN */
317
318/** \def reti()
319 \ingroup avr_interrupts
320
321 Returns from an interrupt routine, enabling global interrupts. This should
322 be the last command executed before leaving an #ISR defined with the
323 #ISR_NAKED attribute.
324
325 This macro actually compiles into a single line of assembly, so there is
326 no function call overhead.
327
328 \note According to the GCC documentation, the only code supported in
329 naked functions is \ref inline_asm "inline assembly".
330*/
331# define reti() __asm__ __volatile__ ("reti" ::: "memory")
332
333#if defined(__DOXYGEN__)
334/** \def BADISR_vect
335 \ingroup avr_interrupts
336
337 \code #include <avr/interrupt.h> \endcode
338
339 This is a vector which is aliased to \c __vector_default, the vector
340 executed when an IRQ fires with no accompanying ISR handler. This
341 may be used along with the ISR() macro to create a catch-all for
342 undefined but used ISRs for debugging purposes. It cannot be used
343 with #ISR_N since there is no associated interrupt number.
344
345 Using option
346 <a href="https://gcc.gnu.org/onlinedocs/gcc/AVR-Options.html#index-mprune-vectab">-mprune-vectab</a>
347 to remove the tail end of unused vectors from the vector table
348 makes it harder to find such rogue IRQs. */
349# define BADISR_vect
350#else /* !DOXYGEN */
351# define BADISR_vect __vector_default
352#endif /* DOXYGEN */
353
354/** \name ISR attributes */
355
356#if defined(__DOXYGEN__)
357/** \def ISR_BLOCK
358 \ingroup avr_interrupts
359
360 Identical to an ISR with no attributes specified. Global
361 interrupts are initially disabled by the AVR hardware when
362 entering the ISR, without the compiler modifying this state.
363
364 Use this attribute in the \c attributes parameter of the #ISR
365 and #ISR_N macros.
366*/
367# define ISR_BLOCK
368
369/** \def ISR_NOBLOCK
370 \ingroup avr_interrupts
371
372 ISR runs with global interrupts initially enabled. The interrupt
373 enable flag is activated by the compiler as early as possible
374 within the ISR to ensure minimal processing delay for nested
375 interrupts.
376
377 This may be used to create nested ISRs, however care should be
378 taken to avoid stack overflows, or to avoid infinitely entering
379 the ISR for those cases where the AVR hardware does not clear the
380 respective interrupt flag before entering the ISR.
381
382 Use this attribute in the \c attributes parameter of the #ISR and
383 #ISR_N macros.
384*/
385# define ISR_NOBLOCK
386
387/** \def ISR_NAKED
388 \ingroup avr_interrupts
389
390 ISR is created with no prologue or epilogue code. The user code is
391 responsible for preservation of the machine state including the
392 SREG register, as well as placing a reti() at the end of the
393 interrupt routine.
394
395 Use this attribute in the \c attributes parameter of the #ISR and
396 #ISR_N macros.
397
398 \note According to GCC documentation, the only code supported in
399 naked functions is \ref inline_asm "inline assembly".
400*/
401# define ISR_NAKED
402
403/** \def ISR_FLATTEN
404 \ingroup avr_interrupts
405
406 The compiler will try to inline all called function into the ISR.
407
408 Use this attribute in the \c attributes parameter of the #ISR and
409 #ISR_N macros.
410*/
411# define ISR_FLATTEN
412
413/** \def ISR_NOICF
414 \ingroup avr_interrupts
415
416 Avoid identical-code-folding optimization against this ISR.
417 This has an effect with GCC 5 and newer only.
418
419 Use this attribute in the \c attributes parameter of the #ISR and
420 #ISR_N macros.
421*/
422# define ISR_NOICF
423
424/** \def ISR_NOGCCISR
425 \ingroup avr_interrupts
426
427 Do not generate
428 <a href="https://sourceware.org/binutils/docs/as/AVR-Pseudo-Instructions.html">\c __gcc_isr pseudo instructions</a>
429 for this ISR.
430 This has an effect with
431 <a href="https://gcc.gnu.org/gcc-8/changes.html#avr">GCC 8</a>
432 and newer only.
433
434 Use this attribute in the \c attributes parameter of the #ISR and
435 #ISR_N macros.
436*/
437# define ISR_NOGCCISR
438
439/** \def ISR_ALIASOF(target_vector)
440 \ingroup avr_interrupts
441
442 The ISR is linked to another ISR, specified by the vect parameter.
443
444 Use this attribute in the \c attributes parameter of the #ISR macro.
445 Example:
446 \code
447 ISR (INT0_vect)
448 {
449 PORTB = 42;
450 }
451
452 ISR (INT1_vect, ISR_ALIASOF (INT0_vect));
453 \endcode
454
455 Notice that the #ISR_ALIASOF macro implements its own IRQ handler that
456 jumps to the aliased ISR, which means there is a run-time overhead of
457 a JMP/RJMP instruction. For an alternative without overhead, see
458 the #ISR_N macro.
459*/
460# define ISR_ALIASOF(target_vector)
461#else /* !DOXYGEN */
462# define ISR_BLOCK /* empty */
463/* FIXME: This won't work with older versions of avr-gcc as ISR_NOBLOCK
464 will use `signal' and `interrupt' at the same time. */
465# ifdef __HAVE_SIGNAL_N__
466/* Use "noblock" if available. This works rather like a flag that can be
467 combined with "signal(n)" without imposing a specific function name,
468 like "interrupt" would do. */
469# define ISR_NOBLOCK __attribute__((__noblock__))
470# else
471# define ISR_NOBLOCK __attribute__((__interrupt__))
472# endif /* Have signal(n) and noblock */
473
474# define ISR_NAKED __attribute__((__naked__))
475
476#if (__GNUC__ == 4 && __GNUC_MINOR__ >= 6) || (__GNUC__ >= 5)
477# define ISR_FLATTEN __attribute__((__flatten__))
478#else
479# define ISR_FLATTEN /* empty */
480#endif /* has flatten (GCC 4.6+) */
481
482#if defined (__has_attribute)
483#if __has_attribute (__no_icf__)
484# define ISR_NOICF __attribute__((__no_icf__))
485#else
486# define ISR_NOICF /* empty */
487#endif /* has no_icf */
488
489#if __has_attribute (__no_gccisr__)
490# define ISR_NOGCCISR __attribute__((__no_gccisr__))
491#else
492# define ISR_NOGCCISR /* empty */
493#endif /* has no_gccisr */
494#endif /* has __has_attribute (GCC 5+) */
495
496# define ISR_ALIASOF(v) __attribute__((__alias__(__STRINGIFY(v))))
497#endif /* DOXYGEN */
498
499/**@}*/
500
501#endif