ADI的BF609双核DSP怎么做开发,我来说一说(二)DDR驱动测试
作者的话
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" );
}
}