mirror of
https://github.com/RIOT-OS/RIOT.git
synced 2024-12-29 04:50:03 +01:00
Merge pull request #20241 from benpicco/busy_wait
sys/busy_wait: add busy wait helper
This commit is contained in:
commit
714958ad3c
@ -57,6 +57,11 @@ extern "C"
|
|||||||
#endif
|
#endif
|
||||||
/** @} */
|
/** @} */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief CPU cycles per busy wait loop
|
||||||
|
*/
|
||||||
|
#define CPU_CYCLES_PER_LOOP (7)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @name Use shared I2C functions
|
* @name Use shared I2C functions
|
||||||
* @{
|
* @{
|
||||||
|
@ -170,6 +170,14 @@ extern "C" {
|
|||||||
*/
|
*/
|
||||||
#define IRQ_API_INLINED (1)
|
#define IRQ_API_INLINED (1)
|
||||||
|
|
||||||
|
#if defined(CPU_CORE_CORTEX_M0) || defined(CPU_CORE_CORTEX_M0PLUS) \
|
||||||
|
|| defined(CPU_CORE_CORTEX_M23)
|
||||||
|
/**
|
||||||
|
* @brief CPU cycles per busy wait loop
|
||||||
|
*/
|
||||||
|
#define CPU_CYCLES_PER_LOOP (4)
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
@ -28,6 +28,11 @@ extern "C" {
|
|||||||
/** Mapping configured ESP32 default clock to CLOCK_CORECLOCK define */
|
/** Mapping configured ESP32 default clock to CLOCK_CORECLOCK define */
|
||||||
#define CLOCK_CORECLOCK (1000000UL * CONFIG_ESP32_DEFAULT_CPU_FREQ_MHZ)
|
#define CLOCK_CORECLOCK (1000000UL * CONFIG_ESP32_DEFAULT_CPU_FREQ_MHZ)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief CPU cycles per busy wait loop
|
||||||
|
*/
|
||||||
|
#define CPU_CYCLES_PER_LOOP (6)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @name Predefined GPIO names
|
* @name Predefined GPIO names
|
||||||
* @{
|
* @{
|
||||||
|
@ -28,6 +28,11 @@ extern "C" {
|
|||||||
/** Mapping configured ESP32-C3 default clock to CLOCK_CORECLOCK define */
|
/** Mapping configured ESP32-C3 default clock to CLOCK_CORECLOCK define */
|
||||||
#define CLOCK_CORECLOCK (1000000UL * CONFIG_ESP32C3_DEFAULT_CPU_FREQ_MHZ)
|
#define CLOCK_CORECLOCK (1000000UL * CONFIG_ESP32C3_DEFAULT_CPU_FREQ_MHZ)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief CPU cycles per busy wait loop
|
||||||
|
*/
|
||||||
|
#define CPU_CYCLES_PER_LOOP (4)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @name Predefined GPIO names
|
* @name Predefined GPIO names
|
||||||
* @{
|
* @{
|
||||||
|
@ -28,6 +28,11 @@ extern "C" {
|
|||||||
/** Mapping configured ESP32-S2 default clock to CLOCK_CORECLOCK define */
|
/** Mapping configured ESP32-S2 default clock to CLOCK_CORECLOCK define */
|
||||||
#define CLOCK_CORECLOCK (1000000UL * CONFIG_ESP32S2_DEFAULT_CPU_FREQ_MHZ)
|
#define CLOCK_CORECLOCK (1000000UL * CONFIG_ESP32S2_DEFAULT_CPU_FREQ_MHZ)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief CPU cycles per busy wait loop
|
||||||
|
*/
|
||||||
|
#define CPU_CYCLES_PER_LOOP (6)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @name Predefined GPIO names
|
* @name Predefined GPIO names
|
||||||
* @{
|
* @{
|
||||||
|
@ -19,13 +19,18 @@
|
|||||||
#ifndef PERIPH_CPU_ESP32S3_H
|
#ifndef PERIPH_CPU_ESP32S3_H
|
||||||
#define PERIPH_CPU_ESP32S3_H
|
#define PERIPH_CPU_ESP32S3_H
|
||||||
|
|
||||||
/** Mapping configured ESP32-S3 default clock to CLOCK_CORECLOCK define */
|
|
||||||
#define CLOCK_CORECLOCK (1000000UL * CONFIG_ESP32S3_DEFAULT_CPU_FREQ_MHZ)
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
extern "C" {
|
extern "C" {
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
/** Mapping configured ESP32-S3 default clock to CLOCK_CORECLOCK define */
|
||||||
|
#define CLOCK_CORECLOCK (1000000UL * CONFIG_ESP32S3_DEFAULT_CPU_FREQ_MHZ)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief CPU cycles per busy wait loop
|
||||||
|
*/
|
||||||
|
#define CPU_CYCLES_PER_LOOP (5)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @name Predefined GPIO names
|
* @name Predefined GPIO names
|
||||||
* @{
|
* @{
|
||||||
|
@ -34,6 +34,11 @@ extern "C" {
|
|||||||
*/
|
*/
|
||||||
#define CPUID_LEN (4U)
|
#define CPUID_LEN (4U)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief CPU cycles per busy wait loop
|
||||||
|
*/
|
||||||
|
#define CPU_CYCLES_PER_LOOP (5)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @name GPIO configuration
|
* @name GPIO configuration
|
||||||
* @{
|
* @{
|
||||||
|
@ -25,6 +25,7 @@
|
|||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
|
||||||
#include "debug.h"
|
#include "debug.h"
|
||||||
|
#include "busy_wait.h"
|
||||||
#include "macros/math.h"
|
#include "macros/math.h"
|
||||||
#include "macros/units.h"
|
#include "macros/units.h"
|
||||||
#include "periph_conf.h"
|
#include "periph_conf.h"
|
||||||
@ -99,22 +100,6 @@ static void check_config(void)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void busy_wait(uint16_t loops)
|
|
||||||
{
|
|
||||||
while (loops) {
|
|
||||||
/* This empty inline assembly should be enough to convince the
|
|
||||||
* compiler that the loop cannot be optimized out. Tested with
|
|
||||||
* GCC 12.2 and clang 16.0.0 successfully. */
|
|
||||||
__asm__ __volatile__ (
|
|
||||||
""
|
|
||||||
: /* no outputs */
|
|
||||||
: /* no inputs */
|
|
||||||
: /* no clobbers */
|
|
||||||
);
|
|
||||||
loops--;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void wait_for_crystals_to_stabilize(void)
|
static void wait_for_crystals_to_stabilize(void)
|
||||||
{
|
{
|
||||||
/* The MSP430x1xx MCU family have an oscillator fault detector that sets
|
/* The MSP430x1xx MCU family have an oscillator fault detector that sets
|
||||||
|
89
sys/include/busy_wait.h
Normal file
89
sys/include/busy_wait.h
Normal file
@ -0,0 +1,89 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2024 ML!PA Consulting GmbH
|
||||||
|
*
|
||||||
|
* This file is subject to the terms and conditions of the GNU Lesser
|
||||||
|
* General Public License v2.1. See the file LICENSE in the top level
|
||||||
|
* directory for more details.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @defgroup busy_wait Busy Waiting low-level helpers
|
||||||
|
* @ingroup sys
|
||||||
|
*
|
||||||
|
* @brief This modules provides helper functions for busy waiting
|
||||||
|
* on short intervals before timers are initialized, e.g.
|
||||||
|
* in `board_init()`.
|
||||||
|
*
|
||||||
|
* @author Benjamin Valentin <benjamin.valentin@ml-pa.com>
|
||||||
|
* @{
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef BUSY_WAIT_H
|
||||||
|
#define BUSY_WAIT_H
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
#include "periph_conf.h"
|
||||||
|
#include "time_units.h"
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief CPU cycles per busy wait loop iteration
|
||||||
|
*
|
||||||
|
* This can be used to roughly estimate the number of cycles
|
||||||
|
* for a given wait time.
|
||||||
|
*/
|
||||||
|
#ifndef CPU_CYCLES_PER_LOOP
|
||||||
|
#define CPU_CYCLES_PER_LOOP 3
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Spin for a number of cycles.
|
||||||
|
*
|
||||||
|
* This will not take into account cycles spent on interrupts
|
||||||
|
* if they are enabled and occur.
|
||||||
|
*
|
||||||
|
* @param loops Number of loop iterations to take
|
||||||
|
*/
|
||||||
|
static inline void busy_wait(unsigned loops)
|
||||||
|
{
|
||||||
|
while (loops) {
|
||||||
|
/* This empty inline assembly should be enough to convince the
|
||||||
|
* compiler that the loop cannot be optimized out. Tested with
|
||||||
|
* GCC 12.2 and clang 16.0.0 successfully. */
|
||||||
|
__asm__ __volatile__ (
|
||||||
|
""
|
||||||
|
: /* no outputs */
|
||||||
|
: /* no inputs */
|
||||||
|
: /* no clobbers */
|
||||||
|
);
|
||||||
|
loops--;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Spin for a number of microseconds.
|
||||||
|
*
|
||||||
|
* This will roughly try to match the requested delay time, but don't
|
||||||
|
* expect high accuracy.
|
||||||
|
*
|
||||||
|
* This will not take into account cycles spent on interrupts
|
||||||
|
* if they are enabled and occur.
|
||||||
|
*
|
||||||
|
* @param usec Number of µs to spin for.
|
||||||
|
*/
|
||||||
|
static inline void busy_wait_us(unsigned usec)
|
||||||
|
{
|
||||||
|
unsigned loops = ((uint64_t)usec * CLOCK_CORECLOCK)
|
||||||
|
/ (US_PER_SEC * CPU_CYCLES_PER_LOOP);
|
||||||
|
busy_wait(loops);
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif /* BUSY_WAIT_H */
|
||||||
|
/** @} */
|
5
tests/sys/busy_wait/Makefile
Normal file
5
tests/sys/busy_wait/Makefile
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
include ../Makefile.sys_common
|
||||||
|
|
||||||
|
USEMODULE += ztimer_usec
|
||||||
|
|
||||||
|
include $(RIOTBASE)/Makefile.include
|
3
tests/sys/busy_wait/Makefile.ci
Normal file
3
tests/sys/busy_wait/Makefile.ci
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
BOARD_INSUFFICIENT_MEMORY := \
|
||||||
|
atmega8 \
|
||||||
|
#
|
50
tests/sys/busy_wait/main.c
Normal file
50
tests/sys/busy_wait/main.c
Normal file
@ -0,0 +1,50 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2024 ML!PA Consulting GmbH
|
||||||
|
*
|
||||||
|
* This file is subject to the terms and conditions of the GNU Lesser
|
||||||
|
* General Public License v2.1. See the file LICENSE in the top level
|
||||||
|
* directory for more details.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @ingroup tests
|
||||||
|
* @{
|
||||||
|
*
|
||||||
|
* @file
|
||||||
|
* @brief Busy Wait loop Test Application
|
||||||
|
*
|
||||||
|
* This can be used to determine `CPU_CYCLES_PER_LOOP` by
|
||||||
|
* comparing the time the busy wait loop took with the
|
||||||
|
* actual µsec timer.
|
||||||
|
*
|
||||||
|
* @author Benjamin Valentin <benjamin.valentin@ml-pa.com>
|
||||||
|
* @}
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include "busy_wait.h"
|
||||||
|
#include "ztimer/stopwatch.h"
|
||||||
|
|
||||||
|
static inline void _measure_interval(ztimer_stopwatch_t *clock, unsigned usec)
|
||||||
|
{
|
||||||
|
unsigned usec_real;
|
||||||
|
|
||||||
|
printf("waiting for %u µs…\n", usec);
|
||||||
|
ztimer_stopwatch_start(clock);
|
||||||
|
busy_wait_us(usec);
|
||||||
|
usec_real = ztimer_stopwatch_measure(clock);
|
||||||
|
printf("took %u µs (diff: %d µs)\n", usec_real, (int)usec_real - usec);
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(void)
|
||||||
|
{
|
||||||
|
ztimer_stopwatch_t clock;
|
||||||
|
ztimer_stopwatch_init(ZTIMER_USEC, &clock);
|
||||||
|
|
||||||
|
_measure_interval(&clock, 10);
|
||||||
|
_measure_interval(&clock, 100);
|
||||||
|
_measure_interval(&clock, 1000);
|
||||||
|
_measure_interval(&clock, 10000);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user