LPC2478 +SDRAM == Problem

Gast #2191131
Lesenswert?

hallo

ich habe folgendes Problem mit meinem LPC2478 +SDRam, wenn ich ein Wort 
in den Speicher schreibe, habe ich dieses jedes aml an 4 worten, 
anstelle von nur 1 wort, kann mir jemand einen tip geben, was ich beim 
initialisieren falsch mache?

SD-Ram: http://www.issi.com/pdf/42S32800B.pdf

Code
1
void init_ram(void) //routine zum initialisieren des SD-Ram Controllers
2
{
3
  EMCControl = 0x00000001;
4
  PCONP |= PCONP_PCEMC; //Memory controller aktivieren
5
  PINSEL5 &= 0x55fdfdd5;
6
  PINSEL5 |= 0x55010115;
7
  PINSEL6 = 0x55555555;
8
  PINSEL7 = 0x55555555;
9
  PINSEL8 = 0x15555555;
10
  PINSEL9 &= 0xfff7ffff;
11
  PINSEL9 |= 0x00040000;
12

13
  EMCDynamictRP     = 3;    // command period: 3(n+1) clock cycles  
14
  EMCDynamictRAS    = 4;    // RAS command period: 4(n+1) clock cycles 
15
  EMCDynamictSREX   = 8;    // Self-refresh period: 8(n+1) clock cycles 
16
  EMCDynamictAPR    = 3;    // Data out to active: 3(n+1) clock cycles 
17
  EMCDynamictDAL     =5;    // Data in to active: 5(n+1) clock cycles 
18
  EMCDynamictWR      = 2;    // Write recovery: 2(n+1) clock cycles 
19
  EMCDynamictRC     = 6;    // Active to Active cmd: 6(n+1) clock cycles 
20
  EMCDynamictRFC    = 6;    // Auto-refresh: 6(n+1) clock cycles 
21
  EMCDynamictXSR    = 8;    // Exit self-refresh: 8(n+1) clock cycles 
22
  EMCDynamictRRD    = 2;    // Active bank A->B: 2(n+1) clock cycles 
23
  EMCDynamictMRD    = 3;    // Load Mode to Active cmd: 3(n+1) clock cycles 
24

25
    /* use slow default settings */
26
// EMC_DYN_RP= 5; // precharge command period
27
//  EMC_DYN_RAS = 6;// active to precharge time
28
//  EMC_DYN_SREX = 9;// self refresh exit time
29
//  EMC_DYN_APR = 3; //data out to active time
30
//  EMC_DYN_DAL = 6; //data in to active time
31
//  EMC_DYN_WR = 5; //write recovery time
32
//  EMC_DYN_RC = 10;//active to active command
33
//  EMC_DYN_RFC = 2; //Refresh period
34
//  EMC_DYN_XSR = 7;// exit self refresh
35
//  EMC_DYN_RRD = 4;// time between bankswitches
36
//  EMC_DYN_MRD = 4;// load mode to active command time */
37

38
  EMCDynamicReadConfig = 1;    // Command delayed strategy 
39

40
  EMCDynamicRasCas0 = 0x00000303;
41
  EMCDynamicConfig0 = 0x00004700;
42
 // EMCDynamicConfig0 &= 0xffe7e767;
43
 // EMCDynamicConfig0 |= 0x00004700;
44
  
45
  unsigned int i;
46
  for(i=0;i<65534;i++);
47

48
  EMCDynamicControl = 0x00000183;
49

50
  for(i=0;i<65534;i++);
51

52
  EMCDynamicControl = 0x00000103;
53

54
  EMCDynamicRefresh = 0x00000002;
55

56
  for(i = 0; i < 0x40; i++);
57

58
  EMCDynamicRefresh = 28;
59
  EMCDynamicControl = 0x00000083;
60

61
#define SDRAM_BASE_ADDR 0xA00000000
62
 // DWORD dummy;
63
 // dummy = *((volatile DWORD *)(SDRAM_BASE_ADDR | (0x33 << 12)));
64
 i = (*(volatile int*)(0xA0000033)); //| (0x4<<5) | (3))); // CAS lat = 3, burst length = 8
65

66
  EMCDynamicControl = 0x00000000;
67
  EMCDynamicConfig0 |= 0x00080000;
68
  for(i=0;i<65534;i++);
69
}
Gast #2191232
Lesenswert?

Schau mal ganz unten im Beitrag:

LCD Timings - SVGA - LPC2478

Dort hat Kai F. folgendes zu diesem Thema geschrieben:

Das Mode-Register wird ja über die Adressleitung geschrieben, d.h. diese
Zeile ist ja ein (spezieller) Lesezugriff auf eine bestimmte Adresse.
Jetzt ist es aber so, dass die Adressierung bei einem SDRAM nicht in
einem Schritt passiert, sondern in drei (Row, Column und dann in der
Seite). Schau mal in das Dokument, das du oben verlinkt hast.
Das knifflige an den SDRAMS und deren Initialisierung ist dann halt den
Shift-Wert (in den Fall 13) richtig zu bestimmen, dass die Bits auch an
der richtigen Stelle im Mode-Register landen.
Burst-Length steht in Bit[2:0], CAS-Latency in Bit[6:4].
Mit der 13 werden nun diese Bits so verschoben, dass sie in der
Row-Adresse stehen. Wenn ich mich richtig erinnere: Column-Breite +
Bus-Breite (1 für 16 Bit; 2 für 32 Bit) + 2 (für Bänke) -> 9+2+2 = 13.


Ich denke, dass da nichts mehr hinzuzufügen ist.
Gast #2192299
Lesenswert?

hier noch der code der testroutine

[c}
/*********************************************************************** 
******
 *   sdram_test.c:  External SDRAM test main C entry file for NXP
 *   LPC23xx/24xx Family Microprocessors
 *
 *   Copyright(C) 2006, NXP Semiconductor
 *   All rights reserved.
 *
 *   History
 *   2006.07.14  ver 1.00    Prelimnary version, first Release
 *
************************************************************************ 
******/
#include "LPC23xx.h"                        /* LPC23xx/24xx definitions 
*/
#include "type.h"
#include "irq.h"
#include "target.h"
#include "ex_sdram.h"
#if FLASH_DEBUG
#if EA_BOARD_LPC24XX
//#include "uart.h"
#endif
#endif

/*********************************************************************** 
******
**   Main Function  main()
************************************************************************ 
******/
int main (void)
{
  MAMCR = 0;
  volatile DWORD *wr_ptr;
  volatile BYTE *char_wr_ptr;
  volatile WORD *short_wr_ptr;
  volatile WORD *long_wr_ptr;
  DWORD  i, x;

  /* initialize memory */
  init_ram();

#ifdef comout
  wr_ptr = (DWORD *)SDRAM_BASE_ADDR;
  char_wr_ptr = (BYTE *)wr_ptr;
  /* Clear content before 8 bit access test */
  for( ;wr_ptr < (DWORD *)(SDRAM_BASE_ADDR + SDRAM_SIZE); )
  {
  *wr_ptr++ = (unsigned long) 0;
  }

  /* 8 bit write */
  for( ;char_wr_ptr < (BYTE *)(SDRAM_BASE_ADDR + SDRAM_SIZE); )
  {
  *char_wr_ptr++ = 0xAA;
  *char_wr_ptr++ = 0x55;
  *char_wr_ptr++ = 0x5A;
  *char_wr_ptr++ = 0xA5;
  }
  /* verifying */
  wr_ptr = (DWORD *)SDRAM_BASE_ADDR  ;
  for ( ; wr_ptr < (DWORD *)(SDRAM_BASE_ADDR + SDRAM_SIZE) ; )
  {
  if ( *wr_ptr != 0xA55A55AA )  /* be aware of endianess */
  {
    while ( 1 );  /* fatal error */
  }
  wr_ptr++;
  }

  wr_ptr = (DWORD *)SDRAM_BASE_ADDR;
  short_wr_ptr = (WORD *)wr_ptr;
  /* Clear content before 16 bit access test */
  for ( ; wr_ptr < (DWORD *)(SDRAM_BASE_ADDR + SDRAM_SIZE) ; )
  {
  *wr_ptr++ = 0;
  }

  /* 16 bit write */
  for ( ; short_wr_ptr < (WORD *)(SDRAM_BASE_ADDR + SDRAM_SIZE) ; )
  {
  *short_wr_ptr++ = 0x5AA5;
  *short_wr_ptr++ = 0xAA55;
  }

  /* Verifying */
  wr_ptr = (DWORD *)SDRAM_BASE_ADDR ;
  for ( ; wr_ptr < (DWORD *)(SDRAM_BASE_ADDR + SDRAM_SIZE) ; )
  {
  if ( *wr_ptr != 0xAA555AA5 )  /* be aware of endianess */
  {
    while ( 1 );  /* fatal error */
  }
  wr_ptr++;
  }
#endif

  wr_ptr = (DWORD *)SDRAM_BASE_ADDR;
  /* Clear content before 16 bit access test */
  for( ; wr_ptr < (DWORD *)(SDRAM_BASE_ADDR + SDRAM_SIZE) ; )
  {
  *wr_ptr++ = 0;
  }
unsigned long z = 0;
  /* 32 bit write */
  wr_ptr = (DWORD *)SDRAM_BASE_ADDR;
  x = SDRAM_BASE_ADDR;
  for( i = 0; i < (SDRAM_SIZE/4); i++ ){
  *wr_ptr++ = x++;
        }

  /* Verifying */
  wr_ptr = (DWORD *)SDRAM_BASE_ADDR ;
  x = SDRAM_BASE_ADDR;
  for( i = 0; i < (SDRAM_SIZE/4); i++ )
  {
  if ( *wr_ptr != (DWORD) x )  /* be aware of endianess */
  {
    while ( 1 );  /* fatal error */
  }
  wr_ptr++;
  x++;
  }

  return 0;
}

/*********************************************************************** 
******
**                            End Of File
************************************************************************ 
*****/

[/c]
Gast #2192344
Lesenswert?

Nimms nicht persönlich aber dein Code ist ja sowas von hässlich, ständig 
irgendwelche Pointer und der ganze Müll.

Hab dir meine eigene SDRAM Schreib- und Leseroutinen angehängt.
Bei SDRAM_LENGTH muss du zunächst die Größe deines SDRAMs in Byte 
angeben.
Nach der SDRAM Initialisierung löschst du diesen mit SDRAM_erase und 
dann schreib einfach ein paar chars und lies diese aus und prüfe auf 
Korrektheit.

Wenn weiterhin Probleme hast dann melde dich


Gruß Alex
Angehängte Dateien:
Gast #2192403
Lesenswert?

OK. Fangen wir aber bei der Hardware an. Ein oft gemachter Fehler ist 
die Geschichte mit der A13 und A14 Leitung.

A13 und A14 muss immer an BA0 und BA1.

Kannst du dein Schaltplan posten, das würde die Sache um einiges 
erleichtern.
Gast #2192437
Lesenswert?

Hoppla ich sehe grad, dass du ja gar keine pull-ups pull-downs an den 
SDRAM Pins deaktiviert/aktiviert hast.
Bei mir, bei nem 128 Mbit SDRAM sieht das Ganze so aus:

//-----------------
PCONP|=(1 << 11);  //  EnableRAMPower();

  PINSEL5  |= 0x55010115;
  PINMODE5 |= 0xAAaaaaaA;
  PINSEL6  |= 0x55555555;
  PINMODE6 |= 0xAAAAAAAA;
  PINSEL7  |= 0x55555555;
  PINMODE7 |= 0xAAAAAAAA;
  PINSEL8  |= 0x15555555;
  PINMODE8 |= 0x1AAAAAAA;
  PINSEL9  |= (1 << 18);
  PINMODE9 |= 0x80000;
//---------------

Beim LPC2478 sind die Pins im Default (after reset) auf pull up gesetzt.

Es ist bei mir etwas länger her, dass ich mich dem dem SDRAm 
beschäfftigt habe.
Gast #2192476
Lesenswert?

Das wird ja immer interessanter!

laut deinem memory dump werden alle 32 Adressen die Schreibdaten einmal 
um 8 und daraufhin um 2 Zähler verringert, irgendwie kann ich das 
überhaupt nicht hachvollziehen. Ich vermute ganz stark, dass die 
Testroutine Fehler enthält.
Leider ist der Kode so hässlich, dass man den überhaupt nicht lesen mag.
Versuch mal Folgendes:
//------------------------------

int main(void){

PLL_init();
SDRAM_init();

SDRAM_erase();

for(unsigned int a = 0; a < 50000; a++)
 {
 SDRAM_write_byte(a,250); // schreibe die ersten 50k bytes
 }

for(unsigned int b = 0; b < 50000; b++)
 {
 unsigned char buf = 0;
 buf = SDRAM_read_byte(b);    // lese die ersten 50K bytes
 if( buf != 250)
    {
     RED_LED_ON;  // prüfe auf Korrektheit z.B. mit einer LED
     while(1);
    }
 }
}//main

//-------------------------------

Hast du eigentlich schon funktionierenden UART? Wenn nicht dann hätte 
ich hier was für den UART0.
Gast #2192483
Lesenswert?

von mir:
> laut deinem memory dump werden alle 32 Adressen die Schreibdaten einmal
> um 8 und daraufhin um 2 Zähler verringert

sorry, hab Quatsch geredet, es sind einmal 24 und daraufhin 30 Zähler, 
die ständig nach je 32 Adressen abgezogen werden.
Gast #2192494
Lesenswert?

es fängt ja schon hiermit an:

> volatile WORD *short_wr_ptr;
> volatile WORD *long_wr_ptr;

warum soll denn der Bezeichnung nach ein short_wr_ptr und long_wr_ptr 
von gleicher länge( WORD) sein?

Ein long_wr_ptr müsste dem Namenssinn nach ein long = DWORD sein.
also so: volatile DWORD *long_wr_ptr;
Gast #2192504
Lesenswert?

> soweit gehts, nur das ganze ram testen?

Sehr schön, wenn die ersten 50000 bytes schon mal richtig sind, dann ist 
es der Rest auch. Damit testest du das ganze SDRAM, wird aber vllt. ne 
Minute brauchen:

//-----------------------------------

int main(void){

PLL_init();
SDRAM_init();

SDRAM_erase();

for(unsigned long a = 0; a < 32000000; a++)
 {
 SDRAM_write_byte(a,250);
 }

for(unsigned long b = 0; b < 32000000; b++)
 {
 unsigned char buf = 0;
 buf = SDRAM_read_byte(b);
 if( buf != 250)
    {
     RED_LED_ON;  // prüfe auf Korrektheit z.B. mit einer LED
     while(1);
    }
 }
}//main

//-----------------------------------
Gast #2192531
Lesenswert?

Meinetwegen:
Folgende Routine schreibt jeweils 4 bytes (=long) auf einmal
und zwar jedes mal die eigene SDRAM-Daten-Adresse und prüft diese 
anschließend auf korrektheit:

//-----------------------------------

int main(void){

PLL_init();
SDRAM_init();

SDRAM_erase();

for(unsigned long a = 0; a < 8000000; a++)
 {
 SDRAM_write_long(a,a);
 }

for(unsigned long b = 0; b < 8000000; b++)
 {
 unsigned long buf = 0;
 buf = SDRAM_read_long(b);
 if( buf != b)
    {
     RED_LED_ON;  // prüfe auf Korrektheit z.B. mit einer LED
     while(1);
    }
 }
}//main

//-----------------------------------
Gast #2192546
Lesenswert?

falls ich jedoch
1
for(unsigned long a = 0; a < 4000000; a++)
2
 {
3
 SDRAM_write_long(a,a);
4
 }
5

6
for(unsigned long b = 0; b < 4000000; b++)
7
 {
8
 unsigned long buf = 0;
9
 buf = SDRAM_read_long(b);
10
 if( buf != b)
11
    {
12
  //   RED_LED_ON;  // prüfe auf Korrektheit z.B. mit einer LED
13
     while(1);
14
    }
15
 }}

anstelle von
1
for(unsigned long a = 0; a < 8000000; a++)
2
 {
3
 SDRAM_write_long(a,a);
4
 }
5

6
for(unsigned long b = 0; b < 8000000; b++)
7
 {
8
 unsigned long buf = 0;
9
 buf = SDRAM_read_long(b);
10
 if( buf != b)
11
    {
12
  //   RED_LED_ON;  // prüfe auf Korrektheit z.B. mit einer LED
13
     while(1);
14
    }
15
 }}

mache gehts, daher auch meine idee, dass was an der initialisierung faul 
ist
Gast #2192627
Lesenswert?

> Für mich sieht es so aus, als ob er den bereich 2mal beschreibt und zwar
> genau nach der hälfte

Genau, ist ja auch richtig so!

Wenn die Speicheradresse beim Schreiben zu Ende ist, dann wird die 
Adresse automatisch auf den Ursprung zurück gesetzt und man überschreibt 
somit den alten Inhalt, kurz gesagt: wenn man ununterbrochen auf das RAM 
schreibt, dann schreibt man immer im Kreis.
Das siehst du auch an deinem letzten geposteten memory dump. Das letzte 
Programmstück von mir schreibt an jede 32-Bit Adresse seine eigene 
Adresse.
nach 16 Mbyte (= 0x00400000 * 4) schreibt er wieder von vorne und 
beginnt an der Adresse 0x00400001, die aber gar nicht da ist, weil du ja 
dein SDRAM auf 16 Mbyte eingestellt hast. Weil die Testroutine von mir 
dies aber ignoriert, der SDRAM Controller aber nicht, schreibst du 
munter weiter als ob nix wäre.
Gast #2192630
Lesenswert?

Das Timing, die Hardware und alle anderen Einstellungen scheinen also 
korrekt zu funktionieren, nur muss man noch die Größe richtig 
einstellen, hab jetzt leider nicht viel Zeit fürs Datenblatt, aber ich 
komme noch dazu..
Gast #2192705
Lesenswert?

so habe deine vorschläge getestet, bis jetzt hat leider noch nichts zum 
erfolg geführt... mit dem buffer macht keinen unterschied, und wenn ich 
die burst länge respektive die adresse verändere, an der ich den SDRam 
konfiguriere wird es höchstens schlechter anstelle von besser... wäre es 
evtl möglich, dass etwas mit den bankselect leitungen nicht richtig 
funktioniert, dass der ram immer auf den banks 0 und 1 angesprochen 
wird? sprich ba1 immer 0 ist und dadurch der speciher auf den unteren 
beiden banks immer überschrieben wird?
Gast #2193264
Lesenswert?

ist aber so angeschlossen, siehe schema, evtl möglich wäre eine 
schlechte lötstelle oder eine unterbrechung in der leiterbahn, werde ich 
überprüfen sobald ich wieder zuhause bin, das würde erklären, wieso er 
beide mal die gleichen 2 banks beschreibt, wenn die leitung A14 nicht 
richtig verbunden wäre...
Gast #2193339
Lesenswert?

Nein, in deinem Schaltplan sind die Leitungen verdreht:

A14 >> BS0
A13 >> BS1

bei mir sieht es so aus:

A14 >> BS1
A13 >> BS0

Theoretisch müsste es egal sein ob BS0 auf A13 oder A14 kommt, bei mir 
funktioniert das aber so und sogar sehr stabil, nutze das SDRAM als 
Frame_Buffer für ein 7" TFT-LCD mit 800x480 px. Pixelfehler wären sofort 
sichtbar gewesen.
Wie du schon sagtest, piepse mal die Leitungen durch. Wenn alles in 
Ordnung ist, dann kannst ja mal ein Oszi an die BS0/BS1 Leitungen hängen 
oder irgnedwas hochohmiges wie eine LowCurrent LED mit hohem 
Vorwiderstand, um zu schauen, ob der LPC die Leitungen beim Ramtest 
überhaupt wackelt. Wenn dies nicht der Fall sein sollte, dann schau 
nochmal die ganzen PINSELxx Einstellungen an.
Gast #2193377
Lesenswert?

Irgendwie komme ich hier grad etwas durcheinander.

Laut Datenblatt akzeptiert der LPC nur ein
8Mx32 SDRAM mit row length = 13, column length = 8.
das ist auch das, was du eingestellt hast.

Dein SDRAM ist aber laut seinem Datenblatt ein
8Mx32 SDRAM mit row length = 12, column length = 9.

Das würde theoretisch heißen, dass der LPC auf das 9. column bit gar 
nicht zugreifen kann, wodurch dir nur die Hälfte (256 anstatt 512) der 
column Adressen zur Verfügung steht, was somit auch insgesamt nur die 
Hälfte des Gesamtspeichers bedeuten würde.

... Ist aber nur eine Vermutung.
Gast #2193510
Lesenswert?

Ich kenne da leider keinen Trick und ich glaube da gibt es auch keinen, 
der LPC unterstützt zwar column length >= 9 aber nicht bei 32bit SDRAMs. 
Wenn du ins Datenblatt (user manual) vom LPC auf Seite 90 schaust, bei 
allen 32bit SDRAMS ist die column length = 8.
Da ist meiner Meinung nach nichts mehr zu machen.

Zumal, wenn ich fragen darf, wozu brauchst du denn soviel RAM, mit dem 
aktuellen hast du doch schon 16Mbyte sicher.

Antwort schreiben

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren