4 Linux下的驱动程序设计
系统采用ARM+嵌入式Linux的构架,Linux版本为2.4.18,采集系统必须和高效灵活的接口驱动程序相结合才能在操作系统下正常工作。
4.1 驱动程序的基本概念
设备驱动程序是操作系统内核和硬件之间的接口,它属于内核一部分,主要功能如下:
(1)对设备初始化或释放;
(2)把数据从内核传送至硬件。从硬件读取数据:
(3)读取应用程序传送给设备的数据,回送应用程序请求的数据:
(4)监测和处理设备出现的异常。
设备驱动程序为应用程序屏蔽了硬件的细节,在应用程序中,硬件设备只是一个设备文件,可以像操作普通文件一样对硬件设备进行操作。
4.2 修改代码
嵌入式Linux在arch/arm/mach-s3c2410目录下的dma.c文件中定义了一些与DMA操作相关的通用函数,主要有:申请DMA通道函数s3c2410_re,quest_dma()、申请DMA中断函数request_irq()、加入DMA队列函数s3c2410_dma_queue_buffer()、进行DMA操作函数process_dma()以及中断处理程序dma_irq_handler()等。在进行特定接口操作时,必须对其进行适当的修改。根据接口设置修改如下内容:
增加外部DMA操作的寄存器设置:
#define XDREQ0_CTL(DEMAND_MODE | SYNC_HCLK | INT_MODE | TSZ_UNIT
| SINGLE_SERVICE | HWSRC(CH0_nXDREQ0) | DMA_SRC_HW | CLR_ATRELOAD | DSZ(DSZ_BYTE)| TX_CNT(0));
//设置DMA为单服务命令模式,8位数据总线、允许中断且通过DREQ0硬件触发DMA操作
#define XDREQ0_RD_SRC 0x22000000
#define XDREQ0_RD_SRC_CTL BUF_ON_MEM_FIX
//设置DMA操作的源地址为系统总线上的0x22000000且地址固定
#define XDREQO_RD_DST_CTL BUF_ON_MEM
//设置DMA操作的目的地址在系统总线且地址逐次加1
通过DMA读取FPGA数据时必须由操作系统在内存中开辟一个空间做为DMA操作的目的地址。操作系统开辟的内存位于虚拟空间.而DMA操作的目的地址必须为物理地址,所以必须进行虚拟地址到物理地址的转换。因此在process_dma()中增加如下代码设置DMA的目的地址寄存器:
regs->DIDST=virt_to_bus(buf->dma_start)
virt_to_bus()是操作系统提供的虚拟地址到物理地址的转换函数,buf->dma_start是系统开辟的虚拟地址空间的首地址。
另外由接口原理图可知,S3C2410须向FPGA发送START信号启动FIFO的读写和DMA操作。所以系统定义GPB3作为START信号,定义如下:
#define START(GPIO_MODE_OUT | GPIO_PULLUP_DIS | GPIO_B3);
同时在process_dma()函数中增加如下代码启动DMA操作:
write_gpio_bit(START,1);
START引脚置为高电平后立即启动FIFO的写操作,同时也就启动了DMA操作进行数据传输,当DMA计数器减为0后发生DMA中断,并且在中断处理程序中将START位置0停止FIFO的写操作。
4.3 接口驱动的关键代码
利用系统提供的DMA操作函数,接口驱动的设计就显得比较容易。接口驱动属于字符设备驱动.重点在初始化和read函数部分。
初始化函数中完成DMA引脚定义、BANK4总线设置、申请DMA通道以及注册字符设备等。read函数是接口驱动的核心。应用程序正是通过调用read函数来读取数据。其核心代码如下:
fpga_buf_t *b=&fpga_buf;
dma_addr_t *buf;
b->size=count;
buf=kmalloc(b->size,GFP_DMA);
s3c2410 dma_queue_buffer(b->dma_ch,(void*)b,buf,b->size,DMA_BUF_RD);
if(copy_to_user(buff,buf,b->size))
return -EFAULT;
kfree(buf);
return b->size;
系统调用read函数时首先通过kmalloc分配一段虚拟内存空间,并将其指针和DMA通道、传输字节数一起通过s3c2410_dma_queue_buffer()加入DMA队列.在队列函数中调用process_dma()函数将
虚拟地址转换为物理地址并且启动DMA操作。DMA操作完成后退出队列并调用copy_to_user()将采集到的数据由内核空间拷贝到用户空间进行后续操作。
5 测试结果
图4为逻辑分析仪测得的数据采集时序图,A1表示FIFO中写入的数据数量;A2表示ARM采集到的数据;A3(0)表示读时钟CLKOUTO,频率为101.5 MHz;A3(1)表示片选信号nGCS4;A3(2)为DMA应答信号DACKO,即FIFO的读请求信号;A3(3)表示FIFO的空信号,即DMA的请求信号DREQO;A3(4)表示FIFO的复位信号,高电平复位,低电平开始工作;A3(5)表示FIFO的写时钟,频率为5 MHz;A3(6)表示写请求;A3(7)表示FIFO满信号。
由测试结果可以看出.DMA操作完全符合时序要求.一次数据采集所需时间约为220 ns,系统工作稳定正常。
6 结束语
本文讨论了S3C2410微控制器的DMA通道在数据采集中的应用,并通过与FPGA相配合设计了基于DMA方式的数据采集系统,同时给出了Linux下设备驱动程序的设计思路。文章所设计的数据采集接口具有很强的通用性,可以广泛用于各种信号量的采集。