Odroid XU4

I've been looking for a power efficient and not too expensive replacement for my Zotac AD10. I have previously tested a Raspberry Pi B, and later on a Beaglebone Black; but both had their shortcomings. The Pi was unreliable because of the SD storage, and i found the lack of a power button particularly annoying. The Beaglebone Black, relying on eMMC, was more resilient, but the HDMI output was acting weird, so they both didn't cut it. ARM platforms are an ideal solution though - their growing popularity means they're often supported by multiple major distributions (especially Debian), and they're a fraction of the cost for a complete x86 setup. So when I was pointed to the Odroid XU4, which comes with a physical power button, can use eMMC memory, and should idle around 2W, I decided to order one.

Hardware specifications

  • Samsung Exynos 5422 Cortex™-A15 2Ghz and Cortex™-A7 octacore CPU
  • Mali-T628 MP6 GPU
  • 2 GiB DDR3L RAM
  • 8 GB eMMC
  • Gigabit Ethernet
  • regular HDMI out
  • 2x USB 3.0, 1x USB 2.0
  • microSD card slot

Hardkernel, the manufacturer, is nice enough to include a power supply in the package. They also offer eMMC modules (or microSD cards) with Linux pre-installed - I picked the minimum size (8 GB) and installed a trimmed Debian Jessie image on it. The modules themselves seem to come with Ubuntu or Android. You also get a microSD adapter to flash the eMMC module with. Hardkernel ships an older LTS kernel (3.10). The upside of course is this will be maintained for a while, and that's where my AD10 was problematic - for HDMI audio to work in a command line environment, I was stuck with kernel 3.11. Here, everything works out of the box. All I needed to do was install MPD, mount the music NFS share, make sure the HDMI output was kept active - append consoleblank=0 to your kernel command line in /boot/boot.ini - and the box was good to go.

Setup

If you prefer setting things up headlessly, just make sure you allow remote root logins before you boot your Odroid. The image author has disabled remote root login with a password, but if you intend to set it up remotely, it's a chicken and egg problem - my Logitech Unified receiver is not supported on a 3.10 kernel, which means a perpetual QWERTY layout, and endless irritation (how do I type :wq in Vim?!). So, mount your module or SD card on the system you flashed it on and fix that before you try your hand at a remote setup. Just a word of warning.
Since I have set up Salt a while ago, and had also integrated the bits and pieces for my previous MPD server, further configuration was pretty straightforward: just a few switches to flip, so to speak.

Limiting fan noise

I have seen some people over at the Hardkernel forums modding their XU4 with a fanless heatsink, but that approach has its own headaches. Apparently the biggest jump in power is from 1,9 GHz to 2,0 GHz, which will surely trigger the fan. Oddly enough, the default governor is set to performance. You can set this directly at boot by editing /boot/boot.ini and setting it to ondemand. I have also limited the maximum clock speed of the four 'big' cores to 1,5 GHz, with this in /etc/rc.local:

for i in 4 5 6 7
do
    echo "1500000" > "/sys/devices/system/cpu/cpu$i/cpufreq/scaling_max_freq"
done

You can of course limit this further; the cores take increments of 100 MHz. I have not tested if the fan spins back on while under sustained load. Under normal circumstances, you will rarely hear it spin up though, and the SoC is still plenty fast at 1,5 GHz. You can check the temperature with the following command:

$ cat /sys/devices/10060000.tmu/temp
sensor0 : 46000
sensor1 : 48000
sensor2 : 51000
sensor3 : 47000
sensor4 : 45000

I only found out after ordering that Hardkernel reports their C1 heatsink to be compatible with the XU4. If you get it, just don't apply the TIM.

Hardware on/off button

I kind of hoped (naively, I guess) that the presence of a hardware button would mean I could plug in the device and push that button to start it. Alas, it does not - the moment you plug it into a wall socket, the Odroid will boot up. It does allow you though to shut it down - it's not clear if this happens cleanly or not; it certainly works, but the VFAT /boot partition always has its dirty bit set next time it comes up. Either way: shutdown works, and after that, you can boot up just fine as well by pushing the power button.

General impression

The Odroid XU4 feels very responsive, especially compared to the AD10 it is replacing, and which is, after all, still an x86 system. I am not sure whether the AD10's sluggishness was due solely to the CPU or the 5400 RPM HD; regular operations like package management were always slow. So far, I'm very happy with this little machine.

Upgrade to Debian 9 'Stretch'

Upgrading to Stretch is as easy as replacing all Jessie entries in /etc/apt/sources.list with Stretch ones. Meveric's meveric-all repository is OS independent. I don't use the deb-multimedia repository, but I suppose by now (November 2017) they have Stretch repositories up as well. This won't touch your kernel, however, since the provided kernel is not part of the Debian repositories.

Kernel 4.9 (LTS)

Hardkernel provides a 4.9 kernel (they are even working on the next planned LTS - 4.14). Switching to the 4.9 release, however, requires a bit of manual work. First, install the 4.9 release:

$ sudo apt-get install linux-image-4.9-armhf-odroid-xu3

Make sure to install the newest uboot package as well. That should be at least the following version:

$ sudo dpkg -l|awk '/uboot/ {print $3}'
20170824-9+deb8u1

Uboot should replace /boot/boot.ini; however, in case it does not, make sure to adapt /boot/boot.ini since kernel 4.9 will need the Odroid XU4 DTS to be loaded. It won't work with the U3 DTS like 3.10 used to.

Find this section - it might look a bit different, but the fatload commands should be the same:

# Load kernel, initrd and dtb in that sequence
fatload mmc 0:1 0x40008000 zImage
fatload mmc 0:1 0x42000000 uInitrd
if test "${board_name}" = "xu4"; then fatload mmc 0:1 0x44000000 exynos5422-odroidxu4.dtb; setenv fdtloaded "true"; fi
if test "${board_name}" = "xu3"; then fatload mmc 0:1 0x44000000 exynos5422-odroidxu3.dtb; setenv fdtloaded "true"; fi
if test "${board_name}" = "xu3l"; then fatload mmc 0:1 0x44000000 exynos5422-odroidxu3-lite.dtb; setenv fdtloaded "true"; fi
#failsafe
if test "${fdtloaded}" != "true"; then fatload mmc 0:1 0x44000000 exynos5422-odroidxu4.dtb; fi

Replace it with this:

# Load kernel, initrd and dtb in that sequence
fatload mmc 0:1 0x40008000 zImage
fatload mmc 0:1 0x42000000 uInitrd
if test "${board_name}" = "xu4"; then fatload mmc 0:1 0x44000000 exynos5422-odroidxu4.dtb; setenv fdtloaded "true"; fi
if test "${board_name}" = "xu3"; then fatload mmc 0:1 0x44000000 exynos5422-odroidxu3.dtb; setenv fdtloaded "true"; fi
if test "${board_name}" = "xu3l"; then fatload mmc 0:1 0x44000000 exynos5422-odroidxu3-lite.dtb; setenv fdtloaded "true"; fi
#force xu4
fatload mmc 0:1 0x44000000 exynos5422-odroidxu4.dtb

Kernel 4.9 has no fan control implemented so far, so you need a workaround for this. Add the following to /etc/rc.local. Adjust the trip points and fan speeds to your liking.

echo Set thermal trip points to 60C and higher
echo '60000' > /sys/devices/virtual/thermal/thermal_zone0/trip_point_0_temp
echo '70000' > /sys/devices/virtual/thermal/thermal_zone0/trip_point_1_temp
echo '80000' > /sys/devices/virtual/thermal/thermal_zone0/trip_point_2_temp
fi

if [ -f '/sys/devices/platform/pwm-fan:/hwmon/hwmon0/fan_speed' ]; then
    #set fan speed
    echo Set fan speed
    echo "0 80 150 245" > /sys/devices/platform/pwm-fan:/hwmon/hwmon0/fan_speed
fi
Updated: 2017-11-26