AVR S7 / GCC - Define custom eeprom segments using linker?

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

As has been asked many a time before, i'd like to split up the eeprom of my device into some fixed segments (for, as usual, boot loader to application  data exchange & interfacing, and to allow an external tool to read some fixed device info, which needs to be always in the same place)

 

I've recently swapped to AVR studio 7 after being happily "stuck" on Studio4 for about 20 years (btw, S4 just 'worked', whereas S7 is both buggy, complex and non intuitive, but that'e what you get when you use an un-necessarily complex environment to progam a simple 8bitter.......)

 

So,

 

I my code i define segments:

 

 #define EEMEMBLDB					__attribute__((section(".eeprombldb")))
 #define EEMEMDB					__attribute__((section(".eepromdb")))

and when i define my variables, i use that attribute setting

 

bldb_t BLDBe EEMEMBLDB = 											// BLDB = Boot-Loader Data Block
{
{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},									// BOOTLOADER BYTES at start of eprom
};

 

 

And in the "AVR/GNU Linker" section of the Studo7 project properties i have these segments included

 

 

-Wl,-Map="$(OutputFileName).map" 
-Wl,--start-group 
-Wl,-lm  
-Wl,--end-group 
-Wl,--gc-sections -mrelax 
-Wl,-section-start=.eeprom=0x810020  
-mmcu=atmega1284 -B "C:\Program Files (x86)\Atmel\Studio\7.0\Packs\atmel\ATmega_DFP\1.3.300\gcc\dev\atmega1284" 
-Wl,-section-start=.eeprombldb=0x810000 

 

and the resulting .map looks like this:

 

.eeprom         0x00810020       0x99
 *(.eeprom*)
 .eepromdb      0x00810020       0x89 activecode/datablocks.o
                0x00810020                VDBe
                0x00810036                CDBe
                0x00810085                IDBe
                0x008100a1                CSDBe
 .eeprombldb    0x008100a9       0x10 activecode/datablocks.o
                0x008100a9                BLDBe
                0x008100b9                __eeprom_end = .

 

 

So it has correctly offset the .eeprom section by 0x20 (from the base address of 0x810000), but it hasn't slotted in the bootloader data block section in front, but has appended it on the end of the rest of the .eeprom section data?

 

 

I'm obviously doing something wrong, but i just can't see what it is currently.....   Anyone shine any light on my stupidity???  ;-)

 

 

 

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

Consider copying avr51.x to local, edit the .eeprom section to insert your new bits then -Wl,-Tavr51_local_copy.x or whatever you called it.

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

Wouldn’t a data structure the size of EEMEM be the simple answer, place this in a header shared by both app and bl?

 

jim

 

(Possum Lodge oath) Quando omni flunkus, moritati.

"I thought growing old would take longer"

 

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

ki0bk wrote:
Wouldn’t a data structure the size of EEMEM be the simple answer, place this in a header shared by both app and bl?
+1

 

(much simpler!)

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

I "can't" use a single structure, much as i would like too, because i need to see individual names for the items in the .map file, because this is automatically parsed into a file (.a2l) for some external s/w to read to access those memory locations by parameter names.  If i put it all in a single struct, i just get the name of the struct at the start address and that's it.....  What i really need to find the time to do is to write the software to generate the struct from the params,, rather than the struct from the params, so that s/w could also then parse the names and relative addresses out!

 

 

Clawson, can you expand on your file trick? I understand the basics, take the std gcc memory allocation file, modify it to suit my requirements, and include it as a local, specific copy, which i then use the linker to throw at the compiler etc.  But,  which files do a specifically need?  (AVR'S sit by "Type" i understand that, but persumably the compiler is using pre-compiled object files for this sort of thing?

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

The X file for 1284 is avr51.x which should be in your GCC installation in ...\avr\lib\ldscripts. For example:

C:\Program Files (x86)\Atmel\Studio\7.0\toolchain\avr8\avr8-gnu-toolchain\avr\lib\ldscripts>grep -i eeprom avr51.x
__EEPROM_REGION_LENGTH__ = DEFINED(__EEPROM_REGION_LENGTH__) ? __EEPROM_REGION_LENGTH__ : 64K;
  eeprom (rw!x) : ORIGIN = 0x810000, LENGTH = __EEPROM_REGION_LENGTH__
  .eeprom  :
    KEEP(*(.eeprom*))
     __eeprom_end = . ;
  }  > eeprom

so take avr51.x as a local copy, edit that copy (and perhaps rename it to avoid possible name clashes/accidents) then -T this to the linker. as the above search shows the stuff relevant to EEPROM is:

  .eeprom  :
  {
    /* See .data above...  */
    KEEP(*(.eeprom*))
     __eeprom_end = . ;
  }  > eeprom

Actually I hadn't realised that it contains ".eeprom*" so it looks like this should be conglomerating any eeprom* sections anyway but I bet it does it in alpha sort order in which case just ".epprom" would come before ".eepromb" or ".eepromldb" so you may want to list them explicitly, something like:

  .eeprom  :
  {
    /* See .data above...  */
    KEEP(*(.eepromb*))
    KEEP(*(.eepromldb*))
    KEEP(*(.eeprom*))
     __eeprom_end = . ;
  }  > eeprom

(or whatever your preferred order is) to force the link order. If you need these at specific boundaries then consider something like:

  .eeprom  :
  {
    /* See .data above...  */
    KEEP(*(.eepromb*))
    /* to next 32 byte boundary... */
    . = ALIGN(32)
    KEEP(*(.eepromldb*))
    KEEP(*(.eeprom*))
     __eeprom_end = . ;
  }  > eepro

Either read the avr-ld manual to learn more about what you can do in ldscripts or just look at the pattern of what's done in the other .data / .text sections to see some of the things possible.

 

EDIT: recent manual...  https://sourceware.org/binutils/docs-2.34/ld/Scripts.html#Scripts

Last Edited: Mon. Jul 13, 2020 - 04:18 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

max_torque_2008 wrote:
If i put it all in a single struct, i just get the name of the struct at the start address and that's it.

Isn't there an option to control that?

 

Surely, Your "external s/w" should be able to work it out from the definition of the struct ?

 

EDIT: Or, perhaps, from the ELF ?

 

PS

 

max_torque_2008 wrote:
AVR (sic) studio 7

 

You mean Atmel Studio 7

Top Tips:

  1. How to properly post source code - see: https://www.avrfreaks.net/comment... - also how to properly include images/pictures
  2. "Garbage" characters on a serial terminal are (almost?) invariably due to wrong baud rate - see: https://learn.sparkfun.com/tutorials/serial-communication
  3. Wrong baud rate is usually due to not running at the speed you thought; check by blinking a LED to see if you get the speed you expected
  4. Difference between a crystal, and a crystal oscillatorhttps://www.avrfreaks.net/comment...
  5. When your question is resolved, mark the solution: https://www.avrfreaks.net/comment...
  6. Beginner's "Getting Started" tips: https://www.avrfreaks.net/comment...
Last Edited: Mon. Jul 13, 2020 - 06:07 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

awneil wrote:
Surely, Your "external s/w" should be able to work it out from the definition of the struct ?

That would be soooo much easier then parsing the map file!

but OP has not said why he/she is doing this.

 

jim

 

 

(Possum Lodge oath) Quando omni flunkus, moritati.

"I thought growing old would take longer"

 

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

mainly because i'm working with something already written (not by me) which i can't realistically change!

 

in the long run, yes, i'll probably get the dog to wag it's tail, rather than the otherway around and use an .xml generator to build the code files from the setup, rather than as currently, where the setup comes from the code files.......

 

And no, i still can't get it to work!  Will have another go tomorrow with a fresh morning brain, not a jaded evening one!

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

Having just said "which i can't change" i'm beginning to think that now might be the moment to do just that wink

 

 

First problem that pops up is how to automate the check sum correction on the eeprom data in .eep format!  Currently, a bit of software looks at the .map, yanks the eeprom addresses for each block out, then loops through the .eep, calculating the checksums, and then writes those checksums into the .eep in the checksum block.  But with a single struct in the eeprom (which is absolutely the nicest way of organising that memory section by far as mentioned) we can no longer "see" the addresses for individual blocks, so the checksum software needs changing.  I guess as we know the order of the blocks no longer changes (because it is fixed by the new struct) we can look at the ram addresses for each block (blocks get copied to RAM at run time) and with a bit of maths, pull out address boundaries using the ram addresses and block lengths?

 

Kinda the same thing, but obv someone (me) is going to have to re-write that bit of software OR i bite the bullet properly and just write the higher level generator code to build the structs and blocks from the top down, using that s/w to write the necessary matching code files. That as mentioned is rather better idea, but will take a bit of time.......

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

Easily done in Python I would suggest. You can easily generate .hex from code.
.
Another approach.. use objcopy to convert data to bin (assuming you know the base location). Just fopen/fread/etc the bin to do the checksum stuff. Then invoke objcopy again to convert bin back to hex (with suitable base address)

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

Just define the symbols in assembly.

Declare, but do not define them in C.

Iluvatar is the better part of Valar.

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

What currently happens is someone writes C code, which AVRstudio uses to generate the .hex and .eep for the embedded processor, and the .map and .h files are parsed by a psuedo text parser (writted in C++) and that spits out some propriety descriptive files in .xml format, and those files are loaded by another bit of software (data logging / calibration tool) that can interface to the running embedded device via CCP / XCP.

 

The automation allows people (not just me) to take some basic hardware (which i supply) and write their own functional code, and the tool chain then builds the files to allow those people seamless access for realtime logging and system calibration, without anyone having to wade manually through endless files and parameters.  Unfortunately it's based on stuff first written (mostly by me) about 20 years ago and so it's clunky at best.

 

As mentioned, i really need to bite the bullet and bring the whole thing kicking and screaming into the 2000's and spin the proccess on it's head, so the user adds the parameters to the tool, and the tool then generates the matching files, because the embedded C code files are in reality the least complex / difficult bit.......

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

Something like this

  .macro ntry,name,offset,value
    .org \offset, 0xFF
    .global \name
    \name : .byte \value
  .mend

  .section .eeprom,"a",@progbits
  ntry dozen,0,12
  ; 3-byte gap
  ntry pie,4,3
  ; 4-byte gap
  ntry ace,9,1

should work.

Iluvatar is the better part of Valar.