Linux驱动程序开发.ppt

上传人:牧羊曲112 文档编号:5438166 上传时间:2023-07-07 格式:PPT 页数:112 大小:702KB
返回 下载 相关 举报
Linux驱动程序开发.ppt_第1页
第1页 / 共112页
Linux驱动程序开发.ppt_第2页
第2页 / 共112页
Linux驱动程序开发.ppt_第3页
第3页 / 共112页
Linux驱动程序开发.ppt_第4页
第4页 / 共112页
Linux驱动程序开发.ppt_第5页
第5页 / 共112页
点击查看更多>>
资源描述

《Linux驱动程序开发.ppt》由会员分享,可在线阅读,更多相关《Linux驱动程序开发.ppt(112页珍藏版)》请在三一办公上搜索。

1、Linux驱动程序移植及分析,程杰http:/,一、Linux内核启动过程概述二、MTD简介及修改Nand MTD分区三、移植YAFFS文件系统四、Framebuffer驱动分析五、嵌入式Linux 音频驱动程序设计六、Linux IIS音频应用程序开发简介,一、Linux内核启动过程概述,1 Linux内核启动,汇编代码部分检测内核是否支持处理器和开发板连接内核使用的虚拟地址,设置页表,使能MMU常规工作:复制数据段、调用strat_kernel函数C代码部分内核初始化调用rest_init函数,创建系统第一个进程init重设页表、设置系统时钟、初始化串口,开始,确定内核是否支持架构_loo

2、kup_processor_type,确定内核是否支持开发板_lookup_machine_type,建立一级页表_creat_page_tables,禁止Icache Dcache_arm720t_setup,使能MMU_enale_mmu,复制数据段清楚BSS段保存CPU ID调用start_kernel,汇编阶段,输出Linux版本信息printk,设置与体系相关的内容setup_arch,初始化控制台console_init,启动init过程 rest_init,C阶段,2 引导阶段代码分析,78 ENTRY(stext)79msrcpsr_c,#PSR_F_BIT|PSR_I_BIT

3、|MODE_SVC ensure svc mode80 and irqs disabled81 mrcp15,0,r9,c0,c0 get processor id82bl_lookup_processor_type r5=procinfo r9=cpuid83movsr10,r5 invalid processor(r5=0)?84beq_error_p yes,error p85bl_lookup_machine_type r5=machinfo86movsr8,r5 invalid machine(r5=0)?87beq_error_a yes,error a88bl_create_pa

4、ge_tables,79 通过设置CPSR寄存器来确保处理器进入SVC模式,并禁止中断81 读取协处理器CP15的寄存器C0获得CPU ID82 调用函数确定是否支持CPU85 调用函数确定是否支持当前开发板如果_lookup_processor_type和_lookup_machine_type返回成功,系统将调用_creat_page_tables来创建一级页表以建立虚拟地址到物理地址的映射关系,接着会调用_enable_mmu来打开MMU,3 start_kernel函数分析,进入start_kernel后,如果在串口中看不到信息,说明启动出现问题,可能原因有两个:bootloader传

5、入参数不对setup_arch针对开发板的设置不正确在执行console_init函数前,系统信息保存在缓冲区中,只有在初始化控制台后才会输出,(1)setup_arch函数分析,arch/arm/kernel/setup.cvoid _init setup_arch(char*cmdline_p)setup_processor();mdesc=setup_machine(machine_arch_type);if(mdesc-boot_params)tags=phys_to_virt(mdesc-boot_params);if(tags-hdr.tag=ATAG_CORE)if(meminf

6、o.nr_banks!=0)squash_mem_tags(tags);parse_tags(tags);memcpy(saved_command_line,from,COMMAND_LINE_SIZE);saved_command_lineCOMMAND_LINE_SIZE-1=0;parse_cmdline(cmdline_p,from);paging_init(,setup_processor()用来进行处理器相关的一些设置。setup_machine()用来获得开发板的machine_desc结构if(mdesc-boot_params)用来确定u-boot传入参数的启动地址之后的每一

7、个tag,在setup.c中都定义了相应的处理函数eg内存tag:parse_tag_mem32()命令行tag:parse_tag_cmdline()parse_cmdline()对一些参数进行先期处理,“mem=”用来限制Linux使用的内存总量系统将调用early_mem对其进行处理“console=”用来指定要使用的控制台名称、序号、参数console_setup函数将处理这个信息,并保存在全局结构console_cmdline中,后面console_init函数初始化控制台时会根据这些信息选择,(2)paging_init函数分析,调用形式:paging_init(其中:meminf

8、o中存放内存信息mdesc是开发板定义参数结构体调用流程:paging_init-devicemapes_init-map_io(),(3)console_init函数分析,位置 drivers/char/tty_io.cvoid _init console_init(void)initcall_t*call;/*Setup the default TTY line discipline.*/(void)tty_register_ldisc(N_TTY,将调用_con_initcall 至 _con_initcall_end之间定义的每个函数,这些函数使用console_initcall宏指定

9、,总结启动函数调用过程,start_kernel-setup_arch-setup_processorsetup_machinepage_tagsparse_cmdlinepaging_init-devicemaps_init-mdesc-map_io()console_init-register_console(),二、MTD简介及修改Nand MTD分区,1 MTD简介,MTD(memory technology device内存技术设备)是用于访问memory设备(ROM、flash)的Linux的子系统。MTD的主要目的是为了使新的memory设备的驱动更加简单,为此它在硬件和上层之间

10、提供了一个抽象的接口。MTD的所有源代码在/drivers/mtd子目录下。CFI接口的MTD设备分为四层,从上到下依次是:设备节点、MTD设备层、MTD原始设备层和硬件驱动层。,1.1 Flash硬件驱动层,硬件驱动层负责在init时驱动Flash硬件,Linux MTD设备的NORFlash芯片驱动遵循CFI接口标准,其驱动程序位于drivers/mtd/chips子目录下。NAND型Flash的驱动程序则位于/drivers/mtd/nand子目录下,1.2 MTD原始设备,原始设备层有两部分组成,一部分是MTD原始设备的通用代码,另一部分是各个特定的Flash的数据,例如分区。用于描述

11、MTD原始设备的数据结构是mtd_info,这其中定义了大量的关于MTD的数据和操作函数。mtd_table(mtdcore.c)则是所有MTD原始设备的列表mtd_part(mtd_part.c)是用于表示MTD原始设备分区的结构,其中包含了mtd_info,因为每一个分区都是被看成一个MTD原始设备加在mtd_table中的,1.3 MTD设备层,基于MTD原始设备,linux系统可以定义出MTD的块设备(主设备号31)和字符设备(设备号90)。MTD字符设备的定义在mtdchar.c中实现,通过注册一系列file operation函数(lseek、open、close、read、wri

12、te)。MTD块设备则是定义了一个描述MTD块设备的结构 mtdblk_dev,并声明了一个名为mtdblks的指针数组,这数组中的每一个mtdblk_dev和mtd_table中的每一个 mtd_info一一对应。,1.4文件系统,在Bootloader中将JFFS(或JFFS2)的文件系统映像jffs.image(或jffs2.img)烧到flash的某一个分区中,在/arch/arm/mach-your/arch.c文件的 your_fixup函数中将该分区作为根文件系统挂载。文件系统:内核启动后,通过mount 命令可以将flash中的其余分区作为文件系统挂载到mountpoint上。

13、,2 修改Nand MTD分区,SEP4020 Nand Flash 有64MB空间目前分区情况:mtdblock0 0 x00000000-0 x0100000 1Mmtdblock1 0 x00100000-0 x0600000 5Mmtdblock2 0 x00600000-0 x1E00000 24Mmtdblock3 0 x01E00000-0 x04000000 34M,SEP4020 NAND的驱动程序,其目录位于:./drivers/mtd/nand/sep4020.c 宏定义:#define NUM_PARTITIONS 4/NAND的分区数目(这里分为4个分区)#defin

14、e UBOOT_SIZE SZ_1M*1/UBOOT分区空间大小#define KERNEL_SIZE SZ_1M*5/内核分区空间大小#define ROOT_SIZE SZ_1M*24/根文件系统分区大小#define USER_SIZE SZ_1M*34/用户空间分区大小,static struct mtd_partition partition_info=.name=U-boot,.offset=0,.size=UBOOT_SIZE,.name=linux 2.6.16 kernel,.offset=UBOOT_SIZE,.size=KERNEL_SIZE,.name=root,.of

15、fset=UBOOT_SIZE+KERNEL_SIZE,.size=ROOT_SIZE,.name=user,.offset=UBOOT_SIZE+KERNEL_SIZE+ROOT_SIZE,.size=USER_SIZE;,上面的代码可以看出:NAND被分为4个分区我们可能修改NAND分区数目和各分区的大小(包括增加分区删除分区合并分区等)注意:无论做任何修改,所有分区的大小不能超过NAND的总量(目前64M).,增加一个分区,#define NUM_PARTITIONS 5/NAND的分区数目(修改)#define UBOOT_SIZE SZ_1M*1/UBOOT分区空间大小#define

16、 KERNEL_SIZE SZ_1M*5/内核分区空间大小#define ROOT_SIZE SZ_1M*24/根文件系统分区大小#define USER_SIZE SZ_1M*17/用户空间分区大小(修改)#define USER1_SIZE SZ_1M*17/用户增加的分区(修改),这样就将原来的第四分区(34M)分为两个分区(17M+17M)的空间.在串口调试工具输出的NAND分区信息中可以看到如下五个分区:Creating 5 MTD partitions on NAND 64MiB 3,3V 8-bit:0 x00000000-0 x00100000:U-boot0 x0010000

17、0-0 x00600000:linux 2.6.16 kernel0 x00600000-0 x01e00000:root0 x01e00000-0 x02f00000:user0 x02f00000-0 x04000000:user1,删除(合并)一个分区,#define NUM_PARTITIONS 3/NAND分区数目(修改)#define UBOOT_SIZE SZ_1M*1#define KERNEL_SIZE SZ_1M*5#define ROOT_SIZE SZ_1M*58/根目录空间大小(修改)static struct mtd_partition partition_info

18、=.name=U-boot,.offset=0,.size=UBOOT_SIZE,.name=linux 2.6.16 kernel,.offset=UBOOT_SIZE,.size=KERNEL_SIZE,.name=root,.offset=UBOOT_SIZE+KERNEL_SIZE,.size=ROOT_SIZE,;,这样就将原来的后两个分区就合并成为一个54M空间的分区.在串口调试工具输出的NAND分区信息中可以看到如下三个分区:Creating 3 MTD partitions on NAND 64MiB 3,3V 8-bit:0 x00000000-0 x00100000:U-b

19、oot0 x00100000-0 x00600000:linux 2.6.16 kernel0 x00600000-0 x04000000:root,static struct mtd_partition partition_info=.name=U-boot,.offset=0,.size=UBOOT_SIZE,.name=linux 2.6.16 kernel,.offset=UBOOT_SIZE,.size=KERNEL_SIZE,.name=root,.offset=UBOOT_SIZE+KERNEL_SIZE,.size=ROOT_SIZE,.name=user,.offset=UB

20、OOT_SIZE+KERNEL_SIZE+ROOT_SIZE,.size=USER_SIZE,/以下分区为增加的一个分区,在地偏移量后面要加上USER空间的大小.name=user1,.offset=UBOOT_SIZE+KERNEL_SIZE+ROOT_SIZE+USER_SIZE,.size=USER1_SIZE;,三、移植YAFFS文件系统,1.1简介,Yaffs(Yet Another Flash File System)文件系统是专门针对NAND闪存设计的嵌入式文件系统,目前有YAFFS和YAFFS2两个版本,两个版本的主要区别之一在于YAFFS2能够更好的支持大容量的NAND FL

21、ASH芯片。Yaffs文件系统有些类似于JFFS/JFFS2文件系统,与之不同的是JFFS1/2文件系统最初是针对NOR FLASH的应用场合设计的,而NOR FLASH和NAND FLASH本质上有较大的区别,所以尽管JFFS1/2 文件系统也能应用于NAND FLASH,但由于它在内存占用和启动时间方面针对NOR的特性做了一些取舍,所以对NAND来说通常并不是最优的方案。,NOR和NAND的比较,基本上NOR比较适合存储程序代码,其容量一般较小(比如小于32MB),价格较高,而NAND容量可达1GB以上,价格也相对便宜,适合存储数据。一般来说,128MB以下容量NAND FLASH 芯片的

22、一页大小为528字节,用来存放数据,另外每一页还有16字节的备用空间(SpareData,OOB),用来存储ECC校验/坏块标志等信息,再由若干页组成一个块,通常一块为32页16K。与NOR相比,NAND不是完全可靠的,每块芯片出厂时都有一定比例的坏块存在,对数据的存取不是使用地址映射而是通过寄存器的操作,串行存取数据。,1.2Yaffs文件系统数据在NAND上的存储方式,Yaffs对文件系统上的所有内容(比如正常文件,目录,链接,设备文件等等)都统一当作文件来处理,每个文件都有一个页面专门存放文件头,文件头保存了文件的模式、所有者id、组id、长度、文件名、Parent Object ID等

23、信息。因为需要在一页内放下这些内容,所以对文件名的长度,符号链接对象的路径名等长度都有限制。前面说到对于NAND FLASH上的每一页数据,都有额外的空间用来存储附加信息,Yaffs正是利用了这部分空间中剩余的部分来存储文件系统相关的内容。,以512+16B为一个PAGE的NAND FLASH芯片为例,Yaffs文件系统数据的存储布局如下所示,可以看到在这里YAFFS一共使用了8个BYTE用来存放文件系统相关的信息(yaffs_Tags)。这8个Byte的具体使用情况按顺序如下:,Serial Number在文件系统创建时都为0,以后每次写具有同一ObjectID和ChunkID的page的时

24、候都加一,因为Yaffs在更新一个PAGE的时候总是在一个新的物理Page上写入数据,再将原先的物理Page删除,所以该serial number可以在断电等特殊情况下,当新的page已经写入但老的page还没有被删除的时候用来识别正确的Page,保证数据的正确性。ObjectID号为18bit,所以文件的总数限制在256K即26万个左右。以上这些是针对Yaffs1而言,对于Yaffs2因为针对chunk size大于1k的NAND FLASH,在Tags各分量及总体尺寸上都做了修改,以便更快更好的处理大容量的NAND FLASH芯片。由于Tag尺寸的增大,在512+16B类型的NAND FL

25、ASH上就一个Trunk对应一个page的情况,目前就无法使用Yaffs2文件系统了。由于文件系统的基本组织信息保存在页面的备份空间中,因此,在文件系统加载时只需要扫描各个页面的备份空间,即可建立起整个文件系统的结构,而不需要像JFFS1/2 那样扫描整个介质,从而大大加快了文件系统的加载速度。,1.3yaffs文件系统在内存中的组织方式,操作文件系统的第一步自然是取得SuperBlock了,Yaffs文件系统本身在NAND Flash上并不存在所谓的SuperBlock块,完全是在文件系统mount的过程中由read_super函数填充的.通常一个具体的文件系统在VFS的Super_bloc

26、k结构中除了通用的数据外,还有自己专用的数据,Yaffs文件系统的专用数据是一个yaffs_DeviceStruct结构,主要用来存储一些相关软硬件配置信息,相关函数指针和统计信息等。,SuperBlock,File system type Size Status Information about other metadata structures,文件在内存中的组织方式,在mount过程执行read_super的过程中,Yaffs文件系统还需要将文件系统的目录结构在内存中建立起来。由于没有super块,所以需要扫描Yaffs分区,根据从OOB中读取出的yaffs_tags信息判断出是文件头

27、page还是数据page。再根据文件头page中的内容以及数据page中的ObjectID/ChunkID/serial Number等信息在内存中为每个文件(Object)建立一个对应的yaffs_object对象。,yaffs_object结构,如修改时间,用户ID,组ID等文件属性;用作yaffs文件系统维护用的各种标记位如脏(dirty)标记,删除标记等等;用作组织结构的,如指向父目录的Parent指针,指向同级目录中其他对象链表的siblings双向链表头结构,Yaffs_object中有其各自专有的数据内容,普通文件:文件尺寸,用于快速查找文件数据块的yaffs_Tnode 树的指

28、针等目录:目录项内容双向链表头(children)链接:softlink的alias,hardlink对应的ObjectID 通过创建这些yaffs_object,yaffs文件系统就能够将存储在NAND FLASH上数据系统的组织起来,在内存中维护一个完整的文件系统结构。,2 Yaffs文件系统集成及应用相关,这里所谓移植,就是在特定的软硬件环境里编译出yaffs文件系统模块:在内核中建立YAFFS目录fs/yaffs,并把下载的YAFFS代码复制到该目录下面。修改Kconfig文件,加入yaffs目录修改fs/makefile,加入yaffs目录,2.1 配置、编译内核,讲解用到的几个选项

29、:CONFIG_YAFFS_FS:支持YAFFS文件系统CONFIG_YAFFS_YAFFS1:支持YAFFS1文件系统,特别应用于每页大小为512Byte的Nand Flash上CONFIG_YAFFS_YAFFS2:支持YAFFS2文件系统,对于每页大小为2048Byte的Nand Flash,这是必须的CONFIG_YAFFS_DOES_ECC:使用YAFFS本身的ECC校验函数,Turn off debug chunk erase check,这一项试验的结果选上后平均可以提高20-30%左右的擦写速度 最好把Lets Yaffs do its own ECC选上,同时,把MTD NA

30、ND驱动中的ECC校验关闭。,2.2Yaffs文件系统的制作和使用,Yaffs源代码包的utils目录下包含了mkyaffsimage 和mkyaffs2image的代码,简单的修改一下Makefile里的内核路径就能编译出mkyaffsimage/mkyaffs2image工具。运行mkyaffsimage dir imagename可以制作出yaffs1文件系统的镜像。但是,需要注意的是,制作出来的yaffs image文件与通常的文件系统的image文件不同,因为在image文件里除了以512字节为单位的一个page的data数据外,同时紧跟在后还包括了16字节为单位的NAND备份数据区

31、(OOB)的数据。所以实际上是以528个字节为单位的。就是因为包含了这额外的16字节/page的数据,所以基本上常规办法如dd,或者通常的下载其它类型image的工具就无法正常下载yaffs image了,需要修改你所使用的下载工具的代码,使得它能将yaffs image中的这些额外数据也写入NAND FLASH OOB中。,需要注意通过mkyaffsimage制做出来的image其OOB中也包含它自己计算的ECC校验数据,其校验算法有可能和MTD NAND驱动的校验算法不同,如果在内核中由MTD来处理ECC,会造成MTD认为所有的page都校验错误。所以,最好把Lets Yaffs do i

32、ts own ECC选上,同时,把MTD NAND驱动中的ECC校验关闭。,其它方式制作yaffs文件系统,如果不考虑产线批量下载的话,也可以通过mount拷贝的方式准备yaffs文件系统。用flash_eraseall将NAND FLASH分区擦除,然后做为yaffs分区直接mount上来,将文件系统的内容拷贝上去就可以了。这可能是在真正的NAND FLASH上试验yaffs文件系统最简单的方式了。,四、Linux Framebuffer驱动设计,Aokikyon,概述,Linux操作系统,应用程序处于用户态,无法直接对LCD进行读写在Linux系统中,Framebuffer驱动提供了用户和

33、LCD屏幕之间的接口功能Framebuffer将显示设备抽象为内存缓冲区用户通过对内存的读写,可控制LCD输出,Framebuffer原理,必须使用Linux抽象出来的Framebuffer设备对LCD进行读写在DEV目录中一般命名为fb0、fb1FB驱动提供ioctl接口函数,实现查询、修改显示设备的参数功能Eg:图像的分辨率、像素位宽,Framebuffer,Linux,用户,LCD,Framebuffer设备驱动结构,驱动文件:linux/drivers/video/目录fbmem.c:提供LCD驱动的通用文件接口 fbcon.c:提供控制台相关操作接口函数 fb.h:定义了主要数据结构

34、 skeletonfb.c:演示了开发Framebuffer驱动程序的框架,FB驱动重要数据结构,struct fb_info 驱动最关键的结构体,包含了设备属性和操作的完整描述 struct fb_ops 提供底层操作的函数的指针,其中几个重要函数需要驱动设计人员完成,struct fb_fix_screeninfo 填充用户不可修改的参数,包含识别符、显示类型、显示的颜色属性等 struct fb_var_screeninfo 填充用户可以修改的参数,包括屏幕分辨率、每个像素的位宽、帧延时、行延时等,struct fb_fops Framebuffer属于字符设备,用户通过fb_fops结

35、构中定义的文件操作接口函数可以操作Framebuffer设备,文件接口函数统一由fbmem.c实现,一般不需要驱动编写人员再次编写,需要驱动设计人员完成的函数,fb_check_var()检测输入参数的正确性,若为硬件不支持的输出模式,则报错 fb_set_par()更新fb_var_screen结构体中的参数,用来更改硬件设置,fb_fillrect()在屏幕上填充矩形 fb_copyarea()区域复制函数 fb_imageblit()在屏幕上显示图片 init_LCD()初始化硬件寄存器 fb_probe()Framebuffer驱动初始化,SEP4020 Linux Framebuff

36、er设备驱动实现,1 修改linux/dirvers/video/kconfig文件,添加代码,并在编译内核时选上:config FB_SEP4020tristate SEP4020 LCD supportdepends on(FB=y)&ARM&select FB_CFB_FILLRECTselect FB_CFB_COPYAREAselect FB_CFB_IMAGEBLIT,2 修改linux/dirvers/video/Makefile文件,添加代码:obj-$(CONFIG_FB_SEP4020)+=sepfb.o,3 编写sepfb.c文件(只介绍主要部分)。,/*填充fb_var

37、_screeninfo结构体*/static struct fb_var_screeninfo sepfb_var=.xres=320,/实际x轴分辨率.yres=240,/实际y轴分辨率.xres_virtual=320,/虚拟x轴分辨率.yres_virtual=240,/虚拟y轴分辨率/*填充fb_fix_screeninfo结构体*/static struct fb_fix_screeninfo sepfb_fix=.id=“sep4020fb”,/设备名称.type=FB_TYPE_PACKED_PIXELS,/显示类型.visual=FB_VISUAL_TRUECOLOR,/显示颜

38、色属性,/*填充fb_ops*/static struct fb_ops sepfb_ops=.fb_check_var=sepfb_check_var,/检测参数函数.fb_set_par=sepfb_set_par,/设置参数函数.fb_fillrect=cfb_fillrect,/调用系统提供的函数.fb_copyarea=cfb_copyarea,/调用系统提供的函数.fb_imageblit=cfb_imagelbit,/调用系统提供的函数,/*初始化SEP4020硬件寄存器*/static void init_sep_LCD(void)*(volatile unsigned lon

39、g*)LCDC_LECR_V=0 x00000000;/禁LCDC*(volatile unsigned long*)LCDC_SSA_V=pVideoBuffer;/LCD数据起始地址*(volatile unsigned long*)LCDC_SIZE_V=YMAX|XMAX;*(volatile unsigned long*)LCDC_PCR_V=TFT|COLOR|PBSIZE|BPIX|PIXPOL|FLMPOL|LPPOL|CLKPOL|OEPOL|END_SEL|ACD_SEL|ACD|PCD;*(volatile unsigned long*)LCDC_HCR_V=H_WIDT

40、H|H_WAIT_1|H_WAIT_2;*(volatile unsigned long*)LCDC_VCR_V=V_WIDTH|PASS_FRAME_WAIT|V_WAIT_1|V_WAIT_2;*(volatile unsigned long*)LCDC_PWMR_V=SCR|CC_EN|PW;*(volatile unsigned long*)LCDC_DMACR_V=BL|HM|TM;*(volatile unsigned long*)LCDC_LECR_V=0 x00000001;/使能LCDC*(volatile unsigned long*)LCDC_LCDISR_V=0 x00

41、000000;,/*Framebuffer初始化函数*/static int _init sep4020fb_probe(struct fb_info*info)unsigned long pVideoBuffer;/物理地址unsigned long*videomemory;/虚拟地址videomemory=dma_alloc_writecombine(NULL,1536000,Framebuffer设备的用户空间访问,1 将LCD作为启动控制终端,将内核启动信息输出在屏幕上,需要修改Linux启动命令参数,添加代码“console=tty0”2 操作/dev/tty0设备在LCD上显示字符

42、,指令为“echo helloworld/dev/tty0”3 操作/dev/fb0设备在LCD上显示图片,将图片转换为和屏幕参数相对应的bin文件,通过指令“cp x.bin/dev/fb0”可将其显示显示在屏幕上,用户态下访问Framebuffer流程图,基于Framebuffer的应用程序开发,MiniguiQTOPIAMplayer,演示,一些运行GUI界面时的图片,五、嵌入式Linux 音频驱动程序设计,1.概述,目前,手机、MID、MP3等许多嵌入式设备包含数字音频设备,数字音频系统一般由处理器通过IIS、AC97等接口连接外部音频编解码器(CODEC),音频解码器实现声音的AD和

43、DA功能。音频编解码是数字音频系统的核心,衡量其性能的主要指标有采样频率和量化精度。在Linux系统中,为了处理数字音频相关工作,先后出现了两种音频设备框架:OSS和ALSA。ALSA完全开放,但是OSS更为成熟,1.1 IIS音频接口,IIS接口(Inter-IC Sound)在20世纪80年代首先被PHILIPS用于消费音频产品。IIS总线只处理声音数据,其他信号(如控制信号)必须单独传输。为了使芯片的引出管脚尽可能少,IIS只使用了三根串行总线。这三根线分别是:提供分时复用功能的数据线、字段选择线(声道选择)、时钟信号线。,SEP4020的IIS控制器具有如下功能:,支持MASTER 和

44、SLAVE 模式支持TRANSMITTER 和RECEIVER 功能支持32、16、8 位字长支持立体声和单声道支持静音和停止播放数据高位(MSB)先出/先入接收发送共享832 数据FIFO,1.2 UDA1341音频编解码芯片,SEP4020开发板使用的音频编解码芯片为NXP公司的UDA1341。UDA1341支持IIS总线数据格式,采用位元流转换技术进行信号处理,具有可编程增益放大器(PGA)和数字自动增益控制器(AGC)。UDA1341对外提供两组音频信号输入接口,每组包括左右2个声道。由于IIS总线只处理音频数据,因此UDA1341还内置用于传输控制信号的L3总线接口。L3接口相当于混

45、音器控制接口,可以控制输入输出音频信号的低音及音量大小等。,2.Linux OSS音频设备驱动,OSS的含义为,Open Sound System,是unix平台上一个统一的音频接口。以前,每个Unix厂商都会提供一个自己专有的API,用来处理音频。这就意味着为一种Unix平台编写的音频处理应用程序,在移植到另外一种Unix平台上时,必须要重写。OSS出现以后情况就大不一样了,只要音频处理应用程序按照OSS的API来编写,那么在移植到另外一个平台时,只需要重新编译即可。因此,OSS提供了源代码级的可移植性。由于Linux对Unix有着良好的兼容性,所以只需改变很少的地方,就可以使基于OSS的程

46、序在Linux下正常运行,Linux内核也对OSS架构提供了完善的支持。,2.1 OSS驱动组成,OSS标准有两个基本音频设备:dsp(数字信号处理器)和mixer(混音器)。dsp也称为编解码器,实现录音和放音的功能,其对应的设备文件是/dev/dsp或者/dev/sound/dsp。向改设备写数据即意味着激活CODEC上的D/A转换器进行播放,而向该设备读数据则意味着激活声卡上的A/D转换器进行录音。dsp的指标主要有:采样速率(电话为8K,CD为44.1K)、通道数目(单声道,立体声)、量化精度(8-bit,16-bit)。mixer设备用来控制多个输入、输出的音量,也控制输入(micr

47、ophone,line-in,CD)之间的切换。,2.2 dsp和mixer设备函数接口,dsp设备接口函数中比较重要的有read()、write()和ioctl()等。write()函数的作用是从用户空间复制音频数据到内核空间缓冲区并最终发送到音频控制器。在数据从缓冲区复制到音频设备的过程中,通常会使用DMA。在放音时,驱动设置完DMA控制器的源地址和目的地址,DMA控制器会自动将数据发送到CODEC的FIFO中,直到发完设定数据再通知上层。read()函数的作用是从音频控制器中获取录音数据到缓冲区并复制到用户空间。ioctl()函数用来设定采样速率、通道数、量化精度、DMA缓冲区大小等参数

48、。mixer设备主要通过ioctl()函数来实现不同的功能,2.3 OSS用户空间编程,OSS的层次结构非常简单,用户通过调用API函数访问OSS驱动。开发OSS应用程序的一般流程是:(1)在应用程序中包含OSS结构的头文件#include。(2)打开设备文件,返回文件描述符。(3)使用ioctl()函数设置设备参数。(4)使用read()函数录音或使用write()函数放音。(5)关闭打开的设备,结束应用程序。,OSS用户空间编程流程图,3.1 硬件接口描述,EP4020芯片与UDA1341相连,UDA1341的L3总线用来配置其自身的参数,可以用来控制输入/输出音频信号的音量大小、增益、低

49、音等。I2S _SCK 为UDA1341 接口的时钟信号;GPIO_PG11 用作GPIO 来控制双向模拟开关4066 将处理器I2S 接口数据信号I2S_SD 连接在UDA1341的数据输入或者输出信号上,从而进行录音/放音的数据切换。,SEP4020与UDA1341的详细接口描述,3.2 注册驱动及初始化硬件接口,在UDA1341 OSS驱动的模块加载函数中,将完成以下工作,初始化代码见代码清单1:(1)初始化3根GPIO口,模拟UDA1341的控制总线L3总线;(2)初始化IIS的GPIO口,配置成IIS模式;(3)初始化PWM,提供CDCLOCK信号;(4)调用init_sep4020

50、_iis_bus()函数,初始化IIS寄存器;(5)调用init_uda1341()函数,初始化UDA1341芯片;(6)调用audio_init_dma()函数,初始化DMA控制器;(7)注册dsp和mixer两个设备;,UDA1341 OSS 驱动初始化函数,static int _init sep4020_uda1341_init(void)printk(sep4020_uda1341_init!);init_gpio();init_pwm();init_sep4020_iis_bus();init_uda1341();audio_init_dma(,代码说明,初始化PWM给CDCLK提

展开阅读全文
相关资源
猜你喜欢
相关搜索
资源标签

当前位置:首页 > 生活休闲 > 在线阅读


备案号:宁ICP备20000045号-2

经营许可证:宁B2-20210002

宁公网安备 64010402000987号