From 6c31471ffdcd988127cde20804750d7bb078af2c Mon Sep 17 00:00:00 2001 From: Markus Hitter Date: Sun, 26 Jul 2015 14:53:48 +0200 Subject: [PATCH] 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. --- delay-arm.c | 17 ++++++++++++++++ delay-avr.c | 53 ++++++++++++++++++++++++++++++++++++++++++++++++ delay.c | 58 +++++++++-------------------------------------------- 3 files changed, 79 insertions(+), 49 deletions(-) create mode 100644 delay-arm.c create mode 100644 delay-avr.c diff --git a/delay-arm.c b/delay-arm.c new file mode 100644 index 0000000..326c453 --- /dev/null +++ b/delay-arm.c @@ -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__ */ diff --git a/delay-avr.c b/delay-avr.c new file mode 100644 index 0000000..64e627f --- /dev/null +++ b/delay-avr.c @@ -0,0 +1,53 @@ + +/** \file + \brief Delay routines, AVR specific part. +*/ + +#if defined TEACUP_C_INCLUDE && defined __AVR__ + +#include + +#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__ */ diff --git a/delay.c b/delay.c index cfdff69..e6158f6 100644 --- a/delay.c +++ b/delay.c @@ -4,60 +4,20 @@ \brief Delay routines */ -#include -#include -#include "watchdog.h" +#define TEACUP_C_INCLUDE +#include "delay-avr.c" +#include "delay-arm.c" +#undef TEACUP_C_INCLUDE -#if F_CPU < 4000000UL -#error Delay functions only work with F_CPU >= 4000000UL -#endif +#include "watchdog.h" -/** 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(!). - Accuracy on 16 MHz CPU clock: delay is about 0.8% too short. + \param delay Time to wait in milliseconds. - 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) { - 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. + Accuracy on AVR, 20 MHz: delay < 0.04% too long over the whole range. + Accuracy on AVR, 16 MHz: delay < 0.8% too short over the whole range. */ void delay_ms(uint32_t delay) { wd_reset();