Closed stefanrueger closed 1 year ago
I'm not so sure whether this is a pilot error or not.
ELF files can contain any arbitrary sections. Anyone can define more sections in their setup as they like.
The -R .eeprom
in the objcopy command says: "Copy all loadable sections except the one named .eeprom".
the user-defined flash section
That's it: it is user defined. It got an arbitrary name defined by the user.
It cannot be easily deduced whether the user wants an arbitrary name to got into flash, EEPROM, or maybe even into any outside storage device (like an SPI-attached flash).
I'm all for adding some kind of knob to tune the decision what is to be considered "flash" contents, but I don't agree that the (gratuitous) definition "anything not named .eeprom is flash" is the generally correct behaviour.
Btw., the normal way to handle this situation is that the linker script categorizes the various input sections into a few output sections, for flash (also includes SRAM initialization data), eeprom, and sram. That's the way the standard linker script handle it for the various flash subsections (vector table, progmem constant data, program code, static RAM initialization data).
The more I think about it, the more it looks like a pilot error on the project to me. Someone invented an arbitrary section, but did not keep up the remaining parts of the toolchain to deal with it.
So I just did a quick Google search and found a simple article here. https://scienceprog.com/control-memory-sections-using-avr-gcc/
So we need to use linker opton to make sure the .progdata
section is located in the Flash.
-Wl,--section-start=.progdata=0x03ee
@dl8dtl Well, something in the avr-toolchain does exatly that! I haven't dreamt that up, and certainly not created my .hex file myself. So someone, who cobbled together the Makefiles for creating a .hex for that avr-toolchain has made that decision that, indeed, anything not named .eeprom should go into hex.
It cannot be easily deduced whether the user wants an arbitrary name to got into flash, EEPROM, or maybe even into any outside storage device (like an SPI-attached flash).
I notice that .eeprom also resides in a different address interval at 0x00810000 according to avr-readelf -S
, so maybe the avr-toolchain uses the address range to make that distinction? Guessing here.
$ avr-readelf -S build-uno/morse.elf
There are 15 section headers, starting at offset 0x1f54:
Section Headers:
[Nr] Name Type Addr Off Size ES Flg Lk Inf Al
[ 0] NULL 00000000 000000 000000 00 0 0 0
[ 1] .data PROGBITS 00800100 0004b0 000012 00 WA 0 0 1
[ 2] .text PROGBITS 00000000 0000b4 0003ee 00 AX 0 0 2
[ 3] .progdata PROGBITS 000003ee 0004a2 00000e 00 A 0 0 1
[ 4] .bss NOBITS 00800112 0004c2 000064 00 WA 0 0 1
[ 5] .eeprom PROGBITS 00810000 0004c2 000020 00 WA 0 0 1
[ 6] .comment PROGBITS 00000000 0004e2 000011 01 MS 0 0 1
[ 7] .note.gnu.avr.dev NOTE 00000000 0004f4 000040 00 0 0 4
[ 8] .debug_info PROGBITS 00000000 000534 0005f4 00 0 0 1
[ 9] .debug_abbrev PROGBITS 00000000 000b28 0005a2 00 0 0 1
[10] .debug_line PROGBITS 00000000 0010ca 00001a 00 0 0 1
[11] .debug_str PROGBITS 00000000 0010e4 000208 00 0 0 1
[12] .shstrtab STRTAB 00000000 001ec1 000091 00 0 0 1
[13] .symtab SYMTAB 00000000 0012ec 0006f0 10 14 46 4
[14] .strtab STRTAB 00000000 0019dc 0004e5 00 0 0 1
Key to Flags:
W (write), A (alloc), X (execute), M (merge), S (strings)
I (info), L (link order), G (group), T (TLS), E (exclude), x (unknown)
O (extra OS processing required) o (OS specific), p (processor specific)
-Wl,--section-start=.progdata=0x03ee
@mcuee If I explicitly use that linker option, avr-readelf gives me exactly the same output for the .progdata section. So, I am assuming that is what the toolchain has implicitly decided to do?
all for adding some kind of knob to tune the decision what is to be considered "flash" contents
And what could that be? Address ranges? Name conventions? What the toolchain does?
So with the surprises-the-user hat on it is surprising that avrdude -U flash:w:file.elf:e
should behave differently from avrdude -U flash:w:file.hex:i
as both are spit out by the same toolchain.
I'm not so sure whether this is a pilot error or not.
And if this is a pilot error as you suspect, what would the correct command be to create the .hex from the .elf?
I notice that .eeprom also resides in a different address interval at 0x00810000 according to avr-readelf -S , so maybe the avr-toolchain uses the address range to make that distinction? Guessing here.
The article above that @mcuee found confirms my guess: They write
The memory space “seen” by AVRGCC runs from addresses:
0x00000000 up to 0x0007FFFF for Flash memory,
0x00800000 up to 0x0080FFFF for RAM, and
0x00810000 up to 0x0081FFFF for EEPROM.
So, looking at the output of avr-readelf
the section .progdata
must reside in flash. And AVRDUDE is wrong not to do so.
Someone invented an arbitrary section
Just to be clear, if it isn't from my description before, the .progdata name comes from my very own source code:
const uint8_t two[] __attribute__((section (".progdata"))) = {
'H', 'e', 'l', 'l', 'o', ',', ' ', 'w', 'o', 'r', 'l', 'd', '\n', 0
};
I could have chosen the name .arewenothavingfuntoday
and apart from cutting off the name in the avr-readelf
output
[ 3] .arewenothavingfu PROGBITS 000003ee 0004a2 00000e 00 A 0 0 1
the result is the same. I assume the compiler saw the global variable const uint8_t two[]
with the section name, packed it into flash (because const
) and gave it its own section, so linker scripts can reason about that. All looks sane to me.
So key observation is that it's not the arbitrary user name that matters here but the (correct) compiler decision that the global const
variable needs to reside in flash, which is what the compiler/linker indicates by putting it into the address range [0, 0x 7ffff]. The name is secondary but it gets its own section b/c the user asked for that. The toolchain quite rightly puts that into the .elf and the .hex. And AVRDUDE should respect that, too.
So key observation is that it's not the arbitrary user name that matters here but the (correct) compiler decision that the global
const
variable needs to reside in flash, which is what the compiler/linker indicates by putting it into the address range [0, 0x 7ffff]. The name is secondary but it gets its own section b/c the user asked for that. The toolchain quite rightly puts that into the .elf and the .hex. And AVRDUDE should respect that, too.
Good summary.
So from my quick read (I know very little of avr-gcc toolchain), avr-gcc toolchain is correct, avr-objcopy correctly understand that .progdata
is located in Flash (address range is within Flash are) and generate the correct hex file.
The issue here is that avrdude seems to only include .text
section and .data
section when programming flash.
From here: https://github.com/avrdudes/avrdude/pull/1195#issuecomment-1331020497
This already works in the existing code, but there is no check for sections, as a result, data from other sectors, not .text and not .data, will be written immediately after them to flash.
@dl8dtl Is this because of avr-libc? https://www.nongnu.org/avr-libc/user-manual/mem_sections.html
-Wl,--section-start=.progdata=0x03ee
@mcuee If I explicitly use that linker option, avr-readelf gives me exactly the same output for the .progdata section. So, I am assuming that is what the toolchain has implicitly decided to do?
Since I do not have the source codes of the morse
project, I am trying to reproduce this issue using Arduino IDE and I do not see the following two in the hex file or elf file.
uint8_t one[] = {
'B', 'o', 'n', 'j', 'o', 'u', 'r', ' ', 'l', 'e', ' ', 'm', 'o', 'n', 'd', 'e', '\n', 0
};
const uint8_t two[] __attribute__((section (".progdata"))) = {
'H', 'e', 'l', 'l', 'o', ',', ' ', 'w', 'o', 'r', 'l', 'd', '\n', 0
};
Just to be clear, if it isn't from my description before, the .progdata name comes from my very own source code:
Exactly. That's why it is also your responsibility to handle it in the linker script if you invent sections by your own.
If you had named it .progmem (as anyone else is doing, and avr-libc has support macros for), the default linker script would already do it for you.
avr-objcopy correctly understand that
.progdata
is located in Flash
No, avr-objcopy doesn't know anything about flash or anything else like that. It's just the user who called avr-objcopy with the -R .eeprom
argument who told it to include all loaded sections except .eeprom
.
Btw., I suspect that this avr-objcopy -R .eeprom
inadvertently gets your .hex file two copies of the .data
section. The default linkerscript knows that one copy of .data
needs to go into the flash (from where the startup code can pick it up at initialization time). But then, the objcopy copying everything but .eeprom
will pull a second copy of it.
@dl8dtl and @stefanrueger
I can reproduce what @stefanrueger gets.
Base blinking program using avr-gcc. https://github.com/tderflinger/arduino-blink-purec
My simple patch:
$ git diff
diff --git a/Makefile b/Makefile
index 7dd1853..11240f8 100644
--- a/Makefile
+++ b/Makefile
@@ -5,10 +5,10 @@ ARDUINO_USB ?= /dev/ttyUSB0
all: led.hex
-led.hex: led
- avr-objcopy -O ihex -R .eeprom led led.hex
+led.hex: led.elf
+ avr-objcopy -O ihex -R .eeprom led.elf led.hex
-led: led.o
+led.elf: led.o
avr-gcc $(LDFLAGS) -o $@ $^
led.o: led.c
@@ -18,6 +18,6 @@ deploy: led.hex
avrdude -F -V -c arduino -p ATMEGA328p -P ${ARDUINO_USB} -b 115200 -U flash:w:led.hex
clean: FRC
- rm -f led.elf led.hex led.o led
+ rm -f led.elf led.hex led.o
-FRC:
\ No newline at end of file
+FRC:
diff --git a/led.c b/led.c
index 6c476ad..bd4b43d 100644
--- a/led.c
+++ b/led.c
@@ -1,10 +1,18 @@
#include <avr/io.h>
#define F_CPU 16000000
-#define BLINK_DELAY_MS 5000
+#define BLINK_DELAY_MS 500
#include <util/delay.h>
+uint8_t one[] = {
+ 'B', 'o', 'n', 'j', 'o', 'u', 'r', ' ', 'l', 'e', ' ', 'm', 'o', 'n', 'd', 'e', '\n', 0
+};
+
+const uint8_t two[] __attribute__((section (".progdata"))) = {
+ 'H', 'e', 'l', 'l', 'o', ',', ' ', 'w', 'o', 'r', 'l', 'd', '\n', 0
+};
+
int main (void)
{
// Arduino digital pin 13 (pin 5 of PORTB) for output
@@ -19,4 +27,4 @@ int main (void)
PORTB &= ~ 0B100000; // PORTB5
_delay_ms(BLINK_DELAY_MS);
}
-}
\ No newline at end of file
+}
Results.
$ make
avr-gcc -Os -DF_APU=16000000UL -mmcu=atmega328p -c -o led.o led.c
avr-gcc -mmcu=atmega328p -o led.elf led.o
avr-objcopy -O ihex -R .eeprom led.elf led.hex
$ avr-readelf -S led.elf
There are 13 section headers, starting at offset 0x22ec:
Section Headers:
[Nr] Name Type Addr Off Size ES Flg Lk Inf Al
[ 0] NULL 00000000 000000 000000 00 0 0 0
[ 1] .data PROGBITS 00800100 000148 000012 00 WA 0 0 1
[ 2] .text PROGBITS 00000000 000074 0000c6 00 AX 0 0 2
[ 3] .progdata PROGBITS 000000c6 00013a 00000e 00 A 0 0 1
[ 4] .comment PROGBITS 00000000 00015a 000011 01 MS 0 0 1
[ 5] .note.gnu.av[...] NOTE 00000000 00016c 000040 00 0 0 4
[ 6] .debug_info PROGBITS 00000000 0001ac 0005f4 00 0 0 1
[ 7] .debug_abbrev PROGBITS 00000000 0007a0 0005a2 00 0 0 1
[ 8] .debug_line PROGBITS 00000000 000d42 00001d 00 0 0 1
[ 9] .debug_str PROGBITS 00000000 000d5f 000208 00 0 0 1
[10] .symtab SYMTAB 00000000 000f68 000bf0 10 11 133 4
[11] .strtab STRTAB 00000000 001b58 00070f 00 0 0 1
[12] .shstrtab STRTAB 00000000 002267 000084 00 0 0 1
Key to Flags:
W (write), A (alloc), X (execute), M (merge), S (strings), I (info),
L (link order), O (extra OS processing required), G (group), T (TLS),
C (compressed), x (unknown), o (OS specific), E (exclude),
D (mbind), p (processor specific)
$ avrdude -c usbasp -p m328p -U ./led.elf -q
avrdude: AVR device initialized and ready to accept instructions
avrdude: device signature = 0x1e950f (probably m328p)
avrdude: Note: flash memory has been specified, an erase cycle will be performed.
To disable this feature, specify the -D option.
avrdude: erasing chip
avrdude: reading input file ./led.elf for flash
with 216 bytes in 2 sections within [0, 0xe5]
using 2 pages and 40 pad bytes
avrdude: writing 216 bytes flash ...
avrdude: 216 bytes of flash written
avrdude: verifying flash memory against ./led.elf
avrdude: 216 bytes of flash verified
avrdude done. Thank you.
$ avrdude -c usbasp -p m328p -qqt
avrdude> dump flash
>>> dump flash
0000 0c 94 34 00 0c 94 49 00 0c 94 49 00 0c 94 49 00 | .4. .I. .I. .I.|
0010 0c 94 49 00 0c 94 49 00 0c 94 49 00 0c 94 49 00 | .I. .I. .I. .I.|
0020 0c 94 49 00 0c 94 49 00 0c 94 49 00 0c 94 49 00 | .I. .I. .I. .I.|
0030 0c 94 49 00 0c 94 49 00 0c 94 49 00 0c 94 49 00 | .I. .I. .I. .I.|
0040 0c 94 49 00 0c 94 49 00 0c 94 49 00 0c 94 49 00 | .I. .I. .I. .I.|
0050 0c 94 49 00 0c 94 49 00 0c 94 49 00 0c 94 49 00 | .I. .I. .I. .I.|
0060 0c 94 49 00 0c 94 49 00 11 24 1f be cf ef d8 e0 | .I. .I..$......|
0070 de bf cd bf 11 e0 a0 e0 b1 e0 e4 ed f0 e0 02 c0 |................|
0080 05 90 0d 92 a2 31 b1 07 d9 f7 0e 94 4b 00 0c 94 |.. ..1......K. .|
0090 61 00 0c 94 00 00 25 9a 2d 9a 2f ef 89 e6 98 e1 |a. ...%.-./.....|
00a0 21 50 80 40 90 40 e1 f7 00 c0 00 00 2d 98 2f ef |!P.@.@......-./.|
00b0 89 e6 98 e1 21 50 80 40 90 40 e1 f7 00 c0 00 00 |....!P.@.@......|
00c0 eb cf f8 94 ff cf ff ff ff ff ff ff ff ff ff ff |................|
00d0 ff ff ff ff 42 6f 6e 6a 6f 75 72 20 6c 65 20 6d |....Bonjour le m|
00e0 6f 6e 64 65 0a 00 ff ff ff ff ff ff ff ff ff ff |onde ...........|
00f0 ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff |................|
avrdude> quit
>>> quit
avrdude>
Btw., I suspect that this
avr-objcopy -R .eeprom
inadvertently gets your .hex file two copies of the.data
section. The default linkerscript knows that one copy of.data
needs to go into the flash (from where the startup code can pick it up at initialization time). But then, the objcopy copying everything but.eeprom
will pull a second copy of it.
Actually not true. I have removed -R .eeprom
from the Makefile and it is still the same.
$ make clean
rm -f led.elf led.hex led.o
$ make
avr-gcc -Os -DF_APU=16000000UL -mmcu=atmega328p -c -o led.o led.c
avr-gcc -mmcu=atmega328p -o led.elf led.o
avr-objcopy -O ihex led.elf led.hex
xiaof@LAPTOP-913SIMUD MINGW64 /c/work/avr/avrdude_test/arduino-blink-purec
$ avr-readelf -S led.elf
There are 13 section headers, starting at offset 0x22ec:
Section Headers:
[Nr] Name Type Addr Off Size ES Flg Lk Inf Al
[ 0] NULL 00000000 000000 000000 00 0 0 0
[ 1] .data PROGBITS 00800100 000148 000012 00 WA 0 0 1
[ 2] .text PROGBITS 00000000 000074 0000c6 00 AX 0 0 2
[ 3] .progdata PROGBITS 000000c6 00013a 00000e 00 A 0 0 1
[ 4] .comment PROGBITS 00000000 00015a 000011 01 MS 0 0 1
[ 5] .note.gnu.av[...] NOTE 00000000 00016c 000040 00 0 0 4
[ 6] .debug_info PROGBITS 00000000 0001ac 0005f4 00 0 0 1
[ 7] .debug_abbrev PROGBITS 00000000 0007a0 0005a2 00 0 0 1
[ 8] .debug_line PROGBITS 00000000 000d42 00001d 00 0 0 1
[ 9] .debug_str PROGBITS 00000000 000d5f 000208 00 0 0 1
[10] .symtab SYMTAB 00000000 000f68 000bf0 10 11 133 4
[11] .strtab STRTAB 00000000 001b58 00070f 00 0 0 1
[12] .shstrtab STRTAB 00000000 002267 000084 00 0 0 1
Key to Flags:
W (write), A (alloc), X (execute), M (merge), S (strings), I (info),
L (link order), O (extra OS processing required), G (group), T (TLS),
C (compressed), x (unknown), o (OS specific), E (exclude),
D (mbind), p (processor specific)
$ avrdude -c usbasp -p m328p -U ./led.hex -q
avrdude: AVR device initialized and ready to accept instructions
avrdude: device signature = 0x1e950f (probably m328p)
avrdude: Note: flash memory has been specified, an erase cycle will be performed.
To disable this feature, specify the -D option.
avrdude: erasing chip
avrdude: reading input file ./led.hex for flash
with 230 bytes in 1 section within [0, 0xe5]
using 2 pages and 26 pad bytes
avrdude: writing 230 bytes flash ...
avrdude: 230 bytes of flash written
avrdude: verifying flash memory against ./led.hex
avrdude: 230 bytes of flash verified
avrdude done. Thank you.
$ avrdude -c usbasp -p m328p -qqt
avrdude> dump flash
>>> dump flash
0000 0c 94 34 00 0c 94 49 00 0c 94 49 00 0c 94 49 00 | .4. .I. .I. .I.|
0010 0c 94 49 00 0c 94 49 00 0c 94 49 00 0c 94 49 00 | .I. .I. .I. .I.|
0020 0c 94 49 00 0c 94 49 00 0c 94 49 00 0c 94 49 00 | .I. .I. .I. .I.|
0030 0c 94 49 00 0c 94 49 00 0c 94 49 00 0c 94 49 00 | .I. .I. .I. .I.|
0040 0c 94 49 00 0c 94 49 00 0c 94 49 00 0c 94 49 00 | .I. .I. .I. .I.|
0050 0c 94 49 00 0c 94 49 00 0c 94 49 00 0c 94 49 00 | .I. .I. .I. .I.|
0060 0c 94 49 00 0c 94 49 00 11 24 1f be cf ef d8 e0 | .I. .I..$......|
0070 de bf cd bf 11 e0 a0 e0 b1 e0 e4 ed f0 e0 02 c0 |................|
0080 05 90 0d 92 a2 31 b1 07 d9 f7 0e 94 4b 00 0c 94 |.. ..1......K. .|
0090 61 00 0c 94 00 00 25 9a 2d 9a 2f ef 89 e6 98 e1 |a. ...%.-./.....|
00a0 21 50 80 40 90 40 e1 f7 00 c0 00 00 2d 98 2f ef |!P.@.@......-./.|
00b0 89 e6 98 e1 21 50 80 40 90 40 e1 f7 00 c0 00 00 |....!P.@.@......|
00c0 eb cf f8 94 ff cf 48 65 6c 6c 6f 2c 20 77 6f 72 |......Hello, wor|
00d0 6c 64 0a 00 42 6f 6e 6a 6f 75 72 20 6c 65 20 6d |ld .Bonjour le m|
00e0 6f 6e 64 65 0a 00 ff ff ff ff ff ff ff ff ff ff |onde ...........|
00f0 ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff |................|
avrdude> quit
>>> quit
avrdude>
$ avrdude -c usbasp -p m328p -U ./led.elf -q
avrdude: AVR device initialized and ready to accept instructions
avrdude: device signature = 0x1e950f (probably m328p)
avrdude: Note: flash memory has been specified, an erase cycle will be performed.
To disable this feature, specify the -D option.
avrdude: erasing chip
avrdude: reading input file ./led.elf for flash
with 216 bytes in 2 sections within [0, 0xe5]
using 2 pages and 40 pad bytes
avrdude: writing 216 bytes flash ...
avrdude: 216 bytes of flash written
avrdude: verifying flash memory against ./led.elf
avrdude: 216 bytes of flash verified
avrdude done. Thank you.
$ avrdude -c usbasp -p m328p -qqt
avrdude> dump flash
>>> dump flash
0000 0c 94 34 00 0c 94 49 00 0c 94 49 00 0c 94 49 00 | .4. .I. .I. .I.|
0010 0c 94 49 00 0c 94 49 00 0c 94 49 00 0c 94 49 00 | .I. .I. .I. .I.|
0020 0c 94 49 00 0c 94 49 00 0c 94 49 00 0c 94 49 00 | .I. .I. .I. .I.|
0030 0c 94 49 00 0c 94 49 00 0c 94 49 00 0c 94 49 00 | .I. .I. .I. .I.|
0040 0c 94 49 00 0c 94 49 00 0c 94 49 00 0c 94 49 00 | .I. .I. .I. .I.|
0050 0c 94 49 00 0c 94 49 00 0c 94 49 00 0c 94 49 00 | .I. .I. .I. .I.|
0060 0c 94 49 00 0c 94 49 00 11 24 1f be cf ef d8 e0 | .I. .I..$......|
0070 de bf cd bf 11 e0 a0 e0 b1 e0 e4 ed f0 e0 02 c0 |................|
0080 05 90 0d 92 a2 31 b1 07 d9 f7 0e 94 4b 00 0c 94 |.. ..1......K. .|
0090 61 00 0c 94 00 00 25 9a 2d 9a 2f ef 89 e6 98 e1 |a. ...%.-./.....|
00a0 21 50 80 40 90 40 e1 f7 00 c0 00 00 2d 98 2f ef |!P.@.@......-./.|
00b0 89 e6 98 e1 21 50 80 40 90 40 e1 f7 00 c0 00 00 |....!P.@.@......|
00c0 eb cf f8 94 ff cf ff ff ff ff ff ff ff ff ff ff |................|
00d0 ff ff ff ff 42 6f 6e 6a 6f 75 72 20 6c 65 20 6d |....Bonjour le m|
00e0 6f 6e 64 65 0a 00 ff ff ff ff ff ff ff ff ff ff |onde ...........|
00f0 ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff |................|
avrdude> quit
>>> quit
avrdude>
If you had named it .progmem (as anyone else is doing, and avr-libc has support macros for), the default linker script would already do it for you.
@dl8dtl
That does not seem to help in my testing, no matter what I called that section, .progmem
, progmem
and PROGMEM
. Does this mean my avr-gcc (from MSYS2) is broken?
$ avr-gcc -v
Using built-in specs.
Reading specs from c:/msys64/mingw64/bin/../lib/gcc/avr/8.5.0/device-specs/specs-avr2
COLLECT_GCC=C:\msys64\mingw64\bin\avr-gcc.exe
COLLECT_LTO_WRAPPER=c:/msys64/mingw64/bin/../libexec/gcc/avr/8.5.0/lto-wrapper.exe
Target: avr
Configured with: ../gcc-8.5.0/configure --build=x86_64-w64-mingw32 --prefix=/mingw64 --target=avr --enable-languages=c,c++ --disable-nls --disable-libssp --disable-shared --disable-threads --disable-libgomp --disable-libada --with-dwarf2 --enable-mingw-wildcard
Thread model: single
gcc version 8.5.0 (GCC)
I have removed
-R .eeprom
from the Makefile and it is still the same.
Sure, you don't have EEPROM initialization data anyway in that project. ;-) But OK, it's indeed there only once, my assumption was wrong.
no matter what I called that section,
.progmem
,progmem
andPROGMEM
Well, the normal AVR way is to use __attribute__((__progmem__))
. This is what the <avr/pgmspace.h>
macros are using.
I looked into the generated assembly, that eventually translates into a section name .progmem.data
. If you use that in your example, everything "magically" works: there is no longer a section by that name in the resulting ELF file, everything gets integrated into the .text
section.
That's the way how it is supposed to work. Anything deviating from that default scheme needs to provide a custom linker script that deals with the self-declared sections, taking care of properly transferring all flash data to the output section .text
.
That's why it is also your responsibility to handle it in the linker script if you invent sections by your own.
Well, the avr-gcc compiler, linker and/or default linker scripts seem to disagree with you @dl8dtl! They automagically do the right thing and squeeze the .progdata
section between .text
and .data
. I suspect it is because the avr compiler saw a global variable with a const
modifier, and therefore decided it must be put in flash and told the linker so.
I want the .progdata
section in high flash. Had the compiler/linker not done that out of their own volition, I would have gone to the trouble learning about linker scripts making sure that .progdata
is moved into high flash. Either way, (with or without my responsibility) it ended up in the right address space [0, 0x7ffff].
avr-objcopy -R .eeprom
inadvertently gets your .hex file two copies of the.data
section
It does not. I checked: .data
is there only once (count the 'Bonjour`s in the .hex); have a look yourself: morse.zip; I used the avr-toolchain 5.4.0. Or try it yourself with your favourite avr-toolchain. Would be interesting to see what you get!
If you had named it .progmem (as anyone else is doing, and avr-libc has support macros for)
.progmem
does the wrong thing for me: it puts the data into low flash. I need them in high flash after .text
.
It is useful to store certain data at the top of a large flash memory, particularly when PROGMEM
data threaten to flow beyond the bottom 64 kB space. In this case PROGMEM
data are not guaranteed to be reachable by *_P()
functions. Not all *_P()
functions have a *_PF()
equivalent (that reaches beyond 64 kB) in the avr-libc
library. Hence, it makes sense to put all those data at the top of the sketch that only need be processed by *_PF()
functions. This leaves (more of) the remaining PROGMEM
data in reach of *_P()
functions.
Alternatively, could have used __attribute__((section (".text")))
but then my data would be word-aligned, which can result in unwanted pad bytes (I may be known for many things but certainly not for gratuitous waste of flash :)
Summarising, everyone seems to think the little .progdata
section belongs in flash: the compiler, the linker (positioning it between .text and .data), perhaps even the default linker script, the generated .elf file (asserted through address space [0, 0x7ffff]), the .hex file, the avr-
Well, no. The compiler doesn't know anything about your .progdata
details at all. It just copies the section over into the output file, and depending on the section order, objcopy copies it from there into the hex file. This might or might not be the correct place … You could name your section .foobar
, and it will go into the output file as well.
Btw., the reason the default .progmem.data
section is located as low as possible is that the LPM
instruction can only handle data within the first 64 KiB of flash. The difference is, for 128 KiB devices, all instructions can automatically handle everything up to 128 KiB (since the PC addresses in 16-bit words), but LPM
addresses byte addressed data, and is thus restricted on the lower half of that flash. (For devices beyond 128 KiB, things get worse though, and for devices with at most 64 KiB, it doesn't matter at all.)
If you want your flash data go on top of the normal instructions, call the section .progmemx.data
. That one is correctly handled by the default linker script.
Note that <avr/pgmspace.h>
also offers macros to access flash data beyond 64 KiB, but it's getting more cumbersome then.
[must use] custom linker script
The produced .elf does not know whether a custom linker script was used. Neither does AVRDUDE. I think the .elf file is correct. And still think AVRDUDE is wrong when it interprets the elf. @dl8dtl Tell me what is wrong with the .elf. Which bit in the data is wrong? The sections don't overlap. The .progdata section is of type PROGBITS. It is in the flash region [0, 0x7ffff]. It has the ALLOC attribute set. What more could a custom linker script have done?
top of the normal instructions, call the section
.progmemx.data
Alas, that doesn't seem to work in my avr-toolchain 5.4.0: puts the data below the instructions (like PROGMEM) and is probably word aligned (bad).
<avr/pgmspace.h> also offers macros to access flash data beyond 64 KiB
I know. The problem is that avr-libc has asymmetric support of beyond 64 kB data. Le me repeat my above use case (please read it this time): It is useful to store certain data at the top of a large flash memory, particularly when PROGMEM data threaten to flow beyond the bottom 64 kB space. In this case PROGMEM data are not guaranteed to be reachable by _P() functions. Not all _P() functions have a _PF() equivalent (that reaches beyond 64 kB) in the avr-libc library. Hence, it makes sense to put all those data at the top of the sketch that only need be processed by _PF() functions. This leaves (more of) the remaining PROGMEM data in reach of *_P() functions.
Well, then your toolchain is too old.
Btw. before AVRDUDE could handle ELF files at all, the recommended way to produce the hex file was avr-objcopy -i .text -i .data
. With that, your example would lose as well.
Just kicking out the EEPROM section is basically a poor abuse only. This gets immediately obvious if your program code also contains initialization values for fuses (<avr/fuse.h>
). -R .eeprom
would also copy them to flash as well. Certainly, it's just a few bytes, but would you consider that technically correct then?
Your entire example does not work by design but only by incident (since the default of the linker is to just copy all unprocessed input section to output sections, and since that poorly designed objcopy just copies everything it finds to the output file).
The problem is that avr-libc has asymmetric support of beyond 64 kB data.
No, the AVR itself has asymmetric support for it. LPM
can only handle 64 KiB, even though the PC on 128 KiB devices can handle more. avr-libc can only work on top of these instructions.
It is useful to store certain data at the top of a large flash memory,
That's the reason why the toolchain was then taught to handle .progmemx.*
.
I did design the ELF file handling in AVRDUDE many years ago, and I designed it in a way to match the remaining toolchain elements. I refuse to consider this a bug, sorry.
Regarding missing _PF functions in avr-libc: I could accept that as an enhancement request though. ;-)
__attribute__((__progmem__))
This does work.
mcuee@UbuntuSwift3:~/build/avr/arduino-blink-purec$ cat led.c
#include <avr/io.h>
#define F_CPU 16000000
#define BLINK_DELAY_MS 500
#include <util/delay.h>
#define _EEMEM __attribute__((__used__, __section__ (".eeprom")))
#define _EEPROM uint8_t __eeprom[32] _EEMEM
_EEPROM = { "Hello World!" };
FUSES = { 0xF7, 0xD6, 0xFD }; // lfuse, hfuse, efuse
const uint8_t one[] __attribute__((__progmem__)) = {
'B', 'o', 'n', 'j', 'o', 'u', 'r', ' ', 'l', 'e', ' ', 'm', 'o', 'n', 'd', 'e', '\n', 0 };
const uint8_t two[] __attribute__((__progmem__)) = {
'H', 'e', 'l', 'l', 'o', ',', ' ', 'w', 'o', 'r', 'l', 'd', '\n', 0 };
int main (void)
{
// Arduino digital pin 13 (pin 5 of PORTB) for output
DDRB |= 0B100000; // PORTB5
while(1) {
// turn LED on
PORTB |= 0B100000; // PORTB5
_delay_ms(BLINK_DELAY_MS);
// turn LED off
PORTB &= ~ 0B100000; // PORTB5
_delay_ms(BLINK_DELAY_MS);
}
}
mcuee@UbuntuSwift3:~/build/avr/arduino-blink-purec$ make clean
rm -f led.elf led.hex led.o led
mcuee@UbuntuSwift3:~/build/avr/arduino-blink-purec$ make
avr-gcc -Os -DF_APU=16000000UL -mmcu=atmega328p -c -o led.o led.c
avr-gcc -mmcu=atmega328p -o led.elf led.o
avr-objcopy -O ihex -R .eeprom led.elf led.hex
mcuee@UbuntuSwift3:~/build/avr/arduino-blink-purec$ avrdude -c usbasp -p m328p -U led.elf
avrdude: AVR device initialized and ready to accept instructions
avrdude: device signature = 0x1e950f (probably m328p)
avrdude: Note: flash memory has been specified, an erase cycle will be performed.
To disable this feature, specify the -D option.
avrdude: erasing chip
avrdude: reading input file led.elf for flash
with 208 bytes in 1 section within [0, 0xcf]
using 2 pages and 48 pad bytes
avrdude: writing 208 bytes flash ...
Writing | ################################################## | 100% 0.09 s
avrdude: 208 bytes of flash written
avrdude: verifying flash memory against led.elf
Reading | ################################################## | 100% 0.04 s
avrdude: 208 bytes of flash verified
avrdude done. Thank you.
mcuee@UbuntuSwift3:~/build/avr/arduino-blink-purec$ avrdude -c usbasp -p m328p -qqt
avrdude> dump flash
0000 0c 94 44 00 0c 94 4e 00 0c 94 4e 00 0c 94 4e 00 | .D. .N. .N. .N.|
0010 0c 94 4e 00 0c 94 4e 00 0c 94 4e 00 0c 94 4e 00 | .N. .N. .N. .N.|
0020 0c 94 4e 00 0c 94 4e 00 0c 94 4e 00 0c 94 4e 00 | .N. .N. .N. .N.|
0030 0c 94 4e 00 0c 94 4e 00 0c 94 4e 00 0c 94 4e 00 | .N. .N. .N. .N.|
0040 0c 94 4e 00 0c 94 4e 00 0c 94 4e 00 0c 94 4e 00 | .N. .N. .N. .N.|
0050 0c 94 4e 00 0c 94 4e 00 0c 94 4e 00 0c 94 4e 00 | .N. .N. .N. .N.|
0060 0c 94 4e 00 0c 94 4e 00 48 65 6c 6c 6f 2c 20 77 | .N. .N.Hello, w|
0070 6f 72 6c 64 0a 00 42 6f 6e 6a 6f 75 72 20 6c 65 |orld .Bonjour le|
0080 20 6d 6f 6e 64 65 0a 00 11 24 1f be cf ef d8 e0 | monde ..$......|
0090 de bf cd bf 0e 94 50 00 0c 94 66 00 0c 94 00 00 |......P. .f. ...|
00a0 25 9a 2d 9a 2f ef 89 e6 98 e1 21 50 80 40 90 40 |%.-./.....!P.@.@|
00b0 e1 f7 00 c0 00 00 2d 98 2f ef 89 e6 98 e1 21 50 |......-./.....!P|
00c0 80 40 90 40 e1 f7 00 c0 00 00 eb cf f8 94 ff cf |.@.@............|
00d0 ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff |................|
00e0 ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff |................|
00f0 ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff |................|
avrdude> quit
avrdude>
Regarding a possible enhancement option, we could teach the -U
option which ELF sections to use, somehow. I'm only afraid that makes the syntax and possible ambiguities of the syntax even worse – we already have the issue with Windows filenames that contain a colon, where the heuristics fail, and the user is required to supply all four syntax elements after -U
.
@dl8dtl
What is the right syntax to define the attribute .progmemx.*.
? Thanks.
Just kicking out the EEPROM section is basically a poor abuse only.
You don't need to kick out the EEPROM section in objcopy. It is the address space that makes things right.
Again, what is wrong with the following .elf? In terms of attributes? In terms of addresses? In terms of types?
$ readelf -S morse.elf
There are 15 section headers, starting at offset 0x1f54:
Section Headers:
[Nr] Name Type Addr Off Size ES Flg Lk Inf Al
[ 0] NULL 00000000 000000 000000 00 0 0 0
[ 1] .data PROGBITS 00800100 0004b0 000012 00 WA 0 0 1
[ 2] .text PROGBITS 00000000 0000b4 0003ee 00 AX 0 0 2
[ 3] .progdata PROGBITS 000003ee 0004a2 00000e 00 A 0 0 1
[ 4] .bss NOBITS 00800112 0004c2 000064 00 WA 0 0 1
[ 5] .eeprom PROGBITS 00810000 0004c2 000020 00 WA 0 0 1
[ 6] .comment PROGBITS 00000000 0004e2 000011 01 MS 0 0 1
[ 7] .note.gnu.avr.dev NOTE 00000000 0004f4 000040 00 0 0 4
[ 8] .debug_info PROGBITS 00000000 000534 0005f4 00 0 0 1
[ 9] .debug_abbrev PROGBITS 00000000 000b28 0005a2 00 0 0 1
[10] .debug_line PROGBITS 00000000 0010ca 00001a 00 0 0 1
[11] .debug_str PROGBITS 00000000 0010e4 000208 00 0 0 1
[12] .shstrtab STRTAB 00000000 001ec1 000091 00 0 0 1
[13] .symtab SYMTAB 00000000 0012ec 0006f0 10 14 46 4
[14] .strtab STRTAB 00000000 0019dc 0004e5 00 0 0 1
Key to Flags:
W (write), A (alloc), X (execute), M (merge), S (strings), I (info),
L (link order), O (extra OS processing required), G (group), T (TLS),
C (compressed), x (unknown), o (OS specific), E (exclude),
p (processor specific)
Let me repeat: the .elf does not know whether it was created by an old or a new toolchain or whether you approve of its making (custom linker script or not). What is it that kicks .progdata
out?
I don't think there's a separate keyword for that, so you can only declare it with the full section attribute syntax.
… __attribute__((__section__((".progmemx.data")))
.
Let me repeat: the .elf does not know whether it was created by an old or a new toolchain
It does. If you'd use the newer linker scripts, and .progmemx.data, your data would appear inside .text in the resulting ELF file. That is the big difference, the toolchain design is supposed to have all flash data in .text.
__attribute__((__section__((".progmemx.data")))
That's exactly what I did!
__attribute__((__section__((".progmemx.data")))
That's exactly what I did!
Yep, but with too old linker scripts that don't have the support for .progmemx.* added.
the toolchain design is supposed to have all flash data in .text
and .data
and other sections; why then would the toolchain have left the space between .text
and .data
and actually considered .progdata
to sit between them?
With an up-to-date toolchain, it looks like that:
$ avr-objdump -h led.o
led.o: file format elf32-avr
Sections:
Idx Name Size VMA LMA File off Algn
0 .text 00000000 00000000 00000000 00000034 2**0
CONTENTS, ALLOC, LOAD, READONLY, CODE
1 .data 00000012 00000000 00000000 00000034 2**0
CONTENTS, ALLOC, LOAD, DATA
2 .bss 00000000 00000000 00000000 00000046 2**0
ALLOC
3 .text.startup 0000002c 00000000 00000000 00000046 2**0
CONTENTS, ALLOC, LOAD, RELOC, READONLY, CODE
4 .progmemx.data 0000000e 00000000 00000000 00000072 2**0
CONTENTS, ALLOC, LOAD, READONLY, DATA
5 .comment 00000013 00000000 00000000 00000080 2**0
CONTENTS, READONLY
$ avr-objdump -h led
led: file format elf32-avr
Sections:
Idx Name Size VMA LMA File off Algn
0 .data 00000012 00800100 000000d4 00000148 2**0
CONTENTS, ALLOC, LOAD, DATA
1 .text 000000d4 00000000 00000000 00000074 2**1
CONTENTS, ALLOC, LOAD, READONLY, CODE
2 .comment 00000012 00000000 00000000 0000015a 2**0
CONTENTS, READONLY
3 .note.gnu.avr.deviceinfo 00000040 00000000 00000000 0000016c 2**2
CONTENTS, READONLY
4 .debug_info 000005f4 00000000 00000000 000001ac 2**0
CONTENTS, READONLY, DEBUGGING
5 .debug_abbrev 000005a2 00000000 00000000 000007a0 2**0
CONTENTS, READONLY, DEBUGGING
6 .debug_line 0000001d 00000000 00000000 00000d42 2**0
CONTENTS, READONLY, DEBUGGING
7 .debug_str 00000208 00000000 00000000 00000d5f 2**0
CONTENTS, READONLY, DEBUGGING
Note that led.o contains .progmemx.data, while the linked ELF file doesn't. It has everything in .text.
With an up-to-date toolchain, it looks like that:
What is the avr-gcc version you are using? Apparently avr-gcc 7.3 from Atmel does not work.
mcuee@UbuntuSwift3:~/build/avr/arduino-blink-purec$ avr-gcc -v
Using built-in specs.
Reading specs from /home/mcuee/avr8-gnu-toolchain-linux_x86_64/bin/../lib/gcc/avr/7.3.0/device-specs/specs-avr2
COLLECT_GCC=avr-gcc
COLLECT_LTO_WRAPPER=/home/mcuee/avr8-gnu-toolchain-linux_x86_64/bin/../libexec/gcc/avr/7.3.0/lto-wrapper
Target: avr
Configured with: /home/toolsbuild/workspace/avr8-gnu-toolchain/src/gcc/configure LDFLAGS=-L/home/toolsbuild/workspace/avr8-gnu-toolchain/avr8-gnu-toolchain-linux_x86_64-hostlibs/lib CPPFLAGS= --target=avr --host=x86_64-pc-linux-gnu --build=x86_64-pc-linux-gnu --prefix=/home/toolsbuild/workspace/avr8-gnu-toolchain/avr8-gnu-toolchain-linux_x86_64 --libdir=/home/toolsbuild/workspace/avr8-gnu-toolchain/avr8-gnu-toolchain-linux_x86_64/lib --enable-languages=c,c++ --with-dwarf2 --enable-doc --disable-shared --disable-libada --disable-libssp --disable-nls --with-avrlibc=yes --with-mpfr=/home/toolsbuild/workspace/avr8-gnu-toolchain/avr8-gnu-toolchain-linux_x86_64-hostlibs --with-gmp=/home/toolsbuild/workspace/avr8-gnu-toolchain/avr8-gnu-toolchain-linux_x86_64-hostlibs --with-mpc=/home/toolsbuild/workspace/avr8-gnu-toolchain/avr8-gnu-toolchain-linux_x86_64-hostlibs --with-pkgversion=AVR_8_bit_GNU_Toolchain_3.7.0_1796 --with-bugurl=http://www.microchip.com
Thread model: single
gcc version 7.3.0 (AVR_8_bit_GNU_Toolchain_3.7.0_1796)
the toolchain design is supposed to have all flash data in .text
and
.data
No. The linker script takes care of copying the initial values to .text.
With an up-to-date toolchain, it looks like that:
What is the avr-gcc version you are using? Apparently avr-gcc 7.3 from Atmel does not work.
I think it's merely a matter of the binutils version.
Atmel decoupled their stuff from the opensource mainline development many years ago. :-( Basically by the time when they started to put everything into device packs. They no longer use the official avr-libc stuff there, and likely lag behind with a lot of the remaining tool development.
The linker script takes care of copying the initial values to .text.
No. We had that before. The .text section does not contain .data.
The linker script takes care of copying the initial values to .text.
No. We had that before. The .text section does not contain .data.
OK, you're right. Copying that to flash was always considered the job of the postprocessing tool.
But to make nails with heads: let's extend the -U option to allow for explicitly naming ELF sections to include.
I think it's merely a matter of the binutils version.
2017-07-27 Georg-Johann Lay <gjl@gcc.gnu.org>
PR ld/21849
* scripttempl/avr.sc: Split .progmemx.* from .progmem.* and locate
former at a higher address.
(GNU ld ChangeLog-2017)
The current AVRDUDE code almost gets the sections right (in my sense). It just misses some sections that are mapped into Segments in the elf file. Look closely at Segment 00 in below output from readelf
:
$ readelf -l morse.elf
Elf file type is EXEC (Executable file)
Entry point 0x0
There are 4 program headers, starting at offset 52
Program Headers:
Type Offset VirtAddr PhysAddr FileSiz MemSiz Flg Align
LOAD 0x0000b4 0x00000000 0x00000000 0x003fc 0x003fc R E 0x2
LOAD 0x0004b0 0x00800100 0x000003fc 0x00012 0x00012 RW 0x1
LOAD 0x0004c2 0x00800112 0x00800112 0x00000 0x00064 RW 0x1
LOAD 0x0004c2 0x00810000 0x00810000 0x00020 0x00020 RW 0x1
Section to Segment mapping:
Segment Sections...
00 .text .progdata
01 .data
02 .bss
03 .eeprom
The AVRDUDE scan misses the .progdata section (that has all the right attributes, addresses, types ...) in Section 00
I suggest changing the code to scoop up the remaining sections that are needed for Section 00 of the program. I also suggest @dl8dtl look away for this ;)
I suggest to extend -U
instead. ;-)
But to make nails with heads: let's extend the -U option to allow for explicitly naming ELF sections to include.
No that's not needed. A different scan of the .elf segments will do. It's all already there in the segments.
Really, the question is whether we can tell from the .elf file which sections belong to flash and which not. The user does not need to know (and should not need to know, b/c the elf file already does). Here my proposal: Sections that are
A
(for Alloc)are used. Voila. A small step for AVRDUDE. A large step for Mankind.
I'm afraid .data doesn't match your requirements (outside of your address range).
With an up-to-date toolchain, it looks like that: ... Note that led.o contains .progmemx.data, while the linked ELF file doesn't. It has everything in .text.
@dl8dtl I get the same result as you under MSYS2, Sorry I miss-understood the meaning of "top of the memory" and thought that it did not work.
$ avr-objdump -h led.elf
led.elf: file format elf32-avr
Sections:
Idx Name Size VMA LMA File off Algn
0 .data 00000000 00800100 000000d0 00000184 2**0
CONTENTS, ALLOC, LOAD, DATA
1 .text 000000d0 00000000 00000000 000000b4 2**1
CONTENTS, ALLOC, LOAD, READONLY, CODE
2 .eeprom 00000020 00810000 00810000 00000184 2**0
CONTENTS, ALLOC, LOAD, DATA
3 .fuse 00000003 00820000 00820000 000001a4 2**0
CONTENTS, ALLOC, LOAD, DATA
4 .comment 00000011 00000000 00000000 000001a7 2**0
CONTENTS, READONLY
5 .note.gnu.avr.deviceinfo 00000040 00000000 00000000 000001b8 2**2
CONTENTS, READONLY, OCTETS
6 .debug_info 000005f4 00000000 00000000 000001f8 2**0
CONTENTS, READONLY, DEBUGGING, OCTETS
7 .debug_abbrev 000005a2 00000000 00000000 000007ec 2**0
CONTENTS, READONLY, DEBUGGING, OCTETS
8 .debug_line 0000001d 00000000 00000000 00000d8e 2**0
CONTENTS, READONLY, DEBUGGING, OCTETS
9 .debug_str 00000208 00000000 00000000 00000dab 2**0
CONTENTS, READONLY, DEBUGGING, OCTETS
$ avrdude -c usbasp -p m328p -U led.elf -q
avrdude: AVR device initialized and ready to accept instructions
avrdude: device signature = 0x1e950f (probably m328p)
avrdude: Note: flash memory has been specified, an erase cycle will be performed.
To disable this feature, specify the -D option.
avrdude: erasing chip
avrdude: reading input file led.elf for flash
with 208 bytes in 1 section within [0, 0xcf]
using 2 pages and 48 pad bytes
avrdude: writing 208 bytes flash ...
avrdude: 208 bytes of flash written
avrdude: verifying flash memory against led.elf
avrdude: 208 bytes of flash verified
avrdude done. Thank you.
$ avrdude -c usbasp -p m328p -qqt
avrdude> dump flash
>>> dump flash
0000 0c 94 3d 00 0c 94 47 00 0c 94 47 00 0c 94 47 00 | .=. .G. .G. .G.|
0010 0c 94 47 00 0c 94 47 00 0c 94 47 00 0c 94 47 00 | .G. .G. .G. .G.|
0020 0c 94 47 00 0c 94 47 00 0c 94 47 00 0c 94 47 00 | .G. .G. .G. .G.|
0030 0c 94 47 00 0c 94 47 00 0c 94 47 00 0c 94 47 00 | .G. .G. .G. .G.|
0040 0c 94 47 00 0c 94 47 00 0c 94 47 00 0c 94 47 00 | .G. .G. .G. .G.|
0050 0c 94 47 00 0c 94 47 00 0c 94 47 00 0c 94 47 00 | .G. .G. .G. .G.|
0060 0c 94 47 00 0c 94 47 00 42 6f 6e 6a 6f 75 72 20 | .G. .G.Bonjour |
0070 6c 65 20 6d 6f 6e 64 65 0a 00 11 24 1f be cf ef |le monde ..$....|
0080 d8 e0 de bf cd bf 0e 94 49 00 0c 94 5f 00 0c 94 |........I. ._. .|
0090 00 00 25 9a 2d 9a 2f ef 89 e6 98 e1 21 50 80 40 |..%.-./.....!P.@|
00a0 90 40 e1 f7 00 c0 00 00 2d 98 2f ef 89 e6 98 e1 |.@......-./.....|
00b0 21 50 80 40 90 40 e1 f7 00 c0 00 00 eb cf f8 94 |!P.@.@..........|
00c0 ff cf 48 65 6c 6c 6f 2c 20 77 6f 72 6c 64 0a 00 |..Hello, world .|
00d0 ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff |................|
00e0 ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff |................|
00f0 ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff |................|
avrdude> quit
>>> quit
avrdude>
Just kicking out the EEPROM section is basically a poor abuse only. This gets immediately obvious if your program code also contains initialization values for fuses (<avr/fuse.h>). -R .eeprom would also copy them to flash as well. Certainly, it's just a few bytes, but would you consider that technically correct then?
And you are absolutely correct about the fuse thingy. I saw this in Arduino IDE and I was thinking it was an Arduino problem. Now I understood. Thanks.
$ cat led.hex
:100000000C943D000C9447000C9447000C9447005E
:100010000C9447000C9447000C9447000C94470044
:100020000C9447000C9447000C9447000C94470034
:100030000C9447000C9447000C9447000C94470024
:100040000C9447000C9447000C9447000C94470014
:100050000C9447000C9447000C9447000C94470004
:100060000C9447000C944700426F6E6A6F757220C3
:100070006C65206D6F6E64650A0011241FBECFEFA2
:10008000D8E0DEBFCDBF0E9449000C945F000C9405
:100090000000259A2D9A2FEF89E698E121508040A3
:1000A0009040E1F700C000002D982FEF89E698E11D
:1000B000215080409040E1F700C00000EBCFF89461
:1000C000FFCF48656C6C6F2C20776F726C640A00F0
:02000004008179
:1000000048656C6C6F20576F726C642100000000B3
:1000100000000000000000000000000000000000E0
:02000004008278
:03000000F7D6FD33
:00000001FF
$ avrdude -c usbasp -p m328p -U led.hex
avrdude: AVR device initialized and ready to accept instructions
avrdude: device signature = 0x1e950f (probably m328p)
avrdude: Note: flash memory has been specified, an erase cycle will be performed.
To disable this feature, specify the -D option.
avrdude: erasing chip
avrdude error: address 0x810010 out of range at line 15 of led.hex
avrdude error: read from file led.hex failed
avrdude done. Thank you.
I'm afraid .data doesn't match your requirements (outside of your address range).
You are right! Seems to be even easier: Copy sections that are
A
(for Alloc)@dl8dtl
I feel it strange that avr-gcc does not create a new section for other memory sections like fuses.
I also feel it strange that we need to create a seperate .eep
file for EEPROM. The hex file can already include the EEPROM as its address range is different from the flash.
Take note I was a Microchip PIC guy last time and not that familiar with Atmel AVR (some encouters with USB AVR/AVR32 but not much, thanks to the free AVR Dragon and two demo boards from Atmel many years ago).
The memory space “seen” by AVRGCC runs from addresses:
0x00000000 up to 0x0007FFFF for Flash memory,
0x00800000 up to 0x0080FFFF for RAM, and
0x00810000 up to 0x0081FFFF for EEPROM.
@mcuee In your run, Bonjour le monde appears to be at the bottom of the instructions. Not what's needed.
Here a zip file morse.zip with an .elf file and the corresponding .hex file for the 16 MHz ATmega328p Uno/ProMini with a LED at B5; it prints Bonjour le monde from
.data
(57600 baud on USART) then morses this text via the LED; then prints Hello, world from user-defined flash section.progdata
and morses this text via the LED.Uploading
morse.elf
behaves differently from uploadingmorse.hex
:Notice the missing "Hello, world" text.
The upload of the
avrdude.elf
file fails to incorporate the user-defined flash section.progdata
, see Section Nr 3 in the following printout:The expected behaviour of
-U morse.elf
should be the same as-U morse.hex
, which is generated byOnly standard avr-toolchain operations were used; the user-defined flash section was generated in the C source using