diff --git a/include/nanokernel.h b/include/nanokernel.h index 3813caa1846..c3b753cb262 100644 --- a/include/nanokernel.h +++ b/include/nanokernel.h @@ -125,6 +125,23 @@ extern nano_context_type_t sys_execution_context_type_get(void); extern int _is_thread_essential(nano_thread_id_t pCtx); +/** + * + * @brief Busy wait the currently executing thread + * + * This routine causes the current task or fiber to execute a "do nothing" + * loop for a specified period of time. + * + * @warning This routine utilizes the system clock, so it must not be invoked + * until the system clock is fully operational or while interrupts + * are locked. + * + * @param usec_to_wait Number of microseconds to busy wait. + * + * @return N/A + */ +extern void sys_thread_busy_wait(uint32_t usec_to_wait); + /** * @brief Nanokernel Fibers * @defgroup nanokernel_fiber Nanokernel Fibers diff --git a/kernel/nanokernel/nano_context.c b/kernel/nanokernel/nano_context.c index 88f1a09db83..e623b8d4f5b 100644 --- a/kernel/nanokernel/nano_context.c +++ b/kernel/nanokernel/nano_context.c @@ -41,6 +41,8 @@ tasks or fibers. #include #include +#include +#include nano_thread_id_t sys_thread_self_get(void) @@ -105,6 +107,37 @@ int _is_thread_essential(struct tcs *pCtx /* pointer to thread */ return ((pCtx == NULL) ? _nanokernel.current : pCtx)->flags & ESSENTIAL; } +/* + * Don't build sys_thread_busy_wait() for ARM, since intrinsics libraries in + * current Zephyr SDK use non-Thumb code that isn't supported on Cortex-M CPUs. + * For the time being any ARM-based application that attempts to use this API + * will get a link error (which is preferable to a mysterious exception). + */ + +#ifndef CONFIG_ARM + +void sys_thread_busy_wait(uint32_t usec_to_wait) +{ + /* use 64-bit math to prevent overflow when multiplying */ + uint32_t cycles_to_wait = (uint32_t)( + (uint64_t)usec_to_wait * + (uint64_t)sys_clock_hw_cycles_per_sec / + (uint64_t)USEC_PER_SEC + ); + uint32_t start_cycles = _sys_clock_cycle_get(); + + for (;;) { + uint32_t current_cycles = _sys_clock_cycle_get(); + + /* this handles the rollover on an unsigned 32-bit value */ + if ((current_cycles - start_cycles) >= cycles_to_wait) { + break; + } + } +} + +#endif /* CONFIG_ARM */ + #ifdef CONFIG_THREAD_CUSTOM_DATA /**