📄 init.c
字号:
//*----------------------------------------------------------------------------
//* ATMEL Microcontroller Software Support - ROUSSET -
//*----------------------------------------------------------------------------
//* The software is delivered "AS IS" without warranty or condition of any
//* kind, either express, implied or statutory. This includes without
//* limitation any warranty or condition with respect to merchantability or
//* fitness for any particular purpose, or against the infringements of
//* intellectual property rights of others.
//*----------------------------------------------------------------------------
//* File Name : init.c
//* Object : Low level initialisations written in C
//* Creation : ODi 06/26/2002
//*
//*----------------------------------------------------------------------------
#include "AT91RM9200.h"
#include "lib_AT91RM9200.h"
// [DOC1768.PDF 23.6.9 PMC Clock Generator PLL A Register]
// 31 30 29 28 27 26 25 24 23 22 21 20 19 18 17 16
// +----+----+----+----+----+------------------------------------------------------+
// | - | - | - | - | - | MULA |
// +----+----+----+----+----+------------------------------------------------------+
//
// 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0
// +---------+-----------------------------+---------------------------------------+
// | OUTA | PLLACOUNT | DIVA |
// +---------+-----------------------------+---------------------------------------+
//
// :DIVA: Divider A
// 0 = Divider output is 0
// 1 = Divider is bypassed
// 2 - 255 = Divider output is the Main Clock divided by DIVA.
//
// :PLLACOUNT: PLL A Counter
// Specifies the number of Slow Clock cycles before the LOCKA bit is set in PMC_SR
// after CKGR_PLLAR is written.
//
// :OUTA: PLL A Clock Frequency Range
// 0 0 : 80 MHz to 160 MHz
// 0 1 : Reserved
// 1 0 : 150 MHz to 240 MHz
// 1 1 : Reserved
//
// :MULA: PLL A Multiplier
// 0 = The PLL A is deactivated.
// 1 up to 2047 = The PLL A Clock frequency is the PLL A input frequency multiplied by MULA + 1.
// [DOC1768.PDF 23.6.11 PMC Master Clock Register]
// 31 30 29 28 27 26 25 24 23 22 21 20 19 18 17 16
// +-------------------------------------------------------------------------------+
// | - |
// +-------------------------------------------------------------------------------+
//
// 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0
// +-----------------------------+---------+--------------+--------------+---------+
// | - | MDIV | - | PRES | CSS |
// +-----------------------------+---------+--------------+--------------+---------+
//
// :CSS: Master Clock Selection
// 0 0 = Slow Clock is selected
// 0 1 = Main Clock is selected
// 1 0 = PLL A Clock is selected
// 1 1 = PLL B Clock is selected
//
// :PRES: Master Clock Prescaler
// 0 0 0 = Selected clock
// 0 0 1 = Selected clock divided by 2
// 0 1 0 = Selected clock divided by 4
// 0 1 1 = Selected clock divided by 8
// 1 0 0 = Selected clock divided by 16
// 1 0 1 = Selected clock divided by 32
// 1 1 0 = Selected clock divided by 64
// 1 1 1 = Reserved
//
// :MDIV: Master Clock Division (on ARM9-based systems only)
// 0 = The Master Clock and the Processor Clock are the same.
// 1 = The Processor Clock is twice as fast as the Master Clock.
// 2 = The Processor Clock is three times faster than the Master Clock.
// 3 = The Processor Clock is four times faster than the Master Clock.
#define LSB(x) ((~(x))+1) & (x))
/* shift val to the position indicated by mask*/
#define MASK_SHIFT(mask,val) ( (val)*LSB(mask)&(mask) )
/* get field(indicated by mask) value in data*/
#define MASK_RD(mask,data) ( ((data)&(mask))/LSB(mask) )
/* these inline function only change the bits indicated by mask to val*/
#define MASK_WR(var,mask,val) do{var = ((var)&(~(mask))) | mask_shift(mask,val)}while(0)
/////////////////////////////////////////////////////////////////////////////////////////////////////
// Configuration for a Quartz 18.432000 MHz
/////////////////////////////////////////////////////////////////////////////////////////////////////
//PLLAR perhaps 0x2026be04 because plla vco range in 150-240 MHz
#define PLLAR 0x20263E04 //* 179,712000 MHz for PCK (18.432/4)*(38+1) = 179.712
#define PLLBR 0x10483E0E //* 48,054857 MHz (divider by 2 for USB) (18.432/14)*(72+1)/2 = 48.054857
#define MCKR 0x00000202 //* PCK/3 = MCK Master Clock = 59,904000MHz with PLLA selected
#define SLOWCLOCK 32768 //* In Hz
#define MAINOSC 18432000
#define MCK 59904000
#define BAUDRATE 115200
#define PLL_INPUT_FREQ_MIN 900000
#define PLL_INPUT_FREQ_MAX 32000000
#define BASE_EBI_CS0_ADDRESS 0x10000000 //* base address to access memory on CS0
#define BASE_EBI_CS1_ADDRESS 0x20000000 //* base address to access memory on CS1
#define PLL_OUTPUT_FREQ_MIN 80000000
#define PLL_OUTPUT_FREQ_MAX 240000000
#define FALSE 0
#define TRUE 1
#define DELAY_PLL 100
#define DELAY_MAIN_FREQ 100
// [DOC1768.PDF 23.6.8 PMC Clock Generator Main Clock Frequency Register]
// 31 30 29 28 27 26 25 24 23 22 21 20 19 18 17 16
// +-----------------------------------------------------------------------+-------+
// | - |MAINRDY|
// +-----------------------------------------------------------------------+-------+
//
// 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0
// +-------------------------------------------------------------------------------+
// | MAINF |
// +-------------------------------------------------------------------------------+
//
// :MAINF: Main Clock Frequency
// Gives the number of Main Clock cycles within 16 Slow Clock periods.
// :MAINRDY: Main Clock Ready
// 0 = MAINF value is not valid or the Main Oscillator is disabled.
// 1 = The Main Oscillator has been enabled previously and MAINF value is available.
//*----------------------------------------------------------------------------
//* \fn AT91F_WaitForMainClockFrequency
//* \brief This function performs very low level HW initialization
//*----------------------------------------------------------------------------
unsigned char AT91F_WaitForMainClockFrequency()
{
volatile char tmp = 0;
/////////////////////////////////////////////////////////////////////////////////////////////////////
// Step 2.
// Checking the Main Oscillator Frequency (Optional)
/////////////////////////////////////////////////////////////////////////////////////////////////////
//* Determine the main clock frequency
while(!(AT91C_BASE_CKGR->CKGR_MCFR & AT91C_CKGR_MAINRDY) && (tmp++ < DELAY_MAIN_FREQ));
if (tmp >= DELAY_MAIN_FREQ)
return FALSE;
return TRUE;
}
//*----------------------------------------------------------------------------
//* \fn AT91F_CheckPLL_FrequencyRange
//* \brief This function performs very low level HW initialiszation
//*----------------------------------------------------------------------------
unsigned char AT91F_CheckPLL_FrequencyRange(int MainClock,int pllDivider ,int pllMultiplier)
{
if(pllDivider == 0)
return FALSE;
//* Check Input Frequency
if( ((MainClock/pllDivider) < PLL_INPUT_FREQ_MIN)
|| ((MainClock/pllDivider) > PLL_INPUT_FREQ_MAX) )
return FALSE;
//* Check Output Frequency
if( ((MainClock/pllDivider*pllMultiplier) < PLL_OUTPUT_FREQ_MIN)
|| ((MainClock/pllDivider*pllMultiplier) > PLL_OUTPUT_FREQ_MAX) )
return FALSE;
return TRUE;
}
//*----------------------------------------------------------------------------
//* \fn AT91F_InitClocks
//* \brief This function performs very low level HW initialization
//* Setting PLLA and Divider A
//* Setting PLLB and Divider B
//* Selection of Master Clock MCK (and Processor Clock PCK)
//*----------------------------------------------------------------------------
unsigned char AT91F_InitClocks(int PLLAR_Register,int PLLBR_Register ,int MCKR_Register)
{
volatile char tmp = 0;
unsigned int t;
unsigned int MainClock;
unsigned int pllDivider,pllMultiplier;
//禁止PMC的所有中断源
AT91C_BASE_PMC->PMC_IDR = 0xFFFFFFFF;
/* --- Optionnal
* -------------------------
*/
/* Check if Input & Output Frequencies are in the correct range (PLLA and PLLB)*/
MainClock = AT91F_CKGR_GetMainClock(AT91C_BASE_CKGR,SLOWCLOCK);
pllDivider = (PLLAR_Register & AT91C_CKGR_DIVA);
pllMultiplier = ((PLLAR_Register & AT91C_CKGR_MULA) >> 16) + 1;
if(AT91F_CheckPLL_FrequencyRange(MainClock, pllDivider , pllMultiplier) == FALSE)
return FALSE;
pllDivider = (PLLBR_Register & AT91C_CKGR_DIVB);
pllMultiplier = ((PLLBR_Register & AT91C_CKGR_MULB) >> 16) + 1;
if(AT91F_CheckPLL_FrequencyRange(MainClock, pllDivider , pllMultiplier) == FALSE)
return FALSE;
/* --- Step 3.
* -------------------------
*/
t = AT91C_BASE_CKGR->CKGR_PLLAR;
if ( ( t & (AT91C_CKGR_DIVA|AT91C_CKGR_MULA) ) != ( PLLAR_Register & (AT91C_CKGR_DIVA|AT91C_CKGR_MULA) ) ) {
AT91C_BASE_CKGR->CKGR_PLLAR = PLLAR_Register;
//* Wait for PLLA stabilization LOCKA bit in PMC_SR
tmp = 0;
while( !(AT91C_BASE_PMC->PMC_SR & AT91C_PMC_LOCKA) && (tmp++ < DELAY_PLL) ) ;
}
/* --- Step 4.
* -------------------------
*/
t = AT91C_BASE_CKGR->CKGR_PLLBR;
if ( ( t & (AT91C_CKGR_DIVB|AT91C_CKGR_MULB) ) != ( PLLBR_Register & (AT91C_CKGR_DIVB|AT91C_CKGR_MULB) ) ) {
AT91C_BASE_CKGR->CKGR_PLLBR = PLLBR_Register;
//* Wait for PLLB stabilization LOCKB bit in PMC_SR
tmp = 0;
while( !(AT91C_BASE_PMC->PMC_SR & AT91C_PMC_LOCKB) && (tmp++ < DELAY_PLL) ) ;
}
/* --- Step 5.
* -------------------------
*/
/* Constraints of the Master Clock selection sequence */
/* Write in the MCKR dirty value concerning the clock selection CSS then overwrite it in a second sequence*/
t = AT91C_BASE_PMC->PMC_MCKR;
if ( (t&(AT91C_PMC_PRES|AT91C_PMC_CSS)) != (MCKR_Register&(AT91C_PMC_PRES|AT91C_PMC_CSS)) ) {
if ( (MCKR_Register & AT91C_PMC_MDIV) != 0 ) { /*PCK > MCK then PRES field should be written first*/
if ( (MCKR_Register & AT91C_PMC_PRES) != (t & AT91C_PMC_PRES) ) { /*PRES field must be changed*/
/*first only change pres. may be include mdiv*/
AT91C_BASE_PMC->PMC_MCKR = (MCKR_Register & (AT91C_PMC_PRES|AT91C_PMC_MDIV))+(t&AT91C_PMC_CSS);
while( !(AT91C_BASE_PMC->PMC_SR & AT91C_PMC_MCKRDY) );/* Wait until the master clock is established*/
}
if ( (MCKR_Register & AT91C_PMC_CSS) != (t & AT91C_PMC_CSS) ){ /*CSS field should be changed*/
/*just change css*/
AT91C_BASE_PMC->PMC_MCKR = MCKR_Register;
/* Wait until the master clock is established*/
while( !(AT91C_BASE_PMC->PMC_SR & AT91C_PMC_MCKRDY) );
}
} else { /*PCK == MCK then CSS field should be written first*/
if ( (MCKR_Register & AT91C_PMC_CSS) != (t & AT91C_PMC_CSS) ) { /*CSS field must be changed*/
/*first only change CSS. may be include mdiv*/
AT91C_BASE_PMC->PMC_MCKR = (MCKR_Register & (AT91C_PMC_CSS|AT91C_PMC_MDIV))+(t&AT91C_PMC_PRES);
/* Wait until the master clock is established*/
while( !(AT91C_BASE_PMC->PMC_SR & AT91C_PMC_MCKRDY) );
}
if ( (MCKR_Register & AT91C_PMC_PRES) != (t & AT91C_PMC_PRES) ) { /*PRES field should be changed*/
/*just change pres*/
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -