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.

AM3359 EMIF initialization

Other Parts Discussed in Thread: AM3359

I am in the process of launching a bare-metal project on the AM3359 and  I have trouble initializing the DDR2 RAM of the ICE (1.0A) eval board. I took all the parameters from the GEL file and wrote the following initalization routine:

    {
      //! Switch to System Mode
      asm("    swi     #1;");

      //! Enable EMIF
      CM_PER->EMIF_FW_CLKCTRL             |= 2;
      CM_PER->EMIF_CLKCTRL                |= 2;
      while (!(CM_PER->L3_CLKSTCTRL & ((1 << 4) | (1 << 2))));

      //! Phy init
      CONTROL_MODULE->VTP_CTRL            |=  (1 << 6);
      CONTROL_MODULE->VTP_CTRL            &= ~(1 << 0);
      CONTROL_MODULE->VTP_CTRL            |=  (1 << 0);;
      while (!(CONTROL_MODULE->VTP_CTRL & (1 << 5)));

      DDR_PHY->CMD[0].SLAVE_RATIO          = DDR_CONFIG_PHY_CMD0_SLAVE_RATIO;
      DDR_PHY->CMD[0].SLAVE_FORCE          = DDR_CONFIG_PHY_CMD0_SLAVE_FORCE;
      DDR_PHY->CMD[0].SLAVE_DELAY          = DDR_CONFIG_PHY_CMD0_SLAVE_DELAY;
      DDR_PHY->CMD[0].DLL_LOCK_DIFF        = DDR_CONFIG_PHY_CMD0_LOCK_DIFF;
      DDR_PHY->CMD[0].INVERT_CLKOUT        = DDR_CONFIG_PHY_CMD0_INVERT_CLKOUT;

      DDR_PHY->CMD[1].SLAVE_RATIO          = DDR_CONFIG_PHY_CMD1_SLAVE_RATIO;
      DDR_PHY->CMD[1].SLAVE_FORCE          = DDR_CONFIG_PHY_CMD1_SLAVE_FORCE;
      DDR_PHY->CMD[1].SLAVE_DELAY          = DDR_CONFIG_PHY_CMD1_SLAVE_DELAY;
      DDR_PHY->CMD[1].DLL_LOCK_DIFF        = DDR_CONFIG_PHY_CMD1_LOCK_DIFF;
      DDR_PHY->CMD[1].INVERT_CLKOUT        = DDR_CONFIG_PHY_CMD1_INVERT_CLKOUT;

      DDR_PHY->CMD[2].SLAVE_RATIO          = DDR_CONFIG_PHY_CMD2_SLAVE_RATIO;
      DDR_PHY->CMD[2].SLAVE_FORCE          = DDR_CONFIG_PHY_CMD2_SLAVE_FORCE;
      DDR_PHY->CMD[2].SLAVE_DELAY          = DDR_CONFIG_PHY_CMD2_SLAVE_DELAY;
      DDR_PHY->CMD[2].DLL_LOCK_DIFF        = DDR_CONFIG_PHY_CMD2_LOCK_DIFF;
      DDR_PHY->CMD[2].INVERT_CLKOUT        = DDR_CONFIG_PHY_CMD2_INVERT_CLKOUT;

      DDR_PHY->DATA[0].RD_DQS_SLAVE_RATIO  = DDR_CONFIG_PHY_DATA0_RD_DQS_SLAVE_RATIO;
      DDR_PHY->DATA[0].WR_DQS_SLAVE_RATIO  = DDR_CONFIG_PHY_DATA0_WR_DQS_SLAVE_RATIO;
      DDR_PHY->DATA[0].FIFO_WE_SLAVE_RATIO = DDR_CONFIG_PHY_DATA0_FIFO_WE_SLAVE_RATIO;
      DDR_PHY->DATA[0].WR_DATA_SLAVE_RATIO = DDR_CONFIG_PHY_DATA0_WR_DATA_SLAVE_RATIO;

      DDR_PHY->DATA[1].RD_DQS_SLAVE_RATIO  = DDR_CONFIG_PHY_DATA1_RD_DQS_SLAVE_RATIO;
      DDR_PHY->DATA[1].WR_DQS_SLAVE_RATIO  = DDR_CONFIG_PHY_DATA1_WR_DQS_SLAVE_RATIO;
      DDR_PHY->DATA[1].FIFO_WE_SLAVE_RATIO = DDR_CONFIG_PHY_DATA1_FIFO_WE_SLAVE_RATIO;
      DDR_PHY->DATA[1].WR_DATA_SLAVE_RATIO = DDR_CONFIG_PHY_DATA1_WR_DATA_SLAVE_RATIO;

      //! Set control registers
      CONTROL_MODULE->DDR_CMD0_IOCTRL      = DDR_CONFIG_CMD0_IOCTRL;
      CONTROL_MODULE->DDR_CMD1_IOCTRL      = DDR_CONFIG_CMD1_IOCTRL;
      CONTROL_MODULE->DDR_CMD2_IOCTRL      = DDR_CONFIG_CMD2_IOCTRL;
      CONTROL_MODULE->DDR_DATA0_IOCTRL     = DDR_CONFIG_DATA0_IOCTRL;
      CONTROL_MODULE->DDR_DATA1_IOCTRL     = DDR_CONFIG_DATA1_IOCTRL;
      CONTROL_MODULE->DDR_IO_CTRL         &= DDR_CONFIG_IOCTRL;
      CONTROL_MODULE->DDR_CKE_CTRL        |= DDR_CONFIG_CKE_CTRL;

      //! Set memory interface control registers
      EMIF0->DDR_PHY_CTRL_1                = DDR_CONFIG_PHY_CTRL_1;
      EMIF0->DDR_PHY_CTRL_1               |= DDR_CONFIG_DYN_PWRDN;
      EMIF0->DDR_PHY_CTRL_1_SHDW           = DDR_CONFIG_PHY_CTRL_1_SHDW;
      EMIF0->DDR_PHY_CTRL_1_SHDW          |= DDR_CONFIG_DYN_PWRDN_SHDW;
      EMIF0->DDR_PHY_CTRL_2                = DDR_CONFIG_PHY_CTRL_2;

      //! Set memory interface timing registers
      EMIF0->SDRAM_TIM_1                   = DDR_CONFIG_SD_TIM_1;
      EMIF0->SDRAM_TIM_1_SHDW              = DDR_CONFIG_SD_TIM_1_SHDW;
      EMIF0->SDRAM_TIM_2                   = DDR_CONFIG_SD_TIM_2;
      EMIF0->SDRAM_TIM_2_SHDW              = DDR_CONFIG_SD_TIM_2_SHDW;
      EMIF0->SDRAM_TIM_3                   = DDR_CONFIG_SD_TIM_3;
      EMIF0->SDRAM_TIM_3_SHDW              = DDR_CONFIG_SD_TIM_3_SHDW;

      EMIF0->SDRAM_CONFIG                  = DDR_CONFIG_SD_CONFIG_BEFORE;
      EMIF0->SDRAM_REF_CTRL                = DDR_CONFIG_SD_REF_CTRL_BEFORE;
      EMIF0->SDRAM_REF_CTRL_SHDW           = DDR_CONFIG_SD_REF_CTRL_SHDW_BEFORE;

      //! Wait for changes to take effect
      uint32_t ulDelay = DDR_CONFIG_DELAY_INTERVAL;
      while(ulDelay--);
      EMIF0->SDRAM_REF_CTRL                = DDR_CONFIG_SD_REF_CTRL_AFTER;
      EMIF0->SDRAM_REF_CTRL_SHDW           = DDR_CONFIG_SD_REF_CTRL_SHDW_AFTER;

      EMIF0->ZQ_CONFIG                     = DDR_CONFIG_ZQ;
      EMIF0->SDRAM_CONFIG                  = DDR_CONFIG_SD_CONFIG_AFTER;
      CONTROL_MODULE->CONTROL_EMIF_SDRAM_CONFIG = DDR_CONFIG_SD_CONFIG_AFTER;

      //! Switch to User Mode
      asm("    swi     #0;");

}

The defines look like this:

#define DDR_CONFIG_PHY_CMD0_SLAVE_RATIO            (0x00000080UL)
#define DDR_CONFIG_PHY_CMD0_SLAVE_FORCE            (0x00000000UL)
#define DDR_CONFIG_PHY_CMD0_SLAVE_DELAY            (0x00000000UL)
#define DDR_CONFIG_PHY_CMD0_LOCK_DIFF              (0x00000000UL)
#define DDR_CONFIG_PHY_CMD0_INVERT_CLKOUT          (0x00000000UL)

#define DDR_CONFIG_PHY_CMD1_SLAVE_RATIO            (0x00000080UL)
#define DDR_CONFIG_PHY_CMD1_SLAVE_FORCE            (0x00000000UL)
#define DDR_CONFIG_PHY_CMD1_SLAVE_DELAY            (0x00000000UL)
#define DDR_CONFIG_PHY_CMD1_LOCK_DIFF              (0x00000000UL)
#define DDR_CONFIG_PHY_CMD1_INVERT_CLKOUT          (0x00000000UL)

#define DDR_CONFIG_PHY_CMD2_SLAVE_RATIO            (0x00000080UL)
#define DDR_CONFIG_PHY_CMD2_SLAVE_FORCE            (0x00000000UL)
#define DDR_CONFIG_PHY_CMD2_SLAVE_DELAY            (0x00000000UL)
#define DDR_CONFIG_PHY_CMD2_LOCK_DIFF              (0x00000000UL)
#define DDR_CONFIG_PHY_CMD2_INVERT_CLKOUT          (0x00000000UL)

#define DDR_CONFIG_PHY_DATA0_RD_DQS_SLAVE_RATIO    (0x00000012UL)
#define DDR_CONFIG_PHY_DATA0_WR_DQS_SLAVE_RATIO    (0x00000000UL)
#define DDR_CONFIG_PHY_DATA0_FIFO_WE_SLAVE_RATIO   (0x00000080UL)
#define DDR_CONFIG_PHY_DATA0_WR_DATA_SLAVE_RATIO   (0x00000040UL)

#define DDR_CONFIG_PHY_DATA1_RD_DQS_SLAVE_RATIO    (0x00000012UL)
#define DDR_CONFIG_PHY_DATA1_WR_DQS_SLAVE_RATIO    (0x00000000UL)
#define DDR_CONFIG_PHY_DATA1_FIFO_WE_SLAVE_RATIO   (0x00000080UL)
#define DDR_CONFIG_PHY_DATA1_WR_DATA_SLAVE_RATIO   (0x00000040UL)

#define DDR_CONFIG_CMD0_IOCTRL                     (0x0000018BUL)
#define DDR_CONFIG_CMD1_IOCTRL                     (0x0000018BUL)
#define DDR_CONFIG_CMD2_IOCTRL                     (0x0000018BUL)
#define DDR_CONFIG_DATA0_IOCTRL                    (0x0000018BUL)
#define DDR_CONFIG_DATA1_IOCTRL                    (0x0000018BUL)
#define DDR_CONFIG_IOCTRL                          (0x0FFFFFFFUL)
#define DDR_CONFIG_CKE_CTRL                        (0x00000001UL)

#define DDR_CONFIG_PHY_CTRL_1                      (0x00000005UL)
#define DDR_CONFIG_DYN_PWRDN                       (0x00000000UL)
#define DDR_CONFIG_PHY_CTRL_1_SHDW                 (0x00000005UL)
#define DDR_CONFIG_DYN_PWRDN_SHDW                  (0x00000000UL)
#define DDR_CONFIG_PHY_CTRL_2                      (0x00000005UL)

#define DDR_CONFIG_SD_TIM_1                        (0x0666B3C9UL)
#define DDR_CONFIG_SD_TIM_1_SHDW                   (0x0666B3C9UL)
#define DDR_CONFIG_SD_TIM_2                        (0x243631CAUL)
#define DDR_CONFIG_SD_TIM_2_SHDW                   (0x243631CAUL)
#define DDR_CONFIG_SD_TIM_3                        (0x0000033FUL)
#define DDR_CONFIG_SD_TIM_3_SHDW                   (0x0000033FUL)

#define DDR_CONFIG_SD_CONFIG_BEFORE                (0x41805332UL)
#define DDR_CONFIG_SD_REF_CTRL_BEFORE              (0x00004650UL)
#define DDR_CONFIG_SD_REF_CTRL_SHDW_BEFORE         (0x00004650UL)

#define DDR_CONFIG_DELAY_INTERVAL                  (5000UL)

#define DDR_CONFIG_SD_CONFIG_AFTER                 (0x41805332UL)
#define DDR_CONFIG_SD_REF_CTRL_AFTER               (0x0000081AUL)
#define DDR_CONFIG_SD_REF_CTRL_SHDW_AFTER          (0x0000081AUL)

#define DDR_CONFIG_ZQ                              (0x00000000UL)

The controller runs through the whole process, but the DDR looks kind of random with every step I do in the debugger. I am monitoring 0x80000000. Writing to this area with the debugger also does not work. The status register shows that the PHY is not ready.

Can anybody advise?

Thanks in advance!

  • For baremetal application I suggest you take the Starterware code as a reference (http://processors.wiki.ti.com/index.php/StarterWare ).

  • I already did. The sequence of the initialization is similar to the bootloader of StarterWare.No luck with that.

  • Any other hints?
    Would some TI engineer be able to have a glance at the code above to maybe spot some beginner errors that might be obvious to you, but a mystery to me...

  • This is somewhat frustrating...

    I still have the same problem. But it is getting stranger all along. I took the code from TMDXICE3359.gel (version 1.3 as of Oct 25, 2012) and worked it into my C project's init. I use the methods ARM_OPP100_Config() and DDR2_EMIF_Config(). When I execute the GEL file the memory works fine. But when I run the *exact* same init sequence as part of my C project, it fails and I can see more/less random contents, when I have a look at 0x80000000 in the debugger. Seems to be some sort of timing or synchronization problem. But I can see no difference at all in the way the setting up is done.

    Is there something CCS does implicitly, when running a GEL script?

    Please advise...

  • *push*

    This issue is still not resolved...

    Can somebody help me?

  • Can you try verifying the following:

    Looking through the register settings, it does not appear that there are differences between the GEL file and what you are programming in your init routine.

    - Did you set the Clocks and PLL correctly?

    - Can you change the RD_DQS to 0x40 and see if it helps?

    - Are you making any access to the DDR before the DDR initialization in your setup?

    - What type of errors do you notice when you access the DDR address space? Can you confirm these are READ or WRITE errors?

    Regards, Siva

  • Hi Siva,

    thanks for the reply!

    - I setup the DDR PLL as follows:
          //! DDR DPLL configuration: 266 MHz
          // Bypass DDR DPLL
          CM_WKUP->CLKMODE_DPLL_DDR &= ~(0x03);
          CM_WKUP->CLKMODE_DPLL_DDR |=  (0x04);
          // Wait for transition
          while (CM_WKUP->IDLEST_DPLL_DDR != (1 << 8));
          // Set multiplier and divider
          CM_WKUP->CLKSEL_DPLL_DDR   = (266 << 8) | (ulDivider << 0);
          // CLKOUT divided by 1 => 266MHz
          CM_WKUP->DIV_M2_DPLL_DDR   = 1;
          // Lock DDR DPLL
          CM_WKUP->CLKMODE_DPLL_DDR |= (0x07);
          // Wait for transition
          while (CM_WKUP->IDLEST_DPLL_DDR != (1 << 0));

    ulDivider has a value of 23 with a 24MHz crystal mounted on the ICE.
    Other peripherals (UARTs, timers, GPIO) are already up and running. Is it safe to assume the other PLLs are correct?

    - The change of RD_DQS to 0x40 has no effect.

    - For once I have removed all the DDR access in the program. Just trying to initialize and writing to it with the debugger.

    - The behavior I see right now is that at every access the contents seem to change at random. I can't say if this is during READ or WRITE. When I start the debugger and open the Memory Browser tab on address 0x8000 0000, I see bytes and bytes of uninitalized memory. So I type 12345678 at any address. As soon as I hit enter, the whole memory contents change to something else. Still looking like uninitialized garbage. To me it seems to be some sort of timing problem or the PHY still is not correctly initialized.


    I will be looking through the configuration values and init sequence once again.

    Best regards
    Tobias

  • Finally, I had some kind of a breakthrough!

    I went through the GEL initialization and came across the fact, that obviously some of the registers weren't needed to be set. In my code I still set them with default values for completeness. Generally to have them around in case I need to configure them in some kind of later project with maybe a different RAM attached to it. I would never have thought doing so would break something. But it obviously did. I took all unneeded registers out of the setup and just programmed the necessary ones, and it worked! Also I let go of the two staged SDRAM_CONTROL and SDRAM_REF_CTRL setup, changing the settings after a delay to the final values. I just took the final values directly.

    Here is the revised and stripped down code that finally works:

        {
          //! Switch to System Mode
          asm("    swi     #1;");

          //! Enable EMIF
          CM_PER->EMIF_CLKCTRL                 = 2;
          //! Poll for functional peripheral
          while (CM_PER->EMIF_CLKCTRL != 2);

          //! Enable VTP
          CONTROL_MODULE->VTP_CTRL             = 0;
          CONTROL_MODULE->VTP_CTRL             = 6;
          CONTROL_MODULE->VTP_CTRL            |=  (1 << 6);
          CONTROL_MODULE->VTP_CTRL            &= ~(1 << 0);
          CONTROL_MODULE->VTP_CTRL            |=  (1 << 0);
          //! Poll for VTP ready
          while (!(CONTROL_MODULE->VTP_CTRL & (1 << 5)));

          //! Configure DDR Phy command macros
          DDR_PHY->CMD[0].SLAVE_RATIO          = DDR_CONFIG_PHY_CMD0_SLAVE_RATIO;
          DDR_PHY->CMD[0].INVERT_CLKOUT        = DDR_CONFIG_PHY_CMD0_INVERT_CLKOUT;

          DDR_PHY->CMD[1].SLAVE_RATIO          = DDR_CONFIG_PHY_CMD1_SLAVE_RATIO;
          DDR_PHY->CMD[1].INVERT_CLKOUT        = DDR_CONFIG_PHY_CMD1_INVERT_CLKOUT;

          DDR_PHY->CMD[2].SLAVE_RATIO          = DDR_CONFIG_PHY_CMD2_SLAVE_RATIO;
          DDR_PHY->CMD[2].INVERT_CLKOUT        = DDR_CONFIG_PHY_CMD2_INVERT_CLKOUT;

          //! Configure DDR Phy data macros
          DDR_PHY->DATA[0].RD_DQS_SLAVE_RATIO[0]  = DDR_CONFIG_PHY_DATA0_RD_DQS_SLAVE_RATIO;
          DDR_PHY->DATA[0].WR_DQS_SLAVE_RATIO[0]  = DDR_CONFIG_PHY_DATA0_WR_DQS_SLAVE_RATIO;
          DDR_PHY->DATA[0].WRLVL_INIT_RATIO[0]    = DDR_CONFIG_PHY_DATA0_WRLVL_INIT_RATIO;
          DDR_PHY->DATA[0].GATELVL_INIT_RATIO[0]  = DDR_CONFIG_PHY_DATA0_GATELVL_INIT_RATIO;
          DDR_PHY->DATA[0].FIFO_WE_SLAVE_RATIO[0] = DDR_CONFIG_PHY_DATA0_FIFO_WE_SLAVE_RATIO;
          DDR_PHY->DATA[0].WR_DATA_SLAVE_RATIO[0] = DDR_CONFIG_PHY_DATA0_WR_DATA_SLAVE_RATIO;
          DDR_PHY->DATA[0].DLL_LOCK_DIFF          = DDR_CONFIG_PHY_DATA0_DLL_LOCK_DIFF;

          DDR_PHY->DATA[1].RD_DQS_SLAVE_RATIO[0]  = DDR_CONFIG_PHY_DATA1_RD_DQS_SLAVE_RATIO;
          DDR_PHY->DATA[1].WR_DQS_SLAVE_RATIO[0]  = DDR_CONFIG_PHY_DATA1_WR_DQS_SLAVE_RATIO;
          DDR_PHY->DATA[1].WRLVL_INIT_RATIO[0]    = DDR_CONFIG_PHY_DATA1_WRLVL_INIT_RATIO;
          DDR_PHY->DATA[1].GATELVL_INIT_RATIO[0]  = DDR_CONFIG_PHY_DATA1_GATELVL_INIT_RATIO;
          DDR_PHY->DATA[1].FIFO_WE_SLAVE_RATIO[0] = DDR_CONFIG_PHY_DATA1_FIFO_WE_SLAVE_RATIO;
          DDR_PHY->DATA[1].WR_DATA_SLAVE_RATIO[0] = DDR_CONFIG_PHY_DATA1_WR_DATA_SLAVE_RATIO;
          DDR_PHY->DATA[1].DLL_LOCK_DIFF          = DDR_CONFIG_PHY_DATA1_DLL_LOCK_DIFF;

          //! Set control registers
          CONTROL_MODULE->DDR_CMD0_IOCTRL      = DDR_CONFIG_CMD_IOCTRL;
          CONTROL_MODULE->DDR_CMD1_IOCTRL      = DDR_CONFIG_CMD_IOCTRL;
          CONTROL_MODULE->DDR_CMD2_IOCTRL      = DDR_CONFIG_CMD_IOCTRL;
          CONTROL_MODULE->DDR_DATA0_IOCTRL     = DDR_CONFIG_DATA_IOCTRL;
          CONTROL_MODULE->DDR_DATA1_IOCTRL     = DDR_CONFIG_DATA_IOCTRL;
          CONTROL_MODULE->DDR_IO_CTRL         &= DDR_CONFIG_IOCTRL;
          CONTROL_MODULE->DDR_CKE_CTRL        |= DDR_CONFIG_CKE_CTRL;

          //! Set memory interface control registers
          EMIF0->DDR_PHY_CTRL_1                = DDR_CONFIG_PHY_CTRL_1;
          EMIF0->DDR_PHY_CTRL_1_SHDW           = DDR_CONFIG_PHY_CTRL_1;
          EMIF0->DDR_PHY_CTRL_2                = DDR_CONFIG_PHY_CTRL_2;

          //! Set memory interface timing registers
          EMIF0->SDRAM_TIM_1                   = DDR_CONFIG_SD_TIM_1;
          EMIF0->SDRAM_TIM_1_SHDW              = DDR_CONFIG_SD_TIM_1;
          EMIF0->SDRAM_TIM_2                   = DDR_CONFIG_SD_TIM_2;
          EMIF0->SDRAM_TIM_2_SHDW              = DDR_CONFIG_SD_TIM_2;
          EMIF0->SDRAM_TIM_3                   = DDR_CONFIG_SD_TIM_3;
          EMIF0->SDRAM_TIM_3_SHDW              = DDR_CONFIG_SD_TIM_3;

          EMIF0->SDRAM_REF_CTRL                = DDR_CONFIG_SD_REF_CTRL;
          EMIF0->SDRAM_REF_CTRL_SHDW           = DDR_CONFIG_SD_REF_CTRL;

          EMIF0->SDRAM_CONFIG                  = DDR_CONFIG_SD_CONFIG;

          //! Poll for DDR Phy ready indicator
          while(!(EMIF0->STATUS & (1 << 2)));

          //! Switch to User Mode
          asm("    swi     #0;");
        }

    By the way: I also took out the activation of the clock for EMIF0_FW. Earlier TRMs call this EMIF firewall but do not really elaborate. The current TRM does not even mention it at all. This was also something, I had to not do, in order for the RAM to work. What is it?

  • One more thing: The #defines from post #1 are valid!