Atmel Studio 7. SFIOR problem

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

Hello.
I installed the development environment Atmel Studio 7
I create a new GCC Executable Project for Atmega128. I tried to compile this code:

 

#include <avr/io.h>
#include <conf_clock.h>

int main(void)
{
    /* Replace with your application code */
    while (1) 
    {
        SFIOR |= 1;
    }
}

 

When compiling an error is "operand out of range: 32"
How can I configure SFIOR?

 

Thank you

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

Good grief I think you really have found a bug in the compiler! I wonder if this is because on most models of AVR there isn't an SFR at exactly address 0x20/0x40 that you might want to SBI?

 

The fact is that there should be code in the compiler that effectively says "if address < 0x40 and only one bit being set: use sbi" but I think it's actually using "if address <= 0x40 and only one bit being set: use sbi"

 

But what is your intention here anyway? My reading of the docs for SFIOR suggests it would be fairly unusual to want to set just one bit at a time - perhaps I have misunderstood? Why would you want to set just PSR321?

 

On most AVR it is UBRRH or EEDR that is positioned at 0x20/0x40 and they are registers you almost never SBI so I guess this is why this hasn't been seen more often.

 

(just off to try an old compiler to see if this has always been broken...)

 

EDIT: OK so not broken in 4.5.3 then - so perhaps this is a recently introduced bug. Wonder why someone at Atmel (if it was) messed with working code?

 

Anyone reading got access to Studio 6.2 and avr-gcc 4.8.1? Was it broken there? (drop the conf_clock.h include - that's got nothing to do with the issue here).

Last Edited: Fri. Oct 2, 2015 - 01:47 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Thank you, clawson.

I have to reset the timer prescaler for synchronization. For some events... I need to timer starts ticking when the prescaler "tics" is 0. I do this by setting PSR321. How can I use SBI in the GCC C project. Insert in assembly?

Before Atmel Studio 7 I used Atmel Studio 6.2 SP1. There's a project compilling without errors.

 

P.S.

Sorry for my English.

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

Took a look at this, and yes, it is a compiler bug :(

 

For a long time, the address range to verify was hard coded to 0x0, 0x1F (after  adjusting for SFR offset aka memory mapped general regs). As part of a rather big patch, Joern Rennecke changed the upper bound to 0x20 - GET_MODE_SIZE(mode). This should have had the same effect, as mode must be QI (8 bits) for bit addressable instructions. Unfortunately, for some reason, gcc sets mode to VOID (with size = 0), and that incorrectly extends the upper end of the range by a byte.

 

From the patch, it looks like it was done as part of io_low attribute support, which allows symbols (rather than just compile time constants) in the bit addressable instructions. In any case,  the range check is done only for compile time constants, and we know the lower IO address space will fit in a byte even after accounting for SFR offsets, so the (easy) fix would be to revert back to hardcoding the upper end of the range.

 

Don't know why gcc is always passing VOID as the mode though - debugging that is gonna be hairy :)

Regards

Senthil

 

blog | website

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

When waiting for a patch? :)

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

When waiting for a patch? :)

Don't hold your breath! I'd work around this for now. As I say the issue is occuring because it is attempting to use an SBI opcode on a location 1 byte beyond the end of the SBI range. You need to force it ont to use SBI. Now the compiler only uses SBI and CBI when there is just a single bit being changed in the target location so the easy workaround is to always ensure that more than one bit are changed. Now bits 4, 5 and 6 in the SFIOR register are unused. It should not matter if you try to change them as the effect should have no action in the AVR. So instead of writing something like:

 

 SFIOR |= (1 << PSR321);

where you only intend to change bit 0. Do something like:

 

 SFIOR |= (1 << PSR321) | (1 << 4);

The following is using the 4.9.2 compiler from Atmel and shows this will work:

~/windows/avr8-gnu-toolchain-linux_x86_64/bin$ cat avr.c
#include <avr/io.h>

int main(void)
{
    while (1) 
    {
	SFIOR |= (1 << PSR321) | (1 << 4);
    }
}

~/windows/avr8-gnu-toolchain-linux_x86_64/bin$ ./avr-gcc -mmcu=atmega128 -Os -gdwarf-2 avr.c -o avr.elf
~/windows/avr8-gnu-toolchain-linux_x86_64/bin$ ./avr-objdump -S avr.elf

avr.elf:     file format elf32-avr


Disassembly of section .text:

00000000 <__vectors>:
   0:	0c 94 46 00 	jmp	0x8c	; 0x8c <__ctors_end>
   4:	0c 94 50 00 	jmp	0xa0	; 0xa0 <__bad_interrupt>
   8:	0c 94 50 00 	jmp	0xa0	; 0xa0 <__bad_interrupt>
   c:	0c 94 50 00 	jmp	0xa0	; 0xa0 <__bad_interrupt>
  10:	0c 94 50 00 	jmp	0xa0	; 0xa0 <__bad_interrupt>
  14:	0c 94 50 00 	jmp	0xa0	; 0xa0 <__bad_interrupt>
  18:	0c 94 50 00 	jmp	0xa0	; 0xa0 <__bad_interrupt>
  1c:	0c 94 50 00 	jmp	0xa0	; 0xa0 <__bad_interrupt>
  20:	0c 94 50 00 	jmp	0xa0	; 0xa0 <__bad_interrupt>
  24:	0c 94 50 00 	jmp	0xa0	; 0xa0 <__bad_interrupt>
  28:	0c 94 50 00 	jmp	0xa0	; 0xa0 <__bad_interrupt>
  2c:	0c 94 50 00 	jmp	0xa0	; 0xa0 <__bad_interrupt>
  30:	0c 94 50 00 	jmp	0xa0	; 0xa0 <__bad_interrupt>
  34:	0c 94 50 00 	jmp	0xa0	; 0xa0 <__bad_interrupt>
  38:	0c 94 50 00 	jmp	0xa0	; 0xa0 <__bad_interrupt>
  3c:	0c 94 50 00 	jmp	0xa0	; 0xa0 <__bad_interrupt>
  40:	0c 94 50 00 	jmp	0xa0	; 0xa0 <__bad_interrupt>
  44:	0c 94 50 00 	jmp	0xa0	; 0xa0 <__bad_interrupt>
  48:	0c 94 50 00 	jmp	0xa0	; 0xa0 <__bad_interrupt>
  4c:	0c 94 50 00 	jmp	0xa0	; 0xa0 <__bad_interrupt>
  50:	0c 94 50 00 	jmp	0xa0	; 0xa0 <__bad_interrupt>
  54:	0c 94 50 00 	jmp	0xa0	; 0xa0 <__bad_interrupt>
  58:	0c 94 50 00 	jmp	0xa0	; 0xa0 <__bad_interrupt>
  5c:	0c 94 50 00 	jmp	0xa0	; 0xa0 <__bad_interrupt>
  60:	0c 94 50 00 	jmp	0xa0	; 0xa0 <__bad_interrupt>
  64:	0c 94 50 00 	jmp	0xa0	; 0xa0 <__bad_interrupt>
  68:	0c 94 50 00 	jmp	0xa0	; 0xa0 <__bad_interrupt>
  6c:	0c 94 50 00 	jmp	0xa0	; 0xa0 <__bad_interrupt>
  70:	0c 94 50 00 	jmp	0xa0	; 0xa0 <__bad_interrupt>
  74:	0c 94 50 00 	jmp	0xa0	; 0xa0 <__bad_interrupt>
  78:	0c 94 50 00 	jmp	0xa0	; 0xa0 <__bad_interrupt>
  7c:	0c 94 50 00 	jmp	0xa0	; 0xa0 <__bad_interrupt>
  80:	0c 94 50 00 	jmp	0xa0	; 0xa0 <__bad_interrupt>
  84:	0c 94 50 00 	jmp	0xa0	; 0xa0 <__bad_interrupt>
  88:	0c 94 50 00 	jmp	0xa0	; 0xa0 <__bad_interrupt>

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
  98:	0e 94 52 00 	call	0xa4	; 0xa4 <main>
  9c:	0c 94 56 00 	jmp	0xac	; 0xac <_exit>

000000a0 <__bad_interrupt>:
  a0:	0c 94 00 00 	jmp	0	; 0x0 <__vectors>

000000a4 <main>:

int main(void)
{
    while (1) 
    {
	SFIOR |= (1 << PSR321) | (1 << 4);
  a4:	80 b5       	in	r24, 0x20	; 32
  a6:	81 61       	ori	r24, 0x11	; 17
  a8:	80 bd       	out	0x20, r24	; 32
    }
  aa:	fc cf       	rjmp	.-8      	; 0xa4 <main>

000000ac <_exit>:
  ac:	f8 94       	cli

000000ae <__stop_program>:
  ae:	ff cf       	rjmp	.-2      	; 0xae <__stop_program>

Here you can see the compiler emits an IN/OR/OUT sequence using 0x11 as the mask (bits 4 and 0 set) which avoids it trying to use an SBI.

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

Submitted a patch to upstream gcc - https://gcc.gnu.org/ml/gcc-patch...

Regards

Senthil

 

blog | website

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

Good morning, clawson! Good morning, saaadhu!

Thanks a lot for the help!