Forum: Mikrocontroller und Digitale Elektronik Atmel ARM SAMD10 Bootloader, start app problem


von Wad W. (wad_wer)


Lesenswert?

Hi,

ich versuche grade einen kleinen Bootloader nach meinen Vorstellungen zu 
bauen. Bisher klappt auch alles, bis auf das Starten der geladenen app.

Als vorbild hatte ich mir diesen Bootloader genommen:
http://atmel.force.com/support/articles/en_US/FAQ/Low-footprint-SERCOM-UART-bootloader-for-SAM-D10-SAM-D11-devices

darin wird die app so gestartet:
1
    app_start_address = *(uint32_t *)(APP_START + 4);
2
    /* Rebase the Stack Pointer */
3
    __set_MSP(*(uint32_t *) APP_START);
4
5
    /* Rebase the vector table base address */
6
    SCB->VTOR = ((uint32_t) APP_START & SCB_VTOR_TBLOFF_Msk);
7
8
    /* 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:
1
    /* Pointer to the Application Section */
2
    void (*application_code_entry)(void);
3
4
    /* Rebase the Stack Pointer */
5
    __set_MSP(*(uint32_t *) APP_START_ADDRESS);
6
7
    /* Rebase the vector table base address */
8
    SCB->VTOR = ((uint32_t) APP_START_ADDRESS & SCB_VTOR_TBLOFF_Msk);
9
10
    /* Load the Reset Handler address of the application */
11
    application_code_entry = (void (*)(void))(unsigned *)(*(unsigned *)
12
        (APP_START_ADDRESS + 4));
13
14
    /* 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 :)

: Bearbeitet durch User
von Wad W. (wad_wer)


Lesenswert?

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?
1
 /* Rebase the Stack Pointer */
2
    __set_MSP(*(uint32_t *) APP_START);

Seht ihr da meinen Fehler?

von Marco H. (damarco)


Lesenswert?

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

von Wad W. (wad_wer)


Lesenswert?

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.

: Bearbeitet durch User
von Wad W. (wad_wer)


Angehängte Dateien:

Lesenswert?

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...

: Bearbeitet durch User
von Wad W. (wad_wer)


Lesenswert?

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:
1
#include "sam.h"
2
#define APP_START_ADDRESS  0x00000800
3
4
int main(void)
5
{
6
    /* Initialize the SAM system */
7
    SystemInit();
8
  /* Pointer to the Application Section */
9
  void (*application_code_entry)(void);
10
  
11
  /* Rebase the Stack Pointer */
12
  __set_MSP(*(uint32_t *) APP_START_ADDRESS);
13
  
14
  /* Rebase the vector table base address */
15
  SCB->VTOR = ((uint32_t) APP_START_ADDRESS & SCB_VTOR_TBLOFF_Msk);
16
  
17
  /* Load the Reset Handler address of the application */
18
  application_code_entry = (void (*)(void))(unsigned *)(*(unsigned *)(APP_START_ADDRESS + 4));
19
  
20
  /* 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.

: Bearbeitet durch User
von chris_ (Gast)


Lesenswert?

>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.

von Wad W. (wad_wer)


Lesenswert?

hi,

danke :) Es geht also weiter -.-

Habe jetzt einige Sachen durch probiert. Leider ohne erhofftes Ergebnis.

wenn ich:
1
#define APP_START_ADDRESS  0x00000800
2
  
3
int main(void){
4
  uint32_t app_start_address = *(uint32_t *)(APP_START_ADDRESS + 4);
5
  __set_MSP(*(uint32_t *) APP_START_ADDRESS);
6
  SCB->VTOR = ((uint32_t) APP_START_ADDRESS & SCB_VTOR_TBLOFF_Msk);
7
  asm("bx %0"::"r"(app_start_address));
8
  while (1);
9
}

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 :(

: Bearbeitet durch User
von Random .. (thorstendb) Benutzerseite


Lesenswert?

So mach ich das auf dem SAM3X (MDK-ARM, armcc V5):
1
#define NVIC_VectTab_FLASH       0x90000
2
#define SP_OFFS                     0
3
#define RESET_OFFS                  4
4
5
int main(void)
6
{
7
  ...
8
9
  //__disable_irq();
10
  //__DSB();
11
  //__ISB();
12
  SCB->VTOR       = NVIC_VectTab_FLASH;
13
  user_code_entry = (void (*)(void))(( *((unsigned int *)(NVIC_VectTab_FLASH + RESET_OFFS))) );
14
  MSP             = *((unsigned int *)(NVIC_VectTab_FLASH + SP_OFFS));
15
  //__DSB();
16
  //__ISB();
17
  
18
  user_code_entry();
19
20
  while(1);     // should never reach this ...
21
}

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.

von Wad W. (wad_wer)


Lesenswert?

Hi,

vielen dank! leider läuft das bei mir auch nicht wie es soll :(
1
#include "sam.h"
2
#define NVIC_VectTab_FLASH      0x00000800
3
#define SP_OFFS                     0
4
#define RESET_OFFS                  4
5
6
int main(void)
7
{
8
    /* Initialize the SAM system */
9
    SystemInit();
10
  __disable_irq();
11
  __DSB();
12
  __ISB();
13
   void (*user_code_entry)(void);
14
  SCB->VTOR       = NVIC_VectTab_FLASH;
15
  user_code_entry = (void (*)(void))(( *((unsigned int *)(NVIC_VectTab_FLASH + RESET_OFFS))) );
16
  __set_MSP(*((unsigned int *)(NVIC_VectTab_FLASH + SP_OFFS))); 
17
  __DSB();
18
  __ISB();
19
  
20
  user_code_entry();
21
22
  while(1);     // should never reach this ...
23
  }

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.

: Bearbeitet durch User
von Wad W. (wad_wer)


Angehängte Dateien:

Lesenswert?

Habe im Anhang mal den Sprung im Assembler view dokumentiert. Vielleicht 
sieht ja jemand der es kann was falsch läuft?

die Source ist diese:
1
#include "sam.h"
2
#define APP_START      0x00001000
3
4
5
int main(void)
6
{
7
    /* Initialize the SAM system */
8
  __disable_irq();
9
  __DSB();
10
  __ISB();
11
  uint32_t app_start_address = *(uint32_t *)(APP_START + 4);
12
  __set_MSP(*(uint32_t *) APP_START);
13
  SCB->VTOR = ((uint32_t) APP_START & SCB_VTOR_TBLOFF_Msk);
14
  __DSB();
15
  __ISB();
16
    asm("bx %0"::"r"(app_start_address));  
17
  
18
19
  PORT->Group[0].DIRSET.reg = PORT_PA09;
20
        while (1) {
21
    PORT->Group[0].OUTSET.reg = PORT_PA09;
22
    uint8_t i = 0;
23
    for(i=0;i<20;i++)     PORT->Group[0].OUTCLR.reg = PORT_PA09;
24
        }
25
}

und das eigendliche sprungziel wäre hier:
1
--- No source file -------------------------------------------------------------
2
00000FFA  ???     Memory out of bounds or read error 
3
00000FFC  ???     Memory out of bounds or read error 
4
00000FFE  ???     Memory out of bounds or read error 
5
00001000   lsls  r0, r0, #16     
6
00001002   movs  r0, #0     
7
00001004   lsls  r5, r1, #2     
8
00001006   movs  r0, r0     
9
00001008   lsls  r5, r3, #2     
10
0000100A   movs  r0, r0     
11
0000100C   lsls  r5, r3, #2     
12
...

von Nur ein Amateur (Gast)


Lesenswert?

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:
1
/* ... */
2
3
if(((*((uint32_t *) BL_PRGM_START_ADDR)) & 0x2ffe0000) == 0x20020000)
4
{
5
  __set_MSP(*(__IO uint32_t *) BL_PRGM_START_ADDR);
6
  // SCB->VTOR wird in dem geladenen Programm gesetzt
7
  ((void (*)(void)) *(__IO uint32_t *) (BL_PRGM_START_ADDR + 4))();
8
  while(1) {}
9
}
10
11
/* ... */
Wobei
1
#define __IO volatile // in der ST-Lib
Und BL_PRGM_START_ADDR die Addresse des Programms ist.

von Wad W. (wad_wer)


Angehängte Dateien:

Lesenswert?

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);
1
#define APP_START_ADDRESS      0x00000800
2
...
3
  uint32_t *app_start_address = (uint32_t *)(APP_START_ADDRESS+4);
4
  __set_MSP(*(uint32_t *)(APP_START_ADDRESS));
5
  SCB->VTOR = (APP_START_ADDRESS & SCB_VTOR_TBLOFF_Msk);
6
  asm("bx %0"::"r"(app_start_address));
7
...

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
1
  uint32_t *app_start_address = (uint32_t *)(APP_START_ADDRESS+4);
2
  __set_MSP(*(uint32_t *)(APP_START_ADDRESS));
3
000001D8   movs  r3, #128     
4
000001DA   lsls  r3, r3, #4     
5
--- C:\Program Files (x86)\Atmel\Studio\7.0\Packs\arm\cmsis\4.2.0\CMSIS\Include/core_cmFunc.h 
6
  __ASM volatile ("MSR msp, %0\n" : : "r" (topOfMainStack) : "sp");
7
000001DC   ldr  r2, [r3]     
8
000001DE   msr  msp, r2     
9
--- c:\users\felix\Documents\Atmel Studio\7.0\GccApplication8\GccApplication8\Debug/.././main.c 
10
  SCB->VTOR = (APP_START_ADDRESS & SCB_VTOR_TBLOFF_Msk);
11
000001E2   ldr  r2, [pc, #8]     
12
000001E4   str  r3, [r2, #8]     
13
  asm("bx %0"::"r"(app_start_address));
14
000001E6   ldr  r3, [pc, #8]     
15
->000001E8   bx  r3

gehts nach
1
00000800  ???     Memory out of bounds or read error 
2
00000802  ???     Memory out of bounds or read error 
3
->00000804   lsls  r5, r1, #2     
4
00000806   movs  r0, r0     
5
00000808   lsls  r5, r3, #2     
6
0000080A   movs  r0, r0     
7
--- No source file -------------------------------------------------------------
8
0000080C   lsls  r5, r3, #2     
9
0000080E   movs  r0, r0     
10
00000810   movs  r0, r0     
11
00000812   movs  r0, r0     
12
00000814   movs  r0, r0

und dann aber wieder
1
00000094   bne  #14     
2
00000096   ldr  r3, [pc, #20]     
3
00000098   cmp  r3, #0     
4
0000009A   beq  #4     
5
->0000009C   ldr  r0, [pc, #16]     
6
0000009E   b  #0     
7
000000A0   nop     
8
000000A2   movs  r3, #1     
9
--- No source file -------------------------------------------------------------
10
000000A4   strb  r3, [r4]     
11
000000A6   pop  {r4, pc}     
12
000000A8   lsls  r0, r5, #

... im Anhang der komplette speicher

von Wad W. (wad_wer)


Lesenswert?

wieder etwas weiter :)

mit
1
    asm volatile("ldr r2, =0x800");
2
    //asm volatile("ldr r2, [r2]");
3
    asm volatile("mov pc, r2");

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.

: Bearbeitet durch User
von chris_ (Gast)


Lesenswert?

Kann man mit dem Atmel-ICE irgendwelche Fuses im Prozessor einstellen?
Vielleicht liegt es an Fuses für die Speichereinstellung.

von Wad W. (wad_wer)


Lesenswert?

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.

von Wad W. (wad_wer)


Lesenswert?

weiter gehts...

ich versuch mich jetzt an Assembler weil so ja der Kompiler größtenteils 
raus ist.

Habe mir das hier zusammen gesucht:
1
  asm volatile("ldr r1, =0x800"); // lade 0x800 in R1
2
  asm volatile("ldr r0, [r1]"); // lade pointer? auf 0x800 in R0
3
  asm volatile("msr msp, r0"); // MSP (stack pointer auf R0 also 0x800)
4
  asm volatile("ldr r3, =0x804"); // lade 0x804 in R3
5
  asm volatile("ldr r2, [r3]"); // lade pointer? auf 0x804 in R2
6
  asm volatile("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
  asm volatile("ldr r1, =0x0"); // lade 0x0 in R1
2
  asm volatile("ldr r0, [r1]"); // lade pointer? auf 0x0 in R0
3
  asm volatile("msr msp, r0"); // MSP (stack pointer auf R0 also 0x0)
4
  asm volatile("ldr r3, =0x4"); // lade 0x4 in R3
5
  asm volatile("ldr r2, [r3]"); // lade pointer? auf 0x04 in R2
6
  asm volatile("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 :(

: Bearbeitet durch User
von Wad W. (wad_wer)


Lesenswert?

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.

von Wad W. (wad_wer)


Lesenswert?

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:
1
#define APP_START_ADDRESS  0x00000800
2
__set_MSP(*(uint32_t *) APP_START_ADDRESS);
3
asm("bx %0"::"r"(*(uint32_t *)(APP_START_ADDRESS + 4)));

: Bearbeitet durch User
von W.S. (Gast)


Lesenswert?

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.

von Wad W. (wad_wer)


Lesenswert?

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.

: Bearbeitet durch User
von Bernd K. (prof7bit)


Lesenswert?

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?

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.