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
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!
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.
/* (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
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 :
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
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
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"
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.