作者的话
ADI的双核DSP,第二颗是Blackfin系列的BF609,这颗DSP我用了很久,比较熟悉,且写过一些给新手的教程。
硬件准备
ADSP-BF609-CORE:ADI BF609开发板
产品链接:https://item.taobao.com/item.htm?id=39901289258
AD-HP530ICE仿真器:ADI DSP通用仿真器
产品链接:https://item.taobao.com/item.htm?id=753233120844
软件准备
CCES2.2.0
硬件环境的搭建
- 选中DDR程序,鼠标右键:
- 选择芯片型号为BF609,然后下一步:
- 选择emulator,下一步
- 选择ICE-1000(AD-HP530ICE仿真器采用的是ICE-1000的固件),完成
- 回到原界面,选择debug
- 跳出来一个对话框,选择yes
- 软件进行debug编译,这个时候会跳出这个对话框,选择YES。
- 完成编译
- 点击运行,开始跑DDR测试程序,console界面会陆续打印测试结果,说明DDR运行正常,完成程序测试,再中止程序(测试的主频+时钟组合很多,测完一个即可点中止)。
- 回到工程界面
核心代码分析
/********************************************************
*
- OpenADSP开源社区
- http://www.openadsp.com
- 【OpenADSP开源社区】
- http://www.openadsp.cn
********************************************************/
#include <cdefBF609.h>
#include <defBF609.h>
#include <ccblkfn.h>
#include “post_debug.h”
#include “cgu_init.h”
#include “ddr_init.h”
#include <math.h>
#define DLL_LOCK_PERIOD 4500
#define NUM_FREQS 7
/* DDR2 range */
#define DDR2_START_ADDRESS 0x0
#define DDR2_END_ADDRESS 0x8000000
#define BUFFER_SIZE 0x400
#define N BUFFER_SIZE
#define MEM_SIZE_32 0x200 /* 4 byte xfer /
#define INT_XCNT_0 0x100000 / interrupt on x count going to 0 */
int freq[NUM_FREQS] = { 250, 225, 200, 166, 150, 133, 125 };
int nFailureCnt = 0;
int DDR2_Src_Buffer[N];
int DDR2_Dest_Buffer[N];
int nCurrent_DDR_Addr = DDR2_START_ADDRESS;
char * pattern_comments[] =
{
"DDR pattern random ",
"DDR pattern incrementing ",
"DDR pattern all 0’s ",
"DDR pattern all 5’s ",
"DDR pattern all A’s ",
"DDR pattern all F’s ",
};
enum /* data pattern */
{
RANDOM,
INCREMENTING,
ALL_0S,
ALL_5S,
ALL_AS,
ALL_FS,
};
static int nTest = RANDOM;
/* DDR2 timing parameters after calculation */
unsigned int uiCL=0, uiRCD=0, uiRP=0,uiRC=0, uiRRD=0, uiRAS=0, uiRFC=0, uiFAW=0, uiRTP=0, uiWR=0, uiWTR=0, uiREFVAL =0;
/* Local Function Declarations */
void DDR2_Config(unsigned int uiDDRCfg, unsigned int uiDDRTr0, unsigned int uiDDRTr1, unsigned int uiDDRTr2, unsigned int uiDDRMr, unsigned int uiDDREmr1, unsigned int uiDDRCtl);
void Change_CGU(void);
/* Calculate DDR2 timing parameters based on DCLK */
int Calc_Params( float uiDDR2Val, float fDCLKns);
/*
Function name: DDR2_Init
Description: This function initializes the DDR2 based on CGU initialization.
Obtains the MSEL/CLKIN/DF values and calculates DCLK. Based on DCLK calculates
timing parameters
Arguments: None
Return value: None.
*/
void DDR2_Init(void)
{
int i=0,Dll_cycles;
int DFval=0, DSELval = 0, MSELval=0, CSELval = 0;/* Check for DMA IDLE */
while(!(*pREG_DMC0_STAT & BITM_DMC_STAT_IDLE))
NOP;/* put the part into self refresh only if already initialized */
if((*pREG_DMC0_STAT & BITM_DMC_STAT_MEMINITDONE)&&(pREG_DMC0_STAT & BITP_DMC_STAT_DLLCALDONE))
{
/ Enable self Refresh */
*pREG_DMC0_CTL |= BITM_DMC_CTL_SRREQ;/* wait for SRACK to get set */ while(!(*pREG_DMC0_STAT & BITM_DMC_STAT_SRACK)) NOP;
}
/* CGU init */
Change_CGU();/* calculate the DLL wait cycles */
DSELval = (*pREG_CGU0_DIV & BITM_CGU_DIV_DSEL) >> BITP_CGU_DIV_DSEL;
CSELval = (*pREG_CGU0_DIV & BITM_CGU_DIV_CSEL) >> BITP_CGU_DIV_CSEL;
Dll_cycles =DLL_LOCK_PERIOD * DSELval/CSELval;/* DLL Lock */
for (i=0; i<Dll_cycles; i++)
NOP;/* Get the DDR2 out of self refresh only if already initialized */
if((*pREG_DMC0_STAT & BITM_DMC_STAT_MEMINITDONE)&&(pREG_DMC0_STAT & BITP_DMC_STAT_DLLCALDONE))
{
/ Disable self refresh */
*pREG_DMC0_CTL ^=BITM_DMC_CTL_SRREQ;/* Wait for SRACK to clear */ while((*pREG_DMC0_STAT & BITM_DMC_STAT_SRACK)) NOP;
}
/* Get CGU information - needs CLKIN, DSEL, DF, MSEL */
DFval = (*pREG_CGU0_CTL & BITM_CGU_CTL_DF) >> BITP_CGU_CTL_DF;
MSELval = (*pREG_CGU0_CTL & BITM_CGU_CTL_MSEL) >> BITP_CGU_CTL_MSEL;/* Calculate DCLK */
float fDCLKMHz = 0, fDCLKns =0;
fDCLKMHz = ((CLKINMHz * MSELval)/(DFval+1))/(DSELval);
fDCLKns = 1000/fDCLKMHz;/* Calculate parameters */
if (fDCLKMHz >= 200 )
uiCL = 4;
else
uiCL = 3;uiRCD = Calc_Params(DDR2_RCD,fDCLKns);
uiRP = Calc_Params(DDR2_RP,fDCLKns);
uiRC = Calc_Params(DDR2_RC,fDCLKns);
uiRRD = Calc_Params(DDR2_RRD,fDCLKns);
uiRAS = Calc_Params(DDR2_RAS,fDCLKns);
uiRFC = Calc_Params(DDR2_RFC,fDCLKns);
uiFAW = Calc_Params(DDR2_FAW,fDCLKns);
uiWR = Calc_Params(DDR2_WR,fDCLKns);
uiWTR = Calc_Params(DDR2_WTR,fDCLKns);
uiREFVAL = fDCLKMHz *DDR2_TREFIus;DDR2_Config(DDR0_CFG, DDR0_TR0, DDR0_TR1,DDR0_TR2, DDR0_MR, DDR0_EMR1,DDR0_CTL);
}
void DDR2_Config(unsigned int uiDDRCfg, unsigned int uiDDRTr0, unsigned int uiDDRTr1, unsigned int uiDDRTr2, unsigned int uiDDRMr, unsigned int uiDDREmr1, unsigned int uiDDRCtl)
{
int i=0;
int dllDataCycle;
/* Configure DDR2 registers */
*pREG_DMC0_CFG = uiDDRCfg;
*pREG_DMC0_TR0 = uiDDRTr0;
*pREG_DMC0_TR1 = uiDDRTr1;
*pREG_DMC0_TR2= uiDDRTr2;
*pREG_DMC0_MR= uiDDRMr;
*pREG_DMC0_PHY_CTL3 = BITM_DMC_PHY_CTL3_ENODTDQ|BITM_DMC_PHY_CTL3_TMG0|BITM_DMC_PHY_CTL3_TMG1|BITM_DMC_PHY_CTL3_OFST0|BITM_DMC_PHY_CTL3_OFST1;
*pREG_DMC0_PHY_CTL1 =ENUM_DMC_PHY_CTL1_ODT_75;
*pREG_DMC0_CTL= uiDDRCtl;
/* Wait for initialization to complete */
while(!(*pREG_DMC0_STAT & BITM_DMC_STAT_MEMINITDONE))
NOP;
/* Wait for calibration to complete */
while(!(*pREG_DMC0_STAT & BITP_DMC_STAT_DLLCALDONE))
NOP;
/* keep the DLLCALRDCNT reset value and only modify DATACYC */
*pREG_DMC0_DLLCTL= 0x54B;
}
/*
Function name: CalcParams
Description: This function calculates DDR2 timing parameters based on DCLK
Arguments: None
Return value: Returns the calculated parameter value
*/
int Calc_Params( float uiDDR2Val, float fDCLKns)
{
int uiParamVal=0;
float fParamVal = 0.0;fParamVal =uiDDR2Val/fDCLKns;
uiParamVal = ceil(fParamVal);return uiParamVal;
}
void Change_CGU(void)
{
static int nFreqIndex = 0;
if( nFreqIndex > (NUM_FREQS - 1) )
nFreqIndex = 0;
switch(nFreqIndex)
{
case 0:
CGU_Init(20, 1, 2); /* CCLK=500Mhz, 250Mhz DDR2 CLK */
DEBUG_PRINT("Using %d MHz CCLK, %d DDR CLK...\n", 500, freq[nFreqIndex]);
break;
case 1:
CGU_Init(18, 1, 2); /* CCLK=450Mhz, 225Mhz DDR2 CLK */
DEBUG_PRINT("Using %d MHz CCLK, %d DDR CLK...\n", 450, freq[nFreqIndex]);
break;
case 2:
CGU_Init(16, 1, 2); /* CCLK=400Mhz, 200Mhz DDR2 CLK */
DEBUG_PRINT("Using %d MHz CCLK, %d DDR CLK...\n", 400, freq[nFreqIndex]);
break;
case 3:
CGU_Init(20, 1, 3); /* CCLK=500Mhz, 166Mhz DDR2 CLK */
DEBUG_PRINT("Using %d MHz CCLK, %d DDR CLK...\n", 500, freq[nFreqIndex]);
break;
case 4:
CGU_Init(18, 1, 3); /* CCLK=450Mhz, 150Mhz DDR2 CLK */
DEBUG_PRINT("Using %d MHz CCLK, %d DDR CLK...\n", 450, freq[nFreqIndex]);
break;
case 5:
CGU_Init(16, 1, 3); /* CCLK=400Mhz, 133Mhz DDR2 CLK */
DEBUG_PRINT("Using %d MHz CCLK, %d DDR CLK...\n", 400, freq[nFreqIndex]);
break;
case 6:
CGU_Init(20, 1, 4); /* CCLK=500Mhz, 125Mhz DDR2 CLK */
DEBUG_PRINT("Using %d MHz CCLK, %d DDR CLK...\n", 500, freq[nFreqIndex]);
break;
}
nFreqIndex++;
}
void FillSrcBuffer(int nDataPattern)
{
int nIndex = 0;
/* fill our out_buf with some data */
for(nIndex = 0; nIndex < N; nIndex++ )
{
switch (nDataPattern)
{
case ALL_0S:
DDR2_Src_Buffer[nIndex] = 0x00000000;
break;
case ALL_5S:
DDR2_Src_Buffer[nIndex] = 0x55555555;
break;
case ALL_AS:
DDR2_Src_Buffer[nIndex] = 0xaaaaaaaa;
break;
case ALL_FS:
DDR2_Src_Buffer[nIndex] = 0xffffffff;
break;
case INCREMENTING:
DDR2_Src_Buffer[nIndex] = nIndex;
break;
case RANDOM:
DDR2_Src_Buffer[nIndex] = rand();
break;
}
}
}
void WriteDDR(void)
{
int nIndex = 0;
unsigned int pDest = (unsigned int)nCurrent_DDR_Addr;
for(nIndex = 0; nIndex < N; nIndex++ )
{
*pDest = DDR2_Src_Buffer[nIndex];
pDest++;
}
}
void ReadDDR(void)
{
int nIndex = 0;
unsigned int pDest = (unsigned int)nCurrent_DDR_Addr;
for(nIndex = 0; nIndex < N; nIndex++ )
{
DDR2_Dest_Buffer[nIndex] = *pDest;
pDest++;
}
}
bool CompareDDR(void)
{
int nIndex = 0;
unsigned int pDest = (unsigned int)nCurrent_DDR_Addr;
bool bSuccess = true;
for(nIndex = 0; nIndex < N; nIndex++ )
{
if( DDR2_Src_Buffer[nIndex] != DDR2_Dest_Buffer[nIndex] )
{
bSuccess = false;
break;
}
pDest++;
}
return bSuccess;
}
int main( void )
{
int i = 0;
bool bSuccess = true;
int nFreqIndex = 0;
DEBUG_HEADER( “DDR Memory Test” );
/* clear our buffer to start */
for(i=0; i < N; i++)
{
DDR2_Src_Buffer[i]=0;
}
srand(*(volatile int*)0xF0000000); /* seed with a random value */
/* loop through all frequencies */
while(nFreqIndex++ < NUM_FREQS)
{
DDR2_Init();
/* make sure we start with the first pattern */
nTest = 0;
/* loop through all patterns */
while(nTest <= ALL_FS)
{
DEBUG_PRINT("%susing core accesses.\n\n", pattern_comments[nTest]);
nCurrent_DDR_Addr = DDR2_START_ADDRESS;
FillSrcBuffer(nTest);
/* do core access for he second half of memory */
do
{
WriteDDR();
ReadDDR();
bSuccess = CompareDDR();
if(!bSuccess)
{
/* increment the failure count because we want to try */
/* all frequencies no matter what */
break;
}
nCurrent_DDR_Addr += (BUFFER_SIZE * sizeof(unsigned int));
}while(nCurrent_DDR_Addr < DDR2_END_ADDRESS);
if(!bSuccess)
{
nFailureCnt++;
}
nTest++;
} /* while(nTest <= ALL_FS) */
} /* while(nFreqIndex++ < NUM_FREQS) */
/* now tell if there were any issues or not */
if(nFailureCnt)
{
DEBUG_STATEMENT( "DDR Test Failed" );
}
else
{
DEBUG_STATEMENT( "DDR Test OK" );
}
}