树莓派3B+驱动开发(1)- 开发环境搭建

github主页:https://github.com/snqx-lqh

本项目github地址:https://github.com/snqx-lqh/RaspberryPiDriver

本项目硬件地址:https://oshwhub.com/from_zero/shu-mei-pai-kuo-zhan-ban

欢迎交流

笔记说明

笔记主要是要记录如何使用树莓派进行linux的驱动开发,主要是学习记录ARMLinux板子的驱动开发。由于不想破坏原来的电脑环境,或者说想尽量使得编译环境一致,我们使用Docker虚拟环境进行编译。虚拟环境主要编译,文件处理还是使用宿主机。关于Docker可以网上找点其他教程简易入门。

当然,你也可以不使用docker,直接在宿主机编译,没有任何问题。

主要参考的文章

peng-zhihui/Planck-Pi

Philon/rpi-drivers

本节源码路径02_Firmware/01_helloworld

环境搭建

注意:处理文档都在宿主机下,只有编译才使用Docker环境,因为我用vscode远程连接虚拟机编辑文档的话,如果是Docker解压处理的文档,就权限不足,所以处理文档就在宿主机下。

提前安装好docker,下载镜像的时候,去https://xuanyuan.me/blog/archives/1154?from=tencent,关注加速列表。

安装docker的话根据官网一步步走下来就可以了

Install Docker Engine on Ubuntu | Docker Docs

将用户添加到 Docker 组

在Ubuntu系统上,需要在运行Docker命令时添加 sudo 是因为 Docker 守护进程默认以 root 用户权限运行。Docker 执行一些需要特权权限的操作,如访问系统资源、管理容器、构建镜像、挂载文件系统等,以确保安全性和系统稳定性。如果希望不每次都使用 sudo 运行 Docker 命令,可以将当前用户加入 docker 组。

运行以下命令将当前用户添加到docker组中:

BASH 复制代码
sudo usermod -aG docker $USER

注销并重新登录,或者运行以下命令使更改生效(我这里运行命令没生效,重启才可以)

BASH 复制代码
sudo service docker restart
newgrp docker

确保用户$USER 已经成功添加到 docker 组。(自己输入自己的用户名),可以使用以下命令检查

bash 复制代码
id $USER

配置镜像环境

我这里选择的镜像源是docker.1ms.run,到时候不一定能用,注意关注我前面说的镜像表。

下载ubuntu镜像

BASH 复制代码
sudo docker pull docker.1ms.run/ubuntu:20.04

启动一个交互式的容器,使用名为 "rpi3b-plus-env",并将本地主机上的 SDK 目录映射到容器内的 /home 目录,最后以 Bash shell 运行。

BASH 复制代码
#第一次运行docker环境
sudo docker run -it --name rpi3b-plus-env \
-p 8022:22 \
-v /home/lqh/rpi3b_plus_workspace:/home \
docker.1ms.run/ubuntu:20.04 /bin/bash

#第二次运行docker环境
sudo docker start -ai rpi3b-plus-env

#退出
exit

进入容器后需要换源,先安装一个vim。安装前需要软件库更新,不然都没有软件。

BASH 复制代码
apt-get update
apt-get install vim

然后执行vim /etc/apt/sources.list,换成你当时想要的源,可以是清华源,或者其他源。下面是ubuntu20的清华源

BASH 复制代码
deb https://mirrors.tuna.tsinghua.edu.cn/ubuntu/ focal main restricted universe multiverse
# deb-src https://mirrors.tuna.tsinghua.edu.cn/ubuntu/ focal main restricted universe multiverse
deb https://mirrors.tuna.tsinghua.edu.cn/ubuntu/ focal-updates main restricted universe multiverse
# deb-src https://mirrors.tuna.tsinghua.edu.cn/ubuntu/ focal-updates main restricted universe multiverse
deb https://mirrors.tuna.tsinghua.edu.cn/ubuntu/ focal-backports main restricted universe multiverse
# deb-src https://mirrors.tuna.tsinghua.edu.cn/ubuntu/ focal-backports main restricted universe multiverse

deb http://security.ubuntu.com/ubuntu/ focal-security main restricted universe multiverse
# deb-src http://security.ubuntu.com/ubuntu/ focal-security main restricted universe multiverse

# deb https://mirrors.tuna.tsinghua.edu.cn/ubuntu/ focal-proposed main restricted universe multiverse
# # deb-src https://mirrors.tuna.tsinghua.edu.cn/ubuntu/ focal-proposed main restricted universe multiverse

换源完成后,更新

BASH 复制代码
apt-get update

这个时候应该会报一个错误Certificate verification failed: The certificate is NOT trusted.,证书的问题这时候执行以下操作。

BASH 复制代码
# 把之前换源的https换成http
vim /etc/apt/sources.list

# 更新一下
apt-get update

# 安装证书
apt-get install --reinstall ca-certificates

# 把之前换源的http换成https
vim /etc/apt/sources.list

# 更新一下
apt-get update

安装需要的软件

BASH 复制代码
apt-get install xz-utils nano wget unzip build-essential git bc swig libncurses5-dev libpython3-dev libssl-dev pkg-config zlib1g-dev libusb-dev libusb-1.0-0-dev python3-pip gawk bison flex 

安装编译工具链

BASH 复制代码
apt install gcc-arm-linux-gnueabihf

安装完成后可以使用,以下指令查看是否安装成功。

BASH 复制代码
arm-linux-gnueabihf-gcc -v

配置完成后可以commit容器到镜像方便未来部署:

bash 复制代码
sudo docker commit rpi3b-plus-env rpi3b-plus-env.image
sudo docker save -o rpi3b-plus-env.image.tar rpi3b-plus-env.image

如果是其他计算机导入的话

BASH 复制代码
docker load -i rpi3b-plus-env.image.tar

# 或者使用

docker load < rpi3b-plus-env.image.tar

然后建立新环境的时候就可以

bash 复制代码
#第一次运行docker环境
sudo docker run -it --name rpi3b-plus-env \
-p 8022:22 \
-v /home/lqh/rpi3b_plus_workspace:/home \
rpi3b-plus-env.image:latest /bin/bash

简易测试

下载内核源码

我们处理文件在宿主机上面进行处理,主要宿主机远程连接,才可以修改文件内容,如果直接在Docker容器里面的话,他的权限会导致必须要root才能处理,不是很方便,后面想办法解决这个问题。

BASH 复制代码
# 在宿主机中
cd /home/lqh/rpi3b_plus_workspace/
# 下载内核源码
wget https://github.com/raspberrypi/linux/archive/rpi-6.6.y.tar.gz
# 解压,进入内核目录
tar xvf rpi-6.6.y.tar.gz  

# 在Docker环境中
cd /home/linux-rpi-6.6.y
# 清理内核
make mrproper
# 加载RPi-3B+的配置
make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- bcm2709_defconfig
# 编译
make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- -j4

更换内核

我安装的树莓派固件版本是

bash 复制代码
pi@raspberrypi:~/RpiDriver/01_helloworld $ uname -a
Linux raspberrypi 6.6.51+rpt-rpi-v7 #1 SMP Raspbian 1:6.6.51-1+rpt3 (2024-10-08) armv7l GNU/Linux

但是我拉取github源码的话,他是6.6.62版本。所以找了资料,重新换内核。下面的步骤参考博客,但是他是树莓派4B,我是3B+,所以有些不同。

你们的版本应该大概率也会不一样,如果版本不一样会报错无法加载内核。所以需要换内核

进入下载的树莓派源代码目录,设置环境变量KERNEL,并使用make指定bcm2711_defconfig配置模板生成arm架构32位的配置文件。

注意:树莓派版本不同,这里设置的环境变量KERNEL不同,所使用的配置模板也不同,其他型号的具体参数设置请参考链接

在docker环境中

bash 复制代码
cd linux-rpi-6.6.y
KERNEL=kernel7
make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- bcm2709_defconfig
make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- zImage modules dtbs -j4

把树莓派关机,然后卡取下来,插到虚拟机上,使用lsblk,会发现它的两个分区,一个是boot分区小一点,一个是文件系统分区大一点,我这里,boot是sdb1,rootfs是sdb2。然后在宿主机的linux-rpi-6.6.y文件夹做以下操作。

bash 复制代码
sudo mkdir mnt
sudo mkdir mnt/fat32
sudo mkdir mnt/ext4
sudo mount /dev/sdb1 mnt/fat32
sudo mount /dev/sdb2 mnt/ext4

然后加载刚刚编译好的模块

bash 复制代码
KERNEL=kernel7
sudo env PATH=$PATH make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- INSTALL_MOD_PATH=mnt/ext4 modules_install

然后,备份原内核、复制新内核及设备树信息。mkknlimg这个工具高版本内核里面没有,去一个低版本里面下一个,然后放进来。原作者的dts下面没有分芯片,6.6版本的分了芯片,移动dtb的时候注意。

bash 复制代码
sudo cp mnt/fat32/$KERNEL.img mnt/fat32/$KERNEL-backup.img
./scripts/mkknlimg arch/arm/boot/zImage mnt/fat32/$KERNEL.img
sudo cp arch/arm/boot/dts/broadcom/*.dtb mnt/fat32/
sudo cp arch/arm/boot/dts/overlays/*.dtb* mnt/fat32/overlays/
sudo cp arch/arm/boot/dts/overlays/README mnt/fat32/overlays/
sudo umount mnt/fat32
sudo umount mnt/ext4

将SD卡重新插入树莓派,启动树莓派,使用下列命令即可查看内核版本。

bash 复制代码
uname -a

pi@raspberrypi:~ $ uname -a
Linux raspberrypi 6.6.62-v7 #4 SMP Sun Dec  1 17:17:33 CST 2024 armv7l GNU/Linux

就会发现和拉取的版本一样了。

简易helloworld驱动

创建工程目录:

shell 复制代码
# 在宿主机中
# 创建目录,进入
mkdir -p /home/lqh/rpi3b_plus_workspace/example/01_helloworld  
cd /home/lqh/rpi3b_plus_workspace/example/01_helloworld
# 创建驱动模块源码及Makefile
touch hello_drv.c Makefile

hello_drv.c

c 复制代码
#include <linux/init.h>
#include <linux/module.h>

static int __init hello_init(void)
{
    printk("init kernel\n");
    return 0;
}
module_init(hello_init);

static void __exit hello_exit(void)
{
    printk("exit kernel\n");
}
module_exit(hello_exit);

MODULE_LICENSE("GPL"); // 开源许可证

Makefile

Makefile 复制代码
# 模块驱动,必须以obj-m=xxx形式编写
obj-m = hello_drv.o

KDIR = ../linux-rpi-6.6.y
CROSS = ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf-

all:
	$(MAKE) -C $(KDIR) M=$(PWD) $(CROSS) modules

clean:
	$(MAKE) -C $(KDIR) M=`pwd` $(CROSS) clean
shell 复制代码
# 在Docker环境中
# 编译内核
cd /home/example/01_helloworld
make

树莓派运行

makefile编译完成后,直接make就行

BASH 复制代码
make

将make生成的文件,通过scp传到树莓派上,我这里写了个脚本。具体的内容参数,自己修改。

BASH 复制代码
#!/bin/sh

sendfile="hello_drv.ko"
pi_user=pi
pi_ip=192.168.2.149
pi_dir=/home/pi/RpiDriver/01_helloworld

scp ${sendfile} ${pi_user}@${pi_ip}:${pi_dir}

# scp hello_drv.ko pi@192.168.2.149:/home/pi/RpiDriver/01_helloworld

发送树莓派前,在树莓派的指定文件夹下面先建立这些文件夹,不然发送文件会不成功,因为没有该路径

bash 复制代码
mkdir 01_helloworld 02_led_drv_cdev 03_led_drv_platform_device_driver 04_led_drv_platform_dts_driver 05_led_drv_pinctrl_gpio 06_led_drv_misc 07_key_drv_irq 08_key_drv_irq_timer 09_key_drv_irq_sleep_wakeup 10_key_drv_irq_poll 11_key_drv_irq_fasync 12_key_drv_irq_block 13_key_drv_irq_tasklet 14_key_drv_irq_workqueue 15_key_drv_irq_threaded 16_pcf8591_drv_i2c 17_oled_drv_spi 18_pwm_drv

在树莓派上,我们需要加载并使用这个模块。

BASH 复制代码
sudo insmod hello_drv.ko

sudo rmmod hello_drv

可以使用dmesg查看运行过程中的变化

bash 复制代码
dmesg | tail -5

# 查看内核打印信息
[   19.132265] Bluetooth: RFCOMM socket layer initialized
[   19.132291] Bluetooth: RFCOMM ver 1.11
[ 6319.896017] hello_drv: loading out-of-tree module taints kernel.
[ 6319.896438] init kernel                #加载
[ 6390.206953] exit kernel                  #卸载
相关推荐
君逸~~5 小时前
RK3568(二)——字符设备驱动开发
linux·驱动开发·笔记·学习·rk3568
fulinux20 小时前
Linux设备驱动开发 - 平台设备和驱动Platform device和driver
linux·驱动开发·device·platform·driver
牧以南歌〆1 天前
MPU6050六轴传感器的驱动开发(二)
c语言·驱动开发·stm32·单片机·嵌入式硬件·mcu
牧以南歌〆1 天前
MPU6050六轴传感器的驱动开发(一)
c语言·驱动开发·stm32·单片机·嵌入式硬件·mcu
嵌入(师)2 天前
嵌入式驱动开发详解13(IIC驱动架构实现)
驱动开发
三菱-Liu2 天前
三菱伺服通过MR Configurator2进行的试运行模式
运维·驱动开发·嵌入式硬件·制造·mr
嵌入(师)3 天前
嵌入式驱动开发详解14(SPI驱动架构实现)
驱动开发·架构
嵌入(师)3 天前
嵌入式驱动开发详解5(ioctl的使用)
驱动开发
嵌入(师)8 天前
嵌入式驱动开发详解2(设备挂载问题)
驱动开发