CC26xx Driver Library
osc.c
Go to the documentation of this file.
1 /******************************************************************************
2 * Filename: osc.c
3 * Revised: 2015-11-18 16:59:03 +0100 (Wed, 18 Nov 2015)
4 * Revision: 45131
5 *
6 * Description: Driver for setting up the system Oscillators
7 *
8 * Copyright (c) 2015, Texas Instruments Incorporated
9 * All rights reserved.
10 *
11 * Redistribution and use in source and binary forms, with or without
12 * modification, are permitted provided that the following conditions are met:
13 *
14 * 1) Redistributions of source code must retain the above copyright notice,
15 * this list of conditions and the following disclaimer.
16 *
17 * 2) Redistributions in binary form must reproduce the above copyright notice,
18 * this list of conditions and the following disclaimer in the documentation
19 * and/or other materials provided with the distribution.
20 *
21 * 3) Neither the name of the ORGANIZATION nor the names of its contributors may
22 * be used to endorse or promote products derived from this software without
23 * specific prior written permission.
24 *
25 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
26 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
27 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
28 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
29 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
30 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
31 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
32 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
33 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
34 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
35 * POSSIBILITY OF SUCH DAMAGE.
36 *
37 ******************************************************************************/
38 
39 #include <inc/hw_types.h>
40 #include <inc/hw_ccfg.h>
41 #include <inc/hw_fcfg1.h>
42 #include <driverlib/aon_batmon.h>
43 #include <driverlib/aon_rtc.h>
44 #include <driverlib/osc.h>
45 
46 //*****************************************************************************
47 //
48 // Handle support for DriverLib in ROM:
49 // This section will undo prototype renaming made in the header file
50 //
51 //*****************************************************************************
52 #if !defined(DOXYGEN)
53  #undef OSCClockSourceSet
54  #define OSCClockSourceSet NOROM_OSCClockSourceSet
55  #undef OSCClockSourceGet
56  #define OSCClockSourceGet NOROM_OSCClockSourceGet
57  #undef OSCInterfaceEnable
58  #define OSCInterfaceEnable NOROM_OSCInterfaceEnable
59 #endif
60 
61 //*****************************************************************************
62 //
63 // OSCHF switch time calculator defines and globals
64 //
65 //*****************************************************************************
66 
67 #define RTC_CV_TO_MS(x) (( 1000 * ( x )) >> 16 )
68 #define RTC_CV_TO_US(x) (( 1000000 * ( x )) >> 16 )
69 
70 typedef struct {
72  uint32_t timeXoscOff_CV ;
73  uint32_t timeXoscOn_CV ;
74  uint32_t timeXoscStable_CV ;
75  int32_t tempXoscOff ;
77 
79 
80 //*****************************************************************************
81 //
82 // Configure the oscillator input to the a source clock.
83 //
84 //*****************************************************************************
85 void
86 OSCClockSourceSet(uint32_t ui32SrcClk, uint32_t ui32Osc)
87 {
88  //
89  // Check the arguments.
90  //
91  ASSERT((ui32SrcClk & OSC_SRC_CLK_LF) ||
92  (ui32SrcClk & OSC_SRC_CLK_MF) ||
93  (ui32SrcClk & OSC_SRC_CLK_HF));
94  ASSERT((ui32Osc == OSC_RCOSC_HF) ||
95  (ui32Osc == OSC_RCOSC_LF) ||
96  (ui32Osc == OSC_XOSC_HF) ||
97  (ui32Osc == OSC_XOSC_LF));
98 
99  //
100  // Request the high frequency source clock (using 24 MHz XTAL)
101  //
102  if(ui32SrcClk & OSC_SRC_CLK_HF)
103  {
104  //
105  // Enable the HF XTAL as HF clock source
106  //
110  ui32Osc);
111  }
112 
113  //
114  // Configure the medium frequency source clock
115  //
116  if(ui32SrcClk & OSC_SRC_CLK_MF)
117  {
121  ui32Osc);
122  }
123 
124  //
125  // Configure the low frequency source clock.
126  //
127  if(ui32SrcClk & OSC_SRC_CLK_LF)
128  {
129  //
130  // Change the clock source.
131  //
135  ui32Osc);
136  }
137 }
138 
139 //*****************************************************************************
140 //
141 // Get the source clock settings
142 //
143 //*****************************************************************************
144 uint32_t
145 OSCClockSourceGet(uint32_t ui32SrcClk)
146 {
147  uint32_t ui32ClockSource;
148 
149  //
150  // Check the arguments.
151  //
152  ASSERT((ui32SrcClk & OSC_SRC_CLK_LF) ||
153  (ui32SrcClk & OSC_SRC_CLK_HF));
154 
155  //
156  // Return the source for the selected clock.
157  //
158  if(ui32SrcClk == OSC_SRC_CLK_LF)
159  {
163  }
164  else
165  {
169  }
170  return (ui32ClockSource);
171 }
172 
173 //*****************************************************************************
174 //
175 // Enable System CPU access to the OSC_DIG module
176 //
177 //*****************************************************************************
178 void
180 {
181  //
182  // Force power on AUX to ensure CPU has access
183  //
186  { }
187 
188  //
189  // Enable the AUX domain OSC clock and wait for it to be ready
190  //
193  { }
194 }
195 
196 
197 //*****************************************************************************
198 //
199 // Returns maximum startup time (in microseconds) of XOSC_HF
200 //
201 //*****************************************************************************
202 uint32_t
203 OSCHF_GetStartupTime( uint32_t timeUntilWakeupInMs )
204 {
205  uint32_t deltaTimeSinceXoscOnInMs ;
206  int32_t deltaTempSinceXoscOn ;
207  uint32_t newStartupTimeInUs ;
208 
209  deltaTimeSinceXoscOnInMs = RTC_CV_TO_MS( AONRTCCurrentCompareValueGet() - oscHfGlobals.timeXoscOn_CV );
210  deltaTempSinceXoscOn = AONBatMonTemperatureGetDegC() - oscHfGlobals.tempXoscOff;
211 
212  if ( deltaTempSinceXoscOn < 0 ) {
213  deltaTempSinceXoscOn = -deltaTempSinceXoscOn;
214  }
215 
216  if ( (( timeUntilWakeupInMs + deltaTimeSinceXoscOnInMs ) > 3000 ) ||
217  ( deltaTempSinceXoscOn > 5 ) ||
218  ( oscHfGlobals.timeXoscStable_CV < oscHfGlobals.timeXoscOn_CV ) ||
219  ( oscHfGlobals.previousStartupTimeInUs == 0 ) )
220  {
221  newStartupTimeInUs = 2000;
223  newStartupTimeInUs = (( HWREG( CCFG_BASE + CCFG_O_MODE_CONF_1 ) &
226  // Note: CCFG startup time is "in units of 100us" adding 25% margin results in *125
227  }
228  } else {
229  newStartupTimeInUs = RTC_CV_TO_US( oscHfGlobals.timeXoscStable_CV - oscHfGlobals.timeXoscOn_CV );
230  newStartupTimeInUs += ( newStartupTimeInUs >> 2 ); // Add 25 percent margin
231  if ( newStartupTimeInUs < oscHfGlobals.previousStartupTimeInUs ) {
232  newStartupTimeInUs = oscHfGlobals.previousStartupTimeInUs;
233  }
234  }
235 
236  if ( newStartupTimeInUs < 200 ) {
237  newStartupTimeInUs = 200;
238  }
239  if ( newStartupTimeInUs > 4000 ) {
240  newStartupTimeInUs = 4000;
241  }
242  return ( newStartupTimeInUs );
243 }
244 
245 
246 //*****************************************************************************
247 //
248 // Turns on XOSC_HF (but without switching to XOSC_HF)
249 //
250 //*****************************************************************************
251 void
253 {
256 }
257 
258 
259 //*****************************************************************************
260 //
261 // Switch to XOSC_HF if XOSC_HF is ready.
262 //
263 //*****************************************************************************
264 bool
266 {
267  uint32_t startupTimeInUs;
268  uint32_t prevLimmit25InUs;
269 
271  // Already on XOSC - nothing to do
272  return ( 1 );
273  }
274  if ( OSCHfSourceReady()) {
276 
277  //
278  // Store startup time, but limit to 25 percent reduction each time.
279  //
281  startupTimeInUs = RTC_CV_TO_US( oscHfGlobals.timeXoscStable_CV - oscHfGlobals.timeXoscOn_CV );
282  prevLimmit25InUs = oscHfGlobals.previousStartupTimeInUs;
283  prevLimmit25InUs -= ( prevLimmit25InUs >> 2 ); // 25 percent margin
284  oscHfGlobals.previousStartupTimeInUs = startupTimeInUs;
285  if ( prevLimmit25InUs > startupTimeInUs ) {
286  oscHfGlobals.previousStartupTimeInUs = prevLimmit25InUs;
287  }
288  return ( 1 );
289  }
290  return ( 0 );
291 }
292 
293 
294 //*****************************************************************************
295 //
296 // Switch to RCOSC_HF and turn off XOSC_HF
297 //
298 //*****************************************************************************
299 void
301 {
302  //
303  // Set SCLK_HF and SCLK_MF to RCOSC_HF without checking
304  // Doing this anyway to keep HF and MF in sync
305  //
307 
308  //
309  // Do the switching if not already running on RCOSC_HF
310  //
313  }
314 
316  oscHfGlobals.tempXoscOff = AONBatMonTemperatureGetDegC();
317 }
318 
319 //*****************************************************************************
320 //
321 // Calculate the temperature dependent relative frequency offset of HPOSC
322 //
323 //*****************************************************************************
324 int32_t
326 {
327  // Estimate HPOSC frequency, using temperature and curve fitting parameters
328  uint32_t fitParams = HWREG(FCFG1_BASE + FCFG1_O_FREQ_OFFSET);
329  // Extract the P0,P1,P2 params, and sign extend them via shifting up/down
330  int32_t paramP0 = ((((int32_t) fitParams) << (32 - FCFG1_FREQ_OFFSET_HPOSC_COMP_P0_W - FCFG1_FREQ_OFFSET_HPOSC_COMP_P0_S))
331  >> (32 - FCFG1_FREQ_OFFSET_HPOSC_COMP_P0_W));
332  int32_t paramP1 = ((((int32_t) fitParams) << (32 - FCFG1_FREQ_OFFSET_HPOSC_COMP_P1_W - FCFG1_FREQ_OFFSET_HPOSC_COMP_P1_S))
333  >> (32 - FCFG1_FREQ_OFFSET_HPOSC_COMP_P1_W));
334  int32_t paramP2 = ((((int32_t) fitParams) << (32 - FCFG1_FREQ_OFFSET_HPOSC_COMP_P2_W - FCFG1_FREQ_OFFSET_HPOSC_COMP_P2_S))
335  >> (32 - FCFG1_FREQ_OFFSET_HPOSC_COMP_P2_W));
336  int32_t paramP3 = ((((int32_t) HWREG(FCFG1_BASE + FCFG1_O_MISC_CONF_2))
337  << (32 - FCFG1_MISC_CONF_2_HPOSC_COMP_P3_W - FCFG1_MISC_CONF_2_HPOSC_COMP_P3_S))
338  >> (32 - FCFG1_MISC_CONF_2_HPOSC_COMP_P3_W));
339 
340  // Now we can find the HPOSC freq offset, given as a signed variable d, expressed by:
341  //
342  // F_HPOSC = F_nom * (1 + d/(2^22)) , where: F_HPOSC = HPOSC frequency
343  // F_nom = nominal clock source frequency (e.g. 48.000 MHz)
344  // d = describes relative freq offset
345 
346  // We can estimate the d variable, using temperature compensation parameters:
347  //
348  // d = P0 + P1*(t - T0) + P2*(t - T0)^2 + P3*(t - T0)^3, where: P0,P1,P2,P3 are curve fitting parameters from FCFG1
349  // t = current temperature (from temp sensor) in deg C
350  // T0 = 27 deg C (fixed temperature constant)
351  int32_t tempDelta = (tempDegC - 27);
352  int32_t tempDeltaX2 = tempDelta * tempDelta;
353  int32_t d = paramP0 + ((tempDelta*paramP1)>>3) + ((tempDeltaX2*paramP2)>>10) + ((tempDeltaX2*tempDelta*paramP3)>>18);
354 
355  return ( d );
356 }
357 
358 //*****************************************************************************
359 //
360 // Converts the relative frequency offset of HPOSC to the RF Core parameter format.
361 //
362 //*****************************************************************************
363 int16_t
365 {
366  // The input argument, hereby referred to simply as "d", describes the frequency offset
367  // of the HPOSC relative to the nominal frequency in this way:
368  //
369  // F_HPOSC = F_nom * (1 + d/(2^22))
370  //
371  // But for use by the radio, to compensate the frequency error, we need to find the
372  // frequency offset "rfcFreqOffset" defined in the following format:
373  //
374  // F_nom = F_HPOSC * (1 + rfCoreFreqOffset/(2^22))
375  //
376  // To derive "rfCoreFreqOffset" from "d" we combine the two above equations and get:
377  //
378  // (1 + rfCoreFreqOffset/(2^22)) = (1 + d/(2^22))^-1
379  //
380  // Which can be rewritten into:
381  //
382  // rfCoreFreqOffset = -d*(2^22) / ((2^22) + d)
383  //
384  // = -d * [ 1 / (1 + d/(2^22)) ]
385  //
386  // To avoid doing a 64-bit division due to the (1 + d/(2^22))^-1 expression,
387  // we can use Taylor series (Maclaurin series) to approximate it:
388  //
389  // 1 / (1 - x) ~= 1 + x + x^2 + x^3 + x^4 + ... etc (Maclaurin series)
390  //
391  // In our case, we have x = - d/(2^22), and we only include up to the first
392  // order term of the series, as the second order term ((d^2)/(2^44)) is very small:
393  //
394  // freqError ~= -d + d^2/(2^22) (+ small approximation error)
395  //
396  // The approximation error is negligible for our use.
397 
398  int32_t rfCoreFreqOffset = -HPOSC_RelFreqOffset + (( HPOSC_RelFreqOffset * HPOSC_RelFreqOffset ) >> 22 );
399 
400  return ( rfCoreFreqOffset );
401 }
static void AONWUCAuxWakeupEvent(uint32_t ui32Mode)
Control the wake up procedure of the AUX domain.
Definition: aon_wuc.h:476
static uint32_t AONWUCPowerStatusGet(void)
Get the power status of the device.
Definition: aon_wuc.h:556
static void OSCHfSourceSwitch(void)
Switch the high frequency clock.
Definition: osc.h:314
void AUXWUCClockEnable(uint32_t ui32Clocks)
Enable clocks for peripherals in the AUX domain.
Definition: aux_wuc.c:64
#define OSC_SRC_CLK_MF
Definition: osc.h:107
#define AUX_WUC_OSCCTRL_CLOCK
Definition: aux_wuc.h:109
uint32_t timeXoscOff_CV
Definition: osc.c:72
uint32_t AUXWUCClockStatus(uint32_t ui32Clocks)
Get the status of a clock.
Definition: aux_wuc.c:162
uint32_t timeXoscStable_CV
Definition: osc.c:74
int32_t AONBatMonTemperatureGetDegC(void)
Get the current temperature measurement as a signed value in Deg Celsius.
Definition: aon_batmon.c:49
uint32_t OSCClockSourceGet(uint32_t ui32SrcClk)
Get the source clock settings.
Definition: osc.c:145
#define AUX_WUC_CLOCK_READY
Definition: aux_wuc.h:119
void DDI16BitfieldWrite(uint32_t ui32Base, uint32_t ui32Reg, uint32_t ui32Mask, uint32_t ui32Shift, uint16_t ui32Data)
Write a bitfield via the DDI using 16-bit maskable write.
Definition: ddi.c:108
void OSCInterfaceEnable(void)
Enable System CPU access to the OSC_DIG module.
Definition: osc.c:179
uint32_t OSCHF_GetStartupTime(uint32_t timeUntilWakeupInMs)
Returns maximum startup time (in microseconds) of XOSC_HF.
Definition: osc.c:203
#define AONWUC_AUX_POWER_ON
Definition: aon_wuc.h:172
#define OSC_SRC_CLK_HF
Definition: osc.h:106
bool OSCHF_AttemptToSwitchToXosc(void)
Switch to XOSC_HF if XOSC_HF is ready.
Definition: osc.c:265
#define OSC_RCOSC_HF
Definition: osc.h:110
static bool OSCHfSourceReady(void)
Check if the HF clock source is ready to be switched.
Definition: osc.h:284
#define OSC_XOSC_HF
Definition: osc.h:111
#define AONWUC_AUX_WAKEUP
Definition: aon_wuc.h:152
#define OSC_SRC_CLK_LF
Definition: osc.h:108
uint32_t previousStartupTimeInUs
Definition: osc.c:71
uint16_t DDI16BitfieldRead(uint32_t ui32Base, uint32_t ui32Reg, uint32_t ui32Mask, uint32_t ui32Shift)
Read a bitfield via the DDI using 16-bit read.
Definition: ddi.c:198
static OscHfGlobals_t oscHfGlobals
Definition: osc.c:78
#define ASSERT(expr)
Definition: debug.h:74
#define OSC_RCOSC_LF
Definition: osc.h:112
int32_t OSC_HPOSCRelativeFrequencyOffsetGet(int32_t tempDegC)
Calculate the temperature dependent relative frequency offset of HPOSC.
Definition: osc.c:325
int32_t tempXoscOff
Definition: osc.c:75
void OSCHF_SwitchToRcOscTurnOffXosc(void)
Switch to RCOSC_HF and turn off XOSC_HF.
Definition: osc.c:300
uint32_t timeXoscOn_CV
Definition: osc.c:73
#define RTC_CV_TO_US(x)
Definition: osc.c:68
uint32_t AONRTCCurrentCompareValueGet(void)
Get the current value of the RTC counter in a format that matches RTC compare values.
Definition: aon_rtc.c:62
void OSCClockSourceSet(uint32_t ui32SrcClk, uint32_t ui32Osc)
Configure the oscillator input to the a source clock.
Definition: osc.c:86
void OSCHF_TurnOnXosc(void)
Turns on XOSC_HF (but without switching to XOSC_HF).
Definition: osc.c:252
int16_t OSC_HPOSCRelativeFrequencyOffsetToRFCoreFormatConvert(int32_t HPOSC_RelFreqOffset)
Converts the relative frequency offset of HPOSC to the RF Core parameter format.
Definition: osc.c:364
#define OSC_XOSC_LF
Definition: osc.h:113
#define RTC_CV_TO_MS(x)
Definition: osc.c:67