Placing a string directly after the vectors in Flash

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

I would like to place a version string right after the vectors in my ATmega16. I'm using AVRStudio and WinAVR to build my project, and the version string is defined in version.c.

Defining my own section at that address gives a linker error that says that my section overlaps the .text section so that does not work.

If I put my version string in PROGMEM then it is placed in the beginning of the Flash, but other PROGMEM constants are placed before it. If I remove all c-files from the AVRStudio project and then add them again, starting with the version.c so that it will be built first, then the version string is palced where I want it. But I don't like this because it is dependent on the order the files are added, and if someone creates a new project based on this then they will likely not add version.c first... And using a custom Makefile is unfortunately not an option.

.text           0x00000000     0x2ce6
 *(.vectors)
 .vectors       0x00000000       0x54 c:/devtools/winavr-20070525/avr/lib/avr5/crtm16.o
                0x00000000                __vectors
 *(.vectors)
 *(.progmem.gcc*)
 *(.progmem*)
 .progmem.data  0x00000054      0x200 CRC.o
                0x00000154                mCrcTable_L
                0x00000054                mCrcTable_H
 .progmem.data  0x00000254       0x24 Image.o
 .progmem.data  0x00000278        0x2 version.o
                0x00000278                VersionArray <-WRONG!!!

If I put the string in the .vectors section then it is placed where I want it. But I don't feel comfortable doing that. Can I guarantee that the vectors always are placed before my version string?

.text           0x00000000     0x2ce6
 *(.vectors)
 .vectors       0x00000000       0x54 c:/devtools/winavr-20070525/avr/lib/avr5/crtm16.o
                0x00000000                __vectors
 .vectors       0x00000054        0x2 version.o
                0x00000054                VersionArray <-CORRECT!
 *(.vectors)
 *(.progmem.gcc*)
 *(.progmem*)
 .progmem.data  0x00000056      0x200 CRC.o
                0x00000156                mCrcTable_L
                0x00000056                mCrcTable_H
 .progmem.data  0x00000256       0x24 Image.o

Comments and suggestions? Any ideas how to proper solve this?

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

Well one way would be to put it in a self defined section but rather than trying to place this simply with a --section-start use a modified linker script that slots it in between .vectors and .progmem

Cliff

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

A Unix version string is generally embedded somewhere in the .data section. It is up to the "version" program to detect it. Since AVR linkers generally try to place strings early in flash memory, it is not that difficult to find.

I agree that a version string tends to use some weird characters to make it stand out. And you consequently waste a little space. The search algorithm is not expensive though.

char *g_idlist[] = {
	"$Author",
	"$Date",
	"$Header",
	"$Id",
	"$Locker",
	"$Log",
	"$RCSfile",
	"$Revision",
	"$Source",
	"$State",
	"@(#)",
	"#:-);-)8-)",
	NULL
};

Of course you may choose to look for far more strings than this. Or probably may just look for one magic string.

Your biggest concern is that an over-enthusiastic linker chooses to discard the unreferenced version string.

David.

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

Quote:

use some weird characters

The obvious ones being "@(#)" in fact.

In case anyone doesn't know this is the trigger that "what" looks for. Expained here:

http://www.unix.com/302068719-po...

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

You could also use .progmem.gcc, although I'm not sure 'who' uses that.

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

I read and re-read COLA's post and I can't find >>why<< it is important to have the information in a particular place, in this case down low. Y'all have mentioned about searching for it. If you want a particular place, why not "up high" at the end of flash, or just before the bootloader section? If there is room for it down low, there will be room for it up high. Most header files should have constants that can be used so the same scheme should work across all models that have bootloaders, or from FLASHEND for those that don't.

/* ***** DATA MEMORY DECLARATIONS ***************************************** */
#define    FLASHEND        0x7fff  // Note: Word address
#define    IOEND           0x00ff
#define    SRAM_START      0x0100
#define    SRAM_SIZE       4096
#define    RAMEND          0x10ff
#define    XRAMEND         0x0000
#define    E2END           0x07ff
#define    EEPROMEND       0x07ff
#define    EEADRBITS       11



/* ***** BOOTLOADER DECLARATIONS ****************************************** */
#define    NRWW_START_ADDR 0x7000
#define    NRWW_STOP_ADDR  0x7fff
#define    RWW_START_ADDR  0x0
#define    RWW_STOP_ADDR   0x6fff
#define    PAGESIZE        128
#define    FIRSTBOOTSTART  0x7e00
#define    SECONDBOOTSTART 0x7c00
#define    THIRDBOOTSTART  0x7800
#define    FOURTHBOOTSTART 0x7000
#define    SMALLBOOTSTART  FIRSTBOOTSTART
#define    LARGEBOOTSTART  FOURTHBOOTSTART


You can put lipstick on a pig, but it is still a pig.

I've never met a pig I didn't like, as long as you have some salt and pepper.

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

Quote:

why not "up high" at the end of flash, or just before the bootloader section?

Yup, that's exactly where I'd put it too - last two bytes before the BLS boundary or before FLASHEND if bootloader not used. (But by default the avr-libc io???.h files do not have the 4 boot positions defined, though FLASHEND is in bytes, so it'd need to be done manually for those)

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

I agree with Lee. Placing the constants up high will work just as well as down low and is easier to do.

However, if you absolutely insist on putting the constants after the vector table, you'll need to hack the linker script for your device.

The ATmega16 is an "avr5" architecture (see Using The Gnu Tools for the processor/architecture relationship table). That means you want to modify the avr5.x script found in \avr\lib\ldscripts.

Change the section:

  .text :
  {
    *(.vectors)
    KEEP(*(.vectors))
    /* For data that needs to reside in the lower 64k of progmem.  */
    *(.progmem.gcc*)
    *(.progmem*)

to include a new section, say .version:

  .text :
  {
    *(.vectors)
    KEEP(*(.vectors))
    *(.version)
    /* KEEP(*(.version)) - don't need to keep if it isn't defined */
    /* For data that needs to reside in the lower 64k of progmem.  */
    *(.progmem.gcc*)
    *(.progmem*)

Note that the .progmem.gcc* section is right there as well. The .progmem.gcc* section is used to store the initialization constants for the .data section (for example, when you define a global with an initial value, this is where that value resides).

You should have an external makefile (check out the WinAVR MFile template) so you can add the line:

LDFLAGS += -T linker_script.x

Finally, you will nee to define you version (I will assume you want a string, but this could be anything) as:

#define VERSION_SECTION   __attribute__ ((section (".version")))

const char Version [] VERSION_SECTION = "0.8";

Rock on!

Stu

Engineering seems to boil down to: Cheap. Fast. Good. Choose two. Sometimes choose only one.

Newbie? Be sure to read the thread Newbie? Start here!

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

I think I'll go with the custom link script, it seems most suitable for us. Thanks for all the replies!

The reason for not placing it at the highest possible address is that when upgrading the firmware our application receives the entire firmware as a raw binary image. If the version string were at the highest address then the binary image would always have to be equal to the entire flash minus boot size, and the MCU would have to wait for the entire image to be sent before it could decide if the firmware is valid for its type of device.

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

If you put the Version data in a separate section, won't the .HEX file only contain the program records (to its end without the empty space) and the Version info as separate records?

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

rstahlhu wrote:
If you put the Version data in a separate section, won't the .HEX file only contain the program records (to its end without the empty space) and the Version info as separate records?

He just said that it's a raw binary image, not a .HEX file.

Four legs good, two legs bad, three legs stable.

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

Quote:
The .progmem.gcc* section is used to store the initialization constants for the .data section (for example, when you define a global with an initial value, this is where that value resides).
I have never seen .progmem.gcc used at all. The initialization data for the .data section is stored at the end of the .text section (see linker script). I still don't know what .progmem.gcc is used for, but there must be some reason its there (like maybe its for storing serial numbers/version info at a known/fixed location :) ).