mikrocontroller.net

Forum: Mikrocontroller und Digitale Elektronik STM32 und externer RAM


Autor: Stephan M. (stmiko)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
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...
 #define copyData32(pSrc, pDest) asm volatile(                      \
                      "ldmia   r0!,{r2-r6,r8-r10}\n"        \
                      "stmia   r1,{r2-r6,r8-r10}\n"        \
                      : /* no outputs  */            \
                      : "r" (pSrc), "r" (pDest)          \
                      : "r2", "r3", "r4", "r5", "r6", "r8", "r9", "r10");


Die Funktion zum Aufruf sieht folgendermaßen aus

AddrHead_Write = AddrHead[MessNr];
copyInBufferH((u32*)&HeaderR, (u32*)AddrHead_Write);

.
.
.

void copyInBufferH(register u32* pSrc, register u32* pAddr)
{
  copyData32(pSrc, pAddr);
}


Die Konfiguration des RAMS

 /*-- FSMC Configuration ------------------------------------------------------*/
  p.FSMC_AddressSetupTime = 1;    //no effect
  p.FSMC_AddressHoldTime = 1;    //no effect
  p.FSMC_DataSetupTime = 1;      //no effect
  p.FSMC_BusTurnAroundDuration = 1;  //no effect
  p.FSMC_CLKDivision = 1;      //HCLK / 2
  p.FSMC_DataLatency = 0;      //must be 0
  p.FSMC_AccessMode = FSMC_AccessMode_C;

  //FSMC asynchronen Mode für PSRAM Init setzen
  FSMC_NORSRAMInitStructure.FSMC_Bank = FSMC_Bank1_NORSRAM1;  //2;
  FSMC_NORSRAMInitStructure.FSMC_DataAddressMux = FSMC_DataAddressMux_Enable;
  FSMC_NORSRAMInitStructure.FSMC_MemoryType = FSMC_MemoryType_PSRAM;
  FSMC_NORSRAMInitStructure.FSMC_MemoryDataWidth = FSMC_MemoryDataWidth_16b;
  FSMC_NORSRAMInitStructure.FSMC_BurstAccessMode = FSMC_BurstAccessMode_Disable;
  FSMC_NORSRAMInitStructure.FSMC_WaitSignalPolarity = FSMC_WaitSignalPolarity_Low;
  FSMC_NORSRAMInitStructure.FSMC_WrapMode = FSMC_WrapMode_Disable;
  FSMC_NORSRAMInitStructure.FSMC_WaitSignalActive = FSMC_WaitSignalActive_BeforeWaitState;
  FSMC_NORSRAMInitStructure.FSMC_WriteOperation = FSMC_WriteOperation_Enable;
  FSMC_NORSRAMInitStructure.FSMC_WaitSignal = FSMC_WaitSignal_Disable;
  FSMC_NORSRAMInitStructure.FSMC_ExtendedMode = FSMC_ExtendedMode_Disable;
  FSMC_NORSRAMInitStructure.FSMC_WriteBurst = FSMC_WriteBurst_Disable;
  FSMC_NORSRAMInitStructure.FSMC_ReadWriteTimingStruct = &p;
  FSMC_NORSRAMInitStructure.FSMC_WriteTimingStruct = &p;

  FSMC_NORSRAMInit(&FSMC_NORSRAMInitStructure); 

  FSMC_NORSRAMInitStructure.FSMC_Bank = FSMC_Bank1_NORSRAM2;
  FSMC_NORSRAMInit(&FSMC_NORSRAMInitStructure); 

  /* Enable FSMC Bank2_PSRAM Bank */
  FSMC_NORSRAMCmd(FSMC_Bank1_NORSRAM1, ENABLE);  //entfällt später  

  /* Enable FSMC Bank2_PSRAM Bank */
  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

Autor: A. K. (prx)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Musst den Befehlen schon die Register mitgeben, die der Compiler für die 
Adressen auserkoren hat:
#define copyData32(pSrc, pDest) asm volatile(                      \
                      "ldmia   %0,{r2-r6,r8-r10}\n"        \
                      "stmia   %1,{r2-r6,r8-r10}\n"        \
                      : /* no outputs  */            \
                      : "r" (pSrc), "r" (pDest)          \
                      : "r2", "r3", "r4", "r5", "r6", "r8", "r9", "r10");

Das "!" bei LDMIA könnte den Compiler bei Inlining durcheinanderbringen.

Autor: A. K. (prx)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
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.

Autor: Marcus Harnisch (mharnisch) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
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

Autor: Stephan M. (stmiko)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo,

danke erstmal für eure Ausführungen, werde es morgen gleich mal testen
und Rückmeldung geben!

Autor: A. K. (prx)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
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.

Autor: Stephan M. (stmiko)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo,

ich habe mich für die Funktion memcpy() entschieden!
Diese funktioniert bestens :-)

Vielen Dank für eure Hilfe

Stephan

Autor: Marcus Harnisch (mharnisch) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
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.
void copyData32(u32 *pSrc, u32 *pDest)
{
    memcpy(pDest, pSrc, 16);
    memcpy(pDest + 4, pSrc + 4, 16);
}

Aber wenn Zeit nicht das eigentliche Problem ist, dann ist memcpy() in 
jedem Fall sinnvoller als Inline Assembler.

--
Marcus

Antwort schreiben

Die Angabe einer E-Mail-Adresse ist freiwillig. Wenn Sie automatisch per E-Mail über Antworten auf Ihren Beitrag informiert werden möchten, melden Sie sich bitte an.

Wichtige Regeln - erst lesen, dann posten!

  • Groß- und Kleinschreibung verwenden
  • Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang

Formatierung (mehr Informationen...)

  • [c]C-Code[/c]
  • [avrasm]AVR-Assembler-Code[/avrasm]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] - Link zu Artikel
  • Verweis auf anderen Beitrag einfügen: Rechtsklick auf Beitragstitel,
    "Adresse kopieren", und in den Text einfügen




Bild automatisch verkleinern, falls nötig
Bitte das JPG-Format nur für Fotos und Scans verwenden!
Zeichnungen und Screenshots im PNG- oder
GIF-Format hochladen. Siehe Bildformate.
Hinweis: der ursprüngliche Beitrag ist mehr als 6 Monate alt.
Bitte hier nur auf die ursprüngliche Frage antworten,
für neue Fragen einen neuen Beitrag erstellen.

Mit dem Abschicken bestätigst du, die Nutzungsbedingungen anzuerkennen.