PIC24 Support Libraries
 All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
pic24_clockfreq.h
Go to the documentation of this file.
1 /*
2  * "Copyright (c) 2008 Robert B. Reese, Bryan A. Jones, J. W. Bruce ("AUTHORS")"
3  * All rights reserved.
4  * (R. Reese, reese_AT_ece.msstate.edu, Mississippi State University)
5  * (B. A. Jones, bjones_AT_ece.msstate.edu, Mississippi State University)
6  * (J. W. Bruce, jwbruce_AT_ece.msstate.edu, Mississippi State University)
7  *
8  * Permission to use, copy, modify, and distribute this software and its
9  * documentation for any purpose, without fee, and without written agreement is
10  * hereby granted, provided that the above copyright notice, the following
11  * two paragraphs and the authors appear in all copies of this software.
12  *
13  * IN NO EVENT SHALL THE "AUTHORS" BE LIABLE TO ANY PARTY FOR
14  * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT
15  * OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF THE "AUTHORS"
16  * HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
17  *
18  * THE "AUTHORS" SPECIFICALLY DISCLAIMS ANY WARRANTIES,
19  * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
20  * AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
21  * ON AN "AS IS" BASIS, AND THE "AUTHORS" HAS NO OBLIGATION TO
22  * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
23  *
24  * Please maintain this header in its entirety when copying/modifying
25  * these files.
26  *
27  *
28  */
29 
30 
31 // Documentation for this file. If the \file tag isn't present,
32 // this file won't be documented.
33 /** \file
34  * \brief Configures the system clock.
35  *
36  * The clocking options for the PIC24 are chosen in this file.
37  * The resulting settings are used in pic24_clockfreq.c
38  * to configure and switch the oscillator as necessary after the chip
39  * is running.
40  *
41  * To choose a clock configuration, simply
42  * select a value for \ref CLOCK_CONFIG from the table there.
43  * The default selection used by most of the PIC24H examples is FRCPLL_FCY40MHz
44  * (the internal FRC+ PLL configured for FCY = 40 MHz). Some of the examples
45  * in Chapter 12 expect an external 8 MHz crystal, and use the PRIPLL_8MHzCrystal_40MHzFCY option
46  * (external 8 MHz crystal + PLL confgured for FCY = 40 MHz). If \ref CLOCK_CONFIG is not
47  * defined, the default choice for PIC24H processors is FRCPLL_FCY40MHz, while for PIC24F
48  * processors the default is FRCPLL_FCY16MHz (internal FRC+ PLL configured for FCY = 16 MHz).
49  *
50  * This file provides several useful defines as a result of the
51  * clock selection above:
52  * - \ref CLOCK_CONFIG itself, although this is not typically
53  * directly useful. To determine which clock configuration
54  * was chosen, use the \ref CLOCK_CONFIG_INDEX for comparsion
55  * by applying the \ref IS_CLOCK_CONFIG macro.
56  * - The oscillator source as a configuration word (\ref FNOSC_SEL)
57  * and as a COSC/NOSC bitfield in the OSCCON register
58  * (\ref OSC_SEL_BITS).
59  * - The processor clock frequency \ref FCY.
60  * - The primary oscillator type \ref POSCMD_SEL.
61  * - The primary oscillator freqency \ref POSC_FREQ.
62  *
63  * To define a new clock configuation:
64  * - Add a \#define to the table (see the section
65  * "#defines for CLOCK_CONFIG").
66  * - Add a configClockXxx() function which sets up
67  * and typically switches to that clock to
68  * pic24_clockfreq.c and a prototype for
69  * that function in this file.
70  */
71 
72 #ifndef _PIC24_CLOCKFREQ_H_
73 #define _PIC24_CLOCKFREQ_H_
74 
75 
76 #include <stdint.h>
77 #include "pic24_chip.h"
78 #include "pic24_libconfig.h"
79 
80 // Verify that the current processor is supported by the clock
81 // configuration chosen.
82 // 1. Set up some #defines as booleans which tell which processor
83 // is selected for this compile.
84 /// \cond nodoxygen
85 #ifdef __PIC24F__
86 #define PIC24F_DEFINED 1
87 #else
88 #define PIC24F_DEFINED 0
89 #endif
90 #ifdef __PIC24H__
91 #define PIC24H_DEFINED 1
92 #else
93 #define PIC24H_DEFINED 0
94 #endif
95 #ifdef __dsPIC33F__
96 #define dsPIC33F_DEFINED 1
97 #else
98 #define dsPIC33F_DEFINED 0
99 #endif
100 #ifdef __PIC24FK__
101 #define PIC24FK_DEFINED 1
102 #else
103 #define PIC24FK_DEFINED 0
104 #endif
105 #ifdef __PIC24E__
106 #define PIC24E_DEFINED 1
107 #else
108 #define PIC24E_DEFINED 0
109 #endif
110 #ifdef __dsPIC33E__
111 #define dsPIC33E_DEFINED 1
112 #else
113 #define dsPIC33E_DEFINED 0
114 #endif
115 /// \endcond
116 
117 
118 ///@{ \name #defines for CLOCK_CONFIG
119 /** Create a table of vales for \ref CLOCK_CONFIG.
120  * When adding a new entry, you must also write
121  * C code to configure the clock in \ref pic24_clockfreq.c.
122  * See that file for examples and the detailed description
123  * section at the top of this page for more information.
124  * Note that \ref FCY and
125  * \ref POSC_FREQ should be defined as a long (with a
126  * trailing L) to retain enough accuracy to store
127  * these values.
128  *
129  * Table entry notes: (see actual code, not the
130  * documentation, for the table)
131  * - Use -1 for don't-care values
132  * - The "unique index" just means each clock configuration
133  * should be assigned a different number. Giving two
134  * configurations the same index will cause problems!
135  * \see CLOCK_CONFIG_INDEX.
136  * - The processor field should evaluate to a Boolean value
137  * which is true if the processor under which this file
138  * is compiled is supported. Later in this file, the
139  * values PIC24F_DEFINED and PIC24H_DEFINED are set to
140  * true (1) or false (0) based on which processor this
141  * file is compiled with. Use these values in the
142  * Boolean expression. For example:
143  * - 1 (works on any processor)
144  * - PIC24H_DEFINED (works only on the PIC24H)
145  * - PIC24F_DEFINED || PIC24H_DEFINED
146  * (works on PIC24F and PIC24H).
147  * - Valid entries for \ref FNOSC_SEL are defined documentation
148  * for that variable.
149  */
150 // Table entries are:
151 // #define name Unique index FNOSC_SEL FCY POSCMD_SEL POSC_FREQ Processor configClock name Magic number of 498
152 // ------------------------------ ------------ ------------ --------- ---------- --------- ------------------------------------- ---------------- -------------------
153 #define SIM_CLOCK 0, -1, 1000000L, POSCMD_NONE, -1, 1, configClockSim, 498
154 #define FRCPLL_FCY16MHz 1, FNOSC_FRCPLL, 16000000L, POSCMD_NONE, -1, (PIC24F_DEFINED || PIC24FK_DEFINED), configClockFRCPLL_FCY16MHz, 498
155 #define FRC_FCY4MHz 2, FNOSC_FRC, 4000000L, POSCMD_NONE, -1, (PIC24F_DEFINED || PIC24FK_DEFINED), configClockFRC_FCY4MHz, 498
156 #define PRI_NO_PLL_7372KHzCrystal 3, FNOSC_PRI, 3686400L, POSCMD_XT, 7372800L, (PIC24F_DEFINED || PIC24FK_DEFINED || PIC24H_DEFINED || dsPIC33F_DEFINED), configClockPRI_NO_PLL_7372KHzCrystal, 498
157 #define FRC_FCY3685KHz 4, FNOSC_FRC, 3685000L, POSCMD_NONE, -1, (PIC24E_DEFINED || dsPIC33E_DEFINED|| PIC24H_DEFINED || dsPIC33F_DEFINED), configClockFRC_FCY3685KHz, 498
158 #define FRCPLL_FCY40MHz 5, FNOSC_FRCPLL, 40000000L, POSCMD_NONE, -1, (PIC24H_DEFINED || dsPIC33F_DEFINED), configClockFRCPLL_FCY40MHz, 498
159 #define PRIPLL_7372KHzCrystal_40MHzFCY 6, FNOSC_PRIPLL, 40000000L, POSCMD_XT, 7372800L, (PIC24H_DEFINED || dsPIC33F_DEFINED), configClockPRIPLL_7372KHzCrystal_40MHzFCY, 498
160 #define PRIPLL_8MHzCrystal_40MHzFCY 7, FNOSC_PRIPLL, 40000000L, POSCMD_XT, 8000000L, (PIC24H_DEFINED || dsPIC33F_DEFINED || PIC24E_DEFINED || dsPIC33E_DEFINED), configClockPRIPLL_8MHzCrystal_40MHzFCY, 498
161 #define PRIPLL_8MHzCrystal_16MHzFCY 8, FNOSC_PRIPLL, 16000000L, POSCMD_XT, 8000000L, (PIC24F_DEFINED || PIC24FK_DEFINED), configClockPRIPLL_8MHzCrystal_16MHzFCY, 498
162 #define PRI_8MHzCrystal_4MHzFCY 9, FNOSC_PRI, 4000000L, POSCMD_XT, 8000000L, (PIC24F_DEFINED || PIC24FK_DEFINED || PIC24H_DEFINED || dsPIC33F_DEFINED), configClockPRI_8MHzCrystal_4MHzFCY, 498
163 #define FRCPLL_FCY60MHz 10, FNOSC_FRCPLL, 60000000L, POSCMD_NONE, -1, (PIC24E_DEFINED || dsPIC33E_DEFINED), configClockFRCPLL_FCY60MHz, 498
164 #define FRCPLL_FCY70MHz 11, FNOSC_FRCPLL, 70000000L, POSCMD_NONE, -1, (PIC24E_DEFINED || dsPIC33E_DEFINED), configClockFRCPLL_FCY70MHz, 498
165 ///@}
166 
167 
168 #ifndef __DOXYGEN__ // The following non-standard #if confuses Doxygen
169 // Check to make sure the CLOCK_CONFIG choice selected
170 // exists and is valid. Otherwise, the compiler emits some very
171 // confusing errors. Cute hack: the last value in the #define
172 // above (the magic number) is what the #if tests in gcc.
173 #if (CLOCK_CONFIG != 498)
174 #error ***********************************************************************
175 #error * Value chosen for CLOCK_CONFIG does not exist or is not valid! *
176 #error * This produces very confusing compiler errors below. *
177 #error ***********************************************************************
178 #endif
179 #endif
180 
181 // For some reason, primary oscillator selections are named
182 // POSCMD_xx in the PIC24H and POSCMOD_xx in the PIC24F.
183 // Work around this.
184 // Hopefully, this will be defined in PIC24F headers at some point
185 /// \cond nodoxygen
186 #ifndef POSCMD_EC
187 #define POSCMD_EC POSCMOD_EC
188 #define POSCMD_XT POSCMOD_XT
189 #define POSCMD_HS POSCMOD_HS
190 #define POSCMD_NONE POSCMOD_NONE
191 #endif
192 /// \endcond
193 
194 // Turn clock config type info the right #defines, using
195 // a three step process:
196 // Step 1. Just use another macro to turn params (viewied as one argument here)
197 // to multiple arguments to the underscore version of the macro
198 /// \cond nodoxygen
199 #define GET_CLOCK_CONFIG_INDEX(params) _GET_CLOCK_CONFIG_INDEX(params)
200 #define GET_FNOSC_SEL(params) _GET_FNOSC_SEL(params)
201 #define GET_FCY(params) _GET_FCY(params)
202 #define GET_POSCMD_SEL(params) _GET_POSCMD_SEL(params)
203 #define GET_POSC_FREQ(params) _GET_POSC_FREQ(params)
204 #define GET_IS_SUPPORTED(params) _GET_IS_SUPPORTED(params)
205 #define GET_CONFIG_DEFAULT_CLOCK(params) _GET_CONFIG_DEFAULT_CLOCK(params)
206 
207 // Step 2. Return the desired parameter, now that params are seen as
208 // individual arguments.
209 #define _GET_CLOCK_CONFIG_INDEX(ndx, oscSel, Fcy, posCmdSel, poscFreq, isSupported, configClock, magic) ndx
210 #define _GET_FNOSC_SEL(ndx, oscSel, Fcy, posCmdSel, poscFreq, isSupported, configClockFunc, magic) oscSel
211 #define _GET_FCY(ndx, oscSel, Fcy, posCmdSel, poscFreq, isSupported, configClockFunc, magic) Fcy
212 #define _GET_POSCMD_SEL(ndx, oscSel, Fcy, posCmdSel, poscFreq, isSupported, configClockFunc, magic) posCmdSel
213 #define _GET_POSC_FREQ(ndx, oscSel, Fcy, posCmdSel, poscFreq, isSupported, configClockFunc, magic) poscFreq
214 #define _GET_IS_SUPPORTED(ndx, oscSel, Fcy, posCmdSel, poscFreq, isSupported, configClockFunc, magic) isSupported
215 #define _GET_CONFIG_DEFAULT_CLOCK(ndx, oscSel, Fcy, posCmdSel, poscFreq, isSupported, configClockFunc, magic) configClockFunc
216 // Step 3. Call the macros above to set constants based on the
217 // clock config selected.
218 /// \endcond
219 #define CLOCK_CONFIG_INDEX GET_CLOCK_CONFIG_INDEX(CLOCK_CONFIG)
220 #define FNOSC_SEL GET_FNOSC_SEL(CLOCK_CONFIG)
221 #define FCY GET_FCY(CLOCK_CONFIG)
222 #define POSCMD_SEL GET_POSCMD_SEL(CLOCK_CONFIG)
223 #define POSC_FREQ GET_POSC_FREQ(CLOCK_CONFIG)
224 #define CONFIG_DEFAULT_CLOCK() GET_CONFIG_DEFAULT_CLOCK(CLOCK_CONFIG)()
225 
226 // 2. Check to see if this clock configuration supports that processor.
227 #if !GET_IS_SUPPORTED(CLOCK_CONFIG)
228 #error The clock configuration chosen is not supported by this processor.
229 #endif
230 // 3. Check that the primary oscillator type chosen works for the
231 // oscilallator frequency selected. If the primary
232 #if (POSCMD_SEL == POSCMD_XT) && ( (POSC_FREQ < 3500000L) || (POSC_FREQ > 10000000L) )
233 #error The XT oscialltor chosen in POSCMD_SEL does not support this frequency!
234 #error Valid ranges are from 3.5 MHz to 10 MHz.
235 #endif
236 #if (POSCMD_SEL == POSCMD_HS) && ( (POSC_FREQ < 10000000L) || (POSC_FREQ > 32000000L) )
237 #error The HS oscialltor chosen in POSCMD_SEL does not support this frequency!
238 #error Valid ranges are from 10 MHz to 32 MHz.
239 #endif
240 
241 /// @{
242 /// \name Some of the #defines produced by CLOCK_CONFIG choice
243 
244 /** \def CLOCK_CONFIG_INDEX
245  * A unique number is assigned to each clock configuration,
246  * in order to allow comparsions between configurations.
247  * CLOCK_CONFIG_INDEX gives the number assigned to the
248  * selected clock configuration. The macro
249  * \ref IS_CLOCK_CONFIG uses this number for its comparsisons.
250  *
251  * \see SIM_CLOCK
252  */
253 
254 /** \def FNOSC_SEL
255  * Oscillator source selection for the PIC24. FNOSC_SEL
256  * is set to one of the following based on
257  * \ref CLOCK_CONFIG :
258  * \code
259  * Name Description PIC24F PIC24H
260  * ------------- -------------------------------------------- ------ ------
261  * FNOSC_FRC Fast RC oscillator X X
262  * FNOSC_FRCPLL Fast RC oscillator w/ divide and PLL X X
263  * FNOSC_PRI Primary oscillator (XT, HS, EC) X X
264  * FNOSC_PRIPLL Primary oscillator (XT, HS, EC) w/ PLL X X
265  * FNOSC_SOSC Secondary oscillator X X
266  * FNOSC_LPRC Low power RC oscillator X X
267  * FNOSC_FRCDIV Fast RC oscillator with divide X
268  * FNOSC_FRCDIV16 Fast RC oscillator w/ divide by 16 X
269  * FNOSC_LPRCDIVN Low power Fast RC oscillator w/divide by N X
270  \endcode
271  */
272 
273 /** \def FCY
274  * FCY specifies the resulting processor clock frequency after
275  * all PLL/divide operations take the inital clock and produce
276  * a processor clock. The units of this value are Hz, so the
277  * value 40000000L is 40 MHz.
278  *
279  * NOTE: This should be defined as a long (with a trailing L
280  * after the number) to allocate enough space to correctly
281  * store the processor clock frequency.
282  */
283 
284 /** \def POSCMD_SEL
285  * Specifies the primary oscillator type. Valid values:
286  * \code
287  * POSCMD_EC External clock
288  * POSCMD_XT XT oscillator (for crystals from 3.5 MHz to 10 MHz)
289  * POSCMD_HS HS oscillator (for crystals from 10 MHz to 32 MHz)
290  * POSCMD_NONE Primary oscillator disabled
291  * \endcode
292  */
293 
294 /** \def POSC_FREQ
295  * This values gives the primary osciallator frequency (if used).
296  * The units of this value are Hz, so the value 40000000L is 40 MHz.
297  *
298  * NOTE: This should be defined as a long (with a trailing L
299  * after the number) to allocate enough space to correctly
300  * store the processor clock frequency.
301 */
302 
303 /** \def OSC_SEL_BITS
304  * A macro giving the NOSC/COSC bits
305  * for the OSCCON register
306  * which correspond to \ref FNOSC_SEL,
307  * the configuration word which contains
308  * the FNOSC bits.
309  */
310 
311 /** \def CONFIG_DEFAULT_CLOCK
312  * Calls one of the configClock() functions defined
313  * in pic24_clockfreq.c based on the \ref CLOCK_CONFIG
314  * chosen.
315  */
316 ///@}
317 
318 /** A constant which gives the number of processor
319  * clock cycles in 1 millisecond. This value
320  * is cast to a uint32_t.
321  */
322 #define CYCLES_PER_MS ((uint32_t)(FCY * 0.001))
323 
324 /** A constant which gives the number of processor
325  * clock cycles in 1 microsecond. This value
326  * is cast to a uint32_t.
327  */
328 #define CYCLES_PER_US ((uint32_t)(FCY * 0.000001))
329 
330 
331 ///@{ \name Helper macros for clock configuration
332 /** A helper macro to check if the given clock configuration
333  * was selected. Example usage is given in
334  * \ref pic24_clockfreq.c. A shorter example:
335  * \code
336  * #if IS_CLOCK_CONFIG(FRCPLL_FCY40MHz)
337  * ... code only included if CLOCK_CONFIG is FRCPLL_FCY40MHz ...
338  * #endif
339  * \endcode
340  * \param clockConfig Clock configuration to compare the current
341  * clock configuation against.
342  */
343 #define IS_CLOCK_CONFIG(clockConfig) (_GET_CLOCK_CONFIG_INDEX(clockConfig) == CLOCK_CONFIG_INDEX)
344 
345 /** A macro to determine the NOSC/COSC bits
346  * for the OSCCON register given bits taken
347  * from the PIC24's configuration FNOSC word.
348  */
349 #define GET_OSC_SEL_BITS(bits) _GET_OSC_SEL_BITS(bits)
350 /// \cond nodoxygen
351 #if defined(__PIC24H__) || defined (__PIC24FK__) || defined(__dsPIC33F__) || defined(__PIC24E__) || defined(__dsPIC33E__) || defined(__DOXYGEN__)
352 #define _GET_OSC_SEL_BITS(bits) ((bits >> 0) & 0x07)
353 #elif defined (__PIC24F__)
354 #define _GET_OSC_SEL_BITS(bits) ((bits >> 8) & 0x07)
355 #else
356 #error Unknown processor
357 #endif
358 // Note: putting the \ endcond here causes Doxygen 1.5.6
359 // to complain. ???
360 ///@}
361 /// \endcond
362 #define OSC_SEL_BITS GET_OSC_SEL_BITS(FNOSC_SEL)
363 
364 // Double check to make sure the oscillator selection above is valid.
365 #if ( (OSC_SEL_BITS < 0) || (OSC_SEL_BITS > 7) )
366 #error Invalid oscillator selection FNOSC_SEL.
367 #endif
368 
369 /** @{
370  * \name configClock() functions for various clock setups
371  */
372 
373 
374 #if GET_IS_SUPPORTED(SIM_CLOCK)
375 /** Nothing to do! Simulator clock not set by OSCCON,
376  * but instead in the Debugger | Settings, Osc/Trace
377  * dialog box. It should be 2 MHz there, since that's
378  * Fosc = 2*Fcy. At 1 MHz, simulation speed seems fast
379  * enough to execute a reasonable amount of code. Also,
380  * at a 64K line trace buffer, we can see 64 ms of
381  * execution, which is plenty to see 20 ms servo pulses.
382  */
383 void configClockSim(void);
384 #endif
385 
386 #if GET_IS_SUPPORTED(FRCPLL_FCY16MHz)
387 void configClockFRCPLL_FCY16MHz(void);
388 #endif
389 
390 #if GET_IS_SUPPORTED(FRC_FCY4MHz)
391 void configClockFRC_FCY4MHz(void);
392 #endif
393 
394 #if GET_IS_SUPPORTED(PRI_NO_PLL_7372KHzCrystal)
395 void configClockPRI_NO_PLL_7372KHzCrystal(void);
396 #endif
397 
398 #if GET_IS_SUPPORTED(FRC_FCY3685KHz)
399 void configClockFRC_FCY3685KHz(void);
400 #endif
401 
402 #if GET_IS_SUPPORTED(FRCPLL_FCY40MHz)
403 void configClockFRCPLL_FCY40MHz(void);
404 #endif
405 
406 #if GET_IS_SUPPORTED(FRCPLL_FCY60MHz)
407 void configClockFRCPLL_FCY60MHz(void);
408 #endif
409 
410 #if GET_IS_SUPPORTED(FRCPLL_FCY70MHz)
411 void configClockFRCPLL_FCY70MHz(void);
412 #endif
413 
414 #if GET_IS_SUPPORTED(PRI_NO_PLL_7372KHzCrystal)
415 void configClockPRIPLL_7372KHzCrystal_40MHzFCY(void);
416 #endif
417 
418 #if GET_IS_SUPPORTED(PRIPLL_8MHzCrystal_40MHzFCY)
419 void configClockPRIPLL_8MHzCrystal_40MHzFCY(void);
420 #endif
421 
422 #if GET_IS_SUPPORTED(PRIPLL_8MHzCrystal_16MHzFCY)
423 void configClockPRIPLL_8MHzCrystal_16MHzFCY(void);
424 #endif
425 
426 #if GET_IS_SUPPORTED(PRI_8MHzCrystal_4MHzFCY)
427 void configClockPRI_8MHzCrystal_4MHzFCY(void);
428 #endif
429 
430 
431 /// @}
432 
433 /** Configure the default clock by calling the
434  * \ref CONFIG_DEFAULT_CLOCK() macro.
435  */
436 static inline void configClock() {
438 }
439 
440 
441 /** Switch the clock to the source specified. The source
442  * given will be assigned to NOSC in the OSCCON register,
443  * the a switch clock performed.
444  *
445  * Note: <b>DO NOT</b> use \ref FNOSC_SEL as the source;
446  * instead, use \ref OSC_SEL_BITS. FNOSC_SEL is for
447  * configuration bits while switchClock
448  * expects a NOSC value to write to the
449  * OSCCON register.
450  *
451  * \param u8_source The clock source to switch to.
452  */
453 void switchClock(uint8_t u8_source);
454 
455 #endif