/* ---------------------------------------------------------------------------- * 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. * ---------------------------------------------------------------------------- */ //------------------------------------------------------------------------------ // Headers //------------------------------------------------------------------------------ #include "slck.h" #include #if defined(at91sam3u) #include #endif #include #include //------------------------------------------------------------------------------ // 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) // Define clock timeout #define CLOCK_TIMEOUT 0xFFFFFFFF //------------------------------------------------------------------------------ // Local functions //------------------------------------------------------------------------------ #if defined(at91cap7) || defined(at91cap9) //------------------------------------------------------------------------------ /// 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--); } #endif //------------------------------------------------------------------------------ // Global functions //------------------------------------------------------------------------------ #if defined(at91cap7) //------------------------------------------------------------------------------ /// Return 1 if the slow clock is 32k //------------------------------------------------------------------------------ unsigned char SLCK_Is32k(void) { return ((*AT91C_PMC_SR & AT91C_PMC_OSC_SEL) != 0); //return ((*AT91C_SYS_SYS_OSCMR & AT91C_OSC32K_SEL) != 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 OSC32K_XT_EN to 1. *AT91C_SYS_SYS_OSCMR |= AT91C_OSC32K_XT_EN; // Wait 32,768 Hz Startup Time for clock stabilization (software loop). WaitTimeInMs(BOARD_MCK, /*T_ST_SLCK_32K_IN_MS*/10); // Switch from internal RC to 32,768 Hz oscillator by setting the bit OSC32K_SEL to 1. *AT91C_SYS_SYS_OSCMR |= AT91C_OSC32K_SEL; 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 OSC32K_RC_EN to 1 *AT91C_SYS_SYS_OSCMR |= AT91C_OSC32K_RC_EN; // Wait internal RC Startup Time for clock stabilization (software loop). WaitTimeInUs(BOARD_MCK, T_ST_SLCK_RC_IN_US); // Switch from 32768 Hz oscillator to internal RC by setting the bit OSC32K_SEL to 0. *AT91C_SYS_SYS_OSCMR &= (0xFFFFFFFF ^ AT91C_OSC32K_SEL); TRACE_INFO("The slow clock is now the internal RC oscillator\n\r"); } //------------------------------------------------------------------------------ /// by pass the 32kHz oscillator (*** not supported in CAP7 ***) //------------------------------------------------------------------------------ //------------------------------------------------------------------------------ /// set Slow Clock Mode //------------------------------------------------------------------------------ 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 = 500 Hz AT91C_BASE_PMC->PMC_MCKR = AT91C_PMC_CSS_SLOW_CLK | AT91C_PMC_PRES_CLK_64; timeout = 0; while ( !(AT91C_BASE_PMC->PMC_SR & AT91C_PMC_MCKRDY) && timeout++ < CLOCK_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++ < CLOCK_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++ < CLOCK_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(at91cap7) #elif defined(at91cap9) //------------------------------------------------------------------------------ /// 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*/10); // 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 //------------------------------------------------------------------------------ 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 Hz 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++ < CLOCK_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++ < CLOCK_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++ < CLOCK_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) #elif defined(at91sam3u) //------------------------------------------------------------------------------ /// Return 1 if the slow clock is 32k //------------------------------------------------------------------------------ unsigned char SLCK_Is32k(void) { return ((AT91C_BASE_SUPC->SUPC_SR & AT91C_SUPC_SR_OSCSEL_CRYST) != 0); } //------------------------------------------------------------------------------ /// Configure the 32kHz oscillator for the slow clock //------------------------------------------------------------------------------ void SLCK_RCto32k(void) { unsigned int timeout = 0; // 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; } // Select the internal RC oscillator by set XTALSEL to 1. AT91C_BASE_SUPC->SUPC_CR = AT91C_SUPC_CR_XTALSEL_CRYSTAL_SEL | (0xA5 << 24); timeout = 0; while (!(AT91C_BASE_SUPC->SUPC_SR & AT91C_SUPC_SR_OSCSEL_CRYST) && (timeout++ < CLOCK_TIMEOUT)); 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) { TRACE_INFO("Switch to the internal RC oscillator is not possible for SAM3U!!!\n\r"); } //------------------------------------------------------------------------------ /// by pass the 32kHz oscillator //------------------------------------------------------------------------------ void SLCK_bypass32Kosc(void) { // Enable the bypass path OSCBYPASS by set to 1. AT91C_BASE_SUPC->SUPC_MR |= AT91C_SUPC_MR_OSCBYPASS_BYPASS; } 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 = 500 Hz AT91C_BASE_PMC->PMC_MCKR = (oldMck & AT91C_PMC_PRES) | AT91C_PMC_CSS_SLOW_CLK; timeout = 0; while ( !(AT91C_BASE_PMC->PMC_SR & AT91C_PMC_MCKRDY) && timeout++ < CLOCK_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_MOSCXTEN); // 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_MOSCXTST & (0x32<<8) ); AT91C_BASE_CKGR->CKGR_MOR = AT91C_BASE_CKGR->CKGR_MOR | (AT91C_CKGR_MOSCXTEN); // Restart PLL A AT91C_BASE_CKGR->CKGR_PLLAR = oldPll; timeout = 0; while( !(AT91C_BASE_PMC->PMC_SR & AT91C_PMC_LOCKA) && timeout++ < CLOCK_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++ < CLOCK_TIMEOUT); // Reconfigure DBGU TRACE_CONFIGURE(DBGU_STANDARD, 115200, BOARD_MCK); } //------------------------------------------------------------------------------ /// get the slow clock frequency //------------------------------------------------------------------------------ unsigned int SLCK_UtilGetFreq(void) { unsigned int freq = 0; SetFlashWaitState(3); 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 // endof at91sam3u