ARM系统中DMA方式在数据采集中的应用

技术分类: 嵌入式系统  | 2007-12-04
来源:国外电子元器件 | 作者:龙再川 赵凯生

  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()将采集到的数据由内核空间拷贝到用户空间进行后续操作。

0
0
(请您对文章做出评价)
1】【2】【3
加载中

对文章的评论

更多评论

剩余字数:  

相关在线研讨会

我要参加

电路设计中可预测和不可预测问题的调试技术

时间:2008-06-02 10:00:00-12:00:00
简介:在嵌入式系统设计中,经常会出现一些可预测和不可预测的问题或者低概率事件信号。快速有效地发现这些问题需要不同的技术。8月15日…

浏览该文章的用户还看过...

  • 文 章

  • 论 坛

  • 博 客

  • 小 组

设计资源与分销

  • 博客推荐

  • 论坛推荐

  • 在线研讨会