Go Down

Topic: how to not initialize variables (Read 10364 times) previous topic - next topic

udoklein

I have put the compiler options to verbose

Code: [Select]

avr-gcc -c -g -Os -w -ffunction-sections -fdata-sections -mmcu=atmega328p -DF_CPU=16000000L -DARDUINO=21 -I/home/udo/Desktop/electronics/arduino-0021/hardware/arduino/cores/arduino /home/udo/Desktop/electronics/arduino-0021/hardware/arduino/cores/arduino/WInterrupts.c -o/tmp/build2560460169561155056.tmp/WInterrupts.c.o
avr-gcc -c -g -Os -w -ffunction-sections -fdata-sections -mmcu=atmega328p -DF_CPU=16000000L -DARDUINO=21 -I/home/udo/Desktop/electronics/arduino-0021/hardware/arduino/cores/arduino /home/udo/Desktop/electronics/arduino-0021/hardware/arduino/cores/arduino/pins_arduino.c -o/tmp/build2560460169561155056.tmp/pins_arduino.c.o
avr-gcc -c -g -Os -w -ffunction-sections -fdata-sections -mmcu=atmega328p -DF_CPU=16000000L -DARDUINO=21 -I/home/udo/Desktop/electronics/arduino-0021/hardware/arduino/cores/arduino /home/udo/Desktop/electronics/arduino-0021/hardware/arduino/cores/arduino/wiring_pulse.c -o/tmp/build2560460169561155056.tmp/wiring_pulse.c.o
avr-gcc -c -g -Os -w -ffunction-sections -fdata-sections -mmcu=atmega328p -DF_CPU=16000000L -DARDUINO=21 -I/home/udo/Desktop/electronics/arduino-0021/hardware/arduino/cores/arduino /home/udo/Desktop/electronics/arduino-0021/hardware/arduino/cores/arduino/wiring_shift.c -o/tmp/build2560460169561155056.tmp/wiring_shift.c.o
avr-gcc -c -g -Os -w -ffunction-sections -fdata-sections -mmcu=atmega328p -DF_CPU=16000000L -DARDUINO=21 -I/home/udo/Desktop/electronics/arduino-0021/hardware/arduino/cores/arduino /home/udo/Desktop/electronics/arduino-0021/hardware/arduino/cores/arduino/wiring_digital.c -o/tmp/build2560460169561155056.tmp/wiring_digital.c.o
avr-gcc -c -g -Os -w -ffunction-sections -fdata-sections -mmcu=atmega328p -DF_CPU=16000000L -DARDUINO=21 -I/home/udo/Desktop/electronics/arduino-0021/hardware/arduino/cores/arduino /home/udo/Desktop/electronics/arduino-0021/hardware/arduino/cores/arduino/wiring_analog.c -o/tmp/build2560460169561155056.tmp/wiring_analog.c.o
avr-gcc -c -g -Os -w -ffunction-sections -fdata-sections -mmcu=atmega328p -DF_CPU=16000000L -DARDUINO=21 -I/home/udo/Desktop/electronics/arduino-0021/hardware/arduino/cores/arduino /home/udo/Desktop/electronics/arduino-0021/hardware/arduino/cores/arduino/wiring.c -o/tmp/build2560460169561155056.tmp/wiring.c.o
avr-g++ -c -g -Os -w -fno-exceptions -ffunction-sections -fdata-sections -mmcu=atmega328p -DF_CPU=16000000L -DARDUINO=21 -I/home/udo/Desktop/electronics/arduino-0021/hardware/arduino/cores/arduino /home/udo/Desktop/electronics/arduino-0021/hardware/arduino/cores/arduino/Print.cpp -o/tmp/build2560460169561155056.tmp/Print.cpp.o
avr-g++ -c -g -Os -w -fno-exceptions -ffunction-sections -fdata-sections -mmcu=atmega328p -DF_CPU=16000000L -DARDUINO=21 -I/home/udo/Desktop/electronics/arduino-0021/hardware/arduino/cores/arduino /home/udo/Desktop/electronics/arduino-0021/hardware/arduino/cores/arduino/main.cpp -o/tmp/build2560460169561155056.tmp/main.cpp.o
avr-g++ -c -g -Os -w -fno-exceptions -ffunction-sections -fdata-sections -mmcu=atmega328p -DF_CPU=16000000L -DARDUINO=21 -I/home/udo/Desktop/electronics/arduino-0021/hardware/arduino/cores/arduino /home/udo/Desktop/electronics/arduino-0021/hardware/arduino/cores/arduino/Tone.cpp -o/tmp/build2560460169561155056.tmp/Tone.cpp.o
avr-g++ -c -g -Os -w -fno-exceptions -ffunction-sections -fdata-sections -mmcu=atmega328p -DF_CPU=16000000L -DARDUINO=21 -I/home/udo/Desktop/electronics/arduino-0021/hardware/arduino/cores/arduino /home/udo/Desktop/electronics/arduino-0021/hardware/arduino/cores/arduino/WMath.cpp -o/tmp/build2560460169561155056.tmp/WMath.cpp.o
avr-g++ -c -g -Os -w -fno-exceptions -ffunction-sections -fdata-sections -mmcu=atmega328p -DF_CPU=16000000L -DARDUINO=21 -I/home/udo/Desktop/electronics/arduino-0021/hardware/arduino/cores/arduino /home/udo/Desktop/electronics/arduino-0021/hardware/arduino/cores/arduino/HardwareSerial.cpp -o/tmp/build2560460169561155056.tmp/HardwareSerial.cpp.o
avr-g++ -c -g -Os -w -fno-exceptions -ffunction-sections -fdata-sections -mmcu=atmega328p -DF_CPU=16000000L -DARDUINO=21 -I/home/udo/Desktop/electronics/arduino-0021/hardware/arduino/cores/arduino /home/udo/Desktop/electronics/arduino-0021/hardware/arduino/cores/arduino/WString.cpp -o/tmp/build2560460169561155056.tmp/WString.cpp.o
avr-ar rcs /tmp/build2560460169561155056.tmp/core.a /tmp/build2560460169561155056.tmp/WInterrupts.c.o
avr-ar rcs /tmp/build2560460169561155056.tmp/core.a /tmp/build2560460169561155056.tmp/pins_arduino.c.o
avr-ar rcs /tmp/build2560460169561155056.tmp/core.a /tmp/build2560460169561155056.tmp/wiring_pulse.c.o
avr-ar rcs /tmp/build2560460169561155056.tmp/core.a /tmp/build2560460169561155056.tmp/wiring_shift.c.o
avr-ar rcs /tmp/build2560460169561155056.tmp/core.a /tmp/build2560460169561155056.tmp/wiring_digital.c.o
avr-ar rcs /tmp/build2560460169561155056.tmp/core.a /tmp/build2560460169561155056.tmp/wiring_analog.c.o
avr-ar rcs /tmp/build2560460169561155056.tmp/core.a /tmp/build2560460169561155056.tmp/wiring.c.o
avr-ar rcs /tmp/build2560460169561155056.tmp/core.a /tmp/build2560460169561155056.tmp/Print.cpp.o
avr-ar rcs /tmp/build2560460169561155056.tmp/core.a /tmp/build2560460169561155056.tmp/main.cpp.o
avr-ar rcs /tmp/build2560460169561155056.tmp/core.a /tmp/build2560460169561155056.tmp/Tone.cpp.o
avr-ar rcs /tmp/build2560460169561155056.tmp/core.a /tmp/build2560460169561155056.tmp/WMath.cpp.o
avr-ar rcs /tmp/build2560460169561155056.tmp/core.a /tmp/build2560460169561155056.tmp/HardwareSerial.cpp.o
avr-ar rcs /tmp/build2560460169561155056.tmp/core.a /tmp/build2560460169561155056.tmp/WString.cpp.o
avr-g++ -c -g -Os -w -fno-exceptions -ffunction-sections -fdata-sections -mmcu=atmega328p -DF_CPU=16000000L -DARDUINO=21 -I/home/udo/Desktop/electronics/arduino-0021/hardware/arduino/cores/arduino /tmp/build2560460169561155056.tmp/sketch_mar31a.cpp -o/tmp/build2560460169561155056.tmp/sketch_mar31a.cpp.o
avr-gcc -Os -Wl,--gc-sections -mmcu=atmega328p -o /tmp/build2560460169561155056.tmp/sketch_mar31a.cpp.elf /tmp/build2560460169561155056.tmp/sketch_mar31a.cpp.o /tmp/build2560460169561155056.tmp/core.a -L/tmp/build2560460169561155056.tmp -lm
avr-objcopy -O ihex -j .eeprom --set-section-flags=.eeprom=alloc,load --no-change-warnings --change-section-lma .eeprom=0 /tmp/build2560460169561155056.tmp/sketch_mar31a.cpp.elf /tmp/build2560460169561155056.tmp/sketch_mar31a.cpp.eep
avr-objcopy -O ihex -R .eeprom /tmp/build2560460169561155056.tmp/sketch_mar31a.cpp.elf /tmp/build2560460169561155056.tmp/sketch_mar31a.cpp.hex
Binary sketch size: 2436 bytes (of a 30720 byte maximum)


I still do not get it though. Any hints for me?
Check out my experiments http://blog.blinkenlight.net

Coding Badly


Is it possible you have more than one "avr-gcc" on the computer?  Is the Arduino IDE using one compiler version and the makefile using a different compiler version?

udoklein

Ah, good question. Never thought of that.
Double checked:
find, locate, whereis all agree that I have only one version.
--> this is not the reason for the strange behaviour.
Check out my experiments http://blog.blinkenlight.net

gardner


Any hints for me?


Have you built the project both ways and dumped the final elf with avr-objdump to get a feel for what the substance of the difference is?  There might be a clue there.

Have you in fact brought your avr-gcc installation up to date?

nickgammon

#19
Apr 01, 2011, 12:20 am Last Edit: Apr 01, 2011, 12:22 am by Nick Gammon Reason: 1

I still do not get it though. Any hints for me?


What is your ultimate goal here? To resolve this issue with the compiler? Or to count resets? Personally I had never heard of :

Code: [Select]
uint8_t reset_counter __attribute__ ((section (".noinit")));

... until I saw this thread.

You are basically wanting to take some RAM with undefined data in it, and add 1 to it on reset, yes? And if there is a way of detecting a power-on reset, as opposed to a "reset button" reset, you might conceivably initialize it on power-on.

Well, here is how to get unitialized RAM:

Code: [Select]
int * counter;

void setup() {

 Serial.begin (115200);
 
 // get some uninitialized RAM  
 counter = (int *) malloc (sizeof (int));  
 
 // add 1 to it
 *counter++;
 
 Serial.println (*counter);
 
}

void loop() { }


Now I'm assuming here that identical code running after a reset will allocate the same memory address each time (why would it not?). And since malloc doesn't clear memory to zero it won't be initialized. So far so good. But these are my results (hitting reset):

Code: [Select]
14649
14649
14649
14649
14649
14649


It's not zero, but it's not incrementing either. Why? My guess is that the part of the heap that is allocated in this case happens to have been used previously (as part of reset processing) and happens to have 14648 left over in it (hex 0x3938).

But if this doesn't work, how can you really say that using section (".noinit") will work any better? An uninitialized variable has undefined data in it, right? This isn't guaranteed to persist over resets.

Let me put it like this, as I read the docs on .noinit, they specify the the variable is not initialized to zero. But they don't specify that the variable is untouched (eg. during initializing of other things).

The very fact that the .noinit works for some people and not others would seem to give pause to any idea of using it seriously in any sort of production environment.

Please post technical questions on the forum, not by personal message. Thanks!

More info: http://www.gammon.com.au/electronics

nickgammon

Oops, I fell for the old operator-precedence trap. I can in fact get it to work:

Code: [Select]
int * counter;
void setup() {
  Serial.begin (115200);
 
  // get some uninitialized RAM 
  counter = (int *) malloc (sizeof (int)); 
 
  // add 1 to it
  (*counter)++;
 
  Serial.println (*counter);
}

void loop() { }


Output:

Code: [Select]
14651
14652
14653
14654
14655
14656


So that looks OK - you can add 1 after a reset. Still a bit dodgy, but it seems to work.
Please post technical questions on the forum, not by personal message. Thanks!

More info: http://www.gammon.com.au/electronics

udoklein

This thread is basically about satisfying my curiosity.
As I already mentioned this is not for "production use". I am aware of EEProm and how to access it.
I just wanted to understand what is going on. This was just an example for fooling around with the init section.

Your code will always return "1" on my Arduino. So obviously there is something that will initialize my memory. By now I suspect the bootloader to be part of the issue. However the compiler and/or linker play some role as well because I found code that will compile in the IDE but not from the commandline.

What I figure is that different Arduinos behave differently upon reset depending on unknown parameters like compiler, linker, bootloader and/or possibly other stuff.

It follows that for production use of "reset counters" eeprom or flash or external storage is the way to go. However it still leaves the question open where this different behaviour originates.
Check out my experiments http://blog.blinkenlight.net

Coding Badly

@Udo Klein:
Thank you!  This technique has turned out to be rather handy for troubleshooting a reset-bug.

udoklein

Yeah, fooling around leads sometimes to deeper insights. Playing with this I figured out that there are much more resets then I would have expected ;)

Which technique did you use? Memory based or EEProm based?
Check out my experiments http://blog.blinkenlight.net

Coding Badly

Quote
Playing with this I figured out that there are much more resets then I would have expected


That's not good!

Quote
Which technique did you use? Memory based or EEProm based?


The one from your original post (memory based; noinit section).

udoklein

Seems to work for everyone but me :(  So I stick to EEProm.
Check out my experiments http://blog.blinkenlight.net

Coding Badly

I cannot find any significant differences between your build and mine (Arduino 0022).  If you post a sample Sketch and an ELF file I'm willing to compare.

udoklein

Well, I am using Arduino 21. But my impression is that the cause is the bootloader. If I use an ISP and get rid of the bootloader it works as it should. If I can spend some time I will disassemble and analyze where exactly it wipes the memory.
Check out my experiments http://blog.blinkenlight.net

westfw

Quote
my impression is that the cause is the bootloader.

Which version of which bootloader?

Were you equating "building from the command line" with "not using the bootloader" ?

udoklein

#29
Apr 19, 2011, 09:13 pm Last Edit: Apr 27, 2011, 08:33 pm by Udo Klein Reason: 1
If I build from the commandline I usually use an ISP and overwrite the bootloader. Of course I might get different compiler settings as well. If I build from the IDE I usually do not use an ISP (although I could).

So if I use the IDE then the bootloader is in place otherwise not. If I use the command line the compiler might produce different code or maybe not. However since this stuff goes so early in the init section I think I have good reason to suspect the bootloader. Especially since I did not see any code for wiping the memory in the disassembled code. With regard to the bootloader: I used the default supplied with my version of Arduino 0021.

Anyway it does not really matter: I want to have repeatable results thus EEProm seems the only way to go.
Check out my experiments http://blog.blinkenlight.net

Go Up