Die Speicherbereiche, in die ich schreiben kann und in die ich nicht schreiben kann, ARM Cortex-M-Architektur

Ich hoffe, mein Titel ist terminologisch korrekt. Ich arbeite (lerne) mit dem STM32F4 Discovery Board, auf dem sich ein STM32F407VGTx-Mikrocontroller befindet. Ich versuche wirklich, die Antworten im Referenzhandbuch zu finden , aber manchmal ist es wirklich schwer zu finden, wo ich suchen soll. Vielleicht liegt es daran, dass es über 1700 Seiten lang ist ...

Also, hier die Situation, während meiner Tests (C-Code, Compiler ist arm-none-eabi-size), habe ich festgestellt, dass ich jeden Wert in Peripherieregister schreiben kann, zum Beispiel in GPIOD-Register. Aber wenn ich denselben Code verwende (um an eine Adresse zu schreiben), kann ich beispielsweise nicht an die Adresse 0x58 (tatsächlich 0x00000058) schreiben. Im Falle von peripheren Registern gibt das Dokument eindeutig an, welche Register/Bits schreibgeschützt sind und welche schreibgeschützt sind, mit Notationen wie „r“, „rw“. Für die Adresse 0x58 konnte ich jedoch den Grund nicht finden, warum ich nicht darauf schreiben kann.

Jede Anleitung oder Erklärung wäre willkommen, danke.


aktualisieren:

Gegenfrage: Warum sollten Sie an diese Adresse schreiben können? Ist dem etwas zugeordnet? – Markus Müller

Okay, es ist ein bisschen interessant. Ich habe gerade angefangen, etwas über externe Interrupts zu lernen, und ich möchte während meines Lernens alles (also einschließlich externer Interrupts) auf Registerebene tun. Deshalb habe ich keine Funktionen von HAL, SPL oder CMSIS verwendet und auch keine dieser Dateien ist im Projektverzeichnis vorhanden. Ich habe es irgendwie geschafft, also hatte ich das EXTI-Pending-Register korrekt gestartet, aber ich konnte keine Möglichkeit finden, eine Callback-Funktion mit dem Interrupt zu verknüpfen, die den Prozess definiert, der im Falle des Interrupts ausgeführt werden soll. Die Untersuchung der NVIC-Tabelle (Seite 372) aus dem Referenzhandbuch ergab, dass jeder Interrupt mit einer Speicheradresse in der letzten Spalte verbunden ist. Also dachte ich, vielleicht nur eine Idee, diese Orte enthalten die Speicheradresse (Zeiger) zu den Interrupt-Handler-Funktionen. So, Ich dachte dann daran, eine Funktion zu definieren und dann die Adresse dieser Funktion in den Speicherplatz 0x58 zu schreiben. Wenn also der Interrupt kommt, schaut der Mikrocontroller auf 0x58, was ihn an die Stelle der interessierenden Funktion umleitet.

Ja, dieses Update hätte eine ganz andere Frage für sich sein können. Entschuldigung für das Chaos. Ich denke, die Frage kann ohne diese Geschichte beantwortet werden, aber ein Kommentar hat mich dazu veranlasst, dies auch anzuhängen ...

Gegenfrage: Warum sollten Sie an diese Adresse schreiben können? Ist dem etwas zugeordnet?
@MarcusMüller, es ist ein bisschen interessant, warum ich mich selbst brauchte, um an diese Adresse schreiben zu können, es war nur eine hypothetische Sache in meinem Kopf, und ich würde wahrscheinlich sehen, dass es nicht so war, wie ich dachte, wenn ich es schaffen könnte schreiben Sie an diese Adresse. Lassen Sie mich die Geschichte an meine Antwort anhängen, und wenn ich fertig bin, werde ich Sie benachrichtigen.
Ich weiß nicht, ob die Geschichte wichtig ist, die Frage ist, ob es etwas gibt, an das Sie schreiben können, das dieser Adresse zugeordnet ist
ok, ich ging davon aus, dass Sie wissen, warum ich dort nicht schreiben und eine rethorische Frage stellen kann. Wenn das nicht der Fall ist, denke ich, dass mein Update Ihnen nicht viele Informationen zu "Ist etwas darauf zugeordnet" geben wird, weil es erklären wird, warum ich dachte, dass ich beabsichtige, etwas an diese Speicheradresse zu schreiben. Wie gesagt, ich weiß nicht genau, ob diese Region irgendwo 0x58 enthält, wo ich etwas schreiben kann oder nicht. Ich könnte total über Unsinn reden, aber mein Update wird zumindest deutlich machen, warum ich überhaupt auf die Idee gekommen bin, an diese Adresse zu schreiben.

Antworten (4)

Sie müssen sich die Speicherkonfiguration des Prozessors ansehen. Der Cortex-M4 implementiert die ARMv7-M-Architektur. Hier ist ein Schnappschuss der oberen Hälfte der Speicherkarte (ärgerlicherweise ist diese im Referenzhandbuch des M4 auf zwei Seiten aufgeteilt ).

Geben Sie hier die Bildbeschreibung ein

Wie Sie sehen können, 0x00000000 - 0x1FFFFFFFist der Bereich zugewiesen Code. Die STM-Implementierung enthält keinen zugänglichen Pfad auf dem System-AHB-Bus zu diesem Bereich, daher können Sie nicht an diese Adresse schreiben.

oh, ok, diese Region ist also eine Art Festplatte unserer üblichen Computer, nachdem der C-Code kompiliert und in Binärcode konvertiert wurde, wird er in diese Region geladen, und der Mikrocontroller liest Anweisungen von dort. Bin ich wenigstens nah dran?
Der Linker wird verwendet, um die Speicherbereiche und ihre Attribute anzugeben. Schauen Sie sich das an, es könnte helfen keil.com/support/man/docs/armlink/armlink_pge1406297881263.htm Es kann ein verwirrendes Thema sein, aber Teil des Spaßes, Mikros anstelle von vollständigen Systemen zu verwenden :)

Eventuell wird die Vektortabelle verschoben ; Es gibt ein Register, das die "0"-Adresse dieser Tabelle speichert und das angepasst werden kann. Das ist eigentlich ein ziemlich praktisches Feature: Es ermöglicht Ihnen, eine Interrupt-Handler-Tabelle irgendwo im RAM einzurichten, und dann mit einem Schreibvorgang VTOR(der sich bei Adresse 0x08 befindet, glaube ich) zu dieser neuen Tabelle umzuschalten.

Siehe Seite 218 des stm32f4-Programmierhandbuchs .

Lassen Sie mich das selbst versuchen, ob ich Sie richtig verstanden habe oder nicht. Also, 0x00000058und seine Umgebung darf ich nicht ändern, sagen wir, 0x50000000die Adresse ist in Ordnung, damit zu arbeiten. Dann schreibe ich 0x50000000an VTOR. Jetzt beginnt die NVIC-Tabelle mit dieser Adresse. Wenn ich dann die Adresse meiner Interrupt-Handler-Funktion an schreibe, 0x50000058würde ich erreichen, was ich beabsichtigt habe? Ich werde es jetzt versuchen und warte in der Zwischenzeit auf Ihren Kommentar. Danke für die Antwort btw.
@muyustan Sie müssen die gesamte Vektortabelle kopieren, sonst versagen andere IRQs. Und normalerweise können Sie 0x58 während der Flash-Programmierung ändern.
@Jeroen3 aber woher weiß ich dann die Adresse der Funktion, die ich definieren werde?
@muyustan Linker-Skript, das dies definiert, oder das In-Assembly-"Label" verwendet, das Sie auch dort für JMP verwenden würden.
@MarcusMüller ok, ich denke, ich sollte es vorerst loslassen, da die beabsichtigte Sache ein bisschen über mein Wissen hinausgeht. Übrigens habe ich das, was ich im obigen Kommentar erwähnt habe, ausprobiert, konnte aber nicht die richtigen zu verwendenden Speicherbereiche finden.
@muyustan jede RAM-Region reicht aus. Das ist das Schöne an einer so flexiblen Lösung.
@MarcusMüller ok, ich habe im Programmierhandbuch im Abschnitt zu VTOR gesehen, dass die Adresse, die in VTOR eingegeben werden kann, auf 0x00000080 bis 0x3FFFFF80 beschränkt ist. Also, ist Ihre "Jeder RAM-Bereich wird es tun" eine gültige Aussage? Ich urteile nicht, das ist eine direkte Frage. Was mich daran hinderte, diesen Prozess überhaupt auszuprobieren, war, dass ich nicht herausfinden konnte, welcher Adressbereich der Teil ist, den ich als RAM verwenden kann. Es gibt nur viele Informationen in verschiedenen Dokumenten (Ref. Mann, Prog. Mann, Datenblatt, ...), die ich aus dieser Komplexität nicht herausholen konnte. Die meisten Adressen, die ich versucht habe.......
Eine Schreiboperation in sie führte zu einem Fehler, dh ich konnte keine Daten darauf schreiben und beobachtete den Speicherbrowser im Debug-Modus.
@muyustan ist eine gute Frage. Schau mal hier: infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.ddi0439b/…
@muyustan Für VTOR können Sie jede interne RAM-Region verwenden, nicht extern. Wenn Sie die schwache Verknüpfung nicht verwenden, lesen Sie in der Compiler-Dokumentation nach, welche Adressattribute Sie an Funktionen vergeben können.
@MarcusMüller Was sind die Mindestanforderungen, um diese Dokumente zu verstehen? Ich glaube, ich habe allgemeine Kenntnisse über Dinge, aber diese Dokumente wie die, die Sie gerade verlinkt haben, sehen für mich so aus, als wären sie auf Mandarin-Chinesisch geschrieben. Wie auch immer, ich werde es untersuchen und versuchen zu verstehen. Vielleicht werde ich eine weitere Frage zu meinen Verwirrungen, Verständnissen und wahrscheinlicheren "Nicht-Verständnissen" in Bezug auf diese Speicherprobleme posten. Wenn ich das tue, werde ich dich dort markieren, hoffe ich. Danke für Ihr Bemühen.
@muyustan Ich finde du machst das gut. Moderne Mikrocontroller sind unglaublich komplexe Computer. Es ist nicht möglich, alles innerhalb einer Schwachstelle zu verstehen :) Weiter so!
@MarcusMüller ok, eine letzte Sache hat mich verwirrt, ich habe mir bis vor wenigen Minuten nie die Bitstruktur von VTOR angesehen, da ich nie an den Punkt komme, an VTOR zu schreiben. Allerdings habe ich es gerade geschaut, prog. Manpage 227, und sah, dass nur 21 Bits verfügbar sind, um in dieses Register zu schreiben. Wie kann man also eine beliebige 32-Bit-Adresse hineinschreiben?
du kannst nicht! a) Sie haben nicht den vollen 32-Bit-Adressraum, wie Sie selbst bemerkt haben (0x00000080 bis 0x3FFFFF80), daher sind die oberen Bits nicht nützlich, und b) wenn Sie den Absatz über der Tabelle lesen, sehen Sie, dass die unteren Bits sind ebenfalls nicht wählbar.
@muyustan Kann ich wiederholen, was Marcus gesagt hat, du machst das gut! Mikrocontroller erfordern, dass Sie auf einem sehr niedrigen Niveau arbeiten und Standorte, Schutzfunktionen, Interrupts usw. verstehen. Diese Dinge werden bei der Arbeit an einem gehosteten System abstrahiert. Wenn Sie so etwas wie einen Cortex-M4 haben, haben Sie auch den Prozessor und dann alle herstellerspezifischen Peripheriegeräte, mit denen Sie sich befassen müssen. Und gute Fragen :)
Eine andere Sache: So wie Sie nicht versuchen würden, Ihren PC ohne Betriebssystem zu programmieren (Sie würden verrückt werden, wenn Sie Dinge initialisieren, bevor Sie sie verwenden können – und dann herausfinden, wie Sie die Dinge am Laufen halten), verwenden Sie solche wirklich nicht Mikrocontroller ohne ihre HALs. In den meisten Fällen sind diese HALs wirklich "kostenlose Abstraktionen", da sie Ihren Registeradressen nur Namen geben, mit denen Sie arbeiten können, oder Ihnen ermöglichen, eine Funktion im Hersteller-ROM aufzurufen, um in Flash zu schreiben, anstatt dass Sie es tun müssen um die gleiche Funktion zu implementieren. Ich stimme zu, es ist großartig, um zu lernen, wie ein Prozessor funktioniert, was Sie tun,
Aber Sie müssen sich darüber im Klaren sein, dass Sie diesen Weg härter angehen, als es der durchschnittliche Entwickler für MCU-Firmware tun würde. Wenn Sie lernen möchten, wie CPUs im Allgemeinen funktionieren, dann beginnen Sie mit etwas Einfacherem als einer ARMv7-32-Bit-CPU wie dieser ... die Sie tatsächlich auf echter Hardware ausführen müssen (was eine Ebene der Befriedigung hinzufügt, wenn eine LED tatsächlich blinkt, aber fügt auch eine enorme Menge an Komplexität hinzu). Wenn Sie lernen möchten, wie man mit einer CPU umgeht, beginnen Sie vielleicht mit einer einfachen CPU in einem Emulator - das erleichtert das Experimentieren. Es wird Ihnen noch viele nützliche Grundlagen beibringen!
@awjlogan und Marcus, danke euch beiden für eure Kommentare/Ideen/Vorschläge, ich werde sie im Detail prüfen.
Nun, nach zehn Stunden kann ich sagen, dass ich es geschafft habe, die Vektortabelle an einen gewünschten Speicherort zu verschieben und benutzerdefinierte Funktionen der Interrupt-Service-Routine zu verwenden. Allerdings ist mir etwas aufgefallen, das Zurücksetzen funktionierte gut, obwohl ich die Vektortabelle verschoben hatte. Befindet sich der Reset-Handler immer an einer festen Adresse und bewegt sich nicht mit der NVIC-Vektortabelle mit?

Also dachte ich, vielleicht nur eine Idee, diese Orte enthalten die Speicheradresse (Zeiger) zu den Interrupt-Handler-Funktionen.

So funktioniert das. Es gibt auch VTOR, wie Marcus es beschrieben hat. Einfache Projekte verwenden jedoch eine sogenannte Start-Assembler-Datei, startup.sin der normalerweise der Stapel, der Heap und die Vektortabelle an ihrer Position abgelegt werden.
Die Vektortabelle in startup.sist schwach mit einem Standardhandler verknüpft, der nichts tut.
Wenn Sie an anderer Stelle eine Funktion mit genau demselben Namen definieren, überschreibt sie diese Standardeinstellung.

Dabei spielt es für den Cortex M4 noch keine Rolle, dass Ihr Chip von ST ist.

Ich weiß nicht, welchen Compiler Sie verwenden, aber hier ist eine ausführliche Beschreibung der Startdatei von ARM: https://community.arm.com/developer/ip-products/processors/b/processors-ip-blog/ posts/decodierung-der-startdatei-für-arm-cortex-m4

Danke! was denkst du über meinen Kommentar unter der Antwort von Marcus? Weil ich nicht erreichen konnte, was ich beabsichtigte.

Diese Adresse ist Programm-Flash. Wenn Sie in Flash schreiben möchten, ist es möglich, Sie müssen es zuerst mit dem Flash-Peripheriegerät löschen, und Sie können das Programm, das Sie ausführen, nicht wirklich löschen, also tun Sie das nicht. Es gibt zwei Möglichkeiten, dies richtig zu machen. Sie können die Vektortabelle in den SRAM kopieren und das NVIC anweisen, auf die Vektortabelle im SRAM zu zeigen, sodass Sie den Vektor frei ändern können. Eine häufigere Lösung wäre die Verwendung eines festen Interrupt-Codes, der eine Adresse von einer Variablen nimmt und zu dieser Adresse springt, sodass Sie einfach ändern können, wohin die Variable zeigt.

danke, aber ich konnte nicht genau verstehen, was Sie mit "einem festen Interrupt-Code" meinten
oder wenn Sie können, erläutern Sie bitte den Satz, der mit "eine häufigere Lösung ..." beginnt, etwas weiter.
Lassen Sie die Vektoren im Flash bleiben, zeigen Sie den Vektor auf den Code im Flash, lassen Sie den Code im Flash einen Zeiger aus dem SRAM lesen, wo aufgerufen (oder gesprungen) werden soll. Aktualisieren Sie den Zeiger im SRAM, wenn Sie auf eine beliebige Funktion zeigen möchten. Erstellen Sie in der Sprache C eine Interrupt-Routine, die eine Funktion über einen Funktionszeiger aufruft.