2018/01/31

如何在 PC 編譯 open source project 給 raspberry pi,以 NTP 為例

Why

很多 open source project 都很大,放在 pi 編譯有兩個缺點,第一很費時,第二很浪費空間。所以在 PC 編譯好之後再 install 到 pi 會是一個很好的選擇。如果 open source 專案只有提供 Makefile,那就直接把編譯相關的指向到 pi 的 tools。很多大型專案會提供 configure 來進行編譯設定,那就需要透過 configure 來設定 cross 了。以下就透過 ntp 這個專案來說明,其他專案也大同小異。

How

首先要下載原始碼,如果有更新的版本,請自行調整。
wget http://archive.ntp.org/ntp4/ntp-4.2/ntp-4.2.8p10.tar.gz

參考 Cross-compilingNTP host 是目標機器,build 是編譯機器,所以我們要分別在 PC 跟 pi 上面執行 config.guess
PC: x86_64-unknown-linux-gnu
pi: armv7l-unknown-linux-gnueabihf
知道 host 跟 build 該怎麼填之後,還要設定一些編譯要用的環境變數
export RPI_BASE=${HOME}/rpi
export CROSS=${RPI_BASE}/tools/arm-bcm2708/gcc-linaro-arm-linux-gnueabihf-raspbian-x64/bin/arm-linux-gnueabihf-
export CC=${CROSS}gcc
export AR=${CROSS}ar
export LD=${CROSS}ld
export AS=${CROSS}as
再來就要準備編譯了
mkdir target_pi
cd target_pi
../configure --host=armv7l-unknown-linux-gnueabihf --build=x86_64-unknown-linux-gnu --with-yielding-select=yes
make
make DESTDIR=`pwd`/Built install

跑完之後,就會在 Built 裡面建立需要安裝的檔案,tar 起來到 pi 的跟目錄下解 tar 就完成安裝了


2018/01/30

在 PC 編譯 wiringPi

參考了 raspberry pi 操控 gpio 的幾個方法
原本最想要的是直接存取,不知道哪裡沒弄好,gpio8 以上的行為怪怪的,只能 out,設定成 in 時,不管是拉 3.3v 還是 gnd 都是 low,所以改用 wiringpi 來處理。基於上篇,還是在 PC 上編譯 wiringPi 再拿去 raspberry pi 執行。

下載 wiringPi 原始碼

參考官網
git clone git://git.drogon.net/wiringPi

編譯主元件

需要編譯的內容是 wiringPi 和 devLib 這兩支,因為原先的 Makefile 內容是放在 raspberry pi 上編譯用的,所以需要做一些小小的調整,以便符合在 PC 上進行 cross compile。

wiringPi/Makefile 在 LIBS = 後面追加下列內容來蓋掉前面的設定
RPI_BASE := $(HOME)/rpi
CROSS := $(RPI_BASE)/tools/arm-bcm2708/gcc-linaro-arm-linux-gnueabihf-raspbian-x64/bin/arm-linux-gnueabihf-
CC := $(CROSS)gcc
AR := $(CROSS)ar
RANLIB := $(CROSS)ranlib

devLib/Makefile 一樣在 LIBS = 後面追加
RPI_BASE := $(HOME)/rpi
CROSS := $(RPI_BASE)/tools/arm-bcm2708/gcc-linaro-arm-linux-gnueabihf-raspbian-x64/bin/arm-linux-gnueabihf-
CC := $(CROSS)gcc
AR := $(CROSS)ar
RANLIB := $(CROSS)ranlib
INCLUDE += -I../wiringPi

原先的 Makefile 只編出 shared object,如果想要編出 static object,就在 all: 追加 $(STATIC) 就可以了。

編譯 gpio

因為是要先測試功能,所以使用 static object 的 wiringPi 元件,這樣就只需要把 gpio 程式放到 nfs 就能執行。

gpio/Makefile 還是在 LIBS = 後面追加
RPI_BASE := $(HOME)/rpi
CROSS := $(RPI_BASE)/tools/arm-bcm2708/gcc-linaro-arm-linux-gnueabihf-raspbian-x64/bin/arm-linux-gnueabihf-
CC := $(CROSS)gcc
AR := $(CROSS)ar
RANLIB := $(CROSS)ranlib
INCLUDE += -I../wiringPi -I../devLib
LDFLAGS += -L../wiringPi -L../devLib

把 gpio 放到 nfs 上面,把 raspberrypi 的 v33 接到 gpio26 進行測試,改接gnd 再測,再改回 v33 再測,終於可以正常當 input 了。

安裝 shared object

如果有多支程式需要用到 wiringPi,做成 shared object 會比較理想。先把編譯好的 libwiringPi.so.2.44 和 libwiringPiDev.so.2.44 複製到 host 的 nfs 上,然後從 raspberrypi 上複製到 /lib 同時處理 symbolic link。
sudo cp /mnt/nfs/libwiringPi.so.2.44 /lib
sudo ln -s /lib/libwiringPi.so.2.44 /lib/libwiringPi.so
sudo cp /mnt/nfs/libwiringPiDev.so.2.44 /lib
sudo ln -s /lib/libwiringPiDev.so.2.44 /lib/libwiringPiDev.so



完成

基本上到此已經能完全操控 gpio,如果為了效能跟空間,可以參考 wiringPi 的 gpio,把不需要的拿掉,放到自己的程式內部。由於 gpio 需要 sudo 執行,基於安全上的考量,可能要改寫成 gpiod,再透過 ipc 跟 shared memory 去要求或進行控制。

2018/01/27

Raspberry Pi 開發環境建置

raspberry pi 可以直接使用 debian linux 發行套件,安裝 makefile 跟 gcc 就可以拿 source code 去編譯,但是編譯速度絕對不比高速 x86 桌機,遇到需要除錯的程式,還是在 x86 linux 上面編譯好再給 raspberry pi 跑會是一個比較省時間的做法。想法很簡單,就是在 x86 linux 上安裝 raspberry pi cross tools,然後透過 nfs 讓 raspberry pi 直接 mount 去執行。

我目前使用的 x86 linux 是 debian 9 amd64,所以以下內容將以此為基準,使用 debian based 的發行套件應該都能直接套用,其他發行套件可能要做些修改。

安裝 cross tools


編譯環境不該使用 root,所以請用一般 user 登入,把 toolchain 放在 home

aimwang@debian:~$ mkdir rpi
aimwang$debian:~$ cd rpi
aimwang@debian:~/rpi$ git clone https://github.com/raspberrypi/tools.git

安裝並設定 nfs server


aimwang@debian:~$ sudo apt-get install nfs-kernel-server nfs-common
aimwang@debian:~$ sudo mkdir /srv/nfs
aimwang@debian:~$ sudo chmod 777 /srv/nfs

/etc/exports 最後增加 (IP 根據自己的環境改)
/srv/nfs 192.168.22.*(rw,sync,no_subtree_check,no_root_squash)

重新啟動 nfs server
aimwang@debian:~$ sudo /etc/init.d/nfs-kernel-server restart

準備編譯 hello world 等一下要透過 nfs 餵給 raspberry pi 執行
Makefile
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
ROOT_PATH := $(PWD)
RPI_BASE := $(HOME)/rpi
NFS_PATH := /srv/nfs
CROSS := $(RPI_BASE)/tools/arm-bcm2708/gcc-linaro-arm-linux-gnueabihf-raspbian-x64/bin/arm-linux-gnueabihf-
CC := $(CROSS)gcc

all: hello nfs

nfs:
 @cp -f hello $(NFS_PATH)/.

hello:
 @$(CC) $(CFLAGS) -o hello hello.c

clean:
 @rm -f hello
hello.c
1
2
3
4
5
6
7
8
#include <stdio.h>
#include <stdlib.h>

void main (void)
{
 printf ("Hello world!\n");
 exit (0);
}

編譯啦
aimwang@debian:~/project/rpi/hello$ make

Raspberry Pi mount nfs 及執行

pi@raspberrypi:~ $ sudo mount -t nfs 192.168.22.200:/srv/nfs /mnt/nfs
pi@raspberrypi:~ $ /mnt/nfs/gpio
Hello world!

完成