Answers to more questions and notes on common problems.

AMA-1 will no longer be updated. New FAQs will be added here.

1. Error using ASM with C in avr-gcc

Consider the following assembly file asm.S

#include <avr/io.h>
.section text
.global blip
blip:
	sbi PORTB, PB5
	cbi PORTB, PB5
	ret

Compiling with the following command, yields the error message:

$ avr-gcc -c -mmcu=attiny85 -g -x assembler-with-cpp asm.S
asm.S: Assembler messages:
asm.S:5: Error: operand out of range: 56
asm.S:6: Error: operand out of range: 56

The 'tiny85 datasheet says that PORTB is I/O address 0x18, or 24 in base10. Where does this "56" come from???

The answer relates to

  • how memory is arranged on the AVR architecture and the ATtiny85

  • how GCC deals with memory addresses

From the ATtiny85 Datasheet:

attiny85 fig5 2

The "32 Registers" in the figure are the 32 CPU registers (r0 ... r31) and you just name them to use them instead of using a memory address.

The PORTB register resides in the I/O Registers section. This is physically wired to the DFF registers for the peripheral’s digital hardware, but the address of each (physically in the digital multiplexer on the chip) are all in the same address space as everything else. Except for program code (flash), which is in its own separate address space. (there are two address 0x60: one is flash location 0x60 and the other is the first byte of SRAM)

Notice the 0x20 next to "64 I/O Registers"?

The assembler knows all about the I/O registers and which assembly instructions use addresses in that physical segment. Want to use PORTB to set a PB0's output value? Then just issue the assembly instruction:

	sbi PORTB, PB0

This works fine for avr_sim, but NOT the GCC version.

The assembly version looks like:

.equ PORTB 0x18
.equ PB0 = 0

	sbi PORTB, PB0

; which is substituted to yield:
	sbi 0x18, 0
// inside <avr/io.h>
//    --> specifically <avr/sfr_defs.h>
#define __SFR_OFFSET 0x20
#define _SFR_IO8(io_addr) ((io_addr) + __SFR_OFFSET)
#define PORTB  _SFR_IO(0x18)
#define PB0  0

	sbi PORTB, PB0

// which gets substituted to:
	sbi ((0x18) + 0x20), 0     ; 0x38 is 56 in base10

See the "56" !

The real reason that the compiler complains is because the sbi instruction can only operate on the first 32 I/O Registers and this instruction is asking to operate on I/O register 0x38 or 56. That is out of range of the instruction, so the compiler (assembler actually) issues an "appropriate" error.

The C compiler does this offset calculation because GCC was originally made to compile code for Von Neumann architectures which have all memory (code and data) in the same address space.

The AVR architecture is a Harvard architecture, where instruction code and data are in separate address spaces. As a result, AVR-GCC needs to work around GCC’s history. avr-libc: Data in Program Space documentation mentions this and hints at how they do the workaround.

1.1. Solution

The C macro _SFR_IO8() is where the problem of adding the 0x20 I/O Registers address offset happens. Fortunately, the headers provide another macro that does the opposite:

// also defined in <avr/sfr_defs.h>
// which is included by <avr/io.h>
#define _SFR_IO_ADDR(sfr) ((sfr) - __SFR_OFFSET)

	sbi _SFR_IO_ADDR(PORTB), PB0

// yields the following after macro substitutions
	sbi ((((0x18) + 0x20)) - 0x20), 0

// or simplified to:
	sbi 0x18, 0     ; exactly what you want
  • When using GCC and assembly, you must convert the I/O Register name symbols to their correct address by wrapping every peripheral register address in the _SFR_IO_ADDR(regname) macro.

2. Make(file) info

If you want to generate a file called foo.bar, which needs spam.txt for an input, then run these commands.

Rules define what command(s) to run to update a target file when the timestamp of a dependency is newer than the output (target) file.

That’s the gist of what make does.

target.x : dependencyA.y dependencyB.z
	program_name -opt=7 dependencyA.y -o target.x

day15 has the most links and a small tutorial.

Lab 3 also includes some representative examples of Makefile content.