Forum: Mikrocontroller und Digitale Elektronik TIPP: Atxmega DFU-Bootloader auf eigenen "Boot-Pin" verbiegen (direkt im Hex-File)


von Timmo H. (masterfx)


Lesenswert?

Hallo zusammen,
nachdem ich vergeblich versucht habe den DFU-Bootloader so abzuspecken, 
dass man ihn auch mit AVR-GCC kompilieren kann damit er in den 4KB 
Bootbereich des Xmega32A4U passt (weniger als 6K schafft man 
offensichtlich mit avr-gcc nicht), habe ich einen anderen Weg gefunden 
den Boot-Port für meine Ansprüche anzupassen und zwar ohne den 
IAR-Compiler zu verwenden.

Dafür habe ich einfach mit objdump mit den Assembler-Code des Hex-Files 
ausspucken lassen und dank des mitgelieferten Quellcodes auch schnell 
die paar Werte gefunden um den Port und Portpin der den Bootloader 
aktiviert (standardmäßig PC3 beim Atxmega32a4u) anzupassen. Prinzipiell 
geht das bei jedem DFU-Bootloader binary.
Nachdem man sich Paket mit dem DFU 1.04 von der Atmel Seite 
runtergeladen hat läd man einfach das passende Hex-File im Editor. 
Parallel dazu sollte man das µC-Spezifische Datenblatt öffnen und im 
Kapitel "Peripheral Module Address Map" nachschauen wie die Adresse des 
gewünschten Ports ist. Die Adresse des vom Bootloader vorgesehen Ports 
variiert je nach Xmega:
XMEGA_A1U: PORTF PIN 0
XMEGA_A3U, XMEGA_A3BU, XMEGA_C3: PORTE PIN 5
XMEGA_A4U, XMEGA_C4: PORTC PIN 3
XMEGA_B PORTC: PIN 6

Oder man schaut einfach direkt iox*.h File nach.

Die Hex-Files zwischen den verschiedenen Xmegas unterscheiden sich 
natürlich etwas, aber über objdump bekommt kommt man schnell die 
gewünschte Position, da die Abfragen immer gleich sind:
1
    8000:  00 c0         rjmp  .+0        
2
    8002:  00 91 78 00   lds  r16, 0x0078
3
    8006:  05 fd         sbrc  r16, 5
4
    8008:  6a c0         rjmp  .+212      
5
    800a:  f0 92 00 06   sts  0x0640, r15     ; PORTC_DIR
6
    800e:  08 e1         ldi  r16, 0x18  
7
    8010:  00 93 12 06   sts  0x0653, r16     ; PORTC.PIN3CTRL
8
    8014:  0f ef         ldi  r16, 0xFF  
9
    8016:  0a 95         dec  r16
10
    8018:  00 23         and  r16, r16
11
    801a:  e9 f7         brne  .-6        
12
    801c:  00 91 08 06   lds  r16, 0x0648     ; PORTC.IN
13
    8020:  02 ff         sbrs  r16, 3         ; PIN3

Nun ändert man die Adresse des Ports (bzw. PortRegister) im Hexfile ab. 
Es sind genau 3 Adressen (PORT-Adresse, PORT-CTRL, PORT.IN) und eine 
Pin-Nummer die angepasst werden müssen. Glücklicherweise befinden sie 
sich alle in den ersten 4-Zeilen des Hex-Files.
Da jeder Port immer einen Offset von 0x20 zum nächsten hat ist es recht 
einfach.
Für den Atxmega32a4u bei dem der Default-Port PORTC.3 und man ihn auf 
PORTA.2 ändern will sieht das so aus:
1
Vorher         Adresse  |   Nachher         Adresse
2
PORTC_DIR      0x640    |   PORTA_DIR       0x600
3
PORTC_IN       0x648    |   PORTA_IN        0x608
4
PORTC_PIN3CTRL 0x653    |   PORTC_PIN2CTRL  0x612

Die entsprechenden Adressen können direkt ins iHex eingetragen werden 
(achtung Big-Endian, also Bytes verdrehen)
Hier das Original Hex-File:
1
:020000020000FC
2
:1080000000C00091780005FD6AC0F092400608E1CA
3
                                 ^^^^-> PORTC_DIR = 0x0640
4
:10801000009353060FEF0A950023E9F700914806F5
5
             ^^^^-> PORTC_PIN3CTRL   ^^^^-> PORTC_IN = 0x0648
6
:1080200003FFECC0E0E0F0E0079116910F3F19F478
7
         ^^-> PIN3
und hier die geänderte Version für PORTA.2
1
:020000020000FC
2
:1080000000C00091780005FD6AC0F092000608E10A
3
                                 ^^^^-> PORTA_DIR = 0x0600
4
:10801000009312060FEF0A950023E9F70091080676
5
             ^^^^-> PORTA_PIN2CTRL   ^^^^-> PORTA_IN = 0x0608
6
:1080200002FFECC0E0E0F0E0079116910F3F19F479
7
         ^^-> PIN2
Natürlich muss noch jeweils am Ende jeder Zeite die Checksumme neu 
berechnet werden. Das kann man am einfachsten machen indem man das 
geänderte Hex-File einfach mit obj-dump läd, das sagt einem dann welche 
Checksumme erwartet wird (leider in Dez, muss also noch in Hex 
umgerechnet werden). Also z.B. "obj-dump -D -m avr c:\boot_neu.hex"


Vielleicht hilft's ja noch jemanden.

von Timmo H. (masterfx)


Lesenswert?

Oh, da ist ja noch eine Stelle wo der Pullup wieder zurückgesetzt wird:
1
:1080E000530600910020109101200A3A154511F025
2
         ^^^^->PORTC_PIN3CTRL = 0x0653
Aber das wars dann auch.

von Basti M. (counterfeiter)


Lesenswert?

Ah, interessant... habe mir aber dazu den IAR geladen... da ja bis 4 kb 
die Liezens nicht abläuft...

Zwei Fragen:

Wie hast du die XMega Hex Dissambliert? Gibts da ein Programm oder 
musstest du das händisch machen? (Hab das vom AtMega probiert, dass will 
aber nicht mit der XMega Hex)

und dann noch: Hast du das Problem auch, wenn du USB als VirtualCom drin 
hast und dann zum Bootloader springst, dass das USB Laden im Bootloader 
fehl schlägt?
Hier wurde das Problem angesprochen:
http://www.avrfreaks.net/index.php?name=PNphpBB2&file=viewtopic&t=122461

Die habens dann über den Zwischenspeicher im EEPROM gelöst... und einen 
Watchdog reset... nicht besonders schön :-/

Grüße

BAsti

von Timmo H. (masterfx)


Lesenswert?

Basti M. schrieb:
> Wie hast du die XMega Hex Dissambliert? Gibts da ein Programm oder
> musstest du das händisch machen? (Hab das vom AtMega probiert, dass will
> aber nicht mit der XMega Hex)
Hab ich doch geschrieben, das geht mit objdump (ist ja beim avr-gcc 
dabei). "objdump.exe -D -m avr hex_file.hex"

> und dann noch: Hast du das Problem auch, wenn du USB als VirtualCom drin
> hast und dann zum Bootloader springst, dass das USB Laden im Bootloader
> fehl schlägt?
Ich habe bisher nichts mit dem USB gemacht außer eben den 
DFU-Bootloader.

von Basti M. (counterfeiter)


Lesenswert?

oh, dann hab ich das wohl überlesen... okay, alles klar... danke

von Lars (Gast)


Lesenswert?

Basti M. schrieb:
> Ah, interessant... habe mir aber dazu den IAR geladen... da ja bis 4 kb
> die Liezens nicht abläuft...

Kannst Du mir erklären, wie Du dies gemacht hast? Ich versuche dies auch 
mit dem Code für den ATXMEGA 128A4U. Dies funktioniert bei mir aber 
nicht.

Vorgehensweise:

- IAR KickStart Version (4k) installiert.
- 
common.services.usb.class.dfu_atmel.device.bootloader.atxmega128a4u.zip 
entpackt
- Projekt in IAR geöffnet.
- Make

-> Es erscheint die Meldung:

Building configuration: bootloader_xmega - Debug
Updating build tree...
isp.c
main.c
nvm.c
sysclk.c
udc.c
udi_dfu_atmel.c
udi_dfu_atmel_desc.c
usb_device.c
Linking
Fatal Error[e89]: Too much object code produced (more than 0x1000 bytes) 
for this package
Error while running Linker

Total number of errors: 1
Total number of warnings: 0


Funktioniert das mit der 4k Version nur bei bestimmten Controllern? Oder 
gibt es hier einen Trick?. Wäre schön, wenn Du, oder jemand anderes, mir 
hierbei helfen könnte.

Gruß
Lars

von spess53 (Gast)


Lesenswert?

Hi

>- IAR KickStart Version (4k) installiert.

Wenn dein Compiler nur max. 4k Code erzeugen kann, was vestehst du dann 
an der Meldung

>Fatal Error[e89]: Too much object code produced (more than 0x1000 bytes)

nicht? 0x1000 = 4096 Byte.

MfG Spess

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

spess53 schrieb:
> Wenn dein Compiler nur max. 4k Code erzeugen kann, was vestehst du dann
> an der Meldung
>
>>Fatal Error[e89]: Too much object code produced (more than 0x1000 bytes)
>
> nicht?

Dass das erwartete Resultat ja kleiner als 4 KiB sein sollte, weil
es sonst ohnehin nicht in die boot section passt.

Optimierungen im Projekt eingeschaltet?

von Timmo H. (masterfx)


Lesenswert?

Naja der 128A4U hat ja 8k Bootbereich, dennoch sollte man natürlich die 
Compiler Optimierungen an machen. Denn der freie IAR hat ja auch ne 4k 
Begrenzung.

Ich glaube im bootloader sind Optimierungen drin die nur bei Controllern 
mit 4k bootloader Bereich aktiv ist. Die größeren xmegas kommen dann mit 
4k nicht mehr aus. Muss man noch mal genauer gucken.

von Lars (Gast)


Angehängte Dateien:

Lesenswert?

Die Optimierungen habe ich eingeschaltet. Siehe Anhang.

von Peter D. (peda)


Lesenswert?

Zumindest beim AVR-GCC erhöht Inlining den Code drastisch.
Er macht nämlich keine Analyse, wie oft was aufgerufen wird.
D.h. er inlined ohne mit der Wimper zu zucken auch 100 mal.

von Moritz A. (moritz_a)


Lesenswert?

Timmo H. schrieb:
> Ich glaube im bootloader sind Optimierungen drin die nur bei Controllern
> mit 4k bootloader Bereich aktiv ist. Die größeren xmegas kommen dann mit
> 4k nicht mehr aus. Muss man noch mal genauer gucken.

Da ich gerade das selbe Problem habe, habe ich genau dies gemacht. Es 
fallen ja schon die Größenunterschiede bei den mitgelieferten Files auf:
1
> avr-size ../binaries/atxmega32a4u_104.hex ../binaries/atxmega128a4u_104.hex
2
   text     data      bss      dec      hex  filename
3
      0     3944        0     3944      f68  ../binaries/atxmega32a4u_104.hex
4
      0     5588        0     5588     15d4  ../binaries/atxmega128a4u_104.hex

Aber was ist nun konkret unterschiedlich?
1
> diff -rq atxmega32a4u atxmega128a4u
2
Only in atxmega128a4u/common/services/usb/class/dfu_flip/device/bootloader/xmega: atxmega128a4u
3
Only in atxmega32a4u/common/services/usb/class/dfu_flip/device/bootloader/xmega: atxmega32a4u
4
Only in atxmega32a4u/common/services/usb/class/dfu_flip/device/bootloader/xmega: sysclk_opt.c
5
Only in atxmega128a4u/common/services/usb/udc: udc.c
6
Only in atxmega32a4u/common/services/usb/udc: udc_dfu_small.c

Insbesondere in udc/udc_dfu_small fällt auf, dass die abgespeckte 
Variante deutlich mehr statische Annahmen macht, wobei ich das jetzt 
auch nicht weiter verfolgen werde, sondern den "bequemen" Weg mit 
Patchen des Hex-Files gehe ;)

Grüße
Moritz

von Timmo H. (masterfx)


Lesenswert?

Klar die anderen Controller haben mehr Platz im Boot Bereich, darum wird 
dort auch weniger abgespeckt. Aber im Prinzip steht am Anfang genau das 
gleiche. Schau dir mal das hex mit objdump an der gleichen Adresse an.

von Atmega8 A. (atmega8) Benutzerseite


Lesenswert?

Timmo H. schrieb:
> Vielleicht hilft's ja noch jemanden.

Ja, Danke!

Ich habe bei meinem ATXmega128A4U den Boot-Pin auf Port E, Pin 1 
gesetzt.

Für den ATXmega128A4U ist der Boot-Pin "PC3", also 0x640 + 0x13

1. Wert in der Obj-Datei ändern:
Gleich am Anfang des Object-Codes der Datei "atxmega128a4u_104.hex" ist 
der Eintrag für den zu testenden Pin.

0x640 = PortC, Pin3 = +13 => 0x653
1
Position   |                 | Befehl  | Adresse/Register
2
   2000a:  f0 92 40 06   sts  0x0640, r15
3
...
4
   20010:  00 93 53 06   sts  0x0653, r16
5
...
6
  2001c:  00 91 48 06   lds  r16, 0x0648
7
  20020:   03 ff         sbrs  r16, 3
8
...
9
  2008e:  f0 92 53 06   sts  0x0653, r15
----------------------------------------------------------

ändern in:
0x680 = PortE, Pin1 = +11 => 0x691
1
   2000a:  f0 92 80 06   sts  0x0680, r15
2
...
3
   20010:  00 93 91 06   sts  0x0691, r16
4
...
5
  2001c:  00 91 88 06   lds  r16, 0x0688
6
  20020:  01 ff         sbrs  r16, 1
7
...
8
  2008e:  f0 92 91 06   sts  0x0691, r15
----------------------------------------------------------
PortE = 0x680
0x680 + 0x08 (IN) = 0x688 (PortE IN)
0x680 + 0x11 (Pin 1) = 0x691 (PortE, Pin 1)

//-------------------------------------------------------------
Start/Byteanzahl/Adresse/Typ/Daten/Prüfsumme
1
:02 0000 02 2000DC
2
:10 0000 01 000C00091780005FD42C0 {F0928006} 08E1 72  (falsche Prüfsumme)
3
:10 0010 00 {00939106} 0FEF0A950023E9F7 {00918806} 75 (falsche Prüfsumme)
4
:10 0020 00 {01FF} ECC0E0E0F0E0079116910F3F19F4 F8    (falsche Prüfsumme)
5
:10 0030 00 1F3F09F4E3C02BC03091CF0137FDFCCF 47
6
:10 0040 00 3BB72BBFF8012091CA0113E21093CA01 FC
7
:10 0050 00 0A01E8952093CA013BBF08953BB72BBF 27
8
:10 0060 00 F8012091CA014093CA013DE930933400 60
9
:10 0070 00 E8952093CA013BBF089501E70DBF00E2 58
10
:10 0080 00 0EBFC2E9DAE20F94B6000F94720A {F092 42    (falsche Prüfsumme)
11
:10 0090 00 9106} 00910020109101200A3A154511F0 F5    (falsche Prüfsumme)
12
...
//-------------------------------------------------------------
Der Hinweis auf die Fehlermeldung des objdump-Befehls war gut, so muss 
man die Prüfsumme nicht selbst berechnen.

Wenn man den "avr-objdump"-Befehl noch mal auf der veränderten 
"atxmega128a4u_104.hex" ausführt, dann wird ein Fehler ausgegeben mit 
der Nachricht welche Prüfsumme erwartet wird.

Beim ersten mal ausführen wurde zum Beispiel gesagt dass 50(0x32) als 
Prüfsumme erwartet wird, aber anstatt dessen 114(0x72) gefunden wurde.

Hier sind die richtigen Prüfsummen:
Start/Byteanzahl/Adresse/Typ/Daten/Prüfsumme
1
:020000022000DC
2
:1000000000C00091780005FD42C0F092800608E1 32
3
:10001000009391060FEF0A950023E9F700918806 F7
4
:1000200001FFECC0E0E0F0E0079116910F3F19F4 FA
5
:100030001F3F09F4E3C02BC03091CF0137FDFCCF 47
6
:100040003BB72BBFF8012091CA0113E21093CA01 FC
7
:100050000A01E8952093CA013BBF08953BB72BBF 27
8
:10006000F8012091CA014093CA013DE930933400 60
9
:10007000E8952093CA013BBF089501E70DBF00E2 58
10
:100080000EBFC2E9DAE20F94B6000F94720AF092 42
11
:10009000910600910020109101200A3A154511F0 B7
12
...
//-------------------------------------------------------------

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.