1 /* ----------------------------------------------------------------------------
\r
2 * SAM Software Package License
\r
3 * ----------------------------------------------------------------------------
\r
4 * Copyright (c) 2014, Atmel Corporation
\r
6 * All rights reserved.
\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
11 * - Redistributions of source code must retain the above copyright notice,
\r
12 * this list of conditions and the disclaimer below.
\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
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
30 /*----------------------------------------------------------------------------
\r
32 *----------------------------------------------------------------------------*/
\r
38 /*----------------------------------------------------------------------------
\r
40 *----------------------------------------------------------------------------*/
\r
42 #define MASK_STATUS0 0xFFFFFFFC
\r
43 #define MASK_STATUS1 0xFFFFFFFF
\r
45 /*----------------------------------------------------------------------------
\r
47 *----------------------------------------------------------------------------*/
\r
49 * \brief Switch MCK to PLLA clock.
\r
51 static void _PMC_SwitchMck2PllaClock(void)
\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
57 /* Wait until the master clock is established */
\r
58 while( !(PMC->PMC_SR & PMC_SR_MCKRDY) );
\r
62 * \brief Switch MCK to main clock.
\r
64 static void _PMC_SwitchMck2MainClock(void)
\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
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
76 * \brief Switch MCK to slow clock.
\r
78 static void _PMC_SwitchMck2SlowClock(void)
\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
83 /* Wait until the master clock is established */
\r
84 while( !(PMC->PMC_SR & PMC_SR_MCKRDY) );
\r
88 * \brief Set prescaler for MCK.
\r
90 * \param prescaler Master Clock prescaler
\r
92 static void _PMC_SetMckPrescaler(uint32_t prescaler)
\r
94 /* Change MCK Prescaler divider in PMC_MCKR register */
\r
95 PMC->PMC_MCKR = (PMC->PMC_MCKR & ~PMC_MCKR_PRES_Msk) | prescaler;
\r
97 /* Wait until the master clock is established */
\r
98 while( !(PMC->PMC_SR & PMC_SR_MCKRDY) );
\r
100 /*----------------------------------------------------------------------------
\r
101 * Exported functions
\r
102 *----------------------------------------------------------------------------*/
\r
105 * \brief Enables the clock of a peripheral. The peripheral ID is used
\r
106 * to identify which peripheral is targeted.
\r
108 * \note The ID must NOT be shifted (i.e. 1 << ID_xxx).
\r
110 * \param id Peripheral ID (ID_xxx).
\r
112 extern void PMC_EnablePeripheral( uint32_t dwId )
\r
114 assert( dwId < 63 ) ;
\r
118 if ( (PMC->PMC_PCSR0 & ((uint32_t)1 << dwId)) == ((uint32_t)1 << dwId) )
\r
120 TRACE_DEBUG( "PMC_EnablePeripheral: clock of peripheral" " %u is already enabled\n\r", (unsigned int)dwId ) ;
\r
124 PMC->PMC_PCER0 = 1 << dwId ;
\r
130 if ((PMC->PMC_PCSR1 & ((uint32_t)1 << dwId)) == ((uint32_t)1 << dwId))
\r
132 TRACE_DEBUG( "PMC_EnablePeripheral: clock of peripheral" " %u is already enabled\n\r", (unsigned int)(dwId + 32) ) ;
\r
136 PMC->PMC_PCER1 = 1 << dwId ;
\r
142 * \brief Disables the clock of a peripheral. The peripheral ID is used
\r
143 * to identify which peripheral is targeted.
\r
145 * \note The ID must NOT be shifted (i.e. 1 << ID_xxx).
\r
147 * \param id Peripheral ID (ID_xxx).
\r
149 extern void PMC_DisablePeripheral( uint32_t dwId )
\r
151 assert( dwId < 63 ) ;
\r
155 if ( (PMC->PMC_PCSR0 & ((uint32_t)1 << dwId)) != ((uint32_t)1 << dwId) )
\r
157 TRACE_DEBUG("PMC_DisablePeripheral: clock of peripheral" " %u is not enabled\n\r", (unsigned int)dwId ) ;
\r
161 PMC->PMC_PCDR0 = 1 << dwId ;
\r
167 if ( (PMC->PMC_PCSR1 & ((uint32_t)1 << dwId)) != ((uint32_t)1 << dwId) )
\r
169 TRACE_DEBUG( "PMC_DisablePeripheral: clock of peripheral" " %u is not enabled\n\r", (unsigned int)(dwId + 32) ) ;
\r
173 PMC->PMC_PCDR1 = 1 << dwId ;
\r
179 * \brief Enable all the periph clock via PMC.
\r
181 extern void PMC_EnableAllPeripherals( void )
\r
183 PMC->PMC_PCER0 = MASK_STATUS0 ;
\r
184 while ( (PMC->PMC_PCSR0 & MASK_STATUS0) != MASK_STATUS0 ) ;
\r
186 PMC->PMC_PCER1 = MASK_STATUS1 ;
\r
187 while ( (PMC->PMC_PCSR1 & MASK_STATUS1) != MASK_STATUS1 ) ;
\r
189 TRACE_DEBUG( "Enable all periph clocks\n\r" ) ;
\r
193 * \brief Disable all the periph clock via PMC.
\r
195 extern void PMC_DisableAllPeripherals( void )
\r
197 PMC->PMC_PCDR0 = MASK_STATUS0 ;
\r
198 while ( (PMC->PMC_PCSR0 & MASK_STATUS0) != 0 ) ;
\r
200 PMC->PMC_PCDR1 = MASK_STATUS1 ;
\r
201 while ( (PMC->PMC_PCSR1 & MASK_STATUS1) != 0 ) ;
\r
203 TRACE_DEBUG( "Disable all periph clocks\n\r" ) ;
\r
207 * \brief Get Periph Status for the given peripheral ID.
\r
209 * \param id Peripheral ID (ID_xxx).
\r
211 extern uint32_t PMC_IsPeriphEnabled( uint32_t dwId )
\r
213 assert( dwId < ID_PERIPH_COUNT ) ;
\r
217 return ( PMC->PMC_PCSR0 & (1 << dwId) ) ;
\r
220 return ( PMC->PMC_PCSR1 & (1 << (dwId - 32)) ) ;
\r
226 * \brief Enable external oscilator as main clock input.
\r
228 extern void PMC_EnableExtOsc(void)
\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
236 read_MOR = PMC->CKGR_MOR;
\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
245 PMC->CKGR_MOR = read_MOR;
\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
250 read_MOR |= CKGR_MOR_MOSCSEL; /* select external crystal */
\r
252 PMC->CKGR_MOR = read_MOR;
\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
259 * \brief Disable external 12MHz oscilator.
\r
261 extern void PMC_DisableExtOsc(void)
\r
265 read_MOR = PMC->CKGR_MOR;
\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
273 * \brief Select external OSC.
\r
275 extern void PMC_SelectExtOsc(void)
\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
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
298 * \brief Select external OSC.
\r
300 extern void PMC_SelectExtBypassOsc(void)
\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
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
318 * \brief Enable internal 4/8/12MHz fast RC as main clock input.
\r
320 * \param freqSelect fast RC frequency (FAST_RC_4MHZ, FAST_RC_8MHZ, FAST_RC_12MHZ).
\r
322 extern void PMC_EnableIntRC4_8_12MHz(uint32_t freqSelect)
\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
327 /* Wait the Fast RC to stabilize */
\r
328 while (!(PMC->PMC_SR & PMC_SR_MOSCRCS));
\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
334 /* Wait the Fast RC to stabilize */
\r
335 while (!(PMC->PMC_SR & PMC_SR_MOSCRCS));
\r
337 /* Switch to Fast RC */
\r
338 PMC->CKGR_MOR = (PMC->CKGR_MOR & ~CKGR_MOR_MOSCSEL) |
\r
339 CKGR_MOR_KEY_PASSWD;
\r
343 * \brief Disable internal 4/8/12MHz fast RC.
\r
345 extern void PMC_DisableIntRC4_8_12MHz(void)
\r
349 read_MOR = PMC->CKGR_MOR;
\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
358 * \brief Configure PLLA clock by giving MUL and DIV.
\r
359 * Disable PLLA when 'mul' set to 0.
\r
361 * \param mul PLL multiplier factor.
\r
362 * \param div PLL divider factor.
\r
364 extern void PMC_SetPllaClock(uint32_t mul, uint32_t div)
\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
374 /* Wait for PLL stabilization */
\r
375 while( !(PMC->PMC_SR & PMC_SR_LOCKA) );
\r
379 PMC->CKGR_PLLAR = CKGR_PLLAR_ONE; /* disable PLL A */
\r
384 * \brief Selection of Master Clock.
\r
386 * \param clockSource Master Clock source.
\r
387 * \param prescaler Master Clock prescaler.
\r
390 * The PMC_MCKR register must not be programmed in a single write
\r
391 * operation (see. Product Data Sheet).
\r
393 extern void PMC_SetMckSelection(uint32_t clockSource, uint32_t prescaler)
\r
395 switch ( clockSource )
\r
397 case PMC_MCKR_CSS_SLOW_CLK :
\r
398 _PMC_SwitchMck2SlowClock();
\r
399 _PMC_SetMckPrescaler(prescaler);
\r
402 case PMC_MCKR_CSS_MAIN_CLK :
\r
403 _PMC_SwitchMck2MainClock();
\r
404 _PMC_SetMckPrescaler(prescaler);
\r
407 case PMC_MCKR_CSS_PLLA_CLK :
\r
408 _PMC_SetMckPrescaler(prescaler);
\r
409 _PMC_SwitchMck2PllaClock();
\r
415 * \brief Disable all clocks.
\r
417 extern void PMC_DisableAllClocks(void)
\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
423 _PMC_SwitchMck2MainClock();
\r
425 PMC->CKGR_PLLAR = PMC->CKGR_PLLAR & ~CKGR_PLLAR_MULA_Msk; /* disable PLL A */
\r
427 _PMC_SwitchMck2SlowClock();
\r
429 read_reg = PMC->CKGR_MOR;
\r
431 read_reg = (read_reg & ~CKGR_MOR_MOSCRCEN) | CKGR_MOR_KEY_PASSWD; /* disable RC OSC */
\r
433 PMC->CKGR_MOR = read_reg;
\r
435 PMC_DisableAllPeripherals(); /* disable all peripheral clocks */
\r
439 * \brief Configure PLLA as clock input for MCK.
\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
445 extern void PMC_ConfigureMckWithPlla(uint32_t mul, uint32_t div, uint32_t prescaler)
\r
447 /* First, select Main OSC as input clock for MCK */
\r
448 _PMC_SwitchMck2MainClock();
\r
450 /* Then, Set PLLA clock */
\r
451 PMC_SetPllaClock(mul, div);
\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
456 /* Finally, select PllA as input clock for MCK */
\r
457 PMC_SetMckSelection(PMC_MCKR_CSS_PLLA_CLK, prescaler);
\r
462 * \brief Configure PLLA as clock input for MCK.
\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
468 extern void PMC_EnableXT32KFME(void)
\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
477 read_MOR = PMC->CKGR_MOR;
\r
479 read_MOR |= (CKGR_MOR_KEY_PASSWD |CKGR_MOR_XT32KFME); /* enable external crystal - enable RC OSC */
\r
481 PMC->CKGR_MOR = read_MOR;
\r
486 * \brief Configure PLLA as clock input for MCK.
\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
492 extern void PMC_ConfigurePCK2(uint32_t MasterClk, uint32_t prescaler)
\r
494 PMC->PMC_SCDR = PMC_SCDR_PCK2; /* disable PCK */
\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