Chinaunix首页 | 论坛 | 博客
  • 博客访问: 1146757
  • 博文数量: 177
  • 博客积分: 761
  • 博客等级: 上士
  • 技术积分: 1518
  • 用 户 组: 普通用户
  • 注册时间: 2011-02-04 22:37
文章分类

全部博文(177)

文章存档

2017年(1)

2016年(3)

2015年(33)

2014年(48)

2013年(60)

2012年(32)

分类: LINUX

2013-03-11 17:17:34

原文地址:DMA数据传输 作者:angrad

DMA是数据传输的快速通道,不经过CPU,只占用总线周期。主要是根据DATASHEET配置DMA
现写一驱动程序:设置需要用到DMA通道传输数据的源、目的、长度等参数,让DMA自行传输,
传输完毕后,比较源、目的的最终数据,检验是否传输完整并正确。

点击(此处)折叠或打开

  1. #include <linux/module.h>
  2. #include <linux/init.h>
  3. #include <linux/device.h>
  4. #include <linux/cdev.h>
  5. #include <linux/fs.h>
  6. #include <linux/sched.h>
  7. #include <linux/wait.h>
  8. #include <linux/dma-mapping.h>
  9. #include <linux/string.h>
  10. #include <linux/interrupt.h>
  11. #include <mach/irqs.h>


  12. #define BUF_SZ 512*1024
  13. #define NO_DMA 0
  14. #define USE_DMA 1
  15. #define DMA0_BASE_ADDR 0x4B000000
  16. #define DMA1_BASE_ADDR 0x4B000040
  17. #define DMA2_BASE_ADDR 0x4B000080
  18. #define DMA3_BASE_ADDR 0x4B0000C0

  19. struct dma_regs {
  20.         unsigned long disrc;
  21.         unsigned long disrcc;
  22.         unsigned long didst;
  23.         unsigned long didstc;
  24.         unsigned long dcon;
  25.         unsigned long dstat;
  26.         unsigned long dcsrc;
  27.         unsigned long dcdst;
  28.         unsigned long dmasktrig;
  29. };

  30. static DECLARE_WAIT_QUEUE_HEAD(dma_waith);

  31. volatile struct dma_regs *dma_regs;
  32. static dma_addr_t src_phys;
  33. static dma_addr_t dst_phys;
  34. static char *src;
  35. static char *dst;
  36. static struct cdev cdev;
  37. static int major;
  38. static struct class *cls;
  39. static volatile int ev_dma = 0;

  40. static int dma_ioctl (struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg)
  41. {
  42.         int i;

  43.         memset(src, 1, BUF_SZ);
  44.         memset(dst, 0, BUF_SZ);
  45.         switch (cmd) {
  46.         case NO_DMA:
  47.         {
  48.                 for(i=0; i<BUF_SZ; i++)
  49.                         dst[i] = src[i];
  50.                 if (0 == memcmp(src, dst, BUF_SZ))
  51.                         printk("(NO_DMA)Success to memcpy from source to destination.n");
  52.                 else
  53.                         printk("(NO_DMA)Failed to memcpy from source to destination.n");
  54.                 }
  55.         break;
  56.         
  57.         case USE_DMA:
  58.         {
  59.                 ev_dma = 1;
  60.                 /* 设置DMA相关寄存器 */
  61.                  * DISRC[30:0]= src_phys:base address of source data to transfer
  62.                  * DIDST[30:0]= dst_phys:base address of destination for the transfer
  63.                  * DISRCC[1] = 0 : the source is in the system bus (AHB)
  64.                  * DISRCC[0] = 0 : select the address increment.
  65.                  * DIDSTC[2] = 0 : interrupt will occur when TC reaches 0
  66.                  * DIDSTC[1] = 0 : the destination is in the system bus (AHB)
  67.                  * DIDSTC[0] = 0 : select the address increment
  68.                  * DCON[31] = 0 : demand mode will be selected
  69.                  * DCON[30] = 1 : DREQ and DACK are synchronized to HCLK (AHB clock)
  70.                  * DCON[29] = 1 : interrupt request is generated when all the transfer is done
  71.                  * DCON[28] = 0 : a unit transfer is performed
  72.                  * DCON[27] = 1 : whole service mode
  73.                  * DCON[26:24]=000: select DMA request source for each DMA
  74.                  * DCON[23] = 0 : S/W request mode is selected
  75.                  * DCON[22] = 0 : auto reload
  76.                  * DCON[21:20]= 00: data size(byte) to be transferred.
  77.                  * DCON[19:0] = BUF_SZ : initial transfer count
  78.                  * DMASKTRIG[1] = 1 : DMA channel is turned on
  79.                  * DMASKTRIG[0] = 1 : trigger the DMA channel in S/W request mode.
  80.                  */
  81.                 dma_regs->disrc = src_phys;
  82.                 dma_regs->didst = dst_phys;
  83.                 dma_regs->disrcc = (0<<1)|(0<<0);
  84.                 dma_regs->didstc = (0<<2)|(0<<1)|(0<<0);
  85.                 dma_regs->dcon = (0<<31)|(1<<30)|(1<<29)|(0<<28)|(1<<27)|(0<<24)|
  86.                  (0<<23)|(0<<22)|(0<<20)|(BUF_SZ<<0);
  87.                 /* 启动DMA */
  88.                 dma_regs->dmasktrig = (1<<1)|(1<<0);
  89.                 /* 休眠等待数据传输 */
  90.                 wait_event_interruptible(dma_waith, ev_dma);
  91.                 if (0 == memcmp(src, dst, BUF_SZ))
  92.                         printk("(USE_DMA)Success to memcpy from source to destination.n");
  93.                 else
  94.                         printk("(USE_DMA)Failed to memcpy from source to destination.n");
  95.         }
  96.         break;
  97.     }
  98.         return 0;
  99. }

  100. static struct file_operations fops =
  101. {
  102.         .ioctl = dma_ioctl,
  103. };

  104. static irqreturn_t mydma_irq(int irq, void *dat)
  105. {
  106.         ev_dma = 1;
  107.         /* 数据传输完毕唤醒队列 */
  108.         wake_up_interruptible(&dma_waith);

  109.         return IRQ_HANDLED;
  110. }

  111. static int mydma_init(void)
  112. {

  113.         dev_t devt;
  114.         /* 分配源、目的 缓冲区 */
  115.         src = dma_alloc_writecombine(NULL, BUF_SZ, &src_phys,GFP_KERNEL);
  116.         if (NULL == src)
  117.         {
  118.                 printk("src-dma alloc failed!n");
  119.                 return -ENOMEM;
  120.         }
  121.                 dst = dma_alloc_writecombine(NULL, BUF_SZ, &dst_phys, GFP_KERNEL);
  122.         if (NULL == dst)
  123.         {
  124.                 printk("dst-dma alloc failedn");
  125.                 dma_free_writecombine(NULL, BUF_SZ, src, src_phys);
  126.                 return -ENOMEM;
  127.         }
  128.         /* 动态申请字符设备区域 */
  129.         alloc_chrdev_region(&devt, 0, 1, "mydma");
  130.         /* MAJOR得到主设备号*/
  131.         major = MAJOR(devt);
  132.         /* 初始化并添加字符设备 */
  133.         cdev_init(&cdev, &fops);
  134.         cdev_add(&cdev, devt, 1);
  135.         /* 创建类 */
  136.         cls = class_create(THIS_MODULE, "mycls");
  137.         /* 创建类下的设备 */
  138.         device_create(cls, NULL, devt, NULL, "mydma");
  139.         /* 映射DMA寄存器 */
  140.         dma_regs = ioremap(DMA3_BASE_ADDR, sizeof(struct dma_regs));
  141.         /* 申请DMA中断*/
  142.         request_irq(IRQ_DMA3, mydma_irq, 0, "dma3", 1);

  143.         return 0;

  144. }

  145. static void mydma_exit(void)
  146. {
  147.         free_irq(IRQ_DMA3, 1);
  148.         iounmap(dma_regs);
  149.         device_destroy(cls, MKDEV(major, 0));
  150.         class_destroy(cls);
  151.         cdev_del(&cdev);
  152.         unregister_chrdev_region(MKDEV(major, 0), 1);
  153.         dma_free_writecombine(NULL, BUF_SZ, src, src_phys);
  154.         dma_free_writecombine(NULL, BUF_SZ, dst, dst_phys);
  155.         return ;
  156. }

  157. module_init(mydma_init);
  158. module_exit(mydma_exit);

  159. MODULE_LICENSE("GPL");

测试程序:


点击(此处)折叠或打开

  1. #include <stdio.h>
  2. #include <string.h>
  3. #include <fcntl.h>

  4. #define NO_DMA 0
  5. #define USE_DMA 1

  6. int main(int argc, char *argv[])
  7. {
  8.         int cmd, fd;
  9.         
  10.         if (argc != 2)
  11.         {
  12.                 printf("%s n", argv[0]);
  13.                 return -1;
  14.         }
  15.         fd = open("/dev/mydma", O_RDWR);
  16.         if(fd < 0)
  17.                 printf("can not open /dev/mydman");
  18.         if(0 == strcmp(argv[1], "nodma"))
  19.         {
  20.                 cmd = NO_DMA;
  21.         }
  22.         else if(0 == strcmp(argv[1], "usedma"))
  23.         {
  24.                 cmd = USE_DMA;
  25.         }
  26.         else
  27.         {
  28.                 printf("%s n", argv[0]);
  29.                 return -1;
  30.         }
  31.         while(1)
  32.         {
  33.                 ioctl(fd, cmd);
  34.         }
  35.         return 0;
  36. }

2012-05-10 16:05 发表于百度空间,今搬至CU。


阅读(787) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~