Forum: Mikrocontroller und Digitale Elektronik Externes RAM am STM32F4 - wie Variable drin platzieren?


von Johannes N. (strangeman)


Lesenswert?

Hallo,

ich möchte gerne das externe RAM auf dem STM32F429-Discovery board 
verwenden, um darin ein riesiges, ca. 7MB großes packed struct zu 
platzieren.
Momentan mache ich das so:
1
#define SDRAM_START_ADR      ((uint32_t)0xD0000000)
2
3
typedef struct __attribute__((__packed__)) 
4
{
5
   // DATEN, DATEN, DATEN
6
   // weitere ineinander verschachtelte packed structs
7
} myMassiveData_t;
8
9
volatile myMassiveData_t* dataPtr = (myMassiveData_t*)(SDRAM_START_ADR);

Später Initialisiere ich das RAM und greife dann so auf die Daten zu:
1
myMassiveData->XYZ = ABC;

Wenn ich einen kurzen Lese/Schreib-Test mache, klappt alles:
1
myMassiveData->XYZ = ABC;
2
if (myMassiveData->XYZ != ABC)
3
{
4
  //ERROR meldung erzeugen
5
}
Es wird kein Fehler gemeldet.

Allerdings kommen bei Lesezugriffen an anderer Stelle im Programm nur 
Murks-Daten raus.
Was mache ich falsch?

Und ist das überhaupt der richtige Ansatz?

Vielen Dank,
Johannes

von Olaf (Gast)


Lesenswert?

> Was mache ich falsch?

Du benutzt keinen Debugger um dir im Fehlerfalle die falschen 
Daten/Adressen anzuschauen. So ein Teil hilft ungemein bei der 
Ueberlagerung von Wunsch und Wirklichkeit.

Olaf

von (prx) A. K. (prx)


Lesenswert?

Gibts für das "volatile" einen konkreten Anlass?

von Jim M. (turboj)


Lesenswert?

Wurde das SDRAM korrekt initialisiert? Du könntest IMO auch mit dem 
Debugger im SDRAM schreiben und lesen.

von Johannes N. (strangeman)


Lesenswert?

Hallo Olaf,

doch, ich arbeite mit CooCox/CoIDE und nutze dort natürlich den 
Debugger. Wenn ich mir dort den Wert von Variablen ansehe (z.B. indem 
ich mit der Maus darüber "hovere") sehe ich die Murks-Daten.
Interessanterweise auch während des oben gezeigten Leses/Schreib-Tests. 
ich aknn dort genau sehen, dass das Beschreiben der Speicherbereiche 
keinen Effekt hat. Allerdings schlägt der Test nicht fehl, insofern 
hielt ich das, was ich da im Debugger sah für falsch.

Hallo A.K.,

volatile hatte ich gewählt, damit mich die Code-Optimierung nicht bei 
meinem Schreib-/Lese-Test stört.

von Helmut S. (helmuts)


Lesenswert?

Hast du das SDRAM auch konfiguriert?
http://en.radzio.dxp.pl/stm32f429idiscovery/sdram.html

von Johannes N. (strangeman)


Lesenswert?

Hallo,

das SRAM habe ich mit den Funktionen von dieser Webseite initialisiert: 
http://mikrocontroller.bplaced.net/wordpress/?page_id=2747

von Olaf (Gast)


Lesenswert?

> Allerdings schlägt der Test nicht fehl, insofern
> hielt ich das, was ich da im Debugger sah für falsch.

Das ist aber doch eine sehr gewagte Annahme oder? :-)
Normalerweise kannst du einem Deubugger schon trauen.

Schreibt also mal was in dein Ram, liess es, schaue dir nicht nur die 
Daten an sondern auch die Adressen und liess es noch mal nach 100ms 
Wartezeit.

Ausserdem pruefe mal wie deine MCU byteweise auf externes Ram zugreift. 
Also mit anderen Worten kann sie ueberhaubt was du da willst.

Olaf

von Bernd K. (prof7bit)


Lesenswert?

Johannes Neumann schrieb:
> __attribute__((_packed_))

Ok, das ist jetzt wahrscheinlich nicht direkt mit dem Problem verbunden, 
daher nur ganz am Rande gefragt: Gibt es wirklich einen zwingenden Grund 
_packed_ zu verwenden? Kannst Du nicht stattdessen die Felder des 
Structs so anordnen daß alles ordentlich aligned ist und ggf heftige 
erzwungene Verrenkungen des Compilers vermieden werden?

von Helmut S. (helmuts)


Lesenswert?

Johannes Neumann schrieb:
> Hallo,
>
> das SRAM habe ich mit den Funktionen von dieser Webseite initialisiert:
> http://mikrocontroller.bplaced.net/wordpress/?page_id=2747

if(ramcheck==SUCCESS) {
      // wenn kein Fehler -> gruene LED leuchtet
      UB_Led_On(LED_GREEN);

Geht die grüne LED anch dem RAM-test an?

von Johannes N. (strangeman)


Lesenswert?

Hallo,

Ja, das RAM wird korrekt initialisiert.
ich bin dem Fehler inzwischen ein Stück näher:

Das hier funktioniert nicht, der Schreibzugriff hat keinen Effekt.
1
  typedef struct {
2
    int test;
3
    int test2;
4
    int test3;
5
  } test_t;
6
7
  volatile test_t* t = (volatile test_t*)((uint32_t)0xD0000000);
8
  t->test = 0xABCD;
9
  t->test2 = 0x1234;

Das hier funktioniert allerdings:
1
  (*(volatile test_t*)((uint32_t)0xD0000000)).test = 150;
2
  int readback = (*(volatile test_t*)((uint32_t)0xD0000000)).test;
3
  //                                                          |
4
  // Debugger zeigt hierfür Null an <-------------------------+

Es scheint also etwas damit zu tun zu haben, dass ich pointer verwende.
Übrigens zeigt der Debugger für das letzte ".test" den Wert 0 an, obwohl 
150 gelesen werden. Hä?

@Bernd:
Ja, das packed muss leider sein, sonst passen meine Daten nicht ins 
RAM...

von link oder nicht? (Gast)


Lesenswert?

Mal 2 Dinge, du hast den Speicher nicht allokiert, sondern schreibst 
einfach irgendwo hin. Und du beschreibst den signed int mit hex. Hast du 
richtig zurück gerechnet?

Mach den Speicher über den Linker bekannt und lege deine Variable in das 
neue Segment.

von Johannes N. (strangeman)


Lesenswert?

Nein, der Speicher wird nicht allokiert - warum auch? Niemand sonst wird 
darin herumschreiben. Der Linker kennt den Speicher nicht mal.

Ja, es wäre natürlich insgesamt sicherlich nicht schlecht, wenn ich das 
Ding dem Linker bekannt machen würde, dazu müsste ich das Linker Script 
bearbeiten. Ich habe dazu schon ein wenig herumgegoogelt, aber da das 
alles extrem platformspezifisch ist, finde ich wenig, was mir hilft. Die 
Syntax des Linker Scripts ist mir einfach nicht geläufig.

Soviel habe ich verstanden:
Ich muss einen neuen Speicher Bereich anlegen:
1
MEMORY
2
{
3
  rom (rx)  : ORIGIN = 0x08000000, LENGTH = 0x00100000
4
  ram (rwx) : ORIGIN = 0x20000000, LENGTH = 0x00020000
5
  ram1 (rwx) : ORIGIN = 0x10000000, LENGTH = 0x00010000
6
  extram (rwx) : ORIGIN = 0xD0000000, LENGTH = 0x800000
7
}

und dann irgendwie diesen Bereich zuordnen, sowie das Alignment 
klarmachen:
1
SECTIONS 
2
{
3
   /* ... hier der Rest ... */
4
   .extdata : 
5
   {
6
      . = ALIGN(4);
7
   } > extram
8
}

Aber reicht das schon so?

von Christian J. (Gast)


Lesenswert?

Bastel das hier mal in das Linker Skript

/* 8MB externes SDRAM */
      .sdram (NOLOAD):
  {
      . = ALIGN(4);
      *(.sdram)
  } > sdram

Dazu das

MEMORY
{
    flash (rx)  : ORIGIN = 0x08000000, LENGTH = 2048K
    ram (xrw)   : ORIGIN = 0x20000000, LENGTH = 192K
    ccram (rw)  : ORIGIN = 0x10000000, LENGTH = 64K
    sdram (rwx) : ORIGIN = 0xD0100000, LENGTH = 7M  /* 7 MB */
}

(1 MB fuer Videoram allokiert, daher 0xD01)

und dann überlass es dem Compiler wo er was hinlegt.

#define SDRAM __attribute__((section(".sdram")))

int SDRAM MeineVariable;
Blabla


>> aber da das alles extrem platformspezifisch ist,

Nix ist das. Ist GCC spezifisch. Nur macht jeder Bauer sein eigenes 
Feld, bzw Linker Skript.

von Johannes N. (strangeman)


Lesenswert?

Hallo Christian,

vielen Dank, das funktioniert :)
Interessanterweise zeigt der Debugger immernoch für alle Werte jeweils 
0x00 an.

Jedenfalls funktioniert jetzt das Schreiben und Lesen des RAMs. Danke!
Kannst du kurz erklären, was diese Zeilen jetzt aussagen:
>     .sdram (NOLOAD):
>  {
>      . = ALIGN(4);
>      *(.sdram)
>  } > sdram

von linker oder nicht? (Gast)


Lesenswert?

... dem Linker, wo er was hinlegte ... ;-)

von Christian J. (Gast)


Lesenswert?

Johannes Neumann schrieb:

> vielen Dank, das funktioniert :)
> Interessanterweise zeigt der Debugger immernoch für alle Werte jeweils
> 0x00 an.

Also mein EmBlocks zeigt das an was drin steht, im Dump aber auch beim 
"Hovern" bzw Watch fenster. Schon sehr seltsam, es sei denn der Debugger 
weiss nicht wo er die Variable finden kann. Aber das steht ja im .o 
File, wen die Debug Infos eingeschaltet wurden. (Na...?) Ich habe da 
"maximal" eingestellt bei den GCC Options.

> Jedenfalls funktioniert jetzt das Schreiben und Lesen des RAMs. Danke!
> Kannst du kurz erklären, was diese Zeilen jetzt aussagen:

>     .sdram (NOLOAD):

Section Name .sdram (markiert als "not loadable")

>  {

Eine Klammer

>      . = ALIGN(4);

4 Byte Ausrichhtung (big endian?)

>      *(.sdram)

???

>  }

Noch eine Klammer

 > sdram

Alles was reinkommt über der Section Startadresse schreiben

Genaues vielleicht hier:

http://www.scoberlin.de/content/media/http/informatik/gcc_docs/ld_3.html

von linker oder nicht? (Gast)


Lesenswert?

sdram hast du selber unter Memory deklariert. Jetzt teilst du das 
Stück Speicher in Sections, oder in eine große. ;-)

von Christian J. (Gast)


Lesenswert?

Nachwort zum SDRAM:

Ist schön gross (wow!) aber wenn das das Video auch noch läuft und per 
DMA2 angeschlossen ist, ist der Bus dermassen dicht, dass alles heftig 
langsamer läuft, was auf das übrige SDRAM zugreift.

von Johannes N. (strangeman)


Lesenswert?

Bei mir ist kein Video im RAM, stattdessen Musik-Noten und 
Soundparameter für einen Sequencer.
Ja, da wird auch viel zugegriffen, aber hoffentlich weniger als bei 
Videoplayback.

Danke für den Link zum Linker-Script. Meine Frage bezog sich eher auf 
Dinge wie "NOLOAD" - aber das steht dort ja alles drin. Werde ich mir 
mal in Ruhe zu Gemüte führen.

Danke nochmal an alle!

von Christian J. (Gast)


Lesenswert?

Was du hierbei beachten solltest ist, dass Konstrukte wie

global:
int SDRAM testvar = 45;

lokal:
static int SDRAM testvar = 45;

(geht lokal eh nicht, da attribute dort verboten.)

nicht funktonieren! Es gibt nämlich keinen Initializer, der das beim Run 
übernimmt. Die 45 steht im Flash irgendwo aber nicht wird hochkopiert.

Das NOLOAD soll das auch ausdrücken. Um das zu ändern bedarf einer 
Kopierroutine, die in den Startup Code rein muss. Für das .bss Segment 
ist sie schon da. Gilt aber auch für das Core CCRAM.


Bei mir wird das SDRAM gleich immer mit gestartet, ohne dass ich was 
aufrufen muss. Hab das noch dazu gefrickelt. Eine Initialisierung von 
Variablen würde nach dem Schema unten auch für SDRAM gehen. Nur zwei 
Start und Endpunkte hin definieren.

1
/*----------Symbols defined in linker script----------------------------------*/
2
extern unsigned long _sidata;    /*!< Start address for the initialization
3
                                      values of the .data section.            */
4
extern unsigned long _sdata;     /*!< Start address for the .data section     */
5
extern unsigned long _edata;     /*!< End address for the .data section       */
6
extern unsigned long _sbss;      /*!< Start address for the .bss section      */
7
extern unsigned long _ebss;      /*!< End address for the .bss section        */
8
extern void _eram;               /*!< End address for ram                     */
9
10
void Default_Reset_Handler(void)
11
{
12
  /* Initialize data and bss */
13
  unsigned long *pulSrc, *pulDest;
14
15
  /* Copy the data segment initializers from flash to SRAM */
16
  pulSrc = &_sidata;
17
18
  for(pulDest = &_sdata; pulDest < &_edata; )
19
  {
20
    *(pulDest++) = *(pulSrc++);
21
  }
22
23
  /* Zero fill the bss segment.  This is done with inline assembly since this
24
     will clear the value of pulDest if it is not kept in a register. */
25
  __asm("  ldr     r0, =_sbss\n"
26
        "  ldr     r1, =_ebss\n"
27
        "  mov     r2, #0\n"
28
        "  .thumb_func\n"
29
        "zero_loop:\n"
30
        "    cmp     r0, r1\n"
31
        "    it      lt\n"
32
        "    strlt   r2, [r0], #4\n"
33
        "    blt     zero_loop");
34
#ifdef __FPU_USED
35
  /* Enable FPU.*/
36
  __asm("  LDR.W R0, =0xE000ED88\n"
37
        "  LDR R1, [R0]\n"
38
        "  ORR R1, R1, #(0xF << 20)\n"
39
        "  STR R1, [R0]");
40
#endif
41
42
/* Enable external SDRAM */
43
#ifdef DATA_IN_ExtSDRAM
44
    SystemInit_ExtMemCtl();
45
#endif
46
47
  /* Call the application's entry point.*/
48
  main();
49
}

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.