快捷搜索:

通过mmap方式应用程序在Linux下访问物理地址提高

媒介

按照Linux分层驱动思惟,外设驱动与主机节制器的驱动不相关,主机节制器的驱动不关心外设,而外设驱动也不关心主机,外设造访核心层的通用利用法度榜样接口进行数据传输,主机和外设之间可以进行随意率性的组合。这样思惟要求利用法度榜样不该当直接造访物理地址,而是该当经由过程驱动法度榜样的调用来实现,以便维持利用法度榜样的可移植性,操作造访的统一性,利用法度榜样使用系统的统一调用接口造访外设,如应用write(),read()等函数进行实际的外设读写节制。利用法度榜样经由过程调用接口进入内核函数后,内核使用copy_from_user()得到利用层数据,内核驱动法度榜样也经由过程分层终极履行物理造访,之后把得到的数据用copy_to_user()回传给利用法度榜样的调用者。因为驱动对外必要有个统一接口,以是定义了一些布局体,链表等机制,以便让利用法度榜样操作简单化,数据在内核一利用之间的复制,添补布局体等都必要光阴开销,无意偶尔按这种标准调用要领,由于操作光阴过长,无法完成设计目的。

操作效率评估

我们的一个项目中,系统由FPGAARM11结合为核心节制器,此中FPGA连接外部高速ADCDACRF器件在ARM11的节制下,实现GB18000-6C标准的UHF RFID读写节制状态机。FPGA与ARM11的接口采纳SPI,此中ARM11选用三星S3C6410,作为SPI的主机,FPGA作为SPI的从机,受S3C6410的节制。在本系统中,SPI接口充当ARM11和FPGA交互的桥梁,ARM11的敕令和动作参数传给FPGA并启动FPGA处置惩罚状态机,FPGA动作的结果也经由过程SPI回传给ARM11,两者之间的通讯效率在系统中必要重点关注。

评估通讯接口时,使用三星供给的SPI驱动函数,系统运行在533MHz,SPI时钟设置设置设备摆设摆设为16MHz,法度榜样在linux3.0情况下经由过程read/write进行操作,为了评估效率,别的采纳一个GPIO输出脉冲唆使操作历程,试验结果显示效率异常低下,从利用层履行write代码开始到SPI端口输出时钟,延时长达72μs,SPI操作之后,再回到利用层的下一个语句也延时42μs,对付对照少的数据传输环境,附加的额外等待光阴远远擅长实际传输有效光阴,早年面数据看出,经由过程标准库调用严重影响系统机能,没法满意系统需求。经由过程查看驱动法度榜样的源代码,可以发明由于驱动法度榜样层层封装,并且包孕利用层到内核的copy_from_user()和内核到利用层的copy_to_user()两次数据搬移,导致履行效率很低。为了前进数据交互效率,就要设法绕开数据搬移等光阴开销,最好能直接操作寄存器,虽然这种设法主见与Linux分层驱动思惟不相相符,然则在嵌入式系统中,无意偶尔必要高的履行效率,假如使用系统一些特定函数,实现高效率的数据交互从而完成设计目标是有需要和可能的。

linux存在名为mmap的函数,能把物理地址映射为虚拟地址,并且这个函数能直接在利用法度榜样中直接调用而不是仅仅属于内核调用的函数,这样在利用层直接操作S3C6410的物理外设成为可能。斟酌到在特定的嵌入式系统中,特定外设的应用可以由法度榜样节制,这样可以简化共享设备的互斥保护,进一步削减代码量,前进了造访效率。

mmap函数调用实例

mmap函数感化是将物理地址映射至用户空间。下面是函数的参数简单阐明

void* mmap(void * addr, size_t len, int prot, int flags, int fd, off_t offset);

addr: 指定文件应被映射到进程空间的肇端地址

len: 映射到用户空间的字节数

prot: 指定被映射空间的造访权限,

flags: 由以下几个常值指定:

fd: 映射到用户空间的文件的描述符

offset: 被映射内存区在文件中的偏移值该函数映射文件描述符

经由过程这个函数,我们可以在利用层造访对应物理地址精确映射后的虚拟地址,这个函数使我们在利用层也具有对随意率性物理地址的操作权限,下面代码设置设置设备摆设摆设S3C6410的SPI0,由于应用mmap映射,以是不论内核是否带有SPI驱动都不影响我们应用SPI0,然则由于本法度榜样必要比较钻研标准驱动要领与直接存储器造访要领的履行差异,以是在内核中编译了标准SPI的驱动法度榜样。因为S3C6410多半脚都有复用功能,为了使SPI0精确事情,还必要设置设置设备摆设摆设相关对应的GPIO为SPI功能(实际上由于我们编译的内核带有SPI0的驱动,内核法度榜样已经完成了SPI的初始化,有的内核没有编译SPI,以是下面照样完备设置设置设备摆设摆设了SPI,供参考),同时为了察看钻研SPI的履行效率,我们法度榜样还对其他GPIO做了设置设置设备摆设摆设以便输出脉冲,经由过程示波器来评估察看。别的我们还应用多少光阴标志来记录操作历程光阴,对付在没有示波器的环境下也能评估履行光阴。

下面是测试法度榜样代码以及测试历程的示波器记录抓图。

#include “test.h”

void Init_FPGA_SPI(){ //设置设置设备摆设摆设SPI端口

int fbb;

fbb=open(“/dev/mem”,O_RDWR | O_SYNC);

map_base=(char *)mmap(0,4096,PROT_READ|PROT_WRITE,MAP_SHARED,fbb,0x7f00b000);

*(volatile unsigned int *)(map_base+0x04)=0x00000101; //CLK=16.625MHz

*(volaTIle unsigned int *)(map_base+0x08)=0x00000000;

*(volaTIle unsigned int *)(map_base+0x0c)=0x00000002;

*(volaTIle unsigned int *)(map_base)=0x00000003;

FPGA_RUN=map_base+0x18;

map_base=(char *)mmap(0,4096,PROT_READ|PROT_WRITE,MAP_SHARED,fbb,0x7f008000);

GPC=map_base+0x40; //设置设置设备摆设摆设端口复用功能为SPI

map_GPC=*(volaTIle unsigned int *)(GPC+4);

*(volatile unsigned int *)(GPC)=0x12201222;

GPC+=4;

virt_addr2=map_base+0x824;//设置设置设备摆设摆设察看IO

GLEDstate=*(volatile unsigned int *)(virt_addr2);

}

void Init_Timer(){ //添加加设置设置设备摆设摆设1微秒时基准时器

int fbb;

unsigned int temp;

fbb=open(“/dev/mem”,O_RDWR | O_SYNC);

map_base=(char *)mmap(0,4096,PROT_READ|PROT_WRITE,MAP_SHARED,fbb,0x7f006000);

…………………… 篇幅缘故原由略去部分次要代码

MYSYSTICK=map_base+0x14;

}

void SPI_init(){

bits=8;

speed = 16625000;

trr.len =20;

trr.delay_usecs = 0;

trr.speed_hz = speed;

trr.bits_per_word = bits;

fspi = open(“/dev/spidev0.0”, O_RDWR);

ioctl(fspi, SPI_IOC_RD_MODE, &mode);

ioctl(fspi, SPI_IOC_WR_MODE, &mode);

}

__inline unsigned int GETSYSCLK(){

return(*(volatile unsigned int *)(MYSYSTICK));

}

__inline void CSFPGAL(){

map_GPC&=0xfffffff7;

*(volatile unsigned int *)(GPC)=map_GPC;

}

__inline void CSFPGAH(){

map_GPC|=0x00000008;

*(volatile unsigned int *)(GPC)=map_GPC;

}

void test(){

GLEDstate&=0xfffffffe;

*(volatile unsigned int *)(virt_addr2)=GLEDstate;//孕育发生GPIO负跳变

starttime2=GETSYSCLK();

*(volatile unsigned int *)(FPGA_RUN-0x0c)=0x00;

*(volatile unsigned int *)(FPGA_RUN-0x18)=0x23;

*(volatile unsigned int *)(FPGA_RUN-0x18)=0x03;

CSFPGAL();

*(volatile unsigned int *)(FPGA_RUN)=tx[0];

*(volatile unsigned int *)(FPGA_RUN)=tx[1];

*(volatile unsigned int *)(FPGA_RUN)=tx[2];

*(volatile unsigned int *)(FPGA_RUN)=tx[3];

*(volatile unsigned int *)(FPGA_RUN)=tx[4];

while (((*(volatile unsigned int *)(FPGA_RUN-4)&0xfe000)》》13)2000000){ //2000ms测试一次

waittime=GETSYSCLK();

test();

}

}

}

图1示波器截图添加了一些光阴信息以便对应代码注释阐明,对应于代码mmap要领和标准驱动调用要领孕育发生了两组SCK时钟,GPIO察看脚显示第一次SPI造访耗损5μs,第二次造访耗损114μs,此中真正操作SPI的光阴也就4μs不到,其它光阴耗损在系统利用层到内核两次双向的数据拷贝以及为了统一对外接口所做的数据布局设置设置设备摆设摆设等方面,由此比较可以看出两种要领造访效率上的伟大年夜差异。

图 1

结语

经由过程mmap要领利用法度榜样在Linux下操作硬件寄存器,得当于关注高效率的造访场合,在嵌入式利用中,我们既能够得到应用操作系统治理义务和富厚开源驱动库的好处,同时又能在局部提升处置惩罚效率,前进处置惩罚数据的实时性。

责任编辑:gt

您可能还会对下面的文章感兴趣: