甘肃seo网站,免费多用户商城系统源码,品牌策划公司的市场,策划公司活动方案前言 按照Linux分层驱动思想#xff0c;外设驱动与主机控制器的驱动不相关#xff0c;主机控制器的驱动不关心外设#xff0c;而外设驱动也不关心主机#xff0c;外设访问核心层的通用应用程序接口进行数据传输#xff0c;主机和外设之间可以进行任意的组合。这样思想要…前言 按照Linux分层驱动思想外设驱动与主机控制器的驱动不相关主机控制器的驱动不关心外设而外设驱动也不关心主机外设访问核心层的通用应用程序接口进行数据传输主机和外设之间可以进行任意的组合。这样思想要求应用程序不应当直接访问物理地址而是应当通过驱动程序的调用来实现以便保持应用程序的可移植性操作访问的统一性应用程序利用系统的统一调用接口访问外设如使用write()read()等函数进行实际的外设读写控制。应用程序通过调用接口进入内核函数后内核利用copy_from_user()获得应用层数据内核驱动程序也通过分层最终执行物理访问之后把获得的数据用copy_to_user()回传给应用程序的调用者。由于驱动对外需要有个统一接口所以定义了一些结构体链表等机制以便让应用程序操作简单化数据在内核一应用之间的复制填充结构体等都需要时间开销有时按这种标准调用方式因为操作时间过长无法完成设计目的。操作效率评估 我们的一个项目中系统由FPGA和ARM11结合为核心控制器其中FPGA连接外部高速ADC、DAC和RF器件在ARM11的控制下实现GB18000-6C标准的UHF RFID读写控制状态机。FPGA与ARM11的接口采用SPI其中ARM11选用三星S3C6410作为SPI的主机FPGA作为SPI的从机受S3C6410的控制。在本系统中SPI接口充当ARM11和FPGA交互的桥梁ARM11的命令和动作参数传给FPGA并启动FPGA处理状态机FPGA动作的结果也通过SPI回传给ARM11两者之间的通讯效率在系统中需要重点关注。评估通讯接口时利用三星提供的SPI驱动函数系统运行在533MHzSPI时钟配置为16MHz程序在linux3.0环境下通过read/write进行操作为了评估效率另外采用一个GPIO输出脉冲指示操作过程试验结果显示效率非常低下从应用层执行write代码开始到SPI端口输出时钟延时长达72μsSPI操作之后再回到应用层的下一个语句也延时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.hvoid Init_FPGA_SPI(){ //配置SPI端口int fbb;fbbopen(/dev/memO_RDWR | O_SYNC);map_base(char *)mmap(04096PROT_READ|PROT_WRITEMAP_SHAREDfbb0x7f00b000);*(volatile unsigned int *)(map_base0x04)0x00000101; //CLK16.625MHz*(volatile unsigned int *)(map_base0x08)0x00000000;*(volatile unsigned int *)(map_base0x0c)0x00000002;*(volatile unsigned int *)(map_base)0x00000003;FPGA_RUNmap_base0x18;map_base(char *)mmap(04096PROT_READ|PROT_WRITEMAP_SHAREDfbb0x7f008000);GPCmap_base0x40; //配置端口复用功能为SPImap_GPC*(volatile unsigned int *)(GPC4);*(volatile unsigned int *)(GPC)0x12201222;GPC4;virt_addr2map_base0x824;//配置观察IOGLEDstate*(volatile unsigned int *)(virt_addr2);}void Init_Timer(){ //添加加配置1微秒时基定时器int fbb;unsigned int temp;fbbopen(/dev/memO_RDWR | O_SYNC);map_base(char *)mmap(04096PROT_READ|PROT_WRITEMAP_SHAREDfbb0x7f006000);…………………… 篇幅原因略去部分次要代码MYSYSTICKmap_base0x14;}void SPI_init(){bits8;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_GPC0xfffffff7;*(volatile unsigned int *)(GPC)map_GPC;}__inline void CSFPGAH(){map_GPC|0x00000008;*(volatile unsigned int *)(GPC)map_GPC;}void test(){GLEDstate0xfffffffe;*(volatile unsigned int *)(virt_addr2)GLEDstate;//产生GPIO负跳变starttime2GETSYSCLK();*(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)5){}CSFPGAH();stoptime2GETSYSCLK();GLEDstate|0x00000001;*(volatile unsigned int *)(virt_addr2)GLEDstate;GLEDstate0xfffffffe;*(volatile unsigned int *)(virt_addr2)GLEDstate;starttime1GETSYSCLK(); //产生GPIO一个正脉冲write(fspitx5);stoptime1GETSYSCLK();GLEDstate|0x00000001;*(volatile unsigned int *)(virt_addr2)GLEDstate; //产生GPIO正跳变printf(DRVtime%d REGtime%d starttime1-stoptime1starttime2-stoptime2);}int main(void){SPI_init(); Init_FPGA_SPI(); Init_Timer();waittimeGETSYSCLK();while(1){if ((waittime-GETSYSCLK())2000000){ //2000ms测试一次waittimeGETSYSCLK();test();}}}图1示波器截图添加了一些时间信息以便对应代码注释说明对应于代码mmap方式和标准驱动调用方式产生了两组SCK时钟GPIO观察脚显示第一次SPI访问消耗5μs第二次访问消耗114μs其中真正操作SPI的时间也就4μs不到其它时间消耗在系统应用层到内核两次双向的数据拷贝以及为了统一对外接口所做的数据结构配置等方面由此对比可以看出两种方式访问效率上的巨大差异。图 1结语 通过mmap方式应用程序在Linux下操作硬件寄存器适合于关注高效率的访问场合在嵌入式应用中我们既能够获得使用操作系统管理任务和丰富开源驱动库的好处同时又能在局部提升处理效率提高处理数据的实时性。