Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
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
Prev Previous commit
Next Next commit
da1469x/os-tick: Fix slightly incorrect time-keeping
If the LP clock's frequency is not an integer multiple of the specified OS tick
frequency, the period of OS ticks will be incorrect due to an integer division
truncation error (to the tune of almost 1% for RCX), resulting in OS Time
gradually creeping away from the actual time. This commit fixes the issue, by
maintaining the fractional OS tick value and advance OS Time accordingly.
  • Loading branch information
apc067 committed Oct 29, 2024
commit 217eeb1f0e78fedd2412cba65a675fc7a94cd61b
2 changes: 1 addition & 1 deletion hw/mcu/dialog/da1469x/include/mcu/da1469x_clock.h
Original file line number Diff line number Diff line change
Expand Up @@ -173,7 +173,7 @@ void da1469x_clock_lp_rcx_disable(void);
/**
* Set the RTC dividers
*/
void da1469x_clock_lp_set_rtc_divs(void);
void da1469x_clock_lp_set_rtc_divs(uint32_t rtc_clock_freq);

/**
* Enable AMBA clock(s)
Expand Down
7 changes: 7 additions & 0 deletions hw/mcu/dialog/da1469x/include/mcu/da1469x_hal.h
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,13 @@ extern const int qspi_flash_config_array_size;

const struct qspi_flash_config *da1469x_qspi_get_config(void);

/**
* Calculate the OS tick parameters.
*
* @param cycles_per_sec Input frequency of timer generating OS ticks
*/
void hal_os_tick_calc_params(uint32_t cycles_per_sec);

#ifdef __cplusplus
}
#endif
Expand Down
8 changes: 4 additions & 4 deletions hw/mcu/dialog/da1469x/src/da1469x_clock.c
Original file line number Diff line number Diff line change
Expand Up @@ -476,14 +476,14 @@ da1469x_clock_lp_rcx_disable(void)
}

void
da1469x_clock_lp_set_rtc_divs(void)
da1469x_clock_lp_set_rtc_divs(uint32_t rtc_clock_freq)
{
/* Please see the DA1469x desig doc section 2.20.4 for details */
/* Please see the DA1469x Datasheet section 34.3 for details */
uint32_t reg;

reg = ((da1469x_clock_lp_freq_get() % RTC_IN_FREQ_HZ) * RTC_DIV_FRAC_ADJ) <<
reg = ((rtc_clock_freq % RTC_IN_FREQ_HZ) * RTC_DIV_FRAC_ADJ) <<
CRG_TOP_CLK_RTCDIV_REG_RTC_DIV_FRAC_Pos;
reg |= ((da1469x_clock_lp_freq_get() / RTC_IN_FREQ_HZ)) <<
reg |= ((rtc_clock_freq / RTC_IN_FREQ_HZ)) <<
CRG_TOP_CLK_RTCDIV_REG_RTC_DIV_INT_Pos;
reg |= DA1469X_RTC_DIV_DENOM_SEL << CRG_TOP_CLK_RTCDIV_REG_RTC_DIV_DENOM_Pos;
reg |= CRG_TOP_CLK_RTCDIV_REG_RTC_DIV_ENABLE_Msk;
Expand Down
3 changes: 2 additions & 1 deletion hw/mcu/dialog/da1469x/src/da1469x_lpclk.c
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,8 @@ da1469x_lpclk_notify(void)
g_da1469x_lpclk_cmac_cb(lp_curr_freq);
}

da1469x_clock_lp_set_rtc_divs();
da1469x_clock_lp_set_rtc_divs(lp_curr_freq);
hal_os_tick_calc_params(lp_curr_freq);
}
}

Expand Down
57 changes: 35 additions & 22 deletions hw/mcu/dialog/da1469x/src/hal_os_tick.c
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,10 @@
#include "mcu/mcu.h"

struct hal_os_tick {
int ticks_per_ostick;
uint32_t os_ticks_per_sec; /* Configured upon init */
uint32_t cycles_per_ostick; /* For generating the OS ticks */
uint32_t cycles_per_256_osticks; /* For more precise OS Time calculation */
uint32_t os_tick_residual;
os_time_t max_idle_ticks;
uint32_t last_trigger_val;
};
Expand Down Expand Up @@ -88,7 +91,7 @@ hal_os_tick_set_timer_trigger_val(uint32_t trigger_val)
break;
}

trigger_val += g_hal_os_tick.ticks_per_ostick;
trigger_val += g_hal_os_tick.cycles_per_ostick;
}
}

Expand All @@ -97,28 +100,28 @@ hal_os_tick_handler(void)
{
uint32_t primask;
uint32_t timer_val;
int delta;
int ticks;
uint32_t delta_x256;
uint32_t ticks;

__HAL_DISABLE_INTERRUPTS(primask);

/* Calculate elapsed ticks and advance OS time. */
/* Calculate elapsed cycles of timer & record its current value */
timer_val = hal_os_tick_get_timer_val();
delta = sub24(timer_val, g_hal_os_tick.last_trigger_val);
ticks = delta / g_hal_os_tick.ticks_per_ostick;
os_time_advance(ticks);
delta_x256 = ((timer_val - g_hal_os_tick.last_trigger_val) & 0xffffff) << 8;
g_hal_os_tick.last_trigger_val = timer_val;

/* Clear timer interrupt */
TIMER2->TIMER2_CLEAR_IRQ_REG = 1;

/* Update the time associated with the most recent tick */
g_hal_os_tick.last_trigger_val = (g_hal_os_tick.last_trigger_val +
(ticks * g_hal_os_tick.ticks_per_ostick)) &
0xffffff;
/* Re-arm timer for the next OS tick */
hal_os_tick_set_timer_trigger_val(timer_val + g_hal_os_tick.cycles_per_ostick);

/* Update timer trigger value for interrupt at the next tick */
hal_os_tick_set_timer_trigger_val(g_hal_os_tick.last_trigger_val +
g_hal_os_tick.ticks_per_ostick);
/* Update OS Time */
ticks = delta_x256 / g_hal_os_tick.cycles_per_256_osticks;
g_hal_os_tick.os_tick_residual += delta_x256 % g_hal_os_tick.cycles_per_256_osticks;
ticks += g_hal_os_tick.os_tick_residual / g_hal_os_tick.cycles_per_256_osticks;
g_hal_os_tick.os_tick_residual %= g_hal_os_tick.cycles_per_256_osticks;
os_time_advance(ticks);

__HAL_ENABLE_INTERRUPTS(primask);
}
Expand All @@ -133,6 +136,19 @@ hal_os_tick_timer2_isr(void)
os_trace_isr_exit();
}

void
hal_os_tick_calc_params(uint32_t cycles_per_sec)
{
/* Upon imit, `os_ticks_per_sec` becomes available only after clock setup - skip for now */
if (g_hal_os_tick.os_ticks_per_sec == 0) {
return;
}

g_hal_os_tick.cycles_per_256_osticks = (cycles_per_sec << 8) / g_hal_os_tick.os_ticks_per_sec;
g_hal_os_tick.cycles_per_ostick = g_hal_os_tick.cycles_per_256_osticks >> 8;
g_hal_os_tick.max_idle_ticks = (1UL << 22) / g_hal_os_tick.cycles_per_ostick;
}

void
os_tick_idle(os_time_t ticks)
{
Expand All @@ -146,7 +162,7 @@ os_tick_idle(os_time_t ticks)
}

new_trigger_val = g_hal_os_tick.last_trigger_val +
(ticks * g_hal_os_tick.ticks_per_ostick);
(ticks * g_hal_os_tick.cycles_per_ostick);

hal_os_tick_set_timer_trigger_val(new_trigger_val);
}
Expand All @@ -163,13 +179,10 @@ os_tick_init(uint32_t os_ticks_per_sec, int prio)
{
uint32_t primask;

g_hal_os_tick.os_ticks_per_sec = os_ticks_per_sec;
g_hal_os_tick.last_trigger_val = 0;
#if MYNEWT_VAL_CHOICE(MCU_LPCLK_SOURCE, RCX)
g_hal_os_tick.ticks_per_ostick = da1469x_clock_lp_rcx_freq_get() / os_ticks_per_sec;
#else
g_hal_os_tick.ticks_per_ostick = 32768 / os_ticks_per_sec;
#endif
g_hal_os_tick.max_idle_ticks = (1UL << 22) / g_hal_os_tick.ticks_per_ostick;
g_hal_os_tick.os_tick_residual = 0;
hal_os_tick_calc_params(da1469x_clock_lp_freq_get());

TIMER2->TIMER2_CTRL_REG = 0;
TIMER2->TIMER2_PRESCALER_REG = 0;
Expand Down