1.前言
I/O设备与主存信息传送的控制方式分为程序轮询、中断、DMA、RDMA等。
2.DMA介绍
DMA,全称Direct Memory Access,即直接存储器访问。
DMA传输将数据从一个地址空间复制到另一个地址空间,提供在外设和存储器之间或者存储器和存储器之间的高速数据传输。
CPU有转移数据、计算、控制程序转移等很多功能,系统运作的核心就是CPU,CPU无时不刻的在处理着大量的事务,但有些事情却没有那么重要,比方说数据的复制和存储数据,如果我们把这部分的CPU资源拿出来,让CPU去处理其他的复杂计算事务,是不是能够更好的利用CPU的资源呢?
3.传输方式
DMA的作用就是实现数据的直接传输,而去掉了传统数据传输需要CPU寄存器参与的环节,主要涉及四种情况的数据传输,但本质上是一样的,都是从内存的某一区域传输到内存的另一区域(外设的数据寄存器本质上就是内存的一个存储单元)。四种情况的数据传输如下:
- 外设到内存
- 内存到外设
- 内存到内存
- 外设到外设
一个完整的 DMA 传输过程必须经过 DMA 请求、DMA 响应、DMA 传输、DMA 结束这四个阶段。
- DMA 请求:CPU 对 DMA 控制器初始化,并向 I/O 接口发出操作命令,I/O 接口提出 DMA 请求。
- DMA 响应:DMA 控制器对 DMA 请求判别优先级以及屏蔽位,向总线裁决逻辑提出总线请求,当 CPU 执行完成当前的总线周期之后即可释放总线控制权。此时,总线裁决逻辑输出总线应答,表示 DMA 已经就绪,通过 DMA 控制器通知 I/O 接口开始 DMA 传输。
- DMA 传输:在 DMA 控制器的引导下,在存储器和外设之间进行数据传送,在传送过程中不需要 CPU 的参与。
- DMA 结束:当完成既定操作之后,DMA 控制器释放总线控制权,并向 I/O 接口发出结束信号,当 I/O 接口收到结束信号之后,一方面停止 I/O 设备的工作,另一方面向 CPU 提出中断请求,使 CPU 从不介入状态解脱,并执行一段检查本次 DMA 传输操作正确性的代码。最后带着本次操作的结果以及状态继续执行原来的程序。
DMA 的原理就是 CPU 将需要迁移的数据的位置告诉给 DMA,包括源地址,目的地址以及需要迁移的长度,然后启动 DMA 设备,DMA 设备收到命令之后,就去完成相应的操作,最后通过中断反馈给 CPU,结束。
4.API函数
int DMA_Init(void)
{
/* Disable interrupts, we use polling mode */
XAxiDma_IntrDisable((uint32_t)g_axi_dma1_vaddr,XAXIDMA_IRQ_IOC_MASK, XAXIDMA_DMA_TO_DEVICE);
XAxiDma_IntrDisable((uint32_t)g_axi_dma1_vaddr,XAXIDMA_IRQ_IOC_MASK, XAXIDMA_DEVICE_TO_DMA);
return 0;
}
int DMA_WriteValue(unsigned int addr, unsigned char *data, unsigned int len)
{
memcpy((g_axi_dma1_buf_vaddr_write + addr), data, len);
XAxiDma_WriteReg((uint32_t)g_axi_dma1_vaddr, XAXIDMA_SRCADDR_OFFSET, AXI_DMA1_BUF_BASEADDR_WRITE);
XAxiDma_ReadReg((uint32_t)g_axi_dma1_vaddr, XAXIDMA_SRCADDR_OFFSET);
XAxiDma_WriteReg((uint32_t)g_axi_dma1_vaddr, XAXIDMA_BUFFLEN_OFFSET, len);
XAxiDma_ReadReg((uint32_t)g_axi_dma1_vaddr, XAXIDMA_BUFFLEN_OFFSET);
/* Wait till DMA MM2S Transfer Complete */
while(!(XAxiDma_ReadReg((uint32_t)g_axi_dma1_vaddr, XAXIDMA_SR_OFFSET) & 0x1000));
return 0;
}
int DMA_ReadValue(unsigned int addr, unsigned char *data, unsigned int len)
{
unsigned int reg = 0;
for(int ii = 0; ii < len; ii++)
{
*(g_axi_dma1_buf_vaddr_read + addr + ii) = 0;
}
// 停止
XAxiDma_WriteReg((uint32_t)g_axi_dma1_vaddr, XAXIDMA_CR_OFFSET + XAXIDMA_RX_OFFSET, XAXIDMA_CR_RUNSTOP_MASK);
/* 向48h寄存器写入 */
XAxiDma_WriteReg((uint32_t)g_axi_dma1_vaddr, XAXIDMA_DESTADDR_OFFSET + XAXIDMA_RX_OFFSET, AXI_DMA1_BUF_BASEADDR_READ);
XAxiDma_WriteReg((uint32_t)g_axi_dma1_vaddr, XAXIDMA_BUFFLEN_OFFSET + XAXIDMA_RX_OFFSET, len);
//XAxiDma_ReadReg((uint32_t)g_axi_dma1_vaddr, XAXIDMA_BUFFLEN_OFFSET + XAXIDMA_RX_OFFSET);
/* Wait till DMA MM2S Transfer Complete */
do{
reg = (unsigned int)XAxiDma_ReadReg((uint32_t)g_axi_dma1_vaddr, XAXIDMA_SR_OFFSET + XAXIDMA_RX_OFFSET);
}
while(!(reg & 0x1000));
//sync();
//清除中断寄存器
XAxiDma_WriteReg((uint32_t)g_axi_dma1_vaddr, XAXIDMA_SR_OFFSET + XAXIDMA_RX_OFFSET, reg);
///*读数据*/
memcpy(data, (g_axi_dma1_buf_vaddr_read + addr), len);
return 0;
}
5.参与讨论
==============================
新的文章内容和分享已更新在:
|工|·-·|重|·-·|号|:协议森林
==============================