将 DMA 抽象为一个字符设备,在初始化函数中调用
void *dma_alloc_writecombine(struct device *dev, size_t size, dma_addr_t *handle, gfp_t gfp)
函数来分配两段物理地址连续的空间,一段作为源空间,一段作为目的空间。
然后将物理地址进行 ioremap 供驱动使用,最后调用 register_chrdev 来注册这个字符设备。
DMA 的 regs:
#define DMA0_BASE_ADDR 0x4B000000
#define DMA1_BASE_ADDR 0x4B000040
#define DMA2_BASE_ADDR 0x4B000080
#define DMA3_BASE_ADDR 0x4B0000C0
struct s3c_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;
};
配置 DMA(通过 ioctl 调用)
ev_dma = 0;
/* 把源,目的,长度告诉 DMA */
dma_regs->disrc = src_phys; /* 源的物理地址 */
dma_regs->disrcc = (0<<1) | (0<<0); /* 源位于 AHB 总线, 源地址递增 */
dma_regs->didst = dst_phys; /* 目的的物理地址 */
dma_regs->didstc = (0<<2) | (0<<1) | (0<<0); /* 目的位于 AHB 总线, 目的地址递增 */
dma_regs->dcon = (1<<30)|(1<<29)|(0<<28)|(1<<27)|(0<<23)|(0<<20)|(BUF_SIZE<<0); /* 使能中断,单个传输,软件触发, */
/* 启动 DMA */
dma_regs->dmasktrig = (1<<1) | (1<<0);
/* 如何知道 DMA 什么时候完成 ? */
/* 休眠 */
wait_event_interruptible(dma_waitq, ev_dma);
if (memcmp(src, dst, BUF_SIZE) == 0)
{
printk('MEM_CPY_DMA OKn');
}
else
{
printk('MEM_CPY_DMA ERRORn');
}
当 DMA 开始工作时会休眠一段时间,直到复制完成后触发中断来唤醒。
static irqreturn_t s3c_dma_irq(int irq, void *devid)
{
/* 唤醒 */
ev_dma = 1;
wake_up_interruptible(&dma_waitq); /* 唤醒休眠的进程 */
return IRQ_HANDLED;
}
可能这样的实验并不会看出 DMA 的作用,我们可以与普通的复制做一下速度上的对比。例如用 memcpy 来与 DMA PK 一下速度就能看出效果来。
上一篇:S3C2440时钟体系
下一篇:s3c2440的IIS的控制模块
推荐阅读最新更新时间:2024-11-11 18:09
设计资源 培训 开发板 精华推荐
- 使用 Microchip Technology 的 TC323A 的参考设计
- ADR5041A 2.5 Vout 精密微功率并联模式电压基准的典型应用,适用于 ±15 V 输出,采用堆叠式 ADR5045 器件
- CK_LINK Lite2.30
- 使用 ON Semiconductor 的 LV5215LF 的参考设计
- LT3506A 两级降压、高达 25V 输入至 1.2V 输出的典型应用电路
- LTC3718 的典型应用 - 用于 DDR/QDR 存储器终端的低输入电压、DC/DC 控制器
- MCIMX7SABRE: 面向智能设备,基于i.MX 7Dual应用处理器的SABRE电路板
- LT3663IDCB-5、5V 降压转换器的典型应用
- AD9650-80EBZ,用于 AD9650BCPZ-80、2 通道、16 位、80 MSPS 模数转换器的评估板
- Si5367-EVB,Si5367 PLL 时钟发生器评估板,任意频率精密时钟