Sdram write issue

cancel
Showing results for 
Show  only  | Search instead for 
Did you mean: 

Sdram write issue

1,256 Views
lpcware
NXP Employee
NXP Employee
Content originally posted in LPCWare by Scieslik on Sun Apr 15 16:58:52 MST 2012
I am trying to connect some external SDRAM to the LPC1787 to use as a framebuffer source for an LCD screen.

I am using this SDRAM chip: IC42S16100E
Datasheet: http://www.issi.com/pdf/42S16100E.pdf

I have connected all the pins in accordance with the LPC1787 datasheet as follows:
<code>
LPC1787    |     IC42S16100E
----------------------------
A0         |     A0
A1         |     A1
A2         |     A2
A3         |     A3
A4         |     A4
A5         |     A5
A6         |     A6
A7         |     A7
A8         |     A8
A9         |     A9
A10        |     A10
A13 (Bank) |     A11 (Bank)
D0         |     D0
D1         |     D1
D2         |     D2
D3         |     D3
D4         |     D4
D5         |     D5
D6         |     D6
D7         |     D7
D8         |     D8
D9         |     D9
D10        |     D10
D11        |     D11
D12        |     D12
D13        |     D13
D14        |     D14
D15        |     D15
DQM0       |     UDQM
DQM1       |     LDQM
WE         |     WE
CAS        |     CAS
RAS        |     RAS
DYCS0      |     CS
CKE0       |     CKE
CLK0       |     CLK
</code>


Currently, I'm able to write 8 memory locations (32-bit format) consecutively with the project working as expected. When I try to clear the entire SDRAM location, the locations are just randomized.

I have tested as much hardware as I can, including the clock, clock enable, some data pins/address pins just to be sure that they are all functioning, and everything seems to be working. However, I can't clear the full SDRAM location.

Here is my initialization code for the SDRAM:

First the macros:
<code>
#define SDRAM_BASE_ADDR    (0xA0000000)    /* SDRAM Bank 0  */
#define SDRAM_SIZE         (0x200000)      /* 16Mbit Length */
</code>

Now the initialization:

<code>
void vd_g_IoSdramInitTask(void)
{
    uint32_t Temp;
    uint32_t u4_t_idx;
    uint32_t u4_t_tmp;
    volatile uint32_t *short_wr_ptr;

    /* Initialize EMC */
    EMC_Init();

    //Configure memory layout, but MUST DISABLE BUFFERs during configuration
    LPC_EMC->DynamicConfig0 = 0x00000080; /* 16Mbit, 1Mx16, 2 banks, row=11, column=8 */

    /*Configure timing for  ISSI SDRAM IC42S16100E */

    //Timing for 80MHz Bus
    LPC_EMC->DynamicRasCas0    = 0x00000303;     /* 3 RAS, 3 CAS latency */
    LPC_EMC->DynamicReadConfig = 0x00000001;     /* Command delayed strategy, using EMCCLKDELAY */
    LPC_EMC->DynamicRP         = 0x00000002;     /* ( n + 1 ) -> 3 clock cycles */
    LPC_EMC->DynamicRAS        = 0x00000005;     /* ( n + 1 ) -> 6 clock cycles */
    LPC_EMC->DynamicSREX       = 0x00000000;     /* ( n + 1 ) -> 1 clock cycles */
    LPC_EMC->DynamicAPR        = 0x00000004;     /* ( n + 1 ) -> 5 clock cycles */
    LPC_EMC->DynamicDAL        = 0x00000005;     /* ( n ) -> 5 clock cycles */
    LPC_EMC->DynamicWR         = 0x00000003;     /* ( n + 1 ) -> 4 clock cycles */
    LPC_EMC->DynamicRC         = 0x00000008;     /* ( n + 1 ) -> 9 clock cycles */
    LPC_EMC->DynamicRFC        = 0x00000008;     /* ( n + 1 ) -> 9 clock cycles */
    LPC_EMC->DynamicXSR        = 0x00000000;     /* ( n + 1 ) -> 1 clock cycles */
    LPC_EMC->DynamicRRD        = 0x00000001;     /* ( n + 1 ) -> 2 clock cycles */
    LPC_EMC->DynamicMRD        = 0x00000001;     /* ( n + 1 ) -> 2 clock cycles */


    for(u4_t_idx = (U4)0; u4_t_idx < 0x80; u4_t_idx++);    /* Wait 128 clock cycles */


    LPC_EMC->DynamicControl    = 0x00000103;     /* Issue PALL command */
    LPC_EMC->DynamicRefresh    = 0x00000002;     /* ( n * 16 ) -> 16 clock cycles */


    for(u4_t_idx = (U4)0; u4_t_idx < (U4)0x80; u4_t_idx++);        /* wait 128 AHB clock cycles */


    //Timing for 80MHz Bus
    LPC_EMC->DynamicRefresh    = 0x0000004E;         /* ( n * 16 ) -> 1248 clock cycles -> 15.6uS at 80MHz <= 15.625uS ( 32ms / 2048 row ) */


    for(u4_t_idx = (U4)0; u4_t_idx < (U4)0x00000080; u4_t_idx++);    /* wait 128 AHB clock cycles */

    LPC_EMC->DynamicControl    = 0x00000083;                         /* Issue MODE command */
    Temp = *((volatile uint32_t *)(SDRAM_BASE_ADDR | 0xCC00));       /* Set the SDRAM Mode - 3 CAS, 8 Burst Length */


    for(u4_t_idx = (U4)0; u4_t_idx < (U4)0x00000080; u4_t_idx++);    /* wait 128 AHB clock cycles */


    //Timing for 80MHZ Bus
    LPC_EMC->DynamicControl    = 0x00000003;        /* Issue NORMAL command */

    //[re]enable buffers
    LPC_EMC->DynamicConfig0 |= 0x00080000;          /* 16Mbit, 1Mx16, 2 banks, row=11, column=8 */

    short_wr_ptr = (uint32_t *)SDRAM_BASE_ADDR;

    /* Memory Write Test */
    for (u4_t_idx = u4_t_tmp; u4_t_idx < SDRAM_SIZE/4; u4_t_idx++ )
    {
        *short_wr_ptr++ = (U4)0x0000AAAA;
        *short_wr_ptr++ = (U4)0x00005555;
    }
}
</code>

I have tried to write using "u4_t_idx < 8" , which managed to work. However, anything beyond that will not write to the SDRAM. In previous tests, the memory map looked like this:

(u4_t_idx < 8)
0xA0000000 :  AA AA 00 00 55 55 00 00 AA AA 00 00 55 55 00 00 AA AA 00 00 55 55 00 00 AA AA 00 00 55 55 00 00

(u4_t_idx < SDRAM_SIZE/4)
0xA0000000 :  CC 44 CC 44


So the memory is being set to random numbers when I try to write beyond 8 32-bit locations. Any suggestions to help fix this issue would be greatly appreciated.

Thanks in advance!
Labels (1)
0 Kudos
14 Replies

1,178 Views
lpcware
NXP Employee
NXP Employee
Content originally posted in LPCWare by Scieslik on Fri Apr 20 16:21:42 MST 2012
This is a great catch. I didn't realize that the driver software was doing this. It should definitely be brought to NXP's attention.. However, I managed to figure out my problem (after realizing that this wasn't it).

So, the original driver code looked like this:

<code>

void EMC_Init(void)
{
uint8_t i;

/* Enable clock for EMC */
//CLKPWR_ConfigPPWR(CLKPWR_PCONP_PCEMC, ENABLE);
//LPC_EMC->Control = 0x00000001;
// LPC_EMC->Config  = 0x00000000;

  LPC_SC->PCONP   |= 0x00000800;
  LPC_SC->EMCDLYCTL   = 0x00001010;
  LPC_EMC->Control = 0x00000001;
  LPC_EMC->Config  = 0x00000000;

  /* Pin configuration:
   * P2.14 - /EMC_CS2
   * P2.15 - /EMC_CS3
   *
   * P2.16 - /EMC_CAS
   * P2.17 - /EMC_RAS
   * P2.18 - EMC_CLK[0]
   * P2.19 - EMC_CLK[1]
   *
   * P2.20 - EMC_DYCS0
   * P2.21 - EMC_DYCS1
   * P2.22 - EMC_DYCS2
   * P2.23 - EMC_DYCS3
   *
   * P2.24 - EMC_CKE0
   * P2.25 - EMC_CKE1
   * P2.26 - EMC_CKE2
   * P2.27 - EMC_CKE3
   *
   * P2.28 - EMC_DQM0
   * P2.29 - EMC_DQM1
   * P2.30 - EMC_DQM2
   * P2.31 - EMC_DQM3
   *
   * P3.0-P3.31 - EMC_D[0-31]
   * P4.0-P4.23 - EMC_A[0-23]
   *
   * P4.24 - /EMC_OE
   * P4.25 - /EMC_WE
   *
   * P4.30 - /EMC_CS0
   * P4.31 - /EMC_CS1
   */
PINSEL_ConfigPin(2,14,1);
PINSEL_ConfigPin(2,15,1);
PINSEL_ConfigPin(2,16,1);
PINSEL_ConfigPin(2,17,1);
PINSEL_ConfigPin(2,18,1);
PINSEL_ConfigPin(2,19,1);
PINSEL_ConfigPin(2,20,1);
PINSEL_ConfigPin(2,21,1);
   PINSEL_ConfigPin(2,22,1);
PINSEL_ConfigPin(2,23,1);
PINSEL_ConfigPin(2,24,1);
PINSEL_ConfigPin(2,25,1);
PINSEL_ConfigPin(2,26,1);
PINSEL_ConfigPin(2,27,1);
PINSEL_ConfigPin(2,28,1);
PINSEL_ConfigPin(2,29,1);
PINSEL_ConfigPin(2,30,1);
PINSEL_ConfigPin(2,31,1);

for(i = 0; i < 32; i++)
{
PINSEL_ConfigPin(3,i,1);
PINSEL_ConfigPin(4,i,1);
}
}

</code>


I obviously didn't need all of these pins to access one EMC bank, especially when it was only a 16-bit SDRAM chip. So I altered the code to what I showed above. Turns out, when I was removing the excess address pins, I'm slightly embarrassed by this, but I forgot to re-enable the WE pin.

I appreciate all of the help, and you guys have definitely given me a better understanding of what's going on in the EMC controller. I'll definitely fix the PINSEL_ConfigPin function to perform properly... (seems like it should just be "*pPIN &= ~(0x00000007);//Clear function bits"

Again, you guys have been a great help to me in getting a better understanding of how this controller works. Thanks so much.
0 Kudos

1,178 Views
lpcware
NXP Employee
NXP Employee
Content originally posted in LPCWare by Dave on Fri Apr 20 09:54:01 MST 2012
I got to thinking about this pin configuration topic, and it occurred to me that I was relying on a macro somebody else wrote rather than setting the pin up myself.  ( I setup the pins manually in my own code, but I was using the PINSEL macros for testing things from this forum thread).

I took a look in the debugger, and found that the PINSEL_ConfigPin() function screws things up for you...

The default reset mode for a data bus pin is FUNC=0X00, MODE=0X02, HYSTERESIS=ENABLED, INVERT=DISABLED, and SLEW=STANDARD...

When you call PINSEL_ConfigPin() with a new function value, it resets the MODE to INACTIVE (no pull-down/pull-up resistor) and it turns off the HYSTERESIS...

Try replacing your for(...) loop with individual commands like this:

   LPC_IOCON->P3_0 |= 1;               // D0 @ P3.0                                            
   LPC_IOCON->P3_1 |= 1;               // D1 @ P3.1                                            
   LPC_IOCON->P3_2 |= 1;               // D2 @ P3.2                                            
   LPC_IOCON->P3_3 |= 1;               // D3 @ P3.3                                            
   LPC_IOCON->P3_4 |= 1;               // D4 @ P3.4                                            
   etc...

Do the same for all of the pins, including the address lines...

I'll bet it works now...  :-)

0 Kudos

1,178 Views
lpcware
NXP Employee
NXP Employee
Content originally posted in LPCWare by Dave on Fri Apr 20 09:18:50 MST 2012
I'm pretty sure the pin's default mode is with a pull-up enabled...
Also, I'm running my EMC at 120Mhz, and have no issues with data integrity and all pins are in "standard" mode (default settings)...

I did, however, try changing the modes for the data bus to both slew enabled, as well as repeater mode, just as a test, and found the performance was worse...
0 Kudos

1,178 Views
lpcware
NXP Employee
NXP Employee
Content originally posted in LPCWare by PhilYoung on Fri Apr 20 02:10:35 MST 2012
looking at this all you seem to be doing is selecting the pin function, but not setting the pin mode.
this means all of the pins are in standard mode, i.e. slow.
I would set the slew bit to increase the slew rate for the SDRAM interface pins. ( i.e. Bit 9 ).
For the data lines you also need to enable repeater mode since they are bi-directional and must not be left floating on a cmos input.

regards

Phil.
0 Kudos

1,178 Views
lpcware
NXP Employee
NXP Employee
Content originally posted in LPCWare by Scieslik on Thu Apr 19 18:03:23 MST 2012
As far as SDRAM code goes, that is basically it. The only missing information from that code is the actual "EMC_Init()" function. Here it is:

<code>
/*********************************************************************//**
* @brief EMC initialize
* @param[in]None
* @return None
**********************************************************************/
void EMC_Init(void)
{
uint8_t i;

    /* Enable clock for EMC */
//  CLKPWR_ConfigPPWR(CLKPWR_PCONP_PCEMC, ENABLE);
//LPC_EMC->Control = 0x00000001;
// LPC_EMC->Config  = 0x00000000;

LPC_SC->PCONP   |= 0x00000800;
LPC_SC->EMCDLYCTL   = 0x00001010;
LPC_EMC->Control = 0x00000001;
LPC_EMC->Config  = 0x00000000;

  /* Pin configuration:
   * P2.14 - /EMC_CS2
   * P2.15 - /EMC_CS3
   *
   * P2.16 - /EMC_CAS
   * P2.17 - /EMC_RAS
   * P2.18 - EMC_CLK[0]
   * P2.19 - EMC_CLK[1]
   *
   * P2.20 - EMC_DYCS0
   * P2.21 - EMC_DYCS1
   * P2.22 - EMC_DYCS2
   * P2.23 - EMC_DYCS3
   *
   * P2.24 - EMC_CKE0
   * P2.25 - EMC_CKE1
   * P2.26 - EMC_CKE2
   * P2.27 - EMC_CKE3
   *
   * P2.28 - EMC_DQM0
   * P2.29 - EMC_DQM1
   * P2.30 - EMC_DQM2
   * P2.31 - EMC_DQM3
   *
   * P3.0-P3.31 - EMC_D[0-31]
   * P4.0-P4.23 - EMC_A[0-23]
   *
   * P4.24 - /EMC_OE
   * P4.25 - /EMC_WE
   *
   * P4.30 - /EMC_CS0
   * P4.31 - /EMC_CS1
   */
//PINSEL_ConfigPin(2,14,1);/* Not Used */
//PINSEL_ConfigPin(2,15,1);/* Not Used */
PINSEL_ConfigPin(2,16,1);
PINSEL_ConfigPin(2,17,1);
PINSEL_ConfigPin(2,18,1);
//PINSEL_ConfigPin(2,19,1);/* Not Used */
PINSEL_ConfigPin(2,20,1);
//PINSEL_ConfigPin(2,21,1);/* Not Used */
//PINSEL_ConfigPin(2,22,1);/* Not Used */
//PINSEL_ConfigPin(2,23,1);/* Not Used */
PINSEL_ConfigPin(2,24,1);
//PINSEL_ConfigPin(2,25,1);/* Not Used */
//PINSEL_ConfigPin(2,26,1);/* Not Used */
//PINSEL_ConfigPin(2,27,1);/* Not Used */
PINSEL_ConfigPin(2,28,1);
PINSEL_ConfigPin(2,29,1);
//PINSEL_ConfigPin(2,30,1);/* Not Used */
//PINSEL_ConfigPin(2,31,1);/* Not Used */

for(i = 0; i < 16; i++)/* D0 to D15 */
{
PINSEL_ConfigPin(3,i,1);
}

for(i = 0; i < 11; i++)/* A0 to A10 */
{
PINSEL_ConfigPin(4,i,1);
}

PINSEL_ConfigPin(4,13,1);
}
</code>

This code was obtained through NXP's site, and altered to our needs. It should enable all of the necessary EMC pins as I described in the hardware portion of my original post.

Is it possible that the EMCDLYCTL register values aren't correct? I'm not sure if the delay values are too long/short for this. The value shown was in this code when I originally downloaded it.

Thanks again
0 Kudos

1,178 Views
lpcware
NXP Employee
NXP Employee
Content originally posted in LPCWare by PhilYoung on Thu Apr 19 17:01:50 MST 2012
unfortunately a lot of your code is missing, so we have to assume that it's correct, but since the EMC settings seem to make sense I have to suspect that there is a problem with the IO setup.
for SDRAM you need to configure the IO to have fast slew and disable the input filters.

It's also necessary to enable the input mode on the clock, although it is an output the signal is fed back from the pad to the EMC to compensate for IO delays.

regards

Phil.
0 Kudos

1,178 Views
lpcware
NXP Employee
NXP Employee
Content originally posted in LPCWare by Scieslik on Thu Apr 19 11:06:51 MST 2012
Thank you for your response. This would be true for a Bank_Row_Column address mapping. What I described above is for a Row_Bank_Column mapping, which shifts the bits to A10. I have tried to set up the Bank_Row_Column mapping, but with no better results.
0 Kudos

1,178 Views
lpcware
NXP Employee
NXP Employee
Content originally posted in LPCWare by PhilYoung on Wed Apr 18 08:16:46 MST 2012
    LPC_EMC->DynamicControl    = 0x00000083;                         /* Issue MODE command */
    Temp = *((volatile uint32_t *)(SDRAM_BASE_ADDR | 0xCC00));       /* Set the SDRAM Mode - 3 CAS, 8 Burst Length */


Mode will be loaded from bits A9 upwards (A8..A1 = collumn address ), A0 selects the byte in 8 bit mode ( controls DQM )
0xCC00 = mode  0000 0000 0000 0000 1100 1100 0000 0000
drop 9 bits
Mode = 0000 0000 0000 0000 1100 110

which means you have actually set the SDRAM for
burst length = 110 ( reserved )
Burst Type = 0 (sequential)
Cas Latency = 110 ( reserved )
Mode Options = 00000 ( Burst Read / Burst Write ).

I suggest the address offset should be 0x6600

regards

Phil.
0 Kudos

1,178 Views
lpcware
NXP Employee
NXP Employee
Content originally posted in LPCWare by Scieslik on Mon Apr 16 21:34:55 MST 2012
Thank you for pointing this out. My understanding is that mixing up these 2 lines could cause problems when reading 8-bit data since they give access to the upper and lower bytes of a 16-bit read. However, I don't think this would cause issues with writing to a large range of addresses. I have tried to increase some delay configurations arbitrarily, but have been unsuccessful in getting the system to write beyond the limits I described above.

Thanks again for the help, it's very appreciated.
0 Kudos

1,178 Views
lpcware
NXP Employee
NXP Employee
Content originally posted in LPCWare by Scieslik on Mon Apr 16 21:30:42 MST 2012
I have tried a variety of configurations to see if I could find any differences here.

(1) Original configuration - 16MHz crystal, PLL configured to set clock to 80MHz
With this configuration I was able to perform a maximum of 8 write loops. Each loop iteration writes two 32-bit values to RAM starting at 0xA0000000. You can see the write loop in my original post.

(2) PLL w/ EMC Clock Divider - 16MHz crystal, PLL configured to set system to 80MHz, EMC Clock divided down to 40MHz
With this configuration I was able to successfully perform 16 write loops.

(3) No PLL - 16MHz crystal, 16MHz EMC Clock
Successfully wrote for 8 loops

(4) No PLL w/ EMC Clock Divider - 16MHz crystal, EMC Clock divided to 8MHz
Successfully wrote for 16 loops

In all cases, I didn't get above 16 loops (16 loops x 2 writes/loop x 4 bytes/write = 128 bytes written). It appears that the response is better when the Core Clock is faster than the EMC Clock. I am not sure if this gives any good clues as to what the problem could be, but it's what's occurring.

Thanks again!
0 Kudos

1,178 Views
lpcware
NXP Employee
NXP Employee
Content originally posted in LPCWare by wmues on Mon Apr 16 13:31:47 MST 2012
DQM0 <-> LDQM
DQM1 <-> UDQM

What about the delay lines?
0 Kudos

1,178 Views
lpcware
NXP Employee
NXP Employee
Content originally posted in LPCWare by Dave on Mon Apr 16 12:53:47 MST 2012
My reason for asking is crosstalk, signal latency, and signal ringing...  If you're traces are much longer than 4 inches from part to part, then there probably should be series resistors for each line...  If they're all bundled together nicely with ties, then there could be EMI issues between the lines, and of course if the length of each connection is not the same (different length wires), then there could be signal latency...

All of these things can make writes and reads look like "garbage", as you mentioned earlier...

A simple test is to slow the thing WAY down... like try running it below 20Mhz...  it might answer the question: Is it the software, or is it the way I have this thing connected...

Just a thought...
0 Kudos

1,178 Views
lpcware
NXP Employee
NXP Employee
Content originally posted in LPCWare by Scieslik on Sun Apr 15 19:33:46 MST 2012
The layout hasn't quite made it on to a PCB yet. The SDRAM chip is mounted to a small PCB of its own, and ported to the processor via jumper wires.

Here's the PCB the SDRAM is mounted on:
http://www.proto-advantage.com/store/product_info.php?products_id=2200240

The wires have been double-checked to make sure they are connected to the correct pins. As I said originally, I measured some of the components just to be sure the processor was communicating with the SDRAM chip correctly. The clock was measured at 80MHz as I expected, along with the clock enable pin being held high and the chip select pin being held low.

I realize the layout isn't ideal, but I don't see anything obviously wrong with it.

Thanks for the quick response. I appreciate the help.
0 Kudos

1,178 Views
lpcware
NXP Employee
NXP Employee
Content originally posted in LPCWare by Dave on Sun Apr 15 18:30:46 MST 2012
There are a lot of variables here - my first question (without having gone through your code with any detail) is how certain are you of your layout?

trace lengths, trace spacing, layers, etc....

0 Kudos