Forum: Mikrocontroller und Digitale Elektronik Nervenzusammenbruch - Speichertest auf ARM9


von Rudolf M. (Gast)


Lesenswert?

Hall, ich kriege hier die Krise. Mein Speichertest auf meinem ARM9 
(AT91RM9200) funktioniert wunderbar. Und zwar so wunderbar, dass er 
überall - selbst dort, wo gar kein SDRAM gemappt ist, alles als in 
Ordnung erkennt. Jetzt ist das Programm relativ trivial - einfach einen 
Wert an eine Stelle schreiben und zurücklesen. Was kann hier schon 
falsch sein? Ich komme einfach nicht mehr weiter. Lässt man die Adresse 
allerdings in einen "undefinierten" Bereich laufen, kommt die 
entsprechende Exception. Das zumindest funktioniert also.

Wer kann sich das mal ansehen:
1
void memtest (void)
2
{
3
4
  volatile unsigned long *addr, *start, *end;
5
  volatile unsigned long *dummy = 0;
6
  volatile unsigned long value;
7
  volatile unsigned long readback;
8
  int i;
9
10
  static const unsigned long bitpattern[] =
11
  {
12
    0xFFFFFFFF,
13
    0x00000000,
14
    0x55555555,
15
    0xAAAAAAAA,
16
  };
17
18
  start = (unsigned long *)BOARD_SDRAM_START;
19
  end   = (unsigned long *)BOARD_SDRAM_END;
20
  addr  = start;
21
22
  while (addr < end)
23
  {
24
    for (i = 0; i < sizeof(bitpattern)/sizeof(bitpattern[0]); i++)
25
    {
26
      value = bitpattern[i];
27
      readback = ~bitpattern[i];
28
      *addr = value;
29
      *dummy = ~value;
30
      readback = *addr;
31
      if(readback != value)
32
      {
33
        dbgu_printf("Error at adress %x while testing SDRAM!\n\r", addr);
34
        while (1==1);
35
      }
36
    }
37
    addr = addr + 1;
38
  }
39
40
  dbgu_printf("SDRAM OK\n\r");
41
42
}

von Markus M. (Firma: EleLa - www.elela.de) (mmvisual)


Lesenswert?

Wegen:

addr = addr + 1;

müsste es nich so heisen:

addr = addr + sizeof(unsigned long);

oder:

addr++;

Müsste man im Debugger anschauen, welche wie er die Adresse 
incrementiert.


Ich weiß jetzt nicht wie der CS für den externen RAM parametriert wurde, 
aber kann es sein, dass der für den gesammten vom Prozessor vorgesehenen 
RAM Bereich auf L geht?
Dann wird ist der RAM nämlich gespiegelt auf vielen Adressen.

von Peter D. (peda)


Lesenswert?

Rudolf M. schrieb:
> Jetzt ist das Programm relativ trivial - einfach einen
> Wert an eine Stelle schreiben und zurücklesen. Was kann hier schon
> falsch sein?

Das Prinzip.
Die Kapazität der offenen Pins wirkt quasi als Wort-DRAM.
Dein "dummy" wird warscheinlich nicht auf den DRAM zeigen, also erfolgt 
auch kein DRAM-Zugriff.

Ist es überhaupt erlaubt, eine Zeiger auf 0 zu setzen und damit auf die 
Adresse 0 zu schreiben?
Die Adreßvergabe sollte man besser dem Linker überlassen.


Peter

von Tom M. (tomm) Benutzerseite


Lesenswert?

> müsste es nich so heisen:
>
> addr = addr + sizeof(unsigned long);

Nein. addr ist ein Zeiger auf unsigned long. Ein Inkrement lässt den 
Zeiger auf das nächste Element zeigen.

von mach zwei (Gast)


Lesenswert?

Ändere mal dein Programm dahin, dass du zwei for-Schleifen hast.
In der ersten Schleife schreibst du deine 4 Worte und in der zweiten 
Schleife liest du deine 4 Worte.

von Strubi (Gast)


Lesenswert?

Hi,

Haette auch mal auf Mirroring (Spiegelung) getippt. Das kann vorkommen, 
wenn die SDRAM-Bankgroesse nicht richtig konfiguriert ist. Dann 
funktioniert der "lokale" Memorytest prima auch auf den ansich 
ungemappten Adressen. Kann auch vorkommen, dass die Speichergroesse 
richtig detektiert wird, aber deine Programme (die mehrere Baenke 
benutzen) fiese Effekte zeigen.
Bei manchen Architekturen koennte es auch ohne Fehlkonfiguration 
vorkommen.
Deswegen solltest du vielleicht deinen Test etwas umstricken:

- Erst den Speicher in logischen Page-Grössen (1024 * n) aufteilen und 
am Anfang in jede Page eine eindeutige Page-Magic (oder einfach einen 
Zaehler) schreiben
- Im zweiten Durchlauf die Nummern checken. So detektierst du die 
effektive Speichergroesse.

Gruss,

- Strubi

von Ich (Gast)


Lesenswert?

Hallo,
bei einem SDRAM test macht es wenig Sinn die eben geschriebene Stelle 
wieder zu prüfen. Du willst ja auch feststellen das die Refresh Zyklen 
richtig funktionieren.
Besser ist es den Bereich mit einem Muster zu bespielen und dann 
mehrmals wieder auszulesen. Vor dem Auslesen würde ich auch kurz warten 
so das der Refresh auch zuschlägt. Denn wenn du eine Zelle liest machst 
du automatisch einen refresh.
Das ganze machst du dann mit verschiedenen Mustern und 
Umgebungstemperaturen.

von Magnus M. (magnetus) Benutzerseite


Lesenswert?

Peter Dannegger schrieb:
> Rudolf M. schrieb:
>> Jetzt ist das Programm relativ trivial - einfach einen
>> Wert an eine Stelle schreiben und zurücklesen. Was kann hier schon
>> falsch sein?
>
> Das Prinzip.
> Die Kapazität der offenen Pins wirkt quasi als Wort-DRAM.

Ich stimme der Aussage von Peter zu.

Du kannst das überprüfen indem du mal probehalber Pullups oder Pulldowns 
an die Datenleitungen hängst. Dann wird dir dein Programm in den nicht 
belegten Bereichen auch Fehler melden.

Gruß,
Magnetus

von weissnix (Gast)


Lesenswert?

Ohne mich weiter mit ARM9 auszukennen, aber kann es sein, dass du in den 
Cache schreibst und auch gleich wieder aus dem Cache liest?

von Helmut S. (helmuts)


Lesenswert?

weissnix schrieb:
> Ohne mich weiter mit ARM9 auszukennen, aber kann es sein, dass du in den
> Cache schreibst und auch gleich wieder aus dem Cache liest?

Da möchte ich noch eine Frage anschließen.
Wie kann man im C-Programm den Cache abschalten?

von weissnix (Gast)


Lesenswert?

Helmut S. schrieb:
> Da möchte ich noch eine Frage anschließen.
> Wie kann man im C-Programm den Cache abschalten?
Gute Frage!
Aus dem Buch Linux-Gerätetreiber: "Die [...] MIPS-Prozessoren machen 
dies auf sehr interessante Weise. Zwei Adressbereiche mit je 512 MByte 
werden direkt auf physikalische Adressen abgebildet. Jeder 
Speicherzugriff auf einen dieser Adreßbereiche geht an der MMU wie auch 
am Cache vorbei.

von weissnix (Gast)


Lesenswert?

Ups, zu schnell gesendet.

Wie das bei ARM9 funktioniert weiß ich nicht. Ich nehme aber mal an, 
dass man das ohne Plattform Kenntnisse gar nicht in einem Plattform 
unabhängigen C Programm lösen kann.

von abc (Gast)


Lesenswert?

Moin.

der Cach controller über ASM befehle configuriert. Näheres dazu findet 
sich im Handbuch zum Core. Link müsste sich aufs attmels seite finden 
lassen.

Der Cach Controler oder MPU oder MPC wird bei arm wie ein Co Processor 
angesprochen.

von Rudolf M. (Gast)


Lesenswert?

Data cache war aus, der Bootloader schaltet den noch nicht ein. Die 
Speicherkonfiguration war auch ok. Das Kapazitätsproblem auf dem Bus 
wollte ich mit dem Dummy-Zugriff auf die Adresse 0 umgehen. 
Normalerweise sollte das funktionieren.

Ich habe jetzt einfach alle
1
1024*1024/sizeof(addr)
 Adressen die Adresse selbst in den Speicher geschrieben. Beim Auslesen 
konnte ich dann feststellen, dass der Speicher vom SDRAM Controller 
tatsächlich mehrfach hintereinander auf einen großen Adressbereich 
abgebildet wird, so dass man eine Speicherzelle nach dem Ende wieder am 
Anfang landet. Das Datenblatt schweigt sich zu diesem Thema leider aus.

Indem ich in einer ersten Schleife in Megabyte-Abständen die jeweilige 
Adresse in die Speicherzelle schreibe und in einer zweiten Schleife die 
beiden Werte wieder vergleiche, kann ich den tatsächlich vorhandenen 
Speicher feststellen.

Das Ergebnis sind die erwarteten 32 MB, damit ist alles in Butter. Danke 
für die Tips!

von Ulrich P. (uprinz)


Lesenswert?

Rodolfs Problem ist gelöst, trotzdem mal noch ein Tip.

Generell macht man einen Speichertest in dem man einen String in das RAM 
schreibt und diesen wieder ausliest. Dabei sollte der String aus 
zufälligen Werten bestehen, die alle Datenleitungen benötigen, also 
nicht nur ein lustiger Text, sondern ein lustiger Text mit Sonderzeichen 
> ASCII 128.
Außerdem sollte der String eine ungerade länge relativ zum 
Speicheraufbau (Pages/Rows/Columns) haben.

Nur damit kann man erkennen, ob Bits vertauscht und Seiten oder 
komplette RAMs vollständig durch adressiert werden können. Damit kann 
man auch erkennen, wann man, wie Rudolfs Aufbau, im Shadow gelandet ist. 
Man kann den String übrigens auch absichtlich länger als den Cache einer 
CPU machen, so dass das 'durchschreiben' ins physikalische RAM auch dann 
garantiert ist, wenn man sich über die Verwendung von *(volatile void*) 
nicht im klaren ist oder man die Konfiguration des Cache-Controllers 
noch nicht völlig implementiert hat.

Gruß, Ulrich

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.