mini2440 简单的dma工作原理实验

来源:互联网 发布:尸鳖特效软件 编辑:程序博客网 时间:2024/06/06 04:56

以驱动方式测试dma的工作原理,用户层程序不停调用ioctl触发驱动里面完成的dma操作,把内存的数据块从一个连续地址搬到另一个连续地址,然后用memcmp测试搬移后的数据和搬移前是不是完全一样。

简单的驱动代码:

#include <linux/module.h>#include <linux/kernel.h>#include <linux/device.h>#include <linux/fs.h>#include <linux/mm.h>#include <linux/init.h>#include <linux/delay.h>#include <linux/interrupt.h>#include <linux/irq.h>#include <linux/gpio.h>#include <linux/sched.h>#include <linux/wait.h>#include <linux/poll.h>#include <linux/input.h>#include <linux/dma-mapping.h>#include <asm/uaccess.h>#include <asm/irq.h>#include <asm/io.h>#include <mach/regs-gpio.h>#defineMEM_CPY_NO_DMA0#defineMEM_CPY_USE_DMA1#defineDMA_BUF_SIZE(512*1024)#defineGRH_MODULE_NAME"grh_dma"#defineDMA_REG_BASE_ADDR_00x4B000000#defineDMA_REG_BASE_ADDR_10x4B000040#defineDMA_REG_BASE_ADDR_20x4B000080#defineDMA_REG_BASE_ADDR_30x4B0000C0static struct dma_regs{volatile unsigned long *disrc;volatile unsigned long *disrcc;volatile unsigned long *didst;volatile unsigned long *didstc;volatile unsigned long *dcon;volatile unsigned long *dstat;volatile unsigned long *dcsrc;volatile unsigned long *dcdst;volatile unsigned long *dmasktrig;};static struct dma_regs dma_regs_ins;static int major = 0;static char *src;static char *dst;static unsigned int src_phys; //数据源的物理地址static unsigned int dst_phys; //目标位置的物理地址static struct class *dma_class;static struct class_device *dma_class_device; //dma中断处理的相关数据static DECLARE_WAIT_QUEUE_HEAD(dma_waitq); //休眠的进程队列头static volatile int sleep_for_dma; //这个变量为0的时候ioctl函数会休眠,中断里面将其置1,read函数末尾将其设置为0static int dma_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg){int i;memset(src, 0xaa, DMA_BUF_SIZE);memset(dst, 0x55, DMA_BUF_SIZE);switch(cmd){case MEM_CPY_NO_DMA:{for(i=0; i<DMA_BUF_SIZE; i++)dst[i] = src[i];if(0 == memcmp(src, dst, DMA_BUF_SIZE))printk(KERN_EMERG"dma success!\n");elseprintk(KERN_EMERG"dma fail!\n");break;}case MEM_CPY_USE_DMA:{*(dma_regs_ins.disrc) = src_phys; //将数据源的物理地址存入disrc寄存器*(dma_regs_ins.disrcc) = (0<<0) | (0<<1); //源数据和目的位置是位于主存上的,设置dma的地址递增*(dma_regs_ins.didst) = dst_phys; ////将目标物理地址存入didst寄存器*(dma_regs_ins.didstc) = (0<<0) | (0<<1) | (0<<2); //不使用自动加载,地址递增,目的地址是位于主存中的*(dma_regs_ins.dcon) = (1<<30) | (1<<29) | (0<<28) | (1<<27) | (0<<23) | (0<<20) | (DMA_BUF_SIZE<<0); //使能中断,不使用突发传输,dma为软件触发,传输的最小单位是1字节//启动dma*(dma_regs_ins.dmasktrig) = (1<<1) | (1<<0);//休眠进程wait_event_interruptible(dma_waitq, sleep_for_dma);sleep_for_dma = 0;if(0 == memcmp(src, dst, DMA_BUF_SIZE))printk(KERN_EMERG"dma success!\n");elseprintk(KERN_EMERG"dma fail!\n");break;}}return 0;}static struct file_operations dma_fops = {.owner = THIS_MODULE,.ioctl = dma_ioctl,};//dma中断处理函数static irqreturn_t grh_handle_dma_int(int irq, void *dev_id){printk(KERN_EMERG"dma interrupt happened!\n");sleep_for_dma = 1;wake_up_interruptible(&dma_waitq);return IRQ_HANDLED;}static int dma_init(void){unsigned long *p_start;unsigned long **pp;int i;//分配dma使用的缓存空间src = dma_alloc_writecombine(NULL, DMA_BUF_SIZE, &src_phys, GFP_KERNEL);dst = dma_alloc_writecombine(NULL, DMA_BUF_SIZE, &dst_phys, GFP_KERNEL);if(NULL==src){printk(KERN_EMERG"allocate buffer for dma error!\n");return -ENOMEM;}if(NULL==dst){dma_free_writecombine(NULL, DMA_BUF_SIZE, src, src_phys);printk(KERN_EMERG"allocate buffer for dma error!\n");return -ENOMEM;}//进行地址映射p_start = (unsigned long*)ioremap(DMA_REG_BASE_ADDR_0, sizeof(struct dma_regs));pp = &(dma_regs_ins.disrc);for(i=0; i<9; i++){*(pp++) = p_start++;}//申请dma的中断if(request_irq(IRQ_DMA0, grh_handle_dma_int, 0, "dma0", 1)){printk(KERN_EMERG"request irq for dma error!\n");return -ENOMEM;}//默认会等待dma进行休眠sleep_for_dma = 0;major = register_chrdev(0, GRH_MODULE_NAME, &dma_fops);//create my own device classdma_class = class_create(THIS_MODULE, "grh_dma_class");//create my device of my own classdma_class_device = device_create(dma_class, NULL, MKDEV(major,0), NULL, "grh_dma_device");return 0;}static void dma_exit(void){unregister_chrdev(major, GRH_MODULE_NAME);device_unregister(dma_class_device);class_destroy(dma_class);iounmap(dma_regs_ins.disrc);dma_free_writecombine(NULL, DMA_BUF_SIZE, src, src_phys);dma_free_writecombine(NULL, DMA_BUF_SIZE, dst, dst_phys);free_irq(IRQ_DMA0, 1); //释放dma中断}module_init(dma_init);module_exit(dma_exit);MODULE_AUTHOR("GRH");MODULE_VERSION("1.0");MODULE_DESCRIPTION("DMA DRIVER");MODULE_LICENSE("GPL");

//用户层测试程序

#include <stdio.h>#include <stdlib.h>#include <sys/stat.h>#include <sys/types.h>#include <fcntl.h>#include <sys/ioctl.h>#include <string.h>#defineMEM_CPY_NO_DMA0#defineMEM_CPY_USE_DMA1void print_usage(const char *command){printf("usage: %s <nodma|dma>\n", command);}int main(int argc, char *argv[]){int count;int fd;fd = open("/dev/grh_dma_device", O_RDWR);if(fd < 0){printf("open device error!\n");return -1;}if(2 != argc){printf("command format error!\n");print_usage(argv[0]);return -1;}if(0 == strcmp(argv[1],"nodma")){while(1){ioctl(fd, MEM_CPY_NO_DMA);}}else if(0 == strcmp(argv[1],"dma")){while(1){ioctl(fd, MEM_CPY_USE_DMA);}}else{printf("parameter error!\n");print_usage(argv[0]);return -1;}close(fd);return 0;}

运行结果:使用dma时和不使用dma时数据搬移的效率明显加快,cpu消耗量锐减,系统响应速度提升。



0 0
原创粉丝点击