attiny88

Go To Last Post
9 posts / 0 new
Author
Message
#1
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

i want to store a string , and check if that string is available in the .hex generated. but i have no clue how to do this!

any help would be appreciated..

thanks in advance!!

This topic has a solution.
This reply has been marked as the solution. 
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I'm not sure I follow your question. Do you mean something like this:

$ cat avr.c
#include <avr/io.h>

char text[] = "Hello world";

int main(void)
{
}
$ avr-gcc -mmcu=atmega16 -Os avr.c -o avr.elf
$ avr-objcopy -j .text -j .data -O binary avr.elf avr.bin
$ hexdump -C avr.bin
00000000  0c 94 2a 00 0c 94 3f 00  0c 94 3f 00 0c 94 3f 00  |..*...?...?...?.|
00000010  0c 94 3f 00 0c 94 3f 00  0c 94 3f 00 0c 94 3f 00  |..?...?...?...?.|
*
00000050  0c 94 3f 00 11 24 1f be  cf e5 d4 e0 de bf cd bf  |..?..$..........|
00000060  10 e0 a0 e6 b0 e0 e8 e8  f0 e0 02 c0 05 90 0d 92  |................|
00000070  ac 36 b1 07 d9 f7 0e 94  41 00 0c 94 42 00 0c 94  |.6......A...B...|
00000080  00 00 08 95 f8 94 ff cf  48 65 6c 6c 6f 20 77 6f  |........Hello wo|
00000090  72 6c 64 00                                       |rld.|
00000094

In this I wrote an AVR program and  built it. I actually skipped the creation of a .hex file and just went straight to binary and then used a hexdump program to look at what was in the binary. As you can see the "Hello world" I wrote in the C source has made its way into the binary. QED.

 

(If required I could have created .hex from the .elf and then used another avr-objcopy to then convert the .hex to .bin which is closer to what happens in a "normal" build but as hexdump wants to read a .bin file I thought it was easier to go straight to .bin)

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

amazing!! exactly the same thing , but i want to have the string in code memory, and wish to see that in .hex..

how to do this? any idea?

or is there a way to store the string at specific address of code memory?

Last Edited: Wed. May 13, 2015 - 12:26 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Your wish is my command. First with the string in code memory just letting the linker place it for me...

$ cat avr.c
#include <avr/io.h>
#include <avr/pgmspace.h>

const char text[] PROGMEM = "Hello world";

int main(void)
{
}
$ avr-gcc -mmcu=atmega16 -Os avr.c -o avr.elf
$ avr-objcopy -j .text -j .data -O binary avr.elf avr.bin
$ hexdump -C avr.bin
00000000  0c 94 30 00 0c 94 3a 00  0c 94 3a 00 0c 94 3a 00  |..0...:...:...:.|
00000010  0c 94 3a 00 0c 94 3a 00  0c 94 3a 00 0c 94 3a 00  |..:...:...:...:.|
*
00000050  0c 94 3a 00 48 65 6c 6c  6f 20 77 6f 72 6c 64 00  |..:.Hello world.|
00000060  11 24 1f be cf e5 d4 e0  de bf cd bf 0e 94 3c 00  |.$............<.|
00000070  0c 94 3d 00 0c 94 00 00  08 95 f8 94 ff cf        |..=...........|
0000007e

Because I'm using an old (4.5) version of the compiler here I chose to use "PROGMEM". With a more modern compiler I would have used __flash. In either case the result would be the same. As you can see the string has been placed at location 0x0054. That is just after the end of the interrupt vector table (I was building the code for mega16). That is where the linker will put .progmem - immediately after the vectors but before any AVR code for the actual program (it does this to try and pack as much PROGMEM/__flash data into the lower 64K as possible).

 

if I want to control the placement I could choose to put the data at location 0x009C as follows...

$ cat avr.c
#include <avr/io.h>
#include <avr/pgmspace.h>

const char text[] __attribute__((section(".mydata"))) = "Hello world";

int main(void)
{
}
$ avr-gcc -mmcu=atmega16 -Os -Wl,-section-start=.mydata=0x009C avr.c -o avr.elf
$ avr-objcopy -j .text -j .data -j .mydata -O binary avr.elf avr.bin
$ hexdump -C avr.bin
00000000  0c 94 2a 00 0c 94 34 00  0c 94 34 00 0c 94 34 00  |..*...4...4...4.|
00000010  0c 94 34 00 0c 94 34 00  0c 94 34 00 0c 94 34 00  |..4...4...4...4.|
*
00000050  0c 94 34 00 11 24 1f be  cf e5 d4 e0 de bf cd bf  |..4..$..........|
00000060  0e 94 36 00 0c 94 37 00  0c 94 00 00 08 95 f8 94  |..6...7.........|
00000070  ff cf 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
00000080  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
00000090  00 00 00 00 00 00 00 00  00 00 00 00 48 65 6c 6c  |............Hell|
000000a0  6f 20 77 6f 72 6c 64 00                           |o world.|
000000a8

In this case I removed "PROGMEM" (that just does the equivalent of __attribute__((section(".progmem"))) anyway) and replaced it with an __attribute__ to put the data in a section with my own chosen name (".mydata").

 

I then built with "-Wl,-section-start=.mydata=0x009C" which tells the linker I'd like anything in section ".mydata" to be placed from 0x009C onwards. When I converted the .elf to bin (could just as easily have been .hex) I added "-j .mydata" to say "also include anything in the section .mydata in the output file" and there it is.

 

The string is at location 0x009C in the flash image.

 

Simple as that.

 

What's your actual intention here? Why is it important to have data at a fixed location? Are you planning to re-write some flash pages of data using SPM perhaps?

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

By '.hex' file we generally mean the Intel Hex file format.  This format encodes binary data as ASCII in the form of hexidecimal.  Data is presented in records.  The record format is:

 

  1. Start code, one character, an ASCII colon ':'.
  2. Byte count, two hex digits, indicating the number of bytes (hex digit pairs) in the data field. The maximum byte count is 255 (0xFF). 16 (0x10) and 32 (0x20) are commonly used byte counts.
  3. Address, four hex digits, representing the 16-bit beginning memory address offset of the data. The physical address of the data is computed by adding this offset to a previously established base address, thus allowing memory addressing beyond the 64 kilobyte limit of 16-bit addresses. The base address, which defaults to zero, can be changed by various types of records. Base addresses and address offsets are always expressed as big endian values.
  4. Record type (see record types below), two hex digits, 00 to 05, defining the meaning of the data field.
  5. Data, a sequence of n bytes of data, represented by 2n hex digits. Some records omit this field (n equals zero). The meaning and interpretation of data bytes depends on the application.
  6. Checksum

 

The only characters you will ever see in a .hex file are 0-9, A-F, and the colon.  A string like 'Hello World' will be encoded in the data field across one or more records in the .hex file as '48656C6C6F20576F726C64'.

"Experience is what enables you to recognise a mistake the second time you make it."

"Good judgement comes from experience.  Experience comes from bad judgement."

"Wisdom is always wont to arrive late, and to be a little approximate on first possession."

"When you hear hoofbeats, think horses, not unicorns."

"Fast.  Cheap.  Good.  Pick two."

"We see a lot of arses on handlebars around here." - [J Ekdahl]

 

Last Edited: Wed. May 13, 2015 - 04:30 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

As if by magic. To prove Joey's point. Here's what happens if I change my objcopy to be:

$ avr-objcopy -j .text -j .data -j .mydata -O ihex avr.elf avr.hex
$ cat avr.hex
:100000000C942A000C9434000C9434000C943400AA
:100010000C9434000C9434000C9434000C94340090
:100020000C9434000C9434000C9434000C94340080
:100030000C9434000C9434000C9434000C94340070
:100040000C9434000C9434000C9434000C94340060
:100050000C94340011241FBECFE5D4E0DEBFCDBF29
:100060000E9436000C9437000C9400000895F89418
:02007000FFCFC0
:0C009C0048656C6C6F20776F726C64001C
:00000001FF

The "Hello world" bit in that is the second last line:

:0C009C0048656C6C6F20776F726C64001C

You can break down such a line as follows:

Number of bytes on this line: 0C
address where data will go:   009C
type of record (data):        00
the data itself:              48656C6C6F20776F726C6400
the checksum for the line:    1C

As Joey predicted the code for "Hello World" is:

48 65 6C 6C 6F 20  77 6F 72 6C 64 00
H  e  l  l  o  ' ' w  o  r  l  d  0x00

In fact in my original hex dump that showed both the hex codes and the ASCII you could see this in the line:

00000090                                       48 65 6c 6c  |............Hell|
000000a0  6f 20 77 6f 72 6c 64 00                           |o world.|

 

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

ahhh..!!! thanks clawson and joey for your replies :) thats exactly what i was looking for!!

 

@ clawson :

   my intention is actually to have a SoftwareVersion mechanism, such that just by looking at the .hex i must be able to tell which version of Sw was downloaded on the target..

 

and there are couple of Questions

1. basically i have a AVR studio 4 with winAVR compiler. how do i choose which format the output file must be like either .hex or .bin??

2.you have been using

avr-objcopy -j .text -j .data -j .mydata -O ihex avr.elf avr.hex

what does this actually mean, and how and where do i mention this in my AVR studio 4??

 

3. 

const char text[] __attribute__((section(".mydata"))) = "Hello world";
const char text[] __attribute__((section("0x009C"))) = "Hello world";

is this correct??

4:

text             0x00000000         0x00002000         xr
data             0x00800060         0x0000ffa0         rw !x
eeprom           0x00810000         0x00010000         rw !x
fuse             0x00820000         0x00000400         rw !x
lock             0x00830000         0x00000400         rw !x
signature        0x00840000         0x00000400         rw !x
*default*        0x00000000         0xffffffff

 

 

this is  section from MAP file,  which list the amount of memory allocated to each section

so address above 2000, say for ex 5000 is a valid memory location or not?

if yes will that be considered under text section??

 

Please clarify !!

 

 

 

Last Edited: Thu. May 14, 2015 - 06:47 AM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

@ clawson :

   my intention is actually to have a SoftwareVersion mechanism, such that just by looking at the .hex i must be able to tell which version of Sw was downloaded on the target..

That's tricky. As Joey says all that you "see" in .hex file are pairs of [0..9][A..F] digits. Personally I would just do exactly what I have done above. Given a .hex file use:

avr-objcopy -I ihex -O binary somefile.hex somefile.bin
hexdump -C somefile.bin

1. basically i have a AVR studio 4 with winAVR compiler. how do i choose which format the output file must be like either .hex or .bin??

Studio auto-creates a Makefile for you. In it the rule that creates the final output file is something like:

avr-objcopy -O ihex -R .fuse -R .lock -R .eeprom project.elf project.hex

That extracts the "program code" from the .elf file and the "-O ihex" means that it then written out in Intel hex format. If you wanted .bin you need to find a way to change the "-O ihex" to be "-O binary" instead. You'd probably also want the output be changed from project.hex to project.bin (otherwise files with .hex extensions that really contain .bin data could be really confusing!). But what I would do is add a "post build step" (don't know if AS4 allowed that - AS6 certainly does) that just waits until project.hex has been created then do:

avr-objcopy -I ihex -O binary project.hex project.bin

then each time you build you will have both a .hex and a .bin file.

what does this actually mean, and how and where do i mention this in my AVR studio 4??

OK well you don't really need to know this because, as I say, AS4 already adds a line to the build commands that does this for you. But anyway, when you build .c files each is converted to .o (which inside actually holds ELF data). When all the .c files have been compiled and all the .o files have been created they are all passed to avr-ld (the linker) and it "glues together" all the .o files and outputs yet another ELF file but this time called something like project.elf. That is the ultimate output file. It contains everything that the project came together to build. That includes flash contents but also (possibly) EEPROM contents and the contents for things like fuse and lockbit settings too. Because it contains so many different things each is assigned to a section name.

 

The code you write goes into .text.

Any initialised variables you created have their initial values stores in .data

If you used EEPROM then any such values are in a .eeprom section

If you have defined fuse bits they are in .fuse

If you have defined lockbits they are in .loc

and so on

 

In fact you even showed this in your post:

text             0x00000000         0x00002000         xr
data             0x00800060         0x0000ffa0         rw !x
eeprom           0x00810000         0x00010000         rw !x
fuse             0x00820000         0x00000400         rw !x
lock             0x00830000         0x00000400         rw !x
signature        0x00840000         0x00000400         rw !x
*default*        0x00000000         0xffffffff

The text/data/eeprom/fuse/lock/etc names there are all the sections in the .elf file.

 

Now thinlk about what you really require to be in the flash of the AVR to run the program. You don't want the .eeprom values there. You don't want .fuse. You don't want .lock and so on. There are actually TWO sections that must go into the flash. The obvious one is .text (the program code) but because that program code will start by setting up your C variables in RAM it also needs to have access to a copy of the initial values for the RAM variables (the non 0 ones). That section is .data.

So what you really want is a command that says "start with everything in project.elf but just extract .text and .data and use those to create a .hex file in Intel hex format". The command that does that is avr-objcopy ("object copy" where "object" is another word for "binary"). The very simplest command then would be:

avr-objcopy -O ihex -j .text -j .data project.elf project.hex

The "-O ihex" means "I want the file you write out to be in Intel hex format". The two -j's mean "I want to include data from the section with the following name". These options are then followed by the input and output file names. Now you may notice I didn't include "-I elf32-avr" to tell objcopy that the input file project.elf contains ELF data in the 32bit AVR format (that's 32 bit in the sense that some of the fields hold 32 bit values, not that the AVR itself is 32bit - it clearly isn't") because project.elf is so recognizable that as soon as objcopy opens the file it will instantly recognize it as ELF format for AVR anyway.

 

Now there are two options for extracting what you want from the ELF and putting it in the HEX. -j is one way. As soon as you have "-j .something" then it means "include everything from section something but no other sections unless you see more -j's". So my command includes just .text and .data. But in my example above I added my own section called .mydata. The data in that would not make it into the .hex file unless I added another "-j .mydata" to the command. If you have lots of named sections this could become quite tedious as you would have to add another -j to the objcopy for each section you add.

 

To objcopy has another way to do this. Ratther than saying which sections you DO want you can say which sections you don't want - that is which ones should be Removed. The option for that is -R. So another way to do this is:

avr-objcopy -O ihex -R .eeprom -R .fuse -R .lock project.elf project.hex

In this the -R's are saying remove .eeprom, .lock and .fuse but put everything that is left into the .hex. In theory the only things that are normally left after this are .text and .data. What's more the advantage here is that if I add another flash section called .mydata I don't have to change the objcopy command. Because I haven't specifically say "-R .mydata" it will just go into the output along with .text and .data.

 

There is a problem in this though. Some section I add might be an EEPROM or RAM section - perhaps .myEEdata or .myRAMdata. If I had created those in the source and they were included in the ELF then they might inadvertently get copied into .hex file because I forgot to add -R's to remove them. yet I don't want them in the flash.

 

So you have to make a judgement call as to whether to use -j's (and then remember to add any new flash sections as further -j's) or to use -R's (and then remember to add more -R's for non-flash sections).

 

Because most people adding sections in their C code do it to add data in named flash sections most Makefiles and IDEs choose to use an objcopy command with -R's rather than -j's.

 

(I alternate when I hand type these things as in the examples above - I pick whichever is easiest)

3. is this correct??

The first is. The second isn't. What you have to understand is that GCC is a linking compiler. That means that first a compiler runs and generates code and data objects. Then a linker runs and it chooses addresses to assign to those things so they are tightly packed into memory (both ROM and RAM). At the time  the compiler runs nothing is known about where things will go in memory. So you could not use something like:

const char text[] __attribute__((section("0x009C"))) = "Hello world";

and hope to specify the actual address (0x009C) at this stage. Instead the very reason you use section(".name") is simply to tag some code or data to say "I will want to refer to this as .name at a later stage".

 

Then when the linker runs you need to pass it the option -section-start=.name=<some address> and that's the moment at which you tell it you want it at 0x009C or whatever. Because you usually invoke avr-gcc anod not avr-ld directly to invoke the linker you need to tell avr-gcc "the following option is for the linker". the way you do that is by adding "-Wl," to the front. So the command to set the address becomes:

-Wl,-section-start=<section name>=<base address>

and in my specific example the section name I chose was ".mydata" and the address was 0x009C so the command becomes:

-Wl,-section-start=.mydata=0x009C

There is a convention that section names start with '.' but I don't think it's mandatory. I'm pretty certain a section name cannot start with a digit because say you really could use:

const char text[] __attribute__((section("0x009C"))) = "Hello world";

you might end up with a really confusing linker command such as:

-Wl,-section-start=0x009C=0x009C

and this would just even more confusing if you later moved this to address 0x0ABC:

-Wl,-section-start=0x009C=0x0ABC

Anyway I don't think section-start will allow the section name to start with the digit '0' anyway!

this is  section from MAP file,  which list the amount of memory allocated to each section

so address above 2000, say for ex 5000 is a valid memory location or not?

if yes will that be considered under text section??

The problem with ELF format is that it was designed for architectures like 80x86 and ARM which have linear address spaces (Von Neumann) but a chip like an AVR has multiple small address spaces (Harvard). Each one begins at address 0. So flash begins at 0. Ram begins at 0. EEPROM begins at 0. If you then had something at address 0x0123 how would you know whether it was in the flash or the RAM or the EEPROM?

 

To get around this, internally, GCC assigns a fixed offset to some memory spaces. For flash the base is 0x000000 so if it encounters something with address 0x0123 it knows it's in the flash. For RAM an offset of 0x800000 (8 Megabytes) is added. So something at 0x0123 in the RAM would internally have the address 0x800123. For the EEPROM the base is 0x810000. So when the system encounters 0x810123 it knows it is really data at 0x0123 in the EERom and so on. You can see the 0x8N0000 offsets in the .map contents you quoted.

 

You may have noticed that when avr-gcc extracts .eeprom from the ELF to create the .eep (Intel Hex) file it uses the command:

avr-objcopy -j .eeprom  --set-section-flags=.eeprom=alloc,load --change-section-lma .eeprom=0  --no-change-warnings -O ihex "test.elf" "test.eep"

Most of that is involved in changing the 0x810000 base to be 0x0000 in the .hex file that is output.

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

thank you so much clawson.!!:)

crystal clear explanation ... was really helpful in achieving the thing!!

finally did what i actually wanted to..

 

thanks a ton!!!