/* Jump to application Reset Handler in the application */
9
asm("bx %0"::"r"(app_start_address));
APP_START it hier z.B 0x00000400 da der Bootloader kleiner als 1kb ist.
aber selbst dieser "orginale" Bootloader startet bei mir nicht die app
:(
Der speicher wird richtig beschrieben. Das hab ich geprüft indem ich den
gleichen hex File mit atmel studio an die adresse 0x00000400 geflasht
hatte.
Ausserdem hab ich noch die reine C variante getestet
(quelle:https://github.com/avrxml/asf/blob/master/sam0/applications/spi_master_bootloader/spi_master_bootloader.c)
die da so aussieht:
/* Jump to user Reset Handler in the application */
15
application_code_entry();
mit dem gleichen ergebnis. Er macht nach dem Sprung "nix". Wenn ich das
Ganze debugge, sehe ich das er im per Bootloder geladenen Programm
rumspringt (zeigt da ja nur Assembler da er die Sourcen ja net hat).
mein Assembler Verständnis hält sich in grenzen... also sehe ich nicht
wirklich was er da macht. Normal laufen tut das geladene Programm aber
nicht :(
bin für jeden Tipp dankbar :)
eine Sache hab ich grade noch gefunden. Der Bootloder startet sich
selbst neu wenn oder nachdem er zur app gesprungen ist. Aber auch nur
wenn eine da ist. Meine Vermutung wäre also das der Reset Handler der
app wieder auf 0x00000000 zeigt und so der BL neu gestartet wird.
Sollte das nicht eigentlich vom Stack Pointer verhindert werden?
Du musst mal schauen in welchem teil des RAMs dieser dein Programm
erwartet. Steht da nichts oder nur Müll wird wieder der Bootloader ->
Adresse 0x00000..
aufgerufen. So ist das bei SAMD20 und 21
Hi,
danke für den tipp. Das passiert aber selbst wenn ich ein garantiert
laufendes Programm mit Atmel Studio an die start Adresse flashe. Habe es
auch schon ausgelesen und nachgeguckt. Ist alles wo es sein soll im
Flash.
(edit)
Wenn noch keine App an der stelle ist, bleibt der Bootloader einfach
hängen. Startet sich also nicht neu.
Am Reset Handler der app liegt es nicht. Hab mir einen gemacht der etwas
sichtbares macht und dazu kommt es nicht.
Um nochmal sicher zu gehen das ich nix übersehen habe, hab ich nochmal
den "originalen" Atmel Sercom Bootloader genommen und nur die ziel MCU
auf SAMD10 (statt orginal D11) umgestellt. Dann noch den app start Punkt
von 0x00000400 auf 0x00000800 geändert weil wenn ich das in Atmel Studio
baue ist es etwas größer als 1k.
Wenn ich das debugge (ohne das der Bootpin auf masse geschaltet ist)
springt er ins nirgendwo.
Jetzt Flashe ich eine app (das "wenn Knopf gedrückt, LED aus" Beispiel
als .bin Datei) an Position 0x00000800 natürlich ohne den Flash zu
löschen. Und es passiert nix :(
Ich hab mal alle drei Sachen Angegangen...
Hoffe das stört nicht das ich hier was Monolog führe.. aber vielleicht
sieht ja Jemand wo das Problem ist wenn ich beschreibe was ich
versuche..
Habe ein neues Projekt in Atmel Studio auf gemacht und das Tool so
eingestellt das es nur den nötigen Bereich löscht wenn es flasht. So
kann ich an anderer stelle im Speicher die zu startende app ablegen und
sehen was passiert.
nach dem flashen der bin an position 0x00000800
im speicher sieht das so aus:
1
:1007D000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF29
2
:1007E000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF19
3
:1007F000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF09
4
:1008000050080020F1000000ED000000ED000000A5
5
:1008100000000000000000000000000000000000D8
6
:10082000000000000000000000000000ED000000DB
7
:100830000000000000000000ED000000ED000000DE
8
...
nachdem ich mein test Projekt flashe/debugge:
1
... atmel studio überschreibt 2k mit programm und ansonnsten 00000
2
:1007B0000000000000000000000000000000000039
3
:1007C0000000000000000000000000000000000029
4
:1007D0000000000000000000000000000000000019
5
:1007E000000000000000000000000000FFFFFFFF0D
6
:1007F000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF09
7
:1008000050080020F1000000ED000000ED000000A5
8
:1008100000000000000000000000000000000000D8
9
:10082000000000000000000000000000ED000000DB
10
:100830000000000000000000ED000000ED000000DE
11
:10084000ED000000ED000000ED000000ED000000F4
12
...
aber ab 0x00000800 ist noch die app wie sie soll. Unangetastet.
mein projekt ist nur:
/* Jump to user Reset Handler in the application */
21
application_code_entry();
22
23
/* Replace with your application code */
24
while(1)
25
{
26
}
27
}
wobei die Assembler variante zum selben Ergebnis führt. Wenn ich das
debugge, sehe ich das der immer wieder im eigenen Reset Handler (der des
projekts, nicht der app) landet. Das aber nur wenn die Sprungadresse
stimmt und trifft. Ansonsten springt er ins Nichts.
>Hoffe das stört nicht das ich hier was Monolog führe..
Das passt schon. Vielleicht kann ja irgend jemand mal Deine Ergebnisse
verwenden.
Leider kann ich Dir nicht weiter helfen, weil ich die SAMD20 benutze und
mich mit den Speicherbereichen noch nicht auseinandergesetzt habe.
Irgendwann werde ich mich mit der Nutzung des Flash als EEPROM Ersatz
beschäftigen müssen. Das könnte in Richtung der obigen Problematik
gehen.
per makefile baue, springt der zielsicher in den Dummy Handler des
Startup Files (unendlich schleife).
mache ich das gleiche in Atmel Studio springt er zur while(1) schleife
des Reset Handlers (unter dem main aufruf).
wenn ich "SystemInit();" vorher aufrufe, schleift er durch. Als ob der
Sprung einfach resetten würde.
habe das Gefühl das Debuggen hier nicht wirklich weiter hilft ...
Zu sagen ist wieder das Assembler und C variante das gleiche Ergebnis
haben und auch das entfernen von "__set_MSP()" und "SCB->VTOR" nix
ändert.
Ziele ich auf eine falsche oder leere Adresse passiert nix. Deshalb
denke ich das der Sprung befehl erstmal funktioniert...
Mir gehen so langsam die Ideen aus :(
Die Firmware ist ein voll/eigenständiges Programm, was auch vom normalen
Flash-Start laufen könnte.
Du könntest mal schauen, ob die korrekten Werte aus deinem Flash Image
in den MSP, VTOR und die function geladen werden.
Ggf. sind der IRQ Disable und die Barriers noch wichtig.
MSP hab ich ersetzt da der das so nicht gefunden hatte. und das "user
code entry" hab ich initialisiert "void (*user_code_entry)(void);"
Im Debugger fährt er jetzt einfach in den unendlich loop wo er nie
landen dürfte -.-.. wenn ichs mit Makefile baue geht es wieder in den
Dummy Handler.
Hab mir extra ein mini Programm das nur den Port A9 (LED am D10
xplained) high schaltet gemacht.
1
:10000000000400208D0000009D0000009D00000005
2
:1000100000000000000000000000000000000000E0
3
:100020000000000000000000000000009D00000033
4
:1000300000000000000000009D0000009D00000086
5
:100040009D0000009D0000009D0000009D0000003C
6
:100050009D0000009D0000009D0000009D0000002C
7
:100060009D0000009D0000009D0000009D0000001C
8
:100070009D0000009D0000009D0000009D0000000C
9
:100080009D0000009D0000009D0000008022024BAA
10
:1000900092009A609A617047004400418022024BAE
11
:1000A00092009A617047C04600440041FFFFFFFF85
mehr ist das nicht. steht es an Adresse 0 leuchtet die LED.
und hier für den test bei Adresse 800 das gleiche
1
:10080000000400208D0000009D0000009D000000FD
2
:1008100000000000000000000000000000000000D8
3
:100820000000000000000000000000009D0000002B
4
:1008300000000000000000009D0000009D0000007E
5
:100840009D0000009D0000009D0000009D00000034
6
:100850009D0000009D0000009D0000009D00000024
7
:100860009D0000009D0000009D0000009D00000014
8
:100870009D0000009D0000009D0000009D00000004
9
:100880009D0000009D0000009D0000008022024BA2
10
:1008900092009A609A617047004400418022024BA6
11
:1008A00092009A617047C04600440041FFFFFFFF7D
Ich glaube langsam das ich irgendetwas anderes übersehe / falsch mache..
(edit)
Wenn kein Ziel vorhanden ist (0xFFFFFFFF) landet er bei:
--- No source file
-------------------------------------------------------------
FFFFFFFE ??? Memory out of bounds or read error
also wie vorher springt da was, nur danach geht irgendwas schief.
Moin,
Hast du mal die Optimierungsflags des Compilers überprüft?
Ich hatte schon manch ein erstaunliches Verhalten (unter anderem einen
nicht funktionierenden Bootloader), wenn der Compiler zu viel optimiert
hat.
In meinem Bootloader auf stm32 habe ich ansonsten ein paar volatiles
eingestreut, kann aber sein dass es Paranoia war. Never touch a running
system ;)
Der betreffende Abschnitt sieht bei mir so aus:
hi,
dank auch dir für die mühe und den code :) aber leider wieder nix :/
Wo kann ich denn in den Atmel Studio Einstellungen die Optimierung
einstellen?
Ich denke ich bin aber wieder mal ein Schrittchen weiter..
Wenn ich app_start_adress so initiiere:
uint32_t *app_start_address = (uint32_t *)(APP_START_ADDRESS+4);
statt
uint32_t app_start_address = *(uint32_t *)(APP_START_ADDRESS+4);
Springt er immerhin für einen tackt auf die Adresse.. nur um im nächsten
wieder irgendwohin zu gehen... falls da Jemand schlau draus wird:
von hier aus
Springt er zu 0x00000800 und fängt auch an den Code an der Adresse ab zu
arbeiten. einfach eine LED an schalten geht. aber er bleibt da im Dummy
Handler der app hängen. Egal ob ich am Stack und am Vectortable was
mache oder nicht. Auch unbeeinflusst von aktiven oder inaktiven
Interrupts.
ist "mov pc" denn überhaupt die richtige Richtung? und habt Ihr
vielleicht eine Idee warum der in den Dummy Handler der app springt?
Ah und sehe ich das richtig das ich mit "ldr r2, [r2]" einen pointer aus
r2 machen würde? Wenn ich das mache springt er wieder in den Dummy
Handler des Bootloaders.
hi,
ja da gibt es einige fuse settings. Wenn ich das richtig sehe, kann man
mit den fuses (neben anderen Sachen) den Bootloader nur schützen. Ich
hab da nix gesehn was mit dem boot Verhalten zu tuen haben sollte.
weiter gehts...
ich versuch mich jetzt an Assembler weil so ja der Kompiler größtenteils
raus ist.
Habe mir das hier zusammen gesucht:
1
asmvolatile("ldr r1, =0x800");// lade 0x800 in R1
2
asmvolatile("ldr r0, [r1]");// lade pointer? auf 0x800 in R0
3
asmvolatile("msr msp, r0");// MSP (stack pointer auf R0 also 0x800)
4
asmvolatile("ldr r3, =0x804");// lade 0x804 in R3
5
asmvolatile("ldr r2, [r3]");// lade pointer? auf 0x804 in R2
6
asmvolatile("mov pc, r2");// springe zu R2 (0x804)
damit springt er aber zu 0x000000AC. ich hab k.A. warum. mit "bx r2"
passiert genau das gleiche wie mit "mov pc, r2"
wenn ich das aber auf adresse 0x00000000 richte:
1
asmvolatile("ldr r1, =0x0");// lade 0x0 in R1
2
asmvolatile("ldr r0, [r1]");// lade pointer? auf 0x0 in R0
3
asmvolatile("msr msp, r0");// MSP (stack pointer auf R0 also 0x0)
4
asmvolatile("ldr r3, =0x4");// lade 0x4 in R3
5
asmvolatile("ldr r2, [r3]");// lade pointer? auf 0x04 in R2
6
asmvolatile("mov pc, r2");// springe zu R2 (0x4)
springt er nicht auf irgendeine Adresse sondern landet er sauber im
eigenen Reset Handler (adresse 0x000000F0) und startet neu.
Da muss doch irgendwas sein was ich vom Prinzip her falsch mache :(
Tada :)
irgendwie auch dumm :/ die Lösung ist das man im linker script der app
das "rom origin" auf die start Adresse stellen muss.
Orginal:
1
MEMORY
2
{
3
rom(rx):ORIGIN=0x00000000,LENGTH=0x00004000
4
ram(rwx):ORIGIN=0x20000000,LENGTH=0x00001000
5
}
mein Bootloder ist kleiner als 1k. also schreibt er die app an
0x00000400
also:
{
rom (rx) : ORIGIN = 0x00000400, LENGTH = 0x00004000
ram (rwx) : ORIGIN = 0x20000000, LENGTH = 0x00001000
}
[/c]
Gefunden habe ich das
hier:http://www.atmel.com/images/atmel-42238-uart-based-sam-ba-bootloader-for-sam-d20_ap-note_at04189.pdf
Seite 3.
Also so ziemlich alle hier gezeigten Beispiele werden wohl gehen.
Naja hab auf jeden Fall was gelernt.
Ein Nachtrag noch. Den Vectortable muss man nicht umstellen, da das die
app in ihrem startup code macht (zumindest wenn man die startup files
der ASF bzw. vom Atmel Studio nimmt).
Ich mach den Sprung jetzt also erfolgreich so:
Wad W. schrieb:> Bisher klappt auch alles, bis auf das Starten der geladenen app.Wad W. schrieb:> bin für jeden Tipp dankbar :)
Ah - ja so?
Also erstmal eines: es gibt offenbar eine nicht kleinzukriegende Anzahl
von Leuten, die sich für großartig halten, wenn sie nen Startupcode in C
schreiben - so auch diese Atmel-Brüder, die den von dir genannten
Bootlader verzapft haben.
Aber mit sowas verkleistern sich die Leute schlichtweg ihre eigenen
Sinne. Bedenke mal, daß bei eigentlich allen Cortexen die Vektortabelle
ganz am Anfang des Adressraumes zu stehen hat, also ab NULL. Ja, es gibt
auch welche, die diese Tabelle woanders hin verlegen können, aber
erstens müßte man das in der betreffenden Firmware dediziert tun und
zweitens meine ich, daß ein M0+ diese Verlegung nicht kann.
Also hast du die Vektortabelle fest im Bootlader und deine Firmware, die
du ja mit eben diesem Bootlader in den Flash hinter dem Bootlader
geladen hast, kann ohne üble Tricks keinerlei Interrupts benutzen ohne
dabei gnadenlos abzustürzen. Gilt auch für einen eventuell angelassenen
Watchdog.
Also, schreib dir deinen Startupcode selbst und zwar in Assembler,
richte dir dort alle Interrupthandler ein - und zwar resident und
nicht weak, reserviere dir am Ende des RAM einige nötige Bereiche, wo du
eventuelle Handler-Routinen deiner Firmware merken kannst und lebe
damit, daß du ab da für alle Interrupts etwas mehr Zeit einplanen mußt,
da deine Handler im Bootlader erstmal gucken müssen, ob für sie ein
Handler eingetragen ist und dann ggf. diesen aufrufen.
W.S.
Hi,
ich hab mich mit den Startupfiles bisher kaum befasst. bei den STM's
sind die mitgegebenen ja in Assembler. Ich hab mal geguckt und das
Register SCB->VTOR ist laut ARM genau dafür gemacht. Also würde nicht
sagen das es ein übler Trick ist wenn man den Vectortable rebased.
(http://infocenter.arm.com/help/topic/com.arm.doc.dui0662b/DUI0662B_cortex_m0p_r0p1_dgug.pdf)
seite 4-11.
Und so wie ich das jetzt verstanden habe setzt der startup Code von
Atmel den Vectortable auf den ROM Startwert aus dem linker. So müsste
der mit Bootloader geladene Code genauso stabil laufen wie wenn er an
stelle 0x0 stehen würde.
W.S. schrieb:> Ah - ja so?>> Also erstmal eines: es gibt offenbar eine nicht kleinzukriegende Anzahl> von Leuten, die sich für großartig halten, wenn sie nen Startupcode in C> schreiben
Na und? Warum sollte man ihn nicht in C schreiben? Da ist nichts drin
was man in C nicht sogar einfacher formulieren kann als in Assembler.
Abgesehen davon hat das mit dem Problem des OP nicht das geringste zu
tun, es ist nämlich vollkommen belanglos in welcher Sprache der
geschrieben ist solange er das beinhaltet und das tut was er soll.
> Aber mit sowas verkleistern sich die Leute schlichtweg ihre eigenen> Sinne.
Ich glaube eher Deine Sinne sind verkleistert.
> Bedenke mal, daß bei eigentlich allen Cortexen die Vektortabelle> ganz am Anfang des Adressraumes zu stehen hat, also ab NULL.
Ja, die tut man da hin wo das Linkerscript welches man zu benutzen
beabsichtigt das entsprechende Symbol bzw die entsprechende Section für
die Vektortabelle definiert hat. Was war nochmal Dein Punkt?
> Ja, es gibt> auch welche, die diese Tabelle woanders hin verlegen können, aber> erstens müßte man das in der betreffenden Firmware dediziert tun und> zweitens meine ich, daß ein M0+ diese Verlegung nicht kann.
Das kann jeder Cortex vom M0+ aufwärts, dafür gibts das VTOR Register im
System Control Block. Das ist der übliche Weg.
> Also hast du die Vektortabelle fest im Bootlader und deine Firmware, die> du ja mit eben diesem Bootlader in den Flash hinter dem Bootlader> geladen hast, kann ohne üble Tricks keinerlei Interrupts benutzen ohne> dabei gnadenlos abzustürzen. Gilt auch für einen eventuell angelassenen> Watchdog.
Bullshit, bevor er in die Anwendung springen lässt setzt der Bootloader
einfach das VTOR-Register so daß es auf die Vektortabelle der geladenen
Anwendung zeigt. Fertig.
> Also, schreib dir deinen Startupcode selbst und zwar in Assembler,
Was hat das damit zu tun in welcher Sprache das geschrieben ist? Er
kanns auch in Pascal oder in Fortran schreiben wenns ihm Spaß macht und
wenn der verwendete Compiler die nötigen Pragmas oder Attribute
beherrscht um den Speicherort bestimmter Objekte zu bestimmen.
Pragmatische Programmierer die es neu schreiben müssen (weil das
Copyright des vom Hersteller mitgelieferten Startup-Codes nicht passt
oder warum auch immer) schreiben es kurzerhand einfach in C weil es
nicht den geringsten, wirklich nicht den allergeringsten Grund gibt das
in ASM zu tun. Nicht den geringsten. Außer man heißt W.S und will der
Welt beweisen was für ein toller Kerl man ist und schreibt die 3
Schleifen und große const struct in ASM.
> richte dir dort alle Interrupthandler ein - und zwar resident und> nicht weak,
Was ist denn das jetzt wieder für ein Unfug? Welchen Vorteil sollte es
haben im Startup-Code schon irgendwelches Wissen über die Anwendung fest
zu verdrahten? Der richtige Weg ist es weak Symbole mit sinnvollen
default-implementierungen zu schreiben für alles was die Anwendung
eventuell überschreiben und selbst implementieren wollen könnte.
> reserviere dir am Ende des RAM einige nötige Bereiche, wo du> eventuelle Handler-Routinen deiner Firmware merken kannst
RAM? RAM? Echt jetzt? Das wird ja immer lustiger. Obwohl: So richtig
unbeschwert lustig ist das eigentlich schon nicht mehr so ganz, das
schlägt an dieser Stelle eher ins komisch-tragische um :-(
> und lebe> damit, daß du ab da
...dass Du ab da ein vollkommen verklausuliertes vermurkstes Gebilde
gebaut hast das seinesgleichen sucht
> für alle Interrupts etwas mehr Zeit einplanen mußt,
...und außerdem noch Blutdrucktabletten für den Programmierer der den
Code irgendwann mal erbt, die würd ich auch gleich noch einplanen und
mitliefern.
> da deine Handler im Bootlader erstmal gucken müssen, ob für sie ein> Handler eingetragen ist und dann ggf. diesen aufrufen.
...man, man, man, was für ein blühender Unfug. Du haust ja manchmal
Sachen raus die sind schon sehr - ich sag mal kontrovers - aber da eben
hast Du echt mal die Messlatte locker nochmal nen Meter höher gelegt.
Hast Du zufällig mal ne Zeitlang mit Moby trainiert?