1
0
mirror of https://github.com/RIOT-OS/RIOT.git synced 2024-12-29 04:50:03 +01:00

Merge pull request #17633 from fjmolinas/pr_ztimer_auto_adjust

sys/ztimer: add auto_adjust module
This commit is contained in:
Kaspar Schleiser 2022-02-23 10:01:05 +01:00 committed by GitHub
commit c6151226ad
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
16 changed files with 226 additions and 26 deletions

View File

@ -19,6 +19,16 @@
#ifndef BOARD_H
#define BOARD_H
/**
* @name ztimer configuration values
*
* @note Overrides arduino-atmega defaults
* @{
*/
#define CONFIG_ZTIMER_USEC_ADJUST_SET (128)
#define CONFIG_ZTIMER_USEC_ADJUST_SLEEP (116)
/** @} */
#include "board_common.h"
#ifdef __cplusplus

View File

@ -46,8 +46,8 @@ extern "C" {
* @name ztimer configuration values
* @{
*/
#define CONFIG_ZTIMER_USEC_ADJUST_SET (128)
#define CONFIG_ZTIMER_USEC_ADJUST_SLEEP (128)
#define CONFIG_ZTIMER_USEC_ADJUST_SET (132)
#define CONFIG_ZTIMER_USEC_ADJUST_SLEEP (120)
/** @} */
/**

View File

@ -113,8 +113,12 @@ extern "C" {
#define CONFIG_ZTIMER_USEC_DEV (TIMER_DEV(0))
#define CONFIG_ZTIMER_USEC_FREQ (250000LU)
#define CONFIG_ZTIMER_USEC_WIDTH (16)
#define CONFIG_ZTIMER_USEC_ADJUST_SET (124)
#define CONFIG_ZTIMER_USEC_ADJUST_SLEEP (120)
#ifndef CONFIG_ZTIMER_USEC_ADJUST_SET
#define CONFIG_ZTIMER_USEC_ADJUST_SET (128)
#endif
#ifndef CONFIG_ZTIMER_USEC_ADJUST_SLEEP
#define CONFIG_ZTIMER_USEC_ADJUST_SLEEP (116)
#endif
/** @} */
/**

View File

@ -14707,3 +14707,5 @@ drivers/ft5x06/include/ft5x06_constants\.h:[0-9]+: warning: Member FT5X06_G_MODE
drivers/ft5x06/include/ft5x06_constants\.h:[0-9]+: warning: Member FT5X06_G_MODE_INTERRUPT_POLLING \(macro definition\) of file ft5x06_constants\.h is not documented\.
drivers/ft5x06/include/ft5x06_constants\.h:[0-9]+: warning: Member FT5X06_G_MODE_INTERRUPT_TRIGGER \(macro definition\) of file ft5x06_constants\.h is not documented\.
drivers/ft5x06/include/ft5x06_params\.h:[0-9]+: warning: Member FT5X06_PARAM_TYPE \(macro definition\) of file ft5x06_params\.h is not documented\.
boards/arduino\-uno/include/board\.h:[0-9]+: warning: Member CONFIG_ZTIMER_USEC_ADJUST_SET \(macro definition\) of file board\.h is not documented\.
boards/arduino\-uno/include/board\.h:[0-9]+: warning: Member CONFIG_ZTIMER_USEC_ADJUST_SLEEP \(macro definition\) of file board\.h is not documented\.

View File

@ -6,6 +6,10 @@ ifneq (,$(filter auto_init_ztimer,$(USEMODULE)))
USEMODULE += ztimer_init
endif
ifneq (,$(filter ztimer_auto_adjust,$(USEMODULE)))
USEMODULE += ztimer_overhead
endif
ifneq (,$(filter auto_init_saul,$(USEMODULE)))
USEMODULE += saul_init_devs
endif

View File

@ -259,6 +259,20 @@ PSEUDOMODULES += ztimer
PSEUDOMODULES += ztimer_%
PSEUDOMODULES += ztimer64_%
## @defgroup pseudomodule_ztimer_auto_adjust ztimer_auto_adjust
## @brief A module to set on init ztimer->adjust_sleep/adjust_set values
##
## When this module is active, then on init if no CONFIG_ZTIMER_USEC_ADJUST_%
## values are set for the BOARD correction values adjust_sleep and adjust_set
## will be calculated in set for the required clocks.
##
## Note that some BOARDs clocks require a startup time to get accuarate values,
## a configurable @ref CONFIG_ZTIMER_AUTO_ADJUST_SETTLE value can be set for this.
##
## Alternatively CONFIG_ZTIMER_USEC_ADJUST_% values can be set in the BOARDs
## configuration header board.h. These can be found out by running tests/ztimer_overhead
PSEUDOMODULES += ztimer_auto_adjust
# ztimer's main module is called "ztimer_core"
NO_PSEUDOMODULES += ztimer_core
NO_PSEUDOMODULES += netdev_ieee802154_submac

View File

@ -136,6 +136,41 @@ extern "C" {
# endif
#endif
/**
* @brief An offset for ZTIMER_USEC allowing to compensate for the offset
* of @ref ztimer_set(). It can be measured with @ref ztimer_overhead_set()
*
* This value should be configured in the board.h.
*
*/
#ifndef CONFIG_ZTIMER_USEC_ADJUST_SET
#define CONFIG_ZTIMER_USEC_ADJUST_SET 0
#endif
/**
* @brief An offset for ZTIMER_USEC allowing to compentsate for the offset
* of @ref ztimer_sleep().
*
* @note As internally @ref ztimer_sleep() uses @ref ztimer_set()
* @ref CONFIG_ZTIMER_USEC_ADJUST_SET should be tuned before.
*
* This value should be configured in the board.h.
*/
#ifndef CONFIG_ZTIMER_USEC_ADJUST_SLEEP
#define CONFIG_ZTIMER_USEC_ADJUST_SLEEP 0
#endif
/**
* @brief Some MCUs clocks need some warm-up time during which timing is
* inaccurate. This can be a hindrance when using the @ref
* pseudomodule_ztimer_auto_adjust module.
*
* @warning This value will increase the boards start-up time
*/
#ifndef CONFIG_ZTIMER_AUTO_ADJUST_SETTLE
#define CONFIG_ZTIMER_AUTO_ADJUST_SETTLE 0
#endif
#ifdef __cplusplus
}
#endif

View File

@ -31,9 +31,9 @@ extern "C" {
#endif
/**
* @brief Measure ztimer overhead
* @brief Measure overhead for ztimer_set()
*
* This function can be used to measure the overhead incurred by ztimer.
* This function can be used to measure the overhead incurred by ztimer_set().
* It will configure a callback to trigger after @p base ticks, then return the
* number of ticks that have passed, minus @p base.
*
@ -41,7 +41,18 @@ extern "C" {
* @param[in] base base interval to use
* @return (time from ztimer_set() until callback) - base
*/
int32_t ztimer_overhead(ztimer_clock_t *clock, uint32_t base);
int32_t ztimer_overhead_set(ztimer_clock_t *clock, uint32_t base);
/**
* @brief Measure overhead for ztimer_sleep()
*
* This function can be used to measure the overhead incurred by ztimer_sleep().
*
* @param[in] clock ztimer clock to operate on
* @param[in] base base interval to use
* @return (time(ztimer_sleep(base))) - base
*/
int32_t ztimer_overhead_sleep(ztimer_clock_t *clock, uint32_t base);
#endif /* ZTIMER_OVERHEAD_H */
/** @} */

View File

@ -183,6 +183,10 @@ config MODULE_AUTO_INIT_ZTIMER
select MODULE_ZTIMER_INIT
default y
config MODULE_ZTIMER_AUTO_ADJUST
bool "Auto adjust ztimer set and sleep values"
select MODULE_ZTIMER_OVERHEAD
config MODULE_ZTIMER_NOW64
bool "Use a 64-bits result for ztimer_now()"

View File

@ -43,6 +43,7 @@
#include "ztimer/convert_frac.h"
#include "ztimer/convert_shift.h"
#include "ztimer/convert_muldiv64.h"
#include "ztimer/overhead.h"
#include "ztimer/periph_timer.h"
#include "ztimer/periph_rtt.h"
#include "ztimer/periph_rtc.h"
@ -212,6 +213,29 @@ ztimer_clock_t *const ZTIMER_SEC = &_ztimer_convert_frac_sec.super.super;
# endif
#endif
#if IS_USED(MODULE_ZTIMER_USEC)
#ifndef CONFIG_ZTIMER_AUTO_ADJUST_BASE_ITVL
#define CONFIG_ZTIMER_AUTO_ADJUST_BASE_ITVL 1000
#endif
#ifndef CONFIG_ZTIMER_AUTO_ADJUST_ITER
#define CONFIG_ZTIMER_AUTO_ADJUST_ITER 100
#endif
static void _ztimer_usec_overhead(unsigned samples, unsigned base, uint16_t *adjust_value,
int32_t (*overhead_fn)(ztimer_clock_t *clock, uint32_t base))
{
int32_t min = INT32_MAX;
for (unsigned i = 0; i < samples; i++) {
int32_t overhead = overhead_fn(ZTIMER_USEC, base);
if (overhead < min) {
min = overhead;
}
}
*adjust_value = min;
}
#endif
void ztimer_init(void)
{
/* Step 4: initialize used ztimer-periphery */
@ -266,16 +290,42 @@ void ztimer_init(void)
# else
LOG_DEBUG("ztimer_init(): ZTIMER_USEC without conversion\n");
# endif
# ifdef CONFIG_ZTIMER_USEC_ADJUST_SET
LOG_DEBUG("ztimer_init(): ZTIMER_USEC setting adjust_set value to %i\n",
CONFIG_ZTIMER_USEC_ADJUST_SET );
ZTIMER_USEC->adjust_set = CONFIG_ZTIMER_USEC_ADJUST_SET;
# endif
# ifdef CONFIG_ZTIMER_USEC_ADJUST_SLEEP
LOG_DEBUG("ztimer_init(): ZTIMER_USEC setting adjust_sleep value to %i\n",
CONFIG_ZTIMER_USEC_ADJUST_SLEEP );
ZTIMER_USEC->adjust_sleep = CONFIG_ZTIMER_USEC_ADJUST_SLEEP;
# endif
/* warm-up time if set and needed */
if (IS_USED(MODULE_ZTIMER_AUTO_ADJUST) &&
!(CONFIG_ZTIMER_USEC_ADJUST_SET && CONFIG_ZTIMER_USEC_ADJUST_SLEEP)) {
if (CONFIG_ZTIMER_AUTO_ADJUST_SETTLE) {
ztimer_sleep(ZTIMER_USEC, CONFIG_ZTIMER_AUTO_ADJUST_SETTLE);
}
}
/* calculate or set 'adjust_set' */
if (CONFIG_ZTIMER_USEC_ADJUST_SET) {
ZTIMER_USEC->adjust_set = CONFIG_ZTIMER_USEC_ADJUST_SET;
}
else if (IS_USED(MODULE_ZTIMER_AUTO_ADJUST)) {
_ztimer_usec_overhead(CONFIG_ZTIMER_AUTO_ADJUST_ITER, CONFIG_ZTIMER_AUTO_ADJUST_BASE_ITVL,
&ZTIMER_USEC->adjust_set, ztimer_overhead_set);
}
if (ZTIMER_USEC->adjust_set) {
LOG_DEBUG("ztimer_init(): ZTIMER_USEC setting adjust_set value to %i\n",
ZTIMER_USEC->adjust_set);
}
/* calculate or set 'adjust_sleep' */
if (CONFIG_ZTIMER_USEC_ADJUST_SLEEP) {
ZTIMER_USEC->adjust_sleep = CONFIG_ZTIMER_USEC_ADJUST_SLEEP;
}
else if (IS_USED(MODULE_ZTIMER_AUTO_ADJUST)) {
_ztimer_usec_overhead(CONFIG_ZTIMER_AUTO_ADJUST_ITER,
CONFIG_ZTIMER_AUTO_ADJUST_BASE_ITVL, &ZTIMER_USEC->adjust_sleep,
ztimer_overhead_sleep);
}
if (ZTIMER_USEC->adjust_sleep) {
LOG_DEBUG("ztimer_init(): ZTIMER_USEC setting adjust_sleep value to %i\n",
ZTIMER_USEC->adjust_sleep);
}
#endif
#if MODULE_ZTIMER_MSEC

View File

@ -35,7 +35,7 @@ static void _callback(void *arg)
*callback_arg->val = ztimer_now(callback_arg->clock);
}
int32_t ztimer_overhead(ztimer_clock_t *clock, uint32_t base)
int32_t ztimer_overhead_set(ztimer_clock_t *clock, uint32_t base)
{
volatile uint32_t after = 0;
uint32_t pre;
@ -48,3 +48,13 @@ int32_t ztimer_overhead(ztimer_clock_t *clock, uint32_t base)
while (!after) {}
return after - pre - base;
}
int32_t ztimer_overhead_sleep(ztimer_clock_t *clock, uint32_t base)
{
uint32_t pre = ztimer_now(clock);
ztimer_sleep(clock, base);
uint32_t after = ztimer_now(clock);
return after - pre - base;
}

View File

@ -1,6 +1,9 @@
DEVELHELP ?= 0
include ../Makefile.tests_common
USEMODULE += ztimer_overhead ztimer_usec
USEMODULE += ztimer_auto_adjust
USEMODULE += ztimer_overhead
USEMODULE += ztimer_usec
include $(RIOTBASE)/Makefile.include

View File

@ -3,5 +3,22 @@
This test application sets up a ztimer_periph at 1MHz, then measures 1024
times how much overhead ztimer adds.
It uses the "ztimer_overhead()" function. See it's documentation for more
It uses the "ztimer_overhead_set()" function. See it's documentation for more
information.
It then sets `adjust_set` parameter and sleeps 1024 times and measure how
much overhead ztimer_sleep adds.
It uses the "ztimer_overhead_sleep()" function. See it's documentation for more
information.
At the end of the test `adjust_set` and `adjust_sleep` values are printed
that can be set for the target `BOARD` in `board.h`.
e.g for dwm1001:
```shell
ZTIMER_USEC adjust params for dwm1001:
CONFIG_ZTIMER_USEC_ADJUST_SET 6
CONFIG_ZTIMER_USEC_ADJUST_SLEEP 21
```

View File

@ -3,3 +3,4 @@
CONFIG_MODULE_ZTIMER=y
CONFIG_ZTIMER_USEC=y
CONFIG_MODULE_ZTIMER_OVERHEAD=y
CONFIG_MODULE_ZTIMER_AUTO_ADJUST=y

View File

@ -23,26 +23,25 @@
#include <stdlib.h>
#include <inttypes.h>
#include "board.h"
#include "ztimer.h"
#include "ztimer/overhead.h"
#define BASE 1000
#define SAMPLES 1024
int main(void)
static int32_t _ztimer_usec_overhead(unsigned samples, unsigned base,
int32_t (*overhead_fn)(ztimer_clock_t *clock, uint32_t base))
{
uint32_t total = 0;
int32_t min = INT32_MAX;
int32_t max = INT32_MIN;
/* unset configured adjustment */
/* ZTIMER_USEC->adjust_set = 0; */
printf("ZTIMER_USEC->adjust_set = %" PRIu16 "\n", ZTIMER_USEC->adjust_set);
unsigned n = samples;
unsigned n = SAMPLES;
while (n--) {
int32_t overhead = ztimer_overhead(ZTIMER_USEC, BASE);
int32_t overhead = overhead_fn(ZTIMER_USEC, base);
total += labs(overhead);
if (overhead < min) {
min = overhead;
@ -55,5 +54,26 @@ int main(void)
printf("min=%" PRIi32 " max=%" PRIi32 " avg_diff=%" PRIi32 "\n", min, max,
(total / SAMPLES));
return min;
}
int main(void)
{
/* unset configured adjustment */
printf("ZTIMER_USEC auto_adjust params:\n");
printf(" ZTIMER_USEC->adjust_set = %" PRIu16 "\n", ZTIMER_USEC->adjust_set);
ZTIMER_USEC->adjust_set = 0;
printf(" ZTIMER_USEC->adjust_sleep = %" PRIu16 "\n", ZTIMER_USEC->adjust_sleep);
ZTIMER_USEC->adjust_sleep = 0;
printf("ZTIMER_USEC auto_adjust params cleared\n");
printf("zitmer_overhead_set...\n");
ZTIMER_USEC->adjust_set = _ztimer_usec_overhead(SAMPLES, BASE, ztimer_overhead_set);
printf("zitmer_overhead_sleep...\n");
ZTIMER_USEC->adjust_sleep = _ztimer_usec_overhead(SAMPLES, BASE, ztimer_overhead_sleep);
printf("ZTIMER_USEC adjust params for %s:\n", RIOT_BOARD);
printf(" CONFIG_ZTIMER_USEC_ADJUST_SET %" PRIi16 "\n", ZTIMER_USEC->adjust_set);
printf(" CONFIG_ZTIMER_USEC_ADJUST_SLEEP %" PRIi16 "\n", ZTIMER_USEC->adjust_sleep);
return 0;
}

View File

@ -10,8 +10,23 @@ import sys
from testrunner import run
ADJUST_SET_MARGIN = 1
ADJUST_SLEEP_MARGIN = 1
def testfunc(child):
child.expect(r"ZTIMER_USEC->adjust_set = (\d+)\r\n")
auto_adjust_set = int(child.match.group(1))
child.expect(r"ZTIMER_USEC->adjust_sleep = (\d+)\r\n")
auto_adjust_sleep = int(child.match.group(1))
child.expect(r"min=-?\d+ max=-?\d+ avg_diff=\d+\r\n")
child.expect(r"min=-?\d+ max=-?\d+ avg_diff=\d+\r\n")
child.expect(r"CONFIG_ZTIMER_USEC_ADJUST_SET\s+(\d+)\r\n")
adjust_set = int(child.match.group(1))
child.expect(r"CONFIG_ZTIMER_USEC_ADJUST_SLEEP\s+(\d+)\r\n")
adjust_sleep = int(child.match.group(1))
assert auto_adjust_set >= adjust_set - ADJUST_SET_MARGIN
assert auto_adjust_sleep >= adjust_sleep - ADJUST_SLEEP_MARGIN
if __name__ == "__main__":