Does WinAvr20071221 initialize zero register too late?

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

In the documentation (e.g. at http://www.nongnu.org/avr-libc/u... or http://www.nongnu.org/avr-libc/u...) I read
that the __zero_reg__ = r1 should always be 0, since the compiler or optimizer relies on this.

Also I read in the AVR Freaks Design Note #006 that after a power-on-reset or a watchdog/external reset the 32 general purpose registers are un-initialized or unchanged.
So, at start-up it is not assumed that r1 is 0.

Now to WinAVR/GCC:

On an ATmega128 16AU (DateCode 0705) I wondered, why at power-on-reset some port pins were sourcing much more current than assumed, but not after an external reset.
Than I found out that it is due to a "superfluous" command, which sets a Data-Direction-Register to inputs, fails, because the command, which initializes the zero-register
comes too late. (The port pins are connected to some switches => very low impedant, if closed!)
The initialization command is somethink like "eor r1, r1" or "eor __zero_reg__, __zero_reg__" or "clr r1" or "clr __zero_reg__".


	#ifndef outp
		#define outp(val,sfr) (sfr)=(val)
	#endif

	outp(0x00, DDRB);
	outp(0xF0, PORTB);

becomes to:

out	0x17, r1	; 23
ldi	r24, 0xF0	; 240
out	0x18, r24	; 24    
...
eor	r1, r1	

Question:
How can I avoid this behavior? Is this a bug? How can I force the compiler to do it at the beginning?
Should I do it manually? E.g. putting

__asm__ __volatile__ ("eor r1, r1"::)

at the beginning of main, bootloader, init-section to be safe?

Thank you for any hints.

Regards,
Michael

In the beginning was the Word, and the Word was with God, and the Word was God.

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

You should post a compileable source file, which show this behaviour and tell which WINAVR version you use.

I can only see, that the "eor r1,r1" was done as the second instruction after reset.

    00000000 <__vectors>:
    0: 0c 94 34 00 jmp 0x68 ; 0x68 <__ctors_end>

    ...

    00000068 <__ctors_end>:
    68: 11 24 eor r1, r1

Peter

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

skotti wrote:

On an ATmega128 16AU (DateCode 0705) I wondered, why at power-on-reset some port pins were sourcing much more current than assumed, but not after an external reset.

On my experience I found, that the power on reset works not reliable.
It works only, if voltage rises from near zero (<0.1V) and very fast and monotonic.

Thus I enable always the brown out reset to get a reliable working AVR.

Without this, power on reset may fail and the program counter starts anywhere in your code.

Peter

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

Thank you.

@Peter: Yes, I also have brown-out-reset enabled. Did not know that it can also be critical (so I will not disable this feature).

@danni:
For the main-part I found the problem:

void basic_initialization(void) __attribute__ ((naked)) __attribute__ ((section(".init1")) );  // Do not use stack here!

void basic_initialization(void) {
	DDRB =0x00;
	PORTB=0xF0;
} // end of basic_initialization

int main(void) {
	
	while (1) { // endless loop
		
		// tasks
		
	} // end of while (forever-loop)
	
} // end of main

compiles to

   0:	0c 94 46 00 	jmp	0x8c	; 0x8c 
   4:	0c 94 68 00 	jmp	0xd0	; 0xd0 <__bad_interrupt>
...
  88:	0c 94 68 00 	jmp	0xd0	; 0xd0 <__bad_interrupt>

0000008c :
  8c:	17 ba       	out	0x17, r1	; 23
  8e:	80 ef       	ldi	r24, 0xF0	; 240
  90:	88 bb       	out	0x18, r24	; 24
  92:	11 24       	eor	r1, r1
  94:	1f be       	out	0x3f, r1	; 63
  96:	cf ef       	ldi	r28, 0xFF	; 255
  98:	d0 e1       	ldi	r29, 0x10	; 16
  9a:	de bf       	out	0x3e, r29	; 62
  9c:	cd bf       	out	0x3d, r28	; 61

0000009e <__do_copy_data>:
...

Then I changed .init1 to .init2 in the attribute section.

This compiles to

0000008c <__ctors_end>:
  8c:	11 24       	eor	r1, r1
  8e:	1f be       	out	0x3f, r1	; 63
  90:	cf ef       	ldi	r28, 0xFF	; 255
  92:	d0 e1       	ldi	r29, 0x10	; 16
  94:	de bf       	out	0x3e, r29	; 62
  96:	cd bf       	out	0x3d, r28	; 61

00000098 :
  98:	17 ba       	out	0x17, r1	; 23
  9a:	80 ef       	ldi	r24, 0xF0	; 240
  9c:	88 bb       	out	0x18, r24	; 24

This is all right for me. Better I also change it to .init3, to be sure that first the initialization is done and then the user code...

So my basic initialization was a little bit too early...
Yeah, it is written in the manual:
http://www.nongnu.org/avr-libc/u...

But what can I do for the Bootloader section?
Is there another way than using assembler to initialize the zero register?
What is the most compatible way also with regard on future compiler development?

Michael

In the beginning was the Word, and the Word was with God, and the Word was God.

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

Whats the reason to do port initialization prior main?

E.g. if reset need about 65ms and initialization also 1ms more, whats the difference, if the port was set after 65ms instead 66ms after power on?

I think, to do code prior main was primarily suited for enabling external SRAM, so it can be used by the compiler (load defaults) or to increase watchdog time.

All other initialization things should be done inside the main.

Peter

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

Yes, Peter, exactly: I also use external SRAM and did the initialization in init1. I also added some other basic port initializations. So the better place for this is init3 for both (or as you said in main for the further port initializations).

Afterwards you are always smarter...
C-sections:

Quote:

Section .init3 is used in this example, as this ensures the inernal __zero_reg__ has already been set up. The code generated by the compiler might blindly rely on __zero_reg__ being really 0.

Maybe in the future I always will use set_bit / clear_bit commands for setting up Data Direction Registers, especially if the port is shared by different functions (switch inputs, LED outputs) and is initialized at different positions in the code.

In the beginning was the Word, and the Word was with God, and the Word was God.