Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Improve adjtime() functionality #10827

Merged
merged 2 commits into from
Sep 29, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions arch/arm/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -429,6 +429,7 @@ config ARCH_CHIP_STM32
select ARCH_HAVE_TIMEKEEPING
select ARM_HAVE_MPU_UNIFIED
select ARMV7M_HAVE_STACKCHECK
select ARCH_HAVE_ADJTIME
---help---
STMicro STM32 architectures (ARM Cortex-M3/4).

Expand Down
72 changes: 69 additions & 3 deletions arch/arm/src/stm32/stm32_timerisr.c
Original file line number Diff line number Diff line change
Expand Up @@ -58,16 +58,19 @@
/* And I don't know now to re-configure it yet */

#ifdef CONFIG_STM32_SYSTICK_HCLKd8
# define SYSTICK_RELOAD ((STM32_HCLK_FREQUENCY / 8 / CLK_TCK) - 1)
# define SYSTICK_CLOCK (STM32_HCLK_FREQUENCY / 8)
#else
# define SYSTICK_RELOAD ((STM32_HCLK_FREQUENCY / CLK_TCK) - 1)
# define SYSTICK_CLOCK (STM32_HCLK_FREQUENCY)
#endif

#define SYSTICK_RELOAD ((SYSTICK_CLOCK / CLK_TCK) - 1)

/* The size of the reload field is 24 bits. Verify that the reload value
* will fit in the reload register.
*/

#if SYSTICK_RELOAD > 0x00ffffff
#define SYSTICK_MAX 0x00ffffff
#if SYSTICK_RELOAD > SYSTICK_MAX
# error SYSTICK_RELOAD exceeds the range of the RELOAD register
#endif

Expand Down Expand Up @@ -98,6 +101,69 @@ static int stm32_timerisr(int irq, uint32_t *regs, void *arg)
* Public Functions
****************************************************************************/

#ifdef CONFIG_CLOCK_ADJTIME

/****************************************************************************
* Function: up_adj_timer_period
*
* Description:
* Adjusts timer period. This call is used when adjusting timer period as
* defined in adjtime() function.
*
* Input Parameters:
* period_inc_usec - period adjustment in usec (reset to default value
* if 0)
*
****************************************************************************/

void up_adj_timer_period(long long period_inc_usec)
{
uint32_t period;
long long period_inc;

if (period_inc_usec == 0)
{
period_inc = 0;
}
else
{
period_inc = (SYSTICK_CLOCK / 1000000) * period_inc_usec - 1;
}

period = SYSTICK_RELOAD + period_inc;

/* Check whether period is at maximum value. */

if (period > SYSTICK_MAX)
{
period = SYSTICK_MAX;
}

putreg32(period, NVIC_SYSTICK_RELOAD);
}

/****************************************************************************
* Function: up_get_timer_period
*
* Description:
* This function returns the timer period in usec.
*
* Input Parameters:
* period_usec - returned timer period in usec
*
****************************************************************************/

void up_get_timer_period(long long *period_usec)
{
uint32_t period;

period = getreg32(NVIC_SYSTICK_RELOAD);

*period_usec = ((period + 1) / (SYSTICK_CLOCK / 1000000));
}

#endif

/****************************************************************************
* Function: up_timer_initialize
*
Expand Down
28 changes: 12 additions & 16 deletions sched/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -217,28 +217,24 @@ config CLOCK_ADJTIME

if CLOCK_ADJTIME

config CLOCK_ADJTIME_SLEWLIMIT
config CLOCK_ADJTIME_SLEWLIMIT_PPM
int "Adjtime slew limit"
default 2
range 0 100
default 20000
range 1 1000000
---help---
In real time systems we do not want the time to adjust too quickly.
CLOCK_ADJTIME_SLEWLIMIT defines how many seconds can time change
during each clock.
Set limit of adjtime() clock slewing as parts per million.

Note that CLOCK_ADJTIME_SLEWLIMIT is divided by 100 in source code,
therefore CLOCK_ADJTIME_SLEWLIMIT=2 will result in possible 0.02 second
adjustment.
In real time systems we do not want the time to adjust too quickly.
For example CLOCK_ADJTIME_SLEWLIMIT=1000 will slow or speed the timer
tick period by at most 0.1 percent of the nominal value.

config CLOCK_ADJTIME_PERIOD
config CLOCK_ADJTIME_PERIOD_MS
int "Adjtime period"
default 97
range 0 100
default 970
range 1 3600000
---help---
Define system clock adjustment period. Should be between 0.95 and 0.99.

Note that CLOCK_ADJTIME_PERIOD is divided by 100 in source code,
therefore CLOCK_ADJTIME_PERIOD=97 will result in 0.97.
Define system clock adjustment period in milliseconds.
The adjustment commanded by adjtime() call is applied over this time period.

endif

Expand Down
38 changes: 18 additions & 20 deletions sched/clock/clock_adjtime.c
Original file line number Diff line number Diff line change
Expand Up @@ -51,17 +51,6 @@
is enabled!
#endif

/* Set slew limit. In real time systems we don't want the time to adjust
* too quickly. ADJTIME_SLEWLIMIT defines how many seconds can time change
* during each clock.
*/

#define ADJTIME_SLEWLIMIT (CONFIG_CLOCK_ADJTIME_SLEWLIMIT * 0.01)

/* Define system clock adjustment period. */

#define ADJTIME_PERIOD (CONFIG_CLOCK_ADJTIME_PERIOD * 0.01)

/****************************************************************************
* Private Data
****************************************************************************/
Expand Down Expand Up @@ -158,15 +147,16 @@ int adjtime(FAR const struct timeval *delta, FAR struct timeval *olddelta)
* of cycles over which we want to do the adjustment.
*/

count = (USEC_PER_SEC * ADJTIME_PERIOD) / period_usec;
count = (USEC_PER_MSEC * CONFIG_CLOCK_ADJTIME_PERIOD_MS) / period_usec;
incr = adjust_usec / count;

/* Compute maximum possible period increase and check
* whether previously computed increase exceeds the maximum
* one.
*/

incr_limit = ADJTIME_SLEWLIMIT * period_usec;
incr_limit = CONFIG_CLOCK_ADJTIME_SLEWLIMIT_PPM
/ (USEC_PER_SEC / period_usec);
if (incr > incr_limit)
{
/* It does... limit computed increase and increment count. */
Expand All @@ -175,20 +165,28 @@ int adjtime(FAR const struct timeval *delta, FAR struct timeval *olddelta)
count = adjust_usec / incr;
}

/* If requested adjustment is smaller than 1 microsecond per tick,
* adjust the count instead.
*/

if (adjust_usec == 0)
{
incr = 0;
count = 0;
}
else if (incr == 0)
{
incr = 1;
count = adjust_usec / incr;
}

if (is_negative == 1)
{
/* Positive or negative? */

incr = -incr;
}

/* Ignore small differences. */

if (incr == 0)
{
count = 0;
}

leave_critical_section(flags);

/* Initialize clock adjustment and get old adjust values. */
Expand Down
Loading