自娱自乐10之Linux DMA使用2(DMA使用实例,用timer作DMA请求源实现流水灯)
来源:互联网 发布:数据挖掘导论 mobi 编辑:程序博客网 时间:2024/06/16 01:48
我想大家听过流水灯的实现,有很多方法,有一种是用定时器实现的。
通常是利用定时器中断,今天我要用timer作为DMA请求源,当timer时间到启动DMA传输,这样把一个一个数送的gpio口。实现流水灯
下面是代码,我的流水灯只流一次,平台是s3c2440
/*********************************** Copyright(C), 2013 LDP FileName: tiemr.c Author: wwxxxxll Date: Description: linux-3.2-36 History: Author Date Desc************************************/#include <linux/module.h>#include <linux/kernel.h>#include <linux/fs.h>#include <linux/miscdevice.h>#include <linux/dma-mapping.h>#include <linux/slab.h>#include <linux/interrupt.h>#include <asm/io.h>#include <asm/mach/time.h>#include <mach/regs-gpio.h>#include <mach/regs-gpioj.h>#include <mach/hardware.h>#include <mach/dma.h>#include <plat/regs-timer.h>#include <plat/gpio-fns.h>#include <plat/dma-ops.h>#define DEVICE_NAME"timer1" #define DMA_TEST//如果不定义DMA_TEST,就是一个timer1中断驱动#ifdef DMA_TEST#define SIZE 4struct timer_data{ struct samsung_dma_ops * timer_dma_ops; struct samsung_dma_info info;struct samsung_dma_prep_info pre_info;dma_addr_t dma_addr; unsigned ch;void * buf;};static struct timer_data timer1_data;static struct s3c2410_dma_client timer1_dma_client = {.name = "samsung-timer-dma",};#elsestatic irqreturn_t maichong_interrupt_1(int irq, void *dev_id){ printk("interrupt\n"); disable_irq_nosync(IRQ_TIMER1);return IRQ_RETVAL(IRQ_HANDLED);}#endifstatic int timer1_open(struct inode *inode, struct file *file);static int timer1_close(struct inode *inode, struct file *file);static struct file_operations dev_fops = {.owner=THIS_MODULE,.open = timer1_open, .release = timer1_close, };static struct miscdevice misc = {.minor = MISC_DYNAMIC_MINOR,.name = DEVICE_NAME,.fops = &dev_fops,};#ifdef DMA_TEST//dma中断时会调用这个函数,对这个函数来说就是数据传输完成static inline void timer_fp(void *name){unsigned long tcon;printk(KERN_INFO "complete\n"); tcon = __raw_readl(S3C2410_TCON); __raw_writel((tcon & (~(0xf << 8))) | (0xa << 8) ,S3C2410_TCON);//关timer,就流一次}#endifstatic int timer1_open(struct inode *inode, struct file *file){unsigned long tcon;unsigned long tcfg1;unsigned long tcfg0;int ret = 0;printk(KERN_INFO "%s\n", __func__);#ifdef DMA_TEST//设置为输出,根据自己的平台设置s3c2410_gpio_cfgpin(S3C2410_GPB(5), S3C2410_GPIO_OUTPUT);s3c2410_gpio_cfgpin(S3C2410_GPB(6), S3C2410_GPIO_OUTPUT);s3c2410_gpio_cfgpin(S3C2410_GPB(7), S3C2410_GPIO_OUTPUT);s3c2410_gpio_cfgpin(S3C2410_GPB(8), S3C2410_GPIO_OUTPUT);#endiftcon = __raw_readl(S3C2410_TCON);tcfg1 = __raw_readl(S3C2410_TCFG1);tcfg0 = __raw_readl(S3C2410_TCFG0);__raw_writel(tcfg0 | 0xff ,S3C2410_TCFG0 ); //下面对照数据手册看吧#ifdef DMA_TEST__raw_writel((tcfg1 & (~(0xf << 4)) ) | (3 << 4) | (2 << 20), S3C2410_TCFG1 );#else__raw_writel((tcfg1 & (~(0xf << 4)) ) | (3 << 4), S3C2410_TCFG1 );#endif__raw_writel((tcon & (~(0xf << 8)) ) | (0xa << 8) ,S3C2410_TCON );__raw_writel(8000, S3C2410_TCNTB(1));//我没有去计算多长时间,就是可以看到小灯一个一个量__raw_writel(1, S3C2410_TCMPB(1));__raw_writel((tcon & (~(0xf << 8)) ) | (0xa << 8) ,S3C2410_TCON ); #ifndef DMA_TESTif (request_irq(IRQ_TIMER1 , maichong_interrupt_1, IRQF_DISABLED, DEVICE_NAME, NULL)){ printk(KERN_ERR "can't request_irq\n");}#else timer1_data.buf = (void *)kzalloc(SIZE * sizeof(unsigned long), GFP_KERNEL);if (timer1_data.buf == NULL){ret = -ENOMEM;goto mem_err;}//流水灯数据*((unsigned long *)timer1_data.buf) = 0xffffffdf;*((unsigned long *)((unsigned long *)timer1_data.buf + 1)) = 0xffffffbf;*((unsigned long *)((unsigned long *)timer1_data.buf + 2)) = 0xffffff7f;*((unsigned long *)((unsigned long *)timer1_data.buf + 3)) = 0xfffffeff;timer1_data.pre_info.buf = dma_map_single(misc.this_device, timer1_data.buf, SIZE * sizeof(unsigned long), DMA_TO_DEVICE);if (dma_mapping_error(misc.this_device, DMA_TO_DEVICE)){ret = -ENOMEM;goto map_err;}timer1_data.pre_info.cap = DMA_SLAVE;timer1_data.pre_info.direction = DMA_TO_DEVICE; timer1_data.pre_info.fp = timer_fp; timer1_data.pre_info.len = SIZE * timer1_data.info.width; //这个长度是字节数 timer1_data.timer_dma_ops->prepare(timer1_data.ch, &timer1_data.pre_info);timer1_data.timer_dma_ops->trigger(timer1_data.ch);#endif__raw_writel( ( tcon & (~(0xf << 8)) ) | (0x9 << 8) ,S3C2410_TCON ); #ifdef DMA_TESTreturn ret;mem_err:dma_unmap_single(misc.this_device, timer1_data.pre_info.buf, SIZE * sizeof(unsigned long), DMA_TO_DEVICE);kfree(timer1_data.buf);map_err:#endifreturn ret;}static int timer1_close(struct inode *inode, struct file *file){printk(KERN_INFO "%s\n", __func__);#ifndef DMA_TEST free_irq(IRQ_TIMER1, NULL);#else timer1_data.timer_dma_ops->stop(timer1_data.ch);dma_unmap_single(misc.this_device, timer1_data.pre_info.buf, SIZE * sizeof(unsigned long), DMA_TO_DEVICE);kfree(timer1_data.buf);#endif return 0;}static int __init dev_init(void){int ret;#ifdef DMA_TEST timer1_data.timer_dma_ops = samsung_dma_get_ops();timer1_data.info.cap = DMA_SLAVE;timer1_data.info.direction = DMA_TO_DEVICE;timer1_data.info.client = &timer1_dma_client; timer1_data.info.fifo = 0x56000014;//这是GPIO B口数据寄存器地址timer1_data.info.width = 4;//数据宽度 timer1_data.ch = timer1_data.timer_dma_ops->request(DMACH_TIMER, &timer1_data.info); if (timer1_data.ch == 0){ret = -1;goto req_err;} timer1_data.timer_dma_ops->stop(timer1_data.ch);#endifret = misc_register(&misc); if (ret < 0){goto reg_err;} return ret;reg_err:#ifdef DMA_TEST timer1_data.timer_dma_ops->release(DMACH_TIMER, timer1_data.info.client);req_err:#endifreturn ret;}static void __exit dev_exit(void){#ifdef DMA_TEST timer1_data.timer_dma_ops->release(DMACH_TIMER, timer1_data.info.client);#endifmisc_deregister(&misc);}module_init(dev_init);module_exit(dev_exit);MODULE_LICENSE("GPL");MODULE_AUTHOR("wwxxxxll");
测试程序
#include <stdio.h>#include <fcntl.h>int main(void){ int fd; fd = open("/dev/timer1", O_RDWR); if (fd < 0) { return -1; } getchar(); close(fd); return 0;}
打印结果:
不好意思我不能把小灯的现象呈现给大家
后记:
如果你看过前面的udc驱动,你会看到有cache的应用,cache也是我要搞的
不过接下来我会先考虑在udc中加上DMA。这可能是我下期的内容。再见!
- 自娱自乐10之Linux DMA使用2(DMA使用实例,用timer作DMA请求源实现流水灯)
- 自娱自乐9之Linux DMA使用1(三星平台DMA分析)
- DMA的使用实例
- dma使用
- EFM32外设--DMA之Timer+DMA+DAC
- DMA
- DMA
- DMA
- DMA
- DMA
- DMA
- DMA
- DMA
- DMA
- DMA
- dma
- DMA
- dma
- ImageMagick和OpenCV文件格式互转
- linux如何发送电子邮件
- 为什么css中float:right右对齐会换行
- 命名空间 Namespaces
- 编程名言名句
- 自娱自乐10之Linux DMA使用2(DMA使用实例,用timer作DMA请求源实现流水灯)
- utf8与ucs2编码互转及原理
- 例外 Exceptions
- VS2010中没有ado.net entity data model实体数据模型这一选项-解决办法
- JSP跳转的方式
- 开源编码转换库libiconv
- EasyUI+Struts2整合KindEditor
- Paip. DDBS 分布式 数据库系统 attilax总结C0G
- 甘肃农业大学CSDN高校俱乐部策划书