Methode oder Funktion, um festzustellen, ob der Zeiger in Flash oder RAM adressieren soll?

7

Ich arbeite mit einem ARM Cortex M4-Mikrocontroller mit DMA oder peripherem DMA-Controller. Eine Anforderung des DMA besteht darin, dass er nicht auf Zeiger auf Adressen zugreifen kann, die in Flash vorhanden sind, sondern nur auf Zeiger auf Adressen, die sich im RAM befinden. Gibt es eine Möglichkeit festzustellen, ob ein bestimmter Zeiger auf Flash oder RAM zeigt?

Wenn nicht, muss ich einen Puffer im RAM initialisieren und dann strcpy oder ähnliches, um das, was sich im Flash befindet, in den RAM zu übertragen, damit der DMA es lesen kann. Kennt jemand einen besseren Weg, um keine CPU-Zeit zu verschwenden, wenn nicht festgestellt werden kann, ob der Zeiger auf Flash oder RAM zeigt?

Dies ist auf einem Atmel SAM4S.

Pugz
quelle
1
Muss es zur Laufzeit ermittelt werden? Sprechen wir hier über C?
Eugene Sh.
Ja, Makro kommt also wohl nicht in Frage. Jetzt bearbeiten.
Pugz
Können Sie uns mitteilen, welche MCU diese Anforderung hat? Dies kann auch für andere eine nützliche Frage + Antwort sein.
Corecode
Dies ist ein Atmel SAM4S. Ich werde die Frage bearbeiten.
Pugz

Antworten:

5

Sie kennen die Speicherzuordnung Ihres Mikrocontrollers, sodass Sie Ihren Zeiger einfach anhand der Start- und End-RAM-Adressen testen können. In den meisten Fällen stellt Ihr Linkerscript diese Adressen bereit, sodass Sie sie nicht selbst eingeben müssen (Details hängen von Ihrem Linkerscript ab). Beachten Sie, dass bei Verwendung des Linkerskripts die Werte zum Zeitpunkt der Kompilierung nicht bekannt sind, sodass der Compiler die Vergleiche mit bekannten Zeigern nicht optimieren kann.

Wouter van Ooijen
quelle
5

Das Hauptproblem bei der Überprüfung, ob sich ein Zeiger in einem bestimmten Bereich befindet, ist leider der C-Standard selbst. Zeigerarithmetik hat nur dann ein definiertes Verhalten , wenn sie an Zeigern desselben Typs innerhalb des Speicherbereichs desselben Objekts (dh innerhalb desselben zugewiesenen Arraybereichs) ausgeführt wird. Wenn die Vergleichsoperatoren als arithmetische Operationen definiert sind, gilt diese Einschränkung auch für sie. Eine Problemumgehung für dieses Problem wäre das Umwandeln der Zeiger in den in uintptr_tdefinierten Typ, bei stdint.hdem es sich um einen ganzzahligen Typ handelt, der garantiert einen Zeigerwert enthält. Und dann führen Sie Ihre Vergleiche durch.

Nun zum Teil, die richtigen Grenzen zu erreichen. Normalerweise enthält ein C-Projekt eine Art Linker-Skript, das Speicherbereiche der spezifischen Architektur definiert. Im Allgemeinen enthält es Zeilen ähnlich den folgenden:

MEMORY
{
    FLASH (rx) : ORIGIN = 0x00000000, LENGTH = 0x40000
    SRAM (rwx) : ORIGIN = 0x20000000, LENGTH = 0x8000
}

Im selben Skript können dann die folgenden Definitionen hinzugefügt werden:

  _flash_start = ORIGIN(FLASH);
  _flash_end = ORIGIN(FLASH) + LENGTH(FLASH);

Und dann können Sie im C-Code auf diese Symbole zugreifen, indem Sie:

extern int _flash_start ;  
extern int _flash_end;

Und dann ein kniffliger Teil: Die Adresse von _flash_startentspricht der Flash-Startadresse, und die Adresse von _flash_endentspricht der Flash-Endadresse. Dh die &_flash_startund &_flash_endgeben Ihnen die gewünschte Reichweite.

Eugene Sh.
quelle
5

Wenn Ihre MCU den ARM Cortex-Konventionen entspricht, können Sie sich das oberste Halbbyte der betreffenden Adresse ansehen:

int
inflash_p(void *addr)
{
    uintptr_t addr_int = addr;
    unsigned int addrtype = addr_int >> 28;

    // 0 = flash, 1,2 = ram, 4 = periph, e = system
    return (addrtype == 0);
}
Corecode
quelle
Danke, das war mir nicht bewusst! Woher kommt das, TRM?
Domen
Entschuldigung, ich erinnere mich im Moment nicht. Wenn ich wieder darauf stoße, werde ich die Antwort bearbeiten.
Corecode
1 + 2 - was meinst du damit? Meinen Sie eine Rückgabe von 1 oder 2 bedeutet, dass es im RAM ist, oder 3 bedeutet, dass es im RAM ist?
Pugz
Ich denke, es bedeutet 0x10000000- 0x2fffffffoder anders gesagt, jede Adresse, die mit knabbern 1oder beginnt 2.
Domen
2

Sie können den Zeiger auf eine Ganzzahl umwandeln und dann seinen Wert mit dem Flash-Adressraum vergleichen, der in der Speicherzuordnung Ihrer MCU definiert ist. Wenn sich Ihr Flash-Speicher beispielsweise unter den Adressen 0x10000000 - 0x1001ffff befindet, können Sie Folgendes tun:

void DMA_Function(uint8_t *ptr)
{
    uint32_t ptrAddress = (uint32_t)ptr;

    if (ptrAddress >= 0x10000000 && ptrAddress < 0x10020000)
        //The address is in flash
    else
        //The address is not in flash

    ...
}

Natürlich ist es im eigentlichen Code besser, Konstanten anstelle von fest codierten Adressen zu verwenden - beispielsweise FLASH_START_ADDR und FLASH_END_ADDR. Wenn Sie besonders flexibel sein möchten, können Sie Linkervariablen für die Flash-Adressen definieren, wodurch die Adressen nicht in Ihrem Quellcode enthalten sind.

Adam Haun
quelle