DSPC6678的DDR3参数设置(keystone)

DDR前言

在裸机程序上进行DDR适配,对官方demo进行修改。

准备工作:
首先需要找到C6678关于DDR的相关寄存器描述
其次需要找到DDR的数据手册

因为在裸机程序上连接DDR,各部分的底层代码都需要进行检查。
DDR是高速接口,所以对参数要求也比较苛刻。各组线长、内存容量、外接时钟的不同都会影响DDR的使用。

正言

使用了keystone的相关代码进行参考,对level相关补偿进行修改以适配实际场景。
场景:
1.使用4Gb/片的DDR一共片=2GB大小 ——注意这里有坑
2.参考主频率为156.25Mhz
3.硬件线长需要知晓,填写表格自动生成level部分补偿参数
表格参考链接: 关于C6678 DDR3 Leveling 问题

主体函数说明

需要打开两个手册进行对照修改
1.C6678的DDR寄存器参考文件为《Keystone Architecture DDR3 Memory Controller User's Guide》
2.DDR芯片手册(基本都可以在嘉立创商城进行下载)

基本操作流程就是:
1.设置DDR时钟
2.设置补偿参数(level)

主题函数为:
void KeyStone_DDR_init(float ref_clock_MHz, unsigned int DDR_PLLM,unsigned int DDR_PLLD, DDR_ECC_Config * ecc_cfg)

在这里插入图片描述

1.设置DDR时钟

DDR的时钟与C6678的主频设置类似
我们只需要设置倍频与分频参数即可

之后后面的除2操作,就涉及到DDR的原理了(DDR内存每个时钟周期在上升沿和下降沿各传输一次数据,因此实际数据传输速率是时钟频率的两倍。)比如大家用的windows电脑也是一样的,如果看到频率是一半的话不要慌张。

下图取自C6678芯片手册——7.7 DD3 PLL
在这里插入图片描述
我使用的板卡参考时钟为156.25Mhz,要达到1333Mhz就需要进行倍频分频配置。由代码可知:156.25*128/15≈1333Mhz。
让我们进入代码看一下都操作了什么:
在这里插入图片描述
由上图可见:
1.地址映射(咱们现阶段不用管,默认数值都将DDR从0x8000 0000映射到了0x8 0000 0000上了)
2.时钟设置(咱们已经设置好了)
3.初始化(包含了DDR的各种参数)
4.数据测试(咱们不管他,配置好了自动就过了)

2.DDR初始化

DDR初始化的很多参数都与时钟有相当大的关系,而此时钟才是真正的DDR时钟,所以穿入的参数将1333除2了。

/*****************************************************************************
 Prototype    : C6678_EVM_DDR_Init
 Description  : configure DDR according to the clock speed
                please note, clock_MHz is the clock speed in MHz, not data
                rate.
                For example, clock speed for 1333.333M data rate is 666.667-
                MHz
 Input        : float clock_MHz
 Output       : None
 Return Value :

  History        :
  1.Date         : 2011/4/17
    Author       : Brighton Feng
    Modification : Created function

*****************************************************************************/
void C6678_DDR_Init(float clock_MHz, DDR_ECC_Config * ecc_cfg)
{
    Uint32 uiRev= gpBootCfgRegs->DEVICE_ID_REG0&0xF0000000;

    CSL_BootCfgUnlockKicker();

    /*Invert Clock Out*/
    KeyStone_DDR_clock_phase_init(TRUE);

    if(0==uiRev)
    {//Rev 1.0 does not support read eye leveling
        //Set bit 9 = 1 to use forced ratio leveling for read DQS
        gpBootCfgRegs->DDR3_CONFIG_REG[23] |= 0x00000200;
    }

    //initial vale for leveling
    /*WRLVL_INIT_RATIO*/
    gpBootCfgRegs->DDR3_CONFIG_REG[2] = 0x8E;
    gpBootCfgRegs->DDR3_CONFIG_REG[3] = 0x8A;
    gpBootCfgRegs->DDR3_CONFIG_REG[4] = 0x86;
    gpBootCfgRegs->DDR3_CONFIG_REG[5] = 0x7C;
    gpBootCfgRegs->DDR3_CONFIG_REG[6] = 0x6C;
    gpBootCfgRegs->DDR3_CONFIG_REG[7] = 0x65;
    gpBootCfgRegs->DDR3_CONFIG_REG[8] = 0x60;
    gpBootCfgRegs->DDR3_CONFIG_REG[9] = 0x5B;
    gpBootCfgRegs->DDR3_CONFIG_REG[10] = 0x00;

    /*GTLVL_INIT_RATIO*/
    gpBootCfgRegs->DDR3_CONFIG_REG[14] = 0xD0;
    gpBootCfgRegs->DDR3_CONFIG_REG[15] = 0xD3;
    gpBootCfgRegs->DDR3_CONFIG_REG[16] = 0xB9;
    gpBootCfgRegs->DDR3_CONFIG_REG[17] = 0xC3;
    gpBootCfgRegs->DDR3_CONFIG_REG[18] = 0xB3;
    gpBootCfgRegs->DDR3_CONFIG_REG[19] = 0xBA;
    gpBootCfgRegs->DDR3_CONFIG_REG[20] = 0x9F;
    gpBootCfgRegs->DDR3_CONFIG_REG[21] = 0xA4;
    gpBootCfgRegs->DDR3_CONFIG_REG[22] = 0x00;

    /*the PHY_RESET is pulsed (0 -> 1 -> 0) to latch these
    leveling configuration values into the PHY logic.*/
    KeyStone_DDR_latch_leveling_configuration ();

    /*Drives CKE low.
    This is a JEDEC requirement that we have 500us delay between reset de-assert
    and cke assert and then program the correct refresh rate
    The DDR internal clock is divide by 16 before SDCFG write*/
    gpDDR_regs->SDRAM_REF_CTRL = CSL_EMIF4F_SDRAM_REF_CTRL_REG_INITREF_DIS_MASK
        |(unsigned int)(500.f*clock_MHz/16.f);  //not sure about this value


    gpDDR_regs->SDRAM_TIM_1 =
        ((unsigned int)(13.5*clock_MHz/1000.f-0.0001f)<<CSL_EMIF4F_SDRAM_TIM_1_REG_T_RP_SHIFT)|
        ((unsigned int)(13.5*clock_MHz/1000.f-0.0001f)<<CSL_EMIF4F_SDRAM_TIM_1_REG_T_RCD_SHIFT)|
        ((unsigned int)(15*clock_MHz/1000.f-0.0001f)<<CSL_EMIF4F_SDRAM_TIM_1_REG_T_WR_SHIFT)|
        ((unsigned int)(36*clock_MHz/1000.f-0.0001f)<<CSL_EMIF4F_SDRAM_TIM_1_REG_T_RAS_SHIFT)|
        ((unsigned int)(49.5*clock_MHz/1000.f-0.0001f)<<CSL_EMIF4F_SDRAM_TIM_1_REG_T_RC_SHIFT)|
        ((unsigned int)(45*clock_MHz/4000.f-0.0001f)<<CSL_EMIF4F_SDRAM_TIM_1_REG_T_RRD_SHIFT)|  /*T_RRD = (tFAW/(4*tCK)) 每 1*/
        ((unsigned int)(7.5*clock_MHz/1000.f-0.0001f)<<CSL_EMIF4F_SDRAM_TIM_1_REG_T_WTR_SHIFT);
//    gpDDR_regs->SDRAM_TIM_1 = 0x1113783C;

    gpDDR_regs->SDRAM_TIM_2   =
        ((unsigned int)(6*clock_MHz/1000.f-0.0001f)<<CSL_EMIF4F_SDRAM_TIM_2_REG_T_XP_SHIFT)|//T_XP
        ((unsigned int)(120*clock_MHz/1000.f-0.0001f)<<CSL_EMIF4F_SDRAM_TIM_2_REG_T_XSNR_SHIFT)|    /*T_XSNR = (tXS /tCK)每 1*/
        ((512-1)<<CSL_EMIF4F_SDRAM_TIM_2_REG_T_XSRD_SHIFT)|     /*T_XSRD =tXSDLL每 1*/
        ((unsigned int)(7.5*clock_MHz/1000.f-0.0001f)<<CSL_EMIF4F_SDRAM_TIM_2_REG_T_RTP_SHIFT)|
        ((unsigned int)(5.625*clock_MHz/1000.f-0.0001f)<<CSL_EMIF4F_SDRAM_TIM_2_REG_T_CKE_SHIFT);//T_CKE
//    gpDDR_regs->SDRAM_TIM_2   =0x30717FE3;

   gpDDR_regs->SDRAM_TIM_3   =
       (5<<CSL_EMIF4F_SDRAM_TIM_3_REG_T_PDLL_UL_SHIFT)|    /*This field must always be programmed to 0x5.*/
       ((5)<<CSL_EMIF4F_SDRAM_TIM_3_REG_T_CSTA_SHIFT)|     /*This field should be set according to PHY requirements as 0x5.*/
       ((unsigned int)(5.625*clock_MHz/1000.f+0.9999f)<<CSL_EMIF4F_SDRAM_TIM_3_REG_T_CKESR_SHIFT)|
       ((64-1)<<CSL_EMIF4F_SDRAM_TIM_3_REG_ZQ_ZQCS_SHIFT)|
       ((unsigned int)(260*clock_MHz/1000.f-0.0001f)<<CSL_EMIF4F_SDRAM_TIM_3_REG_T_RFC_SHIFT)|
       (15<<CSL_EMIF4F_SDRAM_TIM_3_REG_T_RAS_MAX_SHIFT);   /*This field must always be programmed to 0xF.*/ /*1GB-110 2GB-160 4GB-260 8GB-350*/
    // gpDDR_regs->SDRAM_TIM_3   =0x559F86AF;

    gpDDR_regs->DDR_PHY_CTRL_1  = 0x00100100|
        (12<<CSL_EMIF4F_DDR_PHY_CTRL_1_REG_READ_LATENCY_SHIFT);     /*between CAS Latency + 1 and CAS Latency + 7*/

    gpDDR_regs->ZQ_CONFIG =
        ((0)<<CSL_EMIF4F_ZQ_CONFIG_REG_ZQ_CS1EN_SHIFT)|
        ((1)<<CSL_EMIF4F_ZQ_CONFIG_REG_ZQ_CS0EN_SHIFT)|
        ((1)<<CSL_EMIF4F_ZQ_CONFIG_REG_ZQ_DUALCALEN_SHIFT)|     /*This bit should always be set to 1.*/
        ((1)<<CSL_EMIF4F_ZQ_CONFIG_REG_ZQ_SFEXITEN_SHIFT)|
        ((512/256-1)<<CSL_EMIF4F_ZQ_CONFIG_REG_ZQ_ZQINIT_MULT_SHIFT)|   /*T_ZQ_ZQINIT_MULT = (tZQinit/tZQoper 每 1)*/
        ((256/64-1)<<CSL_EMIF4F_ZQ_CONFIG_REG_ZQ_ZQCL_MULT_SHIFT)|  /*T_ZQ_ZQCL_MULT = (tZQoper/tZQCS 每 1)*/
        /*interval between ZQCS commands = 0.5%/((TSens x Tdriftrate) + (VSens x Vdriftrate))
        =0.5%/((max (dRTTdT, dRONdTM) x Tdriftrate in C/second) + (max(dRTTdV, dRONdVM) x Vdriftrate in mV/second))
        this time need be converted to refresh period number*/
        (((unsigned int)(1000000000*0.5/(1.5*1.2+0.15*15))/(64000000/8192))     //64000/8192=7.8125ms(refresh period)
            <<CSL_EMIF4F_ZQ_CONFIG_REG_ZQ_REFINTERVAL_SHIFT);
//    gpDDR_regs->ZQ_CONFIG = 0x00005161;    // enable configuration

    // gpDDR_regs->ZQ_CONFIG = 0x70073214;

    /*map priority 0,1,2,3 to COS0,
    map priority 3,5,6,7 to COS1*/
    gpDDR_regs->PRI_COS_MAP =
        ((1)<<CSL_EMIF4F_PRI_COS_MAP_REG_PRI_COS_MAP_EN_SHIFT)|
        ((1)<<CSL_EMIF4F_PRI_COS_MAP_REG_PRI_7_COS_SHIFT)|
        ((1)<<CSL_EMIF4F_PRI_COS_MAP_REG_PRI_6_COS_SHIFT)|
        ((1)<<CSL_EMIF4F_PRI_COS_MAP_REG_PRI_5_COS_SHIFT)|
        ((1)<<CSL_EMIF4F_PRI_COS_MAP_REG_PRI_4_COS_SHIFT)|
        ((0)<<CSL_EMIF4F_PRI_COS_MAP_REG_PRI_3_COS_SHIFT)|
        ((0)<<CSL_EMIF4F_PRI_COS_MAP_REG_PRI_2_COS_SHIFT)|
        ((0)<<CSL_EMIF4F_PRI_COS_MAP_REG_PRI_1_COS_SHIFT)|
        ((0)<<CSL_EMIF4F_PRI_COS_MAP_REG_PRI_0_COS_SHIFT);

    /*master based COS map is disabled*/
    gpDDR_regs->MSTID_COS_1_MAP= 0;
    gpDDR_regs->MSTID_COS_2_MAP= 0;

    /*LAT_CONFIG*/
    gpDDR_regs->VBUSM_CONFIG=
        (8<<CSL_EMIF4F_VBUSM_CONFIG_REG_COS_COUNT_1_SHIFT)|
        (16<<CSL_EMIF4F_VBUSM_CONFIG_REG_COS_COUNT_2_SHIFT)|
        (32<<CSL_EMIF4F_VBUSM_CONFIG_REG_PR_OLD_COUNT_SHIFT);

    /*Read Write Execution Threshold*/
    gpDDR_regs->RD_WR_EXEC_THRSH=
        ((1024/8/8-1)<<CSL_EMIF4F_RD_WR_EXEC_THRSH_REG_RD_THRSH_SHIFT)
        |((512/8/8-1)<<CSL_EMIF4F_RD_WR_EXEC_THRSH_REG_WR_THRSH_SHIFT);

    KeyStone_DDR_ECC_init(ecc_cfg);

    /* enables DRAM configuration.  It still has the refresh interval
    programmed to the longer number needed during DRAM initialization.*/
    gpDDR_regs->SDRAM_REF_CTRL = (unsigned int)(500.f*clock_MHz/16.f);

    gpDDR_regs->SDRAM_CONFIG =
        (3<<CSL_EMIF4F_SDRAM_CONFIG_REG_SDRAM_TYPE_SHIFT)|  /*Set to 3 for DDR3. All other values reserved.*/
        (0<<CSL_EMIF4F_SDRAM_CONFIG_REG_IBANK_POS_SHIFT)|
        (DDR_TERM_RZQ_OVER_6<<CSL_EMIF4F_SDRAM_CONFIG_REG_DDR_TERM_SHIFT)|
        (DDR_DYN_ODT_DISABLED<<CSL_EMIF4F_SDRAM_CONFIG_REG_DYN_ODT_SHIFT)|
        (0<<CSL_EMIF4F_SDRAM_CONFIG_REG_DDR_DISABLE_DLL_SHIFT)|
        (SDRAM_DRIVE_RZQ_OVER_7<<CSL_EMIF4F_SDRAM_CONFIG_REG_SDRAM_DRIVE_SHIFT)|
        (DDR_CWL_7<<CSL_EMIF4F_SDRAM_CONFIG_REG_CWL_SHIFT)|
        (DDR_BUS_WIDTH_64<<CSL_EMIF4F_SDRAM_CONFIG_REG_NARROW_MODE_SHIFT)|
        (DDR_CL_9<<CSL_EMIF4F_SDRAM_CONFIG_REG_CL_SHIFT)|
        (DDR_ROW_SIZE_13_BIT<<CSL_EMIF4F_SDRAM_CONFIG_REG_ROWSIZE_SHIFT)|
        (DDR_BANK_NUM_8<<CSL_EMIF4F_SDRAM_CONFIG_REG_IBANK_SHIFT)|
        (0<<CSL_EMIF4F_SDRAM_CONFIG_REG_EBANK_SHIFT)|
        (DDR_PAGE_SIZE_10_BIT_1024_WORD<<CSL_EMIF4F_SDRAM_CONFIG_REG_PAGESIZE_SHIFT);

    TSC_delay_us(600);  //Wait 600us for HW init to complete

//  gpDDR_regs->SDRAM_REF_CTRL    = 64000000/8192/(1000/clock_MHz);
    gpDDR_regs->SDRAM_REF_CTRL    = (unsigned int)64000.f*clock_MHz/8192.f;

    if(KeyStone_DDR_full_leveling())
    {
        while(1);
    }

    if(uiRev)
    {
        /*Rev 2.0,
        read data eye training and read gate training are all triggered for
        initial convergence. However, the read eye sample point may still be
        invalid. Incremental leveling will then force the read eye sample point
        to a good starting value and then it will robustly optimize the read
        eye sample point after multiple successive iterations.*/
        KeyStone_DDR_read_incremental_leveling(100);
    }
}

以上就是keystone的参数,但实际已经根据我的DDR进行了适配。
基本会动三个地方
1.线长补偿(只有此处需要硬件相关计算)
2.TIM时序配置
3.DDR相关寄存器及其他

1.线长补偿

C6678官方提供了计算表格,可以自行去官网下载
下载下来的表格类似于此:
黄色部分需要自己填写,绿色部分就是计算出的参数,
将18个参数都填入gpBootCfgRegs->DDR3_CONFIG_REG寄存器之中即可
在这里插入图片描述

2.TIM时序配置

这就需要根据DDR芯片型号的数据手册进行填写了
我在这里只举个例子
例如
gpDDR_regs->SDRAM_TIM_1
的配置,首先在DDR的寄存器手册中找到这个寄存器:
在这里插入图片描述
进入详情页面
查看其中的一个参数
在这里插入图片描述
圈出的计算公式即为实际的计算公式,如下图的代码
在这里插入图片描述
&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&

那么如何去找Twr这个参数呢?
这就需要我们对照DDR芯片手册了(记着删掉空格再搜索):
在这里插入图片描述

按照上述步骤,将所有的3组TIM参数都进行修正即可,其实大部分应该都是不需要动的。

有个重要的参数在TIM3里面,我就因为这个行刷新时间(tRFC)导致1333Mhz频率跑不通。下图为当前的参数
在这里插入图片描述
tRFC这个参数按照DDR的规格自己进行选择,例如我当前的DDR芯片为4Gb,就需要找到对应4Gb与1333Mhz的参数,实际就是260。下图为DDR芯片手册上的参数对照:
在这里插入图片描述

3.DDR相关寄存器及其他

其他部分的参数也需要大家仔细检查一下,我其实是全部都看了一遍,有些没看懂的也就没动,主要修改了上述两个步骤后DDR就可以跑在1333MHZ了。
这里是因为我看了这位老哥的博客才发现需要仔细配置的
6678 DDR3只能访问一半地址宽度

下述寄存器需要根据DDR的参数实际进行配置才能让DDR的全部空间得以访问。
在这里插入图片描述
笔者可是犯了个超低级错误导致一天的时间被浪费掉了,错把DDR手册上的4Gb当做4GB大小。因为我这块板子接了4块DDR,所以我错误的认为我有16G的空间可以用,但其实确是2G。
下面介绍一下这个寄存器需要改的部分:
1.总线宽度
2.bank数量
3.行宽
4.列宽
为什么这里没有pagesize?不急马上就说

0.DDR手册

先给大家上个DDR手册
下图是DDR手册上的说明(我用的型号属于256 Meg x 16这列)
在这里插入图片描述

1.总线宽度

就是DDR数据线的条数
我用的型号,每个DDR有16条数据线,然后我一共用了4片,所以现在就是4*16就是64的总线宽度。
在这里插入图片描述
下图为位宽寄存器位描述
在这里插入图片描述
下图是DDR手册上数据线的描述,每个DDR有16条数据传输线。
在这里插入图片描述

2.bank数量

这个可以在DDR手册中轻松查到,见“3.DDR相关寄存器及其他”。
在这里插入图片描述
下图为bank数量设定的寄存器位:
在这里插入图片描述

3.行宽

这个也可以在DDR手册中轻松查到,见“3.DDR相关寄存器及其他”。从14到0位,一共是15位:
在这里插入图片描述

4.列宽

这一位需要先看下寄存器说明:
在这里插入图片描述
可以看出pagesize与列宽绑在了一起,那我们用哪个呢?
见“3.DDR相关寄存器及其他”可看出列宽为10,pagesize为2K。寄存器上我们选2,因为1024-word=2048byte。

5.其他

其他寄存器大部分也都可以在DDR手册找到,我这就不细索了。

映射关系

附上地址映射关系,若超过2G的情况则需要先映射再进行操作
在这里插入图片描述

C6678地址说明

由官方手册可以看出,DDR3默认映射到了0x8000 000上2GB。
DDR3接入以后会自动在外部地址0x8 0000 0000上向后延续。
在这里插入图片描述

keystone代码

第二行数据RADDR负责将0x8 0000 0000往后的2G空间映射到BADDR的0x8000 0000上
在这里插入图片描述

上电默认的寄存器结果

在这里插入图片描述

结束

笔者认为,DDR的配置大同小异,即使换了其他芯片使用,基本的操作也都类似。

posted @ 2025-06-03 16:43  东风点点吹  阅读(24)  评论(0)    收藏  举报