avr-libc  2.0.0
Standard C library for AVR-GCC
 

AVR Libc Home Page

AVRs

AVR Libc Development Pages

Main Page

User Manual

Library Reference

FAQ

Example Projects

Loading...
Searching...
No Matches
delay.h
Go to the documentation of this file.
1/* Copyright (c) 2002, Marek Michalkiewicz
2 Copyright (c) 2004,2005,2007 Joerg Wunsch
3 Copyright (c) 2007 Florin-Viorel Petrov
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/* $Id$ */
34
35#ifndef _UTIL_DELAY_H_
36#define _UTIL_DELAY_H_ 1
37
38#ifndef __DOXYGEN__
39# ifndef __HAS_DELAY_CYCLES
40# define __HAS_DELAY_CYCLES 1
41# endif
42#endif /* __DOXYGEN__ */
43
44#include <inttypes.h>
45#include <util/delay_basic.h>
46#include <math.h>
47
48/** \file */
49/** \defgroup util_delay <util/delay.h>: Convenience functions for busy-wait delay loops
50 \code
51 #define F_CPU 1000000UL // 1 MHz
52 //#define F_CPU 14.7456E6
53 #include <util/delay.h>
54 \endcode
55
56 \note As an alternative method, it is possible to pass the
57 F_CPU macro down to the compiler from the Makefile.
58 Obviously, in that case, no \c \#define statement should be
59 used.
60
61 The functions in this header file are wrappers around the basic
62 busy-wait functions from <util/delay_basic.h>. They are meant as
63 convenience functions where actual time values can be specified
64 rather than a number of cycles to wait for. The idea behind is
65 that compile-time constant expressions will be eliminated by
66 compiler optimization so floating-point expressions can be used
67 to calculate the number of delay cycles needed based on the CPU
68 frequency passed by the macro F_CPU.
69
70 \note In order for these functions to work as intended, compiler
71 optimizations <em>must</em> be enabled, and the delay time
72 <em>must</em> be an expression that is a known constant at
73 compile-time. If these requirements are not met, the resulting
74 delay will be much longer (and basically unpredictable), and
75 applications that otherwise do not use floating-point calculations
76 will experience severe code bloat by the floating-point library
77 routines linked into the application.
78
79 The functions available allow the specification of microsecond, and
80 millisecond delays directly, using the application-supplied macro
81 F_CPU as the CPU clock frequency (in Hertz).
82
83*/
84
85#if !defined(__DOXYGEN__)
86static __inline__ void _delay_us(double __us) __attribute__((__always_inline__));
87static __inline__ void _delay_ms(double __ms) __attribute__((__always_inline__));
88#endif
89
90#ifndef F_CPU
91/* prevent compiler error by supplying a default */
92# warning "F_CPU not defined for <util/delay.h>"
93/** \ingroup util_delay
94 \def F_CPU
95 \brief CPU frequency in Hz
96
97 The macro F_CPU specifies the CPU frequency to be considered by
98 the delay macros. This macro is normally supplied by the
99 environment (e.g. from within a project header, or the project's
100 Makefile). The value 1 MHz here is only provided as a "vanilla"
101 fallback if no such user-provided definition could be found.
102
103 In terms of the delay functions, the CPU frequency can be given as
104 a floating-point constant (e.g. 3.6864E6 for 3.6864 MHz).
105 However, the macros in <util/setbaud.h> require it to be an
106 integer value.
107 */
108# define F_CPU 1000000UL
109#endif
110
111#ifndef __OPTIMIZE__
112# warning "Compiler optimizations disabled; functions from <util/delay.h> won't work as designed"
113#endif
114
115#if __HAS_DELAY_CYCLES && defined(__OPTIMIZE__) && \
116 !defined(__DELAY_BACKWARD_COMPATIBLE__) && \
117 __STDC_HOSTED__
118# include <math.h>
119#endif
120
121/**
122 \ingroup util_delay
123
124 Perform a delay of \c __ms milliseconds, using _delay_loop_2().
125
126 The macro F_CPU is supposed to be defined to a
127 constant defining the CPU clock frequency (in Hertz).
128
129 The maximal possible delay is 262.14 ms / F_CPU in MHz.
130
131 When the user request delay which exceed the maximum possible one,
132 _delay_ms() provides a decreased resolution functionality. In this
133 mode _delay_ms() will work with a resolution of 1/10 ms, providing
134 delays up to 6.5535 seconds (independent from CPU frequency). The
135 user will not be informed about decreased resolution.
136
137 If the avr-gcc toolchain has __builtin_avr_delay_cycles()
138 support, maximal possible delay is 4294967.295 ms/ F_CPU in MHz. For
139 values greater than the maximal possible delay, overflows results in
140 no delay i.e., 0ms.
141
142 Conversion of \c __ms into clock cycles may not always result in
143 integer. By default, the clock cycles rounded up to next
144 integer. This ensures that the user gets at least \c __ms
145 microseconds of delay.
146
147 Alternatively, by defining the macro \c __DELAY_ROUND_DOWN__, or
148 \c __DELAY_ROUND_CLOSEST__, before including this header file, the
149 algorithm can be made to round down, or round to closest integer,
150 respectively.
151
152 \note
153
154 The implementation of _delay_ms() based on
155 __builtin_avr_delay_cycles() is not backward compatible with older
156 implementations. In order to get functionality backward compatible
157 with previous versions, the macro \c "__DELAY_BACKWARD_COMPATIBLE__"
158 must be defined before including this header file. Also, the
159 backward compatible algorithm will be chosen if the code is
160 compiled in a <em>freestanding environment</em> (GCC option
161 \c -ffreestanding), as the math functions required for rounding are
162 not available to the compiler then.
163
164 */
165void
166_delay_ms(double __ms)
167{
168 double __tmp ;
169#if __HAS_DELAY_CYCLES && defined(__OPTIMIZE__) && \
170 !defined(__DELAY_BACKWARD_COMPATIBLE__) && \
171 __STDC_HOSTED__
172 uint32_t __ticks_dc;
173 extern void __builtin_avr_delay_cycles(unsigned long);
174 __tmp = ((F_CPU) / 1e3) * __ms;
175
176 #if defined(__DELAY_ROUND_DOWN__)
177 __ticks_dc = (uint32_t)fabs(__tmp);
178
179 #elif defined(__DELAY_ROUND_CLOSEST__)
180 __ticks_dc = (uint32_t)(fabs(__tmp)+0.5);
181
182 #else
183 //round up by default
184 __ticks_dc = (uint32_t)(ceil(fabs(__tmp)));
185 #endif
186
187 __builtin_avr_delay_cycles(__ticks_dc);
188
189#else
190 uint16_t __ticks;
191 __tmp = ((F_CPU) / 4e3) * __ms;
192 if (__tmp < 1.0)
193 __ticks = 1;
194 else if (__tmp > 65535)
195 {
196 // __ticks = requested delay in 1/10 ms
197 __ticks = (uint16_t) (__ms * 10.0);
198 while(__ticks)
199 {
200 // wait 1/10 ms
201 _delay_loop_2(((F_CPU) / 4e3) / 10);
202 __ticks --;
203 }
204 return;
205 }
206 else
207 __ticks = (uint16_t)__tmp;
208 _delay_loop_2(__ticks);
209#endif
210}
211
212/**
213 \ingroup util_delay
214
215 Perform a delay of \c __us microseconds, using _delay_loop_1().
216
217 The macro F_CPU is supposed to be defined to a
218 constant defining the CPU clock frequency (in Hertz).
219
220 The maximal possible delay is 768 us / F_CPU in MHz.
221
222 If the user requests a delay greater than the maximal possible one,
223 _delay_us() will automatically call _delay_ms() instead. The user
224 will not be informed about this case.
225
226 If the avr-gcc toolchain has __builtin_avr_delay_cycles()
227 support, maximal possible delay is 4294967.295 us/ F_CPU in MHz. For
228 values greater than the maximal possible delay, overflow results in
229 no delay i.e., 0us.
230
231 Conversion of \c __us into clock cycles may not always result in
232 integer. By default, the clock cycles rounded up to next
233 integer. This ensures that the user gets at least \c __us
234 microseconds of delay.
235
236 Alternatively, by defining the macro \c __DELAY_ROUND_DOWN__, or
237 \c __DELAY_ROUND_CLOSEST__, before including this header file, the
238 algorithm can be made to round down, or round to closest integer,
239 respectively.
240
241 \note
242
243 The implementation of _delay_ms() based on
244 __builtin_avr_delay_cycles() is not backward compatible with older
245 implementations. In order to get functionality backward compatible
246 with previous versions, the macro \c __DELAY_BACKWARD_COMPATIBLE__
247 must be defined before including this header file. Also, the
248 backward compatible algorithm will be chosen if the code is
249 compiled in a <em>freestanding environment</em> (GCC option
250 \c -ffreestanding), as the math functions required for rounding are
251 not available to the compiler then.
252
253 */
254void
255_delay_us(double __us)
256{
257 double __tmp ;
258#if __HAS_DELAY_CYCLES && defined(__OPTIMIZE__) && \
259 !defined(__DELAY_BACKWARD_COMPATIBLE__) && \
260 __STDC_HOSTED__
261 uint32_t __ticks_dc;
262 extern void __builtin_avr_delay_cycles(unsigned long);
263 __tmp = ((F_CPU) / 1e6) * __us;
264
265 #if defined(__DELAY_ROUND_DOWN__)
266 __ticks_dc = (uint32_t)fabs(__tmp);
267
268 #elif defined(__DELAY_ROUND_CLOSEST__)
269 __ticks_dc = (uint32_t)(fabs(__tmp)+0.5);
270
271 #else
272 //round up by default
273 __ticks_dc = (uint32_t)(ceil(fabs(__tmp)));
274 #endif
275
276 __builtin_avr_delay_cycles(__ticks_dc);
277
278#else
279 uint8_t __ticks;
280 double __tmp2 ;
281 __tmp = ((F_CPU) / 3e6) * __us;
282 __tmp2 = ((F_CPU) / 4e6) * __us;
283 if (__tmp < 1.0)
284 __ticks = 1;
285 else if (__tmp2 > 65535)
286 {
287 _delay_ms(__us / 1000.0);
288 }
289 else if (__tmp > 255)
290 {
291 uint16_t __ticks=(uint16_t)__tmp2;
292 _delay_loop_2(__ticks);
293 return;
294 }
295 else
296 __ticks = (uint8_t)__tmp;
297 _delay_loop_1(__ticks);
298#endif
299}
300
301
302#endif /* _UTIL_DELAY_H_ */
unsigned int uint16_t
Definition stdint.h:93
unsigned long int uint32_t
Definition stdint.h:103
unsigned char uint8_t
Definition stdint.h:83
void _delay_loop_1(uint8_t __count)
Definition delay_basic.h:81
void _delay_loop_2(uint16_t __count)
Definition delay_basic.h:103
#define F_CPU
CPU frequency in Hz.
Definition delay.h:108
void _delay_us(double __us)
Definition delay.h:255
void _delay_ms(double __ms)
Definition delay.h:166
double fabs(double __x)
double ceil(double __x)