Hallo zusammen, ich möchte gerne auf einen externen SDRAM zugreifen, deswegen habe ich den Speicherbereich im linkerscript hinzugefügt: MEMORY { flash (rx) : ORIGIN = 0x00000000, LENGTH = 512K ram (rw) : ORIGIN = 0x40000000, LENGTH = 30720 sdram (rw) : ORIGIN = 0xA0000000, LENGTH = 33554432 } ... sdramlayout : { _sdram_start_ = 0xA0000000; *(.sdramdata) _sdram_end_ = 0x02000000; } > sdram und einen Macro definiert : #define SDRAMDATA _attribute_ ((section (".sdramdata"))) 1.das erste Problem ist, der Compiler baucht mehr Zeit als sonst um den Code zu übersetzen. 2.wenn im Map reinschaue, finde ich folgendes: sdramlayout 0xa0000000 0x2000000 0x40000000 _sdram_start_ = 0xa0000000 *(.sdramdata) .sdramdata 0xa0000000 0x2000000 ./release/ringbuffer.o 0xa0000000 ringbuffer 0xa2000000 _sdram_end_ = 0x2000000 das ganze stimmt bis auf die zweite zeile (0x40000000), was hat diese Adresse hier zu suchen? 3.der Flash Magic verhält sich komisch; es dauert erstmal ewig bis er eine Verbindung mit dem Board erfolgt, und wenn die Sektore die er braucht gelöscht hat, dauert es wieder ewig bis er angefangen hat zu fläshen. muss ich vielleicht was anders im linkerskript hinzufügen? ich bin für jeden Tip dankbar
Auf http://en.mikrocontroller.net gibt es ein paar mehr, die davon Anhnung haben. Umgangssprache ist allerdings Englisch. Ich persönlich traue mich nicht, was zu deinem Linkerskript zu beantworten, weil ich mit ... Zeilen in der Frage nichts anfangen kann. Und bevor ich mich mit Spekulationen ala "Da ist ... falsch oder ..." zum Affen mache, lasse ich es.
Welcher Baustein denn? Von den LPC2000 unterstuetzen nur sehr wenige externes DRAM. Das waere die LPC24xx und evtl. der LPC28xx und sonst nichts. Ohne DRAM controller gestaltet sich die Sache ziemlich schwierig. Robert
Betr. Linker-script. Leider grade keine GNU arm Crosstoolchain zur Hand zum Testen, daher erstmal nur ein paar Fragen: Warum die absolute Angabe von Addressen in der linker-section? Benötigte Addresse steht bereits bei Memory, den Rest lässt man den Linker ausrechnen. Warum grade diese "end-addresse"? Was gibt der Linker als VMA und LMA für die neue section aus? Prinzip von LMA und VMA halbwegs verinnerlicht? Linker-manual durchgelesen (GNU bintutils)? Ist das binary/hex-file extrem gross? Initialisierung der Daten im externen RAM erforderlich? Wie ist ROM/RAM-copy und zero-init dafür implementiert? Die STR710-Beispiele von Anglia-Designs angeschaut (google anglia idealist)? In denen finden sich, wenn recht erinnert, ein paar Beispiele für internes und externes RAM für GNU toolchain inkl. Linker-Scripten. Auch Linkerscripte für GBA sind recht nützlich, da das Teil verschiedenste Speicher bietet. Martin Thomas
Danke für die Antworten. @Robert teufel: es geht um LPC2468, ich benutze die EMC-Initialisierungsroutine von NXP. @Martin Thomas: sorry vielleicht musste ich das ganze linkerskript posten: * ------------------------------------ 0xFFFF FFFF * | | * | AHB Peripherals | * | | * |----------------------------------| 0xF000 0000 * | | * | APB Peripherals | * | | * |----------------------------------| 0xE000 0000 * | [Reserved] | * |----------------------------------| 0x8000 0000 * | | * | Boot block | * | | * |----------------------------------| * | [Reserved] | * |----------------------------------| 0x7FE0 4000 * | Ethernet RAM | 16384 bytes (0x4000) * |----------------------------------| 0x7FE0 0000 * | [Reserved] | * |----------------------------------| 0x7FD0 2000 * | USB RAM | 8192 bytes (0x2000) * |----------------------------------| 0x7FD0 0000 * | [Reserved] | * |----------------------------------| 0x4000 8000 * | | Reserved for IAP | 256 bytes (0x100) * | |---------------------| 0x4000 7F00 * | | UND Stack | 256 bytes (0x100) * | Internal |---------------------| 0x4000 7E00 * | RAM | FIQ Stack | 256 bytes (0x100) * | |---------------------| 0x4000 7D00 * | | IRQ Stack | 256 bytes (0x100) * | |---------------------| 0x4000 7C00 * | | SVC Stack | 1024 bytes (0x400) * | |---------------------| 0x4000 7800 * | | Variables RW and ZI | 30720 bytes (0x7800) * |----------------------------------| 0x4000 0000 * | [Reserved] | * |----------------------------------| 0x0008 0000 * | | * | Flash | 512K * | | * | | * ------------------------------------ 0x00000000 * UND Stack is used by HaltUndef, HaltSWI, HaltPabort and HaldAabort * ********************************************************************/ /* * Defines memory layout */ MEMORY { flash (rx) : ORIGIN = 0x00000000, LENGTH = 512K ram (rw) : ORIGIN = 0x40000000, LENGTH = 30720 ramstack (rw) : ORIGIN = 0x40007800, LENGTH = 2048 usbram (rw) : ORIGIN = 0x7FD00000, LENGTH = 8K ethram (rw) : ORIGIN = 0x7FE00000, LENGTH = 16K sdram (rw) : ORIGIN = 0xA0000000, LENGTH = 33554432 } /* * Define entry point, found in startarm.s */ ENTRY(_reset_handler) /* * Sections */ SECTIONS { /* Place memory counter at address 0 */ . = 0; /* Place startup code at start of flash */ startup : { *(.startup) } > flash =0 . = ALIGN(4); /* Place program code */ prog : { *(.text) *(.rodata) *(.rodata*) *(glue_7) *(glue_7t) } > flash =0 . = ALIGN(4); _end_of_text_ = .; _data_beg_src_ = .; PROVIDE(etext = .); /* Place initialized data */ .data : AT(_data_beg_src_) { _data_beg_ = .; *(.data) } > ram . = ALIGN(4); _data_end_ = .; PROVIDE(edata = .); /* Place zero initialized data */ .bss : { _bss_beg_ = .; *(.bss) } >ram /* Align here to ensure that the .bss section occupies space up to _end. Align after .bss to ensure correct alignment even if the .bss section disappears because there are no input sections. */ . = ALIGN(32 / 8); . = ALIGN(32 / 8); /* Provide end markers */ _end = .; bss_end_ = .; _bss_end_ = .; _end_ = .; PROVIDE(end = .); stacklayout : { _stack_scv_bottom_ = .; . = . + 0x0400; _stack_scv_top_ = .; _stack_irq_bottom_ = .; . = . + 0x0100; _stack_irq_top_ = .; _stack_fiq_bottom_ = .; . = . + 0x0100; _stack_fiq_top_ = .; _stack_und_bottom_ = .; . = . + 0x0100; _stack_und_top_ = .; _stack_iap_bottom_ = .; } >ramstack usbramlayout : { _usbram_start_ = .; _usbram_end_ = 0x2000; } >usbram ethramlayout : { _ethram_start_ = .; _ethram_end_ = 0x4000; } > ethram sdramlayout : { _sdram_start_ = 0xA0000000; *(.sdramdata) _sdram_end_ = 0x02000000; } > sdram Nun, wie soll ich jetzt das schreiben, damit das linkerscript zum SDRAM Startadresse springt? Soweit ich weiss LMA ist die adresse wo der einzelnen Sections geladen werden, und VMA wo die dann ausgeführt werden, wie kann ich das jetzt für meinen Fall im Linkerscript umsetzen.
vielleicht muss ich meine Frage deulicher ausdrücken; ich will auf einen SDRAM zugreifen um Daten drauf zu speichern, stimmt dann mein Linkerskript daoben? wenn nicht was fehlt denn da? Es wäre noch super wenn ihr einen Beispiel habt. Danke im Voraus.
Es gibt bei NXP einen Beispielcode: Sample Code Bundle for LPC23xx/LPC24xx Peripherals using Keil's μVision, V1.50 http://www.standardics.nxp.com/support/documents/microcontrollers/zip/code.bundle.lpc23xx.lpc24xx.uvision.zip Darin ist im Verzeichnis EXTMEM/SDRAM ein Beispiel zum Ansteuern eines SDRAM an Basisadresse 0xA0000000 und Länge 0x02000000 inkl. Schreiben/Lesen. Technisch ist das so gelöst, dass dem External Memory Controller (EMC) des LPC2468 die Basisadresse des SDRAM und die Länge und das Timing... bekannt gemacht wird (ex_sdram.c) und anschliessend Zugriffe über Pointer in den Adressraum erfolgen (sdram_test.c). Der EMC kümmert sich darum, dass diese Zugriffe korrekt ablaufen. Dem Linker ist bei der dort verwendeten Methode das SDRAM schnurz, er kennt das nicht (als was besonderes). Bei deiner Methode mit der eigenen Section (bei der du auch irgendwo z.B. im Startupcode eine Initialisierung brauchst!) hängen die langen Zeiten beim Linken + Löschen IMHO damit zusammen, dass die von dir bekannt gemachten 32 MB auch bearbeitet werden wollen z.B. vorm Flashen gelöscht werden und beim Flashen ggf. beschrieben werden wollen (wenn du irgendwas in der Sektion .sdramdata abgelegt hast). Aber das ist nur meine Laienmeinung, warte mal ab, was die Experten dazu sagen, wenn sie Zeit haben. Nicht zu ungeduldig sein.
Danke Stefan, das Beispiel von NXP benutze ich zum EMC Initialisierung, ich dachte eigentlich, dass man den EMC-Controller benutzt, um die Zugriffszyklen, den Adress- und Databus zu initialisieren, die Speicherorganisation übernimmt dann der Linker, und dachte auch dass die NXP-examples mit Keil-uvision entwicklet wurde D.h. dass der linkerscript dementsprechend automatisch generiert wird. Es ist auf jeden fall ein Versuch Wert; ich werde es so probieren wie im "sdram_test.c" ohne den Linkerscript zu ändern und dann sehen wir was passiert.
Das ist grundsätzlich richtig gedacht. Die Zuordnungen Variable => Adresse könnten vom Linker automatisch zur Compilezeit gemacht werden und müssten nicht explizit von dir zur Compile- oder Laufzeit gemacht werden. Das würde später einen deutlich aufgeräumteren Quellcode ergeben. Nur - Ich kenne die Syntax nicht, um das linker control script zu schreiben. Deine Version legt ja die Sektion .sdramdata an der richtigen Stelle an und sieht deshalb für mich korrekt aus. Ich kann aber nicht sagen, woher die 0x40000000 kommt, die dich stutzig macht. Gibt eigentlich der Compiler/Linker Fehler/Warnungen aus oder macht dich nur das Mapfile skeptisch? Wenn du eine Variable in .sdramdata definierst, wie sieht die Ausgabe im Mapfile aus?
Ich bin nur nicht sicher, ob das so richtig ist, mit linkerskript habe ich überhaupt keine Erfahrung, was mich auch noch skiptisch gemacht hat, war dieses komische Verhalten vom Compiler und dem Flash-Programm, aber deine Erklärung klingt logisch, ich versuche es anderes und dann werde ich dir Bescheid sagen.
Folgendes nur als Vorschlag, grade nichts zur Hand um es in einem Simulator oder "in Hardware" auszuprobieren. 1. Im C-Code nutzt man zwei selbstdefinierte sections. Eine für zu initialisierende Daten im externen Speicher. Entspricht .data bei initialisierten Daten ohne Attribut. Die andere section für Variablen im externen Speicher, die mit 0 zu initialisieren sind (entspr. .bss). Also zum Beispiel:
1 | #define EDATA __attribute__ ((section (".exdata_section")))
|
2 | #define EBSS __attribute__ ((section (".exbss_section")))
|
3 | int foo1 EDATA = 123; |
4 | int foo2 EBSS; |
5 | int foo3[] EDATA = { 1, 2, 3 }; |
2. Den Speicherbereich in MEMORY habe ich einfach mal EXTRAM genannt und testweise so definiert:
1 | MEMORY |
2 | { |
3 | ROM (rx) : ORIGIN = 0x00000000, LENGTH = 0x0003E000 |
4 | RAM (rw) : ORIGIN = 0x40000000, LENGTH = 0x00004000 |
5 | EXTRAM (RW) : ORIGIN = 0xA0000000, LENGTH = 32k |
6 | } |
3. Nun ist dafür zu sorgen, dass die Initialisierungswerte für die Variablen in "EDATA" im FLASH stehen und man sowohl die Addresse der Initialiserungswerte (Kopierquelle) und die Zieladdress dieser Daten (Kopierziel) kennt. Weiterhin muss der Addressebereich von "EBSS" bekannt sein, um diesen mit 0 vorzubelegen. Habe in Linkerscript von einem anderen Projekt genutzt und zwischen "schnipp" und "schnapp" ergänzt:
1 | .data : AT (_etext) |
2 | { |
3 | _data = .; |
4 | *(.data) |
5 | SORT(CONSTRUCTORS) |
6 | } > RAM |
7 | . = ALIGN(4); |
8 | _edata = . ; |
9 | PROVIDE (edata = .); |
10 | |
11 | /* schnipp */ |
12 | |
13 | _edata_LMA = LOADADDR(.data) + SIZEOF(.data); |
14 | .extdata : AT (_edata_LMA) |
15 | { |
16 | _extdata_start = .; |
17 | *(.exdata_section) |
18 | _extdata_end = .; |
19 | } > EXTRAM |
20 | |
21 | .extbss (NOLOAD) : |
22 | { |
23 | _exbss_start = .; |
24 | *(.exbss_section) |
25 | _exbss_end = .; |
26 | } > EXTRAM |
27 | |
28 | /* schnapp */ |
29 | |
30 | /* .bss section which is used for uninitialized data */ |
31 | .bss (NOLOAD) : |
32 | { |
33 | __bss_start = . ; |
34 | __bss_start__ = . ; |
35 | *(.bss) |
36 | *(COMMON) |
37 | . = ALIGN(4); |
38 | } > RAM |
39 | |
40 | . = ALIGN(4); |
41 | __bss_end__ = . ; |
42 | PROVIDE (__bss_end = .); |
Das gibt in einem kleinen Beispiel mit ein paar Variablen folgende Addressen für die Symbole (Ausgabe vomn nm), die zumindest plausibel erscheinen:
1 | ... |
2 | 000002a0 A _etext |
3 | 000002a4 A _edata_LMA |
4 | 00000400 A STACK_SIZE |
5 | 40000000 D _data |
6 | 40000000 d foodata2 |
7 | 40000004 B __bss_start |
8 | 40000004 B __bss_start__ |
9 | 40000004 A _edata |
10 | 40000004 b foobss2 |
11 | 40000008 A __bss_end__ |
12 | 40000500 A _end |
13 | 40000500 B _stack |
14 | a0000000 D _extdata_start |
15 | a0000000 d foo3 |
16 | a000000c d foo1 |
17 | a0000010 B _exbss_start |
18 | a0000010 D _extdata_end |
19 | a0000010 b foo2 |
20 | a0000014 B _exbss_end |
4. Sobald man das Speicherinterface im Startupcode initialisiert hat, sind die Inhalte der initialiserten Variablen ab "_edata_LMA" nach "_exdata_start" zu kopieren. Anzahl dabei: ( _exdata_end - exdata_start ). Weiterhin sind die Speicherstellen von _exbss_start bis _exbss_end mit 0 zu beschreiben. Man kann sich dabei an den Routinen für .data und .bss im "normalen" RAM-Bereich orientieren. Hoffe, es hilft zumindest ein wenig weiter Martin Thomas
@Stefan: ich danke dir vielmals, der Zugriff hat geklappt, und der Linker hat überhaupt nichts mitbekommen. @Mattin Thomas: vielen vielen Dank, das wird für alle fälle ein Unikat in meinem Tutorials-archiev sein, man weiss ja nie.. ;-)
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
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.