Programming Arduino in Atmel Studio

As a fun way to improve my C, I started programming the Arduino using Atmel Studio instead of the friendlier Arduino IDE.

Below is my very first program. It blinks a red LED and a white LED according to a preset pattern.

#define F_CPU 16000000UL

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

struct Led
{
    int pin;
    int blinks;
    int on_duration;
    int off_duration;
};

void delay_ms(int ms)
{
    while (ms-- > 0) {
        _delay_ms(1);
    }
}

void blink(const struct Led* const led)
{
    for (int i = 0; i < led->blinks; i++) {
        PORTB |= led->pin;
        delay_ms(led->on_duration);
        PORTB &= ~led->pin;
        delay_ms(led->off_duration);
    }
}

int main(void)
{
    const struct Led white_led = { 1<<PB6, 10, 100, 500 };
    const struct Led red_led = { 1<<PB7, 10, 500, 1000 };

    DDRB |= white_led.pin;
    DDRB |= red_led.pin;
    while (1) {
        blink(&white_led);
        blink(&red_led);
    }
}

With C in Atmel Studio and the AVR-LIBC library, IO ports are manipulated by changing bit patterns in the registers associated with the relevant ports. This requires a good understanding of bitwise operations in C despite the availability of macros to simplify the task.

For example, to set pin 12 of the Arduino to output mode, bit 6 of register DDRB must be set to 1. To do so requires an | (OR) operation with a bit pattern operand where bit 6 is set to 1 and the rest set to 0, so that the states of the other bits in the register are not disturbed.

Using macros DDRB and PB6 defined in AVR-LIBC, this is done like this: DDRB |= 1 << PB6 .

If you are new to C and are unfamiliar with macros, you might wonder about that statement. Besides, DDRB and PB6 are not referenced anywhere else in my program, so how does this line of code work?

DDRB is a macro that expands into C code to dereference the address of the register associated with setting the mode for pin 12, and PB6 is just a symbolic constant for the value 6. In the statement above, by shifting the value 1 left by 6 positions, we create a new value which is then applied to the bit pattern stored at the dereferenced address with an | operation to turn bit 6 of the register to 1. In this case, this sets pin 12 to output mode.

In a nutshell, the sequence of operations is as follows.

Step 1:

1 << 6 = 01000000

Step 2:

Assuming the register DDRB is initially 00000001:

00000001 | 01000000 = 01000001

In my C program, the result of step 1 is assigned to struct field Led.pin and is used as the second operand for the operation in step 2.

It took about an hour to refresh my knowledge of bitwise operations, but the real challenge was interpreting the Arduino schema and the information in datasheets, especially to find the right registers to manipulate.

Leave a comment

Leave a Reply

This site uses Akismet to reduce spam. Learn how your comment data is processed.