ARM: split out architecture specific parts for delay.c

(Hopefully) no functional change.

Also remove these wd_reset()s in delay_us() to match the behaviour
promised in delay.h. Not that this matters much, watchdog is
disabled by default.
This commit is contained in:
Markus Hitter 2015-07-26 14:53:48 +02:00
parent e2df7733ee
commit 6c31471ffd
3 changed files with 79 additions and 49 deletions

17
delay-arm.c Normal file
View File

@ -0,0 +1,17 @@
/** \file
\brief Delay routines, ARM specific part.
*/
#if defined TEACUP_C_INCLUDE && defined __ARMEL__
/** Delay in microseconds.
\param delay Time to wait in microseconds.
To Be Defined.
*/
void delay_us(uint16_t delay) {
}
#endif /* defined TEACUP_C_INCLUDE && defined __ARMEL__ */

53
delay-avr.c Normal file
View File

@ -0,0 +1,53 @@
/** \file
\brief Delay routines, AVR specific part.
*/
#if defined TEACUP_C_INCLUDE && defined __AVR__
#include <util/delay_basic.h>
#if F_CPU < 4000000UL
#error Delay functions on AVR only work with F_CPU >= 4000000UL
#endif
/** Delay in microseconds.
\param delay Time to wait in microseconds.
Calibrated in SimulAVR.
Accuracy on 20 MHz CPU clock: -1/+3 clock cycles over the whole range(!).
Accuracy on 16 MHz CPU clock: delay is about 0.8% too short.
Exceptions are delays of 0..2 on 20 MHz, which are all 0.75 us and delays
of 0..3 on 16 MHz, which are all 0.93us.
*/
void delay_us(uint16_t delay) {
// Compensate call overhead, as close as possible.
#define OVERHEAD_CALL_CLOCKS 39 // clock cycles
#define OVERHEAD_CALL_DIV ((OVERHEAD_CALL_CLOCKS / (F_CPU / 1000000)) + 1)
#define OVERHEAD_CALL_REM ((OVERHEAD_CALL_DIV * (F_CPU / 1000000)) - \
OVERHEAD_CALL_CLOCKS)
if (delay > OVERHEAD_CALL_DIV) {
delay -= OVERHEAD_CALL_DIV;
if (OVERHEAD_CALL_REM >= 2)
_delay_loop_2((OVERHEAD_CALL_REM + 2) / 4);
}
else {
return;
}
while (delay > (65536L / (F_CPU / 4000000L))) {
#define OVERHEAD_LOOP_CLOCKS 13
_delay_loop_2(65536 - (OVERHEAD_LOOP_CLOCKS + 2) / 4);
delay -= (65536L / (F_CPU / 4000000L));
}
if (delay)
_delay_loop_2(delay * (F_CPU / 4000000L));
}
#endif /* defined TEACUP_C_INCLUDE && defined __AVR__ */

58
delay.c
View File

@ -4,60 +4,20 @@
\brief Delay routines \brief Delay routines
*/ */
#include <stdint.h> #define TEACUP_C_INCLUDE
#include <util/delay_basic.h> #include "delay-avr.c"
#include "watchdog.h" #include "delay-arm.c"
#undef TEACUP_C_INCLUDE
#if F_CPU < 4000000UL #include "watchdog.h"
#error Delay functions only work with F_CPU >= 4000000UL
#endif
/** Delay in microseconds
\param delay time to wait in microseconds
Calibrated in SimulAVR. /** Delay in milliseconds.
Accuracy on 20 MHz CPU clock: -1/+3 clock cycles over the whole range(!). \param delay Time to wait in milliseconds.
Accuracy on 16 MHz CPU clock: delay is about 0.8% too short.
Exceptions are delays of 0..2 on 20 MHz, which are all 0.75 us and delays Accuracy on AVR, 20 MHz: delay < 0.04% too long over the whole range.
of 0..3 on 16 MHz, which are all 0.93us. Accuracy on AVR, 16 MHz: delay < 0.8% too short over the whole range.
*/
void delay_us(uint16_t delay) {
wd_reset();
// Compensate call overhead, as close as possible.
#define OVERHEAD_CALL_CLOCKS 39 // clock cycles
#define OVERHEAD_CALL_DIV ((OVERHEAD_CALL_CLOCKS / (F_CPU / 1000000)) + 1)
#define OVERHEAD_CALL_REM ((OVERHEAD_CALL_DIV * (F_CPU / 1000000)) - \
OVERHEAD_CALL_CLOCKS)
if (delay > OVERHEAD_CALL_DIV) {
delay -= OVERHEAD_CALL_DIV;
if (OVERHEAD_CALL_REM >= 2)
_delay_loop_2((OVERHEAD_CALL_REM + 2) / 4);
}
else {
return;
}
while (delay > (65536L / (F_CPU / 4000000L))) {
#define OVERHEAD_LOOP_CLOCKS 13
_delay_loop_2(65536 - (OVERHEAD_LOOP_CLOCKS + 2) / 4);
delay -= (65536L / (F_CPU / 4000000L));
wd_reset();
}
if (delay)
_delay_loop_2(delay * (F_CPU / 4000000L));
wd_reset();
}
/** Delay in microseconds
\param delay time to wait in milliseconds
Accuracy on 20 MHz: delay < 0.04% too long over the whole range.
Accuracy on 16 MHz: delay < 0.8% too short over the whole range.
*/ */
void delay_ms(uint32_t delay) { void delay_ms(uint32_t delay) {
wd_reset(); wd_reset();