-
Notifications
You must be signed in to change notification settings - Fork 56
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[patch #6418] Yet another delay routines #754
Comments
Carlos Lamas Following David Brown's suggestion of using __builtin_constant_p() GCC function to test the macro arguments I have uploaded a new version of the headers. The main changes are:
Everything else remains the same. |
Clarence Risher I have pursued alternative methods to improve the accuracy of the delay functions. Your work here is impressive, and my testing indicates that it functions as advertised. I will be using your patch personally, and look forward to it being integrated. |
Timothy Baldwin Rather than generating an error when an integer non-constant is passed the non-exact macros could form a loop around a constant delay.
|
This proposal is quite old, it dates back to 2008 and prior to the introduction of
At least some problems are solved:
|
Wed 13 Feb 2008 11:26:51 PM CET
This code is proposed to replace actual avr-libc delay routines. Current delay routines in <util/basic_delay.h> and <util/delay.h> present several problems:
They require the optimization enabled to avoid floating point libraries code bloating the executable.
The arguments passed must be constant but the compiler does not warn the user when a variable is passed. This can also bloat the code with floating point libraries and delay's accuracy loss.
There is a lot of asymmetry between the functions used for microseconds and for milliseconds: the time is not continuous, the 1/10 millisecond precision is arbitrary (F_CPU value is not considered) and inaccurate, and delays are short for high frequency processors...
Solutions
Problem 1. Can be solved eliminating temporary intermediate variables and letting the compiler to do all the arithmetics. If the variables are not defined the intermediate integer and floating point constant values do not need to be stored, even when optimization level is -O0. To accomplish this it's mandatory a conversion from inline function (the argument is an automatic storage class variable) to macro.
Problem 2. The proposed solution is to check the constant parameter passed against an inline assembler constraint in an empty dummy asm() instruction. This also requires to transform the inline function in a macro. Passing a variable as the argument to the macro generates an error a bit obfuscated.
Problem 3. The compiler can choose the delay with the minimum penalty in size. Frequency and time should be taken as a whole, i.e. the number of CPU cycles that must elapse to obtain the delay. And big sized delay loops can produce accurate delays by increasing the counter word size from 16 bit maximum to 24 bit and 32 bit.
Attached files
The new files <util/delay_basic.h> and <util/delay.h> are downwards compatible with currently existing routines.
Another two delay loop functions have been defined: _delay_loop3() and _delay_loop4() to get 24 bit and 32 bit counter values. The code size of this loops is somewhat big including compiler overhead but they allow really, really long delays.
Additionaly, constant argument versions delay loop macros were defined to reduce the code generated and minimize errors when optimization is disabled.
The core of these header files are two delay macros named _delay_cycles() and _delay_exact_cycles(). They do not depend on F_CPU and as such they are placed in delay_basic.h. They wrap to the shortest loop suitable to obtain a delay in CPU cycles (_delay_cycles() accuracy is +/- 0.5 loop step size and _delay_exact_cycles() is +/- 0.5 CPU cycles). Single instruction sequences without loops are used for very short delays (less than 7 CPU cycles). _delay_cycles_exact() inserts padding instructions after the loops at the expense of increasing code size to obtain the best delay accuracy.
Padding instructions used in the code are NOP (1 word, 1 CPU cycle) and RJMP (1 word, 2 CPU cycles). LPM (1 word, 3 cycles) was discarded due to lack of documentation about the behaviour accessing inexistent Flash addresses and other possible fuses and lock bits issues. Also, LPM is not available in all the AVR devices.
The constraint 'd' was preferred to 'w' in 32 bit data sizes to facilitate to the compiler the allocation of the loop variable, at the expense of increasing the code in one instruction (sbiw could be used instead of subi + sbci). Internal constant loop version macros for optimization enabled use a different approach splitting the big data counters (24 bit and 32 bit) in two parts, with 'w' constraint applied only to the less significant 16 bit of the data. For the remaining data part (8 bit or 16 bit) is up to the compiler (constraint 'r') to decide the registers to be used. Optimization disabled counterparts avoid the compiler overhead previous to the loop (not fixed time) moving the counter precharge to the first loop instructions and the compiler overhead after the loop storing data in the temporary and zero registers (complete for loops 1 and 2, partial for loop 3, nothing for loop 4)
The code philosophy remains the same: despite of the increased code complexity in the header files the compiler performs all the arithmetics and the resulting delay code remains short. The only incompatibility can arise with the imposition of using constant values.
Interface summary <util/delay_basic.h>
static inline void _delay_loop_1(uint8_t __count);
static inline void _delay_loop_2(uint16_t __count);
static inline void _delay_loop_3(uint32_t __count);
static inline void _delay_loop_4(uint32_t __count);
#define _delay_cycles(__cycles)
#define _delay_exact_cycles(__cycles)
#define _delay_f_us(__freq, __us)
#define _delay_f_ms(__freq, __ms)
#define _delay_f_s(__freq, __s)
#define _delay_exact_f_us(__freq, __us)
#define _delay_exact_f_ms(__freq, __ms)
#define _delay_exact_f_s(__freq, __s)
Interface summary <util/delay.h>
#define _delay_us(__us)
#define _delay_ms(__ms)
#define _delay_s(__s)
#define _delay_exact_us(__us)
#define _delay_exact_ms(__ms)
#define _delay_exact_s(__s)
Note. Doxygen comments haven't been compiled/tested.
file #15033: delay.tgz
file #15289: delay2.tgz
This issue was migrated from https://savannah.nongnu.org/patch/?6418
The text was updated successfully, but these errors were encountered: