blob: bb530ad9024be7597ddec06c4dea6d2eaaef291c [file] [log] [blame]
/* ----------------------------------------------------------------------------
* ATMEL Microcontroller Software Support
* ----------------------------------------------------------------------------
* Copyright (c) 2008, 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.
* ----------------------------------------------------------------------------
*/
#if defined(at91cap9)
//------------------------------------------------------------------------------
// Headers
//------------------------------------------------------------------------------
#include "slck.h"
#include <utility/assert.h>
#include <utility/trace.h>
#include <utility/util.h>
//------------------------------------------------------------------------------
// Local definitions
//------------------------------------------------------------------------------
/// Start Up Time Slow Clock 32K Oscillator // see DC characteritics in Datasheet
#define T_ST_SLCK_32K_IN_MS 1200
/// Start Up Time Slow Clock RC Oscillator // see DC characteritics in Datasheet
#define T_ST_SLCK_RC_IN_US 75
#define FREQ_SLCK_32K 32768 // see DC characteritics in Datasheet
#define MIN_FREQ_SLCK_RC 20000 // see DC characteritics in Datasheet
#define TIME_5_CYCLES_32K_IN_US ((2 * 5 * 1000000) / FREQ_SLCK_32K)
#define TIME_5_CYCLES_RC_IN_US ((2 * 5 * 1000000) / MIN_FREQ_SLCK_RC)
//------------------------------------------------------------------------------
// Local functions
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
/// Wait time in ms
//------------------------------------------------------------------------------
// not precise, depends on the compiler and on the options
static void WaitTimeInMs(unsigned int pck, unsigned int time_ms)
{
register unsigned int i = 0;
i = (pck / 1000) * time_ms;
i = i / 4;
while(i--);
}
//------------------------------------------------------------------------------
/// Wait time in us
//------------------------------------------------------------------------------
// not precise, depends on the compiler and on the options
static void WaitTimeInUs(unsigned int pck, unsigned int time_us)
{
volatile unsigned int i = 0;
i = (pck / 1000000) * time_us;
i = i / 4;
while(i--);
}
//------------------------------------------------------------------------------
// Global functions
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
/// Return 1 if the slow clock is 32k
//------------------------------------------------------------------------------
unsigned char SLCK_Is32k(void)
{
return ((*AT91C_SYS_SLCKSEL & AT91C_SLCKSEL_OSCSEL) != 0);
}
//------------------------------------------------------------------------------
/// Configure the 32kHz oscillator for the slow clock
//------------------------------------------------------------------------------
void SLCK_RCto32k(void)
{
// Check that the master clock has a different source than slow clock. If no,
if( (AT91C_BASE_PMC->PMC_MCKR & AT91C_PMC_CSS) == 0)
{
TRACE_WARNING("The master clock use the slow clock. " \
"Not possible to change Slow clock\n\r");
return;
}
// Check that the slow clock source is RC
if( SLCK_Is32k() )
{
TRACE_WARNING("The slow clock is already the external 32.768kHz crystal\n\r");
return;
}
// Enable the 32,768 Hz oscillator by setting the bit OSC32EN to 1.
*AT91C_SYS_SLCKSEL |= AT91C_SLCKSEL_OSC32EN;
// Wait 32,768 Hz Startup Time for clock stabilization (software loop).
WaitTimeInMs(BOARD_MCK*2, T_ST_SLCK_32K_IN_MS);
// Switch from internal RC to 32,768 Hz oscillator by setting the bit OSCSEL to 1.
*AT91C_SYS_SLCKSEL |= AT91C_SLCKSEL_OSCSEL;
// Wait 5 slow clock cycles for internal resynchronization.
WaitTimeInUs(BOARD_MCK*2, TIME_5_CYCLES_32K_IN_US);
// Disable the RC oscillator by setting the bit RCEN to 0.
*AT91C_SYS_SLCKSEL &= (0xFFFFFFFF ^ AT91C_SLCKSEL_RCEN);
TRACE_INFO("The slow clock is now the external 32.768kHz crystal\n\r");
}
//------------------------------------------------------------------------------
/// Configure the RC oscillator for the slow clock
//------------------------------------------------------------------------------
void SLCK_32ktoRC(void)
{
// Check that the master clock has a different source than slow clock.
if( (AT91C_BASE_PMC->PMC_MCKR & AT91C_PMC_CSS) == 0)
{
TRACE_WARNING("The master clock use the slow clock. " \
"Not possible to change Slow clock\n\r");
return;
}
// Check that the slow clock source is RC
if( !SLCK_Is32k() )
{
TRACE_WARNING("The slow clock is already the internal RC oscillator\n\r");
return;
}
// Enable the internal RC oscillator by setting the bit RCEN to 1
*AT91C_SYS_SLCKSEL |= AT91C_SLCKSEL_RCEN;
// Wait internal RC Startup Time for clock stabilization (software loop).
WaitTimeInUs(BOARD_MCK*2, T_ST_SLCK_RC_IN_US);
// Switch from 32768 Hz oscillator to internal RC by setting the bit OSCSEL to 0.
*AT91C_SYS_SLCKSEL &= (0xFFFFFFFF ^ AT91C_SLCKSEL_OSCSEL);
// Wait 5 slow clock cycles for internal resynchronization.
WaitTimeInUs(BOARD_MCK*2, TIME_5_CYCLES_RC_IN_US);
// Disable the 32768 Hz oscillator by setting the bit OSC32EN to 0.
*AT91C_SYS_SLCKSEL &= (0xFFFFFFFF ^ AT91C_SLCKSEL_OSC32EN);
TRACE_INFO("The slow clock is now the internal RC oscillator\n\r");
}
//------------------------------------------------------------------------------
/// by pass the 32kHz oscillator
//------------------------------------------------------------------------------
void SLCK_bypass32Kosc(void)
{
// Enable the bypass path OSC32BYP bit set to 1
*AT91C_SYS_SLCKSEL |= AT91C_SLCKSEL_OSC32BYP;
// Disable the 32,768 Hz oscillator by setting the bit OSC32EN to 0
*AT91C_SYS_SLCKSEL &= (0xFFFFFFFF ^ AT91C_SLCKSEL_OSC32EN);
}
//------------------------------------------------------------------------------
/// set Slow Clock Mode
//------------------------------------------------------------------------------
#define TIMEOUT 10000000
void SLCK_UtilSetSlowClockMode(unsigned int timeInSlowClockMode)
{
unsigned int oldPll;
unsigned int oldMck;
unsigned int timeout = 0;
// Save previous values for PLL A and Master Clock configuration
oldPll = AT91C_BASE_CKGR->CKGR_PLLAR;
oldMck = AT91C_BASE_PMC->PMC_MCKR;
// Slow clock is selected for Master Clock
// 32kKz / 64 = 500Hz
// PCK = 500Hz, MCK = 250 MHz
AT91C_BASE_PMC->PMC_MCKR = AT91C_PMC_CSS_SLOW_CLK | AT91C_PMC_PRES_CLK_64 | AT91C_PMC_MDIV_2;
timeout = 0;
while ( !(AT91C_BASE_PMC->PMC_SR & AT91C_PMC_MCKRDY) && timeout++ < TIMEOUT);
// Stop PLL A
// MULA: PLL A Multiplier 0 = The PLL A is deactivated.
AT91C_BASE_CKGR->CKGR_PLLAR = 0x00003f00;
// Stop Main Oscillator
AT91C_BASE_CKGR->CKGR_MOR = AT91C_BASE_CKGR->CKGR_MOR & (~AT91C_CKGR_MOSCEN);
// Wait a while. The clock is at 500Hz...
while( timeInSlowClockMode-- );
// End !
// Restart Main Oscillator
AT91C_BASE_CKGR->CKGR_MOR = AT91C_BASE_CKGR->CKGR_MOR | (AT91C_CKGR_OSCOUNT & (0x32<<8) );
AT91C_BASE_CKGR->CKGR_MOR = AT91C_BASE_CKGR->CKGR_MOR | (AT91C_CKGR_MOSCEN);
// Restart PLL A
AT91C_BASE_CKGR->CKGR_PLLAR = oldPll;
timeout = 0;
while( !(AT91C_BASE_PMC->PMC_SR & AT91C_PMC_LOCKA) && timeout++ < TIMEOUT);
// Selection of Master Clock MCK (so Processor Clock PCK)
AT91C_BASE_PMC->PMC_MCKR = oldMck;
timeout = 0;
while( !(AT91C_BASE_PMC->PMC_SR & AT91C_PMC_MCKRDY) && timeout++ < TIMEOUT);
// Reconfigure DBGU
TRACE_CONFIGURE(DBGU_STANDARD, 115200, BOARD_MCK);
}
//------------------------------------------------------------------------------
/// get the slow clock frequency
//------------------------------------------------------------------------------
unsigned int SLCK_UtilGetFreq(void)
{
unsigned int freq = 0;
SLCK_UtilSetSlowClockMode(0);
if(AT91C_BASE_PMC->PMC_MCFR & (1<<16)) {
freq = BOARD_MAINOSC / (AT91C_BASE_PMC->PMC_MCFR & 0x0000FFFF);
freq *= 16;
}
return freq;
}
#endif //#if defined(at91cap9)