日期:2014-05-16 浏览次数:20657 次
我想大家听过流水灯的实现,有很多方法,有一种是用定时器实现的。
通常是利用定时器中断,今天我要用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 4 struct 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", }; #else static irqreturn_t maichong_interrupt_1(int irq, void *dev_id) { printk("interrupt\n"); disable_irq_nosync(IRQ_TIMER1); return IRQ_RETVAL(IRQ_HANDLED); } #endif static 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,就流一次 } #endif static 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); #endif tcon = __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_TEST if (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; *((