Getting started with Arduino and Slackware

Bender

February 19, 2011

Abstract

The object was to try an Arduino board and setup an Arduino development environment on a Slackware Linux 13.1 host. This was accomplished very quickly, much faster than any other embedded environment the author has tried.
The latest version of this document can be found in pdf at
http://home.comcast.net/~bender647/arduino/arduino_slackware.pdf
or in web form at
http://home.comcast.net/~bender647/arduino/.

1 Board

I ordered an Arduino Uno SMD from Sparkfun Electronics. This board uses an Atmel ATmega328 microcontroller. I have plenty of experience working with surface mount boards and so opted for the SMD edition. The board was shipped with the new optiboot firmware which worked fine. Serial I/O is over the USB interface via a virtual TTY port. The interface was supported out of the box by Slackware’s kernel configuration. I chose to initially power the board off USB and didn’t order any daughter cards or other accessories.

2 Software

While the board was shipping, I built the toolchain for the AVR platform. Slackware does not ship with this software packaged, but all the required components are available at Slackbuilds.org. Just download the following tarballs, grab the source, and run the included build script. You’ll have a Slackware package that allows easy removal or upgrading of the software later. Table 1↓ shows a list of required software.
Table 1 Software packages to install
Package Description Notes
avr-binutils Cross-compiling utilities for the Atmel AVR 8-bit target
avr-gcc C and C++ cross-compilers for Atmel AVR 8-bit target Requires avr-binutils to build
avr-libc C-library for Atmel AVR 8-bit target Requires avr-binutils and avr-gcc to build
arduino Java IDE for working with Arduino board. Also contains very useful board library functions. Install even if you don’t plan on using GUI. Note: for the Arduino Uno, we need version 0022. You can use the older Slackbuild script and edit the version number to use the newer source.
avrdude Tool for in-circuit programming of Atmel microcontrollers. A version of this is included in the arduino package. If nothing else, installing this will give you a manpage for avrdude.
If you have errors while compiling the software, be aware that the cross-compiler will be tested in some configure steps. If you have CFLAGS set in your shell, this might cause the cross-compiler to fail to produce an AVR executable.

3 First hotplug

When the board arrived (attractively packaged, I might add), I gathered a USB-A to USB-B cable to power it. In a terminal on the laptop, I typed:
% tail -f /var/log/messages
and plugged the board to the laptop (You may not have permissions to view /var/log/messages by default. When I setup a new machine, I change the group ownership of that file to wheel, make sure it is mode 640, and add myself to the wheel group).
If all went right, there should be no overcurrent alerts in the log and an LED on the board will be lit. There will also be some useful information in the log listing:
kernel: cdc_acm 4-1:1.0: ttyACM0: USB ACM device
If you have a Arduino Uno like mine with the ATmega8U2 serving USB-to-serial functions, you’ll have a new ACM device. If you have an older board, there will be another, similar message. We are after the tty device name, in this case, ttyACM0. If you have no such message, you may not have the proper drivers. In my case (Arduino Uno), when the board is hotplugged, the cdc_acm module (driver) is loaded.
% lsmod |grep cdc
cdc_acm 13905 0
If you don’t have this driver and you are using an Uno board, make sure you have CONFIG_USB_ACM=m set in your kernel config file and check the /lib/modules/‘uname -r‘/kernel/drivers/usb/class/ directory tree for a cdc_acm.ko* file. This driver is in the stock Slackware kernel-modules packages, so if it’s missing, you recompiled your kernel and should know how to change the configuration and compile again.
Before continuing much further, you need to verify that udev created the device file and that the permissions are appropriate (In Slackware-13.1, a device link should only be created on demand, but if you are carrying legacy configuration from older Slackware versions this might not be the case). Check the device permissions:
% ls -l /dev/ttyACM0
crw-rw—- 1 root dialout 166, 0 2011-02-18 20:43 /dev/ttyACM0
You can see that our udev setup gives ownership of the device to group dialout. This is not a normal group you will have membership in. There are several ways to proceed. In my case, I’m developing while logged directly into the laptop from the keyboard, and I don’t run a graphical login manager. So I added the dialout group to the list of groups someone sitting at the console would normally be associated with (proximity security: if you can locally login, we trust you to use the local hardware). We do this by editing the file, /etc/login.defs, and add dialout to the group list. When you are done:
% grep -i console_groups /etc/login.defs
CONSOLE_GROUPS floppy:audio:cdrom:video:scanner:dialout
After this, it is necessary to log out and in again to have the shells inherit the new group permissions.
If you want absolute membership in this group regardless of login method, then add your username to the group by editing the /etc/group file with vigr. Afterward, only opening a new shell is necessary (for example, by typing newgr dialout). Type id afterward to verify your membership.
We are now ready to test the board.

4 First program

The most foolproof method to test the board is to the use the arduino graphical environment. In our installation, this is installed in /opt:
% /opt/arduino/arduino
Assuming you have the Java runtime installed, a text editor-like window should come up. Before doing anything, we want to set our board type and serial port device.
Under the Tools menu, Board sub-menu, I selected “Arduino Uno”. If you use an older version of the arduino program, like the default 0019 version called out by the Slackbuild script, the Uno board will not be available. I can confirm that version 0022 contains the Uno option.
Under the Tools menu, Serial Port submenu, select your device name (/dev/ttyACM0 in our case). If you do not have read/write privileges to the port, it will not be shown.
These configurations will be saved in your home directory, in ~/.arduino/preferences.txt.
You will have a blank sketch open for edit (In the language of Arduino, a program is for some reason called a sketch). For testing purposes, enter this example program:
void setup() {
  Serial.begin(9600); // set up Serial library at 9600 bps
  Serial.println("Hello, world!"); // write message w/newline
}
void loop() {
  // nop
}
From the Sketch menu, select Verify/Compile. This will compile your program and ready a byte code file (in the /tmp directory). The status line should quickly say “Done compiling”. Now, from the File menu, select Upload to I/O Board. This will upload the byte code to the board, and it will be flashed into the EEPROM. The status line should read “Done uploading”. At this point, your code is on the microcontroller until erased, and will even survive a power-down. We will want to test it now. Because our code writes a message to the serial port, we can use the built-in comm program to test it. From the Tools menu, choose Serial Monitor. The serial comm program will probably reset the port by strobing the DTR line. The Arduino Uno board will run the program setup() function at this point and we should immediately see the message “Hello, world!” in the monitor window. You can also perform a hardware reset by pushing the button on the board, and each time you do so you should see “Hello, world!” in the serial monitor.
Congratulations, you have a working development environment. Save the program for use later. By default, it saves to ~/sketchbook, but this can be changed in the preference file.

4.1 Troubleshooting

If the program did not compile, there should be some clues in the terminal window below the program (as well as in the stderr stream from the shell you launched arduino from). If you want verbose compile messages, hold the shift key while you mouse click in the Verify icon (looks like a Play arrow). The compile step is also dependent on the toolchain software you installed earlier, so make sure that is correctly installed and the tools are in your PATH (if you used the Slackbuilds, the tools should be in /usr/bin which will be in your PATH).
If the program did not upload, again, look for error messages. For verbose output, hold the Shift key while clicking the mouse in the Upload icon (looks like a right arrow). The most likely cause will be selecting the wrong board type or serial port from the menus.

5 Command-line

If you’re an old school programmer, there’s a good chance you’re not going to be a fan of the Java IDE. Fear not, because everything the IDE does to compile and upload a program can be done from the shell.
The clues you need to run the tools comes from shift-clicking the Verify and Upload icons in the IDE. When you do this, the IDE will display every command it runs. This will look familiar to those who have worked on development boards before. The basic steps are as follows:
  1. Add a header file to your source (the IDE would normally take care of this).
  2. Cross-compile your source(s) to an AVR object file.
  3. Cross-compile the library source to AVR object files.
  4. Archive the library objects, for convenience, into one static library file.
  5. Static link the source file to the library routines in one executable.
  6. Convert the relocatable ELF file to memory image in Intel HEX format.
  7. Upload and flash the memory image to the microcontroller.
You may ask why steps 2 and 3, the library compilation, aren’t done during the installation of the tools. This is because you might have many Arduino boards, with different Atmel microcontrollers on them. One AVR toolchain can serve all the boards, but the library routines need to be compiled for the target board specifically. However, if you have only one type of board under development, you can compile the library sources once for yourself and link to this library from each project directory you create.

5.1 Makefile

The traditional command-line automation technique for compiling code and managing its dependencies is the Makefile. If you search on the Web, you will find a few Arduino Makefiles out there. None were able to compile my program out of the box, even when customized. I’m sure I could have tracked down the bugs, but I thought I could learn more by making my own [A]  [A] This Makefile can be downloaded at http://home.comcast.net/bender647/arduino/Makefile. Instead, I watched the steps the IDE took, replicated them, and once tested, put them in a reasonably-sized Makefile. This Makefile will only work for my board and toolchain installation, but I used common macro names so that adapting it should not be daunting.
# Makefile for hello.cpp
# <bender647 at gmail dot com> 2011-02-18
TARGET = hello

# —————————————————————————-
# these from /opt/arduino/hardware/arduino/boards.txt for Arduino Uno
BUILD_MCU = atmega328p
BUILD_F_CPU = 16000000L
UPLOAD_SPEED = 115200
UPLOAD_PROTOCOL = stk500v1
# these general system config
PORT = /dev/ttyACM0
ARD_REV = 0022
ARD_INC = /opt/arduino/hardware/arduino/cores/arduino
# Slackbuild installs AVRDUDE here. But this version doesn’t work for me.
#AVRDUDE = /usr/bin/avrdude
#AVRDUDE_CONF = /etc/avrdude.conf
# Arduino-supplied avrdude works fine (even though its older revision)
AVRDUDE = /opt/arduino/hardware/tools/avrdude
AVRDUDE_CONF = /opt/arduino/hardware/tools/avrdude.conf
# get this from ‘man avrdude’ and search for your MCU
#AVRDUDE_PARTNO = m328p
# or this seems to work too
AVRDUDE_PARTNO = ${BUILD_MCU}
# —————————————————————————-
# these OK for Uno board
CFLAGS = -g -Os -w -ffunction-sections -fdata-sections \
-mmcu=${BUILD_MCU} -DF_CPU=${BUILD_F_CPU} -DARDUINO=${ARD_REV} \
-I${ARD_INC}
CPPFLAGS = -fno-exceptions $(CFLAGS)
LDFLAGS = -Os -Wl,--gc-sections -mmcu=${BUILD_MCU} 
# —————————————————————————-
# library sources - c, cpp and .h files all in $(ARD_INC) for our install
C_SRC := $(wildcard $(ARD_INC)/*.c)
C_OBJ := $(patsubst $(ARD_INC)/%.c,core_${BUILD_MCU}/%.o,$(C_SRC))
CPP_SRC := $(wildcard $(ARD_INC)/*.cpp)
CPP_OBJ := $(patsubst $(ARD_INC)/%.cpp,core_${BUILD_MCU}/%.o,$(CPP_SRC))

#
all: ${TARGET}.hex
#
# compile target file:
${TARGET}.o: ${TARGET}.cpp
#
# compile library src for our cpu config (no deps, just do them all)
core_${BUILD_MCU}/%o: $(ARD_INC)/%c
core_${BUILD_MCU}/%o : $(ARD_INC)/%cpp
#
# archive library - can keep this until we switch board types
core_${BUILD_MCU}.a: $(C_OBJ) $(CPP_OBJ)
#
# link our source with board library:
${TARGET}.elf: core_${BUILD_MCU}.a ${TARGET}.o
#
# convert relocatable ELF to flashable bytes
${TARGET}.hex: ${TARGET}.elf
#
# I haven’t found a use for this but the Java arduino IDE does this
${TARGET}.eep: ${TARGET}.elf
#
# flash it (UNO board does not require preceding reset)
upload: ${TARGET}.hex
#
# cleanup source directory
clean:
#
# also clean library directory
realclean: clean
Keep in mind that any indentation in the Makefile (notably, after a target line), will be a TAB or the Makefile will not work. The only non-straightforward part of this Makefile is the compilation of the arduino library. The object files are placed in a sub-directory, called core_atmega328p, and they are linked into a static library called core_atmega328p.a. This need only be done once, even though it is a very fast procedure.
Before compiling, the following header declaration needs to be placed at the top of your source file:
#include <WProgram.h>
If you prototyped your program using the IDE, it will have been saved with the extension “.pde”. To avoid confusion, I changed the extension to “.cpp” when I added the header file.
Then I edit the Makefile to set the TARGET to the basename of the cpp file (in this case, ‘hello’).
To compile, build library, link and convert to hex, type:
% make
To upload to the board, type:
% make upload
Be aware that if you are plugging and unplugging a board, it is possible to confuse udev and have non-persistent device names created (like /dev/ttyACM1, /dev/ttyACM2). I haven’t had this happen with this board, but with others. In this case, you would need to change the PORT to upload the hex file.
Traditional dummy targets are provided to remove the compiled source and hex, and to remove the library files:
% make clean
% make realclean
If the program compiled and uploaded, it does not mean it must work. Very subtle errors in flags or processor targets can result in a hex file that compiles and uploads without error but is invalid code. When in doubt, check your avr-gcc, avr-g++, avr-ar, avr-objcopy and avrdude command lines against the IDE’s verbose output and adjust the flags in the Makefile accordingly.

5.2 Serial monitor

Of course, there are many terminal emulators that can be used as a serial monitor without running the Arduino IDE. An old Slackware stand-by is minicom.
In order to use minicom, you should first set-up a configuration file as the superuser. Login in as root, and run:
% minicom -s
You will see an DOS-like menu. Using the cursor keys, select the Serial Port setup menu. Change the Serial Device to match your port (in my case, /dev/ttyACM0). Change the Bps/Par/Bits Comm Parameters to 9600 baud (to match our “hello.cpp” setup). Eight data bits, no parity, and 1 stop bit is expected (there is an 8-N-1 quick selection). Save this setup as “ACM0”. Minicom will create a file, /etc/minirc.ACM0. If you like, you can create files for ACM1 and others too. It is possible to create a default setup file in your user directory too if you prefer.
By default, Slackware doesn’t restrict any user from running a minicom configuration. If you wish, you can edit /etc/minicom.users to specifically grant your user permission to the ACM0 configuration.
Now, exit the superuser account and as an underprivileged user, type:
% minicom ACM0
If your board has been properly flashed, the window should say “Hello, world!” after it initializes. It is not uncommon to see some garbled version of your text in the initial buffer read. If you press the reset button on the board, subsequent messages should be clear.
I’m not sure if multiple processes can write to the serial port at a time. If you want to be certain your uploading was not in error, it would not be a bad idea to close minicom when you flash the board. To leave minicom, type Ctrl-A Q.

References

[1] Arduino HomePage. [online] Available http://www.arduino.cc/, February 19, 2011.

[2] SparkFun Electronics. [online] Available http://www.sparkfun.com/, February 19, 2011.

[3] SlackBuilds.org. [online] Available http://slackbuilds.org/, February 19, 2011.

[4] AVR Downloader/UploaDer. [online] Available http://www.nongnu.org/avrdude/, February 19, 2011.

[5] AVR Libc Home Page. [online] Available http://avr-libc.nongnu.org/, February 19, 2011.