当前位置:   article > 正文

基于嵌入式Linux和Qt的汽车智能中控开发_linux驱动开发跟qt开发

linux驱动开发跟qt开发

基于嵌入式Linux和Qt的汽车智能中控开发

前言

笔者本硕湖南某双非,机电专业。本科期间接触到嵌入式相关技术,便对这一领域充满了兴趣,课余时间自学51,机电相关课程课设更是轻松满绩点,大三初次接触STM32,并以32为控制器完成毕设,最终被评为校优秀毕业设计,为本科画上句点;入学研究生后,在导师指点下,二刷电子和计算机专业相关基础课程,动手画了第一块电路板,并入手开发板,正式开始入门嵌入式Linux,经过一年半的时间,笔者基本掌握了基础的嵌入式Linux驱动开发,并制作了一个练手的小项目。现在正值秋招之际,为能顺利找到中意的工作,笔者便想对这一年半的学习经历和完成练手项目的思路及做法做个总结,捋捋思路,做做反思,积累自身的技术。希望自己可以顺利入行嵌入式Linux相关的开发行业或芯片行业。(●’◡’●)

概要

本文是对笔者一年半来学习嵌入式Linux驱动开发和嵌入式Qt的总结,并在此基础上,分享开发一款小汽车智能中控的思路及代码。主要内容有:需求分析,Uboot制作,Linux内核裁剪,驱动开发和Qt人机交互界面开发五个部分。
因为时间紧迫,Qt界面笔者只开发了一个月,期间还要完成课题组横向项目,而且之前只用过C#开发上位机,Qt使用不够熟练,所以界面比较粗糙,还有很多可以提升改善的地方,请见谅,也请多多提出改善意见。

一、需求分析

笔者的大致计划是,学完开发板所有的内容后,再用Qt开发应用程序,在开发板上运行,应用可以调用所有写的驱动,从而验证驱动的可靠性,同时从编写应用的角度,思考学习怎么写出一个方便应用层调用的驱动。最终,决定将小汽车智能中控作为目标,完成整个学习计划。

1、最终效果

要做一个汽车智能中控,我们可以参考实际的汽车中控。目前市场上新款式的小汽车中控基本都是可触摸的LCD屏,控制车内的部分器件,可以包括车内照明灯,后备箱,读取usb设备,影音娱乐等等,使用者可以通过人交交互界面,做出符合常人心理认知的动作,完成想要的操作,如点击灯图标,控制对应灯的亮灭,拖动滑杆控制音响声音大小,挂倒挡自动启动倒车摄像头,长按车窗开关图标控制车窗打开关闭等等。

某汽车中控样例
综上所述,最终的汽车中控应该包含:
a、照明灯控制,点击照明灯按钮打开或关闭照明灯;
b、车窗控制,长按车窗打开(关闭)按钮,控制车窗打开(关闭);
c、RTC实时时钟显示,显示当前日期,时间,且系统掉电不归零;
d、车辆环境感知,可以感知车辆四周有无障碍物以及当前车的运动状态;
e、系统信息显示;
f、系统文件查看,查看当前系统中所有的文件,驱动接口等等,并可以打开简单的文本;
g、通讯接口,与汽车其他模块通讯;
h、娱乐功能,播放视频、音乐;
i、wifi联网,查看天气;
j、可以查看地图;
k、倒车影像,挂倒挡时自动打开倒车影像。

2、硬件分析

笔者使用的是I.MX6U ALPHA开发板,1024*600tftlcd屏幕,可电容触控,硬件资源丰富,是市面上常见的Linux开发板,下图展示了开发板具体的硬件资源。
在这里插入图片描述
图来自正点原子家的Linux开发手册。

根据硬件资源和成品目标,可以确定需要开发的模块,将这些模块按照Linux驱动三大类,字符设备驱动,块设备驱动和网络设备驱动分类,主要包括:
字符设备:
1.1 照明灯控制,本质为控制开关,按一次对应的按键,即可打开或关闭灯,它可以用开发板中红色LED灯表示;
1.2 车窗控制,本质也是控制开关,和照明灯的区别体现在人机交互界面的操作上,一直按着按键,车窗开始运动,到达想要的车窗位置后,松开按键,车窗停止运动,这样才更符合人的心理认知,这一操作可以用蜂鸣器代替;
1.3 RTC,实时时钟,保存本地时间,可在系统断电后继续计时,方便下次系统上电后读取准确的实时时间和日期,开发板硬件支持RTC;
1.4 车辆环境感知,开发板中有两个传感器,ICM20608六轴传感器,可测量三轴加速度和三轴角速度,AP3216C光环境传感器,测量距离,光强,从而模拟车辆环境感知;
1.5 系统信息查看,Linux控制台自带了很多shell命令,可以很方便的查询系统信息,如cat、ps、uname等;
1.6 系统文件查看,Linux的三大组件之一,根文件系统中保存了内核代码的映射文件,可以很方便的与用户或者应用层交互,使用shell命令即可很方便快捷的访问;
1.7 通讯接口实现,如常见的串口、232、485等等;
1.8 娱乐功能,对于驱动层面来说,本质上是LCD驱动和音频模块驱动,有了这二者之后,其他的都是应用层的工作;
块设备:
2.1 倒车摄像头,我手上正好有个USB摄像头,支持V4L2,板子也有USB接口;(为啥没用配备的摄像头呢,笔者想试试驱动一个不是官方调教好的模块,当然,和正点家的配件好贵也有关系 ๑乛◡乛๑ /doge)
网络设备:
3.1 天气预报,驱动层面需要加载wifi,开发板也配备了一个USBwifi模块;

综上所述,基于现有硬件平台足够支撑智能中控的开发。

3、开发内容规划

上一部分笔者分析了智能中控开发的可行性,下面将根据可行性规划具体的开发内容。

3.1 系统搭建

一个Linux系统共有三大文件,Uboot、Kernel和rootfs,而本项目作为一个车载电子产品,功能、体积、功耗、散热、成本等自然受到限制,同时还要达到既定要求,是一个典型的嵌入式系统应用场景。因此,针对本项目的特殊要求从而对软件裁剪,十分有必要。
在该阶段中,需要制做组成Linux的三大文件,并进行针对性的裁剪,最终组建成需要的嵌入式Linux系统。

3.2 驱动编写

Linux系统的驱动可以分为三大类,字符设备,块设备,网络设备。根据前文分析,需要编写的驱动有:
字符设备:lcd,led灯,蜂鸣器,RTC,ICM20608的i2c,AP3216C的spi,串口usart共7个;
块设备:usb摄像头(LeTMC-520);
网络设备:usbWIFI模块(8266)。

3.3 人机交互界面

有了系统和驱动,不能方便的使用是不行的。而Qt作为一款图形用户界面软件开发框架,支持多平台运行,也可以在嵌入式操作系统部署,而且基于C++,完全面向对象开发,非常适合本项目。
所以最后一步,基于Linux虚拟机环境下的Qt,开发可以在开发板中使用的UI软件,实现人车交互。
需要的模块有:
led灯,蜂鸣器,时间日期显示,车辆传感器数据读取,系统信息查询,串口通信,文件读取,usb摄像头数据读取,wifi连接,多媒体。
最终效果:
与手机界面类似,有一个主界面,界面上方显示日期时间,并常驻;界面中有多个按键,点击即可启动对应的程序,实现对应的功能;左右滑动主界面,可以切换界面页数,方便扩展后续功能。
请添加图片描述

4、小结

至此,笔者描述了本项目的需求,确立了项目的目标,分析在当前硬件条件下完成软件设计的可能性,并将项目任务细化,使得能够达成最终目标。

二、系统搭建

Linux系统是一款完全开放源代码的操作系统,其稳定性、安全性、灵活性在长时间的实际使用得到了验证,特别是在服务器端和嵌入式端的广泛应用,充分展现了它的优势。
本章中,笔者将描述本项目运行的基础部分,Linux系统搭建的过程及方法。
启动Linux共需要四大模块,U-BOOT,Linux系统镜像,dtb设备树,rootfs根文件系统,笔者也会分为四部分,分别描述项目是如何建造的。
注:笔者是用正点原子提供的,修改了NXP官方的mfgtool工具,将U-BOOT、Linux镜像、设备树和根文件系统都拷贝到sd卡中,用sd卡启动Linux的,这样只要U-BOOT不修改,Linux镜像,后面会用到的设备树和根系统文件都可以用读卡器在虚拟机下以u盘的方式读写查看,调试起来很方便,后面的文字中没有说明,那么调试和修改代码都是基于这种方式。

1、U-Boot

同Window系统启动时先执行BIOS一样,Linux系统启动时也需要一段引导程序(bootloader)。原因很简单,计算机将存储器分为内存(ddr)和硬盘(flash),内存读写速度块,但掉电数据丢失,硬盘读取速度慢但可以掉电保持,计算机断电时数据保存在硬盘中,内存无数据,运行时cpu是从内存中读写数据的,所以上电时要先由某一小段程序初始化CPU硬件设备,初始化外设、内存等,再把操作系统映像从硬盘中拷到内存,最后启动操作系统。而这里的某段程序,就是bootloader,它在计算机上电时第一个执行,并且只能以启动操作系统为结束。

百度百科的定义:Bootloader是嵌入式系统在加电后执行的第一段代码,在它完成CPU和相关硬件的初始化之后,再将操作系统映像或固化的嵌入式应用程序装载到内存中然后跳转到操作系统所在的空间,启动操作系统运行。

在这里插入图片描述
上图为windows的bootloader程序,BIOS的界面。

那Windows系统由BIOS,那么Linux系统有哪些bootloader呢?作为完全开源的操作系统,它自然有很多,比如 U-Boot、vivi、RedBoot 等等,其中以 U-Boot 使用最为广泛,U-Boot 不仅时一个遵循GPL协议的开源软件,还有丰富的设备驱动源码供使用,也支持多种嵌入式操作系统,如NetBSD、Android等,它丰富的设备驱动,可以让我们在引导操作系统时,使用外设,如启动LCD屏幕,显示logo,启动串口,输出调试信息,启动网络端口,从网络加载操作系统等。

1.1 U-BOOT修改

U-BOOT源码可以直接从官网下载,但是市面上芯片款式成千上万,而且每个芯片都可以由不同的厂家使用在各种板子上,U-BOOT的源码自然不可能支持所有板子,所以每个使用芯片的厂家都会针对自己家的板子移植U-BOOT,大大提升用户使用的体验。
笔者则是在开发板厂家,正点原子提供的U-BOOT源码基础上,对它做了修改。
根据第一章的分析,我们需要上电显示,不需要使用网线接口,不需要串口打印调试信息,而正点提供的都支持了三者。所以要修改的内容就是关闭网线接口,删除网卡驱动。(ps:如果作为真正的产品,串口打印调试信息也可以关闭,但是实验为了开发阶段调试方便,就不关闭了。)
对了,还有就是开机正点原子的确实logo好大好好看,但我还是改了换成我学校的了 (¬◡¬)✧!

1.2 uboot启动logo修改

要修改启动logo,只要在源码中加入显示的logo文件,再修改makefile文件即可。
U-BOOT的logo文件放在/tool/logos/文件夹下,打开文件夹就可以看到U-BOOT自带的logo,把我们提前制作好的.bmp文件放入其中。请添加图片描述
接下来只要修改指定要加载的logo文件即可。
在/tool目录下有一个makefile文件,里面定义了启动时要加载的logo文件名,在makefiel中搜索.bmp即可找到。将原本的代码注释掉,复制并修改为上一步添加的logo文件名。

# Generic logo
ifeq ($(LOGO_BMP),)
LOGO_BMP= $(srctree)/$(src)/logos/CSUST.bmp

# Use board logo and fallback to vendor
ifneq ($(wildcard $(srctree)/$(src)/logos/$(BOARD).bmp),)
#LOGO_BMP= $(srctree)/$(src)/logos/$(BOARD).bmp
LOGO_BMP= $(srctree)/$(src)/logos/CSUST.bmp
else
ifneq ($(wildcard $(srctree)/$(src)/logos/$(VENDOR).bmp),)
#LOGO_BMP= $(srctree)/$(src)/logos/$(VENDOR).bmp
LOGO_BMP= $(srctree)/$(src)/logos/CSUST.bmp
endif
endif
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14

修改前和修改后开机U-BOOT图标对比:
请添加图片描述

1.3 关闭网络

关闭网络接口也很简单,在U-BOOT源码的README文档中,描述了这么一段:

Monitor Functions:
Monitor commands can be included or excluded
from the build by using the #include files
<config_cmd_all.h> and #undef’ing unwanted
commands, or adding #define’s for wanted commands.
。。。。(省略)
EXAMPLE: If you want all functions except of network
support you can write:
#include “config_cmd_all.h”
#undef CONFIG_CMD_NET

可以理解为,如果不想要某些功能的支持,可以在配置文件中使用#undef 加命令,或者不进行#define。
那么,只要在配置文件中找到网络相关的宏定义,并删除就可以关闭网络。正点家的是在/include/configs/mx6ull_alientek_emmc.j中。

#ifdef CONFIG_CMD_NET
#define CONFIG_CMD_PING
#define CONFIG_CMD_DHCP
#define CONFIG_CMD_MII
#define CONFIG_FEC_MXC
#define CONFIG_MII
#define CONFIG_FEC_ENET_DEV		1

#if (CONFIG_FEC_ENET_DEV == 0)
#define IMX_FEC_BASE			ENET_BASE_ADDR
#define CONFIG_FEC_MXC_PHYADDR          0x0
#define CONFIG_FEC_XCV_TYPE             RMII
#elif (CONFIG_FEC_ENET_DEV == 1)
#define IMX_FEC_BASE			ENET2_BASE_ADDR
#define CONFIG_FEC_MXC_PHYADDR		0x1
#define CONFIG_FEC_XCV_TYPE		RMII
#endif
#define CONFIG_ETHPRIME			"FEC"

#define CONFIG_PHYLIB
#define CONFIG_PHY_SMSC
#endif
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22

请添加图片描述

左图为关闭网络后,有图为关闭网络前,可以看到,关闭网络后网线接口指示灯熄灭了,插拔网线也没有反应。
而且串口打印出的信息中也能看到,网络并没有使能。
在这里插入图片描述
至此,我们U-BOOT修改完成,也去掉了网卡驱动.

2、Linux系统

Linux系统就不再多做介绍,这方面的资料数不胜数。
Linux是完全开源的,可以从下载到源码,但是,和U-BOOT一样,市面上芯片千千万,用这千千万芯片做成的不同板子更是不计其数,作为使用板子的一方还要自己移植调试Linux系统,做适配板子板子的这种造轮子的事十分不合理。所以芯片厂家都会选择一个版本的系统,在此基础上适配自己的芯片,使用芯片的厂家再在芯片厂家的系统基础上,加上自己的外设信息,这大大减少了使用方的工作量。
项目使用的系统则是来自i.max芯片厂家NXP提供的官方系统,按照开发板使用手册配置后,笔者再进行了一些裁剪得来的。
至于从NXP官方系统如何配置,购买开发板的文档中写的非常清楚,笔者不再赘述,只说说配置了哪些。

2.1 配置NXP官方Linxu系统

a、准备配置文件。NXP官方提供的EVK开发板的配置文件配置编译出的zimage系统镜像,是可以直接在本项目的开发板上运行的,所以拷贝一份并以此为基础修改配置。
b、准备设备树文件。同配置文件一样,复制一份EVK开发板的设备树.dts文件,作为自己系统的设备树,并在存放设备树的文件夹下的makefile中加入自己系统的设备树编译命令。
c、修改CPU核心工作频率为高性能模型。a中复制的配置文件中有对于CPU频率的设置,如下

CONFIG_CPU_FREQ_DEFAULT_GOV_ONDEMAND=y //将默认cpu频率设置策略调整为ondemand模式
CONFIG_CPU_FREQ_GOV_POWERSAVE=y//使能pwoersave模式的cpu频率设置
CONFIG_CPU_FREQ_GOV_USERSPACE=y//使能USERSPACE模式的cpu频率设置
CONFIG_CPU_FREQ_GOV_INTERACTIVE=y//使能INTERACTIVE模式的cpu频率设置
CONFIG_CPU_FREQ_GOV_ONDEMAND=y//使能ONDEMAND模式的cpu频率设置
  • 1
  • 2
  • 3
  • 4
  • 5

将第一行的默认的设置屏蔽掉即可。
d、将设备树中的emmc驱动修改为8线模式。
e、修改网络驱动,使得网络接口可以使用。
经过这些配置,我们就可以交叉编译得到项目开发板可以使用的通用系统内核镜像文件,拷入板子,测试一下。请添加图片描述
上图中Starting kernel前为U-BOOT输出的信息,下方则为Linux启动的一部分信息。可以看到,系统正常启动。
从中我们可以知道,Linux内核版本为4.1.15,由笔者的虚拟机编译,交叉编译器为gcc,版本4.9.4,编译日期8月19日等待。
PS:其实这个系统镜像早在今年初就制作好了,但是在编写qt应用的时候,多次调整了内核,调试信息中输出的日期是最后一次调试编译时的日期。

2.2 裁剪和配置Linux内核

既然要对Linux内核进行裁剪,那么首先要知道,目前的Linux镜像中都编译了哪些东西。最原始最直观的方式就是查看上一小节制作的配置文件。
请添加图片描述

其实。。也就。。。4k行左右,还没有注释的?哈哈
一行行的看自然效率很低,Linux官方自然想到了这一点,并为解决这一问题提供了方案,那就是用图形界面配置,make menuconfig。
请添加图片描述
图为Linux的图形化配置界面,使用方便,效率高,还有帮助文档可以查看。特别是对于一些重要配置,帮助文档中会建议:

ARM CCI400 PMU support
CONFIG_ARM_CCI400_PMU:
Support for PMU events monitoring on the ARM CCI cache coherent
interconnect.
If unsure, say Y

如果不确定,就设置为Y。非常适合新手。笔者浏览文件配置界面后,基于一定不会用就删掉的思想,裁剪掉了一些用不到驱动。这些驱动有:
a、网线接口。因为我们不会用到网线接口,但是又会用wifi,所以只把网线接口PHY的驱动裁剪掉。
b、Mouse,鼠标驱动。
c、Joysticks/Gamepads,操纵杆/游戏手柄驱动。
在这里插入图片描述
图为取消开发板上的网线接口驱动选项。
裁剪掉一些不用的驱动后,我们也需要确保加入了项目必须的配置。
如多媒体支持,音频支持,spi,i2c,网络指令,sysfs,pinctl,两个usart,can等等。
添加这些操作同裁剪一样,找到对应的选项勾选即可,这里就不过多展示。
径修改后,内核镜像文件大小与未配置前有些变化。
PS:笔者也是第一次进行裁剪内核操作,对很多配置也不熟悉,所以项目中也就仅仅是浅尝辄止,感性的体验一次内核裁剪操作。
在这里插入图片描述
至此,经过Linux内核制作,裁剪,笔者得到了为项目定制的Linux内核镜像文件,复制到sd卡中,替换正点原子官方的内核镜像,系统就可以正常启动。

在这里插入图片描述
图为修改后系统启动时输出的部分调试信息。从中可以看到,can控制器已启动,音频驱动已启动,音频芯片为wm8960,等等。

3 设备树 dts

所谓设备树(Device Tree),故名思意,设备就是芯片外围都有哪些设备,树则是数据结构的一种,数中有很多节点,每个节点之间以一定的形式相连,形成和倒立的苹果树一样的结构,根节点就是苹果树根,枝干分叉处和苹果就是节点,树干则表现了节点间的连接关系。
将设备和树结合起来,就是设备树,这个树的一些节点处保存了设备的信息,方便信息检索和查找。这只是笔者浅显的理解,为避免歧义,同之前一样,引用正点原子提供的描述。

设备树(Device Tree),将这个词分开就是“设备”和“树”,描述设备树的文件叫做 DTS(Device
Tree Source),这个 DTS 文件采用树形结构描述板级设备,也就是开发板上的设备信息,比如
CPU 数量、 内存基地址、IIC 接口上接了哪些设备、SPI 接口上接了哪些设备等等。

在这里插入图片描述
图为正点原子Linux驱动开发手册中对于设备树的描述图。源自:正点原子

树的主干就是系统总线,IIC 控制器、GPIO 控制器、SPI 控制器等都是接到系统主线上的分支。IIC 控制器有分为 IIC1 和 IIC2 两种,其中 IIC1 上接了 FT5206 和 AT24C02这两个 IIC 设备,IIC2 上只接了 MPU6050 这个设备。

那么,细心的小伙伴其实发现了,上一节中,我们启动修改后的系统时输出了一些信息,但如果笔者都没有修改设备树,芯片信息是读不出来的。
以音频芯片wm8960为例,如果不在设备树中描述芯片引脚信息,系统是不会输出:

ALSA device list:
#0: wm8960-audio

这两行信息的。
确实如此,上一节启动修改后系统时,用的设备树确实是笔者修改后的。
在修改内核配置,添加某些驱动时,需要在设备树中描述引脚信息,不然Linux内核中是有了这一款芯片的驱动代码,但也不知道到底芯片的哪些引脚连接了wm8960的哪些引脚,不知道到底要控制哪个引脚才能正确操作wm8960?这些信息都是要通过设备树告诉Linxu内核的。
所以应该在修改内核时,对应的修改设备树,添加必要信息。这并不是笔者上一章忘了,而是想在后面编写驱动代码的时候在描述修改了哪些设备树信息。

4、根文件系统 rootfs

根文件系统,它不同于window下的文件管理器,window的文件管理器管理的是硬盘中的文件,根文件系统则不然。笔者更倾向于将其理解为一个特殊的文件夹,这个文件夹里保存了Linux系统运行所必须的文件,比如库,脚本程序等等,内核代码的映像文件也包含其中,系统引导启动程序会在根文件系统挂载之后将基本的初始化脚本和服务加载到ddr中,还将系统的驱动接口以文件的形式映射出来。
这只是笔者浅显的理解,即使接触Linux有两年多了,笔者依旧只是初探Linux这一庞大而精密的系统一点点皮毛的人,理解有误还望见谅,随时欢迎指正批评,也就不再表达对于根文件系统拙略的见解。

根文件系统首先是内核启动时所 mount(挂载)的第一个文件系统,内核代码映像文件保存在根文件系统中,而系统引导启动程序会在根文件系统挂载之后从中把一些基本的初始化脚本和服务等加载到内存中去运行。

没有根文件系统,Linux就无法正常运行,既然根文件系统这么重要,又该如何构建呢?
当然是有的!其中BusyBox就是制作嵌入式Linux根文件系统的常用工具。它正如名字那样,像一个忙碌的盒子,将各种各样的工具、软件打包起来,供大家使用,我们只要下载源码,按需要配置,编译,即可得到想要的rootfs。

本项目所用的rootfs是根据正点原子Linux嵌入式开发手册制作而来,这个手册可以从正点原子官网免费下载,笔者不再重复。
在这里插入图片描述
这里是本项目最终完成后的rootfs目录。

5、小结

至此本文第二大章结束。本章中笔者介绍了项目中U-BOOT,Linux内核镜像,rootrf和设备树文件的制作过程,并最终成功启动嵌入式Linux系统,为下一章驱动编写做好了铺垫。

声明:本文内容由网友自发贡献,转载请注明出处:【wpsshop博客】
推荐阅读
相关标签
  

闽ICP备14008679号