Skip to main content

Enabling an Industrial I/O Driver on Raspberry Pi 3 running Arch Linux ARM

MPU9250 from TDK is a three in one Gyro + Accelerometer + Compass sensor with an I2C interface. Mainline Linux kernel has the source code for it's driver which reads values from the sensor via I2C and exposes it via the filesystem using the Industrial I/O subsystem. Arch Linux ARM for Raspberry Pi does not come with the driver for this pre-compiled and enabled. Here is how to compile and enable the driver on Raspberry Pi 3 Model B.

Raspberry Pi 3 Model B with MPU9250 connected to it's I2C interface
and a USB-Serial widget to access console over serial

Connections

Buy the MPU9250 Widget from Amazon and hook it up to your Raspberry Pi as per the table


RPi3 (2.54mm)

MPU9250 Module
(2.54mm)

3.3V PWR Pin 1

VCC

GND Pin 9

GND

I2C1_SCL GPIO 3 Pin 5

SCL

I2C1_SDA GPIO 2 Pin 3

SDA

GPIO4 Pin 7

INT


Preparations

  1. Prepare and boot Arch Linux ARM from SD Card: instructions are here.

  2. Connect the Raspberry Pi to your home network using an ethernet cable.

  3. Look up the DHCP assigned IP address from your router’s configuration web interface, it will show as a new device named "alarmpi".

  4. Gain access to the console over SSH using PuTTY or MobaXterm or physically using keyboard/mouse/monitor. Login: alarm and Password: alarm

  5. While following the instructions below, switch to root user whenever required using:

    1. su root

    2. Password: root


Enable Console over USB-Serial [Optional]

Follow instructions over at https://gist.github.com/yeokm1/d6c3ca927919c61257cd

Install required packages on Arch Linux ARM running on RPi3B

  • pacman-key --init
  • pacman-key --populate archlinuxarm
  • pacman -Syu
  • pacman -S curl bash ca-certificates nano i2c-tools jq iio-utils
  • pacman -S base-devel
  • pacman -S dtc git
  • pacman -S linux-raspberrypi-headers
  • pacman -S python python-pip

Enable I2C on Raspberry Pi 3 Model B running Arch Linux ARM

  1. su root

  2. nano /etc/modules-load.d/raspberrypi.conf

  3. Append:

    1. i2c-dev

    2. Save and Reboot

  4. nano /boot/config.txt

  5. Append:

    1. dtparam=i2c=on

    2. Save and Reboot

  6. Test (0x68 is MPU9250):

[root@alarmpi alarm]# i2cdetect -y 1

     0  1  2  3  4  5  6  7  8  9  a  b  c  d  e  f

00:          -- -- -- -- -- -- -- -- -- -- -- -- --

10: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --

20: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --

30: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --

40: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --

50: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --

60: -- -- -- -- -- -- -- -- 68 -- -- -- -- -- -- --

70: -- -- -- -- -- -- -- --


Python Library for reading from MPU9250 over I2C

  1. Install python packages (Latest version from its git repository, replace the version numbers with latest one)

    1. python -m pip install git+https://github.com/FaBoPlatform/FaBo9AXIS-MPU9250-Python.git@78e4da28e176a07cc1c22c2f61a5be7ffe6c2c28

  2. Clone the git repository to fetch the example code

    1. git clone https://github.com/FaBoPlatform/FaBo9AXIS-MPU9250-Python.git


  1. First test in text mode using example from FaBo9AXIS-MPU9250-Python repo (This uses raw I2C bus without the need for MPU9250 Industrial I/O Driver):

[root@alarmpi ~]# python FaBo9AXIS-MPU9250-Python/example/read9axis.py

 ax =  -0.871

 ay =  0.39

 az =  0.31

 gx =  -0.793

 gy =  0.725

 gz =  -0.099

 mx =  30.289

 my =  44.197

 mz =  -24.791


 ax =  -0.872

 ay =  0.392

 az =  0.312

 gx =  -0.801

 gy =  0.71

 gz =  -0.069

 mx =  30.647

 my =  43.475

 mz =  -25.832



Enabling MPU9250 Industrial I/O interface on ArchLinux running on Raspberry Pi 3


  1. Fetch (from mainline kernel repository) the latest sources of inv-mpu6050 which has support for MPU9250 through shallow clone/sparse checkout, execute the following commands while in /root:

    1. su root

    2. mkdir linux_main_src

    3. cd linux_main_src

    4. git init

    5. git remote add origin https://github.com/torvalds/linux.git

    6. git config core.sparsecheckout true

    7. echo "drivers/iio/*" >> .git/info/sparse-checkout

    8. git pull --depth=3 origin master

  2. Create the Makefile for compiling the driver:

    1. Get into /root/linux_main_src/drivers/iio/imu/inv_mpu6050

    2. And modify the Makefile present there for the inv_mpu6080 driver to compile on and for Raspberry Pi 3 platform (lines in blue will be present already, lines in red are the ones that need to be appended, make sure to use a single tab and not spaces at the beginning of the lines below “all:’ and “clean:”) :

      Makefile

# SPDX-License-Identifier: GPL-2.0

#

# Makefile for Invensense MPU6050 device.

#


obj-$(CONFIG_INV_MPU6050_IIO) += inv-mpu6050.o

inv-mpu6050-y := inv_mpu_core.o inv_mpu_ring.o inv_mpu_trigger.o \

                 inv_mpu_aux.o inv_mpu_magn.o


obj-$(CONFIG_INV_MPU6050_I2C) += inv-mpu6050-i2c.o

inv-mpu6050-i2c-y := inv_mpu_i2c.o inv_mpu_acpi.o


obj-$(CONFIG_INV_MPU6050_SPI) += inv-mpu6050-spi.o

inv-mpu6050-spi-y := inv_mpu_spi.o


all:

    make -C /lib/modules/$(shell uname -r)/build M=$(PWD) modules

    gzip -f inv-mpu6050-i2c.ko

    gzip -f inv-mpu6050-spi.ko

    gzip -f inv-mpu6050.ko


clean:

    make -C /lib/modules/$(shell uname -r)/build M=$(PWD) clean

    rm inv-mpu6050-i2c.ko.gz

    rm inv-mpu6050-spi.ko.gz

    rm inv-mpu6050.ko.gz


  1. Change to /root
    cd /root

  2. Create an device tree overlay source file for MPU9250:
    nano /root/mpu9250.dts

  3. Add the contents and save:

// Definitions for MPU9250
// Combination of:
// https://github.com/raspberrypi/linux/blob/rpi-4.9.y/arch/arm/boot/dts/overlays/mpu6050-overlay.dts
// and https://github.com/torvalds/linux/blob/master/Documentation/devicetree/bindings/iio/imu/inv_mpu6050.txt

// Driver codes:
// https://github.com/torvalds/linux/blob/master/drivers/iio/imu/inv_mpu6050/
// and
// https://github.com/torvalds/linux/tree/master/drivers/iio/magnetometer

/dts-v1/;
/plugin/;

/ {
    compatible = "brcm,bcm2708";

    fragment@0 {
            target = <&i2c1>;
            __overlay__ {
                    #address-cells = <1>;
                    #size-cells = <0>;
                    status = "okay";
                    clock-frequency = <400000>;

                    mpu9250: mpu9250@68 {
                            compatible = "invensense,mpu9250";
                            reg = <0x68>;
                            interrupt-parent = <&gpio>;
                            interrupts = <4 1>;
                            mount-matrix = "1",  /* x0 */
                            "0",  /* y0 */
                            "0",  /* z0 */
                            "0",  /* x1 */
                            "1",  /* y1 */
                            "0",  /* z1 */
                            "0",  /* x2 */
                            "0",  /* y2 */
                            "1";  /* z2 */

                            i2c-gate {
                                    #address-cells = <1>;
                                    #size-cells = <0>;
                                    ak8963@c {
                                            compatible = "asahi-kasei,ak8963";
                                            reg = <0x0c>;
                                    };
                            };
                    };
            };
    };

    __overrides__ {
            interrupt = <&mpu9250>,"interrupts:0";
    };
};




  1. Compile the device tree source and place it in overlays folder:
    dtc -I dts -O dtb -o /boot/overlays/mpu9250.dtbo -b 0 -@ /root/mpu9250.dts

  2. Update /boot/config.txt and add the following lines to it, save it and reboot:
    dtoverlay=mpu9250

  3. Read the Accelerometer and Magnetometer values like so:

[alarm@alarmpi ~]$ cat /sys/bus/iio/devices/iio\:device0/in_accel_x_raw

-794

[alarm@alarmpi ~]$ cat /sys/bus/iio/devices/iio\:device0/in_accel_y_raw

271

[alarm@alarmpi ~]$ cat /sys/bus/iio/devices/iio\:device0/in_accel_z_raw

16950

[alarm@alarmpi ~]$ cat /sys/bus/iio/devices/iio\:device1/in_magn_x_raw

42

[alarm@alarmpi ~]$ cat /sys/bus/iio/devices/iio\:device1/in_magn_y_raw

-14

[alarm@alarmpi ~]$ cat /sys/bus/iio/devices/iio\:device1/in_magn_z_raw

43



Python Bar Graph with Industrial I/O Driver

  1. Install python packages (Latest versions from its git repository, replace the version number with latest one)

    1. pacman -S libjpeg

    2. python -m pip install git+https://github.com/peterbrittain/asciimatics.git@476159c95c5b6e34a782ea97503785ad95683805

  2. Clone the git repository to fetch the example code

    1. git clone https://github.com/peterbrittain/asciimatics.git

 

  1. Then run following code using python for live bar  graph:

from asciimatics.effects import Print

from asciimatics.renderers import BarChart, FigletText, SpeechBubble, Box

from asciimatics.scene import Scene

from asciimatics.screen import Screen

from asciimatics.exceptions import ResizeScreenError

import os

import sys

import math

import time


accel_x = open('/sys/bus/iio/devices/iio:device0/in_accel_x_raw', 'r')

accel_y = open('/sys/bus/iio/devices/iio:device0/in_accel_y_raw', 'r')

accel_z = open('/sys/bus/iio/devices/iio:device0/in_accel_z_raw', 'r')


gyro_x = open('/sys/bus/iio/devices/iio:device0/in_anglvel_x_raw', 'r')

gyro_y = open('/sys/bus/iio/devices/iio:device0/in_anglvel_y_raw', 'r')

gyro_z = open('/sys/bus/iio/devices/iio:device0/in_anglvel_z_raw', 'r')


mag_x = open('/sys/bus/iio/devices/iio:device1/in_magn_x_raw', 'r')

mag_y = open('/sys/bus/iio/devices/iio:device1/in_magn_y_raw', 'r')

mag_z = open('/sys/bus/iio/devices/iio:device1/in_magn_z_raw', 'r')


def _speak(screen, text, pos, start):

  return Print(

    screen,

    SpeechBubble(text, None, uni=screen.unicode_aware),

    x=pos[0] + 4, y=pos[1] - 4,

    colour=Screen.COLOUR_WHITE,

    clear=True,

    start_frame=start,

    stop_frame=start+50)


def accelx():

  accel_x.seek(0)

  accel = int(accel_x.readline())

  accel = accel/16000 + 1

  return accel if accel < 2 else 2


def accely():

  accel_y.seek(0)

  accel = int(accel_y.readline())

  accel = accel/16000 + 1

  return accel if accel < 2 else 2


def accelz():

  accel_z.seek(0)

  accel = int(accel_z.readline())

  accel = accel/16000 + 1

  return accel if accel < 2 else 2


def gyrox():

  gyro_x.seek(0)

  gyro = int(gyro_x.readline())

  gyro = gyro/300 + 1

  return gyro if gyro < 2 else 2


def gyroy():

  gyro_y.seek(0)

  gyro = int(gyro_y.readline())

  gyro = gyro/300 + 1

  return gyro if gyro < 2 else 2


def gyroz():

  gyro_z.seek(0)

  gyro = int(gyro_z.readline())

  gyro = gyro/300 + 1

  return gyro if gyro < 2 else 2


def magx():

  mag_x.seek(0)

  mag = int(mag_x.readline())

  mag = mag/100 + 1

  return mag if mag < 2 else 2


def magy():

  mag_y.seek(0)

  mag = int(mag_y.readline())

  mag = mag/100 + 1

  return mag if mag < 2 else 2


def magz():

  mag_z.seek(0)

  mag = int(mag_z.readline())

  mag = mag/100 + 1

  return mag if mag < 2 else 2


def demo(screen):

    scenes = []

    effects = [

        Print(screen,

              BarChart(

                  10, 40,

                  [accelx, accely, accelz],

                  colour=[c for c in range(1, 4)],

                  bg=[c for c in range(1, 4)],

                  scale=2.0,

                  axes=BarChart.X_AXIS,

                  intervals=0.5,

                  labels=True,

                  border=False),

              x=0, y=0, transparent=False, speed=2),

          _speak(screen, "Accelerometer", (0, 14), 0),

          Print(screen,

              BarChart(

                  10, 40,

                  [gyrox, gyroy, gyroz],

                  colour=[c for c in range(7, 10)],

                  bg=[c for c in range(7, 10)],

                  scale=2.0,

                  axes=BarChart.X_AXIS,

                  intervals=0.5,

                  labels=True,

                  border=False),

              x=0, y=15, transparent=False, speed=2),

          _speak(screen, "Gyroscope", (0, 29), 0),

          Print(screen,

              BarChart(

                  10, 40,

                  [magx, magy, magz],

                  colour=[c for c in range(4, 8)],

                  bg=[c for c in range(4, 8)],

                  scale=2.0,

                  axes=BarChart.X_AXIS,

                  intervals=0.5,

                  labels=True,

                  border=False),

              x=44, y=0, transparent=False, speed=2),

          _speak(screen, "Magnetometer", (50, 14), 0),

    ]

    scenes.append(Scene(effects, -1))

    screen.play(scenes, stop_on_resize=True)




while True:

    try:

        Screen.wrapper(demo)

        sys.exit(0)

    except ResizeScreenError:

        pass





Try rotating the MPU9250 widget and watch the bars change.


Enable WiFi on your Raspberry Pi 3 Running Arch Linux ARM [Optional]

  1. su root

  2. sudo pacman -S netctl

  3. nano /etc/netctl/wireless-home

  4. Copy and paste the following contents and modify the SSID and passphrase to match your WiFi network

Description='A simple WPA encrypted wireless connection'

Interface=wlan0

Connection=wireless


Security=wpa

IP=dhcp


ESSID='MyNetwork'

# Prepend hexadecimal keys with \"

# If your key starts with ", write it as '""<key>"'

# See also: the section on special quoting rules in netctl.profile(5)

Key='WirelessKey'

# Uncomment this if your ssid is hidden

#Hidden=yes

# Set a priority for automatic profile selection

#Priority=10


  1. netctl enable /etc/netctl/wireless-home

  2. reboot

Comments