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.

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:

Step 2:

Assuming the register DDRB is initially 00000001:

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.

 

 

Undefined behaviours in C

In C programming, undefined behaviours (UB) present perhaps one of the biggest challenges to beginners. As an occasional practitioner, I am still baffled by them–which happened recently with the code that I wrote in an Arduino sketch.

The function get_input() is generic. Besides parameter String prompt, it takes two generic function pointer parameters (*parse_func)(void* const) and (*validate_func)(const void* const) to read user input and validate user input, respectively. They are generic because they have parameters of type void (albeit with different constraints, to which we will come back).

Below is the function parse_int() passed in place of the parameter (*parse_func)(void* const).

There are two things to note here. First, the function signature matches exactly the function pointer declaration: it takes a parameter of type void* const–or, const pointer to void–and does not return any result. Second, it casts the parameter to the desired type before dereferencing the memory location where the input value is written.

And below, the function validate_positive_int() passed in place of the parameter (*validate_func)(const void* const).

Again, this matches exactly the function pointer declaration. It takes a parameter of type const void* const–or, const pointer to const void–and returns a result of type int. Also, the parameter is cast to the desired type–in this case, const pointer to const int–before the logical operation.

In the course of debugging the sketch, I inadvertently modified this last function as follows.

At some point, I realised my mistake and began to wonder why it had not triggered a compilation error and why my code was running normally with the value 1234 as user input. After all, my intention was to have a const pointer to const int; that is, I did not want the argument being passed to be modifiable.

I joined ##c (IRC) to seek answers.

The answer was, an undefined behaviour arises when a const object is modified through a non-const pointer.

It took me some time to understand–or rather, accept–this. As a programmer of “safer” languages, I found it difficult to take this explanation at face value and so embarked on further exploration with the goal of getting the compiler to throw the error that my mistake deserved.

Eventually, I found that if I cast the argument to exactly what was declared in the function signature, like below, the error would be thrown.

Success in displaying the compilation error helped me understand this undefined behaviour: the constraints in the function declaration, just like much of C, are merely promises that the function will interpret arguments in a certain way, but they do not offer any guarantee that it will fulfil its promises.

Undefined behaviours are still stumbling blocks to those who are not expert C programmers, but understanding–and accepting–that they are part of the language makes coding in C much  easier. I– for one–am going to embrace undefined behaviours from now on.