blob: fb31374fe39e7a6ced68bc9a6ab98f1a3858a641 [file] [log] [blame]
/* ----------------------------------------------------------------------------
* 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;
}
}
}