/home/lucio.albenga.es

Setting Up a GCC Toolchain For Programming Arduino In Plain C

I'm not an Arduino power user but when I decided to start with it I knew I wanted to program it in plain C and I knew I would buy a compatible board instead of the real thing just to take the feel of it. Probably because I'm a programmer, I found much more interesting to go down the rabbit hole of low-level details, datasheets1, etc., instead of letting the Arduino IDE and libs to hide things from me. I also didn't find of any use to learn a pseudo C++ when I already knew C.

During these past weeks, since Qualcomm acquired Arduino, there was a lot of talking about if they will enshittify Arduino, etc. Right now it seems I was right from the start about doing things in pure C and not using Arduino's software because right now it doesn't affect me at all whatever Qualcomm does.

In this howto I will explain to you how to set up a GCC based toolchain so that you can also program your Arduino in C, or if you prefer it in C++, and I will show you all the steps from typing a program all the way to loading it on your board without using Arduino's official software.

The first thing you should do is to install the required sofware and it's quite likely that your POSIX compatible OS already have packages for it. In this howto we will see how to do it on FreeBSD and Devuan GNU + Linux.

pkg install avr-gcc avr-binutils avr-libc avrdude      # FreeBSD
sudo apt install gcc-avr binutils-avr avr-libc avrdude # Devuan

Once the programs are installed, open your preferred editor and type the program below. This program is the typical one that blinks the light of your Arduino, and you'll use it for testing the toolchain and see how everything fits together. For the purposes of this howto this file is called blink.c.

#include <avr/io.h>

#define F_CPU 16000000UL /* required by <util/delay.h> */
#include <util/delay.h>

#define DELAY 1500 /* milliseconds */

int
main (void) {
        DDRB |= _BV(DDB5);
        for(;;) {
                PORTB |= _BV(PORTB5);
                _delay_ms(DELAY);
                PORTB &= ~_BV(PORTB5);
                _delay_ms(DELAY);
        }
}

The F_CPU constant should reflect the CPU frequency (the clock speed) of your Arduino model. I have an Arduino UNO compatible board and in my case this value is 16MHz.

Now it's time to compile the program. Type the following command on your terminal:

avr-gcc -Os -mmcu=atmega328p -o blink blink.c

Once you have the compiled binary file blink you should convert it to a valid Arduino *.hex binary:

avr-objcopy -O ihex -R .eeprom blink blink.hex

Now it's time to connect your Arduino to one of the USB ports of your computer. Check out the port it's connected. You can use the command dmesg to do this. On Devuan the output of dmesg, once connected my Arduino compatible board, looks like the following:

[3975174.307519] usb 2-1: new full-speed USB device number 79 using xhci_hcd
[3975174.456593] usb 2-1: New USB device found, idVendor=1a86, idProduct=7523, bcdDevice= 2.63
[3975174.456606] usb 2-1: New USB device strings: Mfr=0, Product=2, SerialNumber=0
[3975174.456612] usb 2-1: Product: USB2.0-Serial
[3975174.458699] ch341 2-1:1.0: ch341-uart converter detected
[3975174.459258] usb 2-1: ch341-uart converter now attached to ttyUSB0

This means that, in my case, it is connected to /dev/ttyUSB0 (/dev/ttyU0 on my FreeBSD). To load the program into your Arduino type the following command (replace /dev/ttyU0 or /dev/ttyUSB0 with your device):

avrdude -F -V -c arduino -p m328p -P /dev/ttyU0 -U flash:w:blink.hex    # FreeBSD
avrdude -F -V -c arduino -p m328p -P /dev/ttyUSB0 -U flash:w:blink.hex  # Devuan

The output will be something like the following:

avrdude: AVR device initialized and ready to accept instructions
avrdude: device signature = 0x1e950f (probably m328p)
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 blink.hex for flash
         with 176 bytes in 1 section within [0, 0xaf]
         using 2 pages and 80 pad bytes
avrdude: writing 176 bytes flash ...

Writing | ################################################## | 100% 0.06 s 

avrdude: 176 bytes of flash written

As I said before, the program blinks the Arduino light so you can take a look at your Arduino and if its light is blinking it means everything worked fine. Congratulations! You already have a working toolchain and you know the basics to create and load your programs on your Arduino board.

I hope you find this howto useful and that it helps you to start programming your Arduino board with C. This is only a starting point and I recommend you to read the help and/or docs of all these programs, that's where the magic happens.