/* ---------------------------------------------------------------------------- | |
* ATMEL Microcontroller Software Support | |
* ---------------------------------------------------------------------------- | |
* Copyright (c) 2009, Atmel Corporation | |
* | |
* All rights reserved. | |
* | |
* Redistribution and use in source and binary forms, with or without | |
* modification, are permitted provided that the following conditions are met: | |
* | |
* - Redistributions of source code must retain the above copyright notice, | |
* this list of conditions and the disclaimer below. | |
* | |
* Atmel's name may not be used to endorse or promote products derived from | |
* this software without specific prior written permission. | |
* | |
* DISCLAIMER: THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR | |
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF | |
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE | |
* DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR ANY DIRECT, INDIRECT, | |
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT | |
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, | |
* OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF | |
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING | |
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, | |
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | |
* ---------------------------------------------------------------------------- | |
*/ | |
/*---------------------------------------------------------------------------- | |
* Headers | |
*----------------------------------------------------------------------------*/ | |
#include "board.h" | |
/*---------------------------------------------------------------------------- | |
* Types | |
*----------------------------------------------------------------------------*/ | |
/* | |
* \brief Describes a possible clock configuration (processor clock & master clock), | |
* including the necessary register values. | |
*/ | |
typedef struct _ClockConfiguration | |
{ | |
/** Processor clock frequency (in MHz). */ | |
uint16_t pck; | |
/** Master clock frequency (in MHz). */ | |
uint16_t mck; | |
/** CKGR_PLL reqister value. */ | |
uint32_t pllr; | |
/** PMC_MCKR register value. */ | |
uint32_t mckr; | |
} ClockConfiguration ; | |
/*---------------------------------------------------------------------------- | |
* Local variables | |
*----------------------------------------------------------------------------*/ | |
/* Clock configurations for the AT91SAM3S4-EK */ | |
#define CKGR_MUL_SHIFT 16 | |
#define CKGR_PLLCOUNT_SHIFT 8 | |
#define CKGR_DIV_SHIFT 0 | |
/* Clock configuration for the AT91SAM3S */ | |
static const ClockConfiguration clockConfigurations[] = { | |
/* PCK = 24 MHz, MCK = 24 MHz | |
* PCK = 12000000 * (7+1) / 2 / 2 = 24 MHz | |
*/ | |
{24, 24, (CKGR_PLLAR_STUCKTO1 | (7 << CKGR_MUL_SHIFT) \ | |
| (0x3f << CKGR_PLLCOUNT_SHIFT) \ | |
| (2 << CKGR_DIV_SHIFT)), | |
( PMC_MCKR_PRES_CLK_2 | PMC_MCKR_CSS_PLLA_CLK)}, | |
/* PCK = 48 MHz, MCK = 48 MHz | |
* PCK = 12000000 * (7+1) / 1 / 2 = 48 MHz | |
*/ | |
{48, 48, (CKGR_PLLAR_STUCKTO1 | (7 << CKGR_MUL_SHIFT) \ | |
| (0x3f << CKGR_PLLCOUNT_SHIFT) \ | |
| (1 << CKGR_DIV_SHIFT)), | |
( PMC_MCKR_PRES_CLK_2 | PMC_MCKR_CSS_PLLA_CLK)}, | |
/* PCK = 64 MHz, MCK = 64 MHz | |
* PCK = 12000000 * (15+1) / 3 / 1 = 64 MHz | |
*/ | |
{64, 64, (CKGR_PLLAR_STUCKTO1 | (15 << CKGR_MUL_SHIFT) \ | |
| (0x3f << CKGR_PLLCOUNT_SHIFT) \ | |
| (3 << CKGR_DIV_SHIFT)), | |
( PMC_MCKR_PRES_CLK | PMC_MCKR_CSS_PLLA_CLK)} | |
}; | |
/* Number of available clock configurations */ | |
#define NB_CLOCK_CONFIGURATION (sizeof(clockConfigurations)/sizeof(clockConfigurations[0])) | |
/* Current clock configuration */ | |
uint32_t currentConfig = 0; /* 0 have to be the default configuration */ | |
/*---------------------------------------------------------------------------- | |
* Exported functions | |
*----------------------------------------------------------------------------*/ | |
/** | |
* \brief Sets the specified clock configuration. | |
* | |
* \param configuration Index of the configuration to set. | |
*/ | |
void CLOCK_SetConfig(uint8_t configuration) | |
{ | |
TRACE_DEBUG("Setting clock configuration #%d ... ", configuration); | |
currentConfig = configuration; | |
/* Switch to main oscillator in two operations */ | |
PMC->PMC_MCKR = (PMC->PMC_MCKR & (uint32_t)~PMC_MCKR_CSS_Msk) | PMC_MCKR_CSS_MAIN_CLK; | |
while ((PMC->PMC_SR & PMC_SR_MCKRDY) == 0); | |
/* Configure PLL */ | |
PMC->CKGR_PLLAR = clockConfigurations[configuration].pllr; | |
while ((PMC->PMC_SR & PMC_SR_LOCKA) == 0); | |
/* Configure master clock in two operations */ | |
PMC->PMC_MCKR = (clockConfigurations[configuration].mckr & (uint32_t)~PMC_MCKR_CSS_Msk) | PMC_MCKR_CSS_MAIN_CLK; | |
while ((PMC->PMC_SR & PMC_SR_MCKRDY) == 0); | |
PMC->PMC_MCKR = clockConfigurations[configuration].mckr; | |
while ((PMC->PMC_SR & PMC_SR_MCKRDY) == 0); | |
/* DBGU reconfiguration */ | |
UART_Configure(115200, clockConfigurations[configuration].mck*1000000); | |
TRACE_DEBUG("done.\n\r"); | |
} | |
/** | |
* \brief Display the user menu on the DBGU. | |
*/ | |
void CLOCK_DisplayMenu(void) | |
{ | |
uint32_t i; | |
printf("\n\rMenu Clock configuration:\n\r"); | |
for (i = 0; i < NB_CLOCK_CONFIGURATION; i++) { | |
printf(" %u: Set PCK = %3u MHz, MCK = %3u MHz %s\n\r", | |
(unsigned int)i, | |
(unsigned int)clockConfigurations[i].pck, | |
(unsigned int)clockConfigurations[i].mck, | |
(currentConfig==i)?"(curr)":""); | |
} | |
} | |
/** | |
* \brief Get the current MCK | |
*/ | |
uint16_t CLOCK_GetCurrMCK(void) | |
{ | |
return clockConfigurations[currentConfig].mck; | |
} | |
/** | |
* \brief Get the current PCK | |
*/ | |
uint16_t CLOCK_GetCurrPCK(void) | |
{ | |
return clockConfigurations[currentConfig].pck; | |
} | |
/** | |
* \brief Change clock configuration. | |
*/ | |
void CLOCK_UserChangeConfig(void) | |
{ | |
uint8_t key = 0; | |
while (1) | |
{ | |
CLOCK_DisplayMenu(); | |
key = UART_GetChar(); | |
if ((key >= '0') && (key <= ('0' + NB_CLOCK_CONFIGURATION - 1))) | |
{ | |
CLOCK_SetConfig(key - '0'); | |
break; | |
} | |
} | |
} | |