DMA是数据传输的快速通道,不经过CPU,只占用总线周期。主要是根据DATASHEET配置DMA
现写一驱动程序:设置需要用到DMA通道传输数据的源、目的、长度等参数,让DMA自行传输,
传输完毕后,比较源、目的的最终数据,检验是否传输完整并正确。
-
#include <linux/module.h>
-
#include <linux/init.h>
-
#include <linux/device.h>
-
#include <linux/cdev.h>
-
#include <linux/fs.h>
-
#include <linux/sched.h>
-
#include <linux/wait.h>
-
#include <linux/dma-mapping.h>
-
#include <linux/string.h>
-
#include <linux/interrupt.h>
-
#include <mach/irqs.h>
-
-
-
#define BUF_SZ 512*1024
-
#define NO_DMA 0
-
#define USE_DMA 1
-
#define DMA0_BASE_ADDR 0x4B000000
-
#define DMA1_BASE_ADDR 0x4B000040
-
#define DMA2_BASE_ADDR 0x4B000080
-
#define DMA3_BASE_ADDR 0x4B0000C0
-
-
struct dma_regs {
-
unsigned long disrc;
-
unsigned long disrcc;
-
unsigned long didst;
-
unsigned long didstc;
-
unsigned long dcon;
-
unsigned long dstat;
-
unsigned long dcsrc;
-
unsigned long dcdst;
-
unsigned long dmasktrig;
-
};
-
-
static DECLARE_WAIT_QUEUE_HEAD(dma_waith);
-
-
volatile struct dma_regs *dma_regs;
-
static dma_addr_t src_phys;
-
static dma_addr_t dst_phys;
-
static char *src;
-
static char *dst;
-
static struct cdev cdev;
-
static int major;
-
static struct class *cls;
-
static volatile int ev_dma = 0;
-
-
static int dma_ioctl (struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg)
-
{
-
int i;
-
-
memset(src, 1, BUF_SZ);
-
memset(dst, 0, BUF_SZ);
-
switch (cmd) {
-
case NO_DMA:
-
{
-
for(i=0; i<BUF_SZ; i++)
-
dst[i] = src[i];
-
if (0 == memcmp(src, dst, BUF_SZ))
-
printk("(NO_DMA)Success to memcpy from source to destination.n");
-
else
-
printk("(NO_DMA)Failed to memcpy from source to destination.n");
-
}
-
break;
-
-
case USE_DMA:
-
{
-
ev_dma = 1;
-
/* 设置DMA相关寄存器 */
-
* DISRC[30:0]= src_phys:base address of source data to transfer
-
* DIDST[30:0]= dst_phys:base address of destination for the transfer
-
* DISRCC[1] = 0 : the source is in the system bus (AHB)
-
* DISRCC[0] = 0 : select the address increment.
-
* DIDSTC[2] = 0 : interrupt will occur when TC reaches 0
-
* DIDSTC[1] = 0 : the destination is in the system bus (AHB)
-
* DIDSTC[0] = 0 : select the address increment
-
* DCON[31] = 0 : demand mode will be selected
-
* DCON[30] = 1 : DREQ and DACK are synchronized to HCLK (AHB clock)
-
* DCON[29] = 1 : interrupt request is generated when all the transfer is done
-
* DCON[28] = 0 : a unit transfer is performed
-
* DCON[27] = 1 : whole service mode
-
* DCON[26:24]=000: select DMA request source for each DMA
-
* DCON[23] = 0 : S/W request mode is selected
-
* DCON[22] = 0 : auto reload
-
* DCON[21:20]= 00: data size(byte) to be transferred.
-
* DCON[19:0] = BUF_SZ : initial transfer count
-
* DMASKTRIG[1] = 1 : DMA channel is turned on
-
* DMASKTRIG[0] = 1 : trigger the DMA channel in S/W request mode.
-
*/
-
dma_regs->disrc = src_phys;
-
dma_regs->didst = dst_phys;
-
dma_regs->disrcc = (0<<1)|(0<<0);
-
dma_regs->didstc = (0<<2)|(0<<1)|(0<<0);
-
dma_regs->dcon = (0<<31)|(1<<30)|(1<<29)|(0<<28)|(1<<27)|(0<<24)|
-
(0<<23)|(0<<22)|(0<<20)|(BUF_SZ<<0);
-
/* 启动DMA */
-
dma_regs->dmasktrig = (1<<1)|(1<<0);
-
/* 休眠等待数据传输 */
-
wait_event_interruptible(dma_waith, ev_dma);
-
if (0 == memcmp(src, dst, BUF_SZ))
-
printk("(USE_DMA)Success to memcpy from source to destination.n");
-
else
-
printk("(USE_DMA)Failed to memcpy from source to destination.n");
-
}
-
break;
-
}
-
return 0;
-
}
-
-
static struct file_operations fops =
-
{
-
.ioctl = dma_ioctl,
-
};
-
-
static irqreturn_t mydma_irq(int irq, void *dat)
-
{
-
ev_dma = 1;
-
/* 数据传输完毕唤醒队列 */
-
wake_up_interruptible(&dma_waith);
-
-
return IRQ_HANDLED;
-
}
-
-
static int mydma_init(void)
-
{
-
-
dev_t devt;
-
/* 分配源、目的 缓冲区 */
-
src = dma_alloc_writecombine(NULL, BUF_SZ, &src_phys,GFP_KERNEL);
-
if (NULL == src)
-
{
-
printk("src-dma alloc failed!n");
-
return -ENOMEM;
-
}
-
dst = dma_alloc_writecombine(NULL, BUF_SZ, &dst_phys, GFP_KERNEL);
-
if (NULL == dst)
-
{
-
printk("dst-dma alloc failedn");
-
dma_free_writecombine(NULL, BUF_SZ, src, src_phys);
-
return -ENOMEM;
-
}
-
/* 动态申请字符设备区域 */
-
alloc_chrdev_region(&devt, 0, 1, "mydma");
-
/* MAJOR得到主设备号*/
-
major = MAJOR(devt);
-
/* 初始化并添加字符设备 */
-
cdev_init(&cdev, &fops);
-
cdev_add(&cdev, devt, 1);
-
/* 创建类 */
-
cls = class_create(THIS_MODULE, "mycls");
-
/* 创建类下的设备 */
-
device_create(cls, NULL, devt, NULL, "mydma");
-
/* 映射DMA寄存器 */
-
dma_regs = ioremap(DMA3_BASE_ADDR, sizeof(struct dma_regs));
-
/* 申请DMA中断*/
-
request_irq(IRQ_DMA3, mydma_irq, 0, "dma3", 1);
-
-
return 0;
-
-
}
-
-
static void mydma_exit(void)
-
{
-
free_irq(IRQ_DMA3, 1);
-
iounmap(dma_regs);
-
device_destroy(cls, MKDEV(major, 0));
-
class_destroy(cls);
-
cdev_del(&cdev);
-
unregister_chrdev_region(MKDEV(major, 0), 1);
-
dma_free_writecombine(NULL, BUF_SZ, src, src_phys);
-
dma_free_writecombine(NULL, BUF_SZ, dst, dst_phys);
-
return ;
-
}
-
-
module_init(mydma_init);
-
module_exit(mydma_exit);
-
-
MODULE_LICENSE("GPL");
测试程序:
-
#include <stdio.h>
-
#include <string.h>
-
#include <fcntl.h>
-
-
#define NO_DMA 0
-
#define USE_DMA 1
-
-
int main(int argc, char *argv[])
-
{
-
int cmd, fd;
-
-
if (argc != 2)
-
{
-
printf("%s n", argv[0]);
-
return -1;
-
}
-
fd = open("/dev/mydma", O_RDWR);
-
if(fd < 0)
-
printf("can not open /dev/mydman");
-
if(0 == strcmp(argv[1], "nodma"))
-
{
-
cmd = NO_DMA;
-
}
-
else if(0 == strcmp(argv[1], "usedma"))
-
{
-
cmd = USE_DMA;
-
}
-
else
-
{
-
printf("%s n", argv[0]);
-
return -1;
-
}
-
while(1)
-
{
-
ioctl(fd, cmd);
-
}
-
return 0;
-
}
2012-05-10 16:05 发表于百度空间,今搬至CU。
阅读(413) | 评论(0) | 转发(0) |