avr-libc  2.1.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

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: delay_8h_source.html,v 1.1.1.7 2022/01/29 09:21:56 joerg_wunsch Exp $ */
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__)
86 static __inline__ void _delay_us(double __us) __attribute__((__always_inline__));
87 static __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  */
165 void
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  */
254 void
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  return;
289  }
290  else if (__tmp > 255)
291  {
292  uint16_t __ticks=(uint16_t)__tmp2;
293  _delay_loop_2(__ticks);
294  return;
295  }
296  else
297  __ticks = (uint8_t)__tmp;
298  _delay_loop_1(__ticks);
299 #endif
300 }
301 
302 
303 #endif /* _UTIL_DELAY_H_ */
void _delay_loop_2(uint16_t __count)
Definition: delay_basic.h:103
static __inline void __attribute__((__always_inline__)) __power_all_enable()
Definition: power.h:1188
unsigned char uint8_t
Definition: stdint.h:83
void _delay_ms(double __ms)
Definition: delay.h:166
unsigned long int uint32_t
Definition: stdint.h:103
void _delay_us(double __us)
Definition: delay.h:255
#define F_CPU
CPU frequency in Hz.
Definition: delay.h:108
void _delay_loop_1(uint8_t __count)
Definition: delay_basic.h:81
unsigned int uint16_t
Definition: stdint.h:93
double ceil(double __x) __ASM_ALIAS(ceilf)