Programming Arduino Uno in pure C

Posted on 2011/03/29

69


Playing with Arduino board and its graphical development environment I felt the urge to work closer to the hardware, stepping away from the default library and the Java IDE and using the compiler directly from the command line. Fortunately all the tools are there, because the Arduino IDE uses them under the hood. So I tried to use the avr-gcc compiler and the avrdude uploading tool, directly with pure C code.

To make it simple I implemented the classic blink program that toggles the output pin connected to the on-board LED. The Arduino Uno schematics indicate that the LED is connected to the PB5 pin of the Atmega328p chip, so that’s the pin I need to control. The AVR compiler is complemented with a C library: avr-libc, which contains useful functions and headers to develop for AVR chips without using assembly language. Inside the avr-libc manual and the Atmega328p datasheet there are many examples on how to toggle IOs, and with them I prepared the following code:

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

enum {
 BLINK_DELAY_MS = 1000,
};

int main (void)
{
 /* set pin 5 of PORTB for output*/
 DDRB |= _BV(DDB5);

 while(1) {
  /* set pin 5 high to turn led on */
  PORTB |= _BV(PORTB5);
  _delay_ms(BLINK_DELAY_MS);

  /* set pin 5 low to turn led off */
  PORTB &= ~_BV(PORTB5);
  _delay_ms(BLINK_DELAY_MS);
 }

 return 0;
}

The Port “B” of the microcontroller can be changed bit by bit with special instructions called “sbi” and “cbi“, and the compiler recognizes those kind of accesses generating optimized assembly in case of bit-wise operations. The ports definitions and useful macros (like “_BV“)can be found in the “/usr/lib/avr/include/avr/iom328p.h” and “/usr/lib/avr/include/avr/sfr_defs.h” headers.

In order to compile a program and upload it to the Arduino Uno, I need to create an IHEX file and use the avrdude tool to load it inside the Flash. Most of the parameters and options of the avr-gcc and the avrdude tools for the Uno board can be found in the “hardware/arduino/boards.txt” file from inside the Arduino IDE installation directory, and some other information is present in the avrdude manual. The commands that I used to compile and upload the “led.c” code above are:

$ avr-gcc -Os -DF_CPU=16000000UL -mmcu=atmega328p -c -o led.o led.c
$ avr-gcc -mmcu=atmega328p led.o -o led
$ avr-objcopy -O ihex -R .eeprom led led.hex
$ avrdude -F -V -c arduino -p ATMEGA328P -P /dev/ttyACM0 -b 115200 -U flash:w:led.hex

avrdude: AVR device initialized and ready to accept instructions

Reading | ################################################## | 100% 0.00s

avrdude: Device signature = 0x1e950f
avrdude: NOTE: FLASH memory has been specified, an erase cycle will be performed
 To disable this feature, specify the -D option.
avrdude: erasing chip
avrdude: reading input file "led.hex"
avrdude: input file led.hex auto detected as Intel Hex
avrdude: writing flash (88 bytes):

Writing | ################################################## | 100% 0.02s

avrdude: 88 bytes of flash written

avrdude: safemode: Fuses OK

avrdude done.  Thank you.

The code is uploaded and the led starts blinking. Well that was easy, mostly due to the fact that the tools have good support for the Arduino.

It is also possible to do a backup of the Atmega328p Flash content by using this command:

$ avrdude -F -V -c arduino -p ATMEGA328P -P /dev/ttyACM0 -b 115200 -U flash:r:flash_backup.hex:i

See also:

About these ads
Posted in: Embedded