| Digital Power Starter Kit 3 Firmware dsPIC33C Boost Converter Voltage Mode Control Example |

p33c_osc.c
1 /*
2 * File: p33SMPS_oscillator.c
3 * Author: M91406
4 *
5 * Created on October 27, 2017, 11:24 AM
6 */
7
8 /* ************************************************************************************************
9 * PRIVATE DEFINES
10 * ************************************************************************************************/
11
12 // Include Header Files
13 #include "p33c_osc.h"
14
15 /* ************************************************************************************************
16 * PRIVATE DEFINES
17 * ************************************************************************************************/
18
23 #define OSC_CLKSW_TIMEOUT 50000
24
25 /* ************************************************************************************************
26 * PRIVATE VARIABLES
27 * ************************************************************************************************/
32 volatile struct OSCILLATOR_SYSTEM_FREQUENCIES_s SystemFrequencies;
33
34 /*************************************************************************************************
35 * @fn uint16_t p33c_OscFrc_DefaultInitialize(volatile enum CPU_SPEED_DEFAULTS_e cpu_speed)
36 * @ingroup lib-layer-pral-functions-public-osc
37 * @param cpu_speed CPU speed setting of type enum CPU_SPEED_DEFAULTS_e
38 * @return unsigned integer
39 * 0 = unspecified clock failure detected
40 * 1 = clock switch successful
41 * 2 = clock switch failed
42 * 4 = currently selected clock differs from selected clock source
43 * 8 = PLL didn't lock in within given time frame
44 * @brief Initializes the major oscillator and the PLL module step by step by using clock switching
45 * in software. Each step is tested and verified. PLL settings here are pulled from pre-defined
46 * settings set for default CPU speeds from 40 MIPS to 100 MIPS
47 *
48 * @details
49 * Microchip's 16-Bit devices offer a safe 2-step start-up mode, using the internal FRC during power up,
50 * followed by a user defined switch-over to the desired oscillator.
51 * Though this can also be done in hardware automatically, this software-version of the switch-over offers
52 * a better solution to verify each step and enables the user to implement some error handling in the case
53 * of failure.
54 * This function can be used to select a new oscillator at runtime. Each configuration step
55 * will be verified before the next step is performed.
56 *
57 * @note
58 * If a oscillator switch-over is performed, additional settings in the _FOSCSEL and _FOSC
59 * registers of the configuration bits may be required
60 * ************************************************************************************************/
61
62 volatile uint16_t p33c_OscFrc_DefaultInitialize(volatile enum CPU_SPEED_DEFAULTS_e cpu_speed)
63 {
64 volatile int16_t retval = 1;
65 volatile struct OSC_CONFIG_s osc;
66
67 osc.osc_type = OSCCON_xOSC_FRCPLL;
68 osc.N1 = CLKDIV_PLLDIV_N1_1;
69
70 switch(cpu_speed)
71 {
72 case CPU_SPEED_20_MIPS:
73 osc.M = PLLFBD_PLLFBDIV_M_20;
74 break;
75 case CPU_SPEED_30_MIPS:
76 osc.M = PLLFBD_PLLFBDIV_M_30;
77 break;
78 case CPU_SPEED_40_MIPS:
79 osc.M = PLLFBD_PLLFBDIV_M_40;
80 break;
81 case CPU_SPEED_50_MIPS:
82 osc.M = PLLFBD_PLLFBDIV_M_50;
83 break;
84 case CPU_SPEED_60_MIPS:
85 osc.M = PLLFBD_PLLFBDIV_M_60;
86 break;
87 case CPU_SPEED_70_MIPS:
88 osc.M = PLLFBD_PLLFBDIV_M_70;
89 break;
90 case CPU_SPEED_80_MIPS:
91 osc.M = PLLFBD_PLLFBDIV_M_80;
92 break;
93 case CPU_SPEED_90_MIPS:
94 osc.M = PLLFBD_PLLFBDIV_M_90;
95 break;
96 case CPU_SPEED_100_MIPS:
97 osc.M = PLLFBD_PLLFBDIV_M_100;
98 break;
99 default:
100 return(0);
101 break;
102 }
103 osc.N2 = PLLDIV_POST2DIV_N2N3_2;
104 osc.N3 = PLLDIV_POST2DIV_N2N3_1;
105
106 retval &= p33c_Osc_Initialize(osc);
107
108 return(retval);
109 }
110
111 /*************************************************************************************************
112 * @fn uint16_t p33c_OscFrc_Initialize(volatile enum CLKDIV_FRCDIVN_e frc_div, volatile enum OSCTUN_TUN_e frc_tune)
113 * @ingroup lib-layer-pral-functions-public-osc
114 * @brief Initializes the internal RC oscillator divider and tuning register
115 * @param frc_div Internal RC Oscillator frequency divider of type enum CLKDIV_FRCDIVN_e
116 * @param frc_tune Internal RC Oscillator tuning register value of type enum OSCTUN_TUN_e
117 * @return
118 * 0 = unspecified clock failure detected
119 * 1 = clock switch successful
120 * 2 = clock switch failed
121 * 4 = currently selected clock differs from selected clock source
122 * 8 = PLL didn't lock in within given time frame
123 *
124 * @details
125 * Microchip's 16-Bit devices offer a safe 2-step start-up mode, using the internal FRC during power up,
126 * followed by a user defined switch-over to the desired oscillator.
127 * Though this can also be done in hardware automatically, this software-version of the switch-over offers
128 * a better solution to verify each step and enables the user to implement some error handling in the case
129 * of failure.
130 * This function can be used to select a new oscillator at runtime. Each configuration step
131 * will be verified before the next step is performed.
132 *
133 * @note
134 * If a oscillator switch-over is performed, additional settings in the _FOSCSEL and _FOSC
135 * registers of the configuration bits may be required
136 *************************************************************************************************/
137
138 volatile uint16_t p33c_OscFrc_Initialize(volatile enum CLKDIV_FRCDIVN_e frc_div, volatile enum OSCTUN_TUN_e frc_tune)
139 {
140 #if defined (__P33SMPS_CH_MSTR__) || defined (__P33SMPS_CK__)
141
142 // Secondary cores of multi-core devices do not have access to the FRC oscillator tuning register
143
144 volatile uint16_t err=0;
145
146 // Set oscillator tuning
147 // => FRC Oscillator tuning is only available on single core devices and
148 // the master core of dual core devices
149 OSCTUNbits.TUN = frc_tune; // Set Tuning Register for FRC Oscillator
150
151 // Set FRC divider
152 CLKDIVbits.FRCDIV = frc_div; // Set FRC frequency divider
153
154 return(err);
155
156 #else
157 return(1);
158 #endif
159
160 }
161
162 /*************************************************************************************************
163 * @fn uint16_t p33c_Osc_Initialize(volatile struct P33C_OSC_CONFIG_s osc_config)
164 * @ingroup lib-layer-pral-functions-public-osc
165 * @brief
166 * Initializes the major oscillator and the PLL module step by step by using clock switching
167 * in software. Each step is tested and verified
168 *
169 * @param osc_config Main oscillator and PLL configuration of type struct P33C_OSC_CONFIG_s
170 *
171 * @return unsigned integer
172 * 0 = unspecified clock failure detected
173 * 1 = clock switch successful
174 * 2 = clock switch failed
175 * 4 = currently selected clock differs from selected clock source
176 * 8 = PLL didn't lock in within given time frame
177 *
178 * @details
179 * Microchip's 16-Bit devices offer a safe 2-step start-up mode, using the internal FRC during power up,
180 * followed by a user defined switch-over to the desired oscillator.
181 * Though this can also be done in hardware automatically, this software-version of the switch-over offers
182 * a better solution to verify each step and enables the user to implement some error handling in the case
183 * of failure.
184 * This function can be used to select a new oscillator at runtime. Each configuration step
185 * will be verified before the next step is performed.
186 *
187 * @note
188 * If a oscillator switch-over is performed, additional settings in the _FOSCSEL and _FOSC
189 * registers of the configuration bits may be required
190 *************************************************************************************************/
191
192 volatile uint16_t p33c_Osc_Initialize(volatile struct OSC_CONFIG_s osc_config)
193 {
194 volatile uint16_t retval=0;
195 volatile uint16_t _n=0;
196
197 // =============================================================================================
198 // First make sure we are not running from a PLL derived source, when modifying the PLL settings.
199 // This can be accomplished by intentionally switching to a known non-PLL setting, such as FRC.
200 // Switch to FRC (no divider, no PLL), assuming we aren't already running from that.
201 // =============================================================================================
202
203 if(OSCCONbits.COSC != 0b000)
204 {
205 // NOSC = 0b000 = FRC without divider or PLL
206 __builtin_write_OSCCONH(OSCCON_xOSC_FRC);
207 // Clear CLKLOCK and assert OSWEN = 1 to initiate switch-over
208 __builtin_write_OSCCONL((OSCCON & 0x7E) | 0x01);
209 //Wait for switch over to complete.
210 while((OSCCONbits.COSC != OSCCONbits.NOSC) && (_n++ < OSC_CLKSW_TIMEOUT));
211 if (_n >= OSC_CLKSW_TIMEOUT) retval = OSCERR_RST;
212 }
213
214 // Switch to target oscillator
215 if ((OSCCONbits.COSC != osc_config.osc_type) && (OSCCONbits.CLKLOCK == 0))
216 {
217 // Switch to desired system clock, if clock switching is enabled
218
219 #if defined (__P33SMPS_CH__) || defined (__P33SMPS_CK__)
220 // Configure PLL pre-scaler, PLL post-scaler, PLL divisor
221
222 // Clock switch to desired CPU frequency with the PLL enabled in advance
223 // Configure PLL pre-scaler, both PLL post-scalers, and PLL feedback divider
224 PLLDIVbits.VCODIV = osc_config.VCODIV; // FVCO Scaler 1:n
225 CLKDIVbits.PLLPRE = osc_config.N1; // N1 = PLL pre-scaler
226 PLLFBDbits.PLLFBDIV = osc_config.M; // M = PLL feedback divider
227 PLLDIVbits.POST1DIV = osc_config.N2; // N2 = PLL post-scalers #1
228 PLLDIVbits.POST2DIV = osc_config.N3; // N3 = PLL post-scalers #2
229
230 #elif defined (__P33SMPS_FJ__) || defined (__P33SMPS_FJA__) || defined (__P33SMPS_FJC__) || \
231 defined (__P33SMPS_EP__)
232
233 CLKDIVbits.PLLPRE = osc_config.N1; // N1 (non zero)
234 PLLFBD = (osc_config.M - 2); // M = PLLFBD
235 CLKDIVbits.PLLPOST = osc_config.N2; // N2 (non zero)
236
237 #endif
238
239 // Initiate Clock Switch to FRC Oscillator with PLL (NOSC=0b011)
240 __builtin_write_OSCCONH(osc_config.osc_type);
241 if(OSCCONbits.COSC != OSCCONbits.NOSC)
242 {
243 // Assert OSWEN and make sure CLKLOCK is clear, to initiate the switching operation
244 __builtin_write_OSCCONL((OSCCON & 0x7F) | 0x01);
245 // Wait for clock switch to finish
246 while((OSCCONbits.COSC != OSCCONbits.NOSC) && (_n++ < OSC_CLKSW_TIMEOUT));
247 if ((OSCCONbits.COSC != OSCCONbits.NOSC) || (_n >= OSC_CLKSW_TIMEOUT))
248 { retval = OSCERR_CSF; }
249 }
250
251 }
252 else if ((OSCCONbits.COSC != osc_config.osc_type) && (OSCCONbits.CLKLOCK == 1))
253 { // If clock switching is disabled and the current clock differs from the desired clock,
254 // return error code
255 retval = OSCERR_CSD;
256 }
257
258 // Lock registers against accidental changes
259 OSCCONbits.CLKLOCK = 1;
260
261 while((OSCCONbits.LOCK != 1) && (_n++ < OSC_CLKSW_TIMEOUT)); // Wait n while loops for PLL to Lock
262 if ((OSCCONbits.LOCK != 1) || (_n >= OSC_CLKSW_TIMEOUT)) // Error occurred?
263 { retval = OSCERR_PLL_LCK; } // => If so, return error code
264
265 // Return Success/Failure
266 if (retval == 0) {
267 return((1 - OSCCONbits.CF)); // Return oscillator fail status bit
268 } // (1=Success, 0=Failure)
269 else
270 { return(retval); } // Return error code
271
272 }
273
274 /*************************************************************************************************
275 * @fn uint16_t p33c_OscAuxClk_Initialize(volatile struct AUXOSC_CONFIG_s aux_clock_config)
276 * @ingroup lib-layer-pral-functions-public-osc
277 * @brief
278 * Initializes the auxiliary clock and its PLL module step by step
279 * in software. Each step is tested and verified
280 *
281 * @param aux_clock_config Auxiliary oscillator configuration of type struct AUXOSC_CONFIG_s
282 *
283 * @return
284 * 0 = unspecified clock failure detected
285 * 1 = clock switch successful
286 * 2 = clock switch failed
287 * 4 = currently selected clock differs from selected clock source
288 * 8 = PLL didn't lock in within given time frame
289 *
290 * @details
291 * The auxiliary clock is generated by a separate PLL module, which is driven
292 * from one of the main clock signals or PLL outputs. This auxiliary clock can
293 * be used to drive ADCs, PWM, DACs and other peripherals. Each of them might
294 * have individual requirements. Please refer to the specific peripheral sections
295 * in the device data sheet to learn how to configure the auxiliary clock.
296 *
297 *************************************************************************************************/
298
299 volatile uint16_t p33c_OscAuxClk_Initialize(volatile struct AUXOSC_CONFIG_s aux_clock_config)
300 {
301
302 // Set AVCO divider of Auxiliary PLL
303 APLLDIV1bits.AVCODIV = aux_clock_config.AVCODIV; // AVCO Scaler 1:n
304
305 // Configure APLL pre-scaler, APLL post-scaler, APLL divisor
306 ACLKCON1bits.APLLPRE = aux_clock_config.N1; // N1 (non zero)
307 APLLFBD1bits.APLLFBDIV = aux_clock_config.M; // M = APLLFBD
308 APLLDIV1bits.APOST1DIV = aux_clock_config.N2; // N2 (non zero)
309 APLLDIV1bits.APOST2DIV = aux_clock_config.N3; // N3 (non zero)
310
311 // Select clock input source (either primary oscillator or internal FRC)
312 ACLKCON1bits.FRCSEL = aux_clock_config.FRCSEL;
313
314 // Set Enable-bit of Auxiliary PLL
315 ACLKCON1bits.APLLEN = aux_clock_config.APLLEN;
316
317 // if user has not enabled the APLL module, exit here
318 if(!aux_clock_config.APLLEN)
319 { return(0); }
320
321 return(ACLKCON1bits.APLLEN);
322
323 }
324
325 /*************************************************************************************************
326 * @fn uint16_t p33c_OscAuxClk_DefaultInitialize(volatile enum AUX_PLL_DEFAULTS_e afpllo_frequency)
327 * @ingroup lib-layer-pral-functions-public-osc
328 * @brief
329 * Initializes the auxiliary clock and its PLL module step by step
330 * in software. Each step is tested and verified
331 *
332 * @param afpllo_frequency Auxiliary PLL output frequency of type enum AUX_PLL_DEFAULTS_e
333 *
334 * @return
335 * 0 = unspecified clock failure detected
336 * 1 = clock switch successful
337 * 2 = clock switch failed
338 * 4 = currently selected clock differs from selected clock source
339 * 8 = PLL didn't lock in within given time frame
340 *
341 * @details
342 * The auxiliary clock is generated by a separate PLL module, which is driven
343 * from one of the main clock signals or PLL outputs. This auxiliary clock can
344 * be used to drive ADCs, PWM, DACs and other peripherals. Each of them might
345 * have individual requirements. Please refer to the specific peripheral sections
346 * in the device data sheet to learn how to configure the auxiliary clock.
347 *
348 *************************************************************************************************/
349
350 volatile uint16_t p33c_OscAuxClk_DefaultInitialize(volatile enum AUX_PLL_DEFAULTS_e afpllo_frequency)
351 {
352 volatile uint16_t retval = 1;
353 volatile struct AUXOSC_CONFIG_s aux_clock_config;
354
355 // Set FRC as clock input to auxiliary PLL module
356 aux_clock_config.FRCSEL = PLLDIV_ACLKCON_FRCSEL_FRC;
357
358 // Set auxiliary PLL VCO divider to 1:4
359 aux_clock_config.AVCODIV = APLLDIV_AVCODIV_FVCO_DIV_BY_4;
360
361 // Select PLL dividers and multiplier in accordance with user parameter
362 if(afpllo_frequency <= 800) {
363 aux_clock_config.N1 = ACLKCON_APLLDIV_N1_1; // Default divider of 1
364 aux_clock_config.M = (afpllo_frequency >> 2); // frequency divided by 4
365 aux_clock_config.N2 = APLLDIV_POST2DIV_N2N3_2; // Default divider of 2
366 aux_clock_config.N3 = APLLDIV_POST2DIV_N2N3_1; // Default divider of 1
367 }
368 else {
369 return(0); // When frequency is out of range, return failure
370 // Most recent APLL setting remains unchanged
371 }
372
373 // Enable auxiliary PLL
374 aux_clock_config.APLLEN = ACLKCON_APLLEN_ENABLED;
375
376 // Call auxiliary PLL configuration to apply new settings
377 retval &= p33c_OscAuxClk_Initialize(aux_clock_config);
378
379 return(retval);
380 }
381
382 /**************************************************************************************************
383 * @fn uint16_t p33c_Osc_GetFrequencies(volatile uint32_t main_osc_frequency)
384 * @ingroup lib-layer-pral-functions-public-osc
385 * @brief
386 * This routine reads all oscillator related SFRs recalculating the various frequencies
387 * across clock domains. These frequencies are broadcasted in the global data structure
388 * 'system_frequencies'.
389 *
390 * @param main_osc_frequency Frequency of external oscillator frequency in [Hz] of type unsigned integer.
391 * Set to '0' if no external oscillator is used.
392 *
393 * @return
394 * unsigned integer
395 * 0 = reading oscillator settings failed
396 * 1 = reading oscillator settings successfully
397 *
398 * @details
399 * Microchip's 16-Bit devices offer multiple clock sources to clock the CPU. This routine
400 * reads the most recent, oscillator related Special Function Registers (SFR) and determines
401 * the recently active main clock and its frequency and calculates the resulting clock frequencies
402 * of other clock domains.
403 *
404 * The results are broadcasted through the 'system_frequencies' data structure which is globally
405 * accessible in user code and can be used to calculate other oscillator dependent settings such as
406 * timer periods or baud rates of communication interfaces
407 *
408 * Please note:
409 * The contents of data structure 'system_frequencies' is NOT updated automatically. It is
410 * recommended to call the function 'osc_get_frequencies' in user code every time after
411 * clock settings have been modified.
412 *
413 **************************************************************************************************/
414 volatile uint16_t p33c_Osc_SetExtFrequency(volatile int32_t ext_osc_frequency)
415 {
416 volatile uint16_t retval=1;
417
418 SystemFrequencies.fpri = ext_osc_frequency;
419
420 return(retval);
421 }
422
423 /**************************************************************************************************
424 * @fn uint16_t p33c_Osc_GetFrequencies(volatile uint32_t main_osc_frequency)
425 * @ingroup lib-layer-pral-functions-public-osc
426 * @brief
427 * This routine reads all oscillator related SFRs recalculating the various frequencies
428 * across clock domains. These frequencies are broadcasted in the global data structure
429 * 'system_frequencies'.
430 *
431 * @return
432 * unsigned integer
433 * 0 = reading oscillator settings failed
434 * 1 = reading oscillator settings successful
435 *
436 * @details
437 * Microchip's 16-Bit devices offer multiple clock sources to clock the CPU and peripherals. This
438 * routine reads the most recent, oscillator related Special Function Registers (SFR) and determines
439 * the recently active main clock and its frequency and calculates the resulting clock frequencies
440 * of other clock domains.
441 *
442 * The results are broadcasted through the 'system_frequencies' data structure which is globally
443 * accessible in user code and can be used to calculate other oscillator dependent settings such as
444 * timer periods or baud rates of communication interfaces-
445 *
446 * @note
447 * The content of data structure 'system_frequencies' is NOT updated automatically. It is
448 * recommended to call the function 'p33c_Osc_GetFrequencies' in user code every time after
449 * clock settings have been modified.
450 *
451 * @note
452 * If external oscillators are used, users have to specify the clock frequency by calling
453 * the function 'p33c_Osc_SetExtFrequency(volatile int32_t ext_osc_frequency)' before the
454 * function 'p33c_Osc_GetFrequencies' will return accurate frequency information.
455 *
456 * If the recent oscillator is set to "External Clock" and the primary clock frequency
457 * equals zero, this function will return an error code and no frequency information
458 * update will occur.
459 *
460 **************************************************************************************************/
461 volatile uint16_t p33c_Osc_GetFrequencies(void)
462 {
463 volatile int32_t freq=0;
464 volatile uint16_t vbuf=0;
465 volatile enum OSCCON_xOSC_TYPE_e otype;
466
467 // read currently selected oscillator
468 otype = OSCCONbits.COSC;
469
470 // Copy Base FRC frequency into data structure
471 SystemFrequencies.frc = (volatile int32_t)OSC_FRC_FREQ; // Set default FRC oscillator frequency
472
473 // Depending on detected oscillator type, set/override oscillator frequency
474
475 // For all modes using the internal Fast RC Oscillator (FRC), check input divider and tuning register
476 if ((otype == OSCCON_xOSC_FRC) || (otype == OSCCON_xOSC_BFRC) || (otype == OSCCON_xOSC_FRCPLL) || (otype == OSCCON_xOSC_FRCDIVN)) {
477
478 freq = (volatile int32_t)OSC_FRC_FREQ; // Oscillator frequency is 8 MHz
479
480 #if defined (__P33SMPS_CK__) || defined (__P33SMPS_CH_MSTR__)
481 // FRC tuning register does not affect Backup FRC clock
482 if(otype != OSCCON_xOSC_BFRC) {
483 freq += OSC_TUN_STEP_FREQUENCY * (volatile int32_t)(OSCTUNbits.TUN); // Add oscillator tuning value (is singed)
484 SystemFrequencies.frc = freq; // Copy updated fast RC oscillator frequency after tuning
485 }
486 #endif
487
488 // Including FRC divider requires the FRCDIV oscillator to be selected
489 if (otype == OSCCON_xOSC_FRCDIVN) { // If oscillator is using internal divider...
490 vbuf = (CLKDIVbits.FRCDIV & 0x0003); // Copy divider SFR bits
491 freq >>= vbuf; // Right-shift oscillator frequency by divider bits (FRCDIV)
492 }
493
494 }
495
496 // Internal Low-Power RC Oscillator is always fixed to 32 kHz
497 else if (otype == OSCCON_xOSC_LPRC) {
498 freq = (volatile int32_t)32000; // Oscillator frequency is 32 kHz
499 }
500
501 // If external clock modes are set, check if given frequency is non-zero
502 else { // If no oscillator frequency is given, it's assumed FRC oscillator is used
503 if (freq == 0) return(0); // Error: no oscillator frequency of external clock given
504 }
505
506 // Capture system root clock
507 SystemFrequencies.fclk = (volatile uint32_t)freq;
508
509 // Check for PLL usage and calculate oscillator frequency based on recent settings
510 if ( (otype == OSCCON_xOSC_FRCPLL) || (otype == OSCCON_xOSC_PRIPLL) ) {
511
512 // Check if PLL is locked in and stable
513 if (!OSCCONbits.LOCK) return(0); // if incorrect/not valid, return error
514
515 // Check PLL divider N1 for valid value
516 vbuf = (CLKDIVbits.PLLPRE & 0x000F);
517 if((vbuf > 8) || (vbuf == 0)) return (0); // if incorrect/not valid, return error
518 freq /= vbuf; // Divide frequency by divider N1
519
520 // Check PLL multiplier M
521 vbuf = (PLLFBDbits.PLLFBDIV & 0x00FF);
522 if((vbuf > 200) || (vbuf < 3)) return (0); // if incorrect/not valid, return error
523 freq *= vbuf; // Multiply frequency by Multiplier M
524
525 // Capture VCO frequency
526 vbuf = (PLLDIVbits.VCODIV & 0x0003);
527 if(vbuf > 3) return (0); // if incorrect/not valid, return error
528 vbuf = 4-vbuf; // Subtract value from 4 to get divider ratio
529 SystemFrequencies.fvco = (volatile uint32_t)(freq/vbuf); // Divide frequency by VCO divider
530
531 // Check PLL divider N2 for valid value
532 vbuf = (PLLDIVbits.POST1DIV & 0x0007);
533 if((vbuf > 8) || (vbuf == 0)) return (0); // if incorrect/not valid, return error
534 freq /= vbuf; // Divide frequency by divider N2
535
536 // Check PLL divider N3 for valid value
537 vbuf = (PLLDIVbits.POST2DIV & 0x0007);
538 if((vbuf > 8) || (vbuf == 0)) return (0); // if incorrect/not valid, return error
539 freq /= vbuf; // Divide frequency by divider N3
540
541 }
542
543 // Capture PLL output frequency
544 SystemFrequencies.fpllo = (volatile uint32_t)freq;
545
546 // CPU Clock Divider
547 freq >>= 1; // Divide frequency by 2
548 SystemFrequencies.fosc = (volatile uint32_t)freq;
549
550 // Peripheral Bus Divider
551 freq >>= 1; // Divide frequency by 2
552 SystemFrequencies.fp = (volatile uint32_t)freq;
553
554 // Reading DOZE setting
555 if (CLKDIVbits.DOZEN) { // If DOZE divider is enabled
556 vbuf = (CLKDIVbits.DOZE & 0x0003); // Copy divider SFR bits
557 freq >>= vbuf; // Right-shift oscillator frequency by divider bits (DOZE)
558 }
559 SystemFrequencies.fcy = (volatile uint32_t)freq;
560
561 // Calculate CPU clock period
562 SystemFrequencies.tcy = 1.0/((float)SystemFrequencies.fcy);
563
564 // Calculate peripheral clock period
565 SystemFrequencies.tp = 1.0/((float)SystemFrequencies.fp);
566
567 // -----------------------------------------------
568 // Capture APLL frequencies
569 // -----------------------------------------------
570
571 if (ACLKCON1bits.APLLEN) { // APLL is enabled...
572
573 // Select input frequency
574 if(ACLKCON1bits.FRCSEL) { freq = SystemFrequencies.frc; }
575 else { freq = SystemFrequencies.fpri; }
576
577 // Check APLL divider N1 for valid value
578 vbuf = (ACLKCON1bits.APLLPRE & 0x000F);
579 if((vbuf > 8) || (vbuf == 0)) return (0); // if incorrect/not valid, return error
580 freq /= vbuf; // Divide frequency by divider N1
581
582 // Check PLL multiplier M
583 vbuf = (APLLFBD1bits.APLLFBDIV & 0x00FF);
584 if((vbuf > 200) || (vbuf < 3)) return (0); // if incorrect/not valid, return error
585 freq *= vbuf; // Multiply frequency by Multiplier M
586
587 // Capture VCO frequency
588 vbuf = (APLLDIV1bits.AVCODIV & 0x0003);
589 if(vbuf > 3) return (0); // if incorrect/not valid, return error
590 vbuf = 4-vbuf; // Subtract value from 4 to get divider ratio
591 SystemFrequencies.afvco = (volatile uint32_t)(freq/vbuf); // Divide frequency by VCO divider
592
593 // Check PLL divider N2 for valid value
594 vbuf = (APLLDIV1bits.APOST1DIV & 0x0007);
595 if((vbuf > 8) || (vbuf == 0)) return (0); // if incorrect/not valid, return error
596 freq /= vbuf; // Divide frequency by divider N2
597
598 // Check PLL divider N3 for valid value
599 vbuf = (APLLDIV1bits.APOST2DIV & 0x0007);
600 if((vbuf > 8) || (vbuf == 0)) return (0); // if incorrect/not valid, return error
601 freq /= vbuf; // Divide frequency by divider N3
602 SystemFrequencies.afpllo = freq; // Capture auxiliary PLL output
603
604 }
605 else { // APLL is disabled...
606 SystemFrequencies.afpllo = 0; // Reset auxiliary PLL output
607 SystemFrequencies.afvco = 0; // Reset auxiliary PLL VCO output
608 }
609
610 // Return 1=Success, 0=Failure
611 return(1);
612 }
613
614
615 // end of file
616
OSCILLATOR_SYSTEM_FREQUENCIES_s::tcy
volatile float tcy
Definition: p33c_osc.h:134
OSCILLATOR_SYSTEM_FREQUENCIES_s
Definition: p33c_osc.h:124
OSCILLATOR_SYSTEM_FREQUENCIES_s::fvco
volatile uint32_t fvco
Definition: p33c_osc.h:132
OSCILLATOR_SYSTEM_FREQUENCIES_s::fosc
volatile uint32_t fosc
Definition: p33c_osc.h:128
OSC_CLKSW_TIMEOUT
#define OSC_CLKSW_TIMEOUT
value to set the timeout for clock switching operations
Definition: p33c_osc.c:23
OSCILLATOR_SYSTEM_FREQUENCIES_s::fpri
volatile uint32_t fpri
Definition: p33c_osc.h:126
OSCILLATOR_SYSTEM_FREQUENCIES_s::fclk
volatile uint32_t fclk
Definition: p33c_osc.h:127
OSCILLATOR_SYSTEM_FREQUENCIES_s::fpllo
volatile uint32_t fpllo
Definition: p33c_osc.h:131
OSCILLATOR_SYSTEM_FREQUENCIES_s::fp
volatile uint32_t fp
Definition: p33c_osc.h:130
OSCILLATOR_SYSTEM_FREQUENCIES_s::fcy
volatile uint32_t fcy
Definition: p33c_osc.h:129
OSCILLATOR_SYSTEM_FREQUENCIES_s::afpllo
volatile uint32_t afpllo
Definition: p33c_osc.h:135
OSCILLATOR_SYSTEM_FREQUENCIES_s::tp
volatile float tp
Definition: p33c_osc.h:133
OSCILLATOR_SYSTEM_FREQUENCIES_s::afvco
volatile uint32_t afvco
Definition: p33c_osc.h:136
OSCILLATOR_SYSTEM_FREQUENCIES_s::frc
volatile uint32_t frc
Definition: p33c_osc.h:125