]> git.sur5r.net Git - freertos/blob - FreeRTOS/Demo/CORTEX_M7_SAMV71_Xplained_IAR_Keil/libchip_samv7/source/pmc.c
Final V8.2.1 release ready for tagging:
[freertos] / FreeRTOS / Demo / CORTEX_M7_SAMV71_Xplained_IAR_Keil / libchip_samv7 / source / pmc.c
1 /* ----------------------------------------------------------------------------\r
2  *         SAM Software Package License\r
3  * ----------------------------------------------------------------------------\r
4  * Copyright (c) 2014, Atmel Corporation\r
5  *\r
6  * All rights reserved.\r
7  *\r
8  * Redistribution and use in source and binary forms, with or without\r
9  * modification, are permitted provided that the following conditions are met:\r
10  *\r
11  * - Redistributions of source code must retain the above copyright notice,\r
12  * this list of conditions and the disclaimer below.\r
13  *\r
14  * Atmel's name may not be used to endorse or promote products derived from\r
15  * this software without specific prior written permission.\r
16  *\r
17  * DISCLAIMER: THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR\r
18  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF\r
19  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE\r
20  * DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR ANY DIRECT, INDIRECT,\r
21  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT\r
22  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,\r
23  * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF\r
24  * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING\r
25  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,\r
26  * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\r
27  * ----------------------------------------------------------------------------\r
28  */\r
29 \r
30 /*----------------------------------------------------------------------------\r
31  *        Headers\r
32  *----------------------------------------------------------------------------*/\r
33 \r
34 #include "chip.h"\r
35 \r
36 #include <assert.h>\r
37 \r
38 /*----------------------------------------------------------------------------\r
39  *        Local definitions\r
40  *----------------------------------------------------------------------------*/\r
41 \r
42 #define MASK_STATUS0 0xFFFFFFFC\r
43 #define MASK_STATUS1 0xFFFFFFFF\r
44 \r
45 /*----------------------------------------------------------------------------\r
46  *        Local functions\r
47  *----------------------------------------------------------------------------*/\r
48 /**\r
49  * \brief Switch MCK to PLLA clock.\r
50  */\r
51 static void _PMC_SwitchMck2PllaClock(void)\r
52 \r
53 {\r
54     /* Select PLLA as input clock for MCK */\r
55     PMC->PMC_MCKR = (PMC->PMC_MCKR & ~PMC_MCKR_CSS_Msk) | PMC_MCKR_CSS_PLLA_CLK ;\r
56 \r
57     /* Wait until the master clock is established */\r
58     while( !(PMC->PMC_SR & PMC_SR_MCKRDY) );\r
59 }\r
60 \r
61 /**\r
62  * \brief Switch MCK to main clock.\r
63  */\r
64 static void _PMC_SwitchMck2MainClock(void)\r
65 {\r
66     /* Select Main Oscillator as input clock for MCK */\r
67     PMC->PMC_MCKR = (PMC->PMC_MCKR & ~PMC_MCKR_CSS_Msk) | PMC_MCKR_CSS_MAIN_CLK ;\r
68 \r
69     /* Wait until the master clock is established */\r
70     while( !(PMC->PMC_SR & PMC_SR_MCKRDY) );\r
71     PMC->PMC_MCKR = PMC_MCKR_CSS_MAIN_CLK;\r
72     while( !(PMC->PMC_SR & PMC_SR_MCKRDY) );\r
73 }\r
74 \r
75 /**\r
76  * \brief Switch MCK to slow clock.\r
77  */\r
78 static void _PMC_SwitchMck2SlowClock(void)\r
79 {\r
80     /* Select Slow Clock as input clock for MCK */\r
81     PMC->PMC_MCKR = (PMC->PMC_MCKR & ~PMC_MCKR_CSS_Msk) | PMC_MCKR_CSS_SLOW_CLK ;\r
82 \r
83     /* Wait until the master clock is established */\r
84     while( !(PMC->PMC_SR & PMC_SR_MCKRDY) );\r
85 }\r
86 \r
87 /**\r
88  * \brief Set prescaler for MCK.\r
89  *\r
90  * \param prescaler Master Clock prescaler\r
91  */\r
92 static void _PMC_SetMckPrescaler(uint32_t prescaler)\r
93 {\r
94     /* Change MCK Prescaler divider in PMC_MCKR register */\r
95     PMC->PMC_MCKR = (PMC->PMC_MCKR & ~PMC_MCKR_PRES_Msk) | prescaler;\r
96 \r
97     /* Wait until the master clock is established */\r
98     while( !(PMC->PMC_SR & PMC_SR_MCKRDY) );\r
99 }\r
100 /*----------------------------------------------------------------------------\r
101  *        Exported functions\r
102  *----------------------------------------------------------------------------*/\r
103 \r
104 /**\r
105  * \brief Enables the clock of a peripheral. The peripheral ID is used\r
106  * to identify which peripheral is targeted.\r
107  *\r
108  * \note The ID must NOT be shifted (i.e. 1 << ID_xxx).\r
109  *\r
110  * \param id  Peripheral ID (ID_xxx).\r
111  */\r
112 extern void PMC_EnablePeripheral( uint32_t dwId )\r
113 {\r
114     assert( dwId < 63 ) ;\r
115 \r
116     if ( dwId < 32 )\r
117     {\r
118         if ( (PMC->PMC_PCSR0 & ((uint32_t)1 << dwId)) == ((uint32_t)1 << dwId) )\r
119         {\r
120             TRACE_DEBUG( "PMC_EnablePeripheral: clock of peripheral"  " %u is already enabled\n\r", (unsigned int)dwId ) ;\r
121         }\r
122         else\r
123         {\r
124             PMC->PMC_PCER0 = 1 << dwId ;\r
125         }\r
126     }\r
127     else\r
128     {\r
129         dwId -= 32;\r
130         if ((PMC->PMC_PCSR1 & ((uint32_t)1 << dwId)) == ((uint32_t)1 << dwId))\r
131         {\r
132             TRACE_DEBUG( "PMC_EnablePeripheral: clock of peripheral"  " %u is already enabled\n\r", (unsigned int)(dwId + 32) ) ;\r
133         }\r
134         else\r
135         {\r
136             PMC->PMC_PCER1 = 1 << dwId ;\r
137         }\r
138     }\r
139 }\r
140 \r
141 /**\r
142  * \brief Disables the clock of a peripheral. The peripheral ID is used\r
143  * to identify which peripheral is targeted.\r
144  *\r
145  * \note The ID must NOT be shifted (i.e. 1 << ID_xxx).\r
146  *\r
147  * \param id  Peripheral ID (ID_xxx).\r
148  */\r
149 extern void PMC_DisablePeripheral( uint32_t dwId )\r
150 {\r
151     assert( dwId < 63 ) ;\r
152 \r
153     if ( dwId < 32 )\r
154     {\r
155         if ( (PMC->PMC_PCSR0 & ((uint32_t)1 << dwId)) != ((uint32_t)1 << dwId) )\r
156         {\r
157             TRACE_DEBUG("PMC_DisablePeripheral: clock of peripheral" " %u is not enabled\n\r", (unsigned int)dwId ) ;\r
158         }\r
159         else\r
160         {\r
161             PMC->PMC_PCDR0 = 1 << dwId ;\r
162         }\r
163     }\r
164     else\r
165     {\r
166         dwId -= 32 ;\r
167         if ( (PMC->PMC_PCSR1 & ((uint32_t)1 << dwId)) != ((uint32_t)1 << dwId) )\r
168         {\r
169             TRACE_DEBUG( "PMC_DisablePeripheral: clock of peripheral" " %u is not enabled\n\r", (unsigned int)(dwId + 32) ) ;\r
170         }\r
171         else\r
172         {\r
173             PMC->PMC_PCDR1 = 1 << dwId ;\r
174         }\r
175     }\r
176 }\r
177 \r
178 /**\r
179  * \brief Enable all the periph clock via PMC.\r
180  */\r
181 extern void PMC_EnableAllPeripherals( void )\r
182 {\r
183     PMC->PMC_PCER0 = MASK_STATUS0 ;\r
184     while ( (PMC->PMC_PCSR0 & MASK_STATUS0) != MASK_STATUS0 ) ;\r
185 \r
186     PMC->PMC_PCER1 = MASK_STATUS1 ;\r
187     while ( (PMC->PMC_PCSR1 & MASK_STATUS1) != MASK_STATUS1 ) ;\r
188 \r
189     TRACE_DEBUG( "Enable all periph clocks\n\r" ) ;\r
190 }\r
191 \r
192 /**\r
193  * \brief Disable all the periph clock via PMC.\r
194  */\r
195 extern void PMC_DisableAllPeripherals( void )\r
196 {\r
197     PMC->PMC_PCDR0 = MASK_STATUS0 ;\r
198     while ( (PMC->PMC_PCSR0 & MASK_STATUS0) != 0 ) ;\r
199 \r
200     PMC->PMC_PCDR1 = MASK_STATUS1 ;\r
201     while ( (PMC->PMC_PCSR1 & MASK_STATUS1) != 0 ) ;\r
202 \r
203     TRACE_DEBUG( "Disable all periph clocks\n\r" ) ;\r
204 }\r
205 \r
206 /**\r
207  * \brief Get Periph Status for the given peripheral ID.\r
208  *\r
209  * \param id  Peripheral ID (ID_xxx).\r
210  */\r
211 extern uint32_t PMC_IsPeriphEnabled( uint32_t dwId )\r
212 {\r
213     assert( dwId < ID_PERIPH_COUNT ) ;\r
214 \r
215     if ( dwId < 32 )\r
216     {\r
217         return ( PMC->PMC_PCSR0 & (1 << dwId) ) ;\r
218     }\r
219     else {\r
220         return ( PMC->PMC_PCSR1 & (1 << (dwId - 32)) ) ;\r
221     }\r
222 }\r
223 \r
224 \r
225 /**\r
226  * \brief Enable external oscilator as main clock input.\r
227  */\r
228 extern void PMC_EnableExtOsc(void)\r
229 {\r
230     uint32_t   read_MOR;\r
231 \r
232     /* Before switching MAIN OSC on external crystal : enable it and don't disable\r
233      * at the same time RC OSC in case of if MAIN OSC is still using RC OSC\r
234      */\r
235 \r
236     read_MOR = PMC->CKGR_MOR;\r
237 \r
238     read_MOR &= ~CKGR_MOR_MOSCRCF_Msk;   /* reset MOSCRCF field in MOR register before select RC 12MHz */\r
239     read_MOR  |= (CKGR_MOR_KEY_PASSWD \r
240             |   CKGR_MOR_MOSCRCF_12_MHz\r
241             |   CKGR_MOR_MOSCXTEN     \r
242             |   CKGR_MOR_MOSCRCEN     \r
243             |   CKGR_MOR_MOSCXTST(DEFAUTL_MAIN_OSC_COUNT));  /* enable external crystal - enable RC OSC */\r
244 \r
245     PMC->CKGR_MOR = read_MOR;\r
246 \r
247     while( !(PMC->PMC_SR & PMC_SR_MOSCRCS ) );  /* wait end of RC oscillator stabilization */\r
248     while( !(PMC->PMC_SR & PMC_SR_MCKRDY) );\r
249 \r
250     read_MOR |= CKGR_MOR_MOSCSEL;               /* select external crystal */\r
251 \r
252     PMC->CKGR_MOR = read_MOR;\r
253 \r
254     while( !(PMC->PMC_SR & PMC_SR_MOSCSELS ) ); /* Wait end of Main Oscillator Selection */\r
255     while( !(PMC->PMC_SR & PMC_SR_MCKRDY) );\r
256 }\r
257 \r
258 /**\r
259  * \brief Disable external 12MHz oscilator.\r
260  */\r
261 extern void PMC_DisableExtOsc(void)\r
262 {\r
263     uint32_t   read_MOR;\r
264 \r
265     read_MOR = PMC->CKGR_MOR;\r
266 \r
267     read_MOR &= ~CKGR_MOR_MOSCXTEN; /* disable main xtal osc */\r
268     PMC->CKGR_MOR = CKGR_MOR_KEY_PASSWD | read_MOR;\r
269     while( !(PMC->PMC_SR & PMC_SR_MCKRDY) );\r
270 }\r
271 \r
272 /**\r
273  * \brief Select external OSC.\r
274  */\r
275 extern void PMC_SelectExtOsc(void)\r
276\r
277     /* switch from internal RC 12 MHz to external OSC 12 MHz */\r
278     /* wait Main XTAL Oscillator stabilisation*/\r
279     if ((PMC->CKGR_MOR & CKGR_MOR_MOSCSEL ) == CKGR_MOR_MOSCSEL){\r
280         PMC_DisableIntRC4_8_12MHz();\r
281         return;\r
282     }\r
283     /* enable external OSC 12 MHz */\r
284     PMC->CKGR_MOR |= CKGR_MOR_MOSCXTEN | CKGR_MOR_KEY_PASSWD; \r
285     /* wait Main CLK Ready */\r
286     while(!(PMC->CKGR_MCFR & CKGR_MCFR_MAINFRDY)); \r
287     /* switch MAIN clock to external OSC 12 MHz*/\r
288     PMC->CKGR_MOR |= CKGR_MOR_MOSCSEL | CKGR_MOR_KEY_PASSWD;\r
289     /* wait MAIN clock status change for external OSC 12 MHz selection*/\r
290     while(!(PMC->PMC_SR & PMC_SR_MOSCSELS));\r
291     /* in case where MCK is running on MAIN CLK */\r
292     while(!(PMC->PMC_SR & PMC_SR_MCKRDY));\r
293     PMC_DisableIntRC4_8_12MHz();\r
294 }\r
295 \r
296 \r
297 /**\r
298  * \brief Select external OSC.\r
299  */\r
300 extern void PMC_SelectExtBypassOsc(void)\r
301 {   \r
302     volatile uint32_t timeout;\r
303     if((PMC->CKGR_MOR & CKGR_MOR_MOSCXTBY) != CKGR_MOR_MOSCXTBY){\r
304         PMC->CKGR_MOR = CKGR_MOR_KEY_PASSWD |\r
305             CKGR_MOR_MOSCRCEN | \r
306             CKGR_MOR_MOSCXTST(0xFF) |\r
307             CKGR_MOR_MOSCXTBY;\r
308         PMC->CKGR_MOR |= CKGR_MOR_KEY_PASSWD | CKGR_MOR_MOSCSEL;\r
309         /* wait MAIN clock status change for external OSC 12 MHz selection*/\r
310         while(!(PMC->PMC_SR & PMC_SR_MOSCSELS));\r
311         // Check if an external clock is provided\r
312         for(timeout = 0; timeout<0xffff;timeout++);\r
313         while(!(PMC->CKGR_MCFR & CKGR_MCFR_MAINFRDY));\r
314     }\r
315 }\r
316 \r
317 /**\r
318  * \brief Enable internal 4/8/12MHz fast RC as main clock input.\r
319  *\r
320  * \param freqSelect fast RC frequency (FAST_RC_4MHZ, FAST_RC_8MHZ, FAST_RC_12MHZ).\r
321  */\r
322 extern void PMC_EnableIntRC4_8_12MHz(uint32_t freqSelect)\r
323 {\r
324     /* Enable Fast RC oscillator but DO NOT switch to RC now */\r
325     PMC->CKGR_MOR |= (CKGR_MOR_KEY_PASSWD | CKGR_MOR_MOSCRCEN);\r
326 \r
327     /* Wait the Fast RC to stabilize */\r
328     while (!(PMC->PMC_SR & PMC_SR_MOSCRCS));\r
329 \r
330     /* Change Fast RC oscillator frequency */\r
331     PMC->CKGR_MOR = (PMC->CKGR_MOR & ~CKGR_MOR_MOSCRCF_Msk) |\r
332         CKGR_MOR_KEY_PASSWD | freqSelect;\r
333 \r
334     /* Wait the Fast RC to stabilize */\r
335     while (!(PMC->PMC_SR & PMC_SR_MOSCRCS));\r
336 \r
337     /* Switch to Fast RC */\r
338     PMC->CKGR_MOR = (PMC->CKGR_MOR & ~CKGR_MOR_MOSCSEL) |\r
339         CKGR_MOR_KEY_PASSWD;\r
340 }\r
341 \r
342 /**\r
343  * \brief Disable internal 4/8/12MHz fast RC.\r
344  */\r
345 extern void PMC_DisableIntRC4_8_12MHz(void)\r
346 {\r
347     uint32_t   read_MOR;\r
348 \r
349     read_MOR = PMC->CKGR_MOR;\r
350 \r
351     read_MOR &= ~CKGR_MOR_MOSCRCF_Msk;   /* reset MOSCRCF field in MOR register */\r
352     read_MOR &= ~CKGR_MOR_MOSCRCEN;      /* disable fast RC */\r
353     PMC->CKGR_MOR = CKGR_MOR_KEY_PASSWD | read_MOR;\r
354     while( !(PMC->PMC_SR & PMC_SR_MCKRDY) );\r
355 }\r
356 \r
357 /**\r
358  * \brief Configure PLLA clock by giving MUL and DIV.\r
359  *        Disable PLLA when 'mul' set to 0.\r
360  *\r
361  * \param mul  PLL multiplier factor.\r
362  * \param div  PLL divider factor.\r
363  */\r
364 extern void PMC_SetPllaClock(uint32_t mul, uint32_t div)\r
365 {\r
366     if (mul != 0)\r
367     {\r
368         /* Init PLL speed */\r
369         PMC->CKGR_PLLAR = CKGR_PLLAR_ONE \r
370             | CKGR_PLLAR_PLLACOUNT(DEFAUTL_PLLA_COUNT)\r
371             | CKGR_PLLAR_MULA(mul - 1)\r
372             | CKGR_PLLAR_DIVA(div);\r
373 \r
374         /* Wait for PLL stabilization */\r
375         while( !(PMC->PMC_SR & PMC_SR_LOCKA) );\r
376     }\r
377     else\r
378     {\r
379         PMC->CKGR_PLLAR = CKGR_PLLAR_ONE; /* disable PLL A */\r
380     }\r
381 }\r
382 \r
383 /**\r
384  * \brief Selection of Master Clock.\r
385  *\r
386  * \param clockSource  Master Clock source.\r
387  * \param prescaler    Master Clock prescaler.\r
388  *\r
389  * \note\r
390  * The PMC_MCKR register must not be programmed in a single write\r
391  * operation (see. Product Data Sheet).\r
392  */\r
393 extern void PMC_SetMckSelection(uint32_t clockSource, uint32_t prescaler)\r
394 {\r
395     switch ( clockSource )\r
396     {\r
397         case PMC_MCKR_CSS_SLOW_CLK :\r
398             _PMC_SwitchMck2SlowClock();\r
399             _PMC_SetMckPrescaler(prescaler);\r
400             break;\r
401 \r
402         case PMC_MCKR_CSS_MAIN_CLK :\r
403             _PMC_SwitchMck2MainClock();\r
404             _PMC_SetMckPrescaler(prescaler);\r
405             break;\r
406 \r
407         case PMC_MCKR_CSS_PLLA_CLK :\r
408             _PMC_SetMckPrescaler(prescaler);\r
409             _PMC_SwitchMck2PllaClock();\r
410             break ;\r
411     }\r
412 }\r
413 \r
414 /**\r
415  * \brief Disable all clocks.\r
416  */\r
417 extern void PMC_DisableAllClocks(void)\r
418 {\r
419     uint32_t   read_reg;\r
420 \r
421     PMC->PMC_SCDR = PMC_SCDR_PCK0 | PMC_SCDR_PCK1 | PMC_SCDR_PCK2 | PMC_SCDR_PCK3 | PMC_SCDR_PCK4 | PMC_SCDR_PCK5 | PMC_SCDR_PCK6;  /* disable PCK */\r
422 \r
423     _PMC_SwitchMck2MainClock();\r
424 \r
425     PMC->CKGR_PLLAR = PMC->CKGR_PLLAR & ~CKGR_PLLAR_MULA_Msk;       /* disable PLL A */\r
426 \r
427     _PMC_SwitchMck2SlowClock();\r
428 \r
429     read_reg  =  PMC->CKGR_MOR;\r
430 \r
431     read_reg  =  (read_reg & ~CKGR_MOR_MOSCRCEN) | CKGR_MOR_KEY_PASSWD;  /* disable RC OSC */\r
432 \r
433     PMC->CKGR_MOR = read_reg;\r
434 \r
435     PMC_DisableAllPeripherals(); /* disable all peripheral clocks */\r
436 }\r
437 \r
438 /**\r
439  * \brief Configure PLLA as clock input for MCK.\r
440  *\r
441  * \param mul        PLL multiplier factor (not shifted, don't minus 1).\r
442  * \param div        PLL divider factor (not shifted).\r
443  * \param prescaler  Master Clock prescaler (shifted as in register).\r
444  */\r
445 extern void PMC_ConfigureMckWithPlla(uint32_t mul, uint32_t div, uint32_t prescaler)\r
446 {\r
447     /* First, select Main OSC as input clock for MCK */\r
448     _PMC_SwitchMck2MainClock();\r
449 \r
450     /* Then, Set PLLA clock */\r
451     PMC_SetPllaClock(mul, div);\r
452 \r
453     /* Wait until the master clock is established for the case we already turn on the PLL */\r
454     while( !(PMC->PMC_SR & PMC_SR_MCKRDY) );\r
455 \r
456     /* Finally, select PllA as input clock for MCK */\r
457     PMC_SetMckSelection(PMC_MCKR_CSS_PLLA_CLK, prescaler);\r
458 }\r
459 \r
460 \r
461 /**\r
462  * \brief Configure PLLA as clock input for MCK.\r
463  *\r
464  * \param mul        PLL multiplier factor (not shifted, don't minus 1).\r
465  * \param div        PLL divider factor (not shifted).\r
466  * \param prescaler  Master Clock prescaler (shifted as in register).\r
467  */\r
468 extern void PMC_EnableXT32KFME(void)\r
469 {\r
470 \r
471     uint32_t   read_MOR;\r
472 \r
473     /* Before switching MAIN OSC on external crystal : enable it and don't disable\r
474      * at the same time RC OSC in case of if MAIN OSC is still using RC OSC\r
475      */\r
476 \r
477     read_MOR = PMC->CKGR_MOR;\r
478 \r
479     read_MOR |= (CKGR_MOR_KEY_PASSWD |CKGR_MOR_XT32KFME);  /* enable external crystal - enable RC OSC */\r
480 \r
481     PMC->CKGR_MOR = read_MOR;\r
482 \r
483 }\r
484 \r
485 /**\r
486  * \brief Configure PLLA as clock input for MCK.\r
487  *\r
488  * \param mul        PLL multiplier factor (not shifted, don't minus 1).\r
489  * \param div        PLL divider factor (not shifted).\r
490  * \param prescaler  Master Clock prescaler (shifted as in register).\r
491  */\r
492 extern void PMC_ConfigurePCK2(uint32_t MasterClk, uint32_t prescaler)\r
493 {\r
494     PMC->PMC_SCDR = PMC_SCDR_PCK2;  /* disable PCK */\r
495 \r
496     while((PMC->PMC_SCSR)& PMC_SCSR_PCK2);\r
497     PMC->PMC_PCK[2] = MasterClk | prescaler; \r
498     PMC->PMC_SCER = PMC_SCER_PCK2;\r
499     while(!((PMC->PMC_SR) & PMC_SR_PCKRDY2));\r
500 \r
501 }\r
502 \r