1.kmalloc 分配的虚拟地址连续,物理地址一定连续
2.想用DMA必须分配连续的内存
3. kmalloc特殊之处在于它分配的内存是物理上连续的,这对于要进行DMA的设备十分重要. 而用vmalloc分配的内存只是线性地址连续,物理地址不一定连续,不能直接用于DMA。
定义源src 目的dst 源物理地址src_phys 目的物理地址dst_phys 大小定义宏
4.在驱动的入口函数分配缓冲区(注意不能用vmalloc分配出来物理地址不一定连续
)
第一个源表示在系统总线上还是外设总线上
第二个源地址是递增的还是固定的
目的地在内存上还是外设上
6.操作寄存器
创建结构体封装寄存器unsigned long型
DMA0和DMA1,DMA2寄存器地址然后定义变量static volatile struct s3c_dma_regs *dma_regs;
然后再去映射物理地址ioremap。
2.具体步骤
把源,目的,长度告诉DMA
源地址操作寄存器(注意是物理地址)
第一位控制源地址在内存还是在外设,如下图。
目的地址的物理地址
目的寄存器操作
DMA控制寄存器
(1)DMA模式
(2)同步 外设发给单片机请求DMA,答应给我一个DMArequst给我一个回应信号ACK
(3)中断
(4)使能中断知道他已经传输完成。
第二个模式会一直站住总线知道DMA传输完
23位设为0用软件触发的
数据传输大小一个字节,
还有TSZ和DSZ
DSZ:读写数据的大小 传输一次一字节还是4字节
TSZ:单次传输R/W一次 burst传输R/W四次
TC: 传输多少次
总长度=TCTSZDSZ。
dma_regs->dcon = (1<<30)|(1<<29)|(0<<28)|(1<<27)|(0<<23)|(0<<20)|(BUF_SIZE<<0);
/* 使能中断,单个传输,软件触发, */
启动DMA
如何意识到已经传输完成?
(1)完成会产生中断,所以我们先requst_irq
if (request_irq(IRQ_DMA3, s3c_dma_irq, 0, "s3c_dma", 1))
{
printk("can't request_irq for DMA\n");
return -EBUSY;
}
tatic irqreturn_t s3c_dma_irq(int irq, void *devid)
{
/* 唤醒 */
ev_dma = 1; /* 中断事件标志复位 */
wake_up_interruptible(&dma_waitq); /* 唤醒休眠的进程 */
return IRQ_HANDLED;
}
在启动DMA后休眠在中断后唤醒
static DECLARE_WAIT_QUEUE_HEAD(dma_waitq); /* 定义队列 */
wait_event_interruptible(dma_waitq, ev_dma); /* 需要定义中断事件标志来判断条件是否满足 */
static volatile int ev_dma = 0