lpcware

LPC1778 + SDRAM IS42S16400F

Discussion created by lpcware Employee on Jun 15, 2016
Latest reply on Jun 15, 2016 by lpcware
Content originally posted in LPCWare by TP on Sat Oct 13 06:27:19 MST 2012
Hi everyone,

I'm working with LPC1778 controller and external SDRAM. I'm using IS42S16400F SDRAM chip (1M x 16 bits x 4 banks). LPC1778 is running at 120 MHz, EMC Clock is set to CPU/2 (60 MHz). I'm using Keil uVision, SDRAM base address is 0xA0000000.

I can read/write from SDRAM, as long as I don't write more than 512 bytes of data.
I can read/write from SDRAM more than 512 bytes only if I skip every other row (write 512 byte, skip 512 bytes, write 512 bytes etc.)
 
I'll try to clarify problems with few examples.

<code>
U32 *p2_extern = (U32 *) 0xA0000000;

*(p2_extern +   0) = (U32)(p2_extern +   0);
*(p2_extern +   1) = (U32)(p2_extern +   1);
*(p2_extern + 128) = (U32)(p2_extern + 128);
*(p2_extern + 129) = (U32)(p2_extern + 129);

printf("Address %08x: %08x\n",   (p2_extern +   0), *(p2_extern +   0));
printf("Address %08x: %08x\n",   (p2_extern +   1), *(p2_extern +   1));
printf("Address %08x: %08x\n",   (p2_extern +   128), *(p2_extern + 128));
printf("Address %08x: %08x\n",   (p2_extern +   129), *(p2_extern + 129));
</code>
 
In this example, everything seems OK.

<code>
Address a0000000: a0000000
Address a0000004: a0000004
Address a0000200: a0000200
Address a0000204: a0000204
</code>

In next test I will try to write 512 bytes (128 x 32-bit variable) starting from SDRAM base address A000 0000.

<code>
U32 *p2_extern = (U32 *) 0xA0000000;
U32 i;

for(i = 0; i < 128; ++i)
   *p2_extern++ = p2_extern;


p2_extern = (U32 *) 0xA0000000;
for(i = 0; i < 128; ++i)
{
   if(i != 0 && i % 8 == 0)
      printf("\n");

   printf("%08x ", *p1_extern++);

}

</code>

Again, everything is OK. This way I can write on every SDRAM location, as long as don't write more than 512 bytes.

<code>
a0000000 a0000004 a0000008 a000000c a0000010 a0000014 a0000018 a000001c
a0000020 a0000024 a0000028 a000002c a0000030 a0000034 a0000038 a000003c
a0000040 a0000044 a0000048 a000004c a0000050 a0000054 a0000058 a000005c
a0000060 a0000064 a0000068 a000006c a0000070 a0000074 a0000078 a000007c
a0000080 a0000084 a0000088 a000008c a0000090 a0000094 a0000098 a000009c
a00000a0 a00000a4 a00000a8 a00000ac a00000b0 a00000b4 a00000b8 a00000bc
a00000c0 a00000c4 a00000c8 a00000cc a00000d0 a00000d4 a00000d8 a00000dc
a00000e0 a00000e4 a00000e8 a00000ec a00000f0 a00000f4 a00000f8 a00000fc
a0000100 a0000104 a0000108 a000010c a0000110 a0000114 a0000118 a000011c
a0000120 a0000124 a0000128 a000012c a0000130 a0000134 a0000138 a000013c
a0000140 a0000144 a0000148 a000014c a0000150 a0000154 a0000158 a000015c
a0000160 a0000164 a0000168 a000016c a0000170 a0000174 a0000178 a000017c
a0000180 a0000184 a0000188 a000018c a0000190 a0000194 a0000198 a000019c
a00001a0 a00001a4 a00001a8 a00001ac a00001b0 a00001b4 a00001b8 a00001bc
a00001c0 a00001c4 a00001c8 a00001cc a00001d0 a00001d4 a00001d8 a00001dc
a00001e0 a00001e4 a00001e8 a00001ec a00001f0 a00001f4 a00001f8 a00001fc
</code>

Now I will try to write 1024 bytes (256 x 32-bit variables)

<code>
U32 *p2_extern = (U32 *) 0xA0000000;
U32 i;

for(i = 0; i < 256; ++i)
   *p2_extern++ = p2_extern;


p2_extern = (U32 *) 0xA0000000;
for(i = 0; i < 256; ++i)
{
   if(i != 0 && i % 8 == 0)
      printf("\n");

   if(i != 0 && i % 128 == 0)
      printf("\n");

   printf("%08x ", *p1_extern++);

}
</code>

As you can see, first 512 bytes are corrupted with second 512 bytes.

<code>

a0000200 a0000204 a0000208 a000020c a0000210 a0000214 a0000218 a000021c
a0000220 a0000224 a0000228 a000022c a0000230 a0000234 a0000238 a000023c
a0000240 a0000244 a0000248 a000024c a0000250 a0000254 a0000258 a000025c
a0000260 a0000264 a0000268 a000026c a0000270 a0000274 a0000278 a000027c
a0000280 a0000284 a0000288 a000028c a0000290 a0000294 a0000298 a000029c
a00002a0 a00002a4 a00002a8 a00002ac a00002b0 a00002b4 a00002b8 a00002bc
a00002c0 a00002c4 a00002c8 a00002cc a00002d0 a00002d4 a00002d8 a00002dc
a00002e0 a00002e4 a00002e8 a00002ec a00002f0 a00002f4 a00002f8 a00002fc
a0000300 a0000304 a0000308 a000030c a0000310 a0000314 a0000318 a000031c
a0000320 a0000324 a0000328 a000032c a0000330 a0000334 a0000338 a000033c
a0000340 a0000344 a0000348 a000034c a0000350 a0000354 a0000358 a000035c
a0000360 a0000364 a0000368 a000036c a0000370 a0000374 a0000378 a000037c
a0000380 a0000384 a0000388 a000038c a0000390 a0000394 a0000398 a000039c
a00003a0 a00003a4 a00003a8 a00003ac a00003b0 a00003b4 a00003b8 a00003bc
a00003c0 a00003c4 a00003c8 a00003cc a00003d0 a00003d4 a00003d8 a00003dc
a00003e0 a00003e4 a00003e8 a00003ec a00003f0 a00003f4 a00003f8 a00003fc

a0000200 a0000204 a0000208 a000020c a0000210 a0000214 a0000218 a000021c
a0000220 a0000224 a0000228 a000022c a0000230 a0000234 a0000238 a000023c
a0000240 a0000244 a0000248 a000024c a0000250 a0000254 a0000258 a000025c
a0000260 a0000264 a0000268 a000026c a0000270 a0000274 a0000278 a000027c
a0000280 a0000284 a0000288 a000028c a0000290 a0000294 a0000298 a000029c
a00002a0 a00002a4 a00002a8 a00002ac a00002b0 a00002b4 a00002b8 a00002bc
a00002c0 a00002c4 a00002c8 a00002cc a00002d0 a00002d4 a00002d8 a00002dc
a00002e0 a00002e4 a00002e8 a00002ec a00002f0 a00002f4 a00002f8 a00002fc
a0000300 a0000304 a0000308 a000030c a0000310 a0000314 a0000318 a000031c
a0000320 a0000324 a0000328 a000032c a0000330 a0000334 a0000338 a000033c
a0000340 a0000344 a0000348 a000034c a0000350 a0000354 a0000358 a000035c
a0000360 a0000364 a0000368 a000036c a0000370 a0000374 a0000378 a000037c
a0000380 a0000384 a0000388 a000038c a0000390 a0000394 a0000398 a000039c
a00003a0 a00003a4 a00003a8 a00003ac a00003b0 a00003b4 a00003b8 a00003bc
a00003c0 a00003c4 a00003c8 a00003cc a00003d0 a00003d4 a00003d8 a00003dc
a00003e0 a00003e4 a00003e8 a00003ec a00003f0 a00003f4 a00003f8 a00003fc

</code>

Final example
   Step 1: write 128 32-bit values, print value after each write. Writing at location [A000 0000 - A000 0200)
   Step 2: write 128 32-bit values, print value at same index, but in preceding SDRAM row.
   Step 3: print memory from a000 0000 - a000 0400

<code>
U32 *p2_extern = (U32 *) 0xA0000000;
U32 i, j, temp;

printf("Writing and printing first 512 bytes\n");
for(i = 0; i < 128; ++i)
{
   if(i != 0 && i % 8 == 0)
      printf("\n");

   *p2_extern = (U32) p2_extern;
   printf("%08x ", *p2_extern);
   p2_extern++;
}


printf("\n\n\nWriting and printing another 512 bytes\n");
for(i = 0; i < 128; ++i)
{
   if(i != 0 && i % 8 == 0)
      printf("\n");

   printf("%08x (", *(p2_extern - 128));
   *p2_extern = (U32) p2_extern;
  
   printf("%08x) ", *(p2_extern - 128));
   p2_extern++;
}

p2_extern = (U32 *) 0xA0000000;

for(i = 0; i < 256; ++i)
{
   if(i != 0 && i % 8 == 0)
      printf("\n");

   printf("%08x ", *p1_extern++);
}

</code>

In this example, it seems like everything is ok with first SDRAM row of data(a000 0000 - a000 0200), but after second row is finished, data in row 0 are exactly the same as data in row 1.

<code>
Writing and printing first 512 bytes
a0000000 a0000004 a0000008 a000000c a0000010 a0000014 a0000018 a000001c
a0000020 a0000024 a0000028 a000002c a0000030 a0000034 a0000038 a000003c
a0000040 a0000044 a0000048 a000004c a0000050 a0000054 a0000058 a000005c
a0000060 a0000064 a0000068 a000006c a0000070 a0000074 a0000078 a000007c
a0000080 a0000084 a0000088 a000008c a0000090 a0000094 a0000098 a000009c
a00000a0 a00000a4 a00000a8 a00000ac a00000b0 a00000b4 a00000b8 a00000bc
a00000c0 a00000c4 a00000c8 a00000cc a00000d0 a00000d4 a00000d8 a00000dc
a00000e0 a00000e4 a00000e8 a00000ec a00000f0 a00000f4 a00000f8 a00000fc
a0000100 a0000104 a0000108 a000010c a0000110 a0000114 a0000118 a000011c
a0000120 a0000124 a0000128 a000012c a0000130 a0000134 a0000138 a000013c
a0000140 a0000144 a0000148 a000014c a0000150 a0000154 a0000158 a000015c
a0000160 a0000164 a0000168 a000016c a0000170 a0000174 a0000178 a000017c
a0000180 a0000184 a0000188 a000018c a0000190 a0000194 a0000198 a000019c
a00001a0 a00001a4 a00001a8 a00001ac a00001b0 a00001b4 a00001b8 a00001bc
a00001c0 a00001c4 a00001c8 a00001cc a00001d0 a00001d4 a00001d8 a00001dc
a00001e0 a00001e4 a00001e8 a00001ec a00001f0 a00001f4 a00001f8 a00001fc

Writing and printing another 512 bytes
a0000000 (a0000000) a0000004 (a0000004) a0000008 (a0000008) a000000c (a000000c) a0000010 (a0000010) a0000014 (a0000014) a0000018 (a0000018) a000001c (a000001c)
a0000020 (a0000020) a0000024 (a0000024) a0000028 (a0000028) a000002c (a000002c) a0000030 (a0000030) a0000034 (a0000034) a0000038 (a0000038) a000003c (a000003c)
a0000040 (a0000040) a0000044 (a0000044) a0000048 (a0000048) a000004c (a000004c) a0000050 (a0000050) a0000054 (a0000054) a0000058 (a0000058) a000005c (a000005c)
a0000060 (a0000060) a0000064 (a0000064) a0000068 (a0000068) a000006c (a000006c) a0000070 (a0000070) a0000074 (a0000074) a0000078 (a0000078) a000007c (a000007c)
a0000080 (a0000080) a0000084 (a0000084) a0000088 (a0000088) a000008c (a000008c) a0000090 (a0000090) a0000094 (a0000094) a0000098 (a0000098) a000009c (a000009c)
a00000a0 (a00000a0) a00000a4 (a00000a4) a00000a8 (a00000a8) a00000ac (a00000ac) a00000b0 (a00000b0) a00000b4 (a00000b4) a00000b8 (a00000b8) a00000bc (a00000bc)
a00000c0 (a00000c0) a00000c4 (a00000c4) a00000c8 (a00000c8) a00000cc (a00000cc) a00000d0 (a00000d0) a00000d4 (a00000d4) a00000d8 (a00000d8) a00000dc (a00000dc)
a00000e0 (a00000e0) a00000e4 (a00000e4) a00000e8 (a00000e8) a00000ec (a00000ec) a00000f0 (a00000f0) a00000f4 (a00000f4) a00000f8 (a00000f8) a00000fc (a00000fc)
a0000100 (a0000100) a0000104 (a0000104) a0000108 (a0000108) a000010c (a000010c) a0000110 (a0000110) a0000114 (a0000114) a0000118 (a0000118) a000011c (a000011c)
a0000120 (a0000120) a0000124 (a0000124) a0000128 (a0000128) a000012c (a000012c) a0000130 (a0000130) a0000134 (a0000134) a0000138 (a0000138) a000013c (a000013c)
a0000140 (a0000140) a0000144 (a0000144) a0000148 (a0000148) a000014c (a000014c) a0000150 (a0000150) a0000154 (a0000154) a0000158 (a0000158) a000015c (a000015c)
a0000160 (a0000160) a0000164 (a0000164) a0000168 (a0000168) a000016c (a000016c) a0000170 (a0000170) a0000174 (a0000174) a0000178 (a0000178) a000017c (a000017c)
a0000180 (a0000180) a0000184 (a0000184) a0000188 (a0000188) a000018c (a000018c) a0000190 (a0000190) a0000194 (a0000194) a0000198 (a0000198) a000019c (a000019c)
a00001a0 (a00001a0) a00001a4 (a00001a4) a00001a8 (a00001a8) a00001ac (a00001ac) a00001b0 (a00001b0) a00001b4 (a00001b4) a00001b8 (a00001b8) a00001bc (a00001bc)
a00001c0 (a00001c0) a00001c4 (a00001c4) a00001c8 (a00001c8) a00001cc (a00001cc) a00001d0 (a00001d0) a00001d4 (a00001d4) a00001d8 (a00001d8) a00001dc (a00001dc)
a00001e0 (a00001e0) a00001e4 (a00001e4) a00001e8 (a00001e8) a00001ec (a00001ec) a00001f0 (a00001f0) a00001f4 (a00001f4) a00001f8 (a00001f8) a00001fc (a00001fc)

a0000200 a0000204 a0000208 a000020c a0000210 a0000214 a0000218 a000021c
a0000220 a0000224 a0000228 a000022c a0000230 a0000234 a0000238 a000023c
a0000240 a0000244 a0000248 a000024c a0000250 a0000254 a0000258 a000025c
a0000260 a0000264 a0000268 a000026c a0000270 a0000274 a0000278 a000027c
a0000280 a0000284 a0000288 a000028c a0000290 a0000294 a0000298 a000029c
a00002a0 a00002a4 a00002a8 a00002ac a00002b0 a00002b4 a00002b8 a00002bc
a00002c0 a00002c4 a00002c8 a00002cc a00002d0 a00002d4 a00002d8 a00002dc
a00002e0 a00002e4 a00002e8 a00002ec a00002f0 a00002f4 a00002f8 a00002fc
a0000300 a0000304 a0000308 a000030c a0000310 a0000314 a0000318 a000031c
a0000320 a0000324 a0000328 a000032c a0000330 a0000334 a0000338 a000033c
a0000340 a0000344 a0000348 a000034c a0000350 a0000354 a0000358 a000035c
a0000360 a0000364 a0000368 a000036c a0000370 a0000374 a0000378 a000037c
a0000380 a0000384 a0000388 a000038c a0000390 a0000394 a0000398 a000039c
a00003a0 a00003a4 a00003a8 a00003ac a00003b0 a00003b4 a00003b8 a00003bc
a00003c0 a00003c4 a00003c8 a00003cc a00003d0 a00003d4 a00003d8 a00003dc
a00003e0 a00003e4 a00003e8 a00003ec a00003f0 a00003f4 a00003f8 a00003fc

a0000200 a0000204 a0000208 a000020c a0000210 a0000214 a0000218 a000021c
a0000220 a0000224 a0000228 a000022c a0000230 a0000234 a0000238 a000023c
a0000240 a0000244 a0000248 a000024c a0000250 a0000254 a0000258 a000025c
a0000260 a0000264 a0000268 a000026c a0000270 a0000274 a0000278 a000027c
a0000280 a0000284 a0000288 a000028c a0000290 a0000294 a0000298 a000029c
a00002a0 a00002a4 a00002a8 a00002ac a00002b0 a00002b4 a00002b8 a00002bc
a00002c0 a00002c4 a00002c8 a00002cc a00002d0 a00002d4 a00002d8 a00002dc
a00002e0 a00002e4 a00002e8 a00002ec a00002f0 a00002f4 a00002f8 a00002fc
a0000300 a0000304 a0000308 a000030c a0000310 a0000314 a0000318 a000031c
a0000320 a0000324 a0000328 a000032c a0000330 a0000334 a0000338 a000033c
a0000340 a0000344 a0000348 a000034c a0000350 a0000354 a0000358 a000035c
a0000360 a0000364 a0000368 a000036c a0000370 a0000374 a0000378 a000037c
a0000380 a0000384 a0000388 a000038c a0000390 a0000394 a0000398 a000039c
a00003a0 a00003a4 a00003a8 a00003ac a00003b0 a00003b4 a00003b8 a00003bc
a00003c0 a00003c4 a00003c8 a00003cc a00003d0 a00003d4 a00003d8 a00003dc
a00003e0 a00003e4 a00003e8 a00003ec a00003f0 a00003f4 a00003f8 a00003fc
</code>

At last, here is my EMC initialization

<code>
void emc_pin_config(void)
{
   LPC_IOCON->P3_0  |= 0x01; /* D1  @ P3.0 */
   LPC_IOCON->P3_1  |= 0x01; /* D3  @ P3.1 */
   LPC_IOCON->P3_2  |= 0x01; /* D5  @ P3.2 */
   LPC_IOCON->P3_3  |= 0x01; /* D15 @ P3.3 */

   LPC_IOCON->P3_4  |= 0x01; /* D13 @ P3.4 */
   LPC_IOCON->P3_5  |= 0x01; /* D12 @ P3.5 */
   LPC_IOCON->P3_6  |= 0x01; /* D10 @ P3.6 */
   LPC_IOCON->P3_7  |= 0x01; /* D9  @ P3.7 */

   LPC_IOCON->P3_8  |= 0x01; /* D0   @ P3.8 */
   LPC_IOCON->P3_9  |= 0x01; /* D2   @ P3.9 */
   LPC_IOCON->P3_10 |= 0x01; /* D4   @ P3.10 */
   LPC_IOCON->P3_11 |= 0x01; /* D6   @ P3.11 */

   LPC_IOCON->P3_12 |= 0x01; /* D7   @ P3.12 */
   LPC_IOCON->P3_13 |= 0x01; /* D14  @ P3.13 */
   LPC_IOCON->P3_14 |= 0x01; /* D11  @ P3.14 */
   LPC_IOCON->P3_15 |= 0x01; /* D8   @ P3.15 */

   LPC_IOCON->P4_0  |= 0x01; /* A0 @ P4.0 */
   LPC_IOCON->P4_1  |= 0x01; /* A1 @ P4.1 */
   LPC_IOCON->P4_2  |= 0x01; /* A2 @ P4.2 */
   LPC_IOCON->P4_3  |= 0x01; /* A3 @ P4.3 */

   LPC_IOCON->P4_4  |= 0x01; /* A4 @ P4.4 */
   LPC_IOCON->P4_5  |= 0x01; /* A5 @ P4.5 */
   LPC_IOCON->P4_6  |= 0x01; /* A6 @ P4.6 */
   LPC_IOCON->P4_7  |= 0x01; /* A7 @ P4.7 */

   LPC_IOCON->P4_8  |= 0x01; /* A8  @ P4.8 */
   LPC_IOCON->P4_9  |= 0x01; /* A9  @ P4.9 */
   LPC_IOCON->P4_10 |= 0x01; /* A10 @ P4.10 */
   LPC_IOCON->P4_11 |= 0x01; /* A11 @ P4.11 */

   LPC_IOCON->P4_12 |= 0x01; /* BA0 @ P4.13 */
   LPC_IOCON->P4_13 |= 0x01; /* BA1 @ P4.14 */

   LPC_IOCON->P4_25 |= 0x01; /* WEN  @ P4.25 */

   LPC_IOCON->P2_16 |= 0x01; /* CASN @ P2.16 */
   LPC_IOCON->P2_17 |= 0x01; /* RASN @ P2.17 */
   LPC_IOCON->P2_18 |= 0x01; /* CLK[0] @ P2.18 */

   LPC_IOCON->P2_20 |= 0x01; /* DYCSN[0] @ P2.20 */

   LPC_IOCON->P2_24 |= 0x01; /* CKE[0] @ P2.24 */

   LPC_IOCON->P2_28 |= 0x01; /* DQM[0] @ P2.28 */
   LPC_IOCON->P2_29 |= 0x01; /* DQM[1] @ P2.29 */
}

BOOL sdram_init (void)
{
   uint32_t i, dwtemp = dwtemp;
   uint16_t wtemp = wtemp;

   LPC_SC->PCONP     |= 0x00000800;// postavi Power bit
   LPC_SC->EMCDLYCTL  = 0x00001010;// EMC Output delay: 4 ns, feedback clock delay 4 ns

   LPC_EMC->Control   = 0x00000001;// EMC enabled
   LPC_EMC->Config    = 0x00000000;// Little endian

   emc_pin_config();

   // Configure memory layout, but MUST DISABLE BUFFERs during configuration, 64MB, 4Mx16, 4 banks, row=12, column=8
   LPC_EMC->DynamicConfig0 = 0x00000280;

   // Timing for 60 MHz Bus
   LPC_EMC->DynamicRasCas0    = 0x00000202; // 2 RAS, 2 CAS latency
   LPC_EMC->DynamicReadConfig = 0x00000001; // Command delayed strategy, using EMCCLKDELAY

   LPC_EMC->DynamicRP   = 0x00000002; // min 20 ns
   LPC_EMC->DynamicRAS  = 0x00000003; // min 44 ns
   LPC_EMC->DynamicSREX = 0x00000007;     
   LPC_EMC->DynamicAPR  = 0x00000002; // min 20 ns
   LPC_EMC->DynamicDAL  = 0x00000005;
   LPC_EMC->DynamicWR   = 0x00000001;
   LPC_EMC->DynamicRC   = 0x00000005; // min 64 ns
   LPC_EMC->DynamicRFC  = 0x00000005; // min 64 ns
   LPC_EMC->DynamicXSR  = 0x00000007;
   LPC_EMC->DynamicRRD  = 0x00000001; // min 14 ns
   LPC_EMC->DynamicMRD  = 0x00000002;

   for(i = 0; i < 0x80; i++); // wait 128 AHB clock cycles

   LPC_EMC->DynamicControl = 0x00000183; // Issue NOP command

   for(i = 0; i < 0x80; i++); // wait 128 AHB clock cycles

   LPC_EMC->DynamicControl = 0x00000103; // Issue PALL command
   LPC_EMC->DynamicRefresh = 0x00000002; // ( n * 16 ) -> 32 clock cycles
   for(i = 0; i < 0x80; i++); // wait 128 AHB clock cycles

   //Timing for 50MHz Bus
   LPC_EMC->DynamicRefresh = 0x0000003A; // ( n * 16 ) -> 782 clock cycles -> 15.625uS ( 64ms / 4096 row )
   LPC_EMC->DynamicControl = 0x00000083; // Issue MODE command

   dwtemp = *((volatile uint32_t *)(SDRAM_BASE | (0x23<<11))); // 8 burst, 2 CAS latency

   LPC_EMC->DynamicControl = 0x00000000; // Issue NORMAL command

   LPC_EMC->DynamicConfig0 |= 0x00080000;//[re]enable buffers

   for(i = 0; i < 0x80; i++); // wait 128 AHB clock cycles

   return __TRUE;
}

</code>

Any idea?

Outcomes