Wednesday, 28 December 2016

Robot progress

Well, best not let perfect be the enemy of good. While the Freescale board is clearly better, it doesn't actually work. So here is my new Dagu controller board being run from an Arduino. The speed sensor seems to work too - much less jitter than before.

Also, top tip. Don't try to run your DCC railway with this board - it will catch fire. I don't think it like 10,000 direction changes a second.

Friday, 2 December 2016

Target practice

Now, as we know, the original Raspberry Pi uses an ARM11 core, which is based on the ARMv6 architecture. The Raspberry Pi 2 uses quad Cortex-A7 cores (although it's actually just been updated to have the same chip as the Pi 3 for volume reasons) which are based on the ARMv7-A architecture while the Pi 3 uses quad Cortex-A53s which are based on the ARMv8-A architecture.

So what do this have to do with Rust?

Well, in two ways really. One is that the compiler is downloaded as a binary, and it the instructions encoded into the machine code need to be ones that that processor core can understand and execute. Helpfully, the ARM architectures are backwards compatible, so the Pi 3 can run code compiled for an original Pi 2 and both can run code compiled for an original Pi.

The second is in the choice of instructions the compiler chooses to emit. Now, by default, you would expect this to be the same as the compiler itself was compiled to - after all, 9 times out of 10 you're going to run the code on the machine you're using to compile it. But that 1 time in 10, someone may well be cross-compiling. For example, I do a lot of embedded development and I will use my x86_64 laptop to emit binaries which will execute on the ARMv7E-M architecture of my favourite Cortex-M4F based embedded development board.

So, with that in mine, some advice.

When you run rustup on a Raspberry Pi (or any other Linux machine), it will detect the processor architecture and download the appropriate compiler. That compiler will then default to outputting binaries which target the same architecture. Here's the list of available architecture/OS/C-library combinations for I could install today (from


There's four ARM toolchains listed. What gives?

Well aarch64 is the 64-bit ARMv8-A toolchain. You'd use this if your Raspberry Pi 3 was running that new 64-bit release of OpenSUSE or some other 64-bit Linux distribution. It probably isn't.

The armv7 toolchain will run on a Pi 2 or Pi 3, but not a Pi 1 or Zero. This will be automatically selected if you run rustup on a Pi 2 or Pi 3 so be warned if you swap SD cards between various models - this will instantly crash on a Pi 1 or Pi Zero.

The two arm versions are for the two floating point ABIs (application binary interface) - basically, whether the code expects floating point arguments to functions to be placed in hardware floating point registers (gnueabihf) or in standard integer registers (gnueabi). Raspbian requires gnueabihf, while standard Debian for the ARMv6 I believe requires gnueabi. That's one of the reasons for the Raspbian recompile of Debian in the first place - gnueabihf is faster, but it does require your CPU to have hardware floating point registers (which the original Pi does).

Now if you've set yourself up on a Pi 3 but want to run code on a Pi Zero, you can keep you shiny fast compiler but tell it to emit code for a different 'target', like this:

pi@boron:~/livedemo $ rustup target add arm-unknown-linux-gnueabihf
info: downloading component 'rust-std' for 'arm-unknown-linux-gnueabihf'
 61.0 MiB /  61.0 MiB (100 %)   4.1 MiB/s ETA:   0 s              
info: installing component 'rust-std' for 'arm-unknown-linux-gnueabihf'
pi@boron:~/livedemo $ cargo build --target=arm-unknown-linux-gnueabihf
    Compiling livedemo v0.1.0 (file:///home/pi/livedemo)
    Finished debug [unoptimized + debuginfo] target(s) in 7.8 secs
pi@boron:~/livedemo $ ls -l target/
total 8
drwxr-xr-x 3 pi pi 4096 Dec  2 15:49 arm-unknown-linux-gnueabihf
drwxr-xr-x 7 pi pi 4096 Dec  2 16:36 debug
pi@boron:~/livedemo $

Now you have a Pi Zero compatible binary in target/arm-unknown-linux-gnueabihf/debug.

Your other option, if you want to share your SD card between a Pi 1 and a Pi 2/3 is to install the arm toolchain and remove the armv7 toolchain. You'd use a command like "rustup toolchain install beta-arm-unknown-linux-gnueabihf" to do that - I'll leave it as an exercise for the reader.

Bug in Rust 1.13 for ARM and how to work around it

There's a nasty code generation bug in Rust 1.13 stable. Because ARM isn't considered a 'tier-1' platform for Rust at this time, the team have decided to put the fix into 1.14 beta (and 1.15 nightly) but not up-issue 1.13. Unfortunately this means if you follow my last post, you'll get a compiler that doesn't work properly when using floating point functions.

The best fix is probably switch to 1.14 beta until 1.14 stable comes out (around 22 December). You can do this as follows:

pi@boron:~ $ rustup toolchain install beta
info: syncing channel updates for 'beta-armv7-unknown-linux-gnueabihf'
info: downloading component 'rustc'
 47.0 MiB /  47.0 MiB (100 %)   6.2 MiB/s ETA:   0 s                
info: downloading component 'rust-std'
 60.3 MiB /  60.3 MiB (100 %)   6.2 MiB/s ETA:   0 s                
info: downloading component 'cargo'
  4.2 MiB /   4.2 MiB (100 %) 737.2 KiB/s ETA:   0 s                
info: installing component 'rustc'
info: installing component 'rust-std'
info: installing component 'cargo'

    beta-armv7-unknown-linux-gnueabihf installed - rustc 1.14.0-beta.2 (e627a2e6e 2016-11-16)

pi@boron:~ $ rustup default beta
info: using existing install for 'beta-armv7-unknown-linux-gnueabihf'
info: default toolchain set to 'beta-armv7-unknown-linux-gnueabihf'

    beta-armv7-unknown-linux-gnueabihf unchanged - rustc 1.14.0-beta.2 (e627a2e6e 2016-11-16)

pi@boron:~ $ rustc -Vv
rustc 1.14.0-beta.2 (e627a2e6e 2016-11-16)
binary: rustc
commit-hash: e627a2e6edbc7b7fd205de8ca7c86cff76655f4d
commit-date: 2016-11-16
host: armv7-unknown-linux-gnueabihf
release: 1.14.0-beta.2
LLVM version: 3.9
pi@boron:~ $
You can then switch back to stable once 1.14 has been released, or if they do put out a point release (unlikely at this point).