背景
由于项目需要使用了Banana Pi R2这块板子。参考的资料主要是官方的wiki、GitHub以及论坛。
- 官网:http://banana-pi.org/
- Wiki:http://wiki.banana-pi.org/Main_Page
- 论坛:http://forum.banana-pi.org/
- 镜像:https://dev.banana-pi.org.cn/Image/BPI-R2/Ubuntu16.04/
- BSP:https://github.com/BPI-SINOVOIP/BPI-R2-bsp-4.14
初探
先使用官方提供的镜像,制作SD卡启动盘,查看效果。
宿主机环境:
root@liu:~# uname -a
Linux liu 4.15.0-45-generic #48~16.04.1-Ubuntu SMP Tue Jan 29 18:03:48 UTC 2019 x86_64 x86_64 x86_64 GNU/Linux
从官网下载最新镜像:
2017-11-28-ubuntu-16.04-mate-desktop-bpi-r2-sd-emmc.img.zip
安装工具:
root@liu:~# apt install -y gcc-arm-linux-gnueabihf u-boot-tools curl pv
root@liu:~# curl -sL https://github.com/BPI-SINOVOIP/bpi-tools/raw/master/bpi-tools | sudo -E bash
格式化SD卡 (需要保证SD卡的容量是8G或者以上的)
查看SD卡对应的盘符
root@liu:~# fdisk –l
删除SD的所有分区
root@liu:~# fdisk /dev/sdx
格式化SD卡位FAT模式
root@liu:~# mkfs.vfat /dev/sdx -I
烧写镜像到SD卡
root@liu:~# dd if=[imagename] of=/dev/sdx bs=10M
定制系统
官方的镜像太庞杂,希望自己可以定制一个。
编译BSP
先清空之前的内容
root@liu:~# cd /root/src/BPI-R2-bsp-4.14
root@liu:~# ./build.sh
选择 7
重新编译
root@liu:~# ./build.sh
选择 1
需要等待一会,该过程会编译u-boot、kerenl、以及打包。
配置内核选项
配置pty
在内核中选择Unix98 PTY,这样会在/dev/下生成pts目录,及pty节点。如果不配置,会出现下面的现象:ssh连接上了,但是不显示shell终端。
Welcome to Ubuntu 16.04.6 LTS (GNU/Linux 4.14.34-BPI-R2-Kernel armv7l)
* Documentation: https://help.ubuntu.com
* Management: https://landscape.canonical.com
* Support: https://ubuntu.com/advantage
配置串口扩展芯片支持
USB FTDI Single Port Serial Driver
配置overlay文件系统
<*> Overlay filesystem support
[*] Overlayfs: turn on redirect dir feature by default
[*] Overlayfs: turn on inodes index feature by default
这个docker依赖的底层文件系统。
创建文件系统
安装依赖工具包
root@liu:~# apt-get install qemu-user-static debootstrap binfmt-support parted zip
从官网下载Ubuntu16的最小文件系统
http://cdimage.ubuntu.com/ubuntu-base/releases/16.04/release/
root@liu:~# mkdir rootfs
root@liu:~# tar xvf ubuntu-base-16.04-core-armhf.tar.gz -C rootfs
利用qemu和chroot
cp /etc/resolv.conf rootfs/etc/resolv.conf
root@liu:~# cp /usr/bin/qemu-arm-static rootfs/usr/bin/
root@liu:~# chroot /root/image/rootfs
现在通过qemu模拟器进入了刚制作的根文件系统
root@liu:/# ls
bin boot dev etc home lib media mnt opt proc root run sbin srv sys tmp usr var
root@liu:/# pwd
/
更新apt源
root@liu:~# vi /etc/apt/sources.list
deb http://ports.ubuntu.com/ubuntu-ports/ xenial main restricted
deb-src http://ports.ubuntu.com/ubuntu-ports/ xenial main restricted
deb http://ports.ubuntu.com/ubuntu-ports/ xenial universe
deb-src http://ports.ubuntu.com/ubuntu-ports/ xenial universe
deb http://ports.ubuntu.com/ubuntu-ports/ xenial multiverse
deb-src http://ports.ubuntu.com/ubuntu-ports/ xenial multiverse
deb http://ports.ubuntu.com/ubuntu-ports/ xenial-updates main restricted
deb-src http://ports.ubuntu.com/ubuntu-ports/ xenial-updates main restricted
deb http://ports.ubuntu.com/ubuntu-ports/ xenial-updates universe
deb-src http://ports.ubuntu.com/ubuntu-ports/ xenial-updates universe
deb http://ports.ubuntu.com/ubuntu-ports/ xenial-security main restricted
deb-src http://ports.ubuntu.com/ubuntu-ports/ xenial-security main restricted
deb http://ports.ubuntu.com/ubuntu-ports/ xenial-security multiverse
deb-src http://ports.ubuntu.com/ubuntu-ports/ xenial-security multiverse
root@liu:~# apt update
root@liu:~# apt upgrade
root@liu:~# apt-get dist-upgrade
安装必备包
root@liu:~# apt install language-pack-en-base sudo ssh net-tools ethtool wireless-tools ifupdown network-manager iputils-ping rsyslog bash-completion vim minicom lrzsz gcc ntpdate kmod
- ntpdate,如果系统时间不准,可以通过ntpdate cn.pool.ntp.org,进行更新
- kmod,这个安装包是包含modprobe等命令的,如果没有它,后续运行docker会有问题。
设置DNS
# vi /etc/resolv.conf
nameserver 127.0.1.1
nameserver 8.8.8.8
如果不设置,能上网,但ping不通百度。
# ping www.baidu.com
ping: unknown host www.baidu.com
设置主机名
root@liu:~# echo "bpi-r2" >/etc/hostname
root@liu:~# vi /etc/hosts
127.0.0.1 localhost
127.0.1.1 bpi-r2
# The following lines are desirable for IPv6 capable hosts
::1 ip6-localhost ip6-loopback
fe00::0 ip6-localnet
ff00::0 ip6-mcastprefix
ff02::1 ip6-allnodes
ff02::2 ip6-allrouters
设置root用户对于的密码
root@liu:/# passwd
Enter new UNIX password:
Retype new UNIX password:
passwd: password updated successfully
创建普通用户
root@liu:~# useradd -m -G users,sudo,ssh -s /bin/bash bpi
root@liu:~# passwd bpi
Enter new UNIX password:
Retype new UNIX password:
passwd: password updated successfully
设置时区
root@liu:~# locale-gen en_US
root@liu:~# locale-gen en_US.UTF-8
root@liu:~# dpkg-reconfigure tzdata
root@liu:~# update-locale LANG=en_US.UTF-8
设置fstab
root@liu:~# vi /etc/fstab
proc /proc proc defaults 0 0
LABEL=BPI-BOOT /boot vfat errors=remount-ro 0 1
LABEL=BPI-ROOT / ext4 defaults,noatime 0 0
设置网络
root@liu:~# vi /etc/network/interfaces
# loop
auto lo
iface lo inet loopback
#first set the upstream-Port (NIC between CPU and MT7530-Switch) up
auto eth0
iface eth0 inet manual
pre-up ip link set $IFACE up
post-down ip link set $IFACE down
auto eth1
iface eth1 inet manual
pre-up ip link set $IFACE up
post-down ip link set $IFACE down
#then configure the lan-ports
auto lan0
iface lan0 inet static
address 172.16.30.252
netmask 255.255.255.0
gateway 172.16.30.1
pre-up ip link set $IFACE up
post-down ip link set $IFACE down
修改ssh配置
root@liu:~# vi /etc/ssh/sshd_config
PermitRootLogin yes
PubkeyAuthentication no
#AuthorizedKeysFile .ssh/authorized_keys
PasswordAuthentication yes
无网络开机慢
现象: Ubuntu 16.04开机
A start job is running for Raise network interface(5min 4s)
解决方式:
vim /etc/systemd/system/network-online.target.wants/networking.service
将里面的TimeoutStartSec=5min 修改为TimeoutStartSec=5sec
重启系统
安装docker
参考:https://docs.docker.com/engine/install/ubuntu/
安装完之后,默认是没有/etc/docker/daemon.json这个文件的。新建该文件:
# vi /etc/docker/daemon.json
{
"registry-mirrors": ["http://hub-mirror.c.163.com"]
}
清理不必要的包
root@liu:~# rm -rf /var/lib/apt/lists/*
root@liu:~# apt clean
退出qemu
root@liu:~# exit
root@liu:~# rm /root/image/rootfs/usr/bin/qemu-arm-static
制作镜像文件
创建一个新的image文件,大小为8G
root@liu:~# dd if=/dev/zero bs=1M count=7296 | pv | dd of=bpi.img
加载该镜像为虚拟盘
root@liu:~# losetup /dev/loop8 bpi.img
分区并且格式化
root@liu:~# parted -s /dev/loop8 mklabel msdos
root@liu:~# parted -s /dev/loop8 unit MiB mkpart primary fat32 -- 100MiB 356MiB
root@liu:~# parted -s /dev/loop8 unit MiB mkpart primary ext2 -- 356MiB 7295MiB
root@liu:~# partprobe /dev/loop8
root@liu:~# mkfs.vfat /dev/loop8p1 -I -n BPI-BOOT
root@liu:~# mkfs.ext4 -O ^has_journal -E stride=2,stripe-width=1024 -b 4096 /dev/loop8p2 -L BPI-ROOT
root@liu:~# sync
挂载文件系统
root@liu:~# mkdir /mnt/rootfs
root@liu:~# mount /dev/loop8p2 /mnt/rootfs
root@liu:~# mkdir /mnt/rootfs/boot
root@liu:~# mount /dev/loop8p1 /mnt/rootfs/boot
拷贝之前制作的文件系统到该镜像
root@liu:~# cp -a /root/image/rootfs/* /mnt/rootfs
进入BSP目录
root@liu:~# cd /root/src/BPI-R2-bsp-4.14
拷贝boot分区文件:BPI-BOOT-bpi-r2.tgz
root@liu:~# tar xvf SD/BPI-BOOT-bpi-r2.tgz --keep-directory-symlink -C /mnt/rootfs/boot
拷贝内核文件:4.14.34-BPI-R2-Kernel.tgz、4.14.34-BPI-R2-Kernel-net.tgz
root@liu:~# tar xvf SD/4.14.34-BPI-R2-Kernel.tgz --keep-directory-symlink -C /mnt/rootfs
root@liu:~# tar xvf SD/4.14.34-BPI-R2-Kernel-net.tgz --keep-directory-symlink -C /mnt/rootfs
拷贝BootLoader文件:BOOTLOADER-bpi-r2.tgz
root@liu:~# tar xvf SD/BOOTLOADER-bpi-r2.tgz --keep-directory-symlink -C /mnt/rootfs
把电源按键放到黑名单
root@liu:~# echo "blacklist mtk_pmic_keys" > /mnt/rootfs/etc/modules-load.d/mtk_pmic_keys.conf
卸载文件系统
root@liu:~# umount /mnt/rootfs/boot
root@liu:~# umount /mnt/rootfs
写入头文件: BPI-R2-HEAD440-0k.img、BPI-R2-HEAD1-512b.img
root@liu:~# dd if=mt-pack/mtk/bpi-r2/bin/BPI-R2-HEAD440-0k.img of=/dev/loop8 bs=1024 seek=0
root@liu:~# dd if=mt-pack/mtk/bpi-r2/bin/BPI-R2-HEAD1-512b.img of=/dev/loop8 bs=512 seek=1
写入preloader:preloader_iotg7623Np1_sd_1600M.bin 和u-boot:u-boot.bin
root@liu:~# dd if=mt-pack/mtk/bpi-r2/bin/preloader_iotg7623Np1_sd_1600M.bin of=/dev/loop8 bs=1024 seek=2
root@liu:~# dd if=u-boot-mt/u-boot.bin of=/dev/loop8 bs=1024 seek=320
root@liu:~# sync
删除loop盘
root@liu:~# losetup -d /dev/loop8
把镜像写入SD卡
root@liu:~# fdisk -l
root@liu:~# dd if=/root/image/bpi.img of=/dev/sdx bs=10M
脚本
上面的命令,集成到脚本文件中
#!/bin/bash -v
IMAGE=/root/image/bpi.img
BSP=/root/BPI-R2-bsp-4.14
[ -f $IMAGE ] && rm $IMAGE
sudo dd if=/dev/zero bs=1M count=7296 | pv | dd of=$IMAGE
sudo losetup /dev/loop8 $IMAGE
sudo parted -s /dev/loop8 mklabel msdos
sudo parted -s /dev/loop8 unit MiB mkpart primary fat32 -- 100MiB 356MiB
sudo parted -s /dev/loop8 unit MiB mkpart primary ext2 -- 356MiB 7295MiB
sudo partprobe /dev/loop8
sudo mkfs.vfat /dev/loop8p1 -I -n BPI-BOOT
sudo mkfs.ext4 -O ^has_journal -E stride=2,stripe-width=1024 -b 4096 /dev/loop8p2 -L BPI-ROOT
sync
[ -d /mnt/rootfs ] || sudo mkdir /mnt/rootfs
sudo mount /dev/loop8p2 /mnt/rootfs
[ -d /mnt/rootfs/boot ] || sudo mkdir /mnt/rootfs/boot
sudo mount /dev/loop8p1 /mnt/rootfs/boot
sudo cp -a /root/image/rootfs/* /mnt/rootfs
cd $BSP
sudo tar xvf SD/BPI-BOOT-bpi-r2.tgz --keep-directory-symlink -C /mnt/rootfs/boot
sudo tar xvf SD/4.14.34-BPI-R2-Kernel.tgz --keep-directory-symlink -C /mnt/rootfs
sudo tar xvf SD/4.14.34-BPI-R2-Kernel-net.tgz --keep-directory-symlink -C /mnt/rootfs
sudo tar xvf SD/BOOTLOADER-bpi-r2.tgz --keep-directory-symlink -C /mnt/rootfs
sudo umount /mnt/rootfs/boot
sudo umount /mnt/rootfs
sudo dd if=mt-pack/mtk/bpi-r2/bin/BPI-R2-HEAD440-0k.img of=/dev/loop8 bs=1024 seek=0
sudo dd if=mt-pack/mtk/bpi-r2/bin/BPI-R2-HEAD1-512b.img of=/dev/loop8 bs=512 seek=1
sudo dd if=mt-pack/mtk/bpi-r2/bin/preloader_iotg7623Np1_sd_1600M.bin of=/dev/loop8 bs=1024 seek=2
sudo dd if=u-boot-mt/u-boot.bin of=/dev/loop8 bs=1024 seek=320
sync
sudo losetup -d /dev/loop8
sudo dd if=$IMAGE of=/dev/sdc bs=10M
应用
业务层面需要使用操作GPIO和UART,需要注意的的一些细节如下。
GPIO
查看GPIO的基数,可以看到是:232
root@liu:~# mount -t debugfs none /sys/kernel/debug
root@liu:~# cat /sys/kernel/debug/pinctrl/1000b000.pinctrl/gpio-r
GPIO ranges handled:
0: 1000b000.pinctrl GPIOS [232 - 511] PINS [0 - 279]
以GPIO205为例,具体的值为,437(232+205) 操作方式如下
root@liu:~# echo 437 > /sys/class/gpio/export
root@liu:~# echo out > /sys/class/gpio/gpio437/direction
root@liu:~# echo 1 > /sys/class/gpio/gpio437/value
root@liu:~# echo 292 > /sys/class/gpio/unexport
UART
通过设备数可以了解到终端使用的是ttyS0,对应关系如下
- ttyS0 <–> Uart2
- ttyS1 <–> Uart0
- ttyS2 <–> Uart1
设备数信息
root@liu:~# vi linux-mt/arch/arm/boot/dts/mt7623.dtsi
uart2: serial@11004000 {
compatible = "mediatek,mt7623-uart",
"mediatek,mt6577-uart";
reg = <0 0x11004000 0 0x400>;
interrupts = <GIC_SPI 53 IRQ_TYPE_LEVEL_LOW>;
clocks = <&pericfg CLK_PERI_UART2_SEL>,
<&pericfg CLK_PERI_UART2>;
clock-names = "baud", "bus";
status = "disabled";
};
uart0: serial@11002000 {
compatible = "mediatek,mt7623-uart",
"mediatek,mt6577-uart";
reg = <0 0x11002000 0 0x400>;
interrupts = <GIC_SPI 51 IRQ_TYPE_LEVEL_LOW>;
clocks = <&pericfg CLK_PERI_UART0_SEL>,
<&pericfg CLK_PERI_UART0>;
clock-names = "baud", "bus";
status = "disabled";
};
uart1: serial@11003000 {
compatible = "mediatek,mt7623-uart",
"mediatek,mt6577-uart";
reg = <0 0x11003000 0 0x400>;
interrupts = <GIC_SPI 52 IRQ_TYPE_LEVEL_LOW>;
clocks = <&pericfg CLK_PERI_UART1_SEL>,
<&pericfg CLK_PERI_UART1>;
clock-names = "baud", "bus";
status = "disabled";
};
root@liu:~# vi linux-mt/arch/arm/boot/dts/mt7623n-bananapi-bpi-r2.dts
uart0_pins_a: uart@0 {
pins_dat {
pinmux = <MT7623_PIN_79_URXD0_FUNC_URXD0>,
<MT7623_PIN_80_UTXD0_FUNC_UTXD0>;
};
};
uart1_pins_a: uart@1 {
pins_dat {
pinmux = <MT7623_PIN_81_URXD1_FUNC_URXD1>,
<MT7623_PIN_82_UTXD1_FUNC_UTXD1>;
};
};
&uart0 {
pinctrl-names = "default";
pinctrl-0 = <&uart0_pins_a>;
status = "okay";
};
&uart1 {
pinctrl-names = "default";
pinctrl-0 = <&uart1_pins_a>;
status = "okay";
};
&uart2 {
status = "okay";
};
参考
http://www.fw-web.de/dokuwiki/doku.php?id=en:bpi-r2:start
http://forum.banana-pi.org/t/how-to-build-an-ubuntu-debian-sd-image-from-scratch/6805
http://forum.banana-pi.org/t/gpio-uart-not-the-debug-port/3748/6