ADI的BF609双核DSP怎么做开发,我来说一说(二)DDR驱动测试

发布于:2025-04-17 ⋅ 阅读:(30) ⋅ 点赞:(0)

作者的话

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

硬件环境的搭建

在这里插入图片描述

  1. 选中DDR程序,鼠标右键:

在这里插入图片描述

在这里插入图片描述

  1. 选择芯片型号为BF609,然后下一步:

在这里插入图片描述

  1. 选择emulator,下一步

在这里插入图片描述

  1. 选择ICE-1000(AD-HP530ICE仿真器采用的是ICE-1000的固件),完成

在这里插入图片描述

  1. 回到原界面,选择debug

在这里插入图片描述

  1. 跳出来一个对话框,选择yes

在这里插入图片描述

  1. 软件进行debug编译,这个时候会跳出这个对话框,选择YES。

在这里插入图片描述

  1. 完成编译

在这里插入图片描述

  1. 点击运行,开始跑DDR测试程序,console界面会陆续打印测试结果,说明DDR运行正常,完成程序测试,再中止程序(测试的主频+时钟组合很多,测完一个即可点中止)。

在这里插入图片描述

在这里插入图片描述

  1. 回到工程界面

在这里插入图片描述

核心代码分析

/********************************************************
*

  • 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" );
}

}


网站公告

今日签到

点亮在社区的每一天
去签到