Hallo,
ich versuche bei dem besagten uC mit externen SRAM diesen zu beschreiben
und auszulesen. Die Konfiguration ist soweit in Ordnung.
Aus dem Datenblatt habe ich entnommen, dass die erste Adresse die
0x60000000 ist.
Bei dieser Adresse soll ein Header geschrieben werden, der 32 Byte lang
ist. Dem folgenden die eigentliche Werte, die ich mittels des Headers
später auslesen möchte.
Leider funktionieren meine Funktionen nicht so, wie ich mir das
vorstelle. Deshalb meine Frage an euch, hat jemand auch schon mal sowas
gemacht und könnte mir weiterhelfen?
Momentan habe ich eine Funktion, die den Header in den SRAM bei eine
angegebenen Adresse schreiben soll und eine andere die diesen auslesen
soll. Dabei bediene ich mir eines Makros, dass 32Byte in den interen
Registern des Cortex beschreibt und das ist scheinbar der Knackpunkt...
1 | #define copyData32(pSrc, pDest) asm volatile( \
| 2 | "ldmia r0!,{r2-r6,r8-r10}\n" \
| 3 | "stmia r1,{r2-r6,r8-r10}\n" \
| 4 | : /* no outputs */ \
| 5 | : "r" (pSrc), "r" (pDest) \
| 6 | : "r2", "r3", "r4", "r5", "r6", "r8", "r9", "r10");
|
Die Funktion zum Aufruf sieht folgendermaßen aus
1 | AddrHead_Write = AddrHead[MessNr];
| 2 | copyInBufferH((u32*)&HeaderR, (u32*)AddrHead_Write);
| 3 |
| 4 | .
| 5 | .
| 6 | .
| 7 |
| 8 | void copyInBufferH(register u32* pSrc, register u32* pAddr)
| 9 | {
| 10 | copyData32(pSrc, pAddr);
| 11 | }
|
Die Konfiguration des RAMS
1 | /*-- FSMC Configuration ------------------------------------------------------*/
| 2 | p.FSMC_AddressSetupTime = 1; //no effect
| 3 | p.FSMC_AddressHoldTime = 1; //no effect
| 4 | p.FSMC_DataSetupTime = 1; //no effect
| 5 | p.FSMC_BusTurnAroundDuration = 1; //no effect
| 6 | p.FSMC_CLKDivision = 1; //HCLK / 2
| 7 | p.FSMC_DataLatency = 0; //must be 0
| 8 | p.FSMC_AccessMode = FSMC_AccessMode_C;
| 9 |
| 10 | //FSMC asynchronen Mode für PSRAM Init setzen
| 11 | FSMC_NORSRAMInitStructure.FSMC_Bank = FSMC_Bank1_NORSRAM1; //2;
| 12 | FSMC_NORSRAMInitStructure.FSMC_DataAddressMux = FSMC_DataAddressMux_Enable;
| 13 | FSMC_NORSRAMInitStructure.FSMC_MemoryType = FSMC_MemoryType_PSRAM;
| 14 | FSMC_NORSRAMInitStructure.FSMC_MemoryDataWidth = FSMC_MemoryDataWidth_16b;
| 15 | FSMC_NORSRAMInitStructure.FSMC_BurstAccessMode = FSMC_BurstAccessMode_Disable;
| 16 | FSMC_NORSRAMInitStructure.FSMC_WaitSignalPolarity = FSMC_WaitSignalPolarity_Low;
| 17 | FSMC_NORSRAMInitStructure.FSMC_WrapMode = FSMC_WrapMode_Disable;
| 18 | FSMC_NORSRAMInitStructure.FSMC_WaitSignalActive = FSMC_WaitSignalActive_BeforeWaitState;
| 19 | FSMC_NORSRAMInitStructure.FSMC_WriteOperation = FSMC_WriteOperation_Enable;
| 20 | FSMC_NORSRAMInitStructure.FSMC_WaitSignal = FSMC_WaitSignal_Disable;
| 21 | FSMC_NORSRAMInitStructure.FSMC_ExtendedMode = FSMC_ExtendedMode_Disable;
| 22 | FSMC_NORSRAMInitStructure.FSMC_WriteBurst = FSMC_WriteBurst_Disable;
| 23 | FSMC_NORSRAMInitStructure.FSMC_ReadWriteTimingStruct = &p;
| 24 | FSMC_NORSRAMInitStructure.FSMC_WriteTimingStruct = &p;
| 25 |
| 26 | FSMC_NORSRAMInit(&FSMC_NORSRAMInitStructure);
| 27 |
| 28 | FSMC_NORSRAMInitStructure.FSMC_Bank = FSMC_Bank1_NORSRAM2;
| 29 | FSMC_NORSRAMInit(&FSMC_NORSRAMInitStructure);
| 30 |
| 31 | /* Enable FSMC Bank2_PSRAM Bank */
| 32 | FSMC_NORSRAMCmd(FSMC_Bank1_NORSRAM1, ENABLE); //entfällt später
| 33 |
| 34 | /* Enable FSMC Bank2_PSRAM Bank */
| 35 | FSMC_NORSRAMCmd(FSMC_Bank1_NORSRAM2, ENABLE);
|
Nach dem zweiten Ausführen der Fkt. "copyInBufferH" bleibt der
Prozessor an dem Marko hängen. In der AddrHead[MessNr] steht immer
die Anfangsadresse des zu beschreibenden RAMs...
Stephan
Musst den Befehlen schon die Register mitgeben, die der Compiler für die
Adressen auserkoren hat: 1 | #define copyData32(pSrc, pDest) asm volatile( \
| 2 | "ldmia %0,{r2-r6,r8-r10}\n" \
| 3 | "stmia %1,{r2-r6,r8-r10}\n" \
| 4 | : /* no outputs */ \
| 5 | : "r" (pSrc), "r" (pDest) \
| 6 | : "r2", "r3", "r4", "r5", "r6", "r8", "r9", "r10");
|
Das "!" bei LDMIA könnte den Compiler bei Inlining durcheinanderbringen.
Wenn immer nur die 32 Bytes kopiert werden und keine grösseren Blöcke,
dann würde ich nicht drauf wetten, dass deine Version viel effizienter
ist als eine, die weniger Register braucht. Denn die Zwischenregister
müssen gesichert werden, was auch Zeit braucht.
A. K. schrieb:
> Wenn immer nur die 32 Bytes kopiert werden und keine grösseren Blöcke,
> dann würde ich nicht drauf wetten, dass deine Version viel effizienter
> ist als eine, die weniger Register braucht.
Nur die Codegröße unterscheidet sich möglicherweise. Aber warum nicht
einfach memcpy() verwenden?
> Denn die Zwischenregister müssen gesichert werden, was auch Zeit braucht.
Ja, der Teil fehlte mir auch irgendwie :-)
--
Marcus
Hallo,
danke erstmal für eure Ausführungen, werde es morgen gleich mal testen
und Rückmeldung geben!
Marcus Harnisch schrieb:
> Ja, der Teil fehlte mir auch irgendwie :-)
Nicht unbedingt, denn da die Register korrekt als "verwendet"
gekennzeichnet wurden kümmert sich der Compiler selbst darum.
Allerdings werden so aus den 2 LDM/STMs insgesamt 4, sofern das als
eigenständige Funktion implementiert ist. Andernfalls steht diese Aktion
einer effektiven Registeroptimierung im Weg.
Hallo,
ich habe mich für die Funktion memcpy() entschieden!
Diese funktioniert bestens :-)
Vielen Dank für eure Hilfe
Stephan
A. K. schrieb:
> Nicht unbedingt, denn da die Register korrekt als "verwendet"
> gekennzeichnet wurden kümmert sich der Compiler selbst darum.
Irgendwann werde ich mal versuchen, diese kryptische Syntax des GCC
Inline Assemblers zu verstehen. Wenn ich mir die memcpy()
Implementierung bei CodeSourcery anschaue, dann sollte man wirklich
darüber nachdenken...
Und ich dachte schon, der RealView Compiler hätte das durchaus besser
machen können. Erst bei einem doppelten memcpy() mit jeweils vier Worten
wird das von diesem Compiler richtig effizient umgesetzt.
1 | void copyData32(u32 *pSrc, u32 *pDest)
| 2 | {
| 3 | memcpy(pDest, pSrc, 16);
| 4 | memcpy(pDest + 4, pSrc + 4, 16);
| 5 | }
|
Aber wenn Zeit nicht das eigentliche Problem ist, dann ist memcpy() in
jedem Fall sinnvoller als Inline Assembler.
--
Marcus
Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
|