]> git.sur5r.net Git - freertos/blob
d1fe369d0b4fc4a9ad23036e01a9eab845f149c9
[freertos] /
1 /***************************************************************************//**\r
2  * @file system_efm32wg.c\r
3  * @brief CMSIS Cortex-M4 System Layer for EFM32WG devices.\r
4  * @version 4.2.1\r
5  ******************************************************************************\r
6  * @section License\r
7  * <b>Copyright 2015 Silicon Laboratories, Inc. http://www.silabs.com</b>\r
8  ******************************************************************************\r
9  *\r
10  * Permission is granted to anyone to use this software for any purpose,\r
11  * including commercial applications, and to alter it and redistribute it\r
12  * freely, subject to the following restrictions:\r
13  *\r
14  * 1. The origin of this software must not be misrepresented; you must not\r
15  *    claim that you wrote the original software.@n\r
16  * 2. Altered source versions must be plainly marked as such, and must not be\r
17  *    misrepresented as being the original software.@n\r
18  * 3. This notice may not be removed or altered from any source distribution.\r
19  *\r
20  * DISCLAIMER OF WARRANTY/LIMITATION OF REMEDIES: Silicon Laboratories, Inc.\r
21  * has no obligation to support this Software. Silicon Laboratories, Inc. is\r
22  * providing the Software "AS IS", with no express or implied warranties of any\r
23  * kind, including, but not limited to, any implied warranties of\r
24  * merchantability or fitness for any particular purpose or warranties against\r
25  * infringement of any proprietary rights of a third party.\r
26  *\r
27  * Silicon Laboratories, Inc. will not be liable for any consequential,\r
28  * incidental, or special damages, or any other relief, or for any claim by\r
29  * any third party, arising from your use of this Software.\r
30  *\r
31  *****************************************************************************/\r
32 \r
33 #include <stdint.h>\r
34 #include "em_device.h"\r
35 \r
36 /*******************************************************************************\r
37  ******************************   DEFINES   ************************************\r
38  ******************************************************************************/\r
39 \r
40 /** LFRCO frequency, tuned to below frequency during manufacturing. */\r
41 #define EFM32_LFRCO_FREQ  (32768UL)\r
42 #define EFM32_ULFRCO_FREQ (1000UL)\r
43 \r
44 /*******************************************************************************\r
45  **************************   LOCAL VARIABLES   ********************************\r
46  ******************************************************************************/\r
47 \r
48 /* System oscillator frequencies. These frequencies are normally constant */\r
49 /* for a target, but they are made configurable in order to allow run-time */\r
50 /* handling of different boards. The crystal oscillator clocks can be set */\r
51 /* compile time to a non-default value by defining respective EFM32_nFXO_FREQ */\r
52 /* values according to board design. By defining the EFM32_nFXO_FREQ to 0, */\r
53 /* one indicates that the oscillator is not present, in order to save some */\r
54 /* SW footprint. */\r
55 \r
56 #ifndef EFM32_HFXO_FREQ\r
57 #define EFM32_HFXO_FREQ (48000000UL)\r
58 #endif\r
59 \r
60 #define EFM32_HFRCO_MAX_FREQ (28000000UL)\r
61 \r
62 /* Do not define variable if HF crystal oscillator not present */\r
63 #if (EFM32_HFXO_FREQ > 0)\r
64 /** @cond DO_NOT_INCLUDE_WITH_DOXYGEN */\r
65 /** System HFXO clock. */\r
66 static uint32_t SystemHFXOClock = EFM32_HFXO_FREQ;\r
67 /** @endcond (DO_NOT_INCLUDE_WITH_DOXYGEN) */\r
68 #endif\r
69 \r
70 #ifndef EFM32_LFXO_FREQ\r
71 #define EFM32_LFXO_FREQ (EFM32_LFRCO_FREQ)\r
72 #endif\r
73 \r
74 /* Do not define variable if LF crystal oscillator not present */\r
75 #if (EFM32_LFXO_FREQ > 0)\r
76 /** @cond DO_NOT_INCLUDE_WITH_DOXYGEN */\r
77 /** System LFXO clock. */\r
78 static uint32_t SystemLFXOClock = EFM32_LFXO_FREQ;\r
79 /** @endcond (DO_NOT_INCLUDE_WITH_DOXYGEN) */\r
80 #endif\r
81 \r
82 /* Inline function to get the chip's Production Revision. */\r
83 __STATIC_INLINE uint8_t GetProdRev(void)\r
84 {\r
85   return ((DEVINFO->PART & _DEVINFO_PART_PROD_REV_MASK)\r
86                          >> _DEVINFO_PART_PROD_REV_SHIFT);\r
87 }\r
88 \r
89 /*******************************************************************************\r
90  **************************   GLOBAL VARIABLES   *******************************\r
91  ******************************************************************************/\r
92 \r
93 /**\r
94  * @brief\r
95  *   System System Clock Frequency (Core Clock).\r
96  *\r
97  * @details\r
98  *   Required CMSIS global variable that must be kept up-to-date.\r
99  */\r
100 uint32_t SystemCoreClock;\r
101 \r
102 /*******************************************************************************\r
103  **************************   GLOBAL FUNCTIONS   *******************************\r
104  ******************************************************************************/\r
105 \r
106 /***************************************************************************//**\r
107  * @brief\r
108  *   Get the current core clock frequency.\r
109  *\r
110  * @details\r
111  *   Calculate and get the current core clock frequency based on the current\r
112  *   configuration. Assuming that the SystemCoreClock global variable is\r
113  *   maintained, the core clock frequency is stored in that variable as well.\r
114  *   This function will however calculate the core clock based on actual HW\r
115  *   configuration. It will also update the SystemCoreClock global variable.\r
116  *\r
117  * @note\r
118  *   This is an EFM32 proprietary function, not part of the CMSIS definition.\r
119  *\r
120  * @return\r
121  *   The current core clock frequency in Hz.\r
122  ******************************************************************************/\r
123 uint32_t SystemCoreClockGet(void)\r
124 {\r
125   uint32_t ret;\r
126 \r
127   ret = SystemHFClockGet();\r
128   /* Leopard/Giant/Wonder Gecko has an additional divider */\r
129   ret =  ret / (1 + ((CMU->CTRL & _CMU_CTRL_HFCLKDIV_MASK)>>_CMU_CTRL_HFCLKDIV_SHIFT));\r
130   ret >>= (CMU->HFCORECLKDIV & _CMU_HFCORECLKDIV_HFCORECLKDIV_MASK) >>\r
131           _CMU_HFCORECLKDIV_HFCORECLKDIV_SHIFT;\r
132 \r
133   /* Keep CMSIS variable up-to-date just in case */\r
134   SystemCoreClock = ret;\r
135 \r
136   return ret;\r
137 }\r
138 \r
139 \r
140 /***************************************************************************//**\r
141  * @brief\r
142  *   Get the maximum core clock frequency.\r
143  *\r
144  * @note\r
145  *   This is an EFR32 proprietary function, not part of the CMSIS definition.\r
146  *\r
147  * @return\r
148  *   The maximum core clock frequency in Hz.\r
149  ******************************************************************************/\r
150 uint32_t SystemMaxCoreClockGet(void)\r
151 {\r
152   return (EFM32_HFRCO_MAX_FREQ > EFM32_HFXO_FREQ ? \\r
153           EFM32_HFRCO_MAX_FREQ : EFM32_HFXO_FREQ);\r
154 }\r
155 \r
156 \r
157 /***************************************************************************//**\r
158  * @brief\r
159  *   Get the current HFCLK frequency.\r
160  *\r
161  * @note\r
162  *   This is an EFM32 proprietary function, not part of the CMSIS definition.\r
163  *\r
164  * @return\r
165  *   The current HFCLK frequency in Hz.\r
166  ******************************************************************************/\r
167 uint32_t SystemHFClockGet(void)\r
168 {\r
169   uint32_t ret;\r
170 \r
171   switch (CMU->STATUS & (CMU_STATUS_HFRCOSEL | CMU_STATUS_HFXOSEL |\r
172                          CMU_STATUS_LFRCOSEL | CMU_STATUS_LFXOSEL))\r
173   {\r
174     case CMU_STATUS_LFXOSEL:\r
175 #if (EFM32_LFXO_FREQ > 0)\r
176       ret = SystemLFXOClock;\r
177 #else\r
178       /* We should not get here, since core should not be clocked. May */\r
179       /* be caused by a misconfiguration though. */\r
180       ret = 0;\r
181 #endif\r
182       break;\r
183 \r
184     case CMU_STATUS_LFRCOSEL:\r
185       ret = EFM32_LFRCO_FREQ;\r
186       break;\r
187 \r
188     case CMU_STATUS_HFXOSEL:\r
189 #if (EFM32_HFXO_FREQ > 0)\r
190       ret = SystemHFXOClock;\r
191 #else\r
192       /* We should not get here, since core should not be clocked. May */\r
193       /* be caused by a misconfiguration though. */\r
194       ret = 0;\r
195 #endif\r
196       break;\r
197 \r
198     default: /* CMU_STATUS_HFRCOSEL */\r
199       switch (CMU->HFRCOCTRL & _CMU_HFRCOCTRL_BAND_MASK)\r
200       {\r
201       case CMU_HFRCOCTRL_BAND_28MHZ:\r
202         ret = 28000000;\r
203         break;\r
204 \r
205       case CMU_HFRCOCTRL_BAND_21MHZ:\r
206         ret = 21000000;\r
207         break;\r
208 \r
209       case CMU_HFRCOCTRL_BAND_14MHZ:\r
210         ret = 14000000;\r
211         break;\r
212 \r
213       case CMU_HFRCOCTRL_BAND_11MHZ:\r
214         ret = 11000000;\r
215         break;\r
216 \r
217       case CMU_HFRCOCTRL_BAND_7MHZ:\r
218         if ( GetProdRev() >= 19 )\r
219           ret = 6600000;\r
220         else\r
221           ret = 7000000;\r
222         break;\r
223 \r
224       case CMU_HFRCOCTRL_BAND_1MHZ:\r
225         if ( GetProdRev() >= 19 )\r
226           ret = 1200000;\r
227         else\r
228           ret = 1000000;\r
229         break;\r
230 \r
231       default:\r
232         ret = 0;\r
233         break;\r
234       }\r
235       break;\r
236   }\r
237 \r
238   return ret;\r
239 }\r
240 \r
241 \r
242 /**************************************************************************//**\r
243  * @brief\r
244  *   Get high frequency crystal oscillator clock frequency for target system.\r
245  *\r
246  * @note\r
247  *   This is an EFM32 proprietary function, not part of the CMSIS definition.\r
248  *\r
249  * @return\r
250  *   HFXO frequency in Hz.\r
251  *****************************************************************************/\r
252 uint32_t SystemHFXOClockGet(void)\r
253 {\r
254   /* External crystal oscillator present? */\r
255 #if (EFM32_HFXO_FREQ > 0)\r
256   return SystemHFXOClock;\r
257 #else\r
258   return 0;\r
259 #endif\r
260 }\r
261 \r
262 \r
263 /**************************************************************************//**\r
264  * @brief\r
265  *   Set high frequency crystal oscillator clock frequency for target system.\r
266  *\r
267  * @note\r
268  *   This function is mainly provided for being able to handle target systems\r
269  *   with different HF crystal oscillator frequencies run-time. If used, it\r
270  *   should probably only be used once during system startup.\r
271  *\r
272  * @note\r
273  *   This is an EFM32 proprietary function, not part of the CMSIS definition.\r
274  *\r
275  * @param[in] freq\r
276  *   HFXO frequency in Hz used for target.\r
277  *****************************************************************************/\r
278 void SystemHFXOClockSet(uint32_t freq)\r
279 {\r
280   /* External crystal oscillator present? */\r
281 #if (EFM32_HFXO_FREQ > 0)\r
282   SystemHFXOClock = freq;\r
283 \r
284   /* Update core clock frequency if HFXO is used to clock core */\r
285   if (CMU->STATUS & CMU_STATUS_HFXOSEL)\r
286   {\r
287     /* The function will update the global variable */\r
288     SystemCoreClockGet();\r
289   }\r
290 #else\r
291   (void)freq; /* Unused parameter */\r
292 #endif\r
293 }\r
294 \r
295 \r
296 /**************************************************************************//**\r
297  * @brief\r
298  *   Initialize the system.\r
299  *\r
300  * @details\r
301  *   Do required generic HW system init.\r
302  *\r
303  * @note\r
304  *   This function is invoked during system init, before the main() routine\r
305  *   and any data has been initialized. For this reason, it cannot do any\r
306  *   initialization of variables etc.\r
307  *****************************************************************************/\r
308 void SystemInit(void)\r
309 {\r
310   /* Set floating point coprosessor access mode. */\r
311   SCB->CPACR |= ((3UL << 10*2) |                    /* set CP10 Full Access */\r
312                  (3UL << 11*2)  );                  /* set CP11 Full Access */\r
313 }\r
314 \r
315 \r
316 /**************************************************************************//**\r
317  * @brief\r
318  *   Get low frequency RC oscillator clock frequency for target system.\r
319  *\r
320  * @note\r
321  *   This is an EFM32 proprietary function, not part of the CMSIS definition.\r
322  *\r
323  * @return\r
324  *   LFRCO frequency in Hz.\r
325  *****************************************************************************/\r
326 uint32_t SystemLFRCOClockGet(void)\r
327 {\r
328   /* Currently we assume that this frequency is properly tuned during */\r
329   /* manufacturing and is not changed after reset. If future requirements */\r
330   /* for re-tuning by user, we can add support for that. */\r
331   return EFM32_LFRCO_FREQ;\r
332 }\r
333 \r
334 \r
335 /**************************************************************************//**\r
336  * @brief\r
337  *   Get ultra low frequency RC oscillator clock frequency for target system.\r
338  *\r
339  * @note\r
340  *   This is an EFM32 proprietary function, not part of the CMSIS definition.\r
341  *\r
342  * @return\r
343  *   ULFRCO frequency in Hz.\r
344  *****************************************************************************/\r
345 uint32_t SystemULFRCOClockGet(void)\r
346 {\r
347   /* The ULFRCO frequency is not tuned, and can be very inaccurate */\r
348   return EFM32_ULFRCO_FREQ;\r
349 }\r
350 \r
351 \r
352 /**************************************************************************//**\r
353  * @brief\r
354  *   Get low frequency crystal oscillator clock frequency for target system.\r
355  *\r
356  * @note\r
357  *   This is an EFM32 proprietary function, not part of the CMSIS definition.\r
358  *\r
359  * @return\r
360  *   LFXO frequency in Hz.\r
361  *****************************************************************************/\r
362 uint32_t SystemLFXOClockGet(void)\r
363 {\r
364   /* External crystal oscillator present? */\r
365 #if (EFM32_LFXO_FREQ > 0)\r
366   return SystemLFXOClock;\r
367 #else\r
368   return 0;\r
369 #endif\r
370 }\r
371 \r
372 \r
373 /**************************************************************************//**\r
374  * @brief\r
375  *   Set low frequency crystal oscillator clock frequency for target system.\r
376  *\r
377  * @note\r
378  *   This function is mainly provided for being able to handle target systems\r
379  *   with different HF crystal oscillator frequencies run-time. If used, it\r
380  *   should probably only be used once during system startup.\r
381  *\r
382  * @note\r
383  *   This is an EFM32 proprietary function, not part of the CMSIS definition.\r
384  *\r
385  * @param[in] freq\r
386  *   LFXO frequency in Hz used for target.\r
387  *****************************************************************************/\r
388 void SystemLFXOClockSet(uint32_t freq)\r
389 {\r
390   /* External crystal oscillator present? */\r
391 #if (EFM32_LFXO_FREQ > 0)\r
392   SystemLFXOClock = freq;\r
393 \r
394   /* Update core clock frequency if LFXO is used to clock core */\r
395   if (CMU->STATUS & CMU_STATUS_LFXOSEL)\r
396   {\r
397     /* The function will update the global variable */\r
398     SystemCoreClockGet();\r
399   }\r
400 #else\r
401   (void)freq; /* Unused parameter */\r
402 #endif\r
403 }\r