Posts for: #Avr

In which I PEBKAC so you don’t have to

Say you have a simple bit of code:

#include <avr/io.h>
#include <util/delay.h> 

#define LED_BUILTIN _BV(PORTB5)

int main(void) 
{
    DDRB |= LED_BUILTIN;

    while (1)
    {
        PORTB |= LED_BUILTIN;   // turn on led
        _delay_ms(1000);        // delay 1s

        PORTB &= ~LED_BUILTIN;  // turn off led
        _delay_ms(1000);        // delay 1s
    }                                                
}

You have a Makefile that compiles that into an object (.o) file like this:

avr-gcc -mmcu=atmega328p -DF_CPU=16000000 -Os -c blink.c

If you were to forget to set the device type when compiling your .c file into an object file (.o), you would get a warning:

[read more]

ATOMIC_BLOCK magic in avr-libc

The AVR C library, avr-libc, provide an ATOMIC_BLOCK macro that you can use to wrap critical sections of your code to ensure that interrupts are disabled while the code executes. At high level, the ATOMIC_BLOCK macro (when called using ATOMIC_FORCEON) does something like this:

cli();

...your code here...

seti();

But it’s more than that. If you read the documentation for the macro, it says:

Creates a block of code that is guaranteed to be executed atomically. Upon entering the block the Global Interrupt Status flag in SREG is disabled, and re-enabled upon exiting the block from any exit path.

[read more]

AVR micro-optimization: Avr-gcc and –short-enums

How big is an enum?

I noticed something odd while browsing through the assembly output of some AVR C code I wrote recently. In the code, I have the following expression:

int main() {
    setup();

    while (state != STATE_QUIT) {
        loop();
    }
}

Here, state is a variable of type enum STATE, which looks something like this (not exactly like this; there are actually 19 possible values but I didn’t want to clutter this post with unnecessary code listings):

[read more]

AVR micro-optimization: Losing malloc

Pssst! Hey…hey, buddy, wanna get an extra KB for cheap?

When I write OO-style code in C, I usually start with something like the following, in which I use malloc() to allocate memory for a variable of a particular type, perform some initialization actions, and then return it to the caller:

Button *button_new(uint8_t pin, uint8_t poll_freq) {
    Button *button = (Button *)malloc(sizeof(Button));
    // do some initialization stuff

    return button;
}

And when initially writing pipower, that’s exactly what I did. But while thinking about it after the fact, I realized the following:

[read more]

Debugging attiny85 code, part 2: Automating GDB with scripts

This is the second of three posts about using gdb and simavr to debug AVR code. The complete series is:

[read more]

Debugging attiny85 code, part 3: Tracing with simavr

This is the third of three posts about using gdb and simavr to debug AVR code. The complete series is:

[read more]