SRAM über SWD programmieren

Ich versuche, einen Cortex M3-basierten Mikrocontroller über SWD zu programmieren, mehr oder weniger von Anfang an. Ich habe eine SWD-Schnittstellenbibliothek geschrieben und auf einem zweiten Mikro laufen lassen.

Ich habe diesen Blogbeitrag weitgehend verfolgt: http://markdingst.blogspot.ie/2014/03/programming-internal-sram-over-swd.html

Sowie dieser Anwendungshinweis von SiLabs: https://www.silabs.com/Support%20Documents/TechnicalDocs/AN0062.pdf

Ich kann den Kern anhalten und SRAM lesen und schreiben. Ich frage mich, wie ich den Bare-Metal-Code erhalten kann, den ich in SRAM schreiben kann. Kann ich einfach die .hex-Datei nehmen, die der Compiler ausgibt, und diese Wort für Wort beginnend bei 0x20000000 in den SRAM schreiben?

Und wenn ja, welche Kernregister muss ich konfigurieren, damit das neue Programm im SRAM beim Zurücksetzen ausgeführt wird? Wird es ausreichen, den PC auf 0x20000000 einzustellen?

Ich freue mich über jede und jede Hilfe! Danke!

Antworten (2)

Wenn Sie ein Linker-Skript haben, das Ihre ausführbare Datei mit einer geeigneten Adresse für RAM verknüpft, können Sie die Hex-Datei interpretieren und die Nutzlastbytes extrahieren.

Aber es wäre wahrscheinlich einfacher, arm-none-eabi-objcopy zu verwenden, dh

arm-none-eabi-objcopy -O binary myproject.elf myproject.bin

Dadurch erhalten Sie eine rohe Binärdatei, die Sie auf den Chip schreiben können, beginnend mit der Basisadresse, für die Sie verlinkt sind. Beachten Sie, dass bei dieser Vorgehensweise die Basisadresse nicht in der Datei selbst erhalten bleibt - Sie müssen sicherstellen, dass dies zwischen der Dateierstellung und der Dateiverwendung konsistent bleibt. Dennoch ist dies eine ziemlich häufige Wahl - viele einfache Flash-Programme verstehen nur rohe Binärdateien, wobei die Zieladresse explizit auf der Befehlszeile angegeben wird.

Um vollständig aus dem RAM zu laufen, benötigen Sie einen Chip, mit dem Sie die Vektortabelle dorthin verschieben können. manche tun es und manche nicht. Wenn Sie das auf eine Weise tun können, die das Zurücksetzen überlebt und der Reset-Vektor in der Tabelle auf Ihren Code im RAM zeigt, kann es funktionieren. Oder Sie könnten eine Tabelle schreiben, die den Reset-Vektor im RAM auf die übliche Position im Flash zeigt. Denken Sie daran, dass die Verwendung des Zurücksetzens auf RAM etwas eingeschränkt ist, da dort normalerweise kein Programm zum Ausführen vorhanden wäre, es sei denn, es wurde dort abgelegt. Und das Etwas kann ein wenig aufräumen und einfach zur Startadresse verzweigen.

Danke für die Antwort, die Konvertierung in .bin war tatsächlich der Schritt, den ich vermisst habe. Ich habe dazu das hex2bin-Tool verwendet, und im Moment begnüge ich mich damit, den Flash-Controller zu verwenden, um diese Binärdatei auf Flash an Adresse 0 zu schreiben. Ich werde mich zu einem späteren Zeitpunkt erneut mit dem Schreiben in SRAM befassen, denke ich, und Ihr Die Beschreibung dazu wird mir sehr nützlich sein!

Ich kann sicherlich die Sache mit den eigenen Grundprinzipien schätzen und applaudieren. Aber ich empfehle auch, vor dem Laufen zu gehen. Nur weil Sie alles selbst machen wollen, heißt das nicht, dass Sie das, was da ist, nicht nutzen können oder sollten.

Sie sind auf dem richtigen Weg, vielleicht mit Ihren Tools oder vielleicht mit den Tools anderer Leute oder vielleicht mit einem Befehlssatzsimulator. Sie müssen die Verwendung einer Toolchain oder eines Assemblers beherrschen (gut genug werden), wenn Sie nicht in C schreiben oder Ihren eigenen Assembler schreiben möchten, für den ich sagen würde, gehen Sie dafür, aber verwenden Sie einen funktionierenden Assembler und Disassembler als Referenz / Validierung.

Der Cortex-m ist eine Pseudo-Harvard-Architektur. Sie müssen die Dokumente für Ihren speziellen Teil lesen. Idealerweise berühren sich der Programmbereich und der Datenbereich nicht, befinden sich auf separaten Schnittstellen, aber mit diesen Teilen können Sie ein Programm in den RAM herunterladen und einfach ausführen. Aber es ist Chip-spezifisch, erst kürzlich behandelt. Die Abrufseite könnte eine andere Adresse verwenden, um den RAM zu erreichen als die Datenseite. Ein ti msp432 cortex-m4, das ich mit dem RAM spiele, ist bei 0x20000000, aber es scheint nicht, dass Sie dort Code ausführen können, derselbe SRAM ist bei 0x01000000 abgebildet und Sie können beide Adressräume mit Datentransaktionen lesen und schreiben, müssen aber bei ausführen 0x01000000 damit es funktioniert.

Wenn Sie das einmal herausgefunden haben und herausgefunden haben, was Sie tun müssen, um ein Programm zu schreiben und zu assemblieren, dann ja, es ist eine "einfache" Angelegenheit, es herunterzuladen und dann die Ausführung mit dem auf die Einstiegspunktadresse gesetzten Programmzähler zu starten .

Je nachdem, welchen Teil Sie verwenden, gibt es möglicherweise verschiedene Möglichkeiten, um darauf zuzugreifen, uart-basierte Bootloader, swd, usb. Einige Entwicklungsboards werden als entfernbare Flash-Laufwerke angezeigt, und Sie kopieren einfach Ihre .bin-Datei und eine Front-End-MCU lädt diese für Sie in die Back-End-MCU und setzt sie zurück.

Was den Zustand der Maschine betrifft und was Ihr Programm tun muss, das liegt bei Ihnen, Sie werden nicht in der Lage sein, jede mögliche Situation abzudecken (hängende Hardware), also ist das erste, was Sie tun müssen, einfach zu beginnen und davon auszugehen, dass Sie gerade zurückgesetzt haben tatsächlich zurückzusetzen, dann müssen Sie je nachdem, wie Sie fortfahren möchten, möglicherweise alles rückgängig machen, was ein vorheriges Programm getan hat. Im Allgemeinen befindet sich die MCU-Firmware im Flash und das System bootet jedes Mal auf die gleiche Weise, sodass es sich im Grunde um eine bekannte Größe handelt. Und die Annahme hier ist, dass Sie RAM verwenden, um ein Programm zu entwickeln, das letztendlich in Flash sein wird und nicht mit unendlich möglichen Startbedingungen umgehen muss.

Der Cortex-m bootet so, dass Sie die Möglichkeit haben, den Stapelzeiger in der Vektortabelle zu setzen, und dann kümmert sich die Vektortabelle um die Einstellung des PCs, und dann übernimmt Ihr Code von dort. Sie können wählen, ob Ihr Lader den Stapelzeiger und den Programmzähler setzen soll, oder Sie können wählen, ob Ihr Programm den Stapelzeiger setzen soll. Jenseits dieser Einstellung sollte der SP Sie zum Laufen bringen. Beachten Sie, dass bei Verwendung des bx-Befehls (oder pop oder einer anderen kurzen Liste möglicher Befehle) das lsbit der Adresse gesetzt werden muss, um anzuzeigen, dass Sie in den Thumb-Modus wechseln oder im Thumb-Modus bleiben. Dieses Bit wird durch die Anweisung entfernt, dass der Programmzähler dieses Bit eigentlich nicht gesetzt hat, und es ist möglicherweise sowieso nicht möglich, es zu setzen, also sollte 0x20000000 oder 0x01000000 die richtige Adresse sein, nicht 0x20000001 oder 0x01000001 IMO.

BEARBEITEN

Verwenden von GNU-Tools

sram.s

.cpu cortex-m0
.thumb

.thumb_func
.global _start
_start:
    ldr r0,stacktop
    mov sp,r0
    bl notmain
    b hang

.thumb_func
hang:   b .

.align
stacktop: .word 0x20001000

.thumb_func
.globl PUT32
PUT32:
    str r1,[r0]
    bx lr

.thumb_func
.globl GET32
GET32:
    ldr r0,[r0]
    bx lr
.end

blinker01.c

void PUT32 ( unsigned int, unsigned int );
unsigned int GET32 ( unsigned int );

void notmain ( void )
{
    while(1)
    {
        PUT32(0x20000800,GET32(0x20000800)+1);
    }
}

sram.ld

MEMORY
{
    ram : ORIGIN = 0x20000000, LENGTH = 0x1000
}
SECTIONS
{
    .text : { *(.text*) } > ram
    .rodata : { *(.rodata*) } > ram
    .bss : { *(.bss*) } > ram
}

Makefile

ARMGNU = arm-none-eabi
#ARMGNU = arm-linux-gnueabi
AOPS = --warn --fatal-warnings -mcpu=cortex-m0
COPS = -Wall -Werror -O2 -nostdlib -nostartfiles -ffreestanding  -mcpu=cortex-m0
all : blinker01.gcc.thumb.sram.bin

clean:
    rm -f *.bin
    rm -f *.o
    rm -f *.elf
    rm -f *.list
    rm -f *.hex
    rm -f *.srec

sram.o : sram.s
    $(ARMGNU)-as $(AOPS) sram.s -o sram.o

blinker01.gcc.thumb.o : blinker01.c
    $(ARMGNU)-gcc $(COPS) -mthumb -c blinker01.c -o blinker01.gcc.thumb.o

blinker01.gcc.thumb.sram.bin : sram.ld sram.o blinker01.gcc.thumb.o
    $(ARMGNU)-ld -o blinker01.gcc.thumb.sram.elf -T sram.ld sram.o blinker01.gcc.thumb.o
    $(ARMGNU)-objdump -D blinker01.gcc.thumb.sram.elf > blinker01.gcc.thumb.sram.list
    $(ARMGNU)-objcopy blinker01.gcc.thumb.sram.elf blinker01.gcc.thumb.sram.hex -O ihex
    $(ARMGNU)-objcopy blinker01.gcc.thumb.sram.elf blinker01.gcc.thumb.sram.srec -O srec --srec-forceS3
    $(ARMGNU)-objcopy blinker01.gcc.thumb.sram.elf blinker01.gcc.thumb.sram.bin -O binary

Ein einfaches asm-Beispiel ist ... einfacher ... ging weiter und fügte ein bisschen C hinzu. Für einen stm32 können Sie dies beispielsweise bei 0x20000000 laden und ausführen, wie im Linker-Skript sram.ld gezeigt. Auf einem anderen Chip (ti msp432 weiß ich zufällig, dass Sie diesen Ursprung möglicherweise auf 0x01000000 ändern und dort laden müssen).

Dies erzeugt eine Reihe von Formaten für die Binärdatei, die jeweils relativ einfach zu analysieren sind, zum Beispiel ein srec:

S0200000626C696E6B657230312E6763632E7468756D622E7372616D2E7372656332
S315200000000248854600F008F8FFE7FEE700100020CA
S31520000010016070470068704710B50448FFF7FAFF83
S31520000020411C0248FFF7F4FFF7E7C046000800200E
S70520000000DA

(Hinweis, dies ist der echte srec, Sie können diesen extrahieren und versuchen, ihn zu laden und auszuführen)

und verwenden Sie diese, um Daten über swd in Ihren Chip zu laden und dann auszuführen. Es gibt Ihnen sogar einen Einstiegspunkt in die srec. elf, ihex machen das auch. die rohe binäre Bilddatei, die Sie gerade gelesen und hineingeschoben haben.

Dieses spezielle Beispiel können Sie laden und dann stoppen, 0x20000800 überprüfen und sehen, welcher Wert es ist, dann fortfahren und dann wieder stoppen und sehen, dass es sich ändert. Wenn Sie viel einfachere Testprogramme benötigen, z. B. mehrere Nops und dann eine Endlosschleife, können Sie sehen, ob Ihr Programm geladen und ausgeführt wird, und Sie können Register anhalten und untersuchen. Ändern Sie die Anzahl der Nops und sehen Sie, ob sich der PC das nächste Mal ändert, oder lassen Sie ihn Register modifizieren und sehen Sie nach. Aus dem Makefile usw. sollten Sie erkennen können, dass Sie Ihr gesamtes Programm in sram.s haben können und keinen C-Compiler benötigen.

Der obige Code funktioniert mit beiden Varianten none-eabi oder linux-gnueabi.

EDIT2

Wenn ich für Flash baue, verwende ich einen etwas anderen Bootstrap

.thumb_func
.global _start
_start:
stacktop: .word 0x20001000
.word reset
.word hang
.word hang
.word hang
.word hang
.word hang
.word hang
.word hang
.word hang
.word hang
.word hang
.word hang
.word hang
.word hang
.word hang

.thumb_func
reset:
    bl notmain
    b hang
.thumb_func
hang:   b .

Theoretisch können Sie beides tun, indem Sie Ihren Einstiegspunkt auswählen. Sie könnten beispielsweise den Reset-Code den Stapelzeiger setzen lassen, obwohl dies nicht erforderlich ist, da er sich in der Vektortabelle befindet, aber Sie könnten den Reset-Handler dies tun lassen , und dann herausfinden, wo sich dieser Reset-Handler befindet, und wenn er in Sram geladen wird, geben Sie ihn an diesem Offset ein, wenn er beim Flashen einfach richtig bootet. Natürlich müssten Sie positionsunabhängig bauen, ich bevorzuge Bootstraps, dann bauen Sie eine Flash-Version und eine Sram-Version mit einem anderen Linker-Skript für jedes und verschiedene Bootstrap-Programm, das sich nur in den obigen _start und reset unterscheidet, der Rest ist das gleiche.

Beachten Sie, dass (wie ich unangenehm festgestellt habe) das Startup/Init-Geschäft in der GCC-Toolchain zurückgeht und den gesamten Vektor beim Start des Programms erneut schreibt, also selbst wenn Sie Ihre .hex haben und sie an eine beliebige Stelle schreiben, das Startup vector wird sofort überschrieben, wenn Sie in Ihren Code springen! Ich ging damit um, indem ich das #define fand, das dem Startcode mitteilte, was in die Vektoren geladen werden sollte, und es reparierte.
hängt davon ab, wie Sie die Toolchain verwenden, Sie können die Vektortabelle besitzen und alles kontrollieren, Sie müssen weder die Vektortabellen noch den Bootstrap-Code verwenden, der mit den GNU-Tools bereitgestellt wird. Es ist deine Entscheidung. kann leicht Code enthalten, in den Sie einfach verzweigen oder den Programmzähler setzen können.
Wenn Sie swd verwenden, können Sie es einfach ausführen, ohne einen vektorbasierten Reset durchzuführen. Ich kenne das swd-Protokoll noch nicht so gut, habe aber openocd auf mehreren dieser Cortex-m-Chips verwendet und es funktioniert. also wenn sie es können kannst du es auch.
Es war nicht ohne weiteres ersichtlich, wie man das aus dem Setup-Code herausreißen konnte, ohne ein großes Durcheinander zu machen.
Beispiele zur Antwort hinzugefügt