EPC9143 300 W 16th Brick DC/DC Module Reference Design
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  * ************************************************************************************************/
33 
34 
62 volatile uint16_t p33c_OscFrc_DefaultInitialize(volatile enum CPU_SPEED_DEFAULTS_e cpu_speed)
63 {
64  volatile int16_t fres = 0;
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  fres = p33c_Osc_Initialize(osc);
107 
108  return(fres);
109 }
110 
111 
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 // Slave cores 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 
193 volatile uint16_t p33c_Osc_Initialize(volatile struct OSC_CONFIG_s osc_config)
194 {
195 
196  volatile uint16_t _n=0;
197  volatile uint16_t err=0;
198 
199  // =============================================================================================
200  // First make sure we are not running from a PLL derived source, when modifying the PLL settings.
201  // This can be accomplished by intentionally switching to a known non-PLL setting, such as FRC.
202  // Switch to FRC (no divider, no PLL), assuming we aren't already running from that.
203  // =============================================================================================
204 
205  if(OSCCONbits.COSC != 0b000)
206  {
207  // NOSC = 0b000 = FRC without divider or PLL
208  __builtin_write_OSCCONH(OSCCON_xOSC_FRC);
209  // Clear CLKLOCK and assert OSWEN = 1 to initiate switch-over
210  __builtin_write_OSCCONL((OSCCON & 0x7E) | 0x01);
211  //Wait for switch over to complete.
212  while((OSCCONbits.COSC != OSCCONbits.NOSC) && (_n++ < OSC_CLKSW_TIMEOUT));
213  if (_n >= OSC_CLKSW_TIMEOUT) err = OSCERR_RST;
214  }
215 
216  // Switch to target oscillator
217  if ((OSCCONbits.COSC != osc_config.osc_type) && (OSCCONbits.CLKLOCK == 0))
218  {
219  // Switch to desired system clock, if clock switching is enabled
220 
221  #if defined (__P33SMPS_CH__) || defined (__P33SMPS_CK__)
222  // Configure PLL pre-scaler, PLL post-scaler, PLL divisor
223 
224  // Clock switch to desired CPU frequency with the PLL enabled in advance
225  // Configure PLL pre-scaler, both PLL post-scalers, and PLL feedback divider
226  PLLDIVbits.VCODIV = osc_config.VCODIV; // FVCO Scaler 1:n
227  CLKDIVbits.PLLPRE = osc_config.N1; // N1 = PLL pre-scaler
228  PLLFBDbits.PLLFBDIV = osc_config.M; // M = PLL feedback divider
229  PLLDIVbits.POST1DIV = osc_config.N2; // N2 = PLL post-scalers #1
230  PLLDIVbits.POST2DIV = osc_config.N3; // N3 = PLL post-scalers #2
231 
232  #elif defined (__P33SMPS_FJ__) || defined (__P33SMPS_FJA__) || defined (__P33SMPS_FJC__) || \
233  defined (__P33SMPS_EP__)
234 
235  CLKDIVbits.PLLPRE = osc_config.N1; // N1 (non zero)
236  PLLFBD = (osc_config.M - 2); // M = PLLFBD
237  CLKDIVbits.PLLPOST = osc_config.N2; // N2 (non zero)
238 
239  #endif
240 
241  // Initiate Clock Switch to FRC Oscillator with PLL (NOSC=0b011)
242  __builtin_write_OSCCONH(osc_config.osc_type);
243  if(OSCCONbits.COSC != OSCCONbits.NOSC)
244  {
245  // Assert OSWEN and make sure CLKLOCK is clear, to initiate the switching operation
246  __builtin_write_OSCCONL((OSCCON & 0x7F) | 0x01);
247  // Wait for clock switch to finish
248  while((OSCCONbits.COSC != OSCCONbits.NOSC) && (_n++ < OSC_CLKSW_TIMEOUT));
249  if ((OSCCONbits.COSC != OSCCONbits.NOSC) || (_n >= OSC_CLKSW_TIMEOUT))
250  { err = OSCERR_CSF; }
251  }
252 
253  }
254  else if ((OSCCONbits.COSC != osc_config.osc_type) && (OSCCONbits.CLKLOCK == 1))
255  { // If clock switching is disabled and the current clock differs from the desired clock,
256  // return error code
257  err = OSCERR_CSD;
258  }
259 
260  // Lock registers against accidental changes
261  OSCCONbits.CLKLOCK = 1;
262 
263  while((OSCCONbits.LOCK != 1) && (_n++ < OSC_CLKSW_TIMEOUT)); // Wait n while loops for PLL to Lock
264  if ((OSCCONbits.LOCK != 1) || (_n >= OSC_CLKSW_TIMEOUT)) // Error occurred?
265  { err = OSCERR_PLL_LCK; } // => If so, return error code
266 
267 // Return Success/Failure
268  if (err == 0)
269  {
270  return((1 - OSCCONbits.CF)); // Return oscillator fail status bit
271  } // (1=Success, 0=Failure)
272  else
273  { return(err); } // Return error code
274 
275 }
276 
277 
301 volatile uint16_t p33c_OscAuxClk_Initialize(volatile struct AUXOSC_CONFIG_s aux_clock_config)
302 {
303 
304  // Set AVCO divider of Auxiliary PLL
305  APLLDIV1bits.AVCODIV = aux_clock_config.AVCODIV; // AVCO Scaler 1:n
306 
307  // Configure APLL pre-scaler, APLL post-scaler, APLL divisor
308  ACLKCON1bits.APLLPRE = aux_clock_config.N1; // N1 (non zero)
309  APLLFBD1bits.APLLFBDIV = aux_clock_config.M; // M = APLLFBD
310  APLLDIV1bits.APOST1DIV = aux_clock_config.N2; // N2 (non zero)
311  APLLDIV1bits.APOST2DIV = aux_clock_config.N3; // N3 (non zero)
312 
313  // Select clock input source (either primary oscillator or internal FRC)
314  ACLKCON1bits.FRCSEL = aux_clock_config.FRCSEL;
315 
316  // Set Enable-bit of Auxiliary PLL
317  ACLKCON1bits.APLLEN = aux_clock_config.APLLEN;
318 
319  // if user has not enabled the APLL module, exit here
320  if(!aux_clock_config.APLLEN)
321  { return(0); }
322 
323  return(ACLKCON1bits.APLLEN);
324 
325 }
326 
327 
353  volatile uint16_t p33c_OscAuxClk_DefaultInitialize(volatile enum AUX_PLL_DEFAULTS_e afpllo_frequency)
354  {
355  volatile uint16_t fres = 1;
356  volatile struct AUXOSC_CONFIG_s aux_clock_config;
357 
358  // Set FRC as clock input to auxiliary PLL module
359  aux_clock_config.FRCSEL = PLLDIV_ACLKCON_FRCSEL_FRC;
360 
361  // Set auxiliary PLL VCO divider to 1:4
362  aux_clock_config.AVCODIV = APLLDIV_AVCODIV_FVCO_DIV_BY_4;
363 
364  // Select PLL dividers and multiplier in accordance with user parameter
365  if(afpllo_frequency <= 800) {
366  aux_clock_config.N1 = ACLKCON_APLLDIV_N1_1; // Default divider of 1
367  aux_clock_config.M = (afpllo_frequency >> 2); // frequency divided by 4
368  aux_clock_config.N2 = APLLDIV_POST2DIV_N2N3_2; // Default divider of 2
369  aux_clock_config.N3 = APLLDIV_POST2DIV_N2N3_1; // Default divider of 1
370  }
371  else {
372  return(0); // When frequency is out of range, return failure
373  // Most recent APLL setting remains unchanged
374  }
375 
376  // Enable auxiliary PLL
377  aux_clock_config.APLLEN = ACLKCON_APLLEN_ENABLED;
378 
379  // Call auxiliary PLL configuration to apply new settings
380  fres &= p33c_OscAuxClk_Initialize(aux_clock_config);
381 
382  return(fres);
383  }
384 
385 
420 volatile uint16_t p33c_Osc_GetFrequencies(volatile uint32_t main_osc_frequency) {
421 
422  volatile int32_t freq=0;
423  volatile uint16_t vbuf=0;
424  volatile OSCCON_xOSC_TYPE_e otype;
425 
426  // Copy oscillator frequency given as unsigned 32-bit integer into signed 32-bit variable
427  freq = (volatile int32_t)main_osc_frequency;
428 
429  // Capture external oscillator frequency
430  if (main_osc_frequency > 0) {
431  system_frequencies.fpri = (volatile uint32_t)freq;
432  }
433 
434  // read currently selected oscillator
435  otype = OSCCONbits.COSC;
436 
437  // Copy Base FRC frequency into data structure
438  system_frequencies.frc = (volatile int32_t)OSC_FRC_FREQ; // Set default FRC oscillator frequency
439 
440  // Depending on detected oscillator type, set/override oscillator frequency
441 
442  // For all modes using the internal Fast RC Oscillator (FRC), check input divider and tuning register
443  if ((otype == OSCCON_xOSC_FRC) || (otype == OSCCON_xOSC_BFRC) || (otype == OSCCON_xOSC_FRCPLL) || (otype == OSCCON_xOSC_FRCDIVN)) {
444 
445  freq = (volatile int32_t)OSC_FRC_FREQ; // Oscillator frequency is 8 MHz
446 
447  #if defined (__P33SMPS_CK__) || defined (__P33SMPS_CH_MSTR__)
448  // FRC tuning register does not affect Backup FRC clock
449  if(otype != OSCCON_xOSC_BFRC) {
450  freq += OSC_TUN_STEP_FREQUENCY * (volatile int32_t)(OSCTUNbits.TUN); // Add oscillator tuning value (is singed)
451  system_frequencies.frc = freq; // Copy updated fast RC oscillator frequency after tuning
452  }
453  #endif
454 
455  // Including FRC divider requires the FRCDIV oscillator to be selected
456  if (otype == OSCCON_xOSC_FRCDIVN) { // If oscillator is using internal divider...
457  vbuf = (CLKDIVbits.FRCDIV & 0x0003); // Copy divider SFR bits
458  freq >>= vbuf; // Right-shift oscillator frequency by divider bits (FRCDIV)
459  }
460 
461  }
462 
463  // Internal Low-Power RC Oscillator is always fixed to 32 kHz
464  else if (otype == OSCCON_xOSC_LPRC) {
465  freq = (volatile int32_t)32000; // Oscillator frequency is 32 kHz
466  }
467 
468  // If external clock modes are set, check if given frequency is non-zero
469  else { // If no oscillator frequency is given, it's assumed FRC oscillator is used
470  if (freq == 0) return(0); // Error: no oscillator frequency given
471  }
472 
473  // Capture system root clock
474  system_frequencies.fclk = (volatile uint32_t)freq;
475 
476  // Check for PLL usage and calculate oscillator frequency based on recent settings
477  if ( (otype == OSCCON_xOSC_FRCPLL) || (otype == OSCCON_xOSC_PRIPLL) ) {
478 
479  // Check if PLL is locked in and stable
480  if (!OSCCONbits.LOCK) return(0); // if incorrect/not valid, return error
481 
482  // Check PLL divider N1 for valid value
483  vbuf = (CLKDIVbits.PLLPRE & 0x000F);
484  if((vbuf > 8) || (vbuf == 0)) return (0); // if incorrect/not valid, return error
485  freq /= vbuf; // Divide frequency by divider N1
486 
487  // Check PLL multiplier M
488  vbuf = (PLLFBDbits.PLLFBDIV & 0x00FF);
489  if((vbuf > 200) || (vbuf < 3)) return (0); // if incorrect/not valid, return error
490  freq *= vbuf; // Multiply frequency by Multiplier M
491 
492  // Capture VCO frequency
493  vbuf = (PLLDIVbits.VCODIV & 0x0003);
494  if(vbuf > 3) return (0); // if incorrect/not valid, return error
495  vbuf = 4-vbuf; // Subtract value from 4 to get divider ratio
496  system_frequencies.fvco = (volatile uint32_t)(freq/vbuf); // Divide frequency by VCO divider
497 
498  // Check PLL divider N2 for valid value
499  vbuf = (PLLDIVbits.POST1DIV & 0x0007);
500  if((vbuf > 8) || (vbuf == 0)) return (0); // if incorrect/not valid, return error
501  freq /= vbuf; // Divide frequency by divider N2
502 
503  // Check PLL divider N3 for valid value
504  vbuf = (PLLDIVbits.POST2DIV & 0x0007);
505  if((vbuf > 8) || (vbuf == 0)) return (0); // if incorrect/not valid, return error
506  freq /= vbuf; // Divide frequency by divider N3
507 
508  }
509 
510  // Capture PLL output frequency
511  system_frequencies.fpllo = (volatile uint32_t)freq;
512 
513  // CPU Clock Divider
514  freq >>= 1; // Divide frequency by 2
515  system_frequencies.fosc = (volatile uint32_t)freq;
516 
517  // Peripheral Bus Divider
518  freq >>= 1; // Divide frequency by 2
519  system_frequencies.fp = (volatile uint32_t)freq;
520 
521  // Reading DOZE setting
522  if (CLKDIVbits.DOZEN) { // If DOZE divider is enabled
523  vbuf = (CLKDIVbits.DOZE & 0x0003); // Copy divider SFR bits
524  freq >>= vbuf; // Right-shift oscillator frequency by divider bits (DOZE)
525  }
526  system_frequencies.fcy = (volatile uint32_t)freq;
527 
528  // Calculate CPU clock period
530 
531  // Calculate peripheral clock period
533 
534  // -----------------------------------------------
535  // Capture APLL frequencies
536  // -----------------------------------------------
537 
538  if (ACLKCON1bits.APLLEN) { // APLL is enabled...
539 
540  // Select input frequency
541  if(ACLKCON1bits.FRCSEL) { freq = system_frequencies.frc; }
542  else { freq = system_frequencies.fpri; }
543 
544  // Check APLL divider N1 for valid value
545  vbuf = (ACLKCON1bits.APLLPRE & 0x000F);
546  if((vbuf > 8) || (vbuf == 0)) return (0); // if incorrect/not valid, return error
547  freq /= vbuf; // Divide frequency by divider N1
548 
549  // Check PLL multiplier M
550  vbuf = (APLLFBD1bits.APLLFBDIV & 0x00FF);
551  if((vbuf > 200) || (vbuf < 3)) return (0); // if incorrect/not valid, return error
552  freq *= vbuf; // Multiply frequency by Multiplier M
553 
554  // Capture VCO frequency
555  vbuf = (APLLDIV1bits.AVCODIV & 0x0003);
556  if(vbuf > 3) return (0); // if incorrect/not valid, return error
557  vbuf = 4-vbuf; // Subtract value from 4 to get divider ratio
558  system_frequencies.afvco = (volatile uint32_t)(freq/vbuf); // Divide frequency by VCO divider
559 
560  // Check PLL divider N2 for valid value
561  vbuf = (APLLDIV1bits.APOST1DIV & 0x0007);
562  if((vbuf > 8) || (vbuf == 0)) return (0); // if incorrect/not valid, return error
563  freq /= vbuf; // Divide frequency by divider N2
564 
565  // Check PLL divider N3 for valid value
566  vbuf = (APLLDIV1bits.APOST2DIV & 0x0007);
567  if((vbuf > 8) || (vbuf == 0)) return (0); // if incorrect/not valid, return error
568  freq /= vbuf; // Divide frequency by divider N3
569  system_frequencies.afpllo = freq; // Capture auxiliary PLL output
570 
571  }
572  else { // APLL is disabled...
573  system_frequencies.afpllo = 0; // Reset auxiliary PLL output
574  system_frequencies.afvco = 0; // Reset auxiliary PLL VCO output
575  }
576 
577  // Return 1=Success, 0=Failure
578  return(1);
579 }
580 
581 
582 // end of file
583 
p33c_OscAuxClk_Initialize
volatile uint16_t p33c_OscAuxClk_Initialize(volatile struct AUXOSC_CONFIG_s aux_clock_config)
Initializes the auxiliary clock and its PLL module step by step in software. Each step is tested and ...
Definition: p33c_osc.c:301
OSCILLATOR_SYSTEM_FREQUENCIES_s::afvco
volatile uint32_t afvco
Definition: p33c_osc.h:137
OSCILLATOR_SYSTEM_FREQUENCIES_s::tcy
volatile float tcy
Definition: p33c_osc.h:135
OSCILLATOR_SYSTEM_FREQUENCIES_s::fpllo
volatile uint32_t fpllo
Definition: p33c_osc.h:132
p33c_OscFrc_Initialize
volatile uint16_t p33c_OscFrc_Initialize(volatile enum CLKDIV_FRCDIVN_e frc_div, volatile enum OSCTUN_TUN_e frc_tune)
Initializes the internal RC oscillator divider and tuning register.
Definition: p33c_osc.c:138
p33c_OscAuxClk_DefaultInitialize
volatile uint16_t p33c_OscAuxClk_DefaultInitialize(volatile enum AUX_PLL_DEFAULTS_e afpllo_frequency)
Initializes the auxiliary clock and its PLL module step by step in software. Each step is tested and ...
Definition: p33c_osc.c:353
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:127
p33c_OscFrc_DefaultInitialize
volatile uint16_t p33c_OscFrc_DefaultInitialize(volatile enum CPU_SPEED_DEFAULTS_e cpu_speed)
Initializes the major oscillator and the PLL module step by step by using clock switching in software...
Definition: p33c_osc.c:62
OSCILLATOR_SYSTEM_FREQUENCIES_s::fvco
volatile uint32_t fvco
Definition: p33c_osc.h:133
OSCILLATOR_SYSTEM_FREQUENCIES_s::fclk
volatile uint32_t fclk
Definition: p33c_osc.h:128
OSCILLATOR_SYSTEM_FREQUENCIES_s::frc
volatile uint32_t frc
Definition: p33c_osc.h:126
OSCILLATOR_SYSTEM_FREQUENCIES_s::afpllo
volatile uint32_t afpllo
Definition: p33c_osc.h:136
system_frequencies
volatile struct OSCILLATOR_SYSTEM_FREQUENCIES_s system_frequencies
Definition: p33c_osc.c:32
OSCILLATOR_SYSTEM_FREQUENCIES_s::fp
volatile uint32_t fp
Definition: p33c_osc.h:131
p33c_Osc_GetFrequencies
volatile uint16_t p33c_Osc_GetFrequencies(volatile uint32_t main_osc_frequency)
This routine reads all oscillator related SFRs recalculating the various frequencies across clock dom...
Definition: p33c_osc.c:420
OSCILLATOR_SYSTEM_FREQUENCIES_s::fcy
volatile uint32_t fcy
Definition: p33c_osc.h:130
OSCILLATOR_SYSTEM_FREQUENCIES_s::tp
volatile float tp
Definition: p33c_osc.h:134
OSCILLATOR_SYSTEM_FREQUENCIES_s::fosc
volatile uint32_t fosc
Definition: p33c_osc.h:129
OSCILLATOR_SYSTEM_FREQUENCIES_s
Definition: p33c_osc.h:125