1 /******************************************************************************
2 *  Filename:       osc.c
3 *  Revised:        2020-12-11 09:58:05 +0100 (Fri, 11 Dec 2020)
4 *  Revision:       59848
5 *
6 *  Description:    Driver for setting up the system Oscillators
7 *
8 *  Copyright (c) 2015 - 2020, 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 <stdlib.h>
40 #include "../inc/hw_types.h"
41 #include "../inc/hw_ccfg.h"
42 #include "../inc/hw_fcfg1.h"
43 #include "aon_batmon.h"
44 #include "aon_rtc.h"
45 #include "osc.h"
46 #include "sys_ctrl.h"
47 #include "setup_rom.h"
48 
49 //*****************************************************************************
50 //
51 // Handle support for DriverLib in ROM:
52 // This section will undo prototype renaming made in the header file
53 //
54 //*****************************************************************************
55 #if !defined(DOXYGEN)
56     #undef  OSCClockSourceSet
57     #define OSCClockSourceSet               NOROM_OSCClockSourceSet
58     #undef  OSCClockSourceGet
59     #define OSCClockSourceGet               NOROM_OSCClockSourceGet
60     #undef  OSCHF_GetStartupTime
61     #define OSCHF_GetStartupTime            NOROM_OSCHF_GetStartupTime
62     #undef  OSCHF_TurnOnXosc
63     #define OSCHF_TurnOnXosc                NOROM_OSCHF_TurnOnXosc
64     #undef  OSCHF_AttemptToSwitchToXosc
65     #define OSCHF_AttemptToSwitchToXosc     NOROM_OSCHF_AttemptToSwitchToXosc
66     #undef  OSCHF_SwitchToRcOscTurnOffXosc
67     #define OSCHF_SwitchToRcOscTurnOffXosc  NOROM_OSCHF_SwitchToRcOscTurnOffXosc
68     #undef  OSCHF_DebugGetCrystalAmplitude
69     #define OSCHF_DebugGetCrystalAmplitude  NOROM_OSCHF_DebugGetCrystalAmplitude
70     #undef  OSCHF_DebugGetExpectedAverageCrystalAmplitude
71     #define OSCHF_DebugGetExpectedAverageCrystalAmplitude NOROM_OSCHF_DebugGetExpectedAverageCrystalAmplitude
72     #undef  OSCHF_DebugGetCrystalStartupTime
73     #define OSCHF_DebugGetCrystalStartupTime NOROM_OSCHF_DebugGetCrystalStartupTime
74     #undef  OSC_HPOSCInitializeFrequencyOffsetParameters
75     #define OSC_HPOSCInitializeFrequencyOffsetParameters NOROM_OSC_HPOSCInitializeFrequencyOffsetParameters
76     #undef  OSC_HPOSC_Debug_InitFreqOffsetParams
77     #define OSC_HPOSC_Debug_InitFreqOffsetParams NOROM_OSC_HPOSC_Debug_InitFreqOffsetParams
78     #undef  OSC_HPOSCInitializeSingleInsertionFreqOffsParams
79     #define OSC_HPOSCInitializeSingleInsertionFreqOffsParams NOROM_OSC_HPOSCInitializeSingleInsertionFreqOffsParams
80     #undef  OSC_HPOSCRelativeFrequencyOffsetGet
81     #define OSC_HPOSCRelativeFrequencyOffsetGet NOROM_OSC_HPOSCRelativeFrequencyOffsetGet
82     #undef  OSC_AdjustXoscHfCapArray
83     #define OSC_AdjustXoscHfCapArray        NOROM_OSC_AdjustXoscHfCapArray
84     #undef  OSC_HPOSCRelativeFrequencyOffsetToRFCoreFormatConvert
85     #define OSC_HPOSCRelativeFrequencyOffsetToRFCoreFormatConvert NOROM_OSC_HPOSCRelativeFrequencyOffsetToRFCoreFormatConvert
86     #undef  OSC_HPOSCRtcCompensate
87     #define OSC_HPOSCRtcCompensate          NOROM_OSC_HPOSCRtcCompensate
88 #endif
89 
90 //*****************************************************************************
91 //
92 // OSCHF switch time calculator defines and globals
93 //
94 //*****************************************************************************
95 
96 #define RTC_CV_TO_MS(x) ((    1000 * ( x )) >> 16 )
97 #define RTC_CV_TO_US(x) (( 1000000 * ( x )) >> 16 )
98 
99 typedef struct {
100    uint32_t    previousStartupTimeInUs ;
101    uint32_t    timeXoscOff_CV          ;
102    uint32_t    timeXoscOn_CV           ;
103    uint32_t    timeXoscStable_CV       ;
104    int32_t     tempXoscOff             ;
105 } OscHfGlobals_t;
106 
107 static OscHfGlobals_t oscHfGlobals;
108 
109 //*****************************************************************************
110 //
111 //  Configure the oscillator input to the a source clock.
112 //
113 //*****************************************************************************
114 void
OSCClockSourceSet(uint32_t ui32SrcClk,uint32_t ui32Osc)115 OSCClockSourceSet(uint32_t ui32SrcClk, uint32_t ui32Osc)
116 {
117     // Check the arguments.
118     ASSERT((ui32SrcClk & OSC_SRC_CLK_LF) ||
119            (ui32SrcClk & OSC_SRC_CLK_HF));
120     ASSERT((ui32Osc == OSC_RCOSC_HF) ||
121            (ui32Osc == OSC_RCOSC_LF) ||
122            (ui32Osc == OSC_XOSC_HF) ||
123            (ui32Osc == OSC_XOSC_LF));
124 
125     // Request the high frequency source clock (using 24 MHz XTAL)
126     if(ui32SrcClk & OSC_SRC_CLK_HF)
127     {
128         // Enable the HF XTAL as HF clock source
129         DDI16BitfieldWrite(AUX_DDI0_OSC_BASE, DDI_0_OSC_O_CTL0,
130                            DDI_0_OSC_CTL0_SCLK_HF_SRC_SEL_M,
131                            DDI_0_OSC_CTL0_SCLK_HF_SRC_SEL_S,
132                            ui32Osc);
133     }
134 
135     // Configure the low frequency source clock.
136     if(ui32SrcClk & OSC_SRC_CLK_LF)
137     {
138         // Change the clock source.
139         DDI16BitfieldWrite(AUX_DDI0_OSC_BASE, DDI_0_OSC_O_CTL0,
140                            DDI_0_OSC_CTL0_SCLK_LF_SRC_SEL_M,
141                            DDI_0_OSC_CTL0_SCLK_LF_SRC_SEL_S,
142                            ui32Osc);
143     }
144 }
145 
146 //*****************************************************************************
147 //
148 //  Get the source clock settings
149 //
150 //*****************************************************************************
151 uint32_t
OSCClockSourceGet(uint32_t ui32SrcClk)152 OSCClockSourceGet(uint32_t ui32SrcClk)
153 {
154     uint32_t ui32ClockSource;
155 
156     // Check the arguments.
157     ASSERT((ui32SrcClk & OSC_SRC_CLK_LF) ||
158            (ui32SrcClk & OSC_SRC_CLK_HF));
159 
160     // Return the source for the selected clock.
161     if(ui32SrcClk == OSC_SRC_CLK_LF)
162     {
163         ui32ClockSource = DDI16BitfieldRead(AUX_DDI0_OSC_BASE, DDI_0_OSC_O_STAT0,
164                                             DDI_0_OSC_STAT0_SCLK_LF_SRC_M,
165                                             DDI_0_OSC_STAT0_SCLK_LF_SRC_S);
166     }
167     else
168     {
169         ui32ClockSource = DDI16BitfieldRead(AUX_DDI0_OSC_BASE, DDI_0_OSC_O_STAT0,
170                                             DDI_0_OSC_STAT0_SCLK_HF_SRC_M,
171                                             DDI_0_OSC_STAT0_SCLK_HF_SRC_S);
172     }
173     return (ui32ClockSource);
174 }
175 
176 //*****************************************************************************
177 //
178 // Returns maximum startup time (in microseconds) of XOSC_HF
179 //
180 //*****************************************************************************
181 uint32_t
OSCHF_GetStartupTime(uint32_t timeUntilWakeupInMs)182 OSCHF_GetStartupTime( uint32_t timeUntilWakeupInMs )
183 {
184    uint32_t deltaTimeSinceXoscOnInMs   ;
185    int32_t  deltaTempSinceXoscOn       ;
186    uint32_t newStartupTimeInUs         ;
187 
188     // Check CCFG to determine if device is configured for TCXO.
189     if( ( HWREG( CCFG_BASE + CCFG_O_MODE_CONF ) & CCFG_MODE_CONF_XOSC_FREQ_M ) == CCFG_MODE_CONF_XOSC_FREQ_TCXO )
190     {
191         // Device configured for TCXO. Report fixed startup time located in CCFG with
192         // coversion from number of 100us to number of us.
193         newStartupTimeInUs = (( HWREG( CCFG_BASE + CCFG_O_MODE_CONF_1 ) & CCFG_MODE_CONF_1_TCXO_MAX_START_M ) >>
194                                                                           CCFG_MODE_CONF_1_TCXO_MAX_START_S ) * 100;
195     }
196     else
197     {
198        deltaTimeSinceXoscOnInMs = RTC_CV_TO_MS( AONRTCCurrentCompareValueGet() - oscHfGlobals.timeXoscOn_CV );
199        deltaTempSinceXoscOn     = AONBatMonTemperatureGetDegC() - oscHfGlobals.tempXoscOff;
200 
201        if ( deltaTempSinceXoscOn < 0 ) {
202           deltaTempSinceXoscOn = -deltaTempSinceXoscOn;
203        }
204 
205        if (  (( timeUntilWakeupInMs + deltaTimeSinceXoscOnInMs )     > 3000 ) ||
206              ( deltaTempSinceXoscOn                                  >    5 ) ||
207              ( oscHfGlobals.timeXoscStable_CV < oscHfGlobals.timeXoscOn_CV  ) ||
208              ( oscHfGlobals.previousStartupTimeInUs                  ==   0 )    )
209        {
210           newStartupTimeInUs = 2000;
211           if (( HWREG( CCFG_BASE + CCFG_O_SIZE_AND_DIS_FLAGS ) & CCFG_SIZE_AND_DIS_FLAGS_DIS_XOSC_OVR_M ) == 0 ) {
212              newStartupTimeInUs = (( HWREG( CCFG_BASE + CCFG_O_MODE_CONF_1 ) &
213                 CCFG_MODE_CONF_1_XOSC_MAX_START_M ) >>
214                 CCFG_MODE_CONF_1_XOSC_MAX_START_S ) * 125;
215                 // Note: CCFG startup time is "in units of 100us" adding 25% margin results in *125
216           }
217        } else {
218           newStartupTimeInUs = RTC_CV_TO_US( oscHfGlobals.timeXoscStable_CV - oscHfGlobals.timeXoscOn_CV );
219           newStartupTimeInUs += ( newStartupTimeInUs >> 2 ); // Add 25 percent margin
220           if ( newStartupTimeInUs < oscHfGlobals.previousStartupTimeInUs ) {
221              newStartupTimeInUs = oscHfGlobals.previousStartupTimeInUs;
222           }
223        }
224 
225        if ( newStartupTimeInUs < 200 ) {
226           newStartupTimeInUs = 200;
227        }
228        if ( newStartupTimeInUs > 4000 ) {
229           newStartupTimeInUs = 4000;
230        }
231    }
232    return ( newStartupTimeInUs );
233 }
234 
235 
236 //*****************************************************************************
237 //
238 // Turns on XOSC_HF (but without switching to XOSC_HF)
239 //
240 //*****************************************************************************
241 void
OSCHF_TurnOnXosc(void)242 OSCHF_TurnOnXosc( void )
243 {
244 #if ( defined( ROM_OSCClockSourceSet ))
245    ROM_OSCClockSourceSet( OSC_SRC_CLK_HF, OSC_XOSC_HF );
246 #else
247    OSCClockSourceSet( OSC_SRC_CLK_HF, OSC_XOSC_HF );
248 #endif
249    oscHfGlobals.timeXoscOn_CV  = AONRTCCurrentCompareValueGet();
250 }
251 
252 
253 //*****************************************************************************
254 //
255 // Switch to XOSC_HF if XOSC_HF is ready.
256 //
257 //*****************************************************************************
258 bool
OSCHF_AttemptToSwitchToXosc(void)259 OSCHF_AttemptToSwitchToXosc( void )
260 {
261    uint32_t startupTimeInUs;
262    uint32_t prevLimmit25InUs;
263 
264 #if ( defined( ROM_OSCClockSourceGet ))
265    if ( ROM_OSCClockSourceGet( OSC_SRC_CLK_HF ) == OSC_XOSC_HF )
266 #else
267    if ( OSCClockSourceGet( OSC_SRC_CLK_HF ) == OSC_XOSC_HF )
268 #endif
269    {
270       // Already on XOSC - nothing to do
271       return ( 1 );
272    }
273    if ( OSCHfSourceReady()) {
274       OSCHfSourceSwitch();
275 
276       // Store startup time, but limit to 25 percent reduction each time.
277       oscHfGlobals.timeXoscStable_CV  = AONRTCCurrentCompareValueGet();
278       startupTimeInUs   = RTC_CV_TO_US( oscHfGlobals.timeXoscStable_CV - oscHfGlobals.timeXoscOn_CV );
279       prevLimmit25InUs  = oscHfGlobals.previousStartupTimeInUs;
280       prevLimmit25InUs -= ( prevLimmit25InUs >> 2 ); // 25 percent margin
281       oscHfGlobals.previousStartupTimeInUs = startupTimeInUs;
282       if ( prevLimmit25InUs > startupTimeInUs ) {
283          oscHfGlobals.previousStartupTimeInUs = prevLimmit25InUs;
284       }
285       return ( 1 );
286    }
287    return ( 0 );
288 }
289 
290 
291 //*****************************************************************************
292 //
293 // Switch to RCOSC_HF and turn off XOSC_HF
294 //
295 //*****************************************************************************
296 void
OSCHF_SwitchToRcOscTurnOffXosc(void)297 OSCHF_SwitchToRcOscTurnOffXosc( void )
298 {
299 #if ( defined( ROM_OSCClockSourceSet ))
300    ROM_OSCClockSourceSet( OSC_SRC_CLK_HF, OSC_RCOSC_HF );
301 #else
302    OSCClockSourceSet( OSC_SRC_CLK_HF, OSC_RCOSC_HF );
303 #endif
304 
305    // Do the switching if not already running on RCOSC_HF
306 #if ( defined( ROM_OSCClockSourceGet ))
307    if ( ROM_OSCClockSourceGet( OSC_SRC_CLK_HF ) != OSC_RCOSC_HF )
308 #else
309    if ( OSCClockSourceGet( OSC_SRC_CLK_HF ) != OSC_RCOSC_HF )
310 #endif
311    {
312       OSCHfSourceSwitch();
313    }
314 
315    oscHfGlobals.timeXoscOff_CV  = AONRTCCurrentCompareValueGet();
316    oscHfGlobals.tempXoscOff     = AONBatMonTemperatureGetDegC();
317 }
318 
319 //*****************************************************************************
320 //
321 // Adjust the XOSC HF cap array relative to the factory setting
322 //
323 //*****************************************************************************
324 void
OSC_AdjustXoscHfCapArray(int32_t capArrDelta)325 OSC_AdjustXoscHfCapArray( int32_t capArrDelta )
326 {
327    // read the MODE_CONF register in CCFG
328    uint32_t ccfg_ModeConfReg = HWREG( CCFG_BASE + CCFG_O_MODE_CONF );
329    // Clear CAP_MODE and the CAPARRAY_DELATA field
330    ccfg_ModeConfReg &= ~( CCFG_MODE_CONF_XOSC_CAPARRAY_DELTA_M | CCFG_MODE_CONF_XOSC_CAP_MOD_M );
331    // Insert new delta value
332    ccfg_ModeConfReg |= ((((uint32_t)capArrDelta) << CCFG_MODE_CONF_XOSC_CAPARRAY_DELTA_S ) & CCFG_MODE_CONF_XOSC_CAPARRAY_DELTA_M );
333    // Update the HW register with the new delta value
334    DDI32RegWrite(AUX_DDI0_OSC_BASE, DDI_0_OSC_O_ANABYPASSVAL1, SetupGetTrimForAnabypassValue1( ccfg_ModeConfReg ));
335 }
336 
337 //*****************************************************************************
338 //
339 // Initialize the frequency offset curve fitting parameters
340 // These are calculated based on the FCFG1:HPOSC_MEAS_x parameters.
341 //
342 //*****************************************************************************
343 #define  D1OFFSET_25C         (-16)
344 #define  D2OFFSET_85C         (-23)
345 #define  D3OFFSET_n40C        (5)
346 
347 #define  HPOSC_COEFF_BITS     (20) // HPOSC p1,p2,p3 coefficient precision
348 #define  HPOSC_COEFF0_BITS    (16) // HPOSC p0 coefficient precision
349 #define  HPOSC_D_BITS         (30) // HPOSC internal parameter
350 #define  HPOSC_COEFF0_SHIFT   (HPOSC_COEFF_BITS - HPOSC_COEFF0_BITS) // HPOSC internal parameter
351 #define  HPOSC_SHIFT1         (2*HPOSC_COEFF_BITS - HPOSC_D_BITS) // HPOSC internal parameter
352 #define  HPOSC_DC_BIAS        (100000) // HPOSC internal parameter
353 
354 int32_t _hposcCoeffs[4] = {0};  // HPOSC polynomial coefficients
355 
356 typedef struct
357 {
358     int32_t temp[3];
359     int32_t dFreq[3];
360 } hposc_insertions_t;
361 
362 typedef struct
363 {
364     uint8_t pu0b[4];
365     uint8_t pu1b[4];
366     uint8_t pu2b[4];
367     int64_t pu0c[4];
368     int64_t pu1c[4];
369     int64_t pu2c[4];
370 } hposc_param_t;
371 
372 static void
multiplyColumns(int64_t * v1,int64_t * v2,int64_t * pBuf,uint8_t shift)373 multiplyColumns(int64_t *v1, int64_t *v2, int64_t *pBuf, uint8_t shift)
374 {
375     pBuf[0] = (v1[1]*v2[2]) >> shift;
376     pBuf[1] = (v1[2]*v2[1]) >> shift;
377     pBuf[2] = (v1[0]*v2[2]) >> shift;
378     pBuf[3] = (v1[2]*v2[0]) >> shift;
379     pBuf[4] = (v1[0]*v2[1]) >> shift;
380     pBuf[5] = (v1[1]*v2[0]) >> shift;
381 }
382 
383 static int64_t
findDenominator(int64_t * col0,int64_t * col1,int64_t * col2)384 findDenominator(int64_t *col0, int64_t *col1, int64_t *col2)
385 {
386     int64_t tmp, tmpBuf[6];
387 
388     multiplyColumns(col1, col2, tmpBuf, HPOSC_SHIFT1); // Keep HPOSC_D_BITS precision
389 
390     tmp = (tmpBuf[0]*col0[0] - tmpBuf[1]*col0[0] - tmpBuf[2]*col0[1] +
391            tmpBuf[3]*col0[1] + tmpBuf[4]*col0[2] - tmpBuf[5]*col0[2]) >> HPOSC_COEFF_BITS;
392 
393     return tmp;
394 }
395 
396 static int64_t
findNumerator(int32_t * pInput,int64_t * pBuf)397 findNumerator(int32_t *pInput, int64_t *pBuf)
398 {
399     int64_t tmp;
400 
401     tmp = ((int64_t)pInput[0]*pBuf[0]) - ((int64_t)pInput[0]*pBuf[1]) - ((int64_t)pInput[1]*pBuf[2]) +
402           ((int64_t)pInput[1]*pBuf[3]) + ((int64_t)pInput[2]*pBuf[4]) - ((int64_t)pInput[2]*pBuf[5]);
403 
404     return tmp;
405 }
406 
407 static void
findHposcCoefficients(int32_t * pInput,int64_t * col0,int64_t * col1,int64_t * col2,hposc_param_t * pParam)408 findHposcCoefficients(int32_t *pInput, int64_t *col0, int64_t *col1, int64_t *col2, hposc_param_t *pParam)
409 {
410     int64_t d,c0,c1,c2,cn,tmpBuf[6];
411     int32_t inputBuf[3];
412     uint8_t i;
413 
414     if(col1 == NULL) /* 1 insertion */
415     {
416         inputBuf[0] = pInput[0] - HPOSC_DC_BIAS;
417         c0 = (((int64_t)inputBuf[0] << HPOSC_D_BITS) / col0[0]);
418         c1 = 0;
419         c2 = 0;
420     }
421     else /* 3 insertion */
422     {
423         /* Apply DC bias to input data */
424         for(i = 0; i < 3; i++)
425         {
426             inputBuf[i] = pInput[i] - HPOSC_DC_BIAS;
427         }
428 
429         /* Solve intermediate parameters, d: HPOSC_D_BITS, c: HPOSC_COEFF_BITS*2 bits */
430         d = findDenominator(col0, col1, col2);
431 
432         multiplyColumns(col1, col2, tmpBuf, 0);
433         cn = findNumerator(inputBuf, tmpBuf);
434         c0 = cn / d;
435 
436         multiplyColumns(col0, col2, tmpBuf, 0);
437         cn = -1*findNumerator(inputBuf, tmpBuf);
438         c1 = cn / d;
439 
440         multiplyColumns(col0, col1, tmpBuf, 0);
441         cn = findNumerator(inputBuf, tmpBuf);
442         c2 = cn / d;
443     }
444 
445     /* Compute TCF polynomial coefficients */
446     for(i = 0; i < 4; i++)
447     {
448         cn = (((pParam->pu0c[i]*c0) >> (pParam->pu0b[i] - HPOSC_COEFF_BITS)) +
449               ((pParam->pu1c[i]*c1) >> (pParam->pu1b[i] - HPOSC_COEFF_BITS)) +
450               ((pParam->pu2c[i]*c2) >> (pParam->pu2b[i] - HPOSC_COEFF_BITS))) >> HPOSC_SHIFT1;
451 
452         if(i<3)
453         {
454             _hposcCoeffs[3-i] = cn;
455         }
456         else
457         {
458             _hposcCoeffs[0] = (cn >> HPOSC_COEFF0_SHIFT) + ((int64_t)HPOSC_DC_BIAS << HPOSC_COEFF0_BITS); // p[0] is combined with the DC bias
459         }
460     }
461 }
462 
463 static void
findHposcPc(int64_t * pCoeff,uint8_t * pBits,int32_t * pTemp,uint8_t nTemp,int64_t * pOutput)464 findHposcPc(int64_t *pCoeff, uint8_t *pBits, int32_t *pTemp, uint8_t nTemp, int64_t *pOutput)
465 {
466     uint8_t i;
467     int32_t t1,t2,t3;
468 
469     for(i = 0; i < nTemp; i++)
470     {
471         t1 = pTemp[i];
472         t2 = t1*t1;
473         t3 = t2*t1;
474 
475         pOutput[i] = (((int64_t)pCoeff[0]*t3)>>(pBits[0]-HPOSC_COEFF_BITS)) + (((int64_t)pCoeff[1]*t2)>>(pBits[1]-HPOSC_COEFF_BITS)) +
476                      (((int64_t)pCoeff[2]*t1)>>(pBits[2]-HPOSC_COEFF_BITS)) + (((int64_t)pCoeff[3]   )>>(pBits[3]-HPOSC_COEFF_BITS));
477     }
478 }
479 
480 static void
readTempAndFreq(uint32_t regAddr,int32_t * pTemp,int32_t * pdFreq,int32_t deltaFreq)481 readTempAndFreq(uint32_t regAddr, int32_t *pTemp, int32_t *pdFreq, int32_t deltaFreq)
482 {
483     uint32_t insertionData = HWREG(regAddr);
484 
485     /* temp_stored = Temperature - 27, offset by -27C */
486     *pTemp = (((int32_t)( insertionData << ( 32 - FCFG1_HPOSC_MEAS_1_HPOSC_T1_W - FCFG1_HPOSC_MEAS_1_HPOSC_T1_S )))
487                                         >> ( 32 - FCFG1_HPOSC_MEAS_1_HPOSC_T1_W ));
488 
489     /* dFreq_stored = round( (Freq/12e6 - 1) * 2^22 ), 12MHz is the ideal frequency */
490     *pdFreq = (((int32_t)( insertionData << ( 32 - FCFG1_HPOSC_MEAS_1_HPOSC_D1_W - FCFG1_HPOSC_MEAS_1_HPOSC_D1_S )))
491                                          >> ( 32 - FCFG1_HPOSC_MEAS_1_HPOSC_D1_W ));
492     *pdFreq = *pdFreq + deltaFreq;
493 }
494 
495 //*****************************************************************************
496 // The HPOSC initialization function
497 // - Must be called before using HPOSC
498 // - To be used when three temperature frequency offset measurements are available
499 //*****************************************************************************
500 void
OSC_HPOSCInitializeFrequencyOffsetParameters(void)501 OSC_HPOSCInitializeFrequencyOffsetParameters( void )
502 {
503     /* Initialize HPOSC internal parameter */
504     hposc_insertions_t  hposcMeas;
505     int64_t pu0[3],pu1[3],pu2[3] = {0};
506     hposc_param_t hposcParm =
507     {
508         .pu0b = {42, 32, 27, 20},
509         .pu0c = {-284,-184,536,-104798},
510         .pu1b = {36, 32, 27, 20},
511         .pu1c = {-1155,44130,-319090,-3563},
512         .pu2b = {36, 32, 27, 20},
513         .pu2c = {-3410,261727,-32194,-116627}
514     };
515 
516     /* Retrieve insertions from FCFG */
517     readTempAndFreq(FCFG1_BASE + FCFG1_O_HPOSC_MEAS_1, &hposcMeas.temp[0], &hposcMeas.dFreq[0], D1OFFSET_25C);
518     readTempAndFreq(FCFG1_BASE + FCFG1_O_HPOSC_MEAS_2, &hposcMeas.temp[1], &hposcMeas.dFreq[1], D2OFFSET_85C);
519     readTempAndFreq(FCFG1_BASE + FCFG1_O_HPOSC_MEAS_3, &hposcMeas.temp[2], &hposcMeas.dFreq[2], D3OFFSET_n40C);
520 
521     /* Compute HPOSC polynomial coefficients */
522     findHposcPc(hposcParm.pu0c, hposcParm.pu0b, &hposcMeas.temp[0], 3, pu0);
523     findHposcPc(hposcParm.pu1c, hposcParm.pu1b, &hposcMeas.temp[0], 3, pu1);
524     findHposcPc(hposcParm.pu2c, hposcParm.pu2b, &hposcMeas.temp[0], 3, pu2);
525     findHposcCoefficients(&hposcMeas.dFreq[0], pu0, pu1, pu2, &hposcParm);
526 }
527 
528 //*****************************************************************************
529 // Degub function to calculate the HPOSC polynomials for experimental data sets.
530 //*****************************************************************************
531 void
OSC_HPOSC_Debug_InitFreqOffsetParams(HposcDebugData_t * pDebugData)532 OSC_HPOSC_Debug_InitFreqOffsetParams( HposcDebugData_t * pDebugData )
533 {
534     /* Initialize HPOSC internal parameter */
535     hposc_insertions_t  hposcMeas;
536     int64_t pu0[3],pu1[3],pu2[3] = {0};
537     hposc_param_t hposcParm =
538     {
539         .pu0b = {42, 32, 27, 20},
540         .pu0c = {-284,-184,536,-104798},
541         .pu1b = {36, 32, 27, 20},
542         .pu1c = {-1155,44130,-319090,-3563},
543         .pu2b = {36, 32, 27, 20},
544         .pu2c = {-3410,261727,-32194,-116627}
545     };
546 
547     /* Retrieve insertions from FCFG */
548     readTempAndFreq((uint32_t)&pDebugData->meas_1, &hposcMeas.temp[0], &hposcMeas.dFreq[0], pDebugData->offsetD1);
549     readTempAndFreq((uint32_t)&pDebugData->meas_2, &hposcMeas.temp[1], &hposcMeas.dFreq[1], pDebugData->offsetD2);
550     readTempAndFreq((uint32_t)&pDebugData->meas_3, &hposcMeas.temp[2], &hposcMeas.dFreq[2], pDebugData->offsetD3);
551 
552     /* Compute HPOSC polynomial coefficients */
553     findHposcPc(hposcParm.pu0c, hposcParm.pu0b, &hposcMeas.temp[0], 3, pu0);
554     findHposcPc(hposcParm.pu1c, hposcParm.pu1b, &hposcMeas.temp[0], 3, pu1);
555     findHposcPc(hposcParm.pu2c, hposcParm.pu2b, &hposcMeas.temp[0], 3, pu2);
556     findHposcCoefficients(&hposcMeas.dFreq[0], pu0, pu1, pu2, &hposcParm);
557 }
558 
559 //*****************************************************************************
560 // Special HPOSC initialization function
561 // - Used when a single temperature offset measurement is available
562 // - To get a better crystal performance (SW TCXO)
563 //*****************************************************************************
564 void
OSC_HPOSCInitializeSingleInsertionFreqOffsParams(uint32_t measFieldAddress)565 OSC_HPOSCInitializeSingleInsertionFreqOffsParams( uint32_t measFieldAddress )
566 {
567     /* Initialize HPOSC internal parameter */
568     hposc_insertions_t  hposcMeas;
569     int64_t pu0;
570     hposc_param_t hposcParm =
571     {
572         /* Coefficients for SW-TCXO */
573         .pu0b = {44, 44, 27, 20},
574         .pu0c = {7322, -5021, -209, -104861}
575     };
576 
577     /* Retrieve insertions from FCFG */
578     readTempAndFreq( measFieldAddress, &hposcMeas.temp[0], &hposcMeas.dFreq[0], 0);
579 
580     /* Compute HPOSC polynomial coefficients */
581     findHposcPc(hposcParm.pu0c, hposcParm.pu0b, &hposcMeas.temp[0], 1, &pu0);
582     findHposcCoefficients(&hposcMeas.dFreq[0], &pu0, NULL, NULL, &hposcParm);
583 }
584 
585 //*****************************************************************************
586 //
587 // Calculate the temperature dependent relative frequency offset of HPOSC
588 //
589 //*****************************************************************************
590 int32_t
OSC_HPOSCRelativeFrequencyOffsetGet(int32_t tempDegC)591 OSC_HPOSCRelativeFrequencyOffsetGet( int32_t tempDegC )
592 {
593     // Estimate HPOSC frequency offset, using temperature and curve fitting parameters
594 
595     // Now we can find the HPOSC freq offset, given as a signed variable d, expressed by:
596     //
597     //    F_HPOSC = F_nom * (1 + d/(2^22))    , where: F_HPOSC = HPOSC frequency
598     //                                                 F_nom = nominal clock source frequency (e.g. 48.000 MHz)
599     //                                                 d = describes relative freq offset
600 
601     // We can estimate the d variable, using temperature compensation parameters:
602     //
603     //    d = P[3]*(t - T0)^3 + P[2]*(t - T0)^2 + P[1]*(t - T0) + P[0], where: P0,P1,P2,P3 are curve fitting parameters
604     //                                                                  t = current temperature (from temp sensor) in deg C
605     //                                                                  T0 = 27 deg C (fixed temperature constant)
606 
607     int32_t d,t1,t2,t3;
608 
609     t1 = tempDegC - 27;
610     t2 = t1 * t1;
611     t3 = t2 * t1;
612 
613     d =  ((((int64_t)_hposcCoeffs[3]*t3 + (int64_t)_hposcCoeffs[2]*t2 + (int64_t)_hposcCoeffs[1]*t1) >> HPOSC_COEFF0_SHIFT) +
614             (int64_t)_hposcCoeffs[0]) >> HPOSC_COEFF0_BITS;
615 
616     return ( d );
617 }
618 
619 //*****************************************************************************
620 //
621 // Converts the relative frequency offset of HPOSC to the RF Core parameter format.
622 //
623 //*****************************************************************************
624 int16_t
OSC_HPOSCRelativeFrequencyOffsetToRFCoreFormatConvert(int32_t HPOSC_RelFreqOffset)625 OSC_HPOSCRelativeFrequencyOffsetToRFCoreFormatConvert( int32_t HPOSC_RelFreqOffset )
626 {
627    // The input argument, hereby referred to simply as "d", describes the frequency offset
628    // of the HPOSC relative to the nominal frequency in this way:
629    //
630    //    F_HPOSC = F_nom * (1 + d/(2^22))
631    //
632    // But for use by the radio, to compensate the frequency error, we need to find the
633    // frequency offset "rfcFreqOffset" defined in the following format:
634    //
635    //    F_nom = F_HPOSC * (1 + rfCoreFreqOffset/(2^22))
636    //
637    // To derive "rfCoreFreqOffset" from "d" we combine the two above equations and get:
638    //
639    //    (1 + rfCoreFreqOffset/(2^22)) = (1 + d/(2^22))^-1
640    //
641    // Which can be rewritten into:
642    //
643    //    rfCoreFreqOffset = -d*(2^22) / ((2^22) + d)
644    //
645    //               = -d * [ 1 / (1 + d/(2^22)) ]
646    //
647    // To avoid doing a 64-bit division due to the (1 + d/(2^22))^-1 expression,
648    // we can use Taylor series (Maclaurin series) to approximate it:
649    //
650    //       1 / (1 - x) ~= 1 + x + x^2 + x^3 + x^4 + ... etc      (Maclaurin series)
651    //
652    // In our case, we have x = - d/(2^22), and we only include up to the first
653    // order term of the series, as the second order term ((d^2)/(2^44)) is very small:
654    //
655    //       freqError ~= -d + d^2/(2^22)   (+ small approximation error)
656    //
657    // The approximation error is negligible for our use.
658 
659    int32_t rfCoreFreqOffset = -HPOSC_RelFreqOffset + (( HPOSC_RelFreqOffset * HPOSC_RelFreqOffset ) >> 22 );
660 
661    return ( rfCoreFreqOffset );
662 }
663 
664 //*****************************************************************************
665 //
666 // Compensate the RTC increment based on the relative frequency offset of HPOSC
667 //
668 //*****************************************************************************
669 void
OSC_HPOSCRtcCompensate(int32_t relFreqOffset)670 OSC_HPOSCRtcCompensate( int32_t relFreqOffset )
671 {
672     uint32_t rtcSubSecInc;
673     uint32_t lfClkFrequency;
674     uint32_t hfFreq;
675     int64_t  calcFactor;
676 
677     // Calculate SCLK_HF frequency, defined as:
678     // hfFreq = 48000000 * (1 + relFreqOffset/(2^22))
679     if( relFreqOffset >= 0 )
680     {
681         calcFactor = ( ( 48000000 * (int64_t)relFreqOffset ) + 0x200000 ) / 0x400000;
682     }
683     else
684     {
685         calcFactor = ( ( 48000000 * (int64_t)relFreqOffset ) - 0x200000 ) / 0x400000;
686     }
687     hfFreq = 48000000 + calcFactor;
688 
689     // Calculate SCLK_LF frequency, defined as SCLK_LF_FREQ = SCLK_HF_FREQ / 1536
690     lfClkFrequency = ( hfFreq + 768 ) / 1536;
691 
692     // Calculate SUBSECINC, defined as: SUBSECINC = 2^38 / SCLK_LF_FREQ
693     rtcSubSecInc = 0x4000000000 / lfClkFrequency;
694 
695     /* Update SUBSECINC value */
696     SetupSetAonRtcSubSecInc(rtcSubSecInc);
697 }
698 
699 //*****************************************************************************
700 //
701 // Get crystal amplitude (assuming crystal is running).
702 //
703 //*****************************************************************************
704 uint32_t
OSCHF_DebugGetCrystalAmplitude(void)705 OSCHF_DebugGetCrystalAmplitude( void )
706 {
707    uint32_t oscCfgRegCopy  ;
708    uint32_t startTime      ;
709    uint32_t deltaTime      ;
710    uint32_t ampValue       ;
711 
712    // The specified method is as follows:
713    // 1. Set minimum interval between oscillator amplitude calibrations.
714    //    (Done by setting PER_M=0 and PER_E=1)
715    // 2. Wait approximately 4 milliseconds in order to measure over a
716    //    moderately large number of calibrations.
717    // 3. Read out the crystal amplitude value from the peek detector.
718    // 4. Restore original oscillator amplitude calibrations interval.
719    // 5. Return crystal amplitude value converted to millivolt.
720    oscCfgRegCopy = HWREG( AON_PMCTL_BASE + AON_PMCTL_O_OSCCFG );
721    HWREG( AON_PMCTL_BASE + AON_PMCTL_O_OSCCFG ) = ( 1 << AON_PMCTL_OSCCFG_PER_E_S );
722    startTime = AONRTCCurrentCompareValueGet();
723    do {
724       deltaTime = AONRTCCurrentCompareValueGet() - startTime;
725    } while ( deltaTime < ((uint32_t)( 0.004 * FACTOR_SEC_TO_COMP_VAL_FORMAT )));
726    ampValue = ( HWREG( AUX_DDI0_OSC_BASE + DDI_0_OSC_O_STAT1 ) &
727       DDI_0_OSC_STAT1_HPM_UPDATE_AMP_M ) >>
728       DDI_0_OSC_STAT1_HPM_UPDATE_AMP_S ;
729    HWREG( AON_PMCTL_BASE + AON_PMCTL_O_OSCCFG ) = oscCfgRegCopy;
730 
731    return ( ampValue * 15 );
732 }
733 
734 //*****************************************************************************
735 //
736 // Get the expected average crystal amplitude.
737 //
738 //*****************************************************************************
739 uint32_t
OSCHF_DebugGetExpectedAverageCrystalAmplitude(void)740 OSCHF_DebugGetExpectedAverageCrystalAmplitude( void )
741 {
742    uint32_t ampCompTh1    ;
743    uint32_t highThreshold ;
744    uint32_t lowThreshold  ;
745 
746    ampCompTh1 = HWREG( AUX_DDI0_OSC_BASE + DDI_0_OSC_O_AMPCOMPTH1 );
747    highThreshold = ( ampCompTh1 & DDI_0_OSC_AMPCOMPTH1_HPMRAMP3_HTH_M ) >>
748                                   DDI_0_OSC_AMPCOMPTH1_HPMRAMP3_HTH_S ;
749    lowThreshold  = ( ampCompTh1 & DDI_0_OSC_AMPCOMPTH1_HPMRAMP3_LTH_M ) >>
750                                   DDI_0_OSC_AMPCOMPTH1_HPMRAMP3_LTH_S ;
751 
752    return ((( highThreshold + lowThreshold ) * 15 ) >> 1 );
753 }
754 
755 //*****************************************************************************
756 //
757 // Measure the crystal startup time - in number of LF clock edges
758 //
759 //*****************************************************************************
OSCHF_DebugGetCrystalStartupTime(void)760 uint32_t OSCHF_DebugGetCrystalStartupTime( void )
761 {
762    uint32_t lfEdgesFound = 0 ;
763 
764    // Start operation in sync with the LF clock
765    HWREG( AON_RTC_BASE + AON_RTC_O_SYNCLF );
766    OSCHF_TurnOnXosc();
767    while ( ! OSCHF_AttemptToSwitchToXosc() ) {
768       HWREG( AON_RTC_BASE + AON_RTC_O_SYNCLF );
769       lfEdgesFound ++ ;
770    }
771    OSCHF_SwitchToRcOscTurnOffXosc();
772 
773    return ( lfEdgesFound );
774 }
775