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