嵌入式应用开发第四阶段-基于rk3399的视频监控系统
一、需求分析
伴随着嵌入式技术、图像处理技术和无线网络传输技术的发展,传统模拟视频监控系统和基于PC的远程视频监控系统由于自身的不足,已经无法满足现代社会应用中不断涌现出来的新需求,于是基于嵌入式技术的无线网络数字视频监控系统就应因而生了。例如远程监控、远程教学、远程医疗诊断、远程购物、远程探视、电视电话会议等应用都迫切需要高质量的网络视频传输的支持。考虑到了所用的硬件设备大部分都已经具备和我们所学到的知识及本身的能力有限,选择基于rk3399的视频监控系统作为我们本次的课程设计题目是比较实际而且比较容易掌握嵌入式开发的基本方法
设计实现功能要求
1) 利用USB摄像头进行采集图像数据的采集;
2) 利用rk3399对所采集到图像数据进行解码
3) 将解码后的图像显示在LCD屏上。
设计用到的设备
1) PC机
2) RK3399开发板
3) USB摄像头
4) type-c usb线
5) CH340串口线
一、产品的系统构成
系统的工作原理
系统可以分为4 个模块:图像采集模块、图像存储模块、图像处理模块、图像显示模块。系统在RK3399 的控制下从USB 摄像头采集图像数据,然后经过DMA 方式将图像数据传输到内存缓冲区中,由软件将图像数据读出并对图像数据进行压缩和打包处理后存入Flash 中, 最后图像在LCD屏上。本系统的设计难点是如何保证内存中图像数据的读取与USB 摄像头的同步以及图像数据的实时处理。系统采用RK339作为嵌入式处理器,完全可以完成图像数据的实时处理需求,比一般采用添加图像硬件处理模块减少了系统的成本.
二、软硬件协同设计与程序建模
在开始应用编程之前,需要先准备好驱动,在LCD上显示摄像头图像,至少需要三个驱动:LCD驱动、背光驱动、UVC驱动。
以前都是使用的insmod xx.ko进行动态加载驱动,每次开发板上电后,都需要手动/脚本里加载驱动,有点麻烦。
反观内核自带的驱动,使用make menuconfig进入图形配置界面里,找到对应的驱动,可以设置为Y(编译到内核)、M(编译成模块)、N(不编译)。当设置为Y后,进入系统后,就自带了该驱动,不再需要手动加载。
四,嵌入式产品的设计与开发
1.1 LCD 显示原理
液晶显示的原理基于液晶的透光率随其所施电压大小而变化的特性。当光通过上偏振片后,变成线性偏振光,偏振方向与偏振片振动方向一致,与上下玻璃基板上面液晶分子排列顺序一致。当光通过液晶层时,由于受液晶折射,线性偏振光被分解为两束光。又由于这两束光传播速度不同(相位相同),因而当两束光合成后,必然使振光的振动方向发生变化。通过液晶层的光,则被逐渐扭曲。当光达到下偏振片时,其光轴振动方向被扭曲了90度,且与下偏振片的振动方向保持一致。这样,光线通过下偏振片形成亮场。加上电压以后,液晶在电场作用下取向,扭曲消失。这时,通过上偏振片的线性偏振光,在液晶层不再旋转,无法通过下偏振片而形成暗场。可见液晶本身不发光,在外光源的调制下,才能显示,在整个显示过程中,液晶起到一个电压控制的光阀作用。TFT-LCD的工作原理则可简述为:当栅极正向电压大于施加电压时,漏源电极导通,当栅极正向电压等于0或负电压时,漏源电极断开。漏电极与ITO象素电极连结,源电极与源线(列电极)连结,栅极与栅线(行电极)连结。这就是TFT-LCD的简单工作原理
1.2 lcd示例
1)打开lcd设备:
linux系统所有lcd设备名称是统一是 /dev/fbX ,X是0~31 .
RK3399 开发平台lcd设备情况:
[root@edu118 ~]# ls /dev/fb*
/dev/fb0
2)操作lcd设备
a.获得lcd屏的工作参数:可变参数和固定参数
b.使用 mmap 函数把lcd的显存映射到进程空间中 — 得到一个显存首地址
c.通过映射得到的地址往显存写颜色数据。
第一步:
第二步:显存首地址偏移+目标点偏移量 —> 目标点在内存中的绝对地址
第三步:根据 BPP 合成颜色写入到目标点内存中
3)关闭 lcd设备,取消映射(munmap)
2 Linux系统下摄像图像采集
172.16.14.208
1. Linux系统下标准的摄像头框架V4L2
2. V4L2框架不局限应用在摄像头,还有其他类设备
3. 摄像头设备文件:
/dev/videoX X是一个整数从0开始。
4. 摄像头编程流程
Linux下一切都是文件!
1)打开摄像头设备对应文件
int video_device_open(const char*dev)
{
fd_vd = open(dev, O_RDWR); //阻塞方式打开
if (-1 == fd_vd) {
fprintf(stderr, “Cannot open \’%s\’: %d, %s\n”, dev_name, errno, strerror(errno));
return -1;
}
return fd_vd;
}
2)各种操作
a. 查询设备功能:
因为打开的设备不一定就是摄像头设备,不一定支持捕获功能。
b. 根据上一步查询结果来判断是否支持捕获功能
c. 查询摄像头支持的数据格式:
因为不同型号的摄像头支持不一样格式,格式数量也不一样。
d. 从支持格式选择一种可以处理的数据格式 设置到硬件中。
e. 申请缓冲
f. 查询缓冲信息:得到内存偏移量和长度
g. 使用 mmap 进行映射到进程空间中
h. 添加到采集队列中
i. 启动图像采集
j. 取出一帧数据进行处理:实际把最早一帧数据从采集队列取下来,需要自己去复制数据。
k. 把缓冲区重新添加到采集队列
循环:j, k 两步
l. 停止采集
m. 取消映射,关闭设备
3)关闭
2. 示例代码
04-lcd-v4l2
3. 测试
1)编译
编译前根据自己的文件系统路径修改 Makefile
DEST := /home/edu118/work/nanopc-t4/rootfs/home
查看当前路径
edu118@localhost:code$ pwd
/mnt/hgfs/OceanUniversity/2.示例代码/04-lcd-v4l2/code
清上次编译信息
edu118@localhost:code$ make clean
重新编译
edu118@localhost:code$ make
\’./app-lcd-v4l2\’ -> \’/home/edu118/work/nanopc-t4/rootfs/home/app-lcd-v4l2\’
自动复制 生成的 app-lcd-v4l2 到根文件系统的 /home/ 目录中
2)开发板测试
a. 插上摄像头
b. 启动测试
3.LCD显示框架
①:首先从摄像头获取数据放入video_buf,数据的格式(YUV、MJPEG、RGB)和分辨率可能有多种;
②:RK3399的LCD仅支持RGB格式,因此需要数据格式转换;
③:RK3399的LCD分辨率是800X480,因此可能需要大小缩放;
④:根据LCD显示流程,必须要将显示数据写入显存(FrameBuffer);
⑤:最后LCD控制器会将显存数据自动搬运到LCD/VGA等显示设备上;
在应用编程中,要习惯面向对象编程(Object Oriented Programming),也就是把对象作为程序的基本单元,一个对象包含了数据和操作数据的函数,在C语言中常常用结构体(struct)来实现。
关于Linux内核C语言中的面向对象的实现,可以参考这篇博客,介绍了如何C语言实现面向对象,也通过这个能稍微理解Linux驱动中的操作函数的原理。
这里,模仿内核的编程框架,为每个模块实现一个管理链表,模块对应加入链表,再调用对应的操作函数,框架如下:
简单说明下这个框架,主要有四个模块:
video用于摄像头数据采集,convert用于格式转换、process用于缩放等操作、dispaly用于显示。
以convert为例,有一个manager管理每个子模块,将每个子模块放入链表,向上提供统一的操作接口,调用对应文件的操作函数。
五.嵌入式系统移植
建立交叉编译环境
搭建交叉编译环境是嵌入式开发的第一步,也是必备的一步。搭建交叉环境的方法很多,不同的体系结构、不同的操作内容甚至是不同版本的内核,都会用到不用的交叉编译器,选择合适的交叉编译器对于嵌入式开发是非常重要的。由于我们本次用到的是linux 2.6.32.2内核,故我们选择了编译器arm-linux-gcc-4.3.2[3]。以下安装交叉编译器的步骤:
1、下载交叉编译器arm-linux-gcc-4.3.2,下载地址:http://www.handhelds.org/download/projects/toolchain/arm-linux-gcc-4.3.2.tar.bz2
2、复制arm-linux-gcc-4.3.2.tar.bz2到目录 tmp/下并解压:
# cd /tmp
# tar xvzf arm-linux-gcc-4.3.2.tar.bz2
3、把编译器路径加入系统环境变量,运行命令
#gedit /root/.bashrc
编辑/root/.bashrc 文件,在最后一行设置:
export PATH=$PATH:/usr/local/arm/4.3.2/bin
3.2.3解压安装源代码和工具
1、下载linux 2.6.32.2内核源代码
下载地址:http://www.kernel.org/pub/linux/kernel/v2.6/linux-2.6.32.2.tar.gz
2、复制内核代码至目录/tmp/linux 并解压
# tar –xvzf linux-2.6.32.2.tar.gz
3、解压目标文件系统
这里我们使用现有的根文件系统资源root_qtopia-20100108.tgz,将它复制至目录/usr/src 并解压
# tar –xvzf root_qtopia-20100108.tgz
4、安装目标文件系统映象制作工具mkyaffs2image
要把上一步中的root_qtopia 目录烧写入目标板中使用, 就需要使用相应的mkyaffs2image 工具,它是一个命令行的程序,使用它可以把主机上的目标文件系统目录制作成一个映象文件,以烧写到开发板中[4]。
#tar xvzf /tmp/linux/mkyaffs2image.tgz –C /
3.2.4配置网络文件系统NFS服务
1、设置共享目录
运行命令 #gedit /etc/exports
编辑 nfs 服务的配置文件,添加以下内容:
/opt/FriendlyARM/mini2440/root_qtopia *(rw,sync,no_root_squash)
其中:/opt/FriendlyARM/mini2440/root_qtopia 表示nfs 共享目录,它可以作为开发板的根文件系统通过nfs 挂接;* 表示所有的客户机都可以挂接此目录rw 表示挂接此目录的客户机对该目录有读写的权力;no_root_squash 表示允许挂接此目录的客户机享有该主机的root 身份[5]
2、启动NFS 服务
在命令行下运行:
#/etc/init.d/nfs start
3.3 定制Linux内核
Linux 内核是一个社区共同开发的作品,具备一个现代操作系统的所有功能,并能对绝大多数硬件提供支持。然而,我们本次设计有很多功能都没有用到的,为了尽可能减少编译出来的内核体积,在配置内核时,只需要配置需要用到的模块。常用的配置内核的方法有make config ,make menuconfig和make xconfig这里我们使用最广泛的make menuconfig[6]。执行“make menuconfig”,可进入配置内核界面:
配置万能驱动USB摄像头
在Device Drivers 菜单里面,选择 Multimedia devices,回车进入,选择如图“*”号选项,并选择Video capture adapters 进入
出现如图菜单,找到如图选项并进入
出现如图菜单,选择如图“*”号选项,再选GSPCA based webcams 进入
这里我们选择所有类型USB 摄像头的支持
1) 配置网卡驱动
要配置网卡驱动,首先要配置网络协议支持.在主菜单中,选择 Netwoking support,回车进入子菜单, 选择 Networking options 并进入下一级菜单,如图配置选项
选择完毕,一直退回到主菜单,并选择进入 Device Drivers 菜单。找到 Network device support,选择进入下一级菜单, 找到并进入 Ethernet (10 or 100Mbit) 选项[8], 选中:
<*> Generic Media Independent Interface device support
<*> DM9000 support
2) 配置串口驱动
在 Character devices 菜单中,选择进入Serial drivers – – ->,选择如图选项,来配置串口驱动
3) 配置yaff2s文件系统的支持
要使用 yaffs2 文件系统,需要先配置nand flash 驱动支持,在Device drivers 菜单中选择MTD 选项,按回车进入,找到 NAND Device Support 选项并进入,如图选择 Nand Flash 驱动支持
返回到内核配置主菜单,找到 File systems 选项进入,然后找到选项 Miscellaneous filesystems 并进入,再找到 YAFFS2 支持选项,如图选择
4) 配置NFS文件系统
在 File System 菜单中,选择Network File Systems 文件系统的支持且进入, 选择如图选项,这样配置编译出的内核就可以通过 NFS 启动系统了。
完成内核的配置并保存好,接着执行命令:
#make dep ;生成依赖文件
#make zImage ;生成压缩的内核影象文件
3.4 制作目标文件系统映象
3.5 移植bootloader
(1) 打开DNW 程序,接上USB 电缆,根据菜单选择功能号[v]开始下载supervivi
(2)点击“USB Port->Transmit/Restore”选项,并选择打开文件supervivi开始下载。
(3)下载完毕,BIOS 会自动烧写supervivi 到Nand Flash 分区中,并返回到主菜单。
3.6 移植Linux内核
(1)在BIOS 主菜单中选择功能号[k],开始下载linux 内核zImage
(2) 点击“USB Port->Transmit”选项,并选择打开相应的内核文件zImage开始下载.
(3) 下载完毕,BIOS 会自动烧写内核到Nand Flash 分区中,并返回到主菜单
3.7移植根文件系统
(1)在BIOS 主菜单中选择功能号[y],开始下载yaffs 根文件系统映象文件
(2) 点击“ USB Port->Transmit/Restore ” 选项, 并选择打开相应的文件系统映象文件
(3)下载完毕,BIOS 会自动烧写内核到Nand Flash 分区中,并返回到主菜单
六.设计心得
本次设计参考了众多书籍及网络上的理论知识,在理解的基础上结合思考及老师给我们做的项目演示,根据现有的硬件设备,对完整的内核代码进行了相应的裁减,配置出适合我们所设计的系统的内核。整个过程看似有点按部就班,但真正操作起来并没有那么简单,很多时候都会出现一些莫名其妙的错误,以致无法进行下一步的操作。这时就需要回归到理论方面的知识中去,经过多次尝试才能得以解决。