This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

DDR2 Speed on AM335X

Anybody having any issues getting the DDR2 on AM335X to run reliably at 266MHz? On our first spin of boards that were using engineering samples of the AM335X I have an issue with DDR2 not running reliably above 240MHz. At 266MHz I have a memory test where I can get one bit to fail. The way I get it to fail is by flipping all the data bits from all 0's to all 1's ---- I will sometimes see a one bit error in this situation. I do not have the problem if I slow the DDR2 down to 240MHz. And yes I have used the TI spreadsheet tools to set up my DDR2. The Micron memory chip I am interfacing to is good to 400MHz.

Our next set of boards with fully qualified Industrial AM335X chips will arrive this coming week, so hopefully I can go back to full speed (266MHz DDR2) with these new boards.

  • Hi Brad,
     
    Have you followed the DDR2 routing recommendations in the datasheet? In section "5.5.2.2.2.9 DDR2 Signal Termination" of the datasheet, there is a Table 5-47. Please check Note 5 below the table. Let us know what happens with your next batch.
     
    Best Regards
    Biser
  • Simple correction to a previous post. Look for section 5.4.2.2.2.9.

  • For those of you who don't like the starterWare DDRInit that writes to undocumented registers, reserved bit areas in documented registers and the writes of more than 32 bits into 32 bit registers, here is my code for the specific Micron DDR2 I used.

    //Full Micron part number MT47H32M16HR-25E IT:G
    static void DDR2PhyInit(void)
    {
        // Enable VTP (Voltage, Temperature and Process impedance adjustment)
        //Reccomned 0 1 1 Update on 4 consecutive update requests digital filter
        HWREG(SOC_CONTROL_REGS + CONTROL_VTP_CTRL) |= CONTROL_VTP_CTRL_ENABLE;
        HWREG(SOC_CONTROL_REGS + CONTROL_VTP_CTRL) &= ~CONTROL_VTP_CTRL_CLRZ;
        HWREG(SOC_CONTROL_REGS + CONTROL_VTP_CTRL) |= CONTROL_VTP_CTRL_CLRZ;
        while((HWREG(SOC_CONTROL_REGS + CONTROL_VTP_CTRL) & CONTROL_VTP_CTRL_READY) !=
                    CONTROL_VTP_CTRL_READY);

        // DDR PHY CMD0 Register configuration
        HWREG(CMD0_SLAVE_RATIO_0) = 0x80;
        HWREG(CMD0_SLAVE_FORCE_0) = 0x0;                       
        HWREG(CMD0_SLAVE_DELAY_0) = 0x0;
        HWREG(CMD0_LOCK_DIFF_0) = 0x4;
        HWREG(CMD0_INVERT_CLKOUT_0) = 0x0;

        // DDR PHY CMD1 Register configuration
        HWREG(CMD1_SLAVE_RATIO_0) = 0x80;                 
        HWREG(CMD1_SLAVE_FORCE_0) =  0x0;                       
        HWREG(CMD1_SLAVE_DELAY_0) = 0x0;                       
        HWREG(CMD1_LOCK_DIFF_0) = 0x4;                        
        HWREG(CMD1_INVERT_CLKOUT_0) = 0x0;

        // DDR PHY CMD2 Register configuration
        HWREG(CMD2_SLAVE_RATIO_0) = 0x80;                 
        HWREG(CMD2_SLAVE_FORCE_0) = 0x0;                       
        HWREG(CMD2_SLAVE_DELAY_0) = 0x0;                       
        HWREG(CMD2_LOCK_DIFF_0) = 0x4;                        
        HWREG(CMD2_INVERT_CLKOUT_0) = 0x0;

        //DATA macro configuration
        HWREG(DATA0_RD_DQS_SLAVE_RATIO_0)  = ((0x40 << 10)|(0x40 << 0));
        HWREG(DATA0_WR_DQS_SLAVE_RATIO_0)  = ((0x00 << 10)|(0x00 << 0));
        HWREG(DATA0_WRLVL_INIT_RATIO_0)    = ((0x00 << 10)|(0x00 << 0));
        HWREG(DATA0_GATELVL_INIT_RATIO_0)  = ((0x00 << 10)|(0x00 << 0));
        HWREG(DATA0_FIFO_WE_SLAVE_RATIO_0) = ((0x55 << 10)|(0x55 << 0));
        HWREG(DATA0_WR_DATA_SLAVE_RATIO_0) = ((0x40 << 10)|(0x40 << 0));
        HWREG(DATA0_LOCK_DIFF_0) = 0x00;      

        HWREG(DATA1_RD_DQS_SLAVE_RATIO_0)  = ((0x40 << 10)|(0x40 << 0));
        HWREG(DATA1_WR_DQS_SLAVE_RATIO_0)  = ((0x00 << 10)|(0x00 << 0));
        HWREG(DATA1_WRLVL_INIT_RATIO_0)    = ((0x00 << 10)|(0x00 << 0));
        HWREG(DATA1_GATELVL_INIT_RATIO_0)  = ((0x00 << 10)|(0x00 << 0));
        HWREG(DATA1_FIFO_WE_SLAVE_RATIO_0) = ((0x55 << 10)|(0x55 << 0));
        HWREG(DATA1_WR_DATA_SLAVE_RATIO_0) = ((0x40 << 10)|(0x40 << 0));
        HWREG(DATA1_LOCK_DIFF_0) =  0x00;     
     
        HWREG(DATA0_USE_RANK0_DELAYS_0) = 1;
        HWREG(DATA1_USE_RANK0_DELAYS_0) = 1;                        
    }
    //DDR2Init
    static void DDR2Init(void)
    {
        volatile unsigned int delay = 5000;

        // DDR2 Phy Initialization
        DDR2PhyInit();
        HWREG(SOC_CONTROL_REGS + CONTROL_DDR_CMD_IOCTRL(0)) =  0x18B;
        HWREG(SOC_CONTROL_REGS + CONTROL_DDR_CMD_IOCTRL(1)) =  0x18B;
        HWREG(SOC_CONTROL_REGS + CONTROL_DDR_CMD_IOCTRL(2)) =  0x18B;
        HWREG(SOC_CONTROL_REGS + CONTROL_DDR_DATA_IOCTRL(0)) = 0x18B;
        HWREG(SOC_CONTROL_REGS + CONTROL_DDR_DATA_IOCTRL(1)) = 0x18B;
    //    HWREG(SOC_CONTROL_REGS + CONTROL_DDR_CMD_IOCTRL(0)) =  0x273;
    //    HWREG(SOC_CONTROL_REGS + CONTROL_DDR_CMD_IOCTRL(1)) =  0x273;
    //    HWREG(SOC_CONTROL_REGS + CONTROL_DDR_CMD_IOCTRL(2)) =  0x273;
    //    HWREG(SOC_CONTROL_REGS + CONTROL_DDR_DATA_IOCTRL(0)) = 0x273;
    //    HWREG(SOC_CONTROL_REGS + CONTROL_DDR_DATA_IOCTRL(1)) = 0x273;

        // IO to work for DDR2
        HWREG(SOC_CONTROL_REGS + CONTROL_DDR_IO_CTRL) &= 0x0fffffff;

        HWREG(SOC_CONTROL_REGS + CONTROL_DDR_CKE_CTRL) |= CONTROL_DDR_CKE_CTRL_DDR_CKE_CTRL; //(0x131c) (0x00000001u)

        HWREG(SOC_EMIF_0_REGS + EMIF_DDR_PHY_CTRL_1) = 0x05;
        HWREG(SOC_EMIF_0_REGS + EMIF_DDR_PHY_CTRL_1_SHDW) = 0x05;

        HWREG(SOC_EMIF_0_REGS + EMIF_SDRAM_TIM_1) =      0x0668A392; //Using TRAS=40ns from Table 12. Table 8 says 45ns --- but not required for normal operation
        HWREG(SOC_EMIF_0_REGS + EMIF_SDRAM_TIM_1_SHDW) = 0x0668A392;
        HWREG(SOC_EMIF_0_REGS + EMIF_SDRAM_TIM_2) =      0x38173216;
        HWREG(SOC_EMIF_0_REGS + EMIF_SDRAM_TIM_2_SHDW) = 0x38173216;
        HWREG(SOC_EMIF_0_REGS + EMIF_SDRAM_TIM_3) =      0xF00101DF;
        HWREG(SOC_EMIF_0_REGS + EMIF_SDRAM_TIM_3_SHDW) = 0xF00101DF;

    //    HWREG(SOC_EMIF_0_REGS + EMIF_SDRAM_TIM_1) =      0x0666A389;
    //    HWREG(SOC_EMIF_0_REGS + EMIF_SDRAM_TIM_1_SHDW) = 0x0666A389;
    //    HWREG(SOC_EMIF_0_REGS + EMIF_SDRAM_TIM_2) =      0x241E31CA;
    //    HWREG(SOC_EMIF_0_REGS + EMIF_SDRAM_TIM_2_SHDW) = 0x241E31CA;
    //    HWREG(SOC_EMIF_0_REGS + EMIF_SDRAM_TIM_3) =      0x000001BF;
    //    HWREG(SOC_EMIF_0_REGS + EMIF_SDRAM_TIM_3_SHDW) = 0x000001BF;

    //DDR2: MT47H32M16-25E – 8 Meg x 16 x 4 banks   (64MByte or 512Mbits) (13 row bits, 4 banks, 10 column bits)
        HWREG(SOC_EMIF_0_REGS + EMIF_SDRAM_CONFIG) =   0x40805322; //no termination
        HWREG(SOC_EMIF_0_REGS + EMIF_SDRAM_CONFIG_2) = 0x0; //power on value
        HWREG(SOC_EMIF_0_REGS + EMIF_SDRAM_REF_CTRL) =      0x00004650;
        HWREG(SOC_EMIF_0_REGS + EMIF_SDRAM_REF_CTRL_SHDW) = 0x00004650;

        while(delay--); //Some kind of hack here. Should check a status instead of waiting (bpb 4/5/2012)

        HWREG(SOC_EMIF_0_REGS + EMIF_SDRAM_REF_CTRL) = 0x0000040D;   //266MHz * 3.9us  industrial
        HWREG(SOC_EMIF_0_REGS + EMIF_SDRAM_REF_CTRL_SHDW) = 0x0000040D;
    //DDR2: MT47H32M16-25E – 8 Meg x 16 x 4 banks   (64MByte or 512Mbits) (13 row bits, 4 banks, 10 column bits)
        HWREG(SOC_EMIF_0_REGS + EMIF_SDRAM_CONFIG) =   0x40805322; //no termination
        HWREG(SOC_EMIF_0_REGS + EMIF_SDRAM_CONFIG_2) = 0x0; //power on value

        HWREG(SOC_EMIF_0_REGS + EMIF_PWR_MGMT_CTRL) =      0x0; //No power management
        HWREG(SOC_EMIF_0_REGS + EMIF_PWR_MGMT_CTRL_SHDW) = 0x0; //No power management
    }

  • Hello Brad,

    Whats the magic number 4650 used for the refresh rate... the SPL code does the same thing. It's writes the 4650, waits for sometime and then writes the correct value?

    I tried reading through the TRM but cannot find any reference to it. Is there a sequence for initializing the DDR interface??

    Thank you

    Regards

    Santhosh

  • Hello Brad,

    Another question I have is related to the PHY_CTRL_1 register... the sample code used the value 0x100005 but you use the value 0x5. The bit set in the sample code enables power to the PHY data macros (atleast that's what the TRM says). Can you please clarify this??

    I'm referring to the following statement...

    HWREG(SOC_EMIF_0_REGS + EMIF_DDR_PHY_CTRL_1) = 0x05;  (Instead of 0x100005)

    Thank you

    Regards

    Santhosh

  • Santosh,

    Yeah, it would have been nice if I commented on that also since I removed all the other extraneous junk from starterWare DDR2 initialization. Looking at the TRM again myself I can't say why the 0x4650. I guess it needed to be something and I overwrote it later for my industrial temp DDR2 so I did not worry about that value.

    As far as 0x100005 vs 0x5 for EMIF_DDR_PHY_CTRL_1, I just lifted that value from bl_platform.c in starterWare Version 7 and or bl_am335x.c in starterWare Version 6. Another case where I did not worry about the value since it was not overflowing a register or writing to a non-existant register. You will note that I removed the write to EMIF_DDR_PHY_CTRL_2 since as far as I can tell that register does not exist.

    By the way, I have never seen the SPL code and don't know what that is. Is it a Linux thing? I am a bare metal guy, hence my familiarity with starterWare.

    Brad

  • Hello Brad,

    Yes SPL is a linux thing... the 0x5 puzzles me because the TRM clearly says it's set to 1 to enable Power to the PHY Data Macros and you would think that it's needed :)

    Hopefully someone from TI can answer that and also the 4650 magic number.

    Thanks for your reply..

    Regards

    Santhosh