📄 init_flash.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 : FB 23/10/2002
//*
//*----------------------------------------------------------------------------
#include "AT91RM9200.h"
#include "lib_AT91RM9200.h"
/////////////////////////////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////////////////////////////
#define FALSE 0
#define TRUE 1
#define DELAY_PLL 100
#define DELAY_MAIN_FREQ 100
/////////////////////////////////////////////////////////////////////////////////////////////////////
// Configuration for a Quartz 18.432000 MHz
/////////////////////////////////////////////////////////////////////////////////////////////////////
#define PLLAR 0x20263E04 //* 179,712000 MHz for PCK
#define PLLBR 0x10483E0E //* 48,054857 MHz (divider by 2 for USB)
#define MCKR 0x00000202 //* PCK/3 = MCK Master Clock = 59,904000MHz with PLLA selected
#define SLOWCLOCK 32768 //* In Hz
/////////////////////////////////////////////////////////////////////////////////////////////////////
// Frequencies Range
/////////////////////////////////////////////////////////////////////////////////////////////////////
#define INPUT_FREQ_MIN 900000
#define INPUT_FREQ_MAX 32000000
#ifdef AT91RM9200
#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 OUTPUT_FREQ_MIN 80000000
#define OUTPUT_FREQ_MAX 240000000
#else
#ifdef AT91RM3400
#define OUTPUT_FREQ_MIN 20000000
#define OUTPUT_FREQ_MAX 100000000
#endif
#endif
/////////////////////////////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////////////////////////////
//*----------------------------------------------------------------------------
//* \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) < INPUT_FREQ_MIN)
|| ((MainClock/pllDivider) > INPUT_FREQ_MAX) )
return FALSE;
//* Check Output Frequency
if( ((MainClock/pllDivider*pllMultiplier) < OUTPUT_FREQ_MIN)
|| ((MainClock/pllDivider*pllMultiplier) > OUTPUT_FREQ_MAX) )
return FALSE;
return TRUE;
}
//*----------------------------------------------------------------------------
//* \fn AT91F_InitClocks
//* \brief This function performs very low level HW initialization
//*----------------------------------------------------------------------------
unsigned char AT91F_InitClocks(int PLLAR_Register,int PLLBR_Register ,int MCKR_Register)
{
volatile char tmp = 0;
unsigned int MainClock;
unsigned int pllDivider,pllMultiplier;
/////////////////////////////////////////////////////////////////////////////////////////////////////
// Optionnal
/////////////////////////////////////////////////////////////////////////////////////////////////////
//* Check if Input & Output Frequencies are in the correct range
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.
// Setting PLLA and Divider A
/////////////////////////////////////////////////////////////////////////////////////////////////////
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.
// Setting PLLB and Divider B
/////////////////////////////////////////////////////////////////////////////////////////////////////
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.
// Selection of Master Clock MCK (and Processor Clock PCK)
/////////////////////////////////////////////////////////////////////////////////////////////////////
AT91C_BASE_PMC->PMC_MCKR = MCKR_Register;
//* Wait until the master clock is established
tmp = 0;
while( !(AT91C_BASE_PMC->PMC_SR & AT91C_PMC_MCKRDY) && (tmp++ < DELAY_MAIN_FREQ) );
return TRUE;
}
//*----------------------------------------------------------------------------
//* \fn AT91F_InitSDRAM
//* \brief This function performs very low level HW initialisation
//*----------------------------------------------------------------------------
void AT91F_InitSDRAM()
{
int i;
int *pSDRAM = (int *)BASE_EBI_CS1_ADDRESS;
//* Configure PIOC as peripheral (D16/D31)
AT91F_SDRC_CfgPIO();
//* Setup MEMC to support CS1=SDRAM
AT91C_BASE_EBI->EBI_CSA |= AT91C_EBI_CS1A;
AT91C_BASE_EBI->EBI_CFGR = (AT91C_EBI_DBPUC & 0x00) | (AT91C_EBI_EBSEN & 0x00);
//* Init SDRAM
//* 1. A minimum pause of 200us is provided to precede any signal toggle
AT91C_BASE_SDRC->SDRC_CR = AT91C_SDRC_NC_9 | AT91C_SDRC_NR_12 | AT91C_SDRC_NB_4_BANKS | AT91C_SDRC_CAS_2
| 0x100 | 0x4000 | 0x8000
| 0x880000
| 0x21000000;
//* 2. A Precharge All command is issued to the SDRAM
AT91C_BASE_SDRC->SDRC_MR = AT91C_SDRC_MODE_PRCGALL_CMD;
*pSDRAM = 0;
//* 3. Eight Auto-refresh are provided
AT91C_BASE_SDRC->SDRC_MR = AT91C_SDRC_MODE_RFSH_CMD;
for(i=0;i<8;i++)
*pSDRAM = 0;
//* 4. A mode register cycle is issued to program the SDRAM parameters
AT91C_BASE_SDRC->SDRC_MR = AT91C_SDRC_MODE_LMR_CMD;
*(pSDRAM+0x80) = 0;
//* 5. Write refresh rate into SDRAMC refresh timer COUNT register
AT91C_BASE_SDRC->SDRC_TR = (AT91C_SDRC_COUNT & 0x2E0);
*pSDRAM = 0;
//* 6. A Normal Mode Command is provided, 3 clocks after tMRD is set
AT91C_BASE_SDRC->SDRC_MR = AT91C_SDRC_MODE_NORMAL_CMD;
*pSDRAM = 0;
}
//*----------------------------------------------------------------------------
//* \fn AT91F_InitFlash
//* \brief This function performs very low level HW initialization
//*----------------------------------------------------------------------------
void AT91F_InitFlash()
{
AT91C_BASE_MC->MC_PUIA[0] = AT91C_MC_PROT_PNAUNA;
AT91C_BASE_MC->MC_PUP = 0;
AT91C_BASE_MC->MC_PUER = 0; //* Memory controller protection unit disable
AT91C_BASE_MC->MC_ASR = 0; //* read only!
AT91C_BASE_MC->MC_AASR = 0; //* read only!
//* Setup MEMC to support CS0=Flash
AT91C_BASE_EBI->EBI_CSA |= AT91C_EBI_CS0A_SMC;
AT91C_BASE_EBI->EBI_CFGR = (AT91C_EBI_DBPUC & 0x00) | (AT91C_EBI_EBSEN & 0x00);
//* Setup Flash
AT91C_BASE_SMC2->SMC2_CSR[0] = (AT91C_SMC2_NWS & 0x4) | AT91C_SMC2_WSEN
| (AT91C_SMC2_TDF & 0x200) | AT91C_SMC2_BAT | AT91C_SMC2_DBW_16;
}
//*----------------------------------------------------------------------------
//* \fn AT91F_DBGU_Printk
//* \brief This function is used to send a string through the DBGU channel (Very low level debugging)
//*----------------------------------------------------------------------------
void AT91F_DBGU_Printk(
char *buffer) // \arg pointer to a string ending by \0
{
while(*buffer != '\0') {
while (!AT91F_US_TxReady((AT91PS_USART)AT91C_BASE_DBGU));
AT91F_US_PutChar((AT91PS_USART)AT91C_BASE_DBGU, *buffer++);
}
}
//*----------------------------------------------------------------------------
//* \fn AT91F_LowLevelInit
//* \brief This function performs very low level HW initialization
//*----------------------------------------------------------------------------
void AT91F_LowLevelInit()
{
unsigned char status;
/////////////////////////////////////////////////////////////////////////////////////////////////////
// Step 2.
// Checking the Main Oscillator Frequency (Optional)
/////////////////////////////////////////////////////////////////////////////////////////////////////
status = AT91F_WaitForMainClockFrequency();
/////////////////////////////////////////////////////////////////////////////////////////////////////
// Flash AT49BV1614 Initialisation : must be done before change the clocks -> Set correct Wait States
/////////////////////////////////////////////////////////////////////////////////////////////////////
AT91F_InitFlash();
/////////////////////////////////////////////////////////////////////////////////////////////////////
// Step 3. to 5.
/////////////////////////////////////////////////////////////////////////////////////////////////////
status = AT91F_InitClocks(PLLAR,PLLBR,MCKR);
/////////////////////////////////////////////////////////////////////////////////////////////////////
// SDRAM Initialisation
/////////////////////////////////////////////////////////////////////////////////////////////////////
//AT91F_InitSDRAM();
/////////////////////////////////////////////////////////////////////////////////////////////////////
// Test PMC Initialization.
/////////////////////////////////////////////////////////////////////////////////////////////////////
// Open PIO for DBGU
AT91F_DBGU_CfgPIO();
// Configure DBGU
AT91F_US_Configure (
(AT91PS_USART) AT91C_BASE_DBGU, // DBGU base address
60000000, // 60 MHz
AT91C_US_CHMODE_NORMAL | AT91C_US_PAR_NONE , // mode Register to be programmed
115200 , // baudrate to be programmed
0); // timeguard to be programmed
// Enable Transmitter
AT91F_US_EnableTx((AT91PS_USART) AT91C_BASE_DBGU);
AT91F_DBGU_Printk("\n\rAT91F_LowLevelInit() Complete!\n\r");
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -