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.

debugging SDRAM interface with TMS320C6746

Other Parts Discussed in Thread: TMS320C6746, OMAP-L138

Hello,

We are working with target hardware that uses a TMS320C6746, mated with SDRAM.  The SDRAM memory architecture is essentially the same as that used with the OMAP-L138, with the MT46H32M16LF part.  In the process of debugging this memory design, we’ve come across the need to monitor the DDR lines connected to the SDRAM part, for both data and addressing.  However, because of the BGA and board layering, there is no way to connect debug wires to those pins, for monitoring.  Are there any alternative methods for debugging such a memory interface, and looking at those lines?  Ideally, I’d be able to control the DDR pins via Code Composer Studio, as IO or simple reads and writes, and watch their state on an oscilloscope.

Regards,

Robert

  • Robert,

    Perhaps you can explain more about exactly what you are trying to do.

    To me, 'monitoring' implies that the device is running at normal speed doing normal things and you want to watch that while it is happening. But that does not fit with the idea of CCS controlling them as IO.

    An interposer board comes to mind as the only way to get to the signals.

    CCS can easily do a simple read or write, as can the DSP code.

    Depending on what your issue is that you are trying to debug, we may have different recommendations.

    Regards,
    RandyP
  • Randy,

    Thanks for the reply.  The SDRAM, and associated interface, for our target has never been tested before.  So I wrote some basic routines for initialization, and to do simply reads and writes to the SDRAM, from the C6746.  But I'm getting unexplained results, so wanted to monitor the address and data lines, on a scope or logic analyzer.  Then I could see if the correct information is going out over the address and data lines.  Or if not, maybe it's a software/timing issue.  But the address and data lines are not available, for oscilloscope monitoring or logic analyzer, because they are buried in multiple board layers of the target hardware, plus the DSP and SDRAM are BGA, so the pins are not accessible there as well.

    The IO idea was to see if CCS could set those address and data lines as IO, and just change the state of them in CCS, and see if the actual signal coming out of the DSP changed accordingly.  It would be the same as doing simple reads or writes, but on a individual address or data line basis, and at a slower/controlled rate.  

    Maybe the first thing to do, though, is show you the results I'm getting now.  Maybe it can be resolved without monitoring of the hardware lines.  I've attached a picture that shows the basic memory write that I'm doing.  I'm writing values 0 though 9 to the first 10 addresses of the SDRAM.  But, as you can see in the memory window at 0xC0000000, the first location is not 0, as expected, and everything is offset by 1 location.  Would you have any insight into what could be causing this?

    Regards,

    Robert

  • This looks like a DQS timing issue. On this particular device the timing is determined by the routing of the DQGATE signals. Can you please share the length of your CK net as well as your DQS0 and DQS1 nets?

    There should be a trace routed from DQGATE0 to DQGATE1 that is equal to the sum of the length of the CK net plus the average length of the DQS0 and DQS1 nets. How long is that trace on your board?
  • Hi Brad,

    I've referred this to our hardware design engineer, and we'll get back to you.

    Thanks,
    Robert
  • Brad,

    Here are the answers to your question, with a follow-up question:

    G72= length CLKP 19.56615mm
    G75= length CLKN 20.42372mm
    G79= length DQS0 17.10168mm
    G82= length DQS1 17.56169mm

    DQGATE length Was calculated:
    AVERAGE(G72,G75)+AVERAGE(G79,G82)= 37.32662mm

    Should have been calculated?
    G72+G75+AVERAGE(G79,G82)= 57.321555mm

    Please advise,
    Robert
  • Robert56682 said:
    DQGATE length Was calculated:
    AVERAGE(G72,G75)+AVERAGE(G79,G82)= 37.32662mm

    That's correct for differential clock lines.

    Please post the values of the registers SDCR and DRPYC1R.

  • Good to hear. The requested registers:

    SDCR = 0x0A034622

    DRPYC1R = 0x000000C4
  • Robert56682 said:
    SDCR = 0x0A034622

    I don't think it relates to the specific issue you're debugging, but the above configuration has DDRTERM[1:0] = 10b (ODT enabled), but these must be forced to 00b while BOOTUNLOCK=1 to disable termination.

    Robert56682 said:
    DRPYC1R = 0x000000C4

    Try 0x000000C5.

  • The 0x000000C5 seemed to fix it, at least for my simple SRDAM write. I'll move onto more rigorous memory tests now, and see how things hold up.

    By the way, setting DDRTERM[1:0] to 00b did not work. If I did that, the SDRAM writes did not work at all. I had to leave those bits as 10b. Here's the code I had used to do it, which appeared to work, as those bits were cleared in the register after.

    // set BOOTUNLOCK
    DDR->SDCR |= 0x00800000;

    // clear DDR2TERM0 and DDR2TERM1, while setting BOOTUNLOCK back to 0 (needed at the same time)
    //--------------------------------------------------------------------------------------------

    uint32_t ui_32 = DDR->SDCR;
    ui_32 &= 0xf75fffff;
    DDR->SDCR = ui_32;


    Thanks,
    Robert
  • Robert56682 said:
    The 0x000000C5 seemed to fix it, at least for my simple SRDAM write. I'll move onto more rigorous memory tests now, and see how things hold up.

    Great!  By the way, I added this type of issue onto this wiki page since I've seen this come up before:

    http://processors.wiki.ti.com/index.php/Common_DDR_Issues#First_access_of_a_burst_is_garbage

    Robert56682 said:
    By the way, setting DDRTERM[1:0] to 00b did not work. If I did that, the SDRAM writes did not work at all. I had to leave those bits as 10b. Here's the code I had used to do it, which appeared to work, as those bits were cleared in the register after.

    // set BOOTUNLOCK
    DDR->SDCR |= 0x00800000;

    // clear DDR2TERM0 and DDR2TERM1, while setting BOOTUNLOCK back to 0 (needed at the same time)
    //--------------------------------------------------------------------------------------------

    uint32_t ui_32 = DDR->SDCR;
    ui_32 &= 0xf75fffff;
    DDR->SDCR = ui_32;

    On the DDR itself, did you tie the ODT signal to ground?  You may still have an issue that needs to be addressed.  You should not be using ODT on this device.

  • Brad, This was the reply back from our hardware engineer, re: ODT

    I do not believe the ram technology we are using uses ODT. If it does there is no external configuration. The part we are using is 166Mhz Clock Rate LPDDR; Micron MT46H32M16LFBF-6 IT:C

    Thanks,
    Robert
  • Oops! Fair point... Sorry, it's been a while since I've dealt with LPDDR. You are right that LPDDR does not even support ODT. So along those lines I would have expected those bits to be "don't care".
  • No problem, thanks again.
  • Hi Brad (or anyone),

    We could use a little more help on this one. Previously, I had been doing just writes, followed by reads, and it worked well, after your suggested change of C4 to C5 for DRPYC1R.

    Now, I've run into a problem where a read before a write throws off the location of the values being written into memory. Almost like the read causes the address lines to be wrong for the follow-up write. Here is a simple test routine I wrote,. DDR_MEM_BASE is 0xC0000000. The write portion at the end the routine writes power of 2 values to successive locations. If I un-comment the read before it, the memory window at 0xC0000000 shows 4, 8, 1, 2, etc ... instead of 1, 2, 4, 8. But if I leave that read commented, I'll get the correct 1, 2, 4, 8 ordering in the memory.

    Any clues or suggestions?

    Robert

    volatile uint16_t
    *ptr = (uint16_t *)DDR_MEM_BASE;

    uint64_t
    idx = 0U;

    uint16_t
    w_vl;

    uint16_t
    r_vl;

    // this read, before write, causes the write to be off: 4, 8, 1, 2 .. instead of 1, 2, 4, 8
    //r_vl = *ptr;

    for ( idx = 0U; idx < 10U; idx++ )
    {
    w_vl = ( (uint16_t)1U << (uint16_t)idx );

    *( ptr + idx ) = w_vl;
    }
  • Robert,
    Below is a suggested test to see if it gleans any information based on the results.

    Test I would suggest would be:
    1. block write of 4096 bytes- write power of two values is fine
    2. Block read of 4096 bytes
    3. Compare the two (this probably works- the significance is just to prove the timing is generally okay)

    Then, do the same thing, but have the block write part write say 16 bytes, then read 1 back (just pick any word, picking the first of the ’next’ block to write probably makes the loop easiest; we’re not looking at the read response at this point so it shouldn’t matter), write the next 16, read 1 back, and iterate through the 4096 again, and do the compare; then send us results of the two tests.
  • Brandon,

    Thanks for the reply.

    For the first test, the read was the same as write, as expected. Although sometimes when stopping the emulator, I sometimes see a value in the first two 16-bit words of the CCS memory window that wasn't written (like 0xFFFF), even though the software read of that value was the expected/written value. Often then, if I restart and run again, that goes away, and the actual written value ends up in those 2 words in the memory window. I've just chalked it up as an anomaly of emulation or cache, and that the actual write succeeded.

    Second test, I wrote 16 words (16-bit), with the values being increasing powers of 2. Then did a write of the next word of the next block (unwritten at that point). I repeated this for 4096 bytes. When reviewing the memory window, or via memory dump, the words all appeared as expected. There were rows of repeating 16 'power-of-2' values, i.e. 1, 2, 4, 8 .... 8000 for each row of 16 words (16-bit).

    Robert
  • Please provide:

    1. A dump or screenshot of the EMIF registers.
    2. Your DDR configuration spreadsheet.
    3. The speed at which the bus is operating.

  • 1) Did you mean DDR or EMIF?  The registers window is not complete for the DDR in the version of CCS that I have, so I attached a screen shot of the memory range that covers them all, beginning at 0xB0000000.  I've also attached a screenshot of the EMIFa0DSP registers, if that was the interest.

    2) To be honest, I started that, but it's pretty gruesome (for an SDRAM novice), so it was not completed.  But the SDRAM part we're using, MT46H32M16LFBF-6, is the same as the OMAP138 part, so I've used the settings found in the OMAP138 gel file, as attached.

    3) We're running the core at 300 Mhz, and I've targeted 132 Mhz for the DDR.  Pretty much followed the gel file again, for PLL settings, using these pll configuration settings:

      // core = 300 MHz

       r_val = config_pll0( 0, 24, 1, 0, 1, 11, 5 );

       // ddr = 132 MHz

       r_val |= config_pll1( 21, 1, 0, 1, 2);

    OMAPL138_ARM.gel

  • First, very minor nitpick. Your SDRCR configuration (refresh rate) should be 0x405 for 132 MHz operation. Your intervals are about 15ns further apart then they're supposed to be. I don't expect this will make any difference...

    Second, can you have a hardware engineer confirm with an oscilloscope that the LPDDR bus frequency is 132 MHz as expected?

    Third, can you perform the following test:
    A. Update DDR frequency to 100 MHz and confirm on scope.
    B. SDRCR = 0x307
    C. [No action] I was going to have you also update SDTIMR2[T_RASMAX], but it looks like you have an already conservative value so it will still be within spec even at 100 MHz. Otherwise you would have needed to reduce this value.

    By keeping all the parameters the same at a lower clock frequency we'll be adding more margin. If that "fixes" the issue we could potentially run some further experiments where we modify individual timings to understand precisely which timing is causing issues, but this is a good "quick and dirty" test to try and get things operational.
  • Brad,

    While preparing for doing the scope reads, and further investigation, I found something: in the GEL file and other similar code I've seen, after setting EMIF DDR registers, a "syncReset" is performed to the EMIF clock. What I've noticed is that is not completing properly. That may have been the case all along in my situation. I've since scrubbed that portion of the code, and confirmed what appears to be the proper set of steps, but the syncReset is still not completing. That is evidenced by the PTSTAT never going from 1 to 0, after setting up the syncReset state in the MDCTL register, and initiating it in PTCMD. Eventually my while loop times-out and control moves on (not noticed previously). I'm pretty sure I'm following the right sequence for doing the syncReset ... it's not that different than enabling a module, and I pretty much duplicated the PSC1_LPSC_SyncReset() function in the gel file I attached last time, and the instructions in "Power and Sleep Controller" manual, page 120 of SPRUGM7D - April 2010. I guess that is maybe a bit old doc, but I would guess that procedure didn't change.

    I think it would be best to find out why the syncReset is not completing, before moving on ... since I'm not sure how important that is to the register configurations, done before it, being activated.

    Please advise,
    Robert
  • Your gel file you posted earlier has the following:

       // Let float -> integer truncate handle RR round-down; Safer to round down for refresh rate

       EMIFDDR_SDRCR   = (0x1                                  << 31)  |  // LPMODEN (Required for LPSC SyncReset/Enable)

                         (0x1                                  << 30)  |  // MCLKSTOPEN (Required for LPSC SyncReset/Enable)

                         (0x0                                  << 24)  |  // Reserved

                         (0x0                                  << 23)  |  // SR_PD

                         (0x0                                  << 16)  |  // Reserved

                         (((unsigned int) (7.8125 * freq))     << 0);     // RR

    Specifically, it looks like it is setting bits 31:30 of SDRCR.  However, I double checked your screenshot from earlier and I do not see those bits set in your screenshot.  Can you look more closely into that?  I have bumped into this exact issue previously and it related to those two bits:

    https://e2e.ti.com/support/dsp/omap_applications_processors/f/42/t/51874

  • I updated the initialization, so that LPMODEN and MCLKSTOPEN are set to 1. I had that initially, but overwrote it with the 0x405 from previous responses … not realizing that 0xC00000405 is needed prior to the syncReset. After it, the 0xC0000000 is removed, to disable self-refresh. And now syncReset is passing, but still the same mix-up on the written words, if proceeded by a read. 4, 8, 1, 2 instead of 1, 2, 4, 8.

    I’ll continue on to the previously requested steps.

    Thanks,
    Robert
  • We confirmed that the DDR bus is 132 Mhz.  But initially, when trying to change it to 100 Mhz, via the SDRAM configuration registers, it remained at 132 Mhz.  Eventually, it was discovered that is because there is also the PLL 1 settings for DDR.  Isn't the DDR PLL the actual driver of the bus frequency?  When I change the DDR PLL to 100 Mhz ... actually 102 Mhz, to follow the gel file (must have been reason they went 102 instead of 100), the bus is then confirmed as 102 Mhz.  The register settings are then as attached.  However, the problem with memory write disorder, after a read, remains.  But if I do a breakpoint on that read-before-the-writes, then hit go, the writes are in the correct order (versus disorder when just free run of everything).

    Beyond that remaining problem, to be honest, this exercise has left confusion about the whole EMIF, DDR, PLL arrangements.  Questions include: Is it the EMIF or the DDR bus that we're dealing with ... or are they one in the same?  My search through the associated documentation did not help clear it up.  If the DDR PLL is driving the bus speed, why are configuring the registers?

  • Robert56682 said:
    Questions include: Is it the EMIF or the DDR bus that we're dealing with ... or are they one in the same?

    I'm probably confusing things a bit on this topic.  The "DDR2/mDDR Memory Controller" (i.e. Chapter 15 of the TRM) on this device is using TI IP that is normally called the "EMIF" in every other device sold by TI (i.e. that's my excuse for using the wrong term here).  If you catch me saying "EMIF" you should just mentally translate to "DDR2/mDDR Memory Controller".  I can see why this is confusing because the OMAP-L138 also as a peripheral called "EMIFA" (Chapter 20 of the TRM).  To be clear, EMIFA has absolutely nothing to do with this conversation.

    Robert56682 said:
    But initially, when trying to change it to 100 Mhz, via the SDRAM configuration registers, it remained at 132 Mhz

    The DDR frequency comes from one place, PLLC1.  The timings specified in the DDR controller are generally in units of "clock cycles", so the clock frequency itself is specified by the DPLL and the number of clocks for each parameter are programmed in the DDR controller.  So if you program PLLC1 to 204 MHz you'll end up with a 102 MHz clock on the actual DDR bus.  Similarly, the refresh interval is supposed to be 7.8us, but it's given in units of tCK.  So for a 102 MHz bus speed this number needs to be smaller than at 150 MHz (because tCK grows as the frequency shrinks).

    Robert56682 said:
    When I change the DDR PLL to 100 Mhz ... actually 102 Mhz, to follow the gel file (must have been reason they went 102 instead of 100), the bus is then confirmed as 102 Mhz.  The register settings are then as attached.  However, the problem with memory write disorder, after a read, remains.

    This is surprising.  You really should have a lot of margin here.  I recommend having a hardware guy look through your board very carefully.  Perhaps you have insufficient voltage decoupling or some other more serious hardware issue.

  • Good news.  We tried other targets, and the SDRAM write worked for them, with the preceding read … all the way up to 132 Mhz.  It's just the primary one I’ve been working with, and that we've been debugging, that doesn't work.  The only real obvious difference between that board, and the working ones, is that it has the correction pointed out in Advisory 2.3.18 of SPRZ304H.  But that seems unrelated.

    Thanks for the help.  Even though it appears board related, things were learned, and needed technique/firmware changes made, as result of this.

    I’ll continue on with the SDRAM firmware suite that has driven all this, and hopefully no further issues arise.

    Robert