]> git.sur5r.net Git - freertos/blob
858bf344b66346f34460cbd871e33771953553cf
[freertos] /
1 /***************************************************************************//**\r
2  * @file system_efm32wg.c\r
3  * @brief CMSIS Cortex-M4 System Layer for EFM32WG devices.\r
4  * @version 4.0.0\r
5  ******************************************************************************\r
6  * @section License\r
7  * <b>(C) 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 #if defined(_EFM32_GIANT_FAMILY) || defined(_EFM32_WONDER_FAMILY)\r
58 #define EFM32_HFXO_FREQ (48000000UL)        \r
59 #else\r
60 #define EFM32_HFXO_FREQ (32000000UL)\r
61 #endif\r
62 #endif\r
63 /* Do not define variable if HF crystal oscillator not present */\r
64 #if (EFM32_HFXO_FREQ > 0)\r
65 /** @cond DO_NOT_INCLUDE_WITH_DOXYGEN */\r
66 /** System HFXO clock. */ \r
67 static uint32_t SystemHFXOClock = EFM32_HFXO_FREQ;\r
68 /** @endcond (DO_NOT_INCLUDE_WITH_DOXYGEN) */\r
69 #endif\r
70 \r
71 #ifndef EFM32_LFXO_FREQ \r
72 #define EFM32_LFXO_FREQ (EFM32_LFRCO_FREQ)\r
73 #endif\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 #if defined(_EFM32_GIANT_FAMILY) || defined(_EFM32_WONDER_FAMILY)\r
129   /* Leopard/Giant/Wonder Gecko has an additional divider */\r
130   ret =  ret / (1 + ((CMU->CTRL & _CMU_CTRL_HFCLKDIV_MASK)>>_CMU_CTRL_HFCLKDIV_SHIFT));\r
131 #endif\r
132   ret >>= (CMU->HFCORECLKDIV & _CMU_HFCORECLKDIV_HFCORECLKDIV_MASK) >> \r
133           _CMU_HFCORECLKDIV_HFCORECLKDIV_SHIFT;\r
134 \r
135   /* Keep CMSIS variable up-to-date just in case */\r
136   SystemCoreClock = ret;\r
137 \r
138   return ret;\r
139 }\r
140 \r
141 \r
142 /***************************************************************************//**\r
143  * @brief\r
144  *   Get the current HFCLK frequency.\r
145  *\r
146  * @note\r
147  *   This is an EFM32 proprietary function, not part of the CMSIS definition.\r
148  *\r
149  * @return\r
150  *   The current HFCLK frequency in Hz.\r
151  ******************************************************************************/\r
152 uint32_t SystemHFClockGet(void)\r
153 {\r
154   uint32_t ret;\r
155   \r
156   switch (CMU->STATUS & (CMU_STATUS_HFRCOSEL | CMU_STATUS_HFXOSEL |\r
157                          CMU_STATUS_LFRCOSEL | CMU_STATUS_LFXOSEL))\r
158   {\r
159     case CMU_STATUS_LFXOSEL:\r
160 #if (EFM32_LFXO_FREQ > 0)\r
161       ret = SystemLFXOClock;\r
162 #else\r
163       /* We should not get here, since core should not be clocked. May */\r
164       /* be caused by a misconfiguration though. */\r
165       ret = 0;\r
166 #endif\r
167       break;\r
168       \r
169     case CMU_STATUS_LFRCOSEL:\r
170       ret = EFM32_LFRCO_FREQ;\r
171       break;\r
172       \r
173     case CMU_STATUS_HFXOSEL:\r
174 #if (EFM32_HFXO_FREQ > 0)\r
175       ret = SystemHFXOClock;\r
176 #else\r
177       /* We should not get here, since core should not be clocked. May */\r
178       /* be caused by a misconfiguration though. */\r
179       ret = 0;\r
180 #endif\r
181       break;\r
182       \r
183     default: /* CMU_STATUS_HFRCOSEL */\r
184       switch (CMU->HFRCOCTRL & _CMU_HFRCOCTRL_BAND_MASK)\r
185       {\r
186       case CMU_HFRCOCTRL_BAND_28MHZ:\r
187         ret = 28000000;\r
188         break;\r
189 \r
190       case CMU_HFRCOCTRL_BAND_21MHZ:\r
191         ret = 21000000;\r
192         break;\r
193 \r
194       case CMU_HFRCOCTRL_BAND_14MHZ:\r
195         ret = 14000000;\r
196         break;\r
197 \r
198       case CMU_HFRCOCTRL_BAND_11MHZ:\r
199         ret = 11000000;\r
200         break;\r
201 \r
202       case CMU_HFRCOCTRL_BAND_7MHZ:\r
203         if ( GetProdRev() >= 19 )\r
204           ret = 6600000;\r
205         else\r
206           ret = 7000000;\r
207         break;\r
208 \r
209       case CMU_HFRCOCTRL_BAND_1MHZ:\r
210         if ( GetProdRev() >= 19 )\r
211           ret = 1200000;\r
212         else\r
213           ret = 1000000;\r
214         break;\r
215 \r
216       default:\r
217         ret = 0;\r
218         break;\r
219       }\r
220       break;\r
221   }\r
222 \r
223   return ret;\r
224 }\r
225 \r
226 \r
227 /**************************************************************************//**\r
228  * @brief\r
229  *   Get high frequency crystal oscillator clock frequency for target system.\r
230  *\r
231  * @note\r
232  *   This is an EFM32 proprietary function, not part of the CMSIS definition.\r
233  *\r
234  * @return\r
235  *   HFXO frequency in Hz.\r
236  *****************************************************************************/\r
237 uint32_t SystemHFXOClockGet(void)\r
238 {\r
239   /* External crystal oscillator present? */\r
240 #if (EFM32_HFXO_FREQ > 0)\r
241   return SystemHFXOClock;\r
242 #else\r
243   return 0;\r
244 #endif\r
245 }\r
246 \r
247 \r
248 /**************************************************************************//**\r
249  * @brief\r
250  *   Set high frequency crystal oscillator clock frequency for target system.\r
251  *\r
252  * @note\r
253  *   This function is mainly provided for being able to handle target systems\r
254  *   with different HF crystal oscillator frequencies run-time. If used, it\r
255  *   should probably only be used once during system startup.\r
256  *\r
257  * @note\r
258  *   This is an EFM32 proprietary function, not part of the CMSIS definition.\r
259  *\r
260  * @param[in] freq\r
261  *   HFXO frequency in Hz used for target.\r
262  *****************************************************************************/\r
263 void SystemHFXOClockSet(uint32_t freq)\r
264 {\r
265   /* External crystal oscillator present? */\r
266 #if (EFM32_HFXO_FREQ > 0)\r
267   SystemHFXOClock = freq;\r
268 \r
269   /* Update core clock frequency if HFXO is used to clock core */\r
270   if (CMU->STATUS & CMU_STATUS_HFXOSEL)\r
271   {\r
272     /* The function will update the global variable */\r
273     SystemCoreClockGet();\r
274   }\r
275 #else\r
276   (void)freq; /* Unused parameter */\r
277 #endif\r
278 }\r
279 \r
280 \r
281 /**************************************************************************//**\r
282  * @brief\r
283  *   Initialize the system.\r
284  *\r
285  * @details\r
286  *   Do required generic HW system init.\r
287  *\r
288  * @note\r
289  *   This function is invoked during system init, before the main() routine\r
290  *   and any data has been initialized. For this reason, it cannot do any\r
291  *   initialization of variables etc.\r
292  *****************************************************************************/\r
293 void SystemInit(void)\r
294 {\r
295   /* Set floating point coprosessor access mode. */\r
296   SCB->CPACR |= ((3UL << 10*2) |                    /* set CP10 Full Access */\r
297                  (3UL << 11*2)  );                  /* set CP11 Full Access */\r
298 }\r
299 \r
300 \r
301 /**************************************************************************//**\r
302  * @brief\r
303  *   Get low frequency RC oscillator clock frequency for target system.\r
304  *\r
305  * @note\r
306  *   This is an EFM32 proprietary function, not part of the CMSIS definition.\r
307  *\r
308  * @return\r
309  *   LFRCO frequency in Hz.\r
310  *****************************************************************************/\r
311 uint32_t SystemLFRCOClockGet(void)\r
312 {\r
313   /* Currently we assume that this frequency is properly tuned during */\r
314   /* manufacturing and is not changed after reset. If future requirements */\r
315   /* for re-tuning by user, we can add support for that. */\r
316   return EFM32_LFRCO_FREQ;\r
317 }\r
318 \r
319 \r
320 /**************************************************************************//**\r
321  * @brief\r
322  *   Get ultra low frequency RC oscillator clock frequency for target system.\r
323  *\r
324  * @note\r
325  *   This is an EFM32 proprietary function, not part of the CMSIS definition.\r
326  *\r
327  * @return\r
328  *   ULFRCO frequency in Hz.\r
329  *****************************************************************************/\r
330 uint32_t SystemULFRCOClockGet(void)\r
331 {\r
332   /* The ULFRCO frequency is not tuned, and can be very inaccurate */\r
333   return EFM32_ULFRCO_FREQ;\r
334 }\r
335 \r
336 \r
337 /**************************************************************************//**\r
338  * @brief\r
339  *   Get low frequency crystal oscillator clock frequency for target system.\r
340  *\r
341  * @note\r
342  *   This is an EFM32 proprietary function, not part of the CMSIS definition.\r
343  *\r
344  * @return\r
345  *   LFXO frequency in Hz.\r
346  *****************************************************************************/\r
347 uint32_t SystemLFXOClockGet(void)\r
348 {\r
349   /* External crystal oscillator present? */\r
350 #if (EFM32_LFXO_FREQ > 0)\r
351   return SystemLFXOClock;\r
352 #else\r
353   return 0;\r
354 #endif\r
355 }\r
356 \r
357 \r
358 /**************************************************************************//**\r
359  * @brief\r
360  *   Set low frequency crystal oscillator clock frequency for target system.\r
361  *\r
362  * @note\r
363  *   This function is mainly provided for being able to handle target systems\r
364  *   with different HF crystal oscillator frequencies run-time. If used, it\r
365  *   should probably only be used once during system startup.\r
366  *\r
367  * @note\r
368  *   This is an EFM32 proprietary function, not part of the CMSIS definition.\r
369  *\r
370  * @param[in] freq\r
371  *   LFXO frequency in Hz used for target.\r
372  *****************************************************************************/\r
373 void SystemLFXOClockSet(uint32_t freq)\r
374 {\r
375   /* External crystal oscillator present? */\r
376 #if (EFM32_LFXO_FREQ > 0)\r
377   SystemLFXOClock = freq;\r
378 \r
379   /* Update core clock frequency if LFXO is used to clock core */\r
380   if (CMU->STATUS & CMU_STATUS_LFXOSEL)\r
381   {\r
382     /* The function will update the global variable */\r
383     SystemCoreClockGet();\r
384   }\r
385 #else\r
386   (void)freq; /* Unused parameter */\r
387 #endif\r
388 }\r