Merging Bootloader HEX-File and Application HEX-File to one

Last post
32 posts / 0 new
Author
Message
#1
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Hello,
is there a way to merge the Bootloader Hex-file with the Application Hex-File to one Hex-File (Intel-Hex)?
So I could program both in one step.

Regards

Andre

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Supposedly using the Srecord tool.

Jörg Wunsch

Please don't send me PMs, use email if you want to approach me personally.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Here is the rule in the makefile that I use to produce a combined .hex file:

$(DOWNLOAD) : $(TARGET).hex $(BOOTLDR)
	cat $(TARGET).hex $(BOOTLDR) | awk -f combine.awk > $(DOWNLOAD)
	rm $(BOOTLDR:.hex=.elf)

This rule just copies the two .hex files to stdout which is piped to an awk script that strips out the extra end record. The awk script, shown below, actually strips out both end records and then adds one at the end. Simple but effective.

BEGIN {}

# add a record end marker
END { print ":00000001FF" }

# delete the record end marker
/^:00000001FF/{ $0 = ""}

# default action: output all non-blank lines
{ if ($0 != ""){ print } }

Don Kinzer
ZBasic Microcontrollers
http://www.zbasic.net

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Hint: "awk" is spelled "gawk" in WinAVR.

Jörg Wunsch

Please don't send me PMs, use email if you want to approach me personally.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

You could also link the bootloader object file with the program and avoid awk scripting.

It would look like:

LDFLAGS=bootloader.o \
  -Wl,-Map=$(TRG).map,--section-start=.bls=$(BOOTLOADER_START)

where .bls is the name of your bootloader section.

___(°)^(°)___
A(VR)staroth

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

with hex2bin and bin2hex it sould also work:

hex2bin /q /L75000 Code.hex CodeBoot.bin
hex2bin /q /O60000 /M Boot.hex CodeBoot.bin
bin2hex /q /4 CodeBoot.bin CodeBoot.hex

/q is quite
/L is length (of the binfile)
/O is origin/Offset
/4 is Extended Adress (>64k)
/M is merge file into the other

You must flash then CodeBoot.hex....
This solution is fine, also if you want to link other binary data to your hexfile....
write it down in a bacthfile.
perhaps :
make all
make extcoff

and all your stuff is done automatically.... :-)

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Astaroth wrote:
You could also link the bootloader object file with the program and avoid awk scripting.
Quote:

In my case, I need to build two .hex files: one with the bootloader and one without. The one without the bootloader is used to produce an encrypted "field update" file and the combined one is used to initially program devices.

Don Kinzer
ZBasic Microcontrollers
http://www.zbasic.net

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

And what about

BIN=avr-objcopy

%.hex: %.elf 
	$(BIN) -O $(FORMAT) -R .eeprom $< $@

%.field.hex: %.elf 
	$(BIN) -O $(FORMAT) -R .eeprom -R .bls $< $@

___(°)^(°)___
A(VR)staroth

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

dl8dtl wrote:
Hint: "awk" is spelled "gawk" in WinAVR.

For those who don't know, that's because it is the Gnu AWK program.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I try some some of your solutions

regards

Andre

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

OK, I know this is an old thread, but I got here looking for help so others may still end up here as well.

There is another solution, the manual one: Use a text editor to cut off the last line of each file, copy and past the second file into the end of the first, and add pack an end of file record ":00000001FF".

Don's response using AWK hints at this as well.

Maybe this is too obvious, but I thought it was worth adding to the thread.

Dave.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Except that, as Joerg hinted, Srecord is the most obvious way to do this (srec_cat in fact)

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Hi All,
I have a USB bootloader image in .a90 format (no source code for USB bootloader )and the application image in .abs format (from avr studio).
Can anybody guide me and tell how to merge both the images into one.
Is this possible using s-record tool?
Please help me out.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Quote:

the application image in .abs format (from avr studio).

Studio does not have a .abs file type? It does use .aps but that's actually an XML project settings file - nothing to do with source or binary.

Anyway srec_cat can read virtuall every hex format there is so start by identifying what format is in the .a90 - looking at some I've built on my machine with the IAR trial version it looks like Motorola S-Record format. srec_cat has no problem reading this format.

From AVR Sudio it's very likely that what you actually have is a .hex file containing Intel Hex records. srec_cat can read that too. So just use it to read both files and join them to an output format of your choice (probably Intel Hex).

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Hi clawson,
You were right. The image of the application generated by the AVR studio is in .hex format.
I will try using S-record tool to merge the application(.hex) and the bootloader(.a90).

Thanks for the post.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

The key thing is to have a peek inside the .a90 and just confirm that it is in Srecord format - the clue is in the name - each line starts with "S" followed by a lot of ASCII hex couplets. You then need to specify to srec_cat the format of the two input files based on this knowledge together with specifying which format you want output.

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0
full.hex: main.hex boot.hex
	@cat main.hex | awk '/^:00000001FF/ == 0' > $@
	@cat boot.hex >> $@
	@$(AVR_SIZE) $@
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Great!

all: full.hex

...code from above...

PHONY: full.hex
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I was looking for merging application and bootloader hex into one and I've stumbled on this thread, if I don't go wrong, what is needed is:

 

1. Strip out the last line from the bootloader .hex file

2. Copy and paste the whole application .hex below the previous .hex, so that we have bootloader -> application -> 00000001FF closing line

3. Save the full .hex as a new one and program it into the flash of the uC

 

I've done this with Notepad++, is this procedure correct?

Last Edited: Tue. Apr 7, 2015 - 12:03 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 1

so that we have bootloader -> application -> 00000001FF closing line

Wrong way round. The application comes first (it's at 0x0000). However a "clever" programming utility won't mind and will happily accept hex records that are not in increasing address order. However some utilities (especially things like bootloaders themselves) cannot handle HEX where the addresses are not incrementing.

 

If you want an easy life get WinAVR and take from it utils/bin/srec_cat.exe - that will do the joining for you. You can even add a Makefile rule to invoke it as a post build event after app.hex and boot.hex have been created.

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Thanks for your correction clawson, so if I go like:

 

1. Strip out the last line from the application .hex file

2. Copy and paste the whole bootloader .hex below the previous .hex, so that we have application -> bootloader -> 00000001FF closing line

3. Save the full .hex as a new one and program it into the flash of the uC

 

I should be fine, right?

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 1

Here's an example:

$ cat app.hex
:1000000009C00EC00DC00CC00BC00AC009C008C09A
:1000100007C006C011241FBECFE9CDBF02D00DC05E
:10002000EFCFDF93CF93CDB7DEB788E390E025E540
:0E003000FC012083CF91DF910895F894FFCF5B
:00000001FF
$ cat boot.hex
:1010000009C00EC00DC00CC00BC00AC009C008C08A
:1010100007C006C011241FBECFE9CDBF02D020C03B
:10102000EFCFDF93CF9300D0CDB7DEB71A8219820E
:101030000BC088E390E029812655FC01208389813B
:101040009A8101969A83898389819A818A30910550
:1010500084F380E090E0CE5FCDBFCF91DF91089523
:04106000F894FFCF32
:0400000300001000E9
:00000001FF

I built the app to locate at 0 (as normal) and the boot to locate at 0x1000 (and do a bit more than the app). So now I just join them as follows:

$ cat app.hex boot.hex > both.hex
$ cat both.hex 
:1000000009C00EC00DC00CC00BC00AC009C008C09A
:1000100007C006C011241FBECFE9CDBF02D00DC05E
:10002000EFCFDF93CF93CDB7DEB788E390E025E540
:0E003000FC012083CF91DF910895F894FFCF5B
:00000001FF
:1010000009C00EC00DC00CC00BC00AC009C008C08A
:1010100007C006C011241FBECFE9CDBF02D020C03B
:10102000EFCFDF93CF9300D0CDB7DEB71A8219820E
:101030000BC088E390E029812655FC01208389813B
:101040009A8101969A83898389819A818A30910550
:1010500084F380E090E0CE5FCDBFCF91DF91089523
:04106000F894FFCF32
:0400000300001000E9
:00000001FF

However that has left me with a termination record in the middle I don't want. So I now edit and remove that:

$ cat both.hex 
:1000000009C00EC00DC00CC00BC00AC009C008C09A
:1000100007C006C011241FBECFE9CDBF02D00DC05E
:10002000EFCFDF93CF93CDB7DEB788E390E025E540
:0E003000FC012083CF91DF910895F894FFCF5B

:1010000009C00EC00DC00CC00BC00AC009C008C08A
:1010100007C006C011241FBECFE9CDBF02D020C03B
:10102000EFCFDF93CF9300D0CDB7DEB71A8219820E
:101030000BC088E390E029812655FC01208389813B
:101040009A8101969A83898389819A818A30910550
:1010500084F380E090E0CE5FCDBFCF91DF91089523
:04106000F894FFCF32
:0400000300001000E9
:00000001FF

and that's it. As I say, I could just do this with srec_cat:

srec_cat app.hex -intel boot.hex -intel -o both.hex -intel

(it has to be told "intel" each time for the two inputs and the output because otherwise it defaults to Motorola S records).

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

While waiting for your reply I was reading about srec_cat, and I was doing some tests with the exact same syntax you posted above.

What I was wondering about is the 0x1000 stuff, I mean, I took my app.hex file from the temp folder that the Arduino IDE creates when you verify/compile a sketch, how do I know if it has been built to be allocated from 0 (that is the start of the mem right?) or from somewhere else?

Same applies to the bootloader, I'm looking at a atmega328 optiboot, how do I know if it starts from 0x1000?

 

 

EDIT

Looking at the pdf in WinAVR-20100110\doc\srecord, I've seen that every record in the Intel HEX filetype is made up by the following fields:

 

Record Mark

Record Length

Load Offset

Record Type

Data

Checksum

 

The Load Offset got my attention, since its description says:

Each record has a Load Offset field which specifies the 16-bit starting load offset of the data
bytes, therefore this field is only used for Data Records. In other records where this field is not
used, it should be coded as four ASCII zero characters (‘‘0000’’ or 0x30303030). This field is
two byte, represented as four hexadecimal characters.

 

So, that's what makes the app or the bootloader files start from a specific point of memory, but at this point my doubt is:

 

We have a program that needs, for istance, allocated space that goes from address 0 to address 1023 in memory, fine.

Now we have also a bootloader, that needs, for istance, 512 bytes, what if the bootloader hex file has data fields written with the same load offset of the program ones (that in the example above is 0) ?

I'm inclined to think that the bootloader will overwrite part of the program, causing a mess..

 

So how do you join correctly the 2 files?
Does the command:

srec_cat app.hex -intel boot.hex -intel -o both.hex -intel

Do care of all of that?

Last Edited: Tue. Apr 7, 2015 - 04:54 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Arduino ALWAYS build the app at 0 (because it uses chips that have a bootloader in them already).

 

You will know that if you are writing/building your own bootloader that you use -Wl,-Ttext=0x1234 to locate the code at location 0x1234. Obviously you change this 1234 value to whatever address BOOTSZ sets your BLS boundary to be at.

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Ok, so that's why I have to put app.hex first in the srec_cat command in my case.
What about the overlap thing? If app.hex starts at n-address and bootloader.hex too, srec_cat understands it and make them sequential or it is gonna be a problem?

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 1

You don't get a choice about this! The app has to be built at location 0 and the bootloader has to be built at the address chosen by BOOTSZ (one of 4 options available). If you make the mistake of making an app so big that it spills into the bootloader section you aer FUBARed.

 

Typical numbers are that in a 32K chip the bootloader will be 0.5K, 1K, 2K or 4K in size (the four BOOTSZ options) and so that leaves 31.5K, 31K, 30K or 28K for the app.

 

Although I arbitrarily picked 0x1000 (4K) for my example above that doesn't really reflect any kind of reality. It was far more likely to be something like 0x7E00, 0x7C00, 0x7800, 0x7000

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Thanks clawson! Now it's all more clear!

 

So if an ATmega328P has the popular fuses 0x62 0xD9 0xFF (with BOOTSZ1 and BOOTSZ0 set to HIGH), according to the following table extracted from datasheet (where it says that 0 means programmed)

Boot Size Configuration, ATmega328P

It will have the bootloader programmed from sector 0x3800 to 0x3FFF, meaning that I can use a bootloader up to 2048 bytes.

Therefore the bootloader.hex file DOES NOT contain the target addresses, they are defined when the chip is going to be programmed checking the fuse bits.

 

Have I got everything right?

 

Last Edited: Tue. Apr 7, 2015 - 06:30 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Note that those are word addresses in the datasheet, not byte addresses. I believe the Intel hex format uses byte addresses. There are two bytes per word, so multiply the word addresses by 2 to get the byte address.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 1

As Chris says Atmel have this rather nasty habit of always talking about 16 bit words and word addressing when they talk about flash contents. That's because the AVR opcodes are all some multiple of 16 bits in length. So a 32K mega328 (where we use "32K" to mean 32768 bytes) has what Atmel would describe as 16K "words". It could hold 16,384 NOP opcodes for example. As we say, this extends to the addresses they use.

 

So take the second line in your table above. (BOOTSZ=10) that has room for 512 words which means 1024 bytes. It says it uses 8 pages. From that we may deduce that mega328 pages are 128 bytes (64 words) long. It says the app section is 0x0000..0x3DFF but again this is words so in bytes that would be 0x0000..0x7BFF. It then says the loader section is 0x3E00..0x3FFF but that's words. In bytes it is 0x7C00..0x7FFF. I haven't a clue why they even bother with the "end application section" address - it was already given as the upper limit of the "application flash section" but anyway 0x3DFF becomes 0x7BFF. Also the boot reset address is just the start value of "Loader flash section" so 0x3E00 in bytes is 0x7C00.

 

When you think about it this all makes sense. We know it's a 32KB (byte!) chip and 32K is 0x8000. So it kind of makes sense that addresses near the end of it are in the realms of 0x7???. If you see a document talking about a "32K" chip and them mention 0x3??? addresses "near the end" then you must be talking about 16 bit addressing.

 

And yes, this choice of Atmel's to talk in words is confusing.

 

Note that ALL the gcc tools (compiler, linker, etc) do everything in terms of bytes so to locate a bootloader at 0x7C00 you would use -Wl,-Ttext=0x7C00 (and not 0x3E00!)

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Woah! That's a nice way to confuse newcomers!
Thank you for pointing that out christop and clawson!
So, ok, in data sheet they talk in terms of words but compilers and tools always work with bytes.
Where 1 word = 2 bytes.

Beside that, if I have 2048 words for my bootloader (defined by BOOTSZ0 and BOOTSZ1 fuses), and therefore 4096 bytes, the important thing is that my bootloader.hex DOES NOT exceed 4KB in size.
If this condition is satisfied, together with the condition that says that the app.hex must be compiled starting from 0 address (like Arduino IDE does), I can safely merge app.hex and bootloader.hex using srec_cat this way:
srec_cat app.hex -intel boot.hex -intel -o both.hex -intel

Last Edited: Thu. Apr 9, 2015 - 12:53 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Well a further condition is the app cannot get larger than (chip-size - 4K). If it does it would overlap the bootloader. In that contest the bootloader (if written correctly) would win. So part of your app would be missing from the chip.

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Yeah ofc, thanks!