Forum: Mikrocontroller und Digitale Elektronik AVR-GCC - Bootloader & Nutzprogramm in einem. Wie?


von Melanie G. (Gast)


Lesenswert?

Hallo Forum,
ich habe mich nun die letzten Tage in die Thematik des Bootloaders 
eingearbeitet. Die Funktionsweise ist mir bekannt und ich habe auch 
1*10^7 Beispiele und Demos gefunden. Leider handelt es sich dabei immer 
um "Stand-Alone" Bootloader, die eine anschließende Programmierung des 
Nutzprogrammes über diesen erfordert.

Ich würde jedoch gerne mein Nutzprogramm mit einem Bootloader ergänzen. 
Dies hat den Vorteil, dass ich das Gerät im geöffneten Zustand via ISP 
und im geschlossenen Zustand via CAN programmieren kann.

In den Musterbeispielen wird einfach die komplette .text Section in den 
Bootloader Bereich verschoben und genau das will ich ja nicht.

Ich muss also das ".bootsection" Attribut verwenden um den Loader an 
seine richtige Position zu verschieben.

Nun meine Frage: Der Bootloader besteht ja aus mehreren Funktionen, wenn 
ich das Attribut mehrfach verwendet, meckert der Compiler, dass die 
Funktionen sich gegenseitig überschreiben.
Außerdem ist mir die Thematik mit der main() Funktion noch nicht ganz 
klar. Eigentlich bräuchte mein Programm ja zwei main() Funktionen, aber 
das kann ja nicht funktionieren.

Gibt es eine Möglichkeit, dass ich diese zwei "quasi" unabhängigen 
Programme einfach unter einen Hut bekomme? Kennt jemand ein Beispiel, 
indem genau diese Thematik behandelt wird?

Vielen Dank im vorraus

Melanie

von Peter D. (peda)


Lesenswert?

Melanie G. schrieb:
> Eigentlich bräuchte mein Programm ja zwei main() Funktionen, aber
> das kann ja nicht funktionieren.

Du hast es erfaßt, es geht nicht.

Du kannst vom 1. Hexfile die letzte Zeile entfernen und dann das 2. 
anfügen.


Peter

von Melanie G. (Gast)


Lesenswert?

Danke für die klare Aussage!

von Εrnst B. (ernst)


Lesenswert?

Peter Dannegger schrieb:
>> Eigentlich bräuchte mein Programm ja zwei main() Funktionen, aber
>> das kann ja nicht funktionieren.
>
> Du hast es erfaßt, es geht nicht.

Das geht in gewissen Grenzen schon:

Im bootloader-Quelltext:
1
int main(void) __attribute__ ((weak));
2
3
int main(void) {
4
  execute_bootloader();
5
}
Durch das "weak"-Attribute lässt sich der Bootloader dann trotz 
Namensüberschneidung mit dem Hauptprogramm linken.

Macht aber nur selten Sinn, z.B. bei alten Tinies ohne echten 
Bootloader-Support.

von ... (Gast)


Lesenswert?

Melanie G. schrieb:
> Ich würde jedoch gerne mein Nutzprogramm mit einem Bootloader ergänzen.
>
> Dies hat den Vorteil, dass ich das Gerät im geöffneten Zustand via ISP
>
> und im geschlossenen Zustand via CAN programmieren kann.

Eine andere Möglichkeit wäre, der Bootloader erwartet nach jedem Reset 
einen Nutzprogramm-File, ist dieser nicht vorhanden wird nach einer 
kurzen Zeitspanne das vorhandene Nutzprogramm abgearbeitet.

von Thomas E. (thomase)


Lesenswert?

Hallo

mit AVR-Studio gibt es eine Möglichkeit:

Einstellungen im AVR-Programmer unter "Program":
"Erase device..." und "Verify..." auf EIN

dann 1. Programm flashen.

Einstellungen im AVR-Programmer unter "Program":
"Erase device..." und "Verify..." auf AUS

dann 2.Programm flashen.

Mfg

von Archie F. (archie)


Lesenswert?

>dass ich das Gerät im geöffneten Zustand via ISP
>und im geschlossenen Zustand via CAN programmieren kann.

Definiere via CAN eine Nachricht die eine Funktion aufruft mit 
eingeschaltetem Watchdog und einer While(1). Nach dem Absturz wird erst 
Bootloader geladen, der wiederum eine Nachricht an deine Software 
sendet, erhält der Bootloader innerhalb einer definierten Zeit eine 
Antwort von deinem Programm, wird der uC beschrieben. So ähnlich mache 
ich das, bloss nicht über CAN.

von Rangi J. (rangi)


Lesenswert?

Hallo Melanie,
ich hab das so gelöst, durch 2 zusätzliche Sektionen im Linkerscript.
In der 1. section darf nur eine Funktion drin sein um sichszustellen, 
das diese Funktion auch wirklich auf die angegebene Adresse kommt.
1
#define BOOT_SEC_SIZE_100   0x0100      /* BootLoader Start 0x1F00 im Makefile*/
2
#define BOOT_SEC_SIZE_200   0x0200      /* BootLoader Start 0x1E00 im Makefile*/
3
#define BOOT_SEC_SIZE_400   0x0400      /* BootLoader Start 0x1C00 im Makefile*/
4
#define BOOT_SEC_SIZE_800   0x0800      /* BootLoader Start 0x1800 im Makefile*/
5
6
#define BOOT_SEC_SIZE   BOOT_SEC_SIZE_400
7
8
extern u8 my_adress;
9
BOOTLOADER_SECTION void boot_main(void);
10
11
/* ---------------------------------------------------------- */
12
/*                SECTION .bootstart                          */
13
/* ---------------------------------------------------------- */
14
/* Diese Funktion muss auf die BOOTSTART-Adresse geschrieben werden*/
15
__attribute__ ((section (".bootstart"))) void boot_startup(void)
16
{
17
  asm volatile ("eor r1, r1");
18
  asm volatile ("ldi r28, 0x5F");  /*stack-pointer auf 0x0260*/
19
  asm volatile ("ldi r29, 0x02");
20
  asm volatile ("out 0x3e, r29");
21
  asm volatile ("out 0x3d, r28");
22
  
23
  if(/*im Bootloader bleiben*/)
24
  {
25
    /*ggf die schnittstelle hier initialisieren*/
26
    boot_main();
27
  }
28
  /*else zur main() springen*/
29
  asm("rjmp __vectors");    /*auf den RESET-Vector - immer die 0 - hier erfolgt der Sprung zur main()*/
30
}
31
32
/* ---------------------------------------------------------- */
33
/*                SECTION .bootloader                         */
34
/* ---------------------------------------------------------- */
35
BOOTLOADER_SECTION void boot_main(void)
36
{
37
  ...
38
  some code
39
  ...
40
  while(1);
41
}
42
BOOTLOADER_SECTION void foo(void)
43
{
44
  some code
45
}

dem Linker geb ich dann einfach mit:
override LDFLAGS = 
-Wl,--section-start=.bootstart=0x1C00,--section-start=.bootloader=0x1C44 
,-Map,$(PRG).map

die asm-befehle sind aus der ctors() geklaut und du solltest die je nach 
Hardware auch von dort nehmen.

von Rangi J. (rangi)


Lesenswert?

vergessen: meine codeschnipsel sind fuer den Winavr-GCC und einen 
ATMega8515

von Sepp (Gast)


Lesenswert?

Das Problem Bootlader und User-Prog gemeinsam laden zu müssen
hatte ich auch schon mal bei einem ADUC832, ist sehr ähnlich gelagert
wie beim AVR.

Das "Zusammensetzen" der HEX-Files, wie es Peter Dannegger beschrieben
hat, funktioniert einwandfrei. Man muß halt dann das zusammengesetzte
Hex-File laden- ich finde das ist der geringste Aufwand.

von Arno F. (fischera)


Lesenswert?

Rangi Jones schrieb:
> override LDFLAGS =
>
> -Wl,--section-start=.bootstart=0x1C00,--section-start=.bootloader=0x1C44 
,-Map,$(PRG).map
>
>
>
> die asm-befehle sind aus der ctors() geklaut und du solltest die je nach
>
> Hardware auch von dort nehmen.

Hallo Rangi,

bin neu im Umfeld ATMega und versuche dein Beispiel zu benutzen.
Ich habe im Linker Script die folgende Zeile eingegeben:
•
1
override LDFLAGS = -Wl,--section-start=.bootstart=0x1C00,--section-start=.bootloader=0x1C44,-Map,$(PRG).map•

Beim Linken kommt dann aber Syntax Error. Irgendwie versteht er diese 
Zeile nicht. Ich Programmiere einen ATMega88PA.
Das zweite ist das ich nicht verstehe wie ich aus ctors() die 
Asm-Befehle klauen kann. Welche Datei ist das? Bin halt ein ATMega und 
AVR Neuling und versuche gerade Schwimmen zu erlernen. Ich muß genau das 
hinbekommen einen Bootloader der mit dem Hauptprogramm gemeinsam 
Programmiert wird.
Ich habe den Beispiel Code in einer eigenen Datei in mein Projekt 
eingebunden.

Kannst du oder irgend jemand mir bitte Helfen?

von Rangi J. (rangi)


Lesenswert?

also den code kannst du dir am einfachsten aus dem listing ziehen. du 
machst dir ein pojekt was kompiliert und rufst auf: "make lst". dann 
wird dir eine myproject.lst gebaut. darin findest du vermutlich ganz 
weit oben die vektor-tabelle mit dem resetvektor auf der 0:
1
00000000 <__vectors>:
2
       0:  0c 94 3e 00   jmp  0x7c  ; 0x7c <__ctors_end>
3
       ....
welches bei mir auf adresse 0x7c verweist. gehe zu adresse 0x7c und du 
findest:
1
0000007c <__ctors_end>:
2
      7c:  11 24         eor  r1, r1
3
      7e:  1f be         out  0x3f, r1  ; 63
4
      80:  cf ef         ldi  r28, 0xFF  ; 255
5
      82:  d0 e1         ldi  r29, 0x10  ; 16
6
      84:  de bf         out  0x3e, r29  ; 62
7
      86:  cd bf         out  0x3d, r28  ; 61
diese Befehle sind einfach in C-form umzusetzen.

jetzt zu den modifikationen im makefile:
da war ich in meinem post von damals wohl nicht detailliert genug und 
hatte gehofft, dass die leute, die das brauchen schon selber wissen, wie 
man eine section hinzufügt. also hier fehlt noch folgendes:
1
# Rules for building the .text rom images
2
3
text: hex bin srec
4
5
hex:  $(PRG).hex
6
bin:  $(PRG).bin
7
srec: $(PRG).srec
8
9
%.hex: %.elf
10
  $(OBJCOPY) -j .text -j .data -j .bootstart -j .bootloader -O ihex $< $@
11
12
%.srec: %.elf
13
  $(OBJCOPY) -j .text -j .data -j .bootstart -j .bootloader -O srec $< $@
14
15
%.bin: %.elf
16
  $(OBJCOPY) -j .text -j .data -j .bootstart -j .bootloader -O binary $< $@
erklaerung: mit dem _attribut_ section erklaerst du, dass es eine 
section soundso geben wird und diese funktion dort rein kommt. beim 
linken wird dann diese section erstellt und per definition wird diese 
auf die adresse 0x1c00 (je nach hardware) gelegt. alle sprungbefehle 
laufen dann dorthin.

und ich betone nochmal: das ganze ist winavr !

von barbarossa (Gast)


Lesenswert?


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.