Interfaces
After playing around with the image a little, it was time to connect the maaxboard to the outside world. The first things I wanted to try was to use the i2c interface, since that was my preferred bus to hook up my sensors. I2C is a bus which allows multiple devices to share the same bus, each with its own address. Looking around the hardware I found that its 4 i2c buses were spread out:
- Bus 1 is on the camera connector
- Bus 2 is on the GPIO pin header: SDA is pin 3, SCL is pin 5
- Bus 3 is also on the GPIO header: SDA is pin 27, SCL is pin 28
- Bus 4 is on the MIPI (screen) connector
These buses are visible to the system:
$ ls -lia /dev/i2c-*
3192 crw-rw---- 1 root i2c 89, 0 feb 7 16:50 /dev/i2c-0
2566 crw-rw---- 1 root i2c 89, 1 feb 7 16:50 /dev/i2c-1
2567 crw-rw---- 1 root i2c 89, 2 feb 7 16:50 /dev/i2c-2
2568 crw-rw---- 1 root i2c 89, 3 feb 7 16:50 /dev/i2c-3
So I hooked up a small breadboard with 2 i2c devices I had lying around:
- MCP23017 port expander
- BMP280 pressure and temperature sensor
I use the 3.3V and GND connections from the GPIO header:
- GPIO pin 1 (3.3V) to the positive bus on the breadboard
- GPIO pin 6 (GND) to the negative bus on the breadboard
- GPIO pin 3 (SDA from i2c-1 bus)
- GPIO pin 5 (SCL from i2c-1 bus)
I used this tutorial to test the MCP23017: https://www.raspberrypi-spy.co.uk/2013/07/how-to-use-a-mcp23017-i2c-port-expander-with-the-raspberry-pi-part-1/
After connecting everything, the devices showed up on the i2c bus:
pi@maaxboard:~$ sudo i2cdetect -y 1
0 1 2 3 4 5 6 7 8 9 a b c d e f
00: -- -- -- -- -- -- -- -- -- -- -- -- --
10: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
20: 20 -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
30: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
40: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
50: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
60: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
70: -- -- -- -- -- -- 76 --
Address 20 (HEX) was the MCP23017, address 76 (HEX) was the BMP280.
By using the 'i2cset' command, I was able to trigger the connected leds to on and off (this is taken from the tutorial mentioned above):
To do a quick test we can use the command line to enable the LED on GPA0 :
First we configure Port A pins GPA0-6 as outputs and GPA7 as an input. (10000000 in binary and 0x80 in hex) :
sudo i2cset -y 1 0x20 0x00 0x80Then we set GPA0 to logic high which will enable the LED :
sudo i2cset -y 1 0x20 0x14 0x01To turn off the LED we use :
sudo i2cset -y 1 0x20 0x14 0x00
So the GPIO expander worked, how about the sensor? I found a small python script to read out the sensor:
# python test_bmp.py
Temperature in Celsius : 21.94 C
Temperature in Fahrenheit : 71.49 F
Pressure : 1017.50 hPa
So the sensor also worked.
I wanted more, for I knew there were kernel modules for the various sensors, so I would be able to read them continuously without using a python script. I had some experience in compiling linux kernel modules, but I was used to the basic way of building them: https://www.kernel.org/doc/Documentation/kbuild/modules.txt which used the kernel source tree to build a module:
To build against the running kernel use:
$ make -C /lib/modules/`uname -r`/build M=$PWD
This gave an error, because, as I found out, the running kernel was 4.14.78, and the '/lib/modules' directory looked like this:
# ls -lia /lib/modules/4.14.78/
totaal 368
853 drwxrwxr-x 3 user user 4096 apr 16 12:41 .
852 drwxrwxr-x 5 user user 4096 apr 14 21:07 ..
855 lrwxrwxrwx 1 user user 26 jan 14 03:48 build -> /home/embest/compile/linux
867 drwxrwxr-x 9 user user 4096 jan 14 03:48 kernel
30600 -rw-r--r-- 1 root root 64579 apr 16 12:41 modules.alias
12216 -rw-r--r-- 1 root root 69092 apr 16 12:41 modules.alias.bin
857 -rw-rw-r-- 1 user user 31857 jan 14 03:48 modules.builtin
30602 -rw-r--r-- 1 root root 34659 apr 16 12:41 modules.builtin.bin
30599 -rw-r--r-- 1 root root 22440 apr 16 12:41 modules.dep
12215 -rw-r--r-- 1 root root 36296 apr 16 12:41 modules.dep.bin
30603 -rw-r--r-- 1 root root 98 apr 16 12:41 modules.devname
856 -rw-rw-r-- 1 user user 12832 jan 14 03:48 modules.order
30601 -rw-r--r-- 1 root root 85 apr 16 12:41 modules.softdep
12217 -rw-r--r-- 1 root root 30424 apr 16 12:41 modules.symbols
862 -rw-r--r-- 1 root root 37398 apr 16 12:41 modules.symbols.bin
854 lrwxrwxrwx 1 user user 26 jan 14 03:48 source -> /home/embest/compile/linux
The build directory was linked to a nonexistent home directory, probably used in building this image. I tried several things, like downloading a new kernel source, but I got stuck. After a long night of fruitless tries, I woke up the next morning retracing my steps, and found this entry on the element 14 blog:
, which pointed to a download of the kernel sources for this debian build. I followed the steps, and with the addition of a few extra commands:# make modules
# make modules_prepare
I was able to compile the kernel modules for the bmp280 and bmp280-i2c drivers.
After loading them into the kernel with the command:
# modprobe bmp280-i2c
The driver was loaded:
# lsmod
Module Size Used by
bmp280_i2c 16384 0
bmp280 20480 1 bmp280_i2c
brcmfmac 249856 0
brcmutil 16384 1 brcmfmac
crc32_ce 16384 0
crct10dif_ce 16384 0
imx_sdma 36864 0
ip_tables 24576 0
x_tables 40960 1 ip_tables
(note that the bmp280 is also loaded, as required by the bmp280-i2c driver).
Now if we look at the contents of the i2c bus:
# ls -lia /sys/bus/i2c/devices/i2c-1/
totaal 0
7717 drwxr-xr-x 5 root root 0 apr 17 00:04 .
3142 drwxr-xr-x 4 root root 0 apr 17 00:04 ..
21038 drwxr-xr-x 4 root root 0 apr 17 00:04 1-0076
7722 --w------- 1 root root 4096 apr 17 00:04 delete_device
7732 lrwxrwxrwx 1 root root 0 apr 17 00:04 device -> ../../30a30000.i2c
17191 drwxr-xr-x 3 root root 0 apr 17 00:04 i2c-dev
7720 -r--r--r-- 1 root root 4096 apr 17 00:04 name
7721 --w------- 1 root root 4096 apr 16 23:47 new_device
7719 lrwxrwxrwx 1 root root 0 apr 17 00:04 of_node -> ../../../../firmware/devicetree/base/i2c@30a30000
7725 drwxr-xr-x 2 root root 0 apr 17 00:04 power
7724 lrwxrwxrwx 1 root root 0 apr 17 00:04 subsystem -> ../../../../bus/i2c
7718 -rw-r--r-- 1 root root 4096 apr 17 00:04 uevent
We can add the bmp280 device on the address we found on the i2cdetect scan (76):
# echo "bmp280 0x76" > /sys/bus/i2c/devices/i2c-1/new_device
And then we have a new device for the BMP280 sensor (it is loaded as iio/pressure):
# ls -lia /sys/bus/iio/devices/iio\:device0/
totaal 0
21054 drwxr-xr-x 3 root root 0 apr 17 00:08 .
21038 drwxr-xr-x 4 root root 0 apr 17 00:04 ..
21071 -r--r--r-- 1 root root 4096 apr 17 00:08 dev
21061 -rw-r--r-- 1 root root 4096 apr 16 23:47 in_pressure_input
21060 -rw-r--r-- 1 root root 4096 apr 17 00:08 in_pressure_oversampling_ratio
21057 -r--r--r-- 1 root root 4096 apr 17 00:08 in_pressure_oversampling_ratio_available
21059 -rw-r--r-- 1 root root 4096 apr 16 23:47 in_temp_input
21058 -rw-r--r-- 1 root root 4096 apr 17 00:08 in_temp_oversampling_ratio
21056 -r--r--r-- 1 root root 4096 apr 17 00:08 in_temp_oversampling_ratio_available
21062 -r--r--r-- 1 root root 4096 apr 17 00:08 name
21065 drwxr-xr-x 2 root root 0 apr 17 00:08 power
21064 lrwxrwxrwx 1 root root 0 apr 17 00:08 subsystem -> ../../../../../../bus/iio
21055 -rw-r--r-- 1 root root 4096 apr 16 23:47 uevent
And then we can read out the pressure and the temperature by just reading out the 'files':
# cat /sys/bus/iio/devices/iio\:device0/name
bmp280
# cat /sys/bus/iio/devices/iio\:device0/in_pressure_input
101.761613281
# cat /sys/bus/iio/devices/iio\:device0/in_temp_input
21950
Conclusion
With some struggles, I was able to get the i2c bus working. I have the luxury of 2 buses on the GPIO pins, so this gives ample opprtunity to interface with lots of devices, like PWM boards, sensors, GPIO expanders, etc. So far, the maaxboard has exceeded my expectations on this. My only problem so far is the simple fact that the debian image for the maaxboard is not quite ready for general use, it is still a work in progress.