DevOps 树莓派实践例程(一)

lalalatang · January 29, 2020 · 104 hits

利用树莓派做的几个示例

前提:在 raspbian 系统下试验

安装编译器(在宿主机 Ubuntu 下)

  1. 下载树莓派交叉编译工具https://github.com/raspberrypi/tools
  2. 将源码放到各用户都能 share 的文件夹下,如/usr/toolsexe(建议放到 tools 中,这里我 tools 有其他用途因此放到 toolsexe 中)
  3. 将交叉编译工具的路径加到环境变量中,为了以后启动不用再设置,我加到了~/.bashrc 中
    123
    $vi ~/.bashrc#在文件的末尾加上export PATH=$PATH:/usr/toolsexe/arm-bcm2708/gcc-linaro-arm-linux-gnueabihf-raspbian-x64/bin$source .bashrc

更改文件夹内所有文件属性
chmod -R 777 ./toolsexe

以上方法没有验证

在 Ubuntu 下直接用命令行安装
apt-get install gcc-arm-linux-gnueabi make ncurses-dev

arm-linux-gnueabi-gcc led.c -o led执行编译操作,生成的文件 led 是在树莓派上执行的程序,拷贝到树莓派文件夹下,用./led命令执行

sudo apt install g++-arm-linux-gnueabi安装 g++ 编译器

GPIO 控制

  1. 确定使用的 GPIO 引脚,这里选择用 GPIO2,实现功能为点亮/熄灭指示灯
  2. 跳转到cd /sys/class/gpio文件夹,导出相应的 gpio,echo 2 > export,执行该命令后 gpio 文件夹会出现 gpio2 子目录
  3. 设置 gpio 方向为输出
    echo out > /sys/class/gpio/gpio2/direction
  4. echo 1 > /sys/class/gpio/gpio2/value输出高电平或者echo 0 > /sys/class/gpio/gpio2/value输出低电平
    效果图:

/sys/class/gpio 的使用说明(转):
gpio_operation 通过/sys/文件接口操作 IO 端口 GPIO 到文件系统的映射

  • 控制 GPIO 的目录位于/sys/class/gpio
  • /sys/class/gpio/export 文件用于通知系统需要导出控制的 GPIO 引脚编号
  • /sys/class/gpio/unexport 用于通知系统取消导出
  • /sys/class/gpio/gpiochipX 目录保存系统中 GPIO 寄存器的信息,包括每个寄存器控制引脚的起始编号 base,寄存器名称,引脚总数 导出一个引脚的操作步骤
  • 首先计算此引脚编号,引脚编号 = 控制引脚的寄存器基数 + 控制引脚寄存器位数
  • 向/sys/class/gpio/export 写入此编号,比如 12 号引脚,在 shell 中可以通过以下命令实现,命令成功后生成/sys/class/gpio/gpio12 目录,如果没有出现相应的目录,说明此引脚不可导出:
    echo 12 > /sys/class/gpio/export
  • direction 文件,定义输入输入方向,可以通过下面命令定义为输出
    echo out > direction
  • direction 接受的参数:in, out, high, low。high/low 同时设置方向为输出,并将 value 设置为相应的 1/0。
  • value 文件是端口的数值,为 1 或 0.
    echo 1 > value

上文是在 SHELL 下直接控制,接下来介绍如何用 C 程序通过 GPIO2 控制指示灯

C 源程序如下 (文件命名为 led.c):

123456789101112131415161718192021222324252627282930
#include <stdio.h>#include <stdlib.h>#include <unistd.h>#include <string.h>int main(void){  FILE *p=NULL;   int i=0;    p = fopen("/sys/class/gpio/export","w");    fprintf(p,"%d",2);  fclose(p);  p = fopen("/sys/class/gpio/gpio2/direction","w");   fprintf(p,"out");   fclose(p);  for(i=0;i<100;i++)   {       p = fopen("/sys/class/gpio/gpio2/value","w");       fprintf(p,"%d",1);      sleep(1);       fclose(p);      p = fopen("/sys/class/gpio/gpio2/value","w");       fprintf(p,"%d",0);      sleep(1);       fclose(p);  }   p = fopen("/sys/class/gpio/unexport","w");  fprintf(p,"%d",2);  fclose(p);  return 0;}

将 led.c 文件在 Ubuntu 下编译生成 led 文件
arm-linux-gnueabi-gcc led.c -o led

将 led 文件拷贝到树莓派某一文件夹下输入./led,执行程序,现象为指示灯闪烁 100 次后结束。

UART 操作

树莓派 3 的 UART 串口的使用问题可参考Raspberry Pi 3 UART Boot Overlay Part Two

对于树莓派 3 B+ 来说,uart 功能有三种: 1、内部蓝牙使用 2、控制终端使用 3、与其他设备进行串口通信;
然而 树莓派 3 确只提供一个硬件 uart,对应硬件接口 p14-TX/P15-RX。所有树莓派 3 的串口只能是鱼与熊掌不能兼得了。
树莓派 官方系统 Raspbian Jessie releases 默认串口是给蓝牙使用。如果想让串口作为控制终端调试口即 serial console,则需要对系统配置进行修改,关闭蓝牙并且映射 pl011 UART 到 p14 和 p15
一、使能 serial console 步骤如下:

  1. 安装系统并配置系统
    Raspbian Jessie releases 系统安装到 sd 卡上。
    配置系统:sudo raspi-config
    执行:

    123
    Expand filesystem  and enable serial on advanced page exit and rebootsudo apt-get update sudo apt-get upgrade
  2. 设置 Device tree
    sudo vi /boot/config.txt
    在文件末尾添加:
    dtoverlay=pi3-miniuart-bt
    sudo reboot

  3. 使能串口终端 serial console
    编辑 /boot/cmdline.txt 文件
    sudo vi /boot/cmdline.txt
    将文件内容改为
    dwc_otg.lpm_enable=0 console=tty1 console=serial0,115200 root=/dev/mmcblk0p2 rootfstype=ext4 elevator=deadline fsck.repair=yes rootwait
    核对一下,可能不需要更改

树莓派内核编译

参考https://www.raspberrypi.org/documentation/linux/kernel/building.md

  1. 下载树莓派内核
  2. 到内核目录执行sudo make mrproper,保证内核树的绝对干净
  3. 执行 find ./ -name “bcmdefconfig*” 查找下对应的默认配置
    123456
    ./arch/mips/configs/bcm47xx_defconfig./arch/mips/configs/bcm63xx_defconfig./arch/arm/configs/bcm_defconfig./arch/arm/configs/bcm2709_defconfig./arch/arm/configs/bcmrpi_defconfig./arch/arm/configs/bcm2835_defconfig

Pi 1 使用 bcmrpi_defconfig
Pi 2/3 使用 bcm2709_defconfig

12345
KERNEL=kernel7#目录切换到内核源文件下,配置默认设置:sudo make ARCH=arm CROSS_COMPILE=arm-linux-gnueabi-gcc bcm2709_defconfig(默认配置,结果保存在内核源文件夹下.config中)#配置内核模块(可手动修改),执行sudo make ARCH=arm CROSS_COMPILE=arm-linux-gnueabi-gcc menuconfig

显示下图说明参数设置成功

编译内核镜像
sudo make ARCH=arm CROSS_COMPILE=arm-linux-gnueabi- -j4 zImage modules dtbs(要将编译器命令的 gcc 去掉,zImage dtbs 不能省,要编译很久)
-j4:表示多核处理

将编译好的 Linux 内核复制出來:

12
sudo scripts/mkknlimg arch/arm/boot/zImage ../kernel-new.img(安装好tools)#sudo cp arch/arm/boot/Image ../kernel-new.img

安装 modules:
sudo make -j4 ARCH=arm CROSS_COMPILE=arm-linux-gnueabi- INSTALL_MOD_PATH=../modules modules_install(要将编译器命令的 gcc 去掉)

另外有三个文件目录:

123
sudo cp arch/arm/boot/dts/*.dtb /boot/sudo cp arch/arm/boot/dts/overlays/*.dtb* /boot/overlays/sudo cp arch/arm/boot/dts/overlays/README /boot/overlays/

小结:要将编译后拷贝到树莓派 SD 卡上的文件有:

  1. 生成的 kernel-new.img 复制到/boot/
  2. 将 modules/lib/modules/* 文件夹复制到/lib/modules/
  3. arch/arm/boot/dts/*.dtb 复制到/boot/
  4. arch/arm/boot/dts/overlays/.dtb复制到/boot/overlays/
  5. arch/arm/boot/dts/overlays/README 复制到/boot/overlays/

将装有树莓派系统的 SD 卡插在 Linux 系统电脑上,使用 lsblk 指令查看硬盘结构如下图,sdd1(boot 分区) 和 sdd2(root 分区) 为 SD 卡的分区

挂载 SD 卡分区:

1234
sudo mkdir /mnt/fat32sudo mkdir /mnt/ext4sudo mount /dev/sdd1 /mnt/fat32sudo mount /dev/sdd2 /mnt/ext4

1234567891011121314
1. 将kernel-new.img放入boot分区sudo cp kernel-new.img /mnt/fat32/2. 把 modules/lib/modules/ 里面的东西复制到 /lib/modules/sudo cp -r modules/lib/modules/* /mnt/ext4/lib/modules/将 modules/lib/firmware/里面的东西复制到 /lib/firmware/sudo cp -r modules/lib/firmware/* /mnt/ext4/lib/firmware/转到内核源文件目录cd linux/3. arch/arm/boot/dts/*.dtb复制到/boot/sudo cp -r arch/arm/boot/dts/*.dtb  /mnt/fat32/(原本也有,可不操作)4. arch/arm/boot/dts/overlays/*.dtb*复制到/boot/overlays/sudo cp -r arch/arm/boot/dts/overlays/*.dtb*  /mnt/fat32/overlays/5. arch/arm/boot/dts/overlays/README复制到/boot/overlays/sudo cp -r arch/arm/boot/dts/overlays/README  /mnt/fat32/overlays/

sudo vi /mnt/fat32/config.txt 编辑 /boot/config.txt,加入一行
kernel=kernel-new.img

这行是用来指令系统要使用的核心,可以同时放置多个不同核心,以便随时切换。
这样新编译好的核心就安装好了。

最后卸载 SD 卡
sudo umount /mnt/fat32
sudo umount /mnt/ext4

一个模块交叉编译的例子
hello.c 源程序

1234567891011121314151617
#include<linux/module.h>  #include<linux/kernel.h>  #include<linux/init.h>  MODULE_LICENSE("GPL");  static int __init lkp_init(void)  {      printk(KERN_ALERT "Hello World!/n");      return 0;  }  static void __exit lkp_cleanup(void)  {      printk(KERN_ALERT "Bye World!/n");  }  module_init(lkp_init);  module_exit(lkp_cleanup);  MODULE_AUTHOR("lin");  MODULE_DESCRIPTION("hello");

Makefile 文件

12345678
obj-m := hello.o  KERNELBUILD :=/home/lin/Downloads/raspdown/linux#这里指向树莓派linux内核源文件夹default:      make -C $(KERNELBUILD) M=/home/lin/Downloads/raspdown/linux/drivers/testdrive modules   #M值指向你的源文件hello.c和Makefile文件夹 clean:    rm -rf *.o *.ko *.mod.c .*.cmd *.markers *.order *.symvers .tmp_versions

执行生成 hello.ko 文件
sudo make ARCH=arm CROSS_COMPILE=arm-linux-gnueabi-

如果出现类似 “fatal section header offset 32425246532452 in file ‘vmlinux’ is bigger than filesize=35524847” 的问题,重新编译内核镜像和 modules 可以解决

拷贝内核源文件到树莓派
cp -av /usr/src/linux/ /home/pi/
例如:cp -av linux/ /mnt/ext4/home/pi/
设置好相应链接
sudo cd /lib/modules/uname -r/
$ sudo rm build source
$ ln -s /home/pi/linux build
$ ln -s /home/pi/linux source

最后一步 (重要):
Now, we need to fix one more problem: During the cross-compilation build, a couple scripts were compiled for the host. We also need them for the Raspberry Pi. Still on the Pi, this can be checked with e.g.

$ file /home/pi/linux/scripts/recordmcount (returns something with x86-64)
$ cd /home/pi/linux/
$ make scripts(一直敲回车)
$ file /home/pi/linux/scripts/recordmcount (now returns something with 32-bit and ARM)

将 hello.ko 拷贝到树莓派/home/pi/linux/对应的文件夹
转到该文件夹执行
sudo insmod hello.ko
sudo rmmod hello.ko

dmesg 查看消息,如果正常应会出现类似下面显示

12
[ 1205.051527] Hello World!/n[ 1261.434964] Bye World!/n

如果出现 “Invalid module format”,可能没有安装 header(不确定)

1234
sudo apt-cache search linux-headers#查看安装的header执行命令安装相应的header包(在这之前要装bc:apt-get install bc)sudo dpkg -i linux-headers-4.4.23-v7+_4.4.23-v7+-2_armhf.deb

下面是 Ubuntu 下进行内核模块编译过程,作为上述过程参考对比(跳到后文):

Ubuntu 版本信息
$ uname -a
Linux ubuntu 4.4.0-38-generic #57-Ubuntu SMP Tue Sep 6 15:42:33 UTC 2016 x86_64 x86_64 x86_64 GNU/Linux

下载 Ubuntu 系统源码
https://www.kernel.org/pub/linux/kernel
配置内核
$ sudo make x86_64_defconfig(根据电脑默认架构配置)
$ sudo make menuconfig # 进入后直接选 exit。
编译内核
$ sudo make
$ sudo make modules

如果出现 “error: unrecognized command line option ‘-fstack-protector-strong”,则升级 gcc
sudo apt-get install gcc

如果出现 “scripts/sign-file.c:23:30: fatal error: openssl/opensslv.h: No such file or directory”,是编译用到的工具没有安装,执行如下命令安装上相应的工具再进行编译就可以了:
sudo apt-get install git fakeroot build-essential ncurses-dev xz-utils libssl-dev bc

安装内核

此步类似于安装操作系统文件。

1234
$ sudo make modules_install  $ sudo make install  $ cd /boot  $ sudo mkinitramfs -o initrd.img-4.4.0 4.4.0

配置开机启动菜单

1234
$ sudo vi /etc/default/grub # 行“GRUB_HIDDEN_TIMEOUT=0”,由0改为30  ##没操作$ sudo vi /etc/grub.d/30_os-prober # 行“timeout = 0”,由0改为30  # update-grub  $ sudo reboot (开机选项选择相应的内核,这里操作后系统只出现命令行,存疑)

参考http://blog.csdn.net/heyutao007/article/details/5737861

$ uname -a
Linux ubuntu 4.4.0-42-generic #62-Ubuntu SMP Fri Oct 7 23:11:45 UTC 2016 x86_64 x86_64 x86_64 GNU/Linux

在此系统上加载一个简单模块步骤 (用于入门):
hello.c 源程序

1234567891011121314151617
#include<linux/module.h>  #include<linux/kernel.h>  #include<linux/init.h>  MODULE_LICENSE("GPL");  static int __init lkp_init(void)  {      printk(KERN_ALERT "Hello World!/n");      return 0;  }  static void __exit lkp_cleanup(void)  {      printk(KERN_ALERT "Bye World!/n");  }  module_init(lkp_init);  module_exit(lkp_cleanup);  MODULE_AUTHOR("lin");  MODULE_DESCRIPTION("hello");

Makefile 文件,注意 TAB

123456
obj-m := hello.o  KERNELBUILD :=/lib/modules/$(shell uname -r)/build  default:     make -C $(KERNELBUILD) M=$(shell pwd) modules  clean:   rm -rf *.o *.ko *.mod.c .*.cmd *.markers *.order *.symvers .tmp_versions

执行 sudo make,可以生成 hello.ko 文件

插入模块,让其工作
sudo insmod ./hello.ko
卸载模块
sudo rmmod ./hello.ko
用 dmesg 可以看到生成信息类似

12
[  901.467267] Hello World!/n[ 1279.121072] Bye World!/n

参考http://elinux.org/Raspberry_Pi_Kernel_Compilation

No Reply at the moment.
You need to Sign in before reply, if you don't have an account, please Sign up first.