1 /***************************************************************************//**
2 * @file
3 * @brief HFXO Manager API implementation.
4 *******************************************************************************
5 * # License
6 * <b>Copyright 2019 Silicon Laboratories Inc. www.silabs.com</b>
7 *******************************************************************************
8 *
9 * SPDX-License-Identifier: Zlib
10 *
11 * The licensor of this software is Silicon Laboratories Inc.
12 *
13 * This software is provided 'as-is', without any express or implied
14 * warranty. In no event will the authors be held liable for any damages
15 * arising from the use of this software.
16 *
17 * Permission is granted to anyone to use this software for any purpose,
18 * including commercial applications, and to alter it and redistribute it
19 * freely, subject to the following restrictions:
20 *
21 * 1. The origin of this software must not be misrepresented; you must not
22 * claim that you wrote the original software. If you use this software
23 * in a product, an acknowledgment in the product documentation would be
24 * appreciated but is not required.
25 * 2. Altered source versions must be plainly marked as such, and must not be
26 * misrepresented as being the original software.
27 * 3. This notice may not be removed or altered from any source distribution.
28 *
29 ******************************************************************************/
30
31 #include "em_device.h"
32 #include "sl_hfxo_manager.h"
33 #include "sli_hfxo_manager.h"
34 #include "sli_hfxo_manager_internal.h"
35 #include "sl_sleeptimer.h"
36 #include "sl_assert.h"
37 #include "sl_status.h"
38 #include <stdbool.h>
39
40 /*******************************************************************************
41 ********************************* DEFINES *********************************
42 ******************************************************************************/
43 // Table size of HFXO wake-up time measurement
44 #define HFXO_STARTUP_TIME_TABLE_SIZE 10
45
46 // Default time value in microseconds required to wake-up the hfxo oscillator.
47 #define HFXO_STARTUP_TIME_DEFAULT_VALUE_US (600u)
48
49 /*******************************************************************************
50 ***************************** DATA TYPES **********************************
51 ******************************************************************************/
52
53 /*******************************************************************************
54 *************************** LOCAL VARIABLES ********************************
55 ******************************************************************************/
56
57 // Time in ticks required for HFXO start-up after wake-up from sleep.
58 static uint32_t hfxo_startup_time_tick = 0;
59
60 static uint32_t hfxo_last_startup_time = 0;
61
62 static uint32_t hfxo_startup_time_table[HFXO_STARTUP_TIME_TABLE_SIZE];
63
64 static uint8_t hfxo_startup_time_table_index = 0;
65
66 static uint32_t hfxo_startup_time_sum_average = 0;
67
68 static uint32_t hfxo_startup_time_tc_inital = 0;
69
70 static bool hfxo_measurement_on = false;
71
72 /*******************************************************************************
73 ************************** GLOBAL FUNCTIONS *******************************
74 ******************************************************************************/
75
76 /***************************************************************************//**
77 * HFXO Manager module hardware specific initialization.
78 ******************************************************************************/
sl_hfxo_manager_init_hardware(void)79 void sl_hfxo_manager_init_hardware(void)
80 {
81 sli_hfxo_manager_init_hardware();
82 }
83
84 /***************************************************************************//**
85 * Initialize HFXO Manager module.
86 ******************************************************************************/
sl_hfxo_manager_init(void)87 sl_status_t sl_hfxo_manager_init(void)
88 {
89 sl_status_t status;
90
91 // Initialize Sleeptimer module in case not already done.
92 status = sl_sleeptimer_init();
93 if (status != SL_STATUS_OK) {
94 return status;
95 }
96
97 // Set HFXO startup time to conservative default value
98 hfxo_startup_time_tick = (((HFXO_STARTUP_TIME_DEFAULT_VALUE_US * sl_sleeptimer_get_timer_frequency()) + (1000000 - 1)) / 1000000);
99 for (uint8_t i = 0; i < HFXO_STARTUP_TIME_TABLE_SIZE; i++) {
100 hfxo_startup_time_table[i] = hfxo_startup_time_tick;
101 hfxo_startup_time_sum_average += hfxo_startup_time_tick;
102 }
103
104 return SL_STATUS_OK;
105 }
106
107 /***************************************************************************//**
108 * Updates Sleepy Crystal settings.
109 *
110 * @param settings Pointer to settings structure
111 *
112 * @return Status Code.
113 *
114 * @note Those settings are temporarily used to force oscillation on sleepy
115 * crystal.
116 * Default values should be enough to wake-up sleepy crystals. Otherwise,
117 * this function can be used.
118 ******************************************************************************/
sl_hfxo_manager_update_sleepy_xtal_settings(sl_hfxo_manager_sleepy_xtal_settings_t * settings)119 sl_status_t sl_hfxo_manager_update_sleepy_xtal_settings(sl_hfxo_manager_sleepy_xtal_settings_t *settings)
120 {
121 return sli_hfxo_manager_update_sleepy_xtal_settings_hardware(settings);
122 }
123
124 /***************************************************************************//**
125 * When this callback function is called, it means that HFXO failed twice in
126 * a row to start with normal configurations. This may mean that there is a
127 * bad crystal. When getting this callback, HFXO is running but its properties
128 * (frequency, precision) are not guaranteed. This should be considered as an
129 * error situation.
130 ******************************************************************************/
sl_hfxo_manager_notify_consecutive_failed_startups(void)131 __WEAK void sl_hfxo_manager_notify_consecutive_failed_startups(void)
132 {
133 EFM_ASSERT(false);
134 }
135
136 /*******************************************************************************
137 ********************** GLOBAL INTERNAL FUNCTIONS **************************
138 ******************************************************************************/
139
140 /***************************************************************************//**
141 * Function to call just before starting HFXO, to save current tick count.
142 ******************************************************************************/
sli_hfxo_manager_begin_startup_measurement(void)143 void sli_hfxo_manager_begin_startup_measurement(void)
144 {
145 hfxo_measurement_on = true;
146 hfxo_startup_time_tc_inital = sl_sleeptimer_get_tick_count();
147 }
148
149 /***************************************************************************//**
150 * Function to call just after HFXO becomes ready, to save current tick count
151 * and calculate HFXO startup time.
152 ******************************************************************************/
sli_hfxo_manager_end_startup_measurement(void)153 void sli_hfxo_manager_end_startup_measurement(void)
154 {
155 if (hfxo_measurement_on == false) {
156 return;
157 }
158
159 // Complete HFXO restore time measurement
160 hfxo_last_startup_time = sl_sleeptimer_get_tick_count() - hfxo_startup_time_tc_inital;
161
162 // With low precision clock, the HFXO startup time measure could be zero.
163 // In that case, ensure it's a least 1 tick.
164 hfxo_last_startup_time = (hfxo_last_startup_time == 0) ? 1 : hfxo_last_startup_time;
165
166 // Calculate average for HFXO restore time
167 hfxo_startup_time_sum_average -= (int32_t)hfxo_startup_time_table[hfxo_startup_time_table_index] - (int32_t)hfxo_last_startup_time;
168 hfxo_startup_time_table[hfxo_startup_time_table_index] = hfxo_last_startup_time;
169 hfxo_startup_time_tick = ((hfxo_startup_time_sum_average + (HFXO_STARTUP_TIME_TABLE_SIZE - 1) ) / HFXO_STARTUP_TIME_TABLE_SIZE);
170
171 // Update index of wakeup time table
172 hfxo_startup_time_table_index++;
173 hfxo_startup_time_table_index %= HFXO_STARTUP_TIME_TABLE_SIZE;
174
175 hfxo_measurement_on = false;
176 }
177
178 /***************************************************************************//**
179 * Retrieves HFXO startup time average value.
180 *
181 * @return HFXO startup time average value.
182 ******************************************************************************/
sli_hfxo_manager_get_startup_time(void)183 uint32_t sli_hfxo_manager_get_startup_time(void)
184 {
185 return hfxo_startup_time_tick;
186 }
187
188 /***************************************************************************//**
189 * Retrieves HFXO startup time latest value.
190 *
191 * @return HFXO startup time latest value.
192 ******************************************************************************/
sli_hfxo_manager_get_latest_startup_time(void)193 uint32_t sli_hfxo_manager_get_latest_startup_time(void)
194 {
195 return hfxo_last_startup_time;
196 }
197