delay-stm32: inline delays

This commit is contained in:
Nico Tonnhofer 2019-04-16 23:42:25 +02:00
parent 2af85e348f
commit 6ca071804b
3 changed files with 41 additions and 41 deletions

View File

@ -5,46 +5,5 @@
#if defined TEACUP_C_INCLUDE && defined __ARM_STM32__ #if defined TEACUP_C_INCLUDE && defined __ARM_STM32__
#include "cmsis-stm32f4xx.h" // For __ASM() and ...
/** Delay in microseconds.
\param delay Time to wait in microseconds.
Execution times on ARM aren't as predictable as they could be, because
there's a code prefetch engine which can change timings depending on the
position of the code in Flash. We could use the System Tick Timer for this
task, but this timer is probably better used for more important tasks.
delay_us() and delay_ms() are used only rarely and not in a way which would
require high precision.
Nevertheless, calibrated on the oscilloscope. Measured accuracy:
delay_us(10) ...(100) ...(1000) ...(10000) ...(65000)
96 MHz 10.23 us 99.3 us 0.994 ms 9.93 ms 64.5 ms
CAUTION: this currently works for a 96 MHz clock, only! As other clock rates
appear, there's more math neccessary, see the AVR version. Or simply
a second implementation.
*/
void delay_us(uint16_t delay) {
__ASM (".balign 16"); // No gambling with the prefetch engine.
while (delay) {
__ASM volatile (
" nop \n\t" // One nop before the loop slows about 2%.
" movs r7, #9 \n\t" // One more loop round slows about 20%
"1: nop \n\t"
" sub r7, #1 \n\t"
" cmp r7, #0 \n\t"
" bne 1b \n\t"
:
:
: "r7", "cc"
);
delay--;
}
}
#endif /* defined TEACUP_C_INCLUDE && defined __ARM_STM32__ */ #endif /* defined TEACUP_C_INCLUDE && defined __ARM_STM32__ */

36
delay-stm32.h Normal file
View File

@ -0,0 +1,36 @@
#ifndef _DELAY_STM32_H
#define _DELAY_STM32_H
#include "cmsis-stm32f4xx.h" // For __ASM() and ...
/** Delay in microseconds.
\param delay Time to wait in microseconds.
Execution times on ARM aren't as predictable as they could be, because
there's a code prefetch engine which can change timings depending on the
position of the code in Flash. We could use the System Tick Timer for this
task, but this timer is probably better used for more important tasks.
delay_us() and delay_ms() are used only rarely and not in a way which would
require high precision.
*/
static void _delay(uint32_t) __attribute__ ((always_inline));
inline void _delay(uint32_t delay)
{
if (delay)
{
__ASM volatile(
"1: subs %0, %0, #1 \n\t"
" bne 1b\n\t"
: "+r"(delay));
}
else
__ASM volatile("nop \n\t");
}
// void _delay(uint32_t delay);
#define TUNER 1
#define delay_us(delay) (_delay((uint32_t)(((uint64_t)__SYSTEM_CLOCK) * (delay) / 3000000ULL * TUNER)))
#endif /* _DELAY_STM32_H */

View File

@ -3,9 +3,14 @@
#include <stdint.h> #include <stdint.h>
#ifndef __ARM_STM32__
// microsecond delay, does NOT reset WDT if feature enabled // microsecond delay, does NOT reset WDT if feature enabled
void delay_us(uint16_t delay); void delay_us(uint16_t delay);
#else
#include "delay-stm32.h"
#endif
// millisecond delay, does reset WDT if feature enabled // millisecond delay, does reset WDT if feature enabled
void delay_ms(uint32_t delay); void delay_ms(uint32_t delay);