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
typedefstruct__attribute__((__packed__))
4
{
5
// DATEN, DATEN, DATEN
6
// weitere ineinander verschachtelte packed structs
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
> 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
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.
> 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
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?
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.
// 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...
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.
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
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.
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
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
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.
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!
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. */