Frequently Asked Questions

FAQ Index

  1. My program doesn't recognize a variable updated within an interrupt routine
  2. I get "undefined reference to..." for functions like "sin()"
  3. How to permanently bind a variable to a register?
  4. How to modify MCUCR or WDTCR early?
  5. What is all this _BV() stuff about?
  6. Can I use C++ on the AVR?
  7. Shouldn't I initialize all my variables?
  8. Why do some 16-bit timer registers sometimes get trashed?
  9. How do I use a #define'd constant in an asm statement?
  10. Why does the PC randomly jump around when single-stepping through my program in avr-gdb?
  11. How do I trace an assembler file in avr-gdb?
  12. How do I pass an IO port as a parameter to a function?
  13. What registers are used by the C compiler?

My program doesn't recognize a variable updated within an interrupt routine

When using the optimizer, in a loop like the following one:

uint8_t flag;
...

        while (flag == 0) {
                ...
        }

the compiler will typically optimize the access to flag completely away, since its code path analysis shows that nothing inside the loop could change the value of flag anyway. To tell the compiler that this variable could be changed outside the scope of its code path analysis (e. g. from within an interrupt routine), the variable needs to be declared like:

volatile uint8_t flag;

Back to FAQ Index.

I get "undefined reference to..." for functions like "sin()"

In order to access the mathematical functions that are declared in <math.h>, the linker needs to be told to also link the mathematical library, libm.a.

Typically, system libraries like libm.a are given to the final C compiler command line that performs the linking step by adding a flag -lm at the end. (That is, the initial lib and the filename suffix from the library are written immediately after a -l flag. So for a libfoo.a library, -lfoo needs to be provided.) This will make the linker search the library in a path known to the system.

An alternative would be to specify the full path to the libm.a file at the same place on the command line, i. e. after all the object files (*.o). However, since this requires knowledge of where the build system will exactly find those library files, this is deprecated for system libraries.

Back to FAQ Index.

How to permanently bind a variable to a register?

This can be done with

register unsigned char counter asm("r3");

See C Names Used in Assembler Code for more details.

Back to FAQ Index.

How to modify MCUCR or WDTCR early?

The method of early initialization (MCUCR, WDTCR or anything else) is different (and more flexible) in the current version. Basically, write a small assembler file which looks like this:

;; begin xram.S

#include <avr/io.h>

        .section .init1,"ax",@progbits

        ldi r16,_BV(SRE) | _BV(SRW)
        out _SFR_IO_ADDR(MCUCR),r16

;; end xram.S

Assemble it, link the resulting xram.o with other files in your program, and this piece of code will be inserted in initialization code, which is run right after reset. See the linker script for comments about the new .initN sections (which one to use, etc.).

The advantage of this method is that you can insert any initialization code you want (just remember that this is very early startup -- no stack and no __zero_reg__ yet), and no program memory space is wasted if this feature is not used.

There should be no need to modify linker scripts anymore, except for some very special cases. It is best to leave __stack at its default value (end of internal SRAM -- faster, and required on some devices like ATmega161 because of errata), and add -Wl,-Tdata,0x801100 to start the data section above the stack.

For more information on using sections, including how to use them from C code, see Memory Sections.

Back to FAQ Index.

What is all this _BV() stuff about?

When performing low-level output work, which is a very central point in microcontroller programming, it is quite common that a particular bit needs to be set or cleared in some IO register. While the device documentation provides mnemonic names for the various bits in the IO registers, and the AVR device-specific IO definitions reflect these names in definitions for numerical constants, a way is needed to convert a bit number (usually within a byte register) into a byte value that can be assigned directly to the register. However, sometimes the direct bit numbers are needed as well (e. g. in an sbi() call), so the definitions cannot usefully be made as byte values in the first place.

So in order to access a particular bit number as a byte value, use the _BV() macro. Of course, the implementation of this macro is just the usual bit shift (which is done by the compiler anyway, thus doesn't impose any run-time penalty), so the following applies:

_BV(3) => 1 << 3 => 0x08

However, using the macro often makes the program better readable.

"BV" stands for "bit value", in case someone might ask you. :-)

Example: clock timer 2 with full IO clock (CS2x = 0b001), toggle OC2 output on compare match (COM2x = 0b01), and clear timer on compare match (CTC2 = 1). Make OC2 (PD7) an output.

        TCCR2 = _BV(COM20)|_BV(CTC2)|_BV(CS20);
        DDRD = _BV(PD7);

Back to FAQ Index.

Can I use C++ on the AVR?

Basically yes, C++ is supported (assuming your compiler has been configured and compiled to support it, of course). Source files ending in .cc, .cpp or .C will automatically cause the compiler frontend to invoke the C++ compiler. Alternatively, the C++ compiler could be explicitly called by the name avr-c++.

However, there's currently no support for libstdc++, the standard support library needed for a complete C++ implementation. This imposes a number of restrictions on the C++ programs that can be compiled. Among them are:

Constructors and destructors are supported though, including global ones.

When programming C++ in space- and runtime-sensitive environments like microcontrollers, extra care should be taken to avoid unwanted side effects of the C++ calling conventions like implied copy constructors that could be called upon function invocation etc. These things could easily add up into a considerable amount of time and program memory wasted. Thus, casual inspection of the generated assembler code (using the -S compiler option) seems to be warranted.

Back to FAQ Index.

Shouldn't I initialize all my variables?

Global and static variables are guaranteed to be initialized to 0 by the C standard. avr-gcc does this by placing the appropriate code into section .init4 (see The .initN Sections). With respect to the standard, this sentence is somewhat simplified (because the standard allows for machines where the actual bit pattern used differs from all bits being 0), but for the AVR target, in general, all integer-type variables are set to 0, all pointers to a NULL pointer, and all floating-point variables to 0.0.

As long as these variables are not initialized (i. e. they don't have an equal sign and an initialization expression to the right within the definition of the variable), they go into the .bss section of the file. This section simply records the size of the variable, but otherwise doesn't consume space, neither within the object file nor within flash memory. (Of course, being a variable, it will consume space in the target's SRAM.)

In contrast, global and static variables that have an initializer go into the .data section of the file. This will cause them to consume space in the object file (in order to record the initializing value), and in the flash ROM of the target device. The latter is needed since the flash ROM is the only way that the compiler can tell the target device the value this variable is going to be initialized to.

Now if some programmer "wants to make doubly sure" their variables really get a 0 at program startup, and adds an initializer just containing 0 on the right-hand side, they waste space. While this waste of space applies to virtually any platform C is implemented on, it's usually not noticeable on larger machines like PCs, while the waste of flash ROM storage can be very painful on a small microcontroller like the AVR.

So in general, variables should only be explicitly initialized if the initial value is non-zero.

Back to FAQ Index.

Why do some 16-bit timer registers sometimes get trashed?

Some of the timer-related 16-bit IO registers use a temporary register (called TEMP in the Atmel datasheet) to guarantee an atomic access to the register despite the fact that two separate 8-bit IO transfers are required to actually move the data. Typically, this includes access to the current timer/counter value register (TCNTn), the input capture register (ICRn), and write access to the output compare registers (OCRnM). Refer to the actual datasheet for each device's set of registers that involves the TEMP register.

When accessing one of the registers that use TEMP from the main application, and possibly any other one from within an interrupt routine, care must be taken that no access from within an interrupt context could clobber the TEMP register data of an in-progress transaction that has just started elsewhere.

To protect interrupt routines against other interrupt routines, it's usually best to use the SIGNAL() macro when declaring the interrupt function, and to ensure that interrupts are still disabled when accessing those 16-bit timer registers.

Within the main program, access to those registers could be encapsulated in calls to the cli() and sei() macros. If the status of the global interrupt flag before accessing one of those registers is uncertain, something like the following example code can be used.

uint16_t
read_timer1(void)
{
        uint8_t sreg;
        uint16_t val;

        sreg = SREG;
        cli();
        val = TCNT1;
        SREG = sreg;

        return val;
}

Back to FAQ Index.

How do I use a #define'd constant in an asm statement?

So you tried this:

asm volatile("sbi 0x18,0x07;");

Which works. When you do the same thing but replace the address of the port by its macro name, like this:

asm volatile("sbi PORTB,0x07;");

you get a compilation error: "Error: constant value required".

PORTB is a precompiler definition included in the processor specific file included in avr/io.h. As you may know, the precompiler will not touch strings and PORTB, instead of 0x18, gets passed to the assembler. One way to avoid this problem is:

asm volatile("sbi %0, 0x07" : "I" (PORTB):);

Note:
avr/io.h already provides a sbi() macro definition, which can be used in C programs.
Back to FAQ Index.

Why does the PC randomly jump around when single-stepping through my program in avr-gdb?

When compiling a program with both optimization (-O) and debug information (-g) which is fortunately possible in avr-gcc, the code watched in the debugger is optimized code. While it is not guaranteed, very often this code runs with the exact same optimizations as it would run without the -g switch.

This can have unwanted side effects. Since the compiler is free to reorder code execution as long as the semantics do not change, code is often rearranged in order to make it possible to use a single branch instruction for conditional operations. Branch instructions can only cover a short range for the target PC (-63 through +64 words from the current PC). If a branch instruction cannot be used directly, the compiler needs to work around it by combining a skip instruction together with a relative jump (rjmp) instruction, which will need one additional word of ROM.

Another side effect of optimzation is that variable usage is restricted to the area of code where it is actually used. So if a variable was placed in a register at the beginning of some function, this same register can be re-used later on if the compiler notices that the first variable is no longer used inside that function, even though the variable is still in lexical scope. When trying to examine the variable in avr-gdb, the displayed result will then look garbled.

So in order to avoid these side effects, optimization can be turned off while debugging. However, some of these optimizations might also have the side effect of uncovering bugs that would otherwise not be obvious, so it must be noted that turning off optimization can easily change the bug pattern. In most cases, you are better off leaving optimizations enabled while debugging.

Back to FAQ Index.

How do I trace an assembler file in avr-gdb?

When using the -g compiler option, avr-gcc only generates line number and other debug information for C (and C++) files that pass the compiler. Functions that don't have line number information will be completely skipped by a single step command in gdb. This includes functions linked from a standard library, but by default also functions defined in an assembler source file, since the -g compiler switch does not apply to the assembler.

So in order to debug an assembler input file (possibly one that has to be passed through the C preprocessor), it's the assembler that needs to be told to include line-number information into the output file. (Other debug information like data types and variable allocation cannot be generated, since unlike a compiler, the assembler basically doesn't know about this.) This is done using the (GNU) assembler option --gstabs.

Example:

  $ avr-as -mmcu=atmega128 --gstabs -o foo.o foo.s

When the assembler is not called directly but through the C compiler frontend (either implicitly by passing a source file ending in .S, or explicitly using -x assembler-with-cpp), the compiler frontend needs to be told to pass the --gstabs option down to the assembler. This is done using -Wa,--gstabs. Please take care to only pass this option when compiling an assembler input file. Otherwise, the assembler code that results from the C compilation stage will also get line number information, which confuses the debugger.

Note:
You can also use -Wa,-gstabs since the compiler will add the extra '-' for you.
Example:

  $ EXTRA_OPTS="-Wall -mmcu=atmega128 -x assembler-with-cpp"
  $ avr-gcc -Wa,--gstabs ${EXTRA_OPTS} -c -o foo.o foo.S

Also note that the debugger might get confused when entering a piece of code that has a non-local label before, since it then takes this label as the name of a new function that appears to have been entered. Thus, the best practice to avoid this confusion is to only use non-local labels when declaring a new function, and restrict anything else to local labels. Local labels consist just of a number only. References to these labels consist of the number, followed by the letter b for a backward reference, or f for a forward reference. These local labels may be re-used within the source file, references will pick the closest label with the same number and given direction.

Example:

myfunc: push    r16
        push    r17
        push    r18
        push    YL
        push    YH
        ...
        eor     r16, r16        ; start loop
        ldi     YL, lo8(sometable)
        ldi     YH, hi8(sometable)
        rjmp    2f              ; jump to loop test at end
1:      ld      r17, Y+         ; loop continues here
        ...
        breq    1f              ; return from myfunc prematurely
        ...
        inc     r16
2:      cmp     r16, r18
        brlo    1b              ; jump back to top of loop

1:      pop     YH
        pop     YL
        pop     r18
        pop     r17
        pop     r16
        ret

Back to FAQ Index.

How do I pass an IO port as a parameter to a function?

Consider this example code:

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

void
set_bits_func_wrong (volatile uint8_t port, uint8_t mask)
{
    port |= mask;
}

void
set_bits_func_correct (volatile uint8_t *port, uint8_t mask)
{
    *port |= mask;
}

#define set_bits_macro(port,mask) ((port) |= (mask))

int main (void)
{
    set_bits_func_wrong (PORTB, 0xaa);
    set_bits_func_correct (&PORTB, 0x55);
    set_bits_macro (PORTB, 0xf0);

    return (0);
}

The first function will generate object code which is not even close to what is intended. The major problem arises when the function is called. When the compiler sees this call, it will actually pass the value in the the PORTB register (using an IN instruction), instead of passing the address of PORTB (e.g. memory mapped io addr of 0x38, io port 0x18 for the mega128). This is seen clearly when looking at the disassembly of the call:

    set_bits_func_wrong (PORTB, 0xaa);
 10a:   6a ea           ldi     r22, 0xAA       ; 170
 10c:   88 b3           in      r24, 0x18       ; 24
 10e:   0e 94 65 00     call    0xca

So, the function, once called, only sees the value of the port register and knows nothing about which port it came from. At this point, whatever object code is generated for the function by the compiler is irrelevant. The interested reader can examine the full disassembly to see the the function's body is completely fubar.

The second function shows how to pass (by reference) the memory mapped address of the io port to the function so that you can read and write to it in the function. Here's the object code generated for the function call:

    set_bits_func_correct (&PORTB, 0x55);
 112:   65 e5           ldi     r22, 0x55       ; 85
 114:   88 e3           ldi     r24, 0x38       ; 56
 116:   90 e0           ldi     r25, 0x00       ; 0
 118:   0e 94 7c 00     call    0xf8

You can clearly see that 0x0038 is correctly passed for the address of the io port. Looking at the disassembled object code for the body of the function, we can see that the function is indeed performing the operation we intended:

void
set_bits_func_correct (volatile uint8_t *port, uint8_t mask)
{
  f8:   fc 01           movw    r30, r24
    *port |= mask;
  fa:   80 81           ld      r24, Z
  fc:   86 2b           or      r24, r22
  fe:   80 83           st      Z, r24
}
 100:   08 95           ret 

Notice that we are accessing the io port via the LD and ST instructions.

The port parameter must be volatile to avoid a compiler warning.

Note:
Because of the nature of the IN and OUT assembly instructions, they can not be used inside the function when passing the port in this way. Readers interested in the details should consult the Instruction Set data sheet.
Finally we come to the macro version of the operation. In this contrived example, the macro is the most efficient method with respect to both execution speed and code size:

    set_bits_macro (PORTB, 0xf0);
 11c:   88 b3           in      r24, 0x18       ; 24
 11e:   80 6f           ori     r24, 0xF0       ; 240
 120:   88 bb           out     0x18, r24       ; 24

Of course, in a real application, you might be doing a lot more in your function which uses a passed by reference io port address and thus the use of a function over a macro could save you some code space, but still at a cost of execution speed.

Back to FAQ Index.

What registers are used by the C compiler?

Warning:
There was no such alignment before 2000-07-01, including the old patches for gcc-2.95.2. Check your old assembler subroutines, and adjust them accordingly.
Back to FAQ Index.


Automatically generated by Doxygen 1.2.18 on 12 Nov 2002.