This is an automated email from the ASF dual-hosted git repository.
vipulrahane pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/mynewt-core.git
The following commit(s) were added to refs/heads/master by this push:
new 64e8e167b DA1469x: Clock time shifts on reboots (#3321)
64e8e167b is described below
commit 64e8e167b2c82bf50b505122fc8fbce8c5355677
Author: Peter Csaszar <[email protected]>
AuthorDate: Tue Oct 29 14:54:54 2024 -0700
DA1469x: Clock time shifts on reboots (#3321)
- Add missing services to the driver API. It also makes the
actual calibration of the XTAL32K clock a syscfg option, defaulting to 0.
- Eliminate magic numbers
- Streamline the LP clock API, by offering clean access to the
LP clock selected via syscfg.
- Add the function that calculates the RTC divider registers and
invoke it when the LP clock frequency changes.
- 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 advancing OS Time accordingly.
---
hw/mcu/dialog/da1469x/include/mcu/da1469x_clock.h | 59 +++++-
hw/mcu/dialog/da1469x/include/mcu/da1469x_hal.h | 7 +
hw/mcu/dialog/da1469x/include/mcu/da1469x_lpclk.h | 3 +
hw/mcu/dialog/da1469x/src/da1469x_clock.c | 230 +++++++++++++++++++---
hw/mcu/dialog/da1469x/src/da1469x_lpclk.c | 47 ++++-
hw/mcu/dialog/da1469x/src/hal_os_tick.c | 57 +++---
hw/mcu/dialog/da1469x/src/hal_system.c | 19 +-
hw/mcu/dialog/da1469x/syscfg.yml | 17 ++
8 files changed, 359 insertions(+), 80 deletions(-)
diff --git a/hw/mcu/dialog/da1469x/include/mcu/da1469x_clock.h
b/hw/mcu/dialog/da1469x/include/mcu/da1469x_clock.h
index ceec05094..cf2e78008 100644
--- a/hw/mcu/dialog/da1469x/include/mcu/da1469x_clock.h
+++ b/hw/mcu/dialog/da1469x/include/mcu/da1469x_clock.h
@@ -61,6 +61,21 @@ void da1469x_clock_sys_xtal32m_switch_safe(void);
*/
void da1469x_clock_sys_rc32m_disable(void);
+/**
+ * Enable RC32M
+ */
+void da1469x_clock_sys_rc32m_enable(void);
+
+/**
+ * Switch sys_clk to RC32M
+ */
+void da1469x_clock_sys_rc32m_switch(void);
+
+/**
+ * Disable XTAL32K
+ */
+void da1469x_clock_lp_xtal32k_disable(void);
+
/**
* Enable XTAL32K
*/
@@ -73,6 +88,21 @@ void da1469x_clock_lp_xtal32k_enable(void);
*/
void da1469x_clock_lp_xtal32k_switch(void);
+/**
+ * Disable RC32K
+ */
+void da1469x_clock_lp_rc32k_disable(void);
+
+/**
+ * Enable RC32K
+ */
+void da1469x_clock_lp_rc32k_enable(void);
+
+/**
+ * Switch lp_clk to RC32K
+ */
+void da1469x_clock_lp_rc32k_switch(void);
+
/**
* Enable RCX
*/
@@ -95,10 +125,20 @@ void da1469x_clock_lp_rcx_calibrate(void);
*/
void da1469x_clock_lp_rc32k_calibrate(void);
+/**
+ * Calibrate XTAL32K
+ */
+void da1469x_clock_lp_xtal32k_calibrate(void);
+
+/**
+ * Calibrate selected LP clock
+ */
+void da1469x_clock_lp_calibrate(void);
+
/**
* Calibrate RC32M
*/
-void da1469x_clock_lp_rc32m_calibrate(void);
+void da1469x_clock_sys_rc32m_calibrate(void);
/**
* Get calibrated (measured) RCX frequency
@@ -110,16 +150,31 @@ uint32_t da1469x_clock_lp_rcx_freq_get(void);
*/
uint32_t da1469x_clock_lp_rc32k_freq_get(void);
+/**
+ * Get calibrated XTAL32K frequency
+ */
+uint32_t da1469x_clock_lp_xtal32k_freq_get(void);
+
+/**
+ * Get seleted LP clock's frequency
+ */
+uint32_t da1469x_clock_lp_freq_get(void);
+
/**
* Get calibrated (measured) RC32M frequency
*/
-uint32_t da1469x_clock_lp_rc32m_freq_get(void);
+uint32_t da1469x_clock_sys_rc32m_freq_get(void);
/**
* Disable RCX
*/
void da1469x_clock_lp_rcx_disable(void);
+/**
+ * Set the RTC dividers
+ */
+void da1469x_clock_lp_set_rtc_divs(uint32_t rtc_clock_freq);
+
/**
* Enable AMBA clock(s)
*
diff --git a/hw/mcu/dialog/da1469x/include/mcu/da1469x_hal.h
b/hw/mcu/dialog/da1469x/include/mcu/da1469x_hal.h
index 78e167528..2d0a17dc7 100755
--- a/hw/mcu/dialog/da1469x/include/mcu/da1469x_hal.h
+++ b/hw/mcu/dialog/da1469x/include/mcu/da1469x_hal.h
@@ -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
diff --git a/hw/mcu/dialog/da1469x/include/mcu/da1469x_lpclk.h
b/hw/mcu/dialog/da1469x/include/mcu/da1469x_lpclk.h
index 5f0ace4fc..27b75d1d2 100644
--- a/hw/mcu/dialog/da1469x/include/mcu/da1469x_lpclk.h
+++ b/hw/mcu/dialog/da1469x/include/mcu/da1469x_lpclk.h
@@ -33,6 +33,9 @@ void da1469x_lpclk_register_cmac_cb(da1469x_lpclk_cb *cb);
void da1469x_lpclk_enabled(void);
/* Frequency of lp clock changed (e.g. after RCX recalibration) */
void da1469x_lpclk_updated(void);
+/* Initialize selected LP RC clock */
+void da1469x_lpclk_rc_init();
+
#ifdef __cplusplus
}
diff --git a/hw/mcu/dialog/da1469x/src/da1469x_clock.c
b/hw/mcu/dialog/da1469x/src/da1469x_clock.c
index 114023f24..bf37a9ca2 100644
--- a/hw/mcu/dialog/da1469x/src/da1469x_clock.c
+++ b/hw/mcu/dialog/da1469x/src/da1469x_clock.c
@@ -29,39 +29,91 @@
#define XTAL32M_FREQ 32000000
#define RC32M_FREQ 32000000
+#define RC32M_FREQ_MIN 30600000
+#define RC32M_FREQ_MAX 32600000
+#define DIVN_FREQ 32000000 /* For CLK_CTRL_REG::SYS_CLK_SEL != 2 (LP
clock) */
+#define CAL_REF_FREQ DIVN_FREQ /* For CLK_REF_SEL_REG::CAL_CLK_SEL = 0
(DivN) */
#define PLL_FREQ 96000000
#define XTAL32K_FREQ 32768
+#define XTALRDY_IRQ_FREQ 256000 /* For XTALRDY_CTRL_REG::XTALRDY_CLK_SEL =
1 (256 kHz) */
+
+#define XTALRDY_IRQ_DIV (RC32M_FREQ / XTALRDY_IRQ_FREQ)
+#define XTALRDY_IRQ_FREQ_MAX (RC32M_FREQ_MAX / XTALRDY_IRQ_DIV)
+
+#define RTC_IN_FREQ_HZ 100
+#define RTC_DIV_FRAC_ADJ 10 /* For CLK_RTCDIV_REG::RTC_DIV_DENOM = 0
(1000) */
+
+enum da1469x_sys_clk_sel {
+ DA1469X_SYS_XTAL32M = 0,
+ DA1469X_SYS_RC32M,
+ DA1469X_SYS_LP_CLK,
+ DA1469X_SYS_PLL96M,
+};
+
+enum da1469x_xtalrdy_clk_sel {
+ DA1469X_XTALRDY_CLK_32K = 0,
+ DA1469X_XTALRDY_CLK_256K,
+};
+#define DA1469X_XTALRDY_CLK_SEL DA1469X_XTALRDY_CLK_256K
+
+enum da1469x_lp_clk_sel {
+ DA1469X_LP_RC32K = 0,
+ DA1469X_LP_RCX,
+ DA1469X_LP_XTAL32K,
+ DA1469X_LP_EXT,
+};
+
+enum da1469x_ref_sel {
+ DA1469X_REF_DIVN = 0,
+ DA1469X_REF_RC32M,
+ DA1469X_REF_RC32K,
+ DA1469X_REF_XTAL32K,
+ DA1469X_REF_RCOSC,
+};
+#define DA1469X_REF_SEL DA1469X_REF_DIVN
+
+enum da1469x_calib_sel {
+ DA1469X_CALIB_RC32K = 0,
+ DA1469X_CALIB_RC32M,
+ DA1469X_CALIB_XTAL32K,
+ DA1469X_CALIB_RCX,
+ DA1469X_CALIB_RCOSC,
+};
+
+enum da1469x_rtc_div_denom_sel {
+ DA1469X_RTC_DIV_DENOM_1000 = 0,
+ DA1469X_RTC_DIV_DENOM_1024,
+};
+#define DA1469X_RTC_DIV_DENOM_SEL DA1469X_RTC_DIV_DENOM_1000
static uint32_t g_mcu_clock_rcx_freq;
static uint32_t g_mcu_clock_rc32k_freq;
-static uint32_t g_mcu_clock_rc32m_freq;
+static uint32_t g_mcu_clock_rc32m_freq = RC32M_FREQ;
+static uint32_t g_mcu_clock_xtal32k_freq;
uint32_t SystemCoreClock = RC32M_FREQ;
static inline bool
da1469x_clock_is_xtal32m_settled(void)
{
- return ((*(uint32_t *)0x5001001c & 0xff00) == 0) &&
- ((*(uint32_t *)0x50010054 & 0x000f) != 0xb);
+ return ((CRG_XTAL->XTALRDY_STAT_REG &
CRG_XTAL_XTALRDY_STAT_REG_XTALRDY_COUNT_Msk) == 0) &&
+ ((CRG_XTAL->XTAL32M_STAT1_REG &
CRG_XTAL_XTAL32M_STAT1_REG_XTAL32M_STATE_Msk) != 0xb);
}
void
da1469x_clock_sys_xtal32m_init(void)
{
- uint32_t reg;
int xtalrdy_cnt;
/*
- * Number of 256kHz clock cycles (~4.085us) assuming worst case when
actual frequency is 244800.
- * RC32M is in range <30.6, 32.6> so 256Khz can ba as low as 30.6MHz / 125
= 244.8kHz.
+ * Number of XTALRDY IRQ timer clock cycles making up the desired xtal
settling time,
+ * sufficient even at maximum RC32M frequency.
*/
- xtalrdy_cnt = MYNEWT_VAL(MCU_CLOCK_XTAL32M_SETTLE_TIME_US) * 1000 / 4085;
+ xtalrdy_cnt = MYNEWT_VAL(MCU_CLOCK_XTAL32M_SETTLE_TIME_US) *
XTALRDY_IRQ_FREQ_MAX / 1000000;
- reg = CRG_XTAL->XTALRDY_CTRL_REG;
- reg &= ~(CRG_XTAL_XTALRDY_CTRL_REG_XTALRDY_CNT_Msk);
- reg |= CRG_XTAL_XTALRDY_CTRL_REG_XTALRDY_CLK_SEL_Msk;
- reg |= xtalrdy_cnt;
- CRG_XTAL->XTALRDY_CTRL_REG = reg;
+ CRG_XTAL->XTALRDY_CTRL_REG = ((xtalrdy_cnt <<
CRG_XTAL_XTALRDY_CTRL_REG_XTALRDY_CNT_Pos) &
+ CRG_XTAL_XTALRDY_CTRL_REG_XTALRDY_CNT_Msk) |
+ (DA1469X_XTALRDY_CLK_SEL <<
CRG_XTAL_XTALRDY_CTRL_REG_XTALRDY_CLK_SEL_Pos);
}
void
@@ -87,7 +139,9 @@ da1469x_clock_sys_xtal32m_switch(void)
if (CRG_TOP->CLK_CTRL_REG & CRG_TOP_CLK_CTRL_REG_RUNNING_AT_RC32M_Msk) {
CRG_TOP->CLK_SWITCH2XTAL_REG =
CRG_TOP_CLK_SWITCH2XTAL_REG_SWITCH2XTAL_Msk;
} else {
- CRG_TOP->CLK_CTRL_REG &= ~CRG_TOP_CLK_CTRL_REG_SYS_CLK_SEL_Msk;
+ CRG_TOP->CLK_CTRL_REG = (CRG_TOP->CLK_CTRL_REG &
+ ~CRG_TOP_CLK_CTRL_REG_SYS_CLK_SEL_Msk) |
+ (DA1469X_SYS_XTAL32M <<
CRG_TOP_CLK_CTRL_REG_SYS_CLK_SEL_Pos);
}
while (!(CRG_TOP->CLK_CTRL_REG &
CRG_TOP_CLK_CTRL_REG_RUNNING_AT_XTAL32M_Msk));
@@ -129,6 +183,30 @@ da1469x_clock_sys_rc32m_disable(void)
CRG_TOP->CLK_RC32M_REG &= ~CRG_TOP_CLK_RC32M_REG_RC32M_ENABLE_Msk;
}
+void
+da1469x_clock_sys_rc32m_enable(void)
+{
+ CRG_TOP->CLK_RC32M_REG |= CRG_TOP_CLK_RC32M_REG_RC32M_ENABLE_Msk;
+}
+
+void
+da1469x_clock_sys_rc32m_switch(void)
+{
+ CRG_TOP->CLK_CTRL_REG = (CRG_TOP->CLK_CTRL_REG &
+ ~CRG_TOP_CLK_CTRL_REG_SYS_CLK_SEL_Msk) |
+ (DA1469X_SYS_RC32M <<
CRG_TOP_CLK_CTRL_REG_SYS_CLK_SEL_Pos);
+
+ while (!(CRG_TOP->CLK_CTRL_REG &
CRG_TOP_CLK_CTRL_REG_RUNNING_AT_RC32M_Msk));
+
+ SystemCoreClock = g_mcu_clock_rc32m_freq;
+}
+
+void
+da1469x_clock_lp_xtal32k_disable(void)
+{
+ CRG_TOP->CLK_XTAL32K_REG &= ~CRG_TOP_CLK_XTAL32K_REG_XTAL32K_ENABLE_Msk;
+}
+
void
da1469x_clock_lp_xtal32k_enable(void)
{
@@ -140,13 +218,38 @@ da1469x_clock_lp_xtal32k_switch(void)
{
CRG_TOP->CLK_CTRL_REG = (CRG_TOP->CLK_CTRL_REG &
~CRG_TOP_CLK_CTRL_REG_LP_CLK_SEL_Msk) |
- (2 << CRG_TOP_CLK_CTRL_REG_LP_CLK_SEL_Pos);
+ (DA1469X_LP_XTAL32K <<
CRG_TOP_CLK_CTRL_REG_LP_CLK_SEL_Pos);
/* If system is running on LP clock update SystemCoreClock */
if (CRG_TOP->CLK_CTRL_REG & CRG_TOP_CLK_CTRL_REG_RUNNING_AT_LP_CLK_Msk) {
SystemCoreClock = XTAL32K_FREQ;
}
}
+void
+da1469x_clock_lp_rc32k_disable(void)
+{
+ CRG_TOP->CLK_RC32K_REG &= ~CRG_TOP_CLK_RC32K_REG_RC32K_ENABLE_Msk;
+}
+
+void
+da1469x_clock_lp_rc32k_enable(void)
+{
+ CRG_TOP->CLK_RC32K_REG |= CRG_TOP_CLK_RC32K_REG_RC32K_ENABLE_Msk;
+}
+
+void
+da1469x_clock_lp_rc32k_switch(void)
+{
+ CRG_TOP->CLK_CTRL_REG = (CRG_TOP->CLK_CTRL_REG &
+ ~CRG_TOP_CLK_CTRL_REG_LP_CLK_SEL_Msk) |
+ (DA1469X_LP_RC32K <<
CRG_TOP_CLK_CTRL_REG_LP_CLK_SEL_Pos);
+
+ /* If system is running on LP clock update SystemCoreClock */
+ if (CRG_TOP->CLK_CTRL_REG & CRG_TOP_CLK_CTRL_REG_RUNNING_AT_LP_CLK_Msk) {
+ SystemCoreClock = g_mcu_clock_rc32k_freq;
+ }
+}
+
void
da1469x_clock_lp_rcx_enable(void)
{
@@ -158,7 +261,7 @@ da1469x_clock_lp_rcx_switch(void)
{
CRG_TOP->CLK_CTRL_REG = (CRG_TOP->CLK_CTRL_REG &
~CRG_TOP_CLK_CTRL_REG_LP_CLK_SEL_Msk) |
- (1 << CRG_TOP_CLK_CTRL_REG_LP_CLK_SEL_Pos);
+ (DA1469X_LP_RCX <<
CRG_TOP_CLK_CTRL_REG_LP_CLK_SEL_Pos);
/* If system is running on LP clock update SystemCoreClock */
if (CRG_TOP->CLK_CTRL_REG & CRG_TOP_CLK_CTRL_REG_RUNNING_AT_LP_CLK_Msk) {
@@ -188,23 +291,31 @@ da1469x_clock_calibrate(uint8_t clock_sel, uint16_t
ref_cnt)
assert(!(ANAMISC_BIF->CLK_REF_SEL_REG &
ANAMISC_BIF_CLK_REF_SEL_REG_REF_CAL_START_Msk));
ANAMISC_BIF->CLK_REF_CNT_REG = ref_cnt;
- ANAMISC_BIF->CLK_REF_SEL_REG = (clock_sel <<
ANAMISC_BIF_CLK_REF_SEL_REG_REF_CLK_SEL_Pos) |
-
ANAMISC_BIF_CLK_REF_SEL_REG_REF_CAL_START_Msk;
+ /* Select reference clock & calibrated clock */
+ ANAMISC_BIF->CLK_REF_SEL_REG =
+ (DA1469X_REF_SEL << ANAMISC_BIF_CLK_REF_SEL_REG_CAL_CLK_SEL_Pos) |
+ ((clock_sel << ANAMISC_BIF_CLK_REF_SEL_REG_REF_CLK_SEL_Pos) &
+ ANAMISC_BIF_CLK_REF_SEL_REG_REF_CLK_SEL_Msk);
+
+ /* Start measurement */
+ ANAMISC_BIF->CLK_REF_SEL_REG |=
ANAMISC_BIF_CLK_REF_SEL_REG_REF_CAL_START_Msk;
+
+ /* Wait for meaurement to complete */
while (ANAMISC_BIF->CLK_REF_SEL_REG &
ANAMISC_BIF_CLK_REF_SEL_REG_REF_CAL_START_Msk);
ref_val = ANAMISC_BIF->CLK_REF_VAL_REG;
da1469x_pd_release(MCU_PD_DOMAIN_PER);
- return 32000000 * ref_cnt / ref_val;
+ return CAL_REF_FREQ * ref_cnt / ref_val;
}
void
da1469x_clock_lp_rcx_calibrate(void)
{
g_mcu_clock_rcx_freq =
- da1469x_clock_calibrate(3, MYNEWT_VAL(MCU_CLOCK_RCX_CAL_REF_CNT));
+ da1469x_clock_calibrate(DA1469X_CALIB_RCX,
MYNEWT_VAL(MCU_CLOCK_RCX_CAL_REF_CNT));
}
#define RC32K_TARGET_FREQ 32000
@@ -223,7 +334,7 @@ rc32k_trim_set(uint32_t trim)
{
CRG_TOP->CLK_RC32K_REG =
(CRG_TOP->CLK_RC32K_REG & ~CRG_TOP_CLK_RC32K_REG_RC32K_TRIM_Msk) |
- (trim << CRG_TOP_CLK_RC32K_REG_RC32K_TRIM_Pos);
+ ((trim << CRG_TOP_CLK_RC32K_REG_RC32K_TRIM_Pos) &
CRG_TOP_CLK_RC32K_REG_RC32K_TRIM_Msk);
}
void
@@ -252,7 +363,7 @@ da1469x_clock_lp_rc32k_calibrate(void)
freq_prev = freq;
freq_delta_prev = freq_delta;
- freq = da1469x_clock_calibrate(0,
MYNEWT_VAL(MCU_CLOCK_RC32K_CAL_REF_CNT));
+ freq = da1469x_clock_calibrate(DA1469X_CALIB_RC32K,
MYNEWT_VAL(MCU_CLOCK_RC32K_CAL_REF_CNT));
freq_delta = freq - RC32K_TARGET_FREQ;
freq_delta = (int32_t)freq_delta < 0 ? -freq_delta : freq_delta;
@@ -287,9 +398,33 @@ da1469x_clock_lp_rc32k_calibrate(void)
}
void
-da1469x_clock_lp_rc32m_calibrate(void)
+da1469x_clock_lp_xtal32k_calibrate(void)
+{
+#if MYNEWT_VAL(MCU_CLOCK_XTAL32K_ALLOW_CALIB)
+ g_mcu_clock_xtal32k_freq =
+ da1469x_clock_calibrate(DA1469X_CALIB_XTAL32K,
MYNEWT_VAL(MCU_CLOCK_XTAL32K_CAL_REF_CNT));
+#else
+ g_mcu_clock_xtal32k_freq = XTAL32K_FREQ;
+#endif
+}
+
+void
+da1469x_clock_lp_calibrate(void)
{
- g_mcu_clock_rc32m_freq = da1469x_clock_calibrate(1, 100);
+#if MYNEWT_VAL_CHOICE(MCU_LPCLK_SOURCE, RCX)
+ da1469x_clock_lp_rcx_calibrate();
+#elif MYNEWT_VAL_CHOICE(MCU_LPCLK_SOURCE, RC32K)
+ da1469x_clock_lp_rc32k_calibrate();
+#elif MYNEWT_VAL_CHOICE(MCU_LPCLK_SOURCE, XTAL32K)
+ da1469x_clock_lp_xtal32k_calibrate();
+#endif
+}
+
+void
+da1469x_clock_sys_rc32m_calibrate(void)
+{
+ g_mcu_clock_rc32m_freq = da1469x_clock_calibrate(DA1469X_CALIB_RC32M,
+
MYNEWT_VAL(MCU_CLOCK_RC32M_CAL_REF_CNT));
}
uint32_t
@@ -309,7 +444,27 @@ da1469x_clock_lp_rc32k_freq_get(void)
}
uint32_t
-da1469x_clock_lp_rc32m_freq_get(void)
+da1469x_clock_lp_xtal32k_freq_get(void)
+{
+ assert(g_mcu_clock_xtal32k_freq);
+
+ return g_mcu_clock_xtal32k_freq;
+}
+
+uint32_t
+da1469x_clock_lp_freq_get(void)
+{
+#if MYNEWT_VAL_CHOICE(MCU_LPCLK_SOURCE, RCX)
+ return da1469x_clock_lp_rcx_freq_get();
+#elif MYNEWT_VAL_CHOICE(MCU_LPCLK_SOURCE, RC32K)
+ return da1469x_clock_lp_rc32k_freq_get();
+#elif MYNEWT_VAL_CHOICE(MCU_LPCLK_SOURCE, XTAL32K)
+ return da1469x_clock_lp_xtal32k_freq_get();
+#endif
+}
+
+uint32_t
+da1469x_clock_sys_rc32m_freq_get(void)
{
assert(g_mcu_clock_rc32m_freq);
@@ -322,14 +477,26 @@ da1469x_clock_lp_rcx_disable(void)
CRG_TOP->CLK_RCX_REG &= ~CRG_TOP_CLK_RCX_REG_RCX_ENABLE_Msk;
}
+void
+da1469x_clock_lp_set_rtc_divs(uint32_t rtc_clock_freq)
+{
+ /* Please see the DA1469x Datasheet section 34.3 for details */
+ uint32_t reg;
+
+ reg = ((rtc_clock_freq % RTC_IN_FREQ_HZ) * RTC_DIV_FRAC_ADJ) <<
+ CRG_TOP_CLK_RTCDIV_REG_RTC_DIV_FRAC_Pos;
+ 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;
+ CRG_TOP->CLK_RTCDIV_REG = reg;
+}
+
static void
da1469x_delay_us(uint32_t delay_us)
{
- /*
- * SysTick runs on ~32 MHz clock while PLL is not started.
- * so multiplying by 32 to convert from us to SysTicks.
- */
- SysTick->LOAD = delay_us * 32;
+ /* Convert from us to SysTicks (PLL is not started yet) */
+ SysTick->LOAD = delay_us * XTAL32M_FREQ / 1000000;
SysTick->VAL = 0UL;
SysTick->CTRL = SysTick_CTRL_CLKSOURCE_Msk | SysTick_CTRL_ENABLE_Msk;
while (0 == (SysTick->CTRL & SysTick_CTRL_COUNTFLAG_Msk));
@@ -414,8 +581,9 @@ da1469x_clock_pll_wait_to_lock(void)
void
da1469x_clock_sys_pll_switch(void)
{
- /* CLK_SEL_Msk == 3 means PLL */
- CRG_TOP->CLK_CTRL_REG |= CRG_TOP_CLK_CTRL_REG_SYS_CLK_SEL_Msk;
+ CRG_TOP->CLK_CTRL_REG = (CRG_TOP->CLK_CTRL_REG &
+ ~CRG_TOP_CLK_CTRL_REG_SYS_CLK_SEL_Msk) |
+ (DA1469X_SYS_PLL96M <<
CRG_TOP_CLK_CTRL_REG_SYS_CLK_SEL_Pos);
while (!(CRG_TOP->CLK_CTRL_REG &
CRG_TOP_CLK_CTRL_REG_RUNNING_AT_PLL96M_Msk));
diff --git a/hw/mcu/dialog/da1469x/src/da1469x_lpclk.c
b/hw/mcu/dialog/da1469x/src/da1469x_lpclk.c
index 3b603cbf5..7cb3173b8 100644
--- a/hw/mcu/dialog/da1469x/src/da1469x_lpclk.c
+++ b/hw/mcu/dialog/da1469x/src/da1469x_lpclk.c
@@ -32,6 +32,7 @@
bool g_mcu_lpclk_available;
static da1469x_lpclk_cb *g_da1469x_lpclk_cmac_cb;
+static uint32_t g_lpclk_last_freq = 0;
#if MYNEWT_VAL_CHOICE(MCU_LPCLK_SOURCE, XTAL32K)
static void
@@ -45,15 +46,20 @@ da1469x_lpclk_settle_tmr_cb(void *arg)
static void
da1469x_lpclk_notify(void)
{
- if (!g_da1469x_lpclk_cmac_cb || !g_mcu_lpclk_available) {
- return;
- }
+ uint32_t lp_curr_freq;
-#if MYNEWT_VAL_CHOICE(MCU_LPCLK_SOURCE, XTAL32K)
- g_da1469x_lpclk_cmac_cb(32768);
-#elif MYNEWT_VAL_CHOICE(MCU_LPCLK_SOURCE, RCX)
- g_da1469x_lpclk_cmac_cb(da1469x_clock_lp_rcx_freq_get());
-#endif
+ lp_curr_freq = da1469x_clock_lp_freq_get();
+
+ if (lp_curr_freq != g_lpclk_last_freq) {
+ g_lpclk_last_freq = lp_curr_freq;
+
+ if (g_da1469x_lpclk_cmac_cb && g_mcu_lpclk_available) {
+ g_da1469x_lpclk_cmac_cb(lp_curr_freq);
+ }
+
+ da1469x_clock_lp_set_rtc_divs(lp_curr_freq);
+ hal_os_tick_calc_params(lp_curr_freq);
+ }
}
void
@@ -76,6 +82,31 @@ da1469x_lpclk_updated(void)
da1469x_lpclk_notify();
}
+void
+da1469x_lpclk_rc_init(void)
+{
+#if MYNEWT_VAL_CHOICE(MCU_LPCLK_SOURCE, RCX)
+ da1469x_clock_lp_rc32k_disable();
+ da1469x_clock_lp_rcx_enable();
+ da1469x_clock_lp_rcx_switch();
+ da1469x_clock_lp_calibrate();
+ da1469x_lpclk_enabled();
+#elif MYNEWT_VAL_CHOICE(MCU_LPCLK_SOURCE, RC32K)
+ da1469x_clock_lp_rcx_disable();
+ da1469x_clock_lp_rc32k_enable();
+ da1469x_clock_lp_rc32k_switch();
+ da1469x_clock_lp_calibrate();
+ da1469x_lpclk_enabled();
+#elif MYNEWT_VAL_CHOICE(MCU_LPCLK_SOURCE, XTAL32K)
+ /*
+ * We cannot switch lp_clk to XTAL32K here since it needs some time to
+ * settle, so we just disable RCX (we don't need it) and then we'll handle
+ * switch to XTAL32K from sysinit since we need os_cputime for this.
+ */
+ da1469x_clock_lp_rcx_disable();
+#endif
+}
+
void
da1469x_lpclk_init(void)
{
diff --git a/hw/mcu/dialog/da1469x/src/hal_os_tick.c
b/hw/mcu/dialog/da1469x/src/hal_os_tick.c
index 64bc53653..0673f4399 100644
--- a/hw/mcu/dialog/da1469x/src/hal_os_tick.c
+++ b/hw/mcu/dialog/da1469x/src/hal_os_tick.c
@@ -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;
};
@@ -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;
}
}
@@ -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);
}
@@ -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)
{
@@ -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);
}
@@ -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;
diff --git a/hw/mcu/dialog/da1469x/src/hal_system.c
b/hw/mcu/dialog/da1469x/src/hal_system.c
index 0a503915d..d326e26ef 100644
--- a/hw/mcu/dialog/da1469x/src/hal_system.c
+++ b/hw/mcu/dialog/da1469x/src/hal_system.c
@@ -125,23 +125,8 @@ hal_system_clock_start(void)
#endif
da1469x_clock_sys_rc32m_disable();
-#if MYNEWT_VAL_CHOICE(MCU_LPCLK_SOURCE, RCX)
- /* Switch to RCX and calibrate it */
- da1469x_clock_lp_rcx_enable();
- da1469x_clock_lp_rcx_switch();
- da1469x_clock_lp_rcx_calibrate();
- da1469x_lpclk_enabled();
-#else
- /*
- * We cannot switch lp_clk to XTAL32K here since it needs some time to
- * settle, so we just disable RCX (we don't need it) and then we'll handle
- * switch to XTAL32K from sysinit since we need os_cputime for this.
- */
- da1469x_clock_lp_rcx_disable();
-#endif
-
- /* TODO: we should calibrate this periodically */
- da1469x_clock_lp_rc32k_calibrate();
+ /* Initialize the selected RC LP clock */
+ da1469x_lpclk_rc_init();
}
enum hal_reset_reason
diff --git a/hw/mcu/dialog/da1469x/syscfg.yml b/hw/mcu/dialog/da1469x/syscfg.yml
index 5e808b69b..1c62e7064 100644
--- a/hw/mcu/dialog/da1469x/syscfg.yml
+++ b/hw/mcu/dialog/da1469x/syscfg.yml
@@ -67,6 +67,11 @@ syscfg.defs:
Specifies settling time [ms] of 32K crystal oscillator.
value: 8000
+ MCU_CLOCK_XTAL32K_ALLOW_CALIB:
+ description: >
+ Specifies that the 32K crystal oscillator should be calibrated.
+ value: 0
+
MCU_CLOCK_RCX_CAL_REF_CNT:
description: >
Reference count value for calibration of RCX clock. The higher
@@ -83,6 +88,18 @@ syscfg.defs:
value: 1
restrictions: '!0'
+ MCU_CLOCK_XTAL32K_CAL_REF_CNT:
+ description: >
+ Reference count value for calibration of XTAL32K clock.
+ value: 100
+ restrictions: '!0'
+
+ MCU_CLOCK_RC32M_CAL_REF_CNT:
+ description: >
+ Reference count value for calibration of RC32M clock.
+ value: 100
+ restrictions: '!0'
+
MCU_SYSCLK_SOURCE:
description: >
Specifies system clock source