树莓派调试记录

(主机环境:Ubuntu 20.04.2 LTS 、树莓派:Raspberry Pi 4 Model B)

树莓派官网:Teach, Learn, and Make with Raspberry Pi

树莓派Github:https://github.com/raspberrypi

树莓派配置:Raspberry Pi Documentation - Configuration

树莓派论坛:Raspberry Pi Forums - Index page

树莓派镜像烧录工具 (Windows):https://downloads.raspberrypi.org/imager/imager_latest.exe

树莓派镜像:Operating system images – Raspberry Pi


一、获取Raspberry Kernel源码

cd ~/raspberry/linux                #选择源码下载位置(自定义)
sudo apt-get install git            #安装git

#官方的github地址,获取源码
git clone --depth=1 --branch rpi-5.13.y https://github.com/raspberrypi/linux

# --depth=1 获取最近的一次commit
# --branch 指定分支

二、构建 Raspberry Pi 的交叉编译器  

(文件夹名称和路径有些是自定义的,注意区分)

1、首先,确保系统已更新并安装所需的依赖包:

sudo apt update
sudo apt upgrade
sudo apt install build-essential gawk git texinfo bison file wget
sudo apt-get install git bison flex libssl-dev zip libncurses-dev make

2、我测试时,Raspbian 自带 GCC 8.3.0、Binutils 2.31.1 和 Glibc 2.28。所以使用相同的 Glibc 版本构建我们的交叉编译器,避免出现其他问题。查看版本的命令:

gcc --version
ld -v
ldd --version

3、在用户目录下创建一个文件夹,下载 binutils-2.31.tar.bz2、gcc-8.3.0.tar.gz、glibc-2.28.tar.bz2

cd ~
mkdir gcc_all 
cd gcc_all
wget https://ftpmirror.gnu.org/binutils/binutils-2.31.tar.bz2
wget https://ftpmirror.gnu.org/glibc/glibc-2.28.tar.bz2
wget https://ftpmirror.gnu.org/gcc/gcc-8.3.0/gcc-8.3.0.tar.gz

4、提取所有压缩文件,下载 GCC8.3 需要的一些资源文件到源码中,删除没用的压缩包

tar xf binutils-2.31.tar.bz2
tar xf glibc-2.28.tar.bz2
tar xf gcc-8.3.0.tar.gz
rm *.tar.*

cd gcc-8.3.0
contrib/download_prerequisites
rm *.tar.*

 5、创建交叉编译的安装文件夹,并添加到 PATH 路径中

cd ~/gcc_all
mkdir cross-pi-gcc

# 这里的文件夹路径可以自定义,但是要把路径添加到环境变量里
export PATH=/home/lodge/gcc_all/cross-pi-gcc/bin:$PATH

6、复制 Linux 内核头文件到交叉编译安装文件夹,并安装

cd ~/raspberry/linux
KERNEL=kernel7
 
make ARCH=arm INSTALL_HDR_PATH=/home/lodge/gcc_all/cross-pi-gcc/arm-linux-gnueabihf headers_install

7、编译安装

cd ~/gcc_all

# 安装 binutils
mkdir build-binutils && cd build-binutils
 
../binutils-2.31/configure --prefix=/home/lodge/gcc_all/cross-pi-gcc --target=arm-linux-gnueabihf --with-arch=armv6 --with-fpu=vfp --with-float=hard --disable-multilib
 
make -j8
make install


# 安装 GCC
mkdir build-gcc && cd build-gcc
 
../gcc-8.3.0/configure --prefix=/home/lodge/gcc_all/cross-pi-gcc --target=arm-linux-gnueabihf --enable-languages=c,c++,fortran --with-arch=armv6 --with-fpu=vfp --with-float=hard --disable-multilib
 
make -j8 all-gcc
make install-gcc


# 安装 glibc 
mkdir build-glibc && cd build-glibc
 
../glibc-2.28/configure --prefix=/home/lodge/gcc_all/cross-pi-gcc/arm-linux-gnueabihf --build=$MACHTYPE --host=arm-linux-gnueabihf --target=arm-linux-gnueabihf --with-arch=armv6 --with-fpu=vfp --with-float=hard --with-headers=/home/lodge/gcc_all/cross-pi-gcc/arm-linux-gnueabihf/include --disable-multilib libc_cv_forced_unwind=yes
 
make install-bootstrap-headers=yes install-headers
 
make -j8 csu/subdir_lib
 
install csu/crt1.o csu/crti.o csu/crtn.o /home/lodge/gcc_all/cross-pi-gcc/arm-linux-gnueabihf/lib
 
arm-linux-gnueabihf-gcc -nostdlib -nostartfiles -shared -x c /dev/null -o /home/lodge/gcc_all/cross-pi-gcc/arm-linux-gnueabihf/lib/libc.so
 
touch /home/lodge/gcc_all/cross-pi-gcc/arm-linux-gnueabihf/include/gnu/stubs.h


# 退回到gcc,完成安装libgcc
cd ../build-gcc
make -j8 all-target-libgcc
make install-target-libgcc


# 退回到glibc,完成安装Glibc
cd ../build-glibc
make -j8
make install


# 退回到gcc,完成安装gcc
cd ../build-gcc
make -j8
make install
cd ..

8、编译安装完成,可以在系统中查看

arm-linux-gnueabihf-gcc --version

 9、测试

        9.1、编写一个简单的程序 test.cpp

#include <iostream>
using namespace std;

int main(void)
{   
    cout << "Hello Raspberry Pi" << endl;
    cout << "test arm-linux-gnueabihf cross-compile-tools" << endl;
    return 0;
}

        9.2、交叉编译

arm-linux-gnueabihf-g++ test.cpp -o test

         9.3、把编译后的程序拷贝到树莓派中运行

三、编译内核源码

(尽量不要用 root 用户来执行)

1、安装所需依赖包

sudo apt-get install bc bison flex libssl-dev make libc6-dev libncurses5-dev

        安装 32 位工具链

sudo apt install crossbuild-essential-armhf

        安装 64 位工具链

sudo apt install crossbuild-essential-arm64

2、构建配置

cd linux
make kernelversion            #查看源码内核版本

# Raspberry Pi 2, Pi 3, Pi 3+
KERNEL=kernel7
make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- bcm2709_defconfig

# Raspberry Pi 4 32位
KERNEL=kernel7l
make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- bcm2711_defconfig

# Raspberry Pi 4 64位
KERNEL=kernel8
make ARCH=arm64 CROSS_COMPILE=aarch64-linux-gnu- bcm2711_defconfig

3、编译内核、模块、设备树

# 32位
make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- zImage modules dtbs

# 64位
make ARCH=arm64 CROSS_COMPILE=aarch64-linux-gnu- Image modules dtbs

4、安装内核、模块、设备树 到 SD

        将 SD 卡从树莓派中取出,连接到 Ubuntu 机器上,SD 卡中的两个分区,boot rootfs 会自动挂载。

# 挂载路径要以实际为准

# 安装模块 32位
sudo env PATH=$PATH make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- INSTALL_MOD_PATH=/media/lodge/rootfs modules_install

# 安装模块 64位
sudo env PATH=$PATH make ARCH=arm64 CROSS_COMPILE=aarch64-linux-gnu- INSTALL_MOD_PATH=/media/lodge/rootfs modules_install

# 安装内核镜像和设备树 32位
sudo cp /media/lodge/boot/$KERNEL.img /media/lodge/boot/$KERNEL-backup.img
sudo cp arch/arm/boot/zImage /media/lodge/boot/$KERNEL.img
sudo cp arch/arm/boot/dts/*.dtb /media/lodge/boot
sudo cp arch/arm/boot/dts/overlays/*.dtb* /media/lodge/boot/overlays/
sudo cp arch/arm/boot/dts/overlays/README /media/lodge/boot/overlays/

# 安装内核镜像和设备树 64位
sudo cp /media/lodge/boot/$KERNEL.img /media/lodge/boot/$KERNEL-backup.img
sudo cp arch/arm64/boot/zImage /media/lodge/boot/$KERNEL.img
sudo cp arch/arm64/boot/dts/*.dtb /media/lodge/boot
sudo cp arch/arm64/boot/dts/overlays/*.dtb* /media/lodge/boot/overlays/
sudo cp arch/arm64/boot/dts/overlays/README /media/lodge/boot/overlays/

为什么这里还要安装模块呢?

硬件驱动有许许多多,如果把所有的驱动都在编译内核的时候就指定编译到内核里面那么内核会非常大。所以编译内核的时候只编译一部分非常常用的驱动,这些驱动在Linux内核配置的时候指定为 “*”。还有一些不怎么常用的与平台相关的驱动被指定为 “M” 编译,它们可以放到文件系统根分区下,等真正需要的时候再加载。

对于这种驱动模块,可以用 make modules 编译。不过直接 make,不加任何参数,就是make all,包含 make modules。虽然编译了,但并没有被安装到文件系统根分区下,内核启动的时候还是找不到这些模块。make modules_install 就是起这个作用的,把模块放到lib/modules 目录中一个和内核名一样的目录下,并且运行 depmod 生成模块依赖关系文件,系统启动时加载模块就是从dep里面读取信息加载模块。由于是交叉编译,不是要将模块安装到本机,所以需要使用INSTALL_MOD_PATH参数,指定安装的根目录是 SD 卡的 rootfs 分区。

5、取下 SD 卡,插入树莓派中开机,进入系统后可以查看内核版本,看是否更新成功

uname -a

四、Pi4更新内核可能出现的问题

1、开机无法启动,卡死在 bcm2835-dma  unable to set DMA mask

参考:https://github.com/raspberrypi/linux/issues/3057

        https://github.com/raspberrypi/linux/commit/278f37a1cbb70636a6eb000c1c9fd56bf7097f6c

原因:bcm2835 DMA只能寻址 1GB 的问题

解决:在 arch/arm/mach-bcm/board_bcm2835.c 文件中 DT_MACHINE_START 处添加以下片段

    DT_MACHINE_START(BCM2835, "BCM2835")
  + #if defined(CONFIG_ZONE_DMA) && defined(CONFIG_ARM_LPAE)
  +	    .dma_zone_size	= SZ_1G,
  + #endif
	    .map_io = bcm2835_map_io,
	    .init_machine = bcm2835_init,
	    .dt_compat = bcm2835_compat,
	    .smp = smp_ops(bcm2836_smp_ops),
    MACHINE_END

 然后重新编译内核。

五、动态设备树

1、介绍

        一个常规的 Linux 设备树,主要是由源文件.dts 和头文件.dtsi 共同编译生成 .dtb 二进制文件,内核在初始化后会加载这个 dtb 文件,并把相关设备都注册好,然后才可以愉快地使用了。

        这对于大部分硬件产品来说这没什么问题,例如一部手机在出厂以后,它的硬件几乎是不会变的。但对于树莓派这种开发板来说,尤其是它的 40pin 扩展引脚,外围电路的变动可就是无限可能了,而内核加载 dtb 后是不能变的,所以需要一种动态覆盖配置的设备树机制,这就是树莓派的dtoverlay(设备树覆盖)。

        dtoverlay 同样是由 dts 源文件编译而来,语法几乎和设备树一样,不过输出文件扩展名为 .dtbo。树莓派提供了两种方式加载 dtbo

        a)将编译好的 dtbo 放到 /boot/overlays 下,并由 /boot/config.txt 配置和使能;
        b)通过命令 dtoverlay <dtbo_file> 动态覆盖设备树;

2、操作过程(本例在树莓派上操作)

        a)安装设备树编译器

sudo apt-get install device-tree-compiler

        b)新建一个设备树文件 (test_led.dts),并定义一个 led_type LED 设备,并将其命名为 led_1

/dts-v1/;
/plugin/;

/ {
  fragment@0 {
    target-path = "/";
    __overlay__ {
      led_1 {
        compatible = "led_type";
      };
    };
  };
};

        fragment __overlay__ 非常重要!!如果不这么写会导致动态加载失败,其实以上的代码转化为标准的设备树语法为:

/led_1 {
  compatible = "led_type";
};

        c)编译生成 .dtbo 文件

sudo dtc -I dts test_led.dts -o test_led.dtbo

        d)将 test_led.dtbo 文件拷贝到 /boot/overlays/

sudo cp test_led.dtbo /boot/overlays/

        e)在 /boot/config.txt 最后一行添加 dtoverlay=test_led,重启 reboot
        f)可以在 /sys/device/platform 或者 /proc/device-tree 下查看到设备 led_1 已经注册

六、更改 DSI 输出分辨率

参考:RPi 树莓派 DSI 接口研究 MIPI raspberry pi

树莓派内核版本:5.10.52

        因为官方镜像里的 dsi 驱动,默认输出分辨率为 800*480,如果要更改的话,就需要使用开源的树莓派 KMS 驱动。

        在 /boot/config.txt 文件中加入下面三行:

dtoverlay=rpi-ft5406         # 树莓派原生触摸文件;
dtoverlay=vc4-kms-v3d         # 加载kms驱动;
dtoverlay=vc4-kms-dsi-7inch

hdmi_force_hotplug=1        # Pi3上要把这个开启;

        显示:修改 drivers/gpu/drm/panel/panel-raspberrypi-touchscreen.c 下的 rpi_touchscreen_modes 结构体参数;

        触摸:修改 arch/arm/boot/dts/overlays/rpi-ft5406-overlay.dts 下的 touchscreen 节点参数;

        编译烧录到 SD 卡,重启~

七、系统自定义

1、关闭屏保

参考:树莓派关闭屏保

 /etc/lightdm/lightdm.conf 文件中添加一行

xserver-command=X -s 0 dpms

2、屏蔽彩虹屏

树莓派开机会自检GPU,在屏幕中央会出现彩虹色的方块。在 /boot/config.txt 中添加一行

disable_splash=1

意思就是取消启动界面显示。

3、屏蔽开机滚动 log

修改文件: /boot/cmdline.txt

console=tty1 修改成 console=tty3(是将开机的滚动代码指向 tty3,从而开机时的 tty1 没有代码),并在最后添加一句 loglevel=3。

4、开启 SSH 和 串口登录

在 /boot 分区下创建一个 ssh 空文件;

在 /boot/config.txt 文件中添加 

dtoverlay=pi3-miniuart-bt

替换 cmdline.txt 内容为

dwc_otg.lpm_enable=0 console=tty1 console=serial0,115200 root=/dev/mmcblk0p2 rootfstype=ext4 elevator=deadline fsck.repair=yes rootwait

注:原内容要做好备份

5、设置开机界面 (有点问题,偶尔开机不显示)

首先安装 fbi

sudo apt-get install fbi

准备一张不超过屏幕分辨率的图片,重命名为 splash.png,存放在 /home/pi 目录下。

手动写一个服务

sudo nano /etc/systemd/system/splashscreen.service

内容如下

[Unit]
Description=Splash Screen
DefaultDependencies=no
After=local-fs.target

[Service]
ExecStart=/usr/bin/fbi -d /dev/fb0 --noverbose -a /home/pi/splash.png
StandardInput=tty
StandardOutput=tty

[Install]
WantedBy=sysinit.target

参数说明
-d /dev/fb0 告诉fbi命令输出的设备

/dev/fb0 是系统中 framebuffer 设备

--noverbose 禁用 fbi 命令默认会在屏幕底部显示的状态条

-a 自动缩放图像适应显示设备

要显示的图片指向 /home/pi/splash.png

设置服务开机启动并重启看效果

sudo systemctl enable splashscreen
sudo reboot

八、系统镜像打包制作

1、使用 gparted 工具分区

安装

sudo apt install gparted

启动

gparted /dev/sdc

这里的 sdc 是 sd 卡在 Ubuntu 系统下显示的设备节点,以设备显示的为准,可用输入命令查看

ls /dev/sd*

启动后界面如下:

  • 第一个 /dev/sdc1 是 /boot 的 FAT32 分区,第二个是文件系统根分区。可以看出来,第二分区有 26.19GiB 是没有使用的,这部分不需要备份到镜像中

  • 首先,卸载 /dev/sdc2,因为挂载的分区不能修改,鼠标右键选中 sdc2,点击卸载(Unmount)

  • 然后,右键选中 sdc2,点击更改大小,界面如下

  •  可以随意更改镜像大小,也可拖动上方的滑块进行设置,设置完成后预览可以看到有26.25GiB 没有分区,这部分就是不会打包进镜像的

  • 最后点击工具栏上方的 ✓ ,确定执行操作;注意分区的时候,最好给 /dev/sdc2 分区后的未使用空间留有一些余地,以免执行分区的时候出现问题。我这里预留的是 41.68MiB。

2、镜像制作

查看分区情况

sudo fdisk -l /dev/sdc

从显示信息可以看出,扇区大小是 512,扇区末尾是 7290879 

运行 dd 命令打包镜像, 因为扇区是从 0 计数,所以 count 要加 1,of 参数后面是镜像保存路径,可以自定义

sudo dd if=/dev/sdc of=/home/lodge/raspberrypi/backup-img/myImage.img bs=512 count=7290880

等待执行结束,就得到我们想要的镜像包了,然后就可以烧录到 sd 卡使用了。

九、64位系统兼容32位软件

开启armhf架构支持

sudo dpkg --add-architecture armhf 

更新源 

sudo apt-get update

安装32位兼容库

sudo apt-get install libc6:armhf

Useful reference:

1、Building GCC as a cross compiler for Raspberry Pi | Solarian Programmer

2、详细介绍git clone --depth=1的用法_白马金羁侠少年的博客-CSDN博客

3、Raspberry Pi Documentation - The Linux kernel

4、树莓派(Raspberry Pi 4 Model B)编译64位内核Kernel_杨-CSDN博客 (64位系统制作)

5、https://www.raspberrypi.org/forums/viewtopic.php1900946&hilit=icn6211#p1899593

6、树莓派驱动之设备树覆盖_年少生而为人-CSDN博客_dtoverlay

7、树莓派镜像制作(图文)

  • 0
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
在嵌入式Linux下,设备树(device tree)用来描述硬件平台的各种资源,Linux内核在启动过程中,会解析设备树,获取各种硬件资源来初始化硬件。设备树的overlay功能是指可以在系统运行期间动态修改设备树。一般情况下,如上图所示,设备树经过DTC编译器编译为二进制的hello.dtb文件,加载到内存,随Linux内核一起启动后,一般就无法更改了。如果我们想修改设备树,需要修改hello.dts文件文件,重新编译成二进制文件:hello.dtb,然后重新启动内核,重新解析。有了设备树的overlay功能,省去了设备树的重新编译和内核重启,我们可以直接编写一个设备树插件:overlay.dts,编译成overlay.dtbo后,直接给设备树“打补丁”,在运行期间就可以动态添加节点、修改节点...设备树的overlay功能,在很多场合都会用得到,会让我们的开发更加方便:外界插拔设备,无法在设备树中预先描述:耳机树莓 + FPGA开发板基于I2C的温度传感器管脚的重新配置:PIN multiplexing修改bootcmd、分区...设备树的overlay功能,目前还没有加入到内核mainline(linux-5.10.x),但目前有些开发板和配套的BSP已经支持了,支持在系统运行期间动态修改设备树文件。如果你手头的开发板或内核平台还没有支持device tree overlay,可以学习本期课程,学习内核中设备树overlay的实现原理,如何给内核打补丁,使内核支持设备树的overlay功能。有了本期课程的学习基础,明白了设备树overlay的实现原理和运行机制,你就可以尝试在自己的开发板平台上实现这个功能了。本期课程的主要内容如下:在开发板上如何实现设备树的overlay功能Configfs文件系统的配置与挂载Configfs编程接口如何编写设备树 overlay插件设备树 overlay的编译和运行设备树overlay运行机制分析本期课程适合哪些人学习:嵌入式驱动工程师嵌入式BSP工程师嵌入式软件工程师想从事嵌入式开发的同学全网首家讲解设备树overlay的视频教程。   

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

MacLodge

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值