iTOP-STM32MP157开发板采用ST推出的双核cortex-A7+单核cortex-M4异构处理器,既可用Linux、又可以用于STM32单片机开发。开发板采用核心板+底板结构,主频650M、1G内存、8G存储,核心板采用工业级板对板连接器,高可靠,牢固耐用,可满足高速信号环境下使用。共240PIN,CPU功能全部引出:底板扩展接口丰富底板板载4G接口(选配)、千兆以太网、WIFI蓝牙模块HDMI、CAN、RS485、LVDS接口、温湿度传感器(选配)光环境传感器、六轴传感器、2路USB OTG、3路串口,CAMERA接口、ADC电位器、SPDIF、SDIO接口等
第三篇 嵌入式 Linux 驱动开发篇
第一部分 Linux 驱动初探
第三十五章 嵌入式开发概述及环境构建
35.1嵌入式 linux 开发介绍
Linux 是一个开放、灵活、跨平台的操作系统,上至庞大的数据中心,下至可放于掌心中的嵌入式设备, 无处没有 Linux 的身影。更为重要的是, Linux 是一个与 Unix 既一脉相承又与时俱进的系统。可以说, 上世纪 70 年代学习的 Unix 知识和技巧,在今天仍然大有用武之地,这与 Windows 平台的开发形成了鲜 明的对比。程序员不用担心今天微软出一个 .net,明天又出一个 F#,使得自己过去学习的成果付之东流。 成为一名精通 Linux 驱动程序设计的高级程序员一直是不少朋友孜孜以求的目标。要入门 Linux 环境 下的驱动编程,关键是要看对、选对、学会正确的书籍。可以说,如果你选对了 Linux 驱动编程的入门书籍, 配合你在程序设计工作中的刻苦钻研,成为一名精通 Linux 驱动程序设计的高级程序员并非一件可望不可 及的事情。但如果各位程序员朋友没有选对正确的书籍,则你的职业生涯之路就可能面临坎坷。本书我们 将以理论加实践的方式重点讲解嵌入式 Linux 驱动的框架,了解驱动开发通用的流程和方法,进而掌握从应 用程序到驱动程序的调用流程。在使用本教程学习驱动开发的过程中,会涉及迅为的很多开发板,将更多的焦点转移到了驱动编程背后的内核原理,并试图从 Linux 内核的上百个驱动子系统中寻找出内部规律,以 培养读者举一反三的能力,让你能“一通百通”,了解写驱动的通用的方法之后,在工作中很容易在其他 板子上面使用这些知识。Linux 内核有上百个驱动子系统,傻子才会一个目录一个目录地去看,一个目录一个目录地从头学起。我们势必要寻找各种驱动子系统的共性,摸索规律。 从浩如烟海的知识体系、不断更新的软件版本中终生学习,不断攻克一个个挑战,获取新养分,寻找 新灵感,这实在是黑暗的码农生涯中不断闪现的璀璨光芒。Linux 的内核版本不断更新,出现了 Linux 3.0、 Linux 3.1、Linux 3.2、…、Linux 3.19、Linux 4.0、Linux 4.1,变化的是软件的架构,不变的是 Linus 的热情。 我们将以设备树版本的内核为例进行讲解。如果有好的基础,以优秀程序员极强的学习能力,应该很快就 可以掌握这些新知识。机制没有变,变化的只是策略,因此学习能力也是优秀程序员的又一个重要品质。 没有人生下来就是天才,良好的学习能力也是通过后天的不断学习培养的。可以说,学得越多的人,学新 东西的速度一定越快,学习能力也变得越强。因为,知识的共通性实在太多。 本书分为四个部分,第一部分是 linux 驱动初探,第二部分是 linux 内核裁剪与定制,第三部分是 linux 驱动基础,第四部分是 linux 驱动进阶,这四个部分是环环相扣,一脉相承的,所以与本文档配套的视频不能跳,要踏踏实实,一步一个脚印。趋向于激进、浮躁的内心会使得我们难以静下心来研究技术,做技术 的人,从来没有终南捷径,拼得就是坐冷板凳的傻劲。 Linux 设备驱动的学习是一项浩繁的工程,学习 linux 驱动要求我们有足够的学习恒心和毅力。动手实践 永远是学习任何软件开发的最好方法,学习 Linux 设备驱动也不例外。阅读经典书籍和参与 Linux 社区的讨 论也是非常好的学习方法。Linux 内核源代码中包含了一个 Documentation 目录,其中包含了一批内核设计 文档,全部是文本文件。学习 Linux 设备驱动的一个注意事项是要避免管中窥豹、只见树木不见森林,因为 各类 Linux 设备驱动都从属于一个 Linux 设备驱动的架构,单纯而片面地学习几个函数、几个数据结构是不 可能理清驱动中各组成部分之间的关系的。因此,Linux 驱动的分析方法是点面结合,将对函数和数据结构 的理解放在整体架构的背景之中。
35.2 嵌入式 linux 环境构建
俗话说“工欲善其事,必先利其器”,为了方便进行 Linux 设备驱动的开发和调试,我们首先要搭建 linux 驱动开发环境。驱动程序是依赖于 linux 内核的,如果您是在STM32MP157平台上进行驱动开发,必须先在Ubuntu 中下载,配置,编译开发板 STM32MP157平台所使用的 linux 内核。大家可以参考开发板的使用手 册完成下面的部分。
硬件环境构建
- 开发板连接线:调试串口线,OTG 烧写数据线,网线,电源线
- 开发板烧写镜像
软件环境构建
- 下载设备树内核源码,window 和 Ubuntu 下各放一份。
- Windows下安装sourceinsight创建内核源码工程,这是用来浏览内核,编辑驱动的软件
Ubuntu下:安装工具链,配置,编译Linux内核源码
本教程中使用的是STM32MP157开发板。Ubuntu的开发环境是 Ubuntu18
本教程使用的内核源码是linux-5.4.31
交叉编译器使用的是:gcc-arm-10.3-2021.07-x86_64-arm-none-linux-gnueabihf
35.2.1 编译设备树源码
为了方便大家编译设备树源码,本章节将介绍如何编译STM32MP157内核源码(编译之前参考STM32MP157开发板使用手册第九章搭建编译环境)。
首先,进入源码解压的到的/home/topeet/work/linux-5.4.31目录下,如下图所示:
然后我们使用命令“./create.sh”进行编译如下图所示:
编译完成如下图所示:
编译完成生成的 kernel 镜像是“output/”目录下的“uImage”,生成的设备树镜像是“output//dts”目录下的 “stm32mp157a-itop.dtb、stm32mp157a-itop-rgb-043.dtb、 stm32mp157a-itop-lvds-070.dtb stm32mp157a-itop-rgb-050.dtb、 stm32mp157a-itop-lvds-097.dtb 、 stm32mp157a-itop-rgb-070.dtb、stm32mp157a-itop-lvds-101.dtb”,如图所示:
但我们最后要烧写的是opt目录下的bootfs.ext4文件,将该文件对我们默认的/home/image烧写镜像目录下bootfs.ext4文件进行覆盖,如下图所示:
然后我们对该镜像进行烧写,我们在这里为了方便,使用linux版本的烧写工具,进行烧写。
如果使用我们提供好的环境,则在任意目录下使用命令“stm32.sh”打开该烧写文件(如果没用使用我们编译好的编译环境),如下图所示:
然后点击Open file右边的加号,选择open file选项,如下图所示:
找到我们要烧写的镜像,然后选择打开tf-a.tsv配置文件,如下图所示:
选择配置文件之后会将烧写的内容显示出来,然后选择右上角的USB设备,并点击绿色的链接按钮,如下图所示:
连接成功之后(默认都是USB1),之前的Connect会变成Disconnect,然后点击Download按钮就会开始烧写了,如下图所示:
需要注意的是下方的Binaries path可能不会默认选择,未选择时需要自行选择一下:
烧写成功之后,重启开发板,在uboot倒计时的过程之中,按下任意键,然后进入uboot模式,如下图所示:
35.2.2 设置屏幕参数
各屏幕与对应的uboot命令如下:
屏幕 | 设置命令 |
4.3寸屏幕 | setenv lcdtype 4.3 |
5寸屏幕 | setenv lcdtype 5.0 |
9.7寸屏幕 | setenv lcdtype 9.7 |
10.1寸屏幕 | setenv lcdtype 10.1 |
塑胶壳7寸屏幕 | setenv lcdtype 7.0 |
金属框7寸屏幕 | setenv lcdtype 1024x600 |
HDMI屏幕 | setenv lcdtype hdmi |
以设置9.7寸屏为例,上电后在uboot倒计时按回车,进入命令行,输入“setenv lcdtype 9.7”,然后输入“saveenv”保存,然后输入“reset”重启使环境变量生效。
35.2.3 搭建nfs共享目录
为了方便进行 Linux 设备驱动的开发和调试,建立良好的开发环境很重要,还要使用必要的工具软件以 及掌握常用的调试技巧等。本章节将介绍搭建 nfs 共享目录,方便 Ubuntu 与开发板传文件来调试驱动程序。 NFS 是 Network FileSystem 的缩写,是由 SUN 公司研制的 UNIX 表示层协议 (pressentation layer protocol),NFS 是基于 UDP/IP 协议的应用。它的最大功能就是可以通过网络让不同的机器,不同的操作 系统彼此共享文件,可以通过 NFS 挂载远程主机的目录,访问该目录就和访问本地目录一样,所以也可以 简单的将它看成一个文件服务器。通过 NFS 服务,可以实现在线调试文件系统或应用程序,而不用像传统 的方式生成文件系统镜像,然后烧写到开发板的 eMMC 里,再启动开发板。通过 NFS 服务可以提高调试的效率。
35.2.3.1 搭建环境介绍
使用硬件环境是:一台PC,上面运行虚拟机ubuntu、一块 stm32mp157开发板。PC 机和开发板通过网线 连接到路由器上面,路由器分配的网段是192.168.0.x的ip地址,默认网关是路由器的ip地址,即 192.168.0.1。作者虚拟机 Ubuntu的ip地址是192.168.0.140,imx6开发板的ip是根据大家的具体情况而定,网段的子网掩码是 255.255.255.0。大家要根据自己使用的网络环境来设置ip地址,设置原则是确保虚拟机 Ubuntu的ip和开发板的ip在同一网段。
35.2.3.2 搭建NFS服务器
实现 NFS,需要一个主机作为 NFS 服务器,选择虚拟机 Ubuntu 作为主机。首先需要在在虚拟机Ubuntu 上安装 Ubuntu NFS 服务,这是一个软件包,可以使用 apt 命令下载(当然,首先要保证虚拟机可以上网)。 在 Ubuntu root 用户下输入“apt-get install nfs-kernel-server”命令安装 Ubuntu NFS 服务,在安装过程中会提 示”是否继续安装”的信息,输入”y”,如下图:
在这里我们的环境已经安装好了,所以这里显示零更新、零新安装,安装成功之后继续搭建 NFS 服务器。
我们使用命令“vim /etc/exports”,对exports文件进行内容的添加,在最后一行添加以下内容:
/home/nfs/ *(rw,sync,no_root_squash)
添加完成如下图所示:
下面讲解一下上面输入的内容都代表什么意思:
/home/nfs/:要共享的目录;“/home/nfs/ ”目录需要自己建,默认Ubuntu 中是没有的。
*:代表允许所有的网络段访问;
rw:是可读写权限;
sync:是资料同步写入内存和硬盘;
no_root_squash:是 Ubuntu nfs 客户端分享目录使用者的权限,如果客户端使用的是 root 用户,那么对于该共享目录而言,该客户端就具有 root 权限;
其他 Ubuntu nfs 常用的参数有:
ro:只读访问
async :nfs 在写入数据前可以相应请求
secure: nfs 通过以下的安全 TCP/IP 端口发送
insecure: nfs 通过 1024 以上的端口发送
wdelay:如果多个用户要写入 NFS 目录,则归组(默认)
no_wdelay:如果多个用户要写入 NFS 目录,则立即写入,当使用 async 时,无需此设置
hide:在 nfs 共享目录中不共享妻子目录
no_hide:共享 nfs 目录的子目录
subtree_check:如果共享/usr/bin 之类的子目录时,强制 nfs 检查父目录的权限(默认)
no_subtree_check:和上面相对,不检查父目录权限
all_squash:共享文件的 UID 和 GID 映射匿名用户 anonymous,适合公用目录
no_all_squash:保留共享文件的 UID 和 GID(默认)
root_squash root:用户的所有请求映射成如 anonymous 用户一样的权限(默认)
no_root_squash root:用户具有根目录的完全管理访问权限
anonuid=xxx:指定 nfs 服务器/etc/passwd 文件中匿名用户多的 UID
anongid=xxx:指定 nfs 服务器/etc/passwd 文件中匿名用户的 GID
接下来重启 rpcbind 服务,输入“/etc/init.d/rpcbind restart”命令,运行结果如下图:
然后重启 nfs 服务,输入“/etc/init.d/nfs-kernel-server restart”命令,运行结果如下图:
使用命令:“showmount -e”查看是否成功挂载nfs目录(这里也可能要重启ubuntu才会又挂载目录),如下图:
至此,Ubuntu nfs 服务器端的配置完成。
35.2.3.3 NFS共享目录使用
通过路由器网线连接开发板和路由器。系统起来后首先使用“ifconfig”查看开发板 ip。如下图:
然后查看一下 NFS 服务器的 ip,如下图所示:
可以查看到开发板和服务器在同一网段,如果不在同一网段然后修改开发板的网络设置,并重启开发板使之生效。
使用 ping 命令测试网络,如下图所示,开发板和 ubuntu 服务器之间的网络是连通的。
然后使用“mount -t nfs -o nolock 192.168.0.140:/home/nfs /mnt/”命令挂载到 nfs 服务器,如下图所示:
进入虚拟机 Ubuntu 系统中的”/home/nfs”目录(这个目录是 NFS 服务器目录),使用“vim hello”命令新建 hello 文档,并添加“hello topeet nfs”内容,如下图:
接下来查看开发板上的信息,如下图:
最后可以使用命令“umount /mnt/”命令卸载 NFS 目录。
由上图可知,开发板和虚拟机可以完成同步,方便调试。至此,nfs 共享目录的制作和使用介绍全部结束。
35.2.4 设置交叉编译器
如果是使用的我们搭建好的环境,则不需要设置,默认已经设置好了,而如果是自己搭建的环境则需要自己设置交叉编译器。
在虚拟机ubuntu中,进入“/usr/local”目录,使用如下命令创建 arm 目录,再进入此目录。
mkdir arm
接着通过 ssh 工具,将“iTOP-STM32MP157开发板光盘资料\04_TF-A、uboot和内核源码\交叉编译器” 路径下的“gcc-arm-10.3-2021.07-x86_64-arm-none-linux-gnueabihf.tar.xz”编译器拷贝到“/usr/local/arm/”目录下。注意:此编译器用来编译uboot和kernel,编译应用程序的交叉编译器应与文件系统的编译器保持一致。
使用如下命令解压编译器,如下图所示,
tar -vxf gcc-arm-10.3-2021.07-x86_64-arm-none-linux-gnueabihf.tar.xz
解压完成,会得到“gcc-arm-10.3-2021.07-x86_64-arm-none-linux-gnueabihf”文件夹。
使用命令“cd ~”进入文件系统根目录下(一定要使用 root 账户),接着使用“vi .bashrc”命令,打开环境变量配置文件,如下图所示。
在环境变量配置文件最底行,添加以下内容。
export PATH=$PATH:/usr/local/arm/gcc-arm-10.3-2021.07-x86_64-arm-none-linux-gnueabihf/bin
如下图所示,然后保存退出。
接着还需要更新一下环境变量,如下图所示,使用命令“source .bashrc”。
最后做一下环境变量测试,Ubuntu 控制台中输入“arm-”,然后按键盘上的“Tab” 键,会出现如下图所示内容。
至此我们的编译器就设置完成了。