Hallo, könnte mir jemand mal in einfachen Worten und mit Beispiel erklären wie ich das 8MB SDRAM des Disco Board vom F429 benutzen kann? Ist das irgendwie "banked" oder als Ganzes am Stück ab 0xD0000000? Wie initialisiert man es und sagt der CPU wie sie es zu verwalten hat? Konkret möchte ich folgendes realisieren mit der CooCox IDE, nur weiss ich noch nicht wie. Das reicht bei mir dann auch für alle Anwendungen. 1. Den Heap auf das SDRAM legen, da ich oft mit heap arbeite. 2. Wie lege ich einen normalen Array über das SDRAM? 3. Bonus: Kann ich das Datensegment meines Codes da drauf legen, so dass er keinen internal RAM mehr benutzt? (Muss sicher im Linker irgendwo eingestellt werden). 4. Kann man Variablen irgendwie als "xdata" defklarieren, wie zb bei den MCS51er 8 Bit CPU, die idata und xdata beim Keil Compiler kennen? Eine anfängergerechte Antwort mit Beispiel für CooCox User wäre sehr nett, danke! Christian
Christian J. schrieb: > Wie lege ich einen normalen Array über das SDRAM? Das geht übers Linker-Script. Der RAM muss dafür aber inititalisert sein. Grüße Oliver
Es finden sich schon in CMSIS_Boot Init Routinen für den Memory Controller, ob man noch mehr als die braucht weiss ich nicht. #ifdef DATA_IN_ExtSRAM /** * @brief Setup the external memory controller. * Called in startup_stm32f4xx.s before jump to main. * This function configures the external SRAM mounted on STM324xG_EVAL/STM324x7I boards * This SRAM will be used as program data memory (including heap and stack). * @param None * @retval None */ void SystemInit_ExtMemCtl(void) Ich weiss nur nicht wo ich diese defines aktiviere, im eigenen Source Code?. Wie gesagt... für Anfänger..... der nichts weiter vor sich hat als void main() { InitSystem(); ...... } und gern da Code einfügen möchte, um das Gesagte zu machen.
Mein Wissen ist einige Jahre alt aber beim LPC2368 mit GCC konnte ich sowas verwenden: uint32_t batram_id _attribute_ ((section(".batram"))); d.h. "batram_id" wurde aufs Segment .batram abgebildet. oder // Der Zeichenpuffer das Display hat 40 x 20 Zeichen = 800 Zeichen uint8_t GD_CharBuf[MAX_LINE][MAX_LPOS+1] _attribute_ ((section(".usbram"))); uint8_t GD_OldBuf[MAX_LINE][MAX_LPOS+1] _attribute_ ((section(".usbram"))); das eben aufs ".usbram" weil der uC unterschiedliche RAM Bereiche hatte, einen gepufferten, einen für USB usw. Alles mit dem GCC gemacht worden.
Spricht ja auch nichts dagegen, dieses Wissen heute anzuwenden, oder? Die sections musst du im Linkerscript natürlich angeben - und aufpassen, dass der uC nicht versucht vor der FSMC-Initialisierung darauf zuzugreifen (also den Startup-Code nochmal anschauen)
Lasse S. schrieb: > Die sections musst du im Linkerscript natürlich angeben Duuu... wo finde ich das Ding in einem "automatisierten" CooCox Projekt? wo man sich die Konfig ja zusammen klickt .... seufz
Ok, habs gefunden, ich meine nicht das Skript aber die Lösung von Uwe Becker: .HeapMemSection : { *(.HeapMemSection) } > sdram Leider wenig Ahnug von der seltsamen Sytax aber da müsste sich doch auch noch ein weiteres Segment, zb .data reinquetschen lassen, ohne dass die kollidieren. Hier ist der Heap jetzt dorthin bugsiert worden. Rest kompiliert und spielt wie vermutet..... #define BUFFER_SIZE (1024*1024) uint8_t buffer[BUFFER_SIZE] attribute__((section(".HeapMemSection"))); /* 18.12.2013 angepasst von UB auf STM32f429i-Disco-Board */ OUTPUT_FORMAT ("elf32-littlearm", "elf32-bigarm", "elf32-littlearm") /* Internal Memory Map*/ MEMORY { rom (rx) : ORIGIN = 0x08000000, LENGTH = 0x00200000 ram (rwx) : ORIGIN = 0x20000000, LENGTH = 0x00030000 ram1 (rwx) : ORIGIN = 0x10000000, LENGTH = 0x00010000 sdram (rwx) : ORIGIN = 0xD0100000, LENGTH = 0x00400000 } _eram = 0x20000000 + 0x00020000; /* Section Definitions */ SECTIONS { .text : { KEEP(*(.isr_vector .isr_vector.*)) *(.text .text.* .gnu.linkonce.t.*) *(.glue_7t) *(.glue_7) *(.rodata .rodata* .gnu.linkonce.r.*) } > rom .ARM.extab : { *(.ARM.extab* .gnu.linkonce.armextab.*) } > rom __exidx_start = .; .ARM.exidx : { *(.ARM.exidx* .gnu.linkonce.armexidx.*) } > rom __exidx_end = .; . = ALIGN(4); _etext = .; _sidata = .; .data : AT (_etext) { _sdata = .; *(.data .data.*) . = ALIGN(4); _edata = . ; } > ram /* .bss section which is used for uninitialized data */ .bss (NOLOAD) : { _sbss = . ; *(.bss .bss.*) *(COMMON) . = ALIGN(4); _ebss = . ; } > ram /* stack section */ .co_stack (NOLOAD): { . = ALIGN(8); *(.co_stack .co_stack.*) } > ram . = ALIGN(4); _end = . ; .HeapMemSection : { *(.HeapMemSection) } > sdram } [/code]
Hallo, Ich schiebs nochmal hoch. Dass es kompilierte heisst ja noch nichts. Ist es überhaupt möglich das SDRAM in einer Section zu verwenden? Denn diese Zuweisung spielt sich bereits beim Kompilieren ab, bevor das SDRAM überhaupt da ist, denn dieses wird erst im Hauptprogramm durch den Memory Controller in seiner Geometrie initialisiert und mit einem Takt versorgt. Nun haben Compiler aber auch Initsequenzen, wo sie statische Variablen aus dem ROM ins Ram kopieren im Startup Code usw. Jedenfalls ist es bei mir nicht möglich sich den Inhalt des SDRAM im Debugger anzeigen zu lassen, da steht nur wirres Zeugs drin. Einschrieben von Vars geht aber und sie werden auch korrekt gelesen. Wie steht es aber nun zb mit der verwendung als Stack? Oder Heap? Gruss, Christian
Christian J. schrieb: > Wie steht es aber nun zb mit der verwendung als Stack? Oder Heap? Was sollte der Verwendung entgegen stehen? Jeder PC arbeitet mit dynamischen Speicher. Du mußt nur sicherstellen, das der Speicher vor Verwendung richitg initialisiert wird. Das da an Anfang wirres Zeug drin steht, ist völlig normal. Nicht umsonst wir bei C die .bss-Sektion erstmal mit '0' gefüllt. Jens
Jens schrieb: > Was sollte der Verwendung entgegen stehen? > Jeder PC arbeitet mit dynamischen Speicher. Tja, nur haben Compiler sowas wie ein _INIT_GLOBALS Section, die sehe ich deutlich im Startupcode wo Variablen im Ram aus einer Tabelle im Rom geladen werden. Alles was als static markiert wurde und einen Startwert hat wird da geladen. Und zu dem Zeitpunkt gibt es noch kein SDRAM, d.h. die Adressen zeigen ins Leere, was vermutlich eine CPU Exception auslösen wird. Mich hat ja schon stutzig gemacht dass ich den SDRAM Berich mit dem Debugger nicht sehen kann. Die eingeschrieben Werte aus dem programm sind nicht zu finden.
Christian J. schrieb: > Tja, nur haben Compiler sowas wie ein _INIT_GLOBALS Section, die sehe > ich deutlich im Startupcode wo Variablen im Ram aus einer Tabelle im Rom > geladen werden. Alles was als static markiert wurde und einen Startwert > hat wird da geladen. Alles richtig. Deshalb muß die SDRAM-Initialisierung mit in den Startup-Code und zwar logischerweise vor dem Kopieren der Variablen. Jens
Jens schrieb: > Alles richtig. Deshalb muß die SDRAM-Initialisierung mit in den > Startup-Code und zwar logischerweise vor dem Kopieren der Variablen. Schonmal gesehen wie der Memory Controller in C behandelt wird? 10.000 kryptische Einstellungen? Ich werde den nicht ernsthaft in ARM Assembler schreiben, da ich davon keine Ahnung habe (und nicht haben will). Aber scheinbar ist das der einzige Weg .... oder man verwendet die Section wirklich nur nach dem Init() lokal und nicht als globale Variable. Ich werde mal ausprobieren wie es mit dem Heap ausschaut ob man den dorthin bugsieren kann. Danke!
die Initialisierung muss nicht in Assembler gemacht werden. von Clive gibt es einen angepassten Startupcode der mit dem Define "DATA_IN_ExtSDRAM" aktiviert werden sollte schau mal hier : https://my.st.com/public/STe2ecommunities/mcu/Lists/cortex_mx_stm32/Flat.aspx?RootFolder=https%3a%2f%2fmy%2est%2ecom%2fpublic%2fSTe2ecommunities%2fmcu%2fLists%2fcortex%5fmx%5fstm32%2fstm32f429%20and%20sdram&FolderCTID=0x01200200770978C69A1141439FE559EB459D7580009C4E14902C3CDE46A77F0FFD06506F5B¤tviews=375 Zitat :
1 | This function configures the external SDRAM mounted on STM32F429I-DISCO board |
2 | * This SDRAM will be used as program data memory (including heap and stack). |
Gruss Uwe
:
Bearbeitet durch User
Hi Uwe, nach ein wenig rumbasteln ist jetzt klar, dass es funktioniert, wenn man Sections definiert und in Main dann den Init setzt. Das SDRAM ist nur laaaaaangsam, 8Mb vollzukritzeln dauert schon ein paar Sekunden. Aber was macht das schon wenn man volle 8MB an einen uC hat! Das ist wie Weihnachten. Wenn ich so dran denke, dass ich vor 4 Wochen noch von Nix ne Ahnung hatte bei dem Board :-) und jetzt steht schon eine UART mit Terminal für Ausgabe, ein Ringpuffer, ein fertiges Template für EmBlocks.... Emblocks ist echt klasse, komme ich 10mal besser mit klar als mit CooCoxKrampf. Für das das Debuggen im RAM zur Schonung des Flash auch ein Setup gebaut und nur noch 1 Mausklick dafür. Ich habe die Libs von Majerle genommen (bitte nicht böse sein :-), der füllt auch nur die Structs und ruft Init dann auf und die wiederum rufen fmc.c auf.
1 | /* 1 clock cycle = 1 / 90MHz = 11.1ns */ |
2 | FMC_SDRAMTimingInitDef.FMC_LoadToActiveDelay = 2; |
3 | /* TXSR: min=70ns (7x11.10ns) */ |
4 | FMC_SDRAMTimingInitDef.FMC_ExitSelfRefreshDelay = 7; |
5 | /* TRAS: min=42ns (4x11.10ns) max=120k (ns) */ |
6 | FMC_SDRAMTimingInitDef.FMC_SelfRefreshTime = 4; |
7 | /* TRC: min=70 (7x11.10ns) */ |
8 | FMC_SDRAMTimingInitDef.FMC_RowCycleDelay = 7; |
9 | /* TWR: min=1+ 7ns (1+1x11.10ns) */ |
10 | FMC_SDRAMTimingInitDef.FMC_WriteRecoveryTime = 2; |
11 | /* TRP: 20ns => 2x11.10ns */ |
12 | FMC_SDRAMTimingInitDef.FMC_RPDelay = 2; |
13 | /* TRCD: 20ns => 2x11.10ns */ |
14 | FMC_SDRAMTimingInitDef.FMC_RCDDelay = 2; |
15 | |
16 | * Send the command */ |
17 | FMC_SDRAMCmdConfig(&FMC_SDRAMCommandStructure); |
18 | |
19 | /* Set the refresh rate counter */ |
20 | /* (7.81 us x Freq) - 20 = (7.81 * 90MHz) - 20 = 683 */ |
21 | /* Set the device refresh counter */ |
22 | FMC_SetRefreshCount(680); |
Ob man da noch was opmieren kann weiss ich nicht. Die Werte sind sicherlich auch irgendwo abgeschrieben. Linker Script: Ganz sicher bin ich mir hier nicht, das ist nur intuitiv, weil anderes auch so gemacht wurde. Kenne die Syntax eines Linker Scripts leider nicht. MEMORY { ROM (rx) : ORIGIN = 0x08000000, LENGTH = 0x00200000 CCRAM (rwx) : ORIGIN = 0x10000000, LENGTH = 0x00010000 /* 16kb */ RAM (rwx) : ORIGIN = 0x20000000, LENGTH = 0x00030000 /* 192kb */ SDRAM (rwx) : ORIGIN = 0xD0100000, LENGTH = 0x00400000 /* 8 MB */ } später: /* 8MB SDRAM Chip */ .sdram (NOLOAD): { . = ALIGN(4); *(.sdram) } > SDRAM
1 | SDRAM (rwx) : ORIGIN = 0xD0100000, LENGTH = 0x00400000 /* 8 MB */ |
da passt der Text zum define nicht 0x400000 sind nur 4MB falls du das von mir kopiert hast (wovon ich ausgehe) hier eine Erklärung : das SDRAM beginnt bei Adresse 0xD0000000 und hat 8MB falls du also das komplette SDRAM nutzen willst, "müsste" der Eintrag im Linker-Script so lauten :
1 | SDRAM (rwx) : ORIGIN = 0xD0000000, LENGTH = 0x00800000 /* 8 MB */ |
Vorsicht !! das kolidiert dann aber mit dem LCD-Display auf dem STM32F429-Disco das Display nutzt als Grafik-RAM auch das SD-RAM ab der Startadresse 0xD0000000 ich habe den Bereich "SDRAM" im Linker-Script nur hinzugefügt um einen Teil vom SD-RAM (4MB) für Variabeln Nutzen zu können (zusätzlich zum Display) für das Display habe ich 1MB reserviert darum beginnt die Startadresse im Linker-Script für die Variabeln bei 0xD0100000 ist etwas konfus aber ich musste meine Librarys abwärtskompatibel halten du kannst ja bei dir die 8MB aufteilen in : 1MB für das Display und 7MB für Variabeln (Stack/Heap) Gruss Uwe
:
Bearbeitet durch User
Christian J. schrieb: > Das SDRAM ist nur > laaaaaangsam, 8Mb vollzukritzeln dauert schon ein paar Sekunden. dann benutz mal den DMA2D zum kopieren von Daten und nicht die CPU da wirst du staunen wie schnell 8MB gefüllt sind :-) Gruss Uwe
:
Bearbeitet durch User
Hier eine Lib: http://mikrocontroller.bplaced.net/wordpress/?page_id=2747 Vielleicht kannst du da noch ein paar Infos rausziehen...
:
Bearbeitet durch User
Hi Uwe, habs schon bemerkt, ja das habe ich rauskorpiet. Ich benutze deine Libs ja noch nicht, daher brauche ich das mit dem Display derzeit auch nicht. Man muss sich wohl entscheiden zwischen Deinen und denen von Majerle, sind beide sehr ähnlich. Übrigens seltsame Kiste mit dem Startup Code. Der von Emblocks war nicht release fähig... Ich habe deinen reinkopiert ohne nachzudenken und er spielt. Ist aber eben ein C File und kein .s File wie vorher. Das eröffnet natürlich auch neue Möglichkeiten, wie Speicher Init usw. Die Init des SDRAM werde ich da auch reinnehmen. Nutze derzeit die von Majerle. Routinen sind die gleichen wie bei dir. Stellt sich allerdings die Frage wie man die Routine von clive1 einbindet. Sie enthält keinerlei inlcude Files und ist so nicht kompilerbar. Habe sie beide mal angehängt, vielleicht kannst du ja eine draus machen, die fehlerfrei durchkompiliert. Gruss, Christian
Christian J. schrieb: > könnte mir jemand mal in einfachen Worten und mit Beispiel erklären wie.. Nö. Mit einfachen Worten ist das Ganze nicht erreichbar. Du mußt dich schon selber mit der Materie befassen, sonst wird da nix. Zuerst, wie der externe Busanschluß ei deinem µC konkret aufgebaut ist und wie er eingerichtet wird. Dann, was für ein SDRAM tatsächlich dranhängt und wie dieser RAM zu initialisieren ist, also vor allem Organisation und Blockgrößen. Ich hänge dir mal ein Beispiel dran. Das ist zwar für einen 32 Bit breiten SDRAM und für einen LPC2478, aber das Wesentliche kannst du dir dort abgucken. W.S.
>Stellt sich allerdings die Frage wie man die Routine von clive1 >einbindet. Sie enthält keinerlei inlcude Files und ist so nicht >kompilerbar. füge einfach den Teil von Clive anstelle vom original ST-Code in das File "system_stm32f4xx.c" hinzu (da gibt es die gleiche Funktion, die aber fehlerhaft bzw. nicht passend für das Disco-Board ist) also die komplette Funktion "void SystemInit_ExtMemCtl(void)" durch die von Clive ersetzen ich habe es selbst nicht ausprobiert aber falls includes fehlen kann es eigentlich nur die vom fmc und gpio sein #include "stm32f4xx_fmc.h" #include "stm32f4xx_gpio.h"
:
Bearbeitet durch User
Uwe B. schrieb: > also die komplette Funktion "void SystemInit_ExtMemCtl(void)" > durch die von Clive ersetzen Hi, Habs mir grad mal von zu hause aufs Handy geladen. Fragt sich nur ob diese Funktion explizit aufgerufen werden muss, zb aus dem Startup Code oder ob sie durch geheime Mechanismen schon aufgerufen wird. Was ich etwas vermisse ist ein ausführliches Map File. In dem vom GCC steht viel drin aber das vom SDCC ist deutlich übersichtlicher. Ich melde es später mal nach dem Sport was draus geworden ist.....
PS: Es funktioniert nicht mit der clive1 Routine. Durchlaufen wird alles aber beim ersten Zugriff auf das SDRAM klebt er im Exception Handler drin.... erst der ausdrückliche Aufruf von TM_Init_SDRAM() lässt es laufen. edit 10 Minuten später: geht doch, Fehler beim Copy & Paste. Puh, na, also.... PS: Wenn es mal regnet und Du Langeweile hast, schreib deinen Pac Man doch mal auf Autoplay um (aber nicht schummeln) oder so, dass die Geister einen sehen müssen damit sie die Spur aufnehmen können. So wie in einem echten Labyrynath auch.
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.