Rustduino pt. I: setting up the development environment

This post details the steps needed to start programming an Arduino UNO board using the rust programming language and working on Mac OS.

Premise

As a software developer who has always focused on high-level languages and frameworks, I’ve been meaning to explore the world of system programming for quite a while. Beyond satisfying my general fascination with technology, I am convinced that spending some time closer to the hardware level will make me a better programmer overall and give me a chance to learn some valuable skills.

Fast forward to the ongoing winter festivities and I find myself, by coincidence, with everything I need to begin my discovery:

  1. some lovely spare time;
  2. an Arduino UNO board based on the ATMega328P microcontroller;
  3. preliminary support for the microcontroller’s AVR architecture in rust, an intriguing and relatively new programming language that was already on my list of things to play with in 2019.

I’ve decided to document my experiments in a series of blog posts, hopefully sparing a couple of headaches to other developers getting into these subjects. This first post deals with setting up the development environment. Although I work on a Mac and some of these instructions are specific to Mac OS, porting them to Linux should be relatively trivial.

Install XCode’s developer tools and Mac OS’ development headers

Start by installing XCode’s command-line developer tools:

xcode-select --install

If on Mac OS 10.14 (Mojave) install the OS’ development headers:

sudo installer -pkg /Library/Developer/CommandLineTools/Packages/macOS_SDK_headers_for_macOS_10.14.pkg -target /

Missing headers will result in issues while building the zlib library and/or errors while unpacking tar archives using python’s zlib module.

Install Python 2.7.x

Install python via homebrew:

brew update
brew install cmake openssl readline sqlite3 xz zlib python@2

Install the GCC AVR toolchain

Install the GCC AVR toolchain, once again via homebrew:

brew update
brew tap osx-cross/avr
brew install avr-gcc # This takes a while!

This step requires compiling GCC, which takes ~30 minutes. Many thanks to all the partecipants in the discussion related to this issue on GitHub as it helped me figure out what I needed to install.

Install the standard rust toolchain

Install the standard rust toolchain by following the official guide. This will also install the rustup toolchain management tool, which helps managing multiple rust builds on the same machine.

Install the AVR rust toolchain

Time to install the rust toolchain that targets the AVR architecture, which is the architecture of the ATMega328P that powers the Arduino UNO. I had to make a few small modifications to the steps in the repository’s README:

# Grab the avr-rust sources
git clone https://github.com/avr-rust/rust.git avr-rust

# Create a directory to place built files in
mkdir avr-rust-build
cd avr-rust-build

# Generate Makefile using settings suitable for an experimental compiler
../avr-rust/configure \
  --enable-debug \
  --disable-docs \
  --enable-llvm-assertions \
  --enable-debug-assertions \
  --enable-optimize \
  --enable-llvm-release-debuginfo \
  --experimental-targets=AVR \
  --prefix=/opt/avr-rust

# Build the compiler
make  # This takes a while!

# Register the new toolchain with rustup
rustup toolchain link avr-toolchain <absolute path to avr-rust-build>/build/x86_64-apple-darwin/stage1

Now that the AVR toolchain is ready, it’s time to compile a small test program to later deploy on the Arduino UNO. blink programs are simple loops that toggle the state of light-emitting components on and off and they are to system programming what hello, world! programs are to normal programming. One such program is made available by the maintainer of the AVR toolchain which we have just installed. The following instructions are taken directly from the official repo’s README:

git clone https://github.com/avr-rust/blink.git avr-rust-blink
cd avr-rust-blink
export RUST_TARGET_PATH=`pwd`
export XARGO_RUST_SRC=<absolute path to avr-rust>/src	# not avr-rust-build!
rustup run avr-toolchain xargo build --target avr-atmega328p --release

If all goes well, this will produce an .elf file at target/avr-atmega328p/release/blink.elf.

Install the Arduino IDE and avrdude

Although we will not use it in the rest of this post, the official Arduino IDE will become necessary in the future. Download it from Arduino’s home page and install it as any other Mac OS application by moving it to the /Applications folder. Use it from the command line as follows:

/Applications/Arduino.app/Contents/MacOS/Arduino

For the time being, however, avrdude will take care of uploading compiled programs to the board. Install it from homebrew:

brew update
brew install avrdude

Deploy onto the Arduino UNO

Connect the Arduino UNO via USB to the Mac. It should come up as a /tty.usbmodem**** file in the /dev directory. Use avrdude to upload the compiled program to the board:

avrdude -v -p atmega328p -c arduino -P /dev/tty.usbmodem14201 -b 115200 -D -Uflash:w:"target/avr-atmega328p/release/blink.elf"

If everything goes well, one of the yellow LEDs on the board should start blinking at a leisurely pace. Hooray! Further useful pointers about uploading files to the board can be found here, here and here.

Conclusion

We can now cross-compile rust programs and deploy them onto the Arduino UNO. Happy 2019!