第一篇:嵌入式系统语音采集与播放程序设计
ARM9嵌入式系统课程设计
--嵌入式系统语音采集与播放程序设计
班级: 学号: 姓名:
指导老师:
课程设计时间:2011.6.29---2011.7.8
江苏大学
目录
第一章 引言.........................................................1 1.1 设计目的......................................................1 1.2 设计任务与要求................................................1 第二章 课程设计平台构建与流程.......................................2 2.1 嵌入式系统平台构建............................................2 2.2 课程设计流程..................................................3 2.3 课程设计硬件结构与工作原理...................................3 第三章 BOOTLOADER移植与下载.......................................11 3.1 VIVI源代码安装...............................................11 3.2 VIVI源代码分析与移植.........................................11 3.3 VIVI编译与下载...............................................12 第四章 LINUX内核移植与下载........................................14 4.1 LINUX内核源代码安装..........................................14 4.2 LINUX内核源代码分析与移植....................................14 4.3 LINUX内核编译与下载..........................................15 第五章 课程设计功能模块程序设计与交叉编译..........................24 5.1 课程设计模块功能.............................................24 5.2 功能模块驱动程序设计.........................................24 5.3 功能模块交叉编译.............................................28 第六章 根文件系统建立与文件系统下载................................29 6.1 根文件系统分析...............................................29 6.2 文件系统映像文件生成.........................................30 6.3 文件系统下载.................................................31 6.4 功能模块运行与调试...........................................32 第七章 课程设计总结与体会..........................................34 7.1 得出的结论...................................................34 7.2课程设计过程中遇到的问题及解决方法...........................34 7.3 心得体会.....................................................34 参考文献...........................................................36
第一章 引言
1.1 设计目的
分析Linux操作系统下音频设备驱动的结构,编写应用测试程序,实现UDA1341芯片的实时录音及放音功能,进一步熟悉vivi、Linux内核和根文件系统的编译和烧写至开发板的开发流程。
1.2 设计任务与要求
在Samsung公司S3C2410处理器的edukit-Ⅲ开发板上,在嵌入式linux操作系统环境下,根据语音芯片UDA1341的驱动程序和语音数据的特点编写语音采集与播放的应用测试程序,实现语音数据的采集和实时播放功能。1.要求本系统实时的采集与播放
2.通过麦克风录制一段语音信息,对其进行播放 第二章 课程设计平台构建与流程
2.1 嵌入式系统平台构建
2.1.1软件部分
1)Linux或Windows 98/2000/NT/XP 2)cygwin cygwin是一个在windows平台上运行的unix/Linux模拟环境,是cygnus solutions公司开发 3)Embest IDE 英蓓特提供的一个嵌入式开发的集成环境。4)windows中的超级终端
5)Embest online Flash Programmer for ARM 烧写相关文件到NorFlash中的工具。
6)建立linux的交叉编译环境,各项源代码的安装等 2.1.2硬件部分
1)EduKit-II实验平台 2)S3C2410核心子板 3)PC机 2.2 课程设计流程
图2.1 设计流程
2.3 课程设计硬件结构与工作原理
2.3.1硬件模块(1)
SCLLRCIIS控制器SDOSDIMCL 图2.2 典型的IIS总线上的设备
(2)IIS总线结构
IIS总线只处理声音数据,其他控制信号等则需单独提供。IIS总线使用3根串行总线,分别是:提供分时复用功能的SD线(Serial data,串行数据),WS线(Word select,字段选择(声道选择))和SCK线(Continuous Serial clock,连续的时钟信号)。
音频编解码4 ADDRTxFIFODATASFTRBRFCRxFIFOSDCNTLCHHCSCLKIPSR_APCLKIPSR_BSCLKGLRCKCDCLK
图2.3 IIS总线接口内部结构
S3C2410A IIS总线接口各模块的功能描述如下:
● BRFC 表示总线接口、寄存器区和状态机。总线接口逻辑和FIFO访问由状态机控制。
● IPSR 表示两个5位的前置分频器ISPR_A和ISPR_B,一个前置分频器作为IIS总线接口的主时钟发生器,另一个前置分频器作为外部音频编解码器CODEC的时钟发生器。
● TxFIFO和RxFIFO 表示两个64字节的FIFO。在发送数据时,数据写到TxFIFO,在接收数据时,数据从RxFIFO读取。
● SCLKG 表示主IISCLK发生器。在主设模式时,由主时钟产生串行位时钟。● CHNC 表示通道发生器和状态机。通道状态机用于产生和控制IISCLK和IISLRCK。
● SFTR 表示16位移位寄存器。在发送模式时,并行数据移入SFTR并转换成串行数据输出;在接收模式时,串行数据移入SFTR并转换成并行数据输出。具体的相关寄存器的位功能描述请参观相关资料。2.3.2 工作原理
常用的数字音频处理集成电路包括A/D、D/A、DSP、数字滤波器和数字音频I/O接口及设备(麦克风、话筒)等。麦克风输入的模拟音频信号经A/D转换、音频编码器实现模拟音频信号到数字音频信号转换,编码后的数字音频信号通过控制器送入DSP或微处理器相应的处理。音频输出时,数字音频信号(音频数据)经控制器给音频解码器,经D/A转换后由扬声器输出。
数字音频涉及概念很多,重要的是理解:采样和量化。采样就是每隔一定时间读一次声音信号的幅度,而量化则是将采样得到的声音信号幅度转换为数字值。从本质上讲,采样是时间上的数字化,而量化则是幅度上的数字化。
根据奈奎斯特(Nyquist)采样理论采样频率应高于输入信号的最高频率两倍。为了保证声音不失真,采样频率应该在40kHz左右。常用的音频采样频率有8kHz、11.025kHz、22.05kHz、16kHz、37.8kHz、44.1kHz、48kHz等,要达到DVD的音质需要采用更高的采样频率。
量化是对模拟音频信号的幅度数字化,量化位数决定模拟信号数字化以后的动态范围,常用的有8位、12位和16位。量化位越高,信号的动态范围越大,数字化后的音频信号就越接近原始信号,但所需要的存储空间也越大。
声道有单声道、双声道和多声道。双声道又称立体声,在硬件中有两条线路,音质和音色都优于单声道,但数字化后占据的存储空间的大小要比单声道多一倍。多声道能提供更好的听觉感受,不过占用的存储空间也更大。
数字音频数据有PCM、MP3、WMA、WAV、Ogg Vorbis、RA、AAC、ATRAC 3等多种不同的文件格式。
1)IIS总线
IIS总线(IIS,Inter-IC Sound Bus,数字音频集成电路通信总线)是Philip公司提出的音频总线协议,它是一种串行的数字音频总线协议,是音频数据编码或解码常用的串行音频数字接口。
(1)IIS总线的传输模式
数据的发送方和接收方需要采用相同的时钟信号来控制数据传输,数据传输方(主设)必须产生字段选择信号、时钟信号和需要传输的数据信号。在一个复杂的数字音频系统中,可能会有多个发送方和接收方,通常采用系统主控制模式,主控制模块控制数字音频数据在不同集成电路(设备)间的传输,数据发送方就需要在主控制模块的协调下发送数据。IIS总线的三种传输模式如图2、3、4所示,这些模式的配置一般需通过软件来实现。
clock SCKTRANSMITTERword select WSdata SDRECEIVERTRANSMITTER=MASTER
图2.4发送器为主设时的传输模式
clock SCKTRANSMITTERword select WSdata SDRECEIVERRECEIVER=MASTER
图2.5 接收器为主设时的传输模式
CONTROLLERclock SCKTRANSMITTERword select WSdata SDRECEIVERCONTROLLER=MASTER
图2.6 控制器为主设时的传输模式(2)IIS总线时序 1串行数据(SD)○串行数据的传输由时钟信号同步控制,且串行数据线每次传输1字节的数据。当音频数据被数字化成二进制流后,传输时先将数据分成字节(如8位、16位等),每个字节的数据传输从左边的二进制位MSB(Most Significant Bit)开始。当接收方和发送方的数据字段宽度不一样时,发送方不考虑接收方的数据字段宽度。如果发送方发送的数据字段宽度小于系统字段宽度,就在低位补0;如果发送方的数据字段宽度大于接收方的宽度,则超过LSB(Least Significant Bit)的部分被截断。
2字段选择(WS)○音频系统一般包含有左右两个声道,字段选择(WS)用来选择左声道或者右声道,WS=0表示选择左声道;WS=0表示选择左声道。如果不在外部加以控制,WS会在MSB传输前的一个时钟周期发生变化,使数据接收方和发送方保持同步。此外,WS能让接收设备存储前1字节,并且准备接收后1字节。
3时钟信号(SCK)○在IIS总线中,任何一个能够产生时钟信号的电路都可以称为主设备,从设备从外部时钟输入得到时钟信号。IIS的规范中制定了一系列关于时钟信号频率和延时的限制。
图2.7 IIS总线时序
(3)IIS总线接口的工作方式
IIS总线接口是用来连接外部的标准编解码器(CODEC)的接口。S3C2410A提供一个IIS总线接口,能用来连接一个外部8/16位立体声音频CODEC,支持IIS 总线数据格式和MSB-justified数据格式。该接口对FIFO的访问提供DMA传输模式,而不是采用中断模式。它可以同时发送数据和接收数据,也可以只发送或只接收数据。在只发送和只接收模式,S3C2410A的IIS总线接口有以下三种工作方式。
1正常传输方式 ○在正常传输方式,对于发送和接收FIFO,IIS控制寄存器有一个FIFO就绪标志位。当FIFO准备发送数据时,如果发送FIFO不空,则FIFO就绪标志位为“1”;如果发送FIFO为空,该标志为“0”。在接收数据时,当接收FIFO是不满时,FIFO就绪标志位为“1”,指示可以接收数据;若接收FIFO满,则该标志为“0”。通过FIFO就绪标志位,可以确定CPU读/写FIFO的时间。
2DMA传输方式 ○在DMA传输方式,利用DMA控制器来控制发送和接收FIFO的数据存取,由FIFO就绪标志来自动请求DMA的服务。
3发送和接收方式 ○在发送和接收方式,IIS总线接口可以同时发送和接收数据。(4)S3C2410A IIS总线接口的音频串行接口格式
S3C2410A的IIS总线接口支持IIS总线数据格式和MSB-justified数据格式。IIS总线格式 ○IIS总线有IISDI(串行数据输入)、IISDO(串行数据输出)、IISLRCK(左/右通道选择)和IISCLK(串行位时钟)4条线,产生IISLRCK和IISCLK信号的为主设备。串行数据以2的补码发送,首先发送是MSB位。首先发送MSB位可以使发送方和接收方具有不同的字长度,发送方不必知道接收方能处理的位数,同样接收方也不必知道发送方正发来多少位的数据。
当系统字长度大于发送器的字长度时,数据发送时,字被切断(最低数据位设置为0)发送。接收器接收数据时,如果接收到的数据字长比接收器的字长更长时,则多的数据位被忽略。另一方面,如果接收器收到的数据位数比它的字长短时,则缺少的位设置为0。因此,MSB有固定的位置,而LSB的位置与字长度 有关。在IISLRCK发生改变的一个时钟周期,发送器发送下一个字的MSB位。
发送器发送的串行数据可以在时钟信号的上升沿或下降沿同步。然而,串行数据必须在串行时钟信号的上升沿锁存到接收器,所以发送数据使用上升沿进行同步时会一些限制。
左右通道选择线指示当前正发送的通道。IISLRCK可以在串行时钟的上升沿或者下降沿改变,不需要同步。在从模式,这个信号在串行时钟的上升沿被锁存。IISLRCK在MSB位发送的前一个时钟周期内发生改变,这样可以使从发送器同步发送串行数据。另外,允许接收器存储前一个字,并清除输入以接收下一个字。
2MSB-justified数据格式 ○MSB-justified总线格式在体系结构上与IIS总线格式相同。与IIS总线格式唯一不同的是,只要IISLRCK有变化,MSB-justified格式要求发送器总是发送下一个字的最高位。
2)音频编解码芯片UDAl341TS UDA1431TS可把通过麦克风音频输入通道输入的立体声模拟信号转化为IIS格式的数字信号,传送给S3C2410的IIS控制器,然后CPU使用DMA控制器把得到的数字信号存放的一块内存空间上;同样DMA控制器也能把已存的数字信号通过IIS格式发送给UDAl341TS芯片,由该芯片转换成模拟信号,通过耳机音频输出通道输出。利用UDA1341TS内部的PGA(可编程增益放大器)、AGC(自动增益控制)功能对模拟信号进行处理。对于数字信号,UDA1341TS提供DSP(数字音频处理)功能。
S3C2410A的IIS接口线分别与UDA1431TS的BCK、WS、DATAI、SYSCLK相连。当UDA1431TS芯片工作在微控制器输入模式时,使用UDA1431TS的L3总线(L3DATA、L3MODE和L3CLOCK)。L3DATA、L3MODE和L3CLOCK分别表示与微处理器接口的数据线(L3DATA)、模式控制线(L3MODE)和时钟线(L3CLOCK)。微控制器通过对UDA1431TS中的数字音频处理参数进行配置。S3C2410A没有与L3总线配套的专用接口,可以利用通用I/O口进行控制。第三章 Bootloader移植与下载
3.1 Vivi源代码安装
进入cygwin,Vivi源代码的安装:
$> source /tmp/edukit-2410/set_env_linux.sh// Linux编译环境变量设置,第一次打开Cygwin必须设置。
$> cd $WORKDIR $> tar-xvjf /tmp/edukit-2410/source/vivi/vivi-20030929.tar.bz2 $> ls
„ vivi „ „为$WORKDIR目录下其他内容
正确解压后,可以看到多了一个vivi目录,即vivi源代码的安装目录,后面的vivi配置及编译都得进入vivi目录进行。再为EduKit2410实验系统打入vivi源代码的补丁文件:
$> cd vivi $> patch-p1
vivi的代码包括arch,init,lib,drivers和include等几个目录,共200多条文件。
Vivi主要包括下面几个目录:
arch:此目录包括了所有vivi支持的目标板的子目录,例如s3c2410目录。drivers:其中包括了引导内核需要的设备的驱动程序(MTD和串口)。MTD目录下分map、nand和nor三个目录。
init:这个目录只有main.c和version.c两个文件。和普通的C程序一样,vivi将从main函数开始执行。lib:一些平台公共的接口代码,比如time.c里的udelay()和mdelay()。include:头文件的公共目录,其中的s3c2410.h定义了这块处理器的一些寄存器。Platform/smdk2410.h定义了与开发板相关的资源配置参数,我们往往只需要修改这个文件就可以配置目标板的参数,如波特率、引导参数、物理内存映射等。
3.3 Vivi编译与下载
1)Vivi源代码的编译
然后执行以下命令进行编译:
$> source /tmp/edukit-2410/set_env_linux.sh Linux编译环境变量设置
$> cd $WORKDIR/vivi $> make clean
图3.1 vivi编译
$> make menuconfig输入配置smdk2410-amd:Nor Flash boot
smdk2410:Nand boot
或
图3.2 图形界面下配置内核文件
其中,运行make menuconfig后,选择Load an Alternate Configuration file,配置文件名称如下:
smdk2410:编译 vivi 在 Nand Flash(K9S5608)中运行; smdk2410-amd:编译 vivi 在 Nor Flash(AM29LV160DB)中运行。这两个配置文件在usrlocalsrcedukit-2410viviarchdef-configs中,须复制
到usrlocalsrcedukit-2410vivi中;或者可以在 menuconfig 中输入全部路径。配置好后,输入:$> make
图3.3 vivi映像文件生成
如果编过程中没有出现错误,则编译后的执行文件存放于 vivi 目录下。2)下载:
在下载模式下,vivi为用户提供一个命令行人机接口,通过人机接口可使用vivi提供的一些命令。如嵌入式系统没有键盘和显示,可以利用vivi中的串口,将其和宿主机连接起来,利用宿主机中的串口软件(如Windows中的超级终端或Linux中的minicom)来控制。第四章 Linux内核移植与下载
4.1 Linux内核源代码安装
linux源代码安装
运行cygwin,执行以下命令完成cygwin 环境下的Linux源代码的安装: $> source /tmp/edukit-2410/set_env_linux.sh Linux编译环境变量设置
$> cd $WORKDIR $> tar –xvjf /tmp/edukit-2410/linux-2.4.18-rmk7-pxa1-mz5-i2c.tar.bz2 $> ls „ kernel „ „为$WORKDIR 目录下其他内容
图4.1 linux内核安装
正确解压后,相比之前可以看到多了一个kernel目录,即kernel源代码的安装目录,后面的Linux配置及编译都得在kernel目录进行。
实验中提供的linux内核已经包含了Linux源代码的补丁文件、I2C和网络驱动模块
4.2 Linux内核源代码分析与移植
4.2.1 Linux源代码分析
Linux内核由5个主要的子系统组成。这5个子系统分别是进程调度(SCHED)、内存管理(MM)、虚拟文件系统(Virtual File System,VFS)、网络接口(NET)和进程间通信(IPC)。
进程调度控制着进程对CPU的访问。当需要选择下一个进程运行时,由调度 程序选择最值得运行的进程。可运行进程实际是仅等待CPU资源的进程,如果某个进程在等待其它资源,则该进程是不可运行进程。Linux使用了比较简单的基于优先级的进程调度算法选择新的进程。
内存管理允许多个进程安全地共享主内存区域。Linux的内存管理支持虚拟内存,即在计算机中运行的程序,其代码、数据和堆栈的总量可以超过实际内存的大小,操作系统只将当前使用的程序块保留在内存中,其余的程序块则保留在磁盘上。必要时,操作系统负责在磁盘和内存之间交换程序块。内存管理从逻辑上可以分为硬件无关的部分和硬件相关的部分。硬件无关的部分提供了进程的映射和虚拟内存的对换;硬件相关的部分为内存管理硬件提供了虚拟接口。
虚拟文件系统隐藏了各种不同硬件的具体细节,为所有设备提供了统一的接口,虚拟文件系统还支持多达数十种不同的文件系统,这也是Linux较有特色的部分。虚拟文件系统可分为逻辑文件系统和设备驱动程序。逻辑文件系统指Linux所支持的文件系统,如ext2、fat等,设备驱动程序指为每一种硬件控制器所编写的设备驱动程序模块。
网络接口提供了对各种网络标准的存取和各种网络硬件的支持。网络接口可分为网络协议和网络驱动程序两部分。网络协议部分负责实现每一种可能的网络传输协议,网络设备驱动程序负责与硬件设备进行通信,每一种可能的硬件设备都有相应的设备驱动程序
4.2.2 Linux内核及硬件模块驱动移植
内核和文件系统、图形用户系统(GUI窗口系统)可以分开,它们的开发、移植、下载甚至运行都是可以分开的。内核移植是一个比较复杂的任务,也是嵌入式系统开发中非常重要的一个过程。内核移植一般包括内核配置、内核编译和内核下载3大步骤。
4.3 Linux内核编译与下载
4.3.1 Linux内核源代码安装
运行cygwin,执行以下命令完成cygwin环境下的Linux内核源代码的安装: $> source /tmp/edukit-2410/set_env_linux.sh //Linux 编译环境变量设置 $> cd $WORKDIR $> tar –xvjf /tmp/edukit-2410/linux-2.4.18-rmk7-pxa1-mz5-i2c.tar.bz2 $> ls „ kernel „ //„为$WORKDIR 目录下其他内容
正确解压后,可以看到多了一个kernel目录,即kernel内核源代码的安装目录,后面的Linux内核配置及编译都得进入kernel目录进行。实验中提供的linux内核已经包含了Linux源代码的补丁文件、IIC和网络驱动模块。4.3.2 Linux内核的编译 $> cd kernel
图4.2 $> make mrproper 清除所有的旧的配置和旧的编译目标文件等 $> make xconfig 在图形界面下对内核进行配置(配置方法之一)执行make xconfig 后,弹出如图4.3的内核定制界面:
图4.3 内核定制界面
选择按钮”Load Configuration from File”,如图4.4输入smdk2410:
图4.4 内核配置文件
选择配置sound ,设置Sound support为y:
设置BT878 audio dma为y: 设置SMDK-2410 audio support为y:
设置OSS sound modules为y:
根据提示加载配置文件后,点击按钮”Store Configuration to File”,如图4.5输入audio1:
图4.5 存储配置文件
保存,Save and Exit。如图4.6
图4.6 $> make dep //搜索Linux编译输出与源代码之间的依赖关系并生成依赖文件。
图4.7
$> make clean //清除构造内核时生成的目标文件、模块文件和临时文件。$> make zImage //生成压缩的内核映像文件。
图4.8 编译通过后,在/usr/local/src/edukit-2410/kernel/arch/arm/boot/目录下生成内核的压缩映像文件为“zImage”,此文件是最后要烧写到开发板的内核映像文件。
4.3.1 Linux内核下载
内核下载:
1)启动超级终端(波特率为115200),连好串口线,在开机瞬间快速按空格键,进入vivi控制台命令行下;打开S3C2410&NandFlash_vivi.cfg,在Flash Programmer的Progarm页中选择:vivi.bon&load.bin文件进行烧写。如图4.9
图4.9 烧写界面
点击按钮Progarm开始烧写,直到烧写成功;连接串口到PC机COM1,运行成功;连接串口线到 PC 机 COM1,运行光盘中提供的 Windows 超级终端 Hyper Terminal.ht;开发板重新加电,程序运行后,在超级终端上可以看到串口输出类似以下信息:
图4.10 超级终端界面
看到以上信息后,表示正在等待用户从超级终端下载文件。这时,请点击超 级终端菜单“传送”选择 Xmodem 方式下载 vivi.nand 文件,点击 OK 后等待下载烧写结束即可。
图4.11 添加传送文件
图4.12 下载vivi nada 2)在vivi启动等待中,敲入空格键进入vivi界面环境,并输入以下命令: vivi> load flash kernel x <回车> 烧写更新内核约4分钟即可烧写完毕,如图4.13
图4.13 等待下载
3)立即选择要发送的文件,比如zImage文件,这里Linux环境下源代码arch/arm/boot目录下的zImage内核映像文件已转移到 windows某目录下。要选择合适的xmodem协议。以上操作完成 后,单击“发送,几分钟后即可发送完毕。
图4.14 发送zImage
图4.15 下载成功 第五章 课程设计功能模块程序设计与交叉编译
5.1 课程设计模块功能
5.1.1 三个模块:
I2S音频总线接口电路 ;音频编解码器芯片udal41; DMA控制器; 5.1.2工作过程:
麦克风输入的模拟音频信号在音频编解码器中经过A/D转换和编码将模拟信号转换成数字信号,将这些数字信号先传给I2S音频总线接口电路中的FIFO,再由DMA控制器送入DSP中做相应的处理,这是录音的过程;DMA控制器将DSP中存储的信号传送给I2S音频总线接口电路中的FIFO,再发送给音频编解码芯片进行D/A转换,通过耳机输出模拟信号。
5.2 功能模块驱动程序设计
5.2.1 关于驱动结构体
由于目前许多硬件厂商在出售各种产品时,一般都不带Linux下的设备驱动程序,而且编写驱动程序的工作量占整个系统工作量的很大的一部分,这使得Linux下设备驱动程序的开发变得越来越重要。
本课程设计不要求自己编写驱动程序,但要求分析UDAl341TS驱动程序,以便编写出语音采集与播放的应用测试程序,同时为以后编写驱动程序打好基础。嵌入式Linux系统下的IIS音频驱动程序是在/usr/local/src/edukit-2410/drivers/sound 中,3c2410-uda1341.c 文件即是。
关于结构体:
在音频驱动程序中有2个比较重要的结构体: typedef struct { int size;/* buffer size */ char *start;/* point to actual buffer */(内存虚拟地址起始地址)dma_addr_t dma_addr;/* physical buffer address */(内存物理地址起始地址)
struct semaphore sem;/* down before touching the buffer */ int master;/* owner for buffer allocation, contain size when true */(内存大小)
} audio_buf_t;typedef struct { audio_buf_t *buffers;/* pointer to audio buffer structures */ audio_buf_t *buf;/* current buffer used by read/write */ u_int buf_idx;/* index for the pointer above */ u_int fragsize;/* fragment i.e.buffer size */(音频缓冲区片大小)
u_int nbfrags;/* nbr of fragments */(音频缓冲区片数量)dmach_t dma_ch;/* DMA channel(channel2 for audio)*/ } audio_stream_t;audio_stream_t是一个管理多缓冲区的结构体,为音频流数据组成了一个环形缓冲区。audio_buf_t管理一段内存,audio_stream_t管理N个audio_buf_t。
音频驱动的两个file_operations结构定义如下: static struct file_operations smdk2410_audio_fops = { llseek: smdk2410_audio_llseek, write: smdk2410_audio_write, read: smdk2410_audio_read, poll: smdk2410_audio_poll, ioctl: smdk2410_audio_ioctl, open: smdk2410_audio_open, release: smdk2410_audio_release };static struct file_operations smdk2410_mixer_fops = { ioctl: smdk2410_mixer_ioctl, open: smdk2410_mixer_open, release: smdk2410_mixer_release };这里定义了两种类型设备的file_operations结构,前者是DSP设备,后者是混频器设备。Linux 内核内部通过file结构识别设备,通过file_operations数据结构体提供文件系统的入口点函数,也就是访问设备驱动程序里的函数。file_operations结构体原型是在
read()、write()、open()和ioctl()是struct file_operations结构体中的接口函数。
1)read()函数:由已打开的文件读取数据,即播放。
(1)函数定义:ssize_t read(struct file *file, char *buffer, size_t count, loff_t * ppos);(2)函数说明:把参数file所指的文件传送count个字节到buffer指针所指的内存中;若参数count为0,则read()不会有作用并返回0;(3)返回值:返回值为实际读取到的字节数,如果返回0,表示已到达文件尾或是无可读取的数据,此外文件读写位置会随读取到的字节移动。如果正确会返回实际读到的字节数,最好能将返回值与参数count作比较,若返回的字节数比要求读取的字节数少,则有可能读到了文件尾、从管道(pipe)或终端机读取,或者是read()被信号中断了读取动作。当有错误发生时则返回-1,错误代码存入errno中,而文件读写位置则无法预期;2)write()函数:将数据写入已打开的文件内,即录音。
(1)函数定义:ssize_t write(struct file *file, const char *buffer, size_t count, loff_t * ppos);(2)函数说明:把参数buffer所指的内存写入count个字节到参数file所指的文件内。当然,文件读写位置也会随之移动;(3)返回值:若正确会返回实际写入的字节数;当有错误发生时则返回-1,错误代码存入errno中。
3)open()函数:打开音频设备。
(1)函数定义:int(*open)(struct inode *inode, struct file *file);(2)函数说明:参数inode为设备特殊文件的incode(索引结点)结构的指针,参数file是指向这一设备的文件结构的指针。open()的主要任务是确定硬件是否处在就绪状态,验证次设备号的合法性,控制使用设备的进程数;
(3)返回值:如果打开文件成功,open会返回一个文件描述符,以后对文件的所有操作就可以对这个文件描述符进行操作。比如程序中open()函数的返回值赋给了应用程序中的devfd,后面则可以对其进行操作;若打开失败返回负数。
4)ioctl()函数:用于设置编码比特、采样频率和选择声道。(1)函数定义:int ioctl(struct inode *inode, struct file *file,unsigned int cmd, unsigned long arg);(2)函数说明:设备驱动程序中对设备的I/O通道进行管理的特殊控制函数,可以通过它向设备传递控制信息或从设备取得状态信息,实现用户程序命令和驱动命令的相互联系;
(3)返回值:执行成功返回正数,失败返回-1。
5)s3c2410_uda1341_init()函数:动态加载驱动模块时的初始化函数。(1)函数定义:int __init s3c2410_uda1341_init(void);
(2)函数说明:该函数首先会初始化I/O和UDA1341 芯片,然后申请2个DMA 通道用于音频传输。将输出音频缓冲区的DMA通道设为通道2,输入音频缓冲区的DMA 通道设为通道1。最后调用register_sound_dsp()和register_sound_mixer()两个函数来分别注册驱动设备;
(3)返回值:初始化成功,返回0;DMA 通道初始化设置失败,返回负数。6)void __exit s3c2410_uda1341_exit()函数:动态卸载驱动模块时调用的函数。
(1)函数定义:void __exit s3c2410_uda1341_exit(void);
(2)函数说明:注销音频设备,分两次调用audio_clear_dma()函数来分 别释放已申请的音频输入和音频输出的DMA 通道;
(3)返回值:无。
5.3 功能模块交叉编译
用命令Makefile来编译:
图5.1 编译测试文件
将test文件拷贝到D:cygwinusrlocalsrcedukit-2410rootbin中 执行以下命令生成新的文件系统映象:
$>cd $WORKDIR/ $>$SOURCEDIR/mkcramfs root root.cramfs.new
图5.2 生成系统映像文件
生成文件系统映象文件root.cramfs.new。第六章 根文件系统建立与文件系统下载
6.1 根文件系统分析
6.1.1 cramfs 目录结构
一个完整的根文件系统通常包含以下几个目录: /bin 应用程序存放目录。
/sbin 系统管理员服务程序,其中最重要的就是供内核初始化之后执行的/sbin/init 进程。
/lib 存放程序运行所需要的动态库。/proc 系统状态文件目录。/dev 驱动程序存放目录。
/etc 系统配置文件及用户数据存放目录。
/mnt 用于设备安装的目录,通常包含etc 子目录和为块设备安装保留目录。/usr 用于存放用户程序和配置文件的目录,可以根据需要进行设置。一般情况下都要把已经规划好的目录结构转换成一个映象文件,即使用命令工具mkcramfs(cygwin下为mkcramfs.exe),把相应的cramfs 目录树压缩为单一的映象文件。其命令格式为:
mkcramfs [-h] [-e edition] [-i file] [-n name] dirname outfile 使用mkcramfs.exe 在cygwin 下编译生成文件系统映象文件root.cramfs,再固化到开发系统FLASH 上运行。6.1.2 构建cramfs 文件系统
按照本节实验原理中自行构建一个cramfs 文件系统。运行cygwin,执行以下命令解压安装:
$> source /tmp/edukit-2410/set_env_linux.sh //Linux 编译环境变量设置
$> cd $WORKDIR/
图6.1 构建文件系统
$> tar-xvjf /tmp/edukit-2410/root.cramfs.tar.bz2 $> ls „ root „ root 文件夹中就是我们想要的cramfs 文件系统
6.2 文件系统映像文件生成
6.2.1 编译一个应用测试程序test.c 按设计原理要求编写一个应用程序test.c,存放在/home/app/audio目录下,进入该目录后执行以下命令编译链接测试程序:
$> cd /home/app/audio $> make(也可以编写Makefile 来编译)
图6.2 编译test文件
6.2.2 拷贝测试程序到文件系统中,并编译生成文件系统映象
把刚才编译输出的test文件拷贝到文件系统所在的工作目录 root/usr/audio 目录下,执行以下命令生成新的文件系统映象:
$> cd $WORKDIR/ $> $SOURCEDIR/mkcramfs root root.cramfs.new
图6.3 生成映象
刚刚编译生成的文件系统映象root.cramfs.new 中已经包含测试程序。
6.3 文件系统下载
(1)首先SW104 设为短接(从Nand Flash 启动),确定已经成功烧写vivi 和linux kernel,加电运行可以看到vivi 启动信息,输入空格进入命令状态;
(2)双击运行Download.pjf 工程文件(将启动Embest IDE 环境),点击连接Remote connect,程序应该正在运行(此时命令按钮STOP 为红色);在超级终端输入help 看看有没有反应,如果没反应,点击IDE 按钮:Reset->Start(F5);再输入help 测试,直到有反应为止;
(3)如果超级终端可以输出一些信息,再点击IDE 中的Stop,配置Debug 的Download 地址为0x30000000,并点击IDE 菜单Project 选择Settings 项,在Download 页下拉Category 到Download 项,在Download File 选择root.cramfs.new 文件,路径为d:Cygwinusrlocalsrcedukit-2410点击确定后:
图6.4 选择加载的文件
首先点击IDE 菜单DEBUG 选择Download 下载文件系统映象 约1-2 分钟
图6.5 下载成功
其次下载完毕后,点击Start(F5)然后在超级终端里输入:load flash root j(烧写更新文件系统)
图6.6 烧写
注意:只能在“vivi的烧写”和linux内核操作完成后,才可以按以上方法正确烧写root映象到NandFlash。重起实验板,观测超级终端窗口提示信息,引导整个系统启动到linux行命令输入状态。在超级终端输入一些linux命令查看执行结果是否正确。
6.4 功能模块运行与调试
重新加电,在超级终端根据提示启动Linux,按提示输入cd bin、./test指令。
图6.7 输入指令
图6.8 在控制台下运行测试程序
程序执行完后。如图6.9。
图6.9 程序运行时超级终端的输出
第七章 课程设计总结与体会
7.1 得出的结论
通过按上述步骤执行相关应用程序,可以实现对语音的实时采集和播放。需改进的地方:通过录制一段语音信息,录制完成后再播放
7.2课程设计过程中遇到的问题及解决方法
1.在给vivi打补丁时,$> patch-p1
2.在图形界面下进行内核配置时按实验指导书配置导致少了sound这一步导致出错。
3.重新在图形界面下配置后,发现无法生成压缩映像文件。请教研究生后解决了。原来之前配置错误生成了boot文件夹,要把之前boot删掉后重新编译。4.在调试时输入cd bin,./test指令后超级终端无反应。查找后发现,原来在根文件系统编译时没把生成的test文件复制到文件系统所在的工作目录root/bin目录下。重新编译后把生成的test文件复制后在调试后可以进行录放测试。
7.3 心得体会
课程设计刚开始的时候,思绪全无,我真的感到 “书到用时方恨少”,所以又重新把书和实验指导看了几遍,对知识系统而全面进行了梳理,对许多不理解的地方通过上网搜索翻阅图书弄懂,终于熟练掌握了基本理论知识,而且领悟诸多平时学习没有注意到的细节步骤,学会了如何思考的思维方式,找到了设计的灵感。
虽然每天要顶着30多度的高温在宿舍跟实验室之间往返,流了不少汗水,感觉确实不舒服,可最后看到自己的成果后心里很充实很高兴。
在课程设计过程中遇到了这样那样的困难。有时候是电脑出问题了,有时候
是实验箱出毛病,有时候是自己在操作过程中操作错误无法继续,可在研究生学长和其他同学的帮忙下都一一解决。使我深深感觉到团队力量的强大。
最后再次感谢陈老师这学期兢兢业业地给我们传授知识,感谢三位研究生牺牲自己的时间在炎热的夏天帮助我们解决遇到的问题!
参考文献
[1]徐英慧,等.ARM9嵌入式系统设计——基于S3C2410与Linux[M].北京:北京航空航天大学出版社,2007.[2]于明,等.ARM9嵌入式系统设计与开发教程[M].北京:电子工业出版社,2006.[3]田泽.ARM9嵌入式开发实验与实践[M].北京:北京航空航天大学出版社,2006.[4]孙天泽,等.嵌入式设计及Linux驱动开发指南——基于ARM9处理器[M].2版.北京:电子工业出版社,2007.[5]周立功,等.ARM9&WinCE实验与实践——基于S3C2410[M].北京:北京航空航天大学出版社,2007.[6]Samsung Electronics.S3C2410A-200MHz
&
266MHz
32-Bit
RISC Microprocessor USER’S MANUAL Revision 1.0.http://www.xiexiebang.com [7]魏洪兴.嵌入式系统设计师教程[M].北京:清华大学出版社,2006.[8]张纪坤,等.嵌入式Linux系统开发技术详解——基于ARM[M].北京:人民邮电出版社,2006.[9]吴明辉,等.基于ARM的嵌入式系统开发与应用[M].北京:人民邮电出版社,2004.[10]王田苗.嵌入式系统设计与实例开发[M].2版.北京:清华大学出版社,2003.[11]俞建新,等.嵌入式应用程序开发综合实验9例[M].北京:清华大学出版社,2004.[12]许海雁,等.嵌入式系统技术与应用[M].北京:机械工业出版社,2002.36
第二篇:嵌入式系统数字图像采集接口电路设计经验总结
摘要:本文介绍了两种用于嵌入式系统的数字图像采集接口方法,I/O接口和内存直接写入。在对采集速度要求不高的应用中,I/O接口方法可以简化接口电路设计,减少系统资源。对于要求实时进行图像处理的系统,直接写入内存法可以在不需要处理器干预的情况下,直接将图像数据写入系统存储区内,实现高速图像采集。
关键词:嵌入式系统,图像采集,电路设计
Abstract: In this paper, we present two different interfaces between digital a image sensors and a processor for embed systems, I/O mode and DMW(Direct Memory Write)mode.In I/O mode, processor can read image data through I/O port, and the interface is simple.In DMW mode, image data can be write into RAM directly while a processor is suspended.Key words: Embed System, Image Capture, Electronic Circuit
一、引言
随着半导体技术的飞速发展,具有图像功能的嵌入式应用愈来愈多。从数码相机、可视电话、多功能移动电话等消费产品到门禁、数字视频监视等工业控制及安防产品,图像采集和处理已成为重要的组成部分之一。图像采集需要进行同步信号的处理,比通常的A/D数据采集过程复杂,电路的设计也较为困难。传统PC上的图像采集卡都是在Philips、Brooktree等半导体公司提供的接口芯片基础上,由专业公司开发生产。在嵌入式系统中不同的处理器和图像传感器的信号定义及接口方式不同,没有通用的接口芯片。另外,利用系统中的现有资源设计图像采集电路,可以减少器件数量、缩小产品体积和降低系统成本。所以,通常嵌入式系统中要求自行设计图像采集接口电路。本文针对不同采集速度的要求,提出了两种图像采集接口电路的设计方法。
目前市场上主流的图像传感器有CCD、CMOS两种器件,其中CMOS器件上世纪90年代产生,近年来得到了迅速发展。传感器的输出有模拟和数字两种。由于CMOS器件功耗小、使用方便,具有直接数字图像输出功能,作者在设计时选用了CMOS数字输出图像传感器件。其他方式器件的接口设计与此类似,将在讨论中说明。
本文内容做如下安排:第二部分简述图像信号的特点;第三、四部分分别介绍I/O和内存直接写入两种接口设计方法;最后部分是讨论。
二、图像信号介绍
图1给出了采样时钟(PCLK)和输出数据(D)之间的时序关系。在读取图像数据时用PCLK锁存输出数据。除采样时钟(PCLK)和数据输出(D)外,还有水平方向的行同步信号(HSYNC))和垂直方向的场同步信号(VSYNC)。对于隔行扫描器件,还有帧同步信号(FRAME)。如图2,一帧包括两场。图2中窄的矩形条是同步脉冲,同步脉冲期间数据端口输出的数据无效。
PLCK存在时,图像数据端口连续不断地输出数据。由于行之间以及场之间输出数据无效,在采集图像数据必须考虑同步信号,读取有效数据才能保证图像的完整性。
三、I/O接口设计
对于MCU、DSP处理器,I/O是最方便的访问方式之一。以I/O方式读取图像数据不仅可以简化电路设计,而且程序也很简单。但由于读取每一个像素都要检测状态,在处理器速度低的情况下,读取图像慢。在处理器速度快或图像采集速度要求不高的应用中,I/O接口方式是一个较好的选择。
1、电路原理和结构
在图像传感器和处理器之间,利用两个锁存器分别锁存状态和图像数据,处理器通过两个I/O端口分别读取。图3中,在采样时钟的上升沿数据锁存器保存传感器输出的图像数据,当处理器通过I/O口读取图像时,数据锁存器输出数据。其它情况下,锁存器输出处于高阻状态。处理器通过状态锁存器读取同步信号和图像就绪(Ready)指示信号。在数据锁存器保存图像数据的同时,状态锁存器产生Ready信号(从‘0’到‘1’)。处理器读取图像数据时,Ready信号自动清除(从‘1’到‘0’)。处理器读取状态时锁存器驱动总线,其他情况下输出处于高阻状态。
2、图像读取流程
要保证图像的完整性就必须从一场图像的第一行开始读取,对于隔行扫描输出的图像则必须从一帧的第一行开始读取。读取每行图像数据时,则从该行的第一个像素开始。因此,在读取图像数据前应先判断场和行的起始位置。图4是通过I/O接口方式读取图像数据的流程。读取每个像素数据前先查询数据状态,如果数据已准备好则读取数据。
3、同步信号检测
为了简化电路设计,用处理器直接读取同步信号,然后找出场和行的起始位置。
从图2可以看出,处理器读取同步信号时,信号可能处在同步脉冲状态(‘1’)或正常状态(‘0‘)。对于那些同步信号反向的器件,则分别为‘0’和‘1’。如果信号处于同步脉冲状态,第一次检测到的正常状态就起始位置。如果信号处于正常状态,则首先检测到脉冲状态,然后用同样的方法确定起始位置。
通过上述方法可以检测出场的起始位置和行起始位置。
4、用VHDL设计锁存器
在应用中,以上两个锁存器的功能和其他逻辑集中在一起,用可编程逻辑器件实现。下面分别为它们的VHDL表示。
设DO(0-7)是锁存器输出端,DI(0-7)是锁存器输入端,DM(0-7)是中间状态,Data_R是数据读信号(低电平时有效),则数据锁存器的VHDL描述为:
Process(reset, PCLK)--锁存图像数据
Begin If reset='0' then DM<=“00000000”;--清除数据
Else if PCLK'event and PCLK='1' then DM<=DI;--锁存数据
End if;End process;Process(DM, Data_R)--读取图像数据
Begin If Data_R='0' then DO<=DM;--输出图像数据
Else DO<=“ZZZZZZZZ”--输出高阻
End if;End process;进一步设数据有效状态为Dstatus, 状态读写信号为Status_R(低点平时有效),则状态锁存器的VHDL描述为:
Process(reset, PCLK,Data_R)--数据有效状态控制
Begin If reset='0' or Data_R='0' then Dstatus<='0';--清除状态
Else if PCLK'enent and PCLK='1' then Dstatus<='1';--设置状态
End if;End process;Process(Dstatus, Status_R)--读取状态和同步信号
Begin If Status_R='0' then DO0<=Dstatus;DO1<=VSYNC;DO2<=HSYNC;DO3<=FRAME;Else DO<=“ZZZZZZZZ”;--高阻状态
End if;End process;
四、内存直接写入接口设计
在处理器速度较慢且图像数据输出的频率不能降低的情况下,采用上述I/O接口方法不能得到完整的图像。另外,有些应用中要求能够实时采集图像。为此,我们设计了高速数据图像采集方法―内存直接写入法。由于SRAM访问控制简单,电路设计方便,被大量嵌入式系统采用,本文以SRAM作为存储器。
1、电路原理和结构
内存直接写入方法通过设计的图像采集控制器(以下简称控制器)不需处理器参与,直接将图像数据写入系统中的内存中,实现高速图像采集。
图5是接口结构图,当需要采集图像时,处理器向控制器发出采集请求,请求信号capture_r从高到低。控制器接到请求脉冲后,发出处理器挂起请求信号HOLD,使处理器的外总线处于高阻状态,释放出总线。控制器收到处理器应答HOLDA后管理总线,同时检测图像同步信号。当检测到图像开始位置时,控制器自动产生地址和读写控制信号将图像数据直接写入内存中。图像采集完成后,控制器自动将总线控制权交还处理器,处理器继续运行,控制器中与采集相关的状态复位。控制器可以根据同步信号或设定的采集图像大小确定采集是否完成。
在图5中,控制器包括同步信号检测、地址发生器、SRAM写控制器、总线控制器和处理器握手电路等主要部分。同步信号检测确定每一场(帧)和每一行的起始位置;地址发生器产生写SRAM所需的地址;SRAM写控制器产生写入时序;总线控制器在采集图像时管理总线,采集完成后自动释放;处理器握手电路接受处理器命令、发总线管理请求和应答处理器。
2、SRAM写控制时序
采集图像过程中,控制器自动将数据写入到硬件设定的内存中。写内存时,控制器产生RAM地址(A)、片选信号(/CS)、读信号(/RD)和写信号(/WD),同时锁存传感器输出的数据并送到数据总线(D)上。每写入一个数据后,地址(A)自动增1。采集时/CS保持有效(‘0’)状态而/RD处于无效状态(‘1’)。地址A的变化必须与/WD和数据锁存器协调好才能保证图像数据的有效性。
图6是控制器产生的SRAM信号时序图。用PCLK作为地址发生器的输入时钟,且在其上升沿更新地址值。同样,在PCLK的上沿锁存数据并输出到总线上。将PCLK反相,作为/WD信号,使得在/WD的上升沿地址和数据稳定,确保写入数据的有效性。
3、控制器主要功能的VHDL描述 描述控制器中全部功能的VHDL代码较长,而且有些部分是常用的(如计数器等)。图像采集状态产生和同步信号的检测是其中重要的部分。下面介绍这两部分的VHDL描述。
图像采集状态 capture_s: 处理器的采集请求信号capture_r使capture_s从‘0’到‘1’,场地址发生器(计数器)的溢出位vcount_o,清除capture_s。
process(capture_r, reset, vcount_o)begin if reset='0' or vcount_o='1' then capture_s<='0';--清除
else if capture_r'event and capture_r='0' then capture_s<='1';--置状态位
end if;end process;同步信号检测:
只有在采集状态capture_s有效时(‘1’)才检测场同步信号,场同步信号下降沿置场有效状态(vsync_s),场地址发生器溢出位vcount_o清除场有效状态。只有在vsync_s有效情况下才检测行同步信号,行同步信号下降沿置行有效状态(hsync_s),行计数器溢出信号hcount_o清除行状态。只有在行状态有效的情况下计数器才工作,且将数据写入RAM。
Process(capture_s,reset,vcount_o, vsync)Begin If reset='0' or vcount_o='1' or capture_s='0' then Vsync_s<='0';--清除
Else if vsync'event and vsync='0' then Vsync_s<='1';--置状态位
End if;End process;Process(vsync_s, reset, hcount_o, hsync)Begin If vsync_s='0' or reset='0' or hcount_o='1' then Hsync_s<='0';--清除
Else if hsync'event and hsync='0' then Hsync_s<='1';--置状态位
End if;End process;
五、讨论
我们在基于TI公司的TMS320C3X系列DSP开发的嵌入式指纹图像处理模块中分别用上述两种方法成功实现了指纹图像的采集。
采用I/O接口方式最关键的是要求处理器的频率远高于图像数据输出的频率。例如,如果处理的指令周期为20ns,读取每个数据需要10个指令周期,则数据的输出频率不能超过5MHz,它低于一般的CMOS图像传感器件最快的数据输出频率。例如国内使用较多的OV7610和OV7620,其正常输出数据频率为13.5MHz。在应用过程中,通常改变传感器中寄存器的设置值,降低其数据输出频率。本文选用的是CMOS数字输出图像传感器。对于模拟视频信号,在设计时应加同步分离和A/D转换电路。图像采集的数字接口和逻辑控制与本文相同。
在我们系统中所采集的是单色图像,如果采集彩色图像逻辑设计是相同的所不同的只是数据宽度和后期处理方式。
具体应用中可根据需求对上述设计进行修改以满足不同的要求。
第三篇:嵌入式远程视频采集系统的设计与实现(基于S3C2410)
嵌入式远程视频采集系统的设计与实现(基于S3C2410)
发 布 时 间 : 2008-11-19 来 源 : 中电网 作 者 : 张永强,赵永勇,李崇德 浏 览 :
984
多媒体通信技术的发展为信息的获取和传输提供了丰富的手段,视频采集是其中不可缺少的重要组成部分,该系统基于S3C2410的ARM9芯片和嵌入式Linux操作系统,采用USB摄像头捕捉视频,经MPEG-4算法压缩编码,系统直接与网络相连,用户使用标准的网络浏览器和流媒体播放程序即可查看远程视频影像。硬件系统
系统硬件平台选用基于ARM9架构嵌入式芯片S3C2410,稳定工作在202MHz主频,板载64MB SDRAM 64MB FLASH,主板资源包括:主USB口、从USB口、10M/100M以太网口,触摸屏、彩色LCD、键盘、8个用户自定义LED数码管,A/D,RTC电路,2个串口、1个JTAG通用接口,音频模块,支持MPEG4,MP3编解码,3个168PIN的扩展插座,32位的数据总线,保留充分扩展空间。
其中标配模块包括:IC卡+PS2模块、IDE硬盘+CF卡模块、PCMCIA+SD/MMC模块。另外可选配模块有:GPS模块,GPRS模块,FPGA模块,CAN+AD+DA模块、红外模块、蓝牙模块、摄像头模块。软件系统
2.1 内核配置与USB摄像头驱动
假定已经搭建好嵌入式Linux的开发环境,下面第一步工作就是USB摄像头的安装与驱动。首先检查Linux Kernel中是否已经添加了USB模块的支持,并且加入Video4Linux支持。
Multimedia devices→Video For Linux
Video For Linux→[*]V4L information in proc filesystem
在主菜单的USB Support下还有各种摄像头的驱动,选中将要使用的摄像头芯片类型。
<>USB IBM(Xirlink)C-it Camera support<*>USB OV511 Camera support<>USB Philips Cameras <>USB SE401 Camera support<>USB STV680(Pencam)Camera support<>USB 3com HomeConnect(akavicam)support 在USB摄像头选购时,优先考虑Linux内核公开支持的摄像头芯片,不然要额外编写相应的USB摄像头驱动程序,然后进行编译、安装。在此选用网眼公司的V3000产品,他采用了OV511的芯片。
确定USB摄像头被正常驱动后,下一步就是使用Video4Linux提供的API函数集来编写视频采集程序。
2.2 基于V4L设计的视频采集模块
在Linux下,所有外设都被看成是一种特殊的文件,称为设备文件。系统调用是内核和应用程序之间的接口,而设备驱动程序则是内核和外设之间的接口。他完成设备的初始化和释放、对设备文件的各种操作和中断处理等功能,为应用程序屏蔽了外设硬件的细节,使得应用程序可以像普通文件一样对外设进行操作。
Linux系统中的视频子系统Video4Linux为视频应用程序提供了一套统一的API,视频应用程序通过标准的系统调用即可操作各种不同的视频捕获设备。Video4Linux向虚拟文件系统注册视频设备文件,应用程序通过操作视频设备文件实现对视频设备的访问。
Linux下与Video4Linux相关设备及用途如表1所示。
这里主要针对设备文件/dev/video进行视频捕捉方面的程序设计。
Linux下视频采集流程如图2所示。
其中用到的主要函数有:
Camera_open():用来开启视频设备文件,使用前需要首先声明一个video_device类型的设备文件。
Camera_get_capability():通过调用ioctl()函数取得设备文件的相关信息,并存放到video_capability结构里。
Camera_get_picture():通过调用ioctl()函数取得图像的相关信息,并且存放到video_picture结构里。
Camera_close():用来关闭设备文件。Camera_grab_image():用来抓取图像,采用mmap方式,直接将设备文件/dev/video0映射到内存,加速文件I/O操作,还可以使多个线程共享数据。
剩下的还有设备初始化、参数设备等相关函数,不再详述。
2.3 视频压缩编码模块
获取图像数据后,可以直接输出到FrameBuffer进行显示,由于本系统要将采集到的视频影响通过网络传输出去,所以在传输之前要对原始的图像数据进行压缩编码,在此选用MPEG-4视频编解码方案。和其他标准相比,MPEG-4压缩比更高,节省存储空间,图像质量更好,特别适合在低带宽条件下传输视频,并能保持图像的质量。
MPEG-4中基于对象的视频编码过程可以分为3步进行:
(1)从原始视频流中分割视频对象。
(2)对视频对象进行编码,对不同视频对象的运动信息、形状信息、纹理信息分配不同的码字。对输入的任意形状的VOP序列,用基于块的混合编码技术编码,处理顺序是先IVOP后PVOP,BVOP。在对VOP的形状信息编码后,取得任意形状VOP的采样,每个VOP划分为不相交的宏块,每个宏块含有4个8×8象素块进行运动补偿以及纹理编码,已编码的VOP帧保存在帧存中,在当前VOP帧和已编码VOP帧之间的计算运动矢量;对将编码的块和宏块,计算他们的运动补偿预测误差;运动补偿预测后的IVOP及误差用8×8块DCT变换,并进行DCT系数的量化,然后是游程编码和熵编码。
(3)对各个视频对象的码流进行复合,每个视频对象的形状、运动纹理信息复合成VOL比特流,各视频对象视频流复合成统一的码流输出。对视频流进行压缩编码以后,接下来就要实现网络传输部分的功能。
2.4 JRTPLIB网络传输模块
流媒体指的是在网络中使用流技术传输的连续时基媒体,RTP是目前解决流媒体实时传输问题的好办法,JRTPLIB是一个面向对象的RTP库,他完全遵循RFC1889设计,下面讲述如何在Linux平台上运用RTP协议进行实时流媒体编程。
2.4.1 初始化 在使用JRTPLIB进行实时流媒体数据传输之前,首先应该生成RTPSession类的一个实例来表示此次RTP会话,然后调用Create()方法来对其进行初始化操作。RTPSession类的Create()方法只有一个参数,用来指明此次RTP会话所采用的端口号。
2.4.2 数据发送
当RTP会话成功建立起来之后,接下来就可以开始进行流媒体数据的实时传输了。首先需要设置好数据发送的目标地址,RTP协议允许同一会话存在多个目标地址,这可以通过调用RTPSession类的AddDestination()、DeleteDestination()和ClearDestinations()方法来完成。目标地址全部指定之后,接着就可以调用RTPSession类的SendPacket()方法,向所有的目标地址发送流媒体数据。
2.4.3 数据接收
对于流媒体数据的接收端,首先需要调用PollData()方法来接收发送过来的RTP或者RTCP数据报。由于同一个RTP会话中允许有多个参与者(源),因此既可以通过调用GotoFirstSource()和GotoNextSource()方法来遍历所有的源,也可以通过调用GotoFisstSourceWithDat()和GotoNextSourceWithData()方法来遍历那些携带有数据的源。在从RTP会话中检测出有效的数据源之后,接下去就可以调用RTPSession类的GetNextPacket()方法从中抽取RTP数据报,当接收到的RTP数据报处理完之后,要及时释放。
JRTPLIB为RTP数据报定义了3种接收模块,通过调用RTPSession类的SetReceiveMode()方法可以设置下列这些接收模式:
RECEIVEMODE_ALL:缺省的接收模式,所有到达的RTP数据报都将被接受;RECEIVEMODE_IGNORESOME:除了某些特定的发送者之外,所有到达的RTP数据报都将被接受,而被拒绝的发送者列表可以通过调用AddToIgnoreList(),DeleteFromIgnoreList()和ClearIgnoreList()方法来进行设置;RECEIVEMODE_ACCEPTSOME:除了某些特定的发送者之外,所有到达的RTP数据报都将被拒绝,而被接受的发送者列表可以通过调用AddToAcceptList(),DeleteFromAcceptList和ClearAcceptList()方法来进行设置。
2.4.4 控制信息 JRTPLIB是一个高度封装后的RTP库,只要PollData()或者SendPacket()方法被成功调用,JRTPLIB就能够自动对达到的RTCP数据报进行处理,并且还会需在要的时候发送RTCP数据报,从而能够确保整个RTP会话过程的正确性。
在本系统中,使用RTPSession JRTPLIB类库提供的方法来实现底层的RTP/RTCP操作,并且把他封装在CrtpTransmitter类中,该类从Media Sink类继承而来,接收到相应的媒体帧数据,使用RTPSession类库的操作把数据发送到网络上。结语
本系统基于S3C2410平台和Linux操作系统,利用Video4Linux设计采集程序,使用MPEG-4压缩编码算法,通过实时流媒体传输技术实现了网络传输,整个系统具有稳定可靠、安装简便、成本低廉等特点,可扩展应用在工业控制、视频会议系统、可视电话、远程监控系统等诸多领域。
第四篇:嵌入式程序设计课程设计
课程设计
课 程 名嵌入式软件开发技术
题 目 基于嵌入式Linux的温度监测系统的
设计与实现
专 业 计算机科学与技术(嵌入式系统方向)班 级 13计算机嵌入式系统班 学 号 学生姓名
2016年6月
摘要
温度是个很普遍而又非常重要的参数,在日常生活、工农业生产以及科研领域都有着广泛的应用。因此,研制能够准确地测量和记录这个参数值的系统具有十分重要的意义。
基于ARM的嵌入式温度监测系统是采用嵌入式Linux作为操作系统,针对以S5PV210为处理器的开发板设计的一个嵌入式温度监测系统。论文在分析了Linux设备驱动程序的基本工作原理基础上,讨论了开发中经常会碰到的中断处理、拥塞处理、I/O端口,并在此基础上实现了基于S5PV210嵌入式处理器的开、读、写、关外部RAM的字符设备驱动和网络驱动。结合高精度温度传感器DS18B20,实现温度的正确采集,并通过以太网络将数据上传给上位机客户端。
论文首先介绍了通信网络中各种设备特性、总线结构及传输技术,然后根据单片机与PC机之间的串行通信原理,用ubantu完成温度监测系统的软件设计与实现,为用户提供一个友好的人机界面,对监测系统进行控制并显示采集后的数据。本系统还通过多线程实现了多个客户端与服务器的通信。
关键词:S5PV210;嵌入式Linux操作系统;DS18B20;网络编程
I
Abstract
Temperature is a very common and very important parameter, in daily life, industrial and agricultural production and scientific research fields have a wide range of applications.Therefore, it is very important to develop a system that can accurately measure and record the value of this parameter.The temperature monitoring system of base on the ARM is use of embedded Linux as the operating system for the processor to S5PV210 development board designed for an embedded temperature monitoring system.Based on the analysis of the basic working principle based on the Linux device drivers discussed development often encounter interrupt handling, congestion handling, I / O ports, and on this basis to achieve the embedded processor based on open S5PV210 reading, writing, characters off the external RAM device driver and network drives.Combined with precision temperature sensor DS18B20, to achieve the correct temperature acquisition, and upload the data via Ethernet to a PC client.At first,the paper introduces the characteristics of various devices in a communication network, the bus structure and transmission technology, and according to the principle of serial communication between SCM and PC, with ubantu complete temperature monitoring system software design and implementation, to provide users with a friendly man-machine interface, the monitoring system to control and display the data after collection.The system also enables communication via a plurality of multi-threaded client and the server.Key words:S5PV210;embedded Linux operating system;DS18B20;Network programming
II
1.引言.......................................................................................................................................1 1.1 设计背景及意义...............................................................................................................1 1.2 设计的主要内容................................................................................................................2 2.相关技术...............................................................................................................................2 2.1 嵌入式Linux......................................................................................................................2 2.2 S5PV210.............................................................................................................................3 2.3 socket网络编程..............................................................................................................3 3.具体实现功能.......................................................................................................................4 3.1总体框架图........................................................................................................................4 3.2客户端功能........................................................................................................................5 3.3 服务器功能........................................................................................................................5 3.4 实验板输出信息...............................................................................................................5 4.具体实现过程.......................................................................................................................6 4.1 交叉编译工具的安装.......................................................................................................6 4.2 客户端模块的设计...........................................................................................................7 4.3 服务器模块.......................................................................................................................8 4.4 LED点亮模块..................................................................................................................10 4.5 温度感应模块.................................................................................................................11 5.测试结果分析.....................................................................................................................13 5.1 各模块运行的效果.........................................................................................................13 5.2 可扩展功能......................................................................................................................15 6.总结与展望.......................................................................................................................15
第一章 引言
1.1 设计背景及意义
温度作为工业、农业、国防和科研等部门最普遍的测量项目。它在工农业生产、现代科学研究以及高新技术开发过程中也是一个极其普遍而又非
常重要的参数。因此,在这些领域中,对于这个参数的测量与控制就显得尤为重要,特别是在纺织工业、冶金、化工、食品、温室种植,汽车制造以及气象预报和科研实验室等许多地方,都具有举足轻重的作用。
以往这些工作大多是由人工完成,不但工作量大,记录的数据少,对温度的调节缺乏实时性,而且电路复杂,标定和校准也比较麻烦,难以满足现代温度测量的要求[1]。自从传感器技术、微控制器技术和计算机技术日渐成熟之后,现代的温度测量与控制系统克服了以往系统中存在的一些问题,比如对环境温度的控制与调节以及数据的记录都由微控制器或计算机自动完成,人们的工作量大大地降低,而且测得的数据也更加的精确,对环境温度的调节更具有实时性[2]。
1.2 设计的主要内容
此次主要采用嵌入式Linux作为操作系统,针对以S5PV210为处理器的开发板设计的一个嵌入式温度监测系统。在Linux设备驱动程序的基本工作原理基础上,讨论了开发中经常会碰到的中断处理、拥塞处理、I/O端口,并在此基础上实现了基于S5PV210嵌入式处理器的开、读、写、关外部RAM的字符设备驱动和网络驱动。结合高精度温度传感器DS18B20,实现温度的正确采集,并通过以太网络将数据上传给上位机客户端。
温度监测系统根据Linux中的网络通信技术和串口通信技术来传输数据。用ubantu完成温度监测系统的软件设计与实现,为用户提供一个友好的人机界面,对监测系统进行控制并显示采集后的数据。本系统还通过多线程实现了多个客户端与服务器的通信。
第二章 相关技术
2.1 嵌入式Linux Linux是UNIX系统的一套免费使用和自由传播的类Unix操作系统,是一个基于POSIX和UNIX的多用户、多任务、支持多线程和多CPU的操作系统。它能运行主要的UNIX工具软件、应用程序和网络协议。支持32位和64位硬件。Linux继承了Unix以网络为核心的设计思想,是一个性能稳定的多用户网络操作系统。它诞生与1991年的10月5日。以后借助与Internet
网,并进过全世界各地计算机爱好者的共同努力下,现已成为世界上使用最多的一种UNIX类操作系统,并且使用人数还在迅猛增涨。
本次设计采用Linux作为嵌入式操作系统的原因有以下几点:[3] 1)低成本开发系统: 2)可应用于多种硬件平台 3)可定制的内核 4)性能优异 5)良好的网络支持
2.2 S5PV210
S5PV210又名“蜂鸟”(Hummingbird),是三星推出的一款适用于智能手机和平板电脑等多媒体设备的应用处理器。
S5PV210采用了ARM CortexTM-A8内核,ARM V7指令集,主频可达1GHZ,64/32位内部总线结构,32/32KB的数据/指令一级缓存,512KB的二级缓存,可以实现2000DMIPS(每秒运算20亿条指令集)的高性能运算能力。
包含很多强大的硬件编解码功能,内建MFC(Multi Format Codec),支持MPEG-1/2/4,H.263,H.264等格式视频的编解码,支持模拟/数字TV输出。JPEG硬件编解码,最大支持8000x8000分辨率
内建高性能PowerVR SGX540 3D图形引擎和2D图形引擎,支持2D/3D图形加速,是第五代PowerVR产品,其多边形生成率为2800万多边形/秒,像素填充率可达2.5亿/秒,在3D和多媒体方面比以往大幅提升,能够支持DX9,SM3.0,OpenGL2.0等PC级别显示技术。
具备IVA3硬件加速器,具备出色的图形解码性能,可以支持全高清、多标准的视频编码,流畅播放和录制30帧/秒的1920×1080像素(1080p)的视频文件,可以更快解码更高质量的图像和视频,同时,内建的HDMIv1.3,可以将高清视频输出到外部显示器上。
2.3 socket网络编程
Socket是进程通讯的一种方式,即调用这个网络库的一些API函数实现分布在不同主机的相关进程之间的数据交换。[4] 几个定义:
(1)IP地址:即依照TCP/IP协议分配给本地主机的网络地址,两个进程要通讯,任一进程首先要知道通讯对方的位置,即对方的IP。
(2)端口号:用来辨别本地通讯进程,一个本地的进程在通讯时均会占用一个端口号,不同的进程端口号不同,因此在通讯前必须要分配一个没有被访问的端口号。
(3)连接:指两个进程间的通讯链路。
(4)半相关:网络中用一个三元组可以在全局唯一标志一个进程:(协议,本地地址,本地端口号)
这样一个三元组,叫做一个半相关,它指定连接的每半部分。(4)全相关:一个完整的网间进程通信需要由两个进程组成,并且只能使用同一种高层协议。也就是说,不可能通信的一端用TCP协议,而另一端用UDP协议。因此一个完整的网间通信需要一个五元组来标识:(协议,本地地址,本地端口号,远地地址,远地端口号)
这样一个五元组,叫做一个相关(association),即两个协议相同的半相关才能组合成一个合适的相关,或完全指定组成一连接。
第三章 具体实现功能
3.1总体框架图
图1 项目总体框架图
3.2客户端功能
1)显示简单的用户界面 2)发送命令给服务器 3)接收服务器传输的数据 4)显示温度数据
3.3 服务器功能
1)接收客户端发送的命令 2)处理命令
3)把命令转发给硬件 4)获取硬件处理所得的数据 5)把该数据传给客户端
3.4 实验板输出信息
1)LED灯按照客户端的指令亮灭 2)蜂鸣器唱歌
3)核心板控制输出温度传感器的数据到服务器
第四章 具体实现过程
个应用系统要完成各项功能,首先必须有较完善的硬件作保证。同时还必须得到相应设计合理的软件的支持,尤其是微机应用高速发展的今天,许多由硬件完成的工作,都可通过软件编程而代替。甚至有些必须采用很复杂的硬件电路才能完成的工作,用软件编和有时会变得很简单。因此充分利用其内部丰富的硬件资源和软件资源。
程序设计语言有三种:机器语言、汇编语言、高级语言。本系统运用的是高级语言所编写,也就是C语言。所用到的开发平台为ubuntu系统。
4.1 交叉编译工具的安装
(1)考虑到现今Linux平台发展,交叉编译平台编统一为arm-linux-gcc-4.4.3(2)在windows系统下,建立一个共享目录,如:e:/linux_file(3)将光盘目录linux中的arm-linux-gcc-4.4.3.tar.gz 复制到e:/linux_file(4)注意在进行虚拟机设置时使共享目录的有效,并添加共享目录e:/linux_file(5)进入linux操作系统,root目录下建立一个Armcode的子目录,将共享目录下的文件arm-linux-gcc-4.4.3.tar.gz复制到该目录(6)然后进入到该目录,执行解压命令:#cd /root/Armcode;#tar xvzf arm-linux-gcc-4.4.3.tgz –C /;注意:C 后面有个空格,并且C 是大写的,它是英文单词“Change”的第一个字母,在此是改变目录的意思。(7)执行
该
命
令,将
把
arm-linux-gcc
安
装
到/opt/FriendlyARM/toolschain /4.4.3/bin 目录。
(8)把编译器路径加入系统环境变量,运行命令:#gedit /root/.bashrc 编辑/root/.bashrc 文件,在最后一行添加:export PATH=$PATH: /opt/FriendlyARM/toolschain/4.4.3/bin(9)重新登录系统(不必重启机器,开始->logout 即可),使以上设置生效,在命令行输入:arm-linux-gcc –v,会出现如下信息,这说明交叉编译环境已经成功安装。
4.2 客户端模块的设计
用户界面的显示:
void interface_print(char *temp){ system(“clear”);printf(“e[31m*******************2016梧*********************e[0mn”);printf(“e[31m*
*e[0mn”);printf(“e[31m*e[0m e[32m点亮LED1: on1
on2e[0me[31m
*e[0mn”);printf(“e[31m*e[0m e[33m关闭LED1: off1
off2e[0me[31m
*e[0mn”);printf(“e[31m*e[0m e[34m开蜂鸣器: onb
songe[0me[31m
*e[0mn”);printf(“e[31m*e[0m e[35m获取温度: get
e[31m *e[0mn”,temp);printf(“e[31m*e[0m e[36m退
出: e[0me[31m
*e[0mn”);printf(“e[31m*
*e[0mn”);printf(“e[31m******************未
来**********************e[0mn”);}
发送命令给服务器:
/*5.调用I/O函数(read/write)与客户端通讯。*/ int i = 5;int pos;while(1){
ret = poll(pfd,2,-1);
if(ret > 0){
if(pfd[0].revents == POLLIN){
interface_print(temp);
/*从终端读取数据*/
memset(buf,0,sizeof(buf));
ret = read(pfd[0].fd,buf,sizeof(buf)-1);7
州学院
|
点亮LED2:
|
关闭LED2:
|
播放音乐:
|
温度:[%s]e[0m quit
|
的大
神
们
} if(ret > 0){
}
/*发送数据给服务器*/ write(sockfd,buf,ret);
接受服务器传输的数据:
if(pfd[1].revents == POLLIN){
if(!strncmp(buf,“get”,3)){
/*接收服务器发送的信息*/
memset(temp,0,sizeof(temp));
ret = read(pfd[1].fd,temp,sizeof(temp)-1);
if(ret > 0){
temp[ret-1] = ' ';
/*把信息显示到终端*/
interface_print(temp);
}
} } 4.3 服务器模块
接收客户端发送的命令:
/*读取客户端信息*/
memset(buf,0,sizeof(buf));
ret = read(newfd,buf,sizeof(buf)-1);
if(ret > 0){
把命令转发给硬件:
/*发送命令给硬件*/
if(!strncasecmp(buf,“on1”,3)){
cmd = LED_ON;
val = 3;
}else if(!strncasecmp(buf,“on2”,3)){
cmd = LED_ON;
val = 4;
}else if(!strncasecmp(buf,“off1”,4)){
cmd = LED_OFF;
val = 3;
}else if(!strncasecmp(buf,“off2”,4)){
cmd = LED_OFF;
}
val = 4;
}else if(!strncasecmp(buf,“onb”,3)){
pwm_on();
}else if(!strncasecmp(buf,“song”,4)){
pwm_music_fun();
}
if(ioctl(fd_led,cmd,(unsigned long)val)< 0){
perror(“ioctl failedn”);
exit(1);
} } } return(void *)0;
获取硬件处理所得的数据:
void *do_temp(void *arg){ int newfd = *(int *)arg;char buf[100];int dev_fd;unsigned int temp[2];float tempvalue=0;unsigned pos;
dev_fd = open(“/dev/fs210_gpio”,O_RDWR | O_NONBLOCK);if(dev_fd < 0){
perror(“open”);
exit(1);}
while(1){
temp[1]= ioctl(dev_fd,GPIO_ON,temp);
/*
temp[1]&=0xffff;
tempvalue=(float)(temp[1])*0.0625;
*/
if(temp[1]&0x8000)
{
temp[1]= ~temp[1]+1;
temp[1]&=0xffff;
tempvalue=(float)(temp[1])*0.0625;
} } else {
temp[1]&=0xffff;
tempvalue=(float)(temp[1])*0.0625;} memset(buf,0,sizeof(buf));sprintf(buf,“%f”,tempvalue);strcat(buf,“n”);write(newfd,buf,strlen(buf));memset(buf,0,sizeof(buf));sleep(1);} return(void *)0;4.4 LED点亮模块
/*参考内核,采用静态的方式实现点灯和灭灯*/ void led_on(unsigned long val){ printk(“ %ld %sn”,val,__func__);gpio_set_value(S5PV210_GPC0(val),1);}
void led_off(unsigned long val){ printk(“ %ld %sn”,val,__func__);gpio_set_value(S5PV210_GPC0(val),0);}
long test_ioctl(struct file *file, unsigned int cmd, unsigned long data){ unsigned long val = data;switch(cmd){
case LED_ON:
led_on(val);
break;
case LED_OFF:
led_off(val);
break;
default:
break;
}
} return 0;/*向系统注册申请设备号*/ ret = register_chrdev(LED_MAJOR,LED_NAME,&led_fops);if(ret){ printk(“register chrdev failed!n”);errno =-EBUSY;
goto err1;}
/*创建一个设备类*/ led_dev->led_class = class_create(THIS_MODULE, LED_MODULE);if(IS_ERR(led_dev->led_class)){ printk(“class create failedn”);errno = PTR_ERR(led_dev->led_class);goto err2;} /*创建一个设备文件,之后系统会自动在/dev目录下自动创建一个设备文件*/ led_dev->led_device = device_create(led_dev->led_class,NULL,MKDEV(LED_MAJOR,0),NULL,“led”);if(IS_ERR(led_dev->led_device)){
printk(“class create failedn”);
errno = PTR_ERR(led_dev->led_device);
goto err3;} led_init();
return 0;
4.5 温度感应模块
static void WriteOneChar(unsigned char dat){ unsigned char i=0;
writel((readl(gph1con)& 0xFFFFFFF0)| 0x1, gph1con);//gph1_0,output spin_lock(&lock);for(i=0;i<8;i++){
writel(readl(gph1dat)&(0xFFFFFFFE), gph1dat);
__udelay(15);
if(dat&0x01){
writel(readl(gph1dat)| 0x1 , gph1dat);
}
else{
writel(readl(gph1dat)&(0xFFFFFFFE), gph1dat);
}
__udelay(45);
writel(readl(gph1dat)| 0x1 , gph1dat);
__udelay(1);
dat>>=1;} spin_unlock(&lock);}
static unsigned int ReadTemp(void){ unsigned char T_h=0;unsigned char T_l=0;unsigned int temp=0;
writel((readl(gph1pud)& 0xFFFc)| 0x02, gph1pud);//gph1_0,pull-up enabled
spin_lock(&lock);Init_DS18B2O();spin_unlock(&lock);__udelay(400);writel((readl(gph1con)& 0xFFFFFFF0)| 0x1, gph1con);//gph1_0,output writel(readl(gph1dat)| 0x1 , gph1dat);WriteOneChar(0xcc);WriteOneChar(0x44);mdelay(100);spin_lock(&lock);Init_DS18B2O();spin_unlock(&lock);__udelay(400);writel((readl(gph1con)& 0xFFFFFFF0)| 0x1, gph1con);//gph1_0,output writel(readl(gph1dat)| 0x1 , gph1dat);WriteOneChar(0xcc);WriteOneChar(0xBE);T_l=ReadOneChar();//L T_h=ReadOneChar();//H
temp=(unsigned int)(((unsigned int)T_h<<8)|T_l);
printk(“temp=%xrn”,temp);
return temp;}
第五章5.1 各模块运行的效果
客户端:
测试结果分析13
图2 客户端运行效果
服务器:
图3 服务器运行效果
开发板:
图4 开发板的显示效果
5.2 可扩展功能
本项目的只是完成其中的一些功能,其可扩展性强,对进行加强完善,还可作如下扩展:
1.拓展成温度报警器,设定一个上限值和下下限值,当温度达到某个值时,如低于20摄氏度时,LED灯亮,高于40摄氏度时,蜂鸣器发出报警提示音。
2.可使开发板的核心板链接生活中的物件,如台灯,或者房间的灯,从而控制生活中物件的开关。
3.找到家庭电器中的接口,连接相应接口可实现远程控制家电。
第六章 总结与展望
通过这次的课程设计,让我受益匪浅,让我对智能硬件有了更深一层的了解,也体会了智能化在现实生活中的重要性,也让我了解和掌握了一些编程思想。让
我把理论知识用在实践中,实现了理论和实践相结合,从中更懂得理论的是实践的基础,实践有能检验理论的正确性,更激发了我对专业知识的渴求,这些对我以后参加工作或者继续学习都会有很大的帮助和影响。通过这次课程设计,让我意识到了自己的一些不足,从而让我认识到了学习的重要性。
虽然这次实训是那么短暂的1周时间,但是这几天我所学到的还是很多的,通过此次培训学生运用本专业所学的理论知识和专业知识来分析解决实际问题的重要教学环节,是对三年所学知识的复习和巩固。同时通过这次培训让我明白了一个很深刻的道理,让我意识到了团队合作的重要性,一个人不能完成的事情,团队能完成。团队精神有利于提高组织整体效能,只有通过发扬团队精神,才能取得更好的成绩。
因时间及精力有限,系统做的还不是很完善,还是有不足的地方,如果时间充足的话,还可以做得更完善,对其进行功能扩展。
以上这些收获对我来说是非常有帮助的,让我受益匪浅,它也是我人生中一笔宝贵的财富。
参考文献
[1] 李勇, 艾竹君, 刘巧云等.一种新型温度测量系统的设计[J].低温与超导, 2007, 35(5):451-454 [2] 马净, 李晓光,宁伟.几种常用温度传感器的原理及发展[J].中国仪器仪表, 2004,(6):1
[3] 曹忠明, 程姚根.从实践中学嵌入式Linux操作系统[M].北京:电子工业出版社, 2014:8-9 [4] 陈刚 , 冯利美.从实践中学嵌入式Linux应用程序开发[M].北京:电子工业出版社, 2012:193-192
第五篇:嵌入式课程设计之触摸屏程序设计
嵌入式课程设计
设计题目:触摸屏驱动程序设计 班级: 学号: 姓名: 指导老师:
设计时间:2010年12月25日--12月28日
目录
第一部分 要求................................................................................................................................1 1.1设计目的.................................................................................................................................1 1.2 设计意义................................................................................................................................1 1.3 设计内容................................................................................................................................1 1.4 主要任务................................................................................................................................1 第二部分 正文................................................................................................................................2 2.1触摸屏工作原理(触摸屏接口工作模式).........................................................................2 2.2、设计总体方案......................................................................................................................3 2.3、设计所需工具......................................................................................................................6 2.4、平台构建过程......................................................................................................................6 2.4.1、硬件平台搭建...............................................................................................................6 2.4.2根文件系统的制作..........................................................................................................8(1)根文件系统.....................................................................................................................8 第三章 程序..................................................................................................................................13 3.1.程序流程图:.......................................................................................................................13 3.2.分析驱动...............................................................................................................................13 3.2.1、触摸屏设备驱动中数据结构.....................................................................................13 3.2.2、触摸屏驱动模块加载和卸载函数.............................................................................15 3.2.3、触摸屏设备驱动的读函数.........................................................................................17 3.2.4、触摸屏设备驱动的轮询与异步通知.........................................................................17 3.2.5源程序触摸屏驱动代码:............................................................................................18 3.2.6、实验结果显示:.........................................................................................................29 第四部分 心得..............................................................................................................................30 4.1 课程设计心得体会:..........................................................................................................30 第五部分 参考文献......................................................................................................................32 5.1【参考文献】........................................................................................................................32
第一部分 要求
1.1 设计目的
1.基于Linux操作系统,以及Emest III实验箱,利用触摸屏返回触点坐标值及动作信息。
2.坐标及动作的具体显示:触摸笔动作,触点X坐标值,触点Y坐标值。
1.2 设计意义
1.熟悉嵌入式系统开发平台
2.掌握ARM嵌入式Linux操作系统下的各个指令的使用方法 3.了解触摸屏的原理
1.3 设计内容
1.Linux系统的正确移植和使用 2.根文件系统的正确移植和使用 3.驱动程序的编译与装载
4.嵌入式系统下应用程序的交叉编译及下载与调试
1.4 主要任务
1.熟悉实验的流程
2.vivi,linux内核的烧写
3.cramfs文件系统(烧写前需编译)的烧写 4.理解驱动程序源代码
5.调用驱动程序的某些函数,编译与调试应用程序
第二部分 正文
2.1触摸屏工作原理(触摸屏接口工作模式)
(1)普通转换模式
普通转换模式(AUTO_PST = 0,XY_PST = 0)是用作一般目的下的ADC转换。这个模式可以通过设置ADCCON和ADCTSC来进行对AD转换的初始化;而后读取ADCDAT0(ADC数据寄存器0)的XPDATA域(普通ADC转换)的值来完成转换。(2)分离的X/Y轴坐标转换模式:X轴坐标转换和Y轴坐标转换。
X轴坐标转换(AUTO_PST=0且XY_PST=1)将X轴坐标转换数值写入到ADCDAT0寄存器的XPDATA域。转换后,触摸屏接口将产生中断源(INT_ADC)到中断控制器。
Y轴坐标转换(AUTO_PST=0且XY_PST=2)将X轴坐标转换数值写入到ADCDAT1寄存器的YPDATA域。转换后,触摸屏接口将产生中断源(INT_ADC)到中断控制器。
(3)自动(连续)X/Y轴坐标转换模式。
自动(连续)X/Y轴坐标转换模式(AUTO_PST=1且XY_PST= 0)以下面的步骤工作:
触摸屏控制器将自动地切换X轴坐标和Y轴坐标并读取两个坐标轴方向上的坐标。触摸屏控制器自动将测量得到的X轴数据写入到ADCDAT0寄存器的XPDATA域,然后将测量到的Y轴数据到ADCDAT1的YPDATA域。自动(连续)转换之后,触摸屏控制器产生中断源(INT_ADC)到中断控制器。(4)等待中断模式
当触摸屏控制器处于等待中断模式下时,它实际上是在等待触摸笔的点击。在触摸笔点击到触摸屏上时,控制器产生中断信号(INC_TC)。中断产生 2
后,就可以通过设置适当的转换模式(分离的X/Y轴坐标转换模式或自动X/Y轴坐标转换模式)来读取X和Y的位置。(5)静态(Standby)模式
当ADCCON寄存器的STDBM位被设为1时,Standby模式被激活。在该模式下,A/D转换操作停止,ADCDAT0寄存器的XPDATA域和ADCDAT1寄存器的YPDATA(正常ADC)域保持着先前转换所得的值。
2.2、设计总体方案
1、软件
(1)Embest Online Flash Programmer For ARM: Embest Flash在线编程器(2)HYPER TERMINAL(超级终端):传送vivi.nand;
传送vivi.nand
vivi> load flash kernel x <回车> 烧写更新内核,传送zImage文件;等待传送内核文件
传送内核:
vivi>load flash root j <回车> 烧写更新文件系统;烧写新的文件系统 load flash root j
(3)EmbestIDE Pro for ARM: 应用于嵌入式软件开发的新一代集成开发环境,是一个高度集成的图形界面操作环境,包含编辑器、编译汇编链接器、调试器、工程管理、Flash 编程等工具;支持的开发语言包括标准C和汇编语言。(4)cygwin: 一个在windows平台上运行的unix模拟环境,它对于学习unix/linux操作环境,或者从unix到windows的应用程序移植,或者进行某些特殊的开发工作,尤其是使用gnu工具集在windows上进行嵌 5
入式系统开发,把gcc,gdb,gas等开发工具进行了改进,能够生成并解释win32的目标文件。
2、硬件
S3C2410处理器是Samsung公司基于ARM公司的ARM920T处理器核,32位微控制器。该处理器拥有:独立的16KB指令Cache和16KB数据Cache,MMU,支持TFT的LCD控制器,NAND闪存控制器,3路UART,4路DMA,4路带PWM的Timer,I/O口,RTC,8路10位ADC,Touch Screen接口,IIC-BUS 接口,IIS-BUS 接口,2个USB主机,1个USB设备,SD主机和MMC接口,2路SPI。S3C2410处理器最高可运行在203MHz。
2.3、设计所需工具
1.软件: Embest Online Flash Programmer For ARM,HYPER TERMINAL(超级终端),EmbestIDE Pro for ARM,cygwin 1.硬件:s3c2410开发板,Embest实验箱
2.4、平台构建过程
2.4.1、硬件平台搭建
硬件流程图:
(1)Vivi烧写过程
1)首先把SW104断开,Flash Programmer的Program,在File选择Open打开要烧写的配置文件S3C2410&NandFLash_vivi.cfg,在Flash Programmer的Program页中选择要烧写的文件vivi.bon&load.bin。点击按钮 Progarm 开始烧写,直到烧写成功
2)连接串口线到 PC 机 COM1,运行光盘中提供的 Windows 超级终端Hyper Terminal.ht 把开发板重新加电,程序运行后,在超级终端上可以看到串口输出Wating,表示正在等待用户从超级终端下载文件。这时,请点击超级终端菜单“传送”选择 Xmodem 方式下载 vivi.nand 文件,点击 OK 后等待下载烧写结束即可。(2)内核zImage烧写
1)首先SW104设为短接(从Nand Flash启动),并确定已经烧写vivi.nand,加电。)在vivi启动等待中,敲入空格键进入vivi界面环境,并输入以下命令:vivi> load flash kernel x <回车> 烧写更新内核约1分钟即可烧写完毕 3)点击超级终端菜单中的“传送”,选“发送文件”zImage” 并选择xModem方式传送)烧写结束,重起实验板,观测超级终端窗口提示信息就可以启动linux内核,(3)新文件系统的烧写
1)首先SW104设为短接(从Nand Flash启动),确定已经成功烧写vivi.nand,加电运行可以看到vivi启动信息,输入空格进入命令状态;
2)双击运行Download.pjf(该文件在/tmp/edukit-2410/image/中)工程(将启动Embest IDE环境),点击连接Remote connect,程序应该正在运行(命令按钮STOP为红色);在串口输入help,看看有没有反应,如果没反应,点击IDE 按钮:Reset->Start(F5);再输入help测试,直到有反应为止;
3)如果可以输出一些信息,再点击IDE中的Stop,配置Debug的Download地址为0x30000000,并点击IDE菜单Project选择Settings项,在Download页下拉Category到Download项,在Download File选择root.cramfs文件,点击确定后:
点击IDE菜单DEBUG选择Download下载文件系统映象约1分钟
下载完毕后,点击Start(F5)然后在超级终端里输入: load flash root j(烧写更新文件系统)约1分钟即可烧写完毕
注意:只能在“vivi的烧写”操作完成后,才可以按以上方法正确烧写root映象到Nand Flash。
重起实验板,观测超级终端窗口提示信息,引导整个系统启动到linux行命令输入状态。
2.4.2根文件系统的制作(1)根文件系统
根文件系统是Linux系统的核心部分,包含系统使用的软件和库,以及所有用来为用户提供支持架构和用户使用的应用软件,并作为储存数据读写结果的区域。在Linux系统启动时,首先完成内核安装及环境初始化,最后会寻找一个文件系统作为根文件系统被加载。Linux系统中使用“/”来唯一表示根文件系统的安装路径。嵌入式系统中通常可以悬着的根文件系统有:Romfs、CRAMFS、RAMFS、JFFS2、EXT2等,甚至还可以使用NFS作为根文件系统。
(2)cramfs文件系统
Cramfs是Linux创始人Linux torvalds开发的一个适用于嵌入式系统的小文件系统。Cramfs是一个只读文件系统,采用zlib压缩,压缩比一般可以达到1:2,但仍可以做到高效的随机读取。Linux系统中,通常把需要修改的目录压缩存放,并在系统引导的时候再将压缩文件解开。因为cramfs不会影响系统读取文件的速度,而且是一个高度压缩的文件系统,因此非常广泛应用于嵌入式系统中。
(3)cygwin简介
Cygwin是一个在windows平台上运行的unix/Linux模拟环境,是cygnus solutions公司开发的自由软件。Cygwin中,“/”表示根目录,即cygwin的安 8
装目录。我们常用的set_env_linux.sh中定义的目录有:
SOURCEDIR:/tmp/edukit-2410存储了vivi、linux、fs等源代码和例程 WORKDIR:/usr/local/src/edukit-2410工作区。
一般情况下都要把已经规划好的目录结构转换成一个映象文件,即使用命令工具 mkcramfs(cygwin下为 mkcramfs.exe),把相应的 cramfs 目录树压缩为单一的映象文件。其命令格式为:
mkcramfs [-h] [-e edition] [-i file] [-n name] dirname outfile 可以使用我们提供的 mkcramfs.exe 在 cygwin 下编译生成文件系统映象文件 root.cramfs,再固化到开发系统 FLASH 上运行。
(4)常用的Linux行命令
1)、cd 改变当前目录(文件夹)。例如下,cd/ 返回到根目录 cd..退回到上级目录
cd/tmp/edukit-2410/进入/tmp/edukit-2410/文件夹 2)、ls 列出当前目录中的内容。Ls 简单格式列表 ls–l 使用详细格式列表。3)、pwd 显示当前所在的目录。
(5)tar工具命令
tar 程序用于储存或展开 tar 存档文件。命令格式:
tar [-参数] [文件名][路径]-x :extract |--get 从存档展开文件-v :--verbose 详细显示处理的文件-j :--有 bz2 属性的必须包含
-f :--file [HOSTNAME:]F 指定存档或设备(缺省为 /dev/rmt0)
(6)解压原文件系统(命令+解压目录的存放)
1)先将 root.cramfs.tar.bz2文件放在C:cygwin目录中
2)解压文件系统
运行cygwin,执行以下命令解压安装:
$> source /tmp/edukit-2410/set_env_linux.sh Linux编译环境变量设置 $> cd /
$> tar-xvjf root.cramfs.tar.bz2 $> ls „ root „
root文件夹中就是我们想要的cramfs文件系统 3)如果在根目录中产生root文件夹,解压成功 4)在root目录中新建xx文件夹,用于存放应用程序
进入该目录后执行以下命令编译链接测试程序: $> cd root $>mkdir xx
(7)编译应用程序 ts.c(命令+生成文件格式+存放位置): 将编写好的ts.c程序放在C:cygwin目录中 进入该目录后执行以下命令编译链接测试程序: $> cd / $> arm-linux-gcc-o ts ts.c(也可以编写Makefile来编译)
生成文件: ts 如下图所示
将ts文件放入root 下的xx文件夹中
(8)新文件系统的制作: 把刚才编译输出的ts文件拷贝到文件系统所在的工作目录root目录下,执行以下命令生成新的文件系统映象: $> cd /
$> mkcramfs root root.new
刚刚编译生成的文件系统映象 root.new 中已经包含测试程序即生成文件。解压文件系统
解压成功如下
在root目录中新建xx文件夹,用于存放应用程序
将编写好的ts.c程序放在C:cygwin目录中
生成文件: ts 如下图所示
新文件系统的制作
生成文件:
第三章 程序
3.1.程序流程图:
3.2.分析驱动
触摸屏驱动在/kernel/drivers/char/s3c2410-ts.c 文件中。
3.2.1、触摸屏设备驱动中数据结构
(1)触摸屏的file_operations static struct file_operations s3c2410_fops={ owner: THIS_MODULE, open: s3c2410_ts_open, read: s3c2410_ts_read,release: s3c2410_ts_release, #ifdef USE_ASYNC fasync: s3c2410_ts_fasync,//异步通知
#endif poll: s3c2410_ts_poll,//轮询 };(2)触摸屏设备结构体的成员与按键设备结构体的成员类似,也包含一个缓冲区,同时包括自旋锁、等待队列和fasync_struct指针 typedef struct { unsigned int penStatus;/* PEN_UP, PEN_DOWN, PEN_SAMPLE */ TS_RET buf[MAX_TS_BUF];/* protect against overrun(环形缓冲区)*/ unsigned int head, tail;/* head and tail for queued events(环形缓冲区的头尾)*/ wait_queue_head_t wq;//* 等待队列数据结构 spinlock_t lock;//* 自旋锁
#ifdef USE_ASYNC struct fasync_struct *aq;#endif #ifdef CONFIG_PM struct pm_dev *pm_dev;//友善之臂专有的,我后面的代码删除了这段 #endif } TS_DEV;
(3)触摸屏结构体中包含的TS_RET值的类型定义,包含X、Y坐标和状态(PEN_DOWN、PEN_UP)等信息,这个信息会在用户读取触摸信息时复制到用户空 间
typedef struct { 14
unsigned short pressure;//* 压力,这里可定义为笔按下,笔抬起,笔拖曳
unsigned short x;//* 横坐标的采样值 unsigned short y;//* 纵坐标的采样值 unsigned short pad;//* 填充位 } TS_RET;
(4)在触摸屏设备驱动中,将实现open()、release()、read()、fasync()和poll()函数,因此,其文件操作结构体定义
触摸屏驱动文件操作结构体:static struct file_operations s3c2410_fops={} 3.2.2、触摸屏驱动模块加载和卸载函数
(1)在触摸屏设备驱动的模块加载函数中,要完成申请设备号、添加cdev、申请中断、设置触摸屏控制引脚(YPON、YMON、XPON、XMON)等多项工作 触摸屏设备驱动的模块加载函数
static int __init s3c2410_ts_init(void)触摸屏设备驱动模块卸载函数
static void __exit s3c2410_ts_exit(void)(2)可知触摸屏驱动中会产生两类中断,一类是触点中断(INT-TC),一类是X/Y位置转换中断(INT-ADC)。在前一类中断发生后,若之前处于PEN_UP状态,则应该启动X/Y位置转换。另外,将抬起中断也放在INT-TC处理程序中,它会调用tsEvent()完成等待队列和信号的释放 触摸屏设备驱动的触点/抬起中断处理程序
static void s3c2410_isr_tc(int irq, void *dev_id, struct pt_regs *reg)
当X/Y位置转换中断发生后,应读取X、Y的坐标值,填入缓冲区 触摸屏设备驱动X/Y位置转换中断处理程序
static void s3c2410_isr_adc(int irq, void *dev_id, struct pt_regs *reg)触摸屏设备驱动中获得X、Y坐标
static inline void s3c2410_get_XY(void)(3)tsEvent最终为tsEvent_raw(),这个函数很关键,当处于PEN_DOWN状态时调用该函数,它会完成缓冲区的填充、等待队列的唤醒以及异步通知信号的释放;否则(处于PEN_UP状态),将缓冲区头清0,也唤醒等待队列并释放信号
触摸屏设备驱动的tsEvent_raw()函数 static void tsEvent_raw(void)(4)在包含了对拖动轨迹支持的情况下,定时器会被启用,周期为10ms,在每次定时器处理函数被引发时,调用start_ts_adc()开始X/Y位置转换过程
触摸屏设备驱动的定时器处理函数
static void ts_timer_handler(unsigned long data)(5)在触摸屏设备驱动的打开函数中,应初始化缓冲区、penStatus和定期器、等待队列及tsEvent时间处理函数指针 触摸屏设备驱动的打开函数
static int s3c2410_ts_open(struct inode *inode, struct file *filp)16
(6)触摸屏设备驱动的释放函数非常简单,删除为用于拖动轨迹所使用的定时器即可
触摸屏设备驱动的释放函数
static int s3c2410_ts_release(struct inode *inode, struct file *filp)3.2.3、触摸屏设备驱动的读函数
触摸屏设备驱动的读函数实现缓冲区中信息向用户空间的复制,当缓冲区有内容时,直接复制;否则,如果用户阻塞访问触摸屏,则进程在等待队列上睡眠,否则,立即返回-EAGAIN 触摸屏设备驱动的读函数
static ssize_t s3c2410_ts_read(struct file *filp, char *buffer, size_t count, loff_t *ppos)3.2.4、触摸屏设备驱动的轮询与异步通知
在触摸屏设备驱动中,通过s3c2410_ts_poll()函数实现了轮询接口,这个函数的实现非常简单。它将等待队列添加到poll_table,当缓冲区有数据时,返回资源可读取标志,否则返回0 触摸屏设备驱动的poll()函数
static unsigned int s3c2410_ts_poll(struct file *filp, struct poll_table_struct *wait)而为了实现触摸屏设备驱动对应用程序的异步通知,设备驱动中要实现s3c2410_ts_fasync()函数 触摸屏设备驱动的fasync()函数
static int s3c2410_ts_fasync(int fd, struct file *filp, int mode)3.2.5源程序触摸屏驱动代码:
/* * s3c2410-ts.c * * touchScreen driver for SAMSUNG S3C2410 * * Author: Janghoon Lyu
#include
#include
#include
#ifdef CONFIG_PM #include
/* debug macros */ #undef DEBUG #ifdef DEBUG #define DPRINTK(x...)printk(“s3c2410-ts: ” ##x)#else #define DPRINTK(x...)#endif
#define PEN_UP 0
#define PEN_DOWN 1 #define PEN_FLEETING 2 #define MAX_TS_BUF 16 /* how many do we want to buffer */
#undef USE_ASYNC 1 #define DEVICE_NAME “s3c2410-ts” #define TSRAW_MINOR 1
typedef struct { unsigned int penStatus;/* PEN_UP, PEN_DOWN, PEN_SAMPLE */ TS_RET buf[MAX_TS_BUF];/* protect against overrun */ unsigned int head, tail;/* head and tail for queued events */ wait_queue_head_t wq;spinlock_t lock;#ifdef USE_ASYNC struct fasync_struct *aq;#endif #ifdef CONFIG_PM struct pm_dev *pm_dev;#endif } TS_DEV;
static TS_DEV tsdev;
#define BUF_HEAD(tsdev.buf[tsdev.head])#define BUF_TAIL(tsdev.buf[tsdev.tail])#define INCBUF(x,mod)((++(x))&((mod)-1))
static int tsMajor = 0;
static void(*tsEvent)(void);
#define HOOK_FOR_DRAG #ifdef HOOK_FOR_DRAG #define TS_TIMER_DELAY(HZ/100)/* 10 ms */ static struct timer_list ts_timer;#endif
#define wait_down_int(){ ADCTSC = DOWN_INT | XP_PULL_UP_EN |
XP_AIN | XM_HIZ | YP_AIN | YM_GND |
XP_PST(WAIT_INT_MODE);} #define wait_up_int(){ ADCTSC = UP_INT | XP_PULL_UP_EN | XP_AIN | XM_HIZ |
YP_AIN | YM_GND | XP_PST(WAIT_INT_MODE);} #define mode_x_axis(){ ADCTSC = XP_EXTVLT | XM_GND | YP_AIN | YM_HIZ |
XP_PULL_UP_DIS | XP_PST(X_AXIS_MODE);} #define mode_x_axis_n(){ ADCTSC = XP_EXTVLT | XM_GND | YP_AIN | YM_HIZ |
XP_PULL_UP_DIS | XP_PST(NOP_MODE);} #define mode_y_axis(){ ADCTSC = XP_AIN | XM_HIZ | YP_EXTVLT | YM_GND |
XP_PULL_UP_DIS | XP_PST(Y_AXIS_MODE);} #define start_adc_x(){ ADCCON = PRESCALE_EN | PRSCVL(49)|
ADC_INPUT(ADC_IN5)| ADC_START_BY_RD_EN |
ADC_NORMAL_MODE;
ADCDAT0;} #define start_adc_y(){ ADCCON = PRESCALE_EN | PRSCVL(49)|
ADC_INPUT(ADC_IN7)| ADC_START_BY_RD_EN |
ADC_NORMAL_MODE;
ADCDAT1;} #define disable_ts_adc(){ ADCCON &= ~(ADCCON_READ_START);}
static int adc_state = 0;static int x, y;/* touch screen coorinates */
static void tsEvent_raw(void){ if(tsdev.penStatus == PEN_DOWN){
BUF_HEAD.x = x;
BUF_HEAD.y = y;
BUF_HEAD.pressure = PEN_DOWN;
#ifdef HOOK_FOR_DRAG
ts_timer.expires = jiffies + TS_TIMER_DELAY;
add_timer(&ts_timer);#endif } else { #ifdef HOOK_FOR_DRAG
del_timer(&ts_timer);#endif
BUF_HEAD.x = 0;
BUF_HEAD.y = 0;
BUF_HEAD.pressure = PEN_UP;}
tsdev.head = INCBUF(tsdev.head, MAX_TS_BUF);wake_up_interruptible(&(tsdev.wq));
#ifdef USE_ASYNC if(tsdev.aq)
kill_fasync(&(tsdev.aq), SIGIO, POLL_IN);#endif
#ifdef CONFIG_PM pm_access(tsdev.pm_dev);#endif }
static int tsRead(TS_RET * ts_ret){ spin_lock_irq(&(tsdev.lock));ts_ret->x = BUF_TAIL.x;ts_ret->y = BUF_TAIL.y;ts_ret->pressure = BUF_TAIL.pressure;tsdev.tail = INCBUF(tsdev.tail, MAX_TS_BUF);spin_unlock_irq(&(tsdev.lock));
return sizeof(TS_RET);}
static ssize_t s3c2410_ts_read(struct file *filp, char *buffer, size_t count, loff_t *ppos){ TS_RET ts_ret;
retry: if(tsdev.head!= tsdev.tail){
int count;
count = tsRead(&ts_ret);
if(count)copy_to_user(buffer,(char *)&ts_ret, count);
return count;} else {
if(filp->f_flags & O_NONBLOCK)
return-EAGAIN;
interruptible_sleep_on(&(tsdev.wq));
if(signal_pending(current))
return-ERESTARTSYS;
goto retry;}
return sizeof(TS_RET);}
#ifdef USE_ASYNC static int s3c2410_ts_fasync(int fd, struct file *filp, int mode){ return fasync_helper(fd, filp, mode, &(tsdev.aq));} #endif
static unsigned int s3c2410_ts_poll(struct file *filp, struct poll_table_struct *wait){ poll_wait(filp, &(tsdev.wq), wait);return(tsdev.head == tsdev.tail)? 0 :(POLLIN | POLLRDNORM);}
static inline void start_ts_adc(void){ adc_state = 0;mode_x_axis();start_adc_x();}
static inline void s3c2410_get_XY(void){ if(adc_state == 0){
adc_state = 1;
disable_ts_adc();
y =(ADCDAT0 & 0x3ff);
mode_y_axis();
start_adc_y();} else if(adc_state == 1){
adc_state = 0;
disable_ts_adc();
x =(ADCDAT1 & 0x3ff);
tsdev.penStatus = PEN_DOWN;
DPRINTK(“PEN DOWN: x: %08d, y: %08dn”, x, y);
wait_up_int();
tsEvent();} }
static void s3c2410_isr_adc(int irq, void *dev_id, struct pt_regs *reg){ #if 0 DPRINTK(“Occured Touch Screen Interruptn”);DPRINTK(“SUBSRCPND = 0x%08lxn”, SUBSRCPND);#endif spin_lock_irq(&(tsdev.lock));if(tsdev.penStatus == PEN_UP)s3c2410_get_XY();#ifdef HOOK_FOR_DRAG else s3c2410_get_XY();#endif spin_unlock_irq(&(tsdev.lock));}
static void s3c2410_isr_tc(int irq, void *dev_id, struct pt_regs *reg){ #if 0 DPRINTK(“Occured Touch Screen Interruptn”);DPRINTK(“SUBSRCPND = 0x%08lxn”, SUBSRCPND);#endif spin_lock_irq(&(tsdev.lock));if(tsdev.penStatus == PEN_UP){ start_ts_adc();} else { tsdev.penStatus = PEN_UP;DPRINTK(“PEN UP: x: %08d, y: %08dn”, x, y);wait_down_int();tsEvent();
} spin_unlock_irq(&(tsdev.lock));}
#ifdef HOOK_FOR_DRAG static void ts_timer_handler(unsigned long data){ spin_lock_irq(&(tsdev.lock));if(tsdev.penStatus == PEN_DOWN){
start_ts_adc();} spin_unlock_irq(&(tsdev.lock));} #endif
static int s3c2410_ts_open(struct inode *inode, struct file *filp){ tsdev.head = tsdev.tail = 0;tsdev.penStatus = PEN_UP;#ifdef HOOK_FOR_DRAG init_timer(&ts_timer);ts_timer.function = ts_timer_handler;#endif tsEvent = tsEvent_raw;init_waitqueue_head(&(tsdev.wq));
MOD_INC_USE_COUNT;return 0;}
static int s3c2410_ts_release(struct inode *inode, struct file *filp){ #ifdef HOOK_FOR_DRAG del_timer(&ts_timer);#endif MOD_DEC_USE_COUNT;return 0;}
static struct file_operations s3c2410_fops = { owner: THIS_MODULE, open: s3c2410_ts_open, read: s3c2410_ts_read,release: s3c2410_ts_release,#ifdef USE_ASYNC fasync: s3c2410_ts_fasync, #endif poll: s3c2410_ts_poll, };
void tsEvent_dummy(void){} #ifdef CONFIG_PM static int s3c2410_ts_pm_callback(struct pm_dev *pm_dev, pm_request_t req,void *data){ switch(req){
case PM_SUSPEND:
tsEvent = tsEvent_dummy;
break;
case PM_RESUME:
tsEvent = tsEvent_raw;
wait_down_int();
break;} return 0;} #endif
#ifdef CONFIG_DEVFS_FS static devfs_handle_t devfs_ts_dir, devfs_tsraw;#endif static int __init s3c2410_ts_init(void){ int ret;
tsEvent = tsEvent_dummy;
ret = register_chrdev(0, DEVICE_NAME, &s3c2410_fops);if(ret < 0){ printk(DEVICE_NAME “ can't get major numbern”);return ret;} tsMajor = ret;
/* set gpio to XP, YM, YP and YM */ #if 0 set_GPIO_mode(GPIO106_nYPON_MD);
set_GPIO_mode(GPIO105_YMON_MD);set_GPIO_mode(GPIO104_nXPON_MD);set_GPIO_mode(GPIO103_XMON_MD);
GPUP(GPIO106_nYPON)|= GPIO_bit(GPIO106_nYPON);GPUP(GPIO105_YMON)&= GPIO_bit(GPIO105_YMON);GPUP(GPIO104_nXPON)|= GPIO_bit(GPIO104_nXPON);GPUP(GPIO103_XMON)&= GPIO_bit(GPIO103_XMON);#else set_gpio_ctrl(GPIO_YPON);set_gpio_ctrl(GPIO_YMON);set_gpio_ctrl(GPIO_XPON);set_gpio_ctrl(GPIO_XMON);#endif
/* Enable touch interrupt */ ret = request_irq(IRQ_ADC_DONE, s3c2410_isr_adc, SA_INTERRUPT,DEVICE_NAME, s3c2410_isr_adc);if(ret)goto adc_failed;ret = request_irq(IRQ_TC, s3c2410_isr_tc, SA_INTERRUPT,DEVICE_NAME, s3c2410_isr_tc);if(ret)goto tc_failed;
/* Wait for touch screen interrupts */ wait_down_int();
#ifdef CONFIG_DEVFS_FS devfs_ts_dir = devfs_mk_dir(NULL, “touchscreen”, NULL);devfs_tsraw = devfs_register(devfs_ts_dir, “0raw”, DEVFS_FL_DEFAULT,tsMajor, TSRAW_MINOR, S_IFCHR | S_IRUSR | S_IWUSR,&s3c2410_fops, NULL);#endif
#ifdef CONFIG_PM #if 0 tsdev.pm_dev = pm_register(PM_GP_DEV, PM_USER_INPUT,s3c2410_ts_pm_callback);#endif tsdev.pm_dev = pm_register(PM_DEBUG_DEV, PM_USER_INPUT,s3c2410_ts_pm_callback);#endif printk(DEVICE_NAME “ initializedn”);
return 0;tc_failed: free_irq(IRQ_ADC_DONE, s3c2410_isr_adc);adc_failed: return ret;}
static void __exit s3c2410_ts_exit(void){ #ifdef CONFIG_DEVFS_FS
devfs_unregister(devfs_tsraw);devfs_unregister(devfs_ts_dir);#endif unregister_chrdev(tsMajor, DEVICE_NAME);#ifdef CONFIG_PM pm_unregister(tsdev.pm_dev);#endif free_irq(IRQ_ADC_DONE, s3c2410_isr_adc);free_irq(IRQ_TC, s3c2410_isr_tc);}
module_init(s3c2410_ts_init);module_exit(s3c2410_ts_exit);触摸屏应用程序
#include
#define PEN_UP 0 /* 触摸笔抬笔,即触摸屏不被压下 */ #define PEN_DOWN 1 /* 触摸笔下笔,即触摸屏被压下 */ #define PEN_FLEETING 2 /* 触摸笔拖动 */
typedef struct { unsigned short pressure;/* 触摸笔动作 */ unsigned short x;
/* 触点x座标值 */ unsigned short y;
/* 触点y座标值 */ unsigned short pad;}TS_RET;
int main(){ int fd,ret,i;
unsigned char suba;TS_RET tsret;
fd = open(“/dev/touchscreen/0raw”, O_RDWR);/* 打开设备 */ if(fd ==-1){ printf(“nCan't open I2C device!n”);exit(-1);}
while(1){
ret = read(fd,(char *)&tsret, sizeof(TS_RET));
if(ret!= sizeof(TS_RET))
{
printf(“read touch screen error!”);
close(fd);
exit(-1);
}
else
{
printf(“pressure is: %dn”, tsret.pressure);
printf(“x is: %dn”, tsret.x);
printf(“y is: %dn”, tsret.y);
} }
close(fd);return 0;} 3.3.应用程序的调试
使用s3c2410_ts.c触摸屏驱动编写应用程序,读取触摸屏的触点坐标值及动作信息(触点x坐标值,y坐标及是否有压力值press),并在串口中断打印出来
对触摸屏设别的操作有打开设备,关闭设备,读操作等。编写应用程序读取触摸屏的触点坐标值及动作信息时,只需利用触摸屏驱动程序便可实现,先打开触摸屏设备,然后调用读函数即可。
其中,触摸笔动作取值如下: #define PEN_UP 0 #define PEN_DOWN
/* 触摸笔抬笔,即触摸屏不被压下 */ /* 触摸笔下笔,即触摸屏被压下 */
#define PEN_FLEETING 2 结构体定义如下: typedef struct { unsigned short pressure;unsigned short x;unsigned short y;unsigned short pad;}TS_RET 打开应用程序:
/* 触摸笔拖动 */
/* 触摸笔动作 */ /* 触点x座标值 */ /* 触点y座标值 */
3.2.6、实验结果显示:
第四部分 感想
第四部分 心得
4.1 课程设计心得体会:
为期几天的课程设计结束了,再次期间我积极亲自实验,用的目标板是s3c2410核心子板,用JTAG仿真器,用Cygwin模拟软件来学习触摸板的设计。我学会了很多,学会了很多。
首先我扪主要了解整个设计过程,以及实验环境的建立,这次用的是交叉编译环境,通过这次课设我更清楚搭建嵌入式系统的开发平台,我们用的目标板是s3c2410核心子板,用JTAG仿真器,用Cygwin模拟软件,课设的这几天我学会了熟练的使用Cygwin软件,掌握了一些常用的命令,加上研究生学长给我们的指导,知道了如何学习,如何思考,知道了运linux操作系统开发嵌入式与wince操作系统开发嵌入式的区别。
其次是学会vivi,内核,根文件系统的编译与移植(烧写),通过这个过程我熟悉了怎么把软件固化到硬件上,知道了软件怎么控制硬件,这个步骤很重要,要烧写不成功,目标板系统就运行不起来,实验就失败了,这个过程我们练习了好多变呢,大家都很累哦!
再次我们就开始写我们的应用程序,通过以上步骤实验系统搭建好了,只要调试好应用程序,然后再运行成功就行了,为此我又把课本上讲得触摸屏原理那章认真看了,又看了实验指导书,查资料,上网搜索,终于编出应用程序,经过不断的调试才编译成功,这个过程太辛苦了,加上实验板不太好,真是对我们的挑战,不过看到运行的 30
结果,大家都很高兴,也很有成就感啊!还看懂了一些s3c2410的驱动程序的源代码,了解了s3c2410一些控制器的使用,以及s3c2410A的一些接口原理与应用。
我明白了只有不断的努力,不断的学习,才能在将来遇到的问题中能够游刃有余,才能够不会捉襟见肘。
第五部分 参考文献
5.1【参考文献】 程昌南,方强等.《ARM Linux入门与实践 》【M】.北京:北京航空航天大学出版社,2008.10 2 张晓林等.《嵌入式系统设计与实践》【M】.北京:北京航空航天大学出版社,2006.1 3 李俊等.《嵌入式Linux设备驱动开发详解》【M】.北京:北京人民邮电出版社,2008.3 4 黄智伟,邓月明,王彦.《ARM9嵌入式系统设计基础教程》.北京:北京航空航天大学出版社,2008.8 5 [美]Wayne Wolf.嵌入式计算系统设计原理.孙玉芳, 梁彬 罗保国 等译.北京: 机械工业出版社, 2002 李剑, 赵鹏程, 汤建彬.32位ARM嵌入式处理器的调试技术.电子技术应用, 2003,(3)钟汉如, 王创生.嵌入式Linux的中断处理与实时调度的实现机制.计算机工程, 2002, 28(10)Arnold Berger.嵌入式系统设计.吕骏 译.北京: 电子工业出版社, 2002