S3C实现DMA驱动程序编写

发布者:DreamySunset最新更新时间:2024-08-05 来源: cnblogs关键字:S3C  DMA  驱动程序 手机看文章 扫描二维码
随时随地手机看文章

 54         {

 55             break;

 56         }

 57     }

 58 

 59     return 0;

 60 }

 61 

 62 static struct file_operations dma_fops = {

 63     .owner  = THIS_MODULE,

 64     .ioctl  = s3c_dma_ioctl,

 65 };

 66 

 67 static int s3c_dma_init(void)

 68 {

 69     /* 分配SRC, DST对应的缓冲区 */

 70     src = dma_alloc_writecombine(NULL, BUF_SIZE, &src_phys, GFP_KERNEL);

 71     if (NULL == src)

 72     {

 73         printk('can't alloc buffer for srcn');

 74         return -ENOMEM;

 75     }

 76     

 77     dst = dma_alloc_writecombine(NULL, BUF_SIZE, &dst_phys, GFP_KERNEL);

 78     if (NULL == dst)

 79     {

 80         dma_free_writecombine(NULL, BUF_SIZE, src, src_phys);

 81         printk('can't alloc buffer for dstn');

 82         return -ENOMEM;

 83     }

 84 

 85     major = register_chrdev(0, 's3c_dma', &dma_fops);

 86 

 87     /* 为了自动创建设备节点 */

 88     cls = class_create(THIS_MODULE, 's3c_dma');

 89     class_device_create(cls, NULL, MKDEV(major, 0), NULL, 'dma'); /* /dev/dma */

 90         

 91     return 0;

 92 }

 93 

 94 static void s3c_dma_exit(void)

 95 {

 96     class_device_destroy(cls, MKDEV(major, 0));

 97     class_destroy(cls);

 98     unregister_chrdev(major, 's3c_dma');

 99     dma_free_writecombine(NULL, BUF_SIZE, src, src_phys);

100     dma_free_writecombine(NULL, BUF_SIZE, dst, dst_phys);    

101 }

102 

103 module_init(s3c_dma_init);

104 module_exit(s3c_dma_exit);

105 

106 MODULE_LICENSE('GPL');


附上测试程序2.


 1 #include

 2 #include

 3 #include

 4 #include

 5 #include

 6 #include

 7 

 8 /* ./dma_test nodma

 9  * ./dma_test dma

10  */

11 #define MEM_CPY_NO_DMA  0

12 #define MEM_CPY_DMA     1

13 

14 void print_usage(char *name)

15 {

16     printf('Usage:n');

17     printf('%s n', name);

18 }

19 

20 

21 int main(int argc, char **argv)

22 {

23     int fd;

24     

25      if (argc != 2)

26     {

27         print_usage(argv[0]);

28         return -1;

29     }

30 

31     fd = open('/dev/dma', O_RDWR);

32     if (fd < 0)

33     {

34         printf('can't open /dev/dman');

35         return -1;

36     }

37 

38     if (strcmp(argv[1], 'nodma') == 0)

39     {

40         while (1)

41         {

42             ioctl(fd, MEM_CPY_NO_DMA);

43         }

44     }

45     else if (strcmp(argv[1], 'dma') == 0)

46     {

47         while (1)

48         {

49             ioctl(fd, MEM_CPY_DMA);

50         }

51     }

52     else

53     {

54         print_usage(argv[0]);

55         return -1;

56     }

57     return 0;     

58 }


三.映射s3c的DMA内存地址


测试程序时,不知道大家有没有发现,当我们运行test测试程序时,我们的拷贝进程占用了全部的CPU,以至于我们想运行一条命令都要等好久才能实现,


为了解决它,我们就引入了DMA,接下来,我们就真正开始DMA的编程


 1 #define DMA0_BASE_ADDR  0x4B000000

 2 #define DMA1_BASE_ADDR  0x4B000040

 3 #define DMA2_BASE_ADDR  0x4B000080

 4 #define DMA3_BASE_ADDR  0x4B0000C0

 5 

 6 struct s3c_dma_regs {

 7     unsigned long disrc;

 8     unsigned long disrcc;

 9     unsigned long didst;

10     unsigned long didstc;

11     unsigned long dcon;

12     unsigned long dstat;

13     unsigned long dcsrc;

14     unsigned long dcdst;

15     unsigned long dmasktrig;

16 };


如程序中所示:首先定义DMA的四个通道的基地址,接着定义一个s3c的dma的寄存器结构体.


分别再入口函数中映射DMA的内存IO端口,此处我们使用DMA0,当然如果要使用其他的DMA,类似.


在入口函数中映射:


dma_regs = ioremap(DMA0_BASE_ADDR, sizeof(struct s3c_dma_regs));

在出口函数中解除DMA映射.


iounmap(dma_regs);


四.注册DMA中断


前面我们已经映好DMA的内存地址了.


接下来,要想DMA工作,还需要对齐进行注册DMA中断和DMA配置.


在入口函数中注册DMA中断,再出口函数中释放DMA中断


在入口函数中注册中断:


1 if (request_irq(IRQ_DMA3, s3c_dma_irq, 0, 's3c_dma', 1))

2     {

3         printk('can't request_irq for DMAn');

4         return -EBUSY;

5     }

在出口函数中释放中断:


free_irq(IRQ_DMA3, 1);

当用户程序中定义为 MEM_CPY_DMA 使用DMA传输时,便会在ioctl函数中进入case MEM_CPY_DMA :中.


接着我们便在其中配置号DMA的源.目的参数,接着便启动传输,CPU则进入休眠状态,让出CPU供其他进程使用.当DMA拷贝完成时,便会触发中断,从而唤醒.


ioctl函数的部分程序如下面所示:


 1         case MEM_CPY_DMA :

 2         {

 3             ev_dma = 0;

 4             

 5             /* 把源,目的,长度告诉DMA */

 6             dma_regs->disrc      = src_phys;        /* 源的物理地址 */

 7             dma_regs->disrcc     = (0<<1) | (0<<0); /* 源位于AHB总线, 源地址递增 */

 8             dma_regs->didst      = dst_phys;        /* 目的的物理地址 */

 9             dma_regs->didstc     = (0<<2) | (0<<1) | (0<<0); /* 目的位于AHB总线, 目的地址递增 */

10             dma_regs->dcon       = (1<<30)|(1<<29)|(0<<28)|(1<<27)|(0<<23)|(0<<20)|(BUF_SIZE<<0);  /* 使能中断,单个传输,软件触发, */

11 

12             /* 启动DMA */

13             dma_regs->dmasktrig  = (1<<1) | (1<<0);

14 

15             /* 如何知道DMA什么时候完成? */

16             /* 休眠 */

17             wait_event_interruptible(dma_waitq, ev_dma);

18 

19             if (memcmp(src, dst, BUF_SIZE) == 0)

20             {

21                 printk('MEM_CPY_DMA OKn');

22             }

23             else

24             {

25                 printk('MEM_CPY_DMA ERRORn');

26             }

27             

28             break;

29         }


中断服务程序:


1 static irqreturn_t s3c_dma_irq(int irq, void *devid)

2 {

3     /* 唤醒 */

4     ev_dma = 1;

5     wake_up_interruptible(&dma_waitq);   /* 唤醒休眠的进程 */

6     return IRQ_HANDLED;

7 }


附上驱动程序3:


  1 #include

  2 #include

  3 #include

  4 #include

  5 #include

  6 #include

  7 #include

  8 #include

  9 #include

 10 #include

 11 #include

 12 #include

 13 #include

 14 

 15 #define MEM_CPY_NO_DMA  0

 16 #define MEM_CPY_DMA     1

 17 

 18 #define BUF_SIZE  (512*1024)

 19 

 20 #define DMA0_BASE_ADDR  0x4B000000

 21 #define DMA1_BASE_ADDR  0x4B000040

 22 #define DMA2_BASE_ADDR  0x4B000080

 23 #define DMA3_BASE_ADDR  0x4B0000C0

 24 

 25 struct s3c_dma_regs {

 26     unsigned long disrc;

 27     unsigned long disrcc;

 28     unsigned long didst;

 29     unsigned long didstc;

 30     unsigned long dcon;

 31     unsigned long dstat;

 32     unsigned long dcsrc;

 33     unsigned long dcdst;

 34     unsigned long dmasktrig;

 35 };

 36 

 37 

 38 static int major = 0;

 39 

 40 static char *src;

 41 static u32 src_phys;

 42 

 43 static char *dst;

 44 static u32 dst_phys;

 45 

 46 static struct class *cls;

 47 

 48 static volatile struct s3c_dma_regs *dma_regs;

 49 

 50 static DECLARE_WAIT_QUEUE_HEAD(dma_waitq);

 51 /* 中断事件标志, 中断服务程序将它置1,ioctl将它清0 */

 52 static volatile int ev_dma = 0;

 53 

 54 static int s3c_dma_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)

[1] [2] [3]
关键字:S3C  DMA  驱动程序 引用地址:S3C实现DMA驱动程序编写

上一篇:S3C2440实现dm9000网卡驱动程序移植
下一篇:S3C2440 nand_flash驱动程序

推荐阅读最新更新时间:2024-11-13 17:25

接近开关的51单片机驱动程序
今天用做了个小东西:数码管显示接近开关变化值接近开关通过外部中断0连接单片机;数码管示数增加到50后清零; #include reg51.h // 引用标准库的头文件 #include intrins.h #define uchar unsigned char #define uint unsigned int #define NoOp 0x00 // 空操作寄存器 #define Digit0 0x01 // 数码管1寄存器 #define Digit1 0x02 // 数码管2寄存器 #define Digit2 0x03 // 数码管3寄存器
[单片机]
stm32舵机驱动程序分享
  STM32系列基于专为要求高性能、低成本、低功耗的嵌入式应用专门设计的ARM Cortex-M3内核。按内核架构分为不同产品:   其中STM32F系列有:   STM32F103“增强型”系列   STM32F101“基本型”系列   STM32F105、STM32F107“互联型”系列   增强型系列时钟频率达到72MHz,是同类产品中性能最高的产品;基本型时钟频率为36MHz,以16位产品的价格得到比16位产品大幅提升的性能,是32位产品用户的最佳选择。两个系列都内置32K到128K的闪存,不同的是SRAM的最大容量和外设接口的组合。时钟频率72MHz时,从闪存执行代码,STM32功耗36mA,相当于0.5mA/MHz。
[单片机]
STM32F3的ADC使用DMA模式传输转换数据
本文使用ADC转换电位器输出的电压值,并用DMA模式传输转换的结果,每8次采样转换取平均值,做一个简单的数字滤波。 ADC的详细配置与使用 见之前的日记 STM32中ADC的使用 ,只是最后增加一步配置DMA: DMA for ADC channels features configuration  To enable the DMA mode for ADC channels group, use the ADC_DMACmd() function.  To configure the DMA transfer request, use ADC_DMAConfig() function. DMA的配置 (摘自STM32F3
[单片机]
micro2440 按键驱动程序
my_buttons.c文件: #include linux/fs.h #include linux/poll.h #include linux/irq.h #include linux/interrupt.h #include mach/regs-gpio.h #include mach/hardware.h #include linux/miscdevice.h #define DEVICE_NAME mybuttons struct button_irq_desc { int irq; int pin; int pin_setting; int number; char *na
[单片机]
关于STM32F107VCT6串口DMA接收数字控制LED亮灭的功能实现
主函数中代码如下: #include stm32f10x.h void GPIO_Config(void); void USART_Config(void); void DMA_Config(void); void NVIC_Config(void); void LED1_ON(void); void LED2_ON(void); void LED3_ON(void); void LED4_ON(void); void LED_ALL_OFF(void); void delay(void); uint8_t DMA_BUFFER ; int main() { GPIO_Config(); USART_Co
[单片机]
关于STM32F107VCT6串口<font color='red'>DMA</font>接收数字控制LED亮灭的功能实现
关于STM32 ADC DMA 使用心得(2)
(二)ADC循环采集六路电压,使用DMA. 这次实验真的很郁闷,对DMA的不了解让我深陷误区,明白之后,让我更加佩服DMA的强大。 误区就是:从实验的目标我们知道这次是用DMA把ADC转换的数据传送到内存中的一个数组里存起来,因为是采集6个通道,这里使能了ADC的扫描模式。一旦启动ADC,就会按顺序转换SQRX里选中的通道,问题就是我一开始以为ADC与DMA并不会协调工做,也就是ADC自己转自己的,DMA自己传自己的,这样的话内存里的数组就不是我想要的了,后来着实的研究了很长时间,在群里的一位兄弟的提醒下,我才知道,可能我想的复杂了,也许就可以在ADC转一次,然后DMA把数据传一次,Ok,经过实验得知,这个想法是正确的。
[单片机]
S3C内部中断和外部中断
1.中断分两大类:内部中断和外部中断。 2.外部中断。24个外部中断占用GPF0-GPF7(EINT0-EINT7),GPG0-GPG15(EINT8-EINT23)。用这些脚做中断输入,则必须配置引脚为中断,并且不要上拉。具体参考datesheet数据手册。 寄存器:EXTINT0-EXTINT2:三个寄存器设定EINT0-EINT23的触发方式。 EINTFLT0-EINTFLT3:控制滤波时钟和滤波宽度。 EINTPEND:这个是中断挂起寄存器,清除时要写1,后面还有几个是写1清除。当一个外部中断(EINT4-EINT23)发生后,那么相应的位会被置1。为什么没有EINT0-EINT3,呵呵,看
[单片机]
12.2440串口驱动程序设计
串口的功能就是接受数据跟发送数据的,在上一节已经了解串口的引脚信号。但是数据的收发需要一定的条件,也就是串口的初始化。所以所以今天的内容就会被划分为三个部分: 1.串口的初始化: 创建一个uart.c来对串口进行处理,然后把它加入到Makefile工程文件里: 接着就是串口处理程序的实现了。 程序的刚开始是对串口进行初始化,初始化的步骤: 配置引脚功能 设置数据模式 设置工作模式 设置波特率。 1)配置引脚功能: 在2440里的串口底板原理图: 上面的11 TXD0和12 RXD0就是串口的发送和接受引脚,对应的编号里的3,2口,5口是接地的。接下来在核心板原理图里找对应的共用引脚。在核心板原理图里搜
[单片机]
12.2440串口<font color='red'>驱动程序</font>设计
小广播
设计资源 培训 开发板 精华推荐

最新单片机文章
何立民专栏 单片机及嵌入式宝典

北京航空航天大学教授,20余年来致力于单片机与嵌入式系统推广工作。

 
EEWorld订阅号

 
EEWorld服务号

 
汽车开发圈

电子工程世界版权所有 京ICP证060456号 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号 Copyright © 2005-2024 EEWORLD.com.cn, Inc. All rights reserved