关于DMA传输的几点说明:
1 memory到外设的传输,调用alt_dma_txchan_ioctl()时,有一个参数为alt_dma_tx_only_on等
2调用alt_dma_txchan_send函数时,在传输结束前就返回一个值,如果此值为负的话,说明发送请求失败。正确传输结束后,调用done函数。
3接收函数alt_dma_rxthan_prepare类似上面的1和2
4传输结束,有两种可能:数据传完或者end of packet(要预先使能)
5 Sopc builder中例化时要制定哪些可以访问DMA的主端口,DMA的avalon slave端口要接cpu。实际传输的最大数可以帮助确定设置的位数
6 alt_dma_txchan_ioctl用于控制dma的一些工作性质,使用多的话可以用信号量等来“抢占”
7dma传输最小应该传4字或者其倍数。
两图是地址为什么加4的原因(每个寄存器32位,偏移为1时,地址应该加4)
内存到串口的DMA传输程序!
(使用的是HAL API函数,用IOWR灯访问reg调整参数也可以)
#include"system.h"
#include<stdio.h>
#include<stdlib.h>
#include"altera_avalon_pio_regs.h"
#include"altera_avalon_uart_regs.h"
#include"altera_avalon_timer_regs.h"
#include"altera_avalon_dma_regs.h"
#include"alt_types.h"
#include"sys/alt_irq.h"
#include"sys/alt_dma.h"
staticvolatileintrx_done = 0;//两种试验,数组和字符串
volatilestaticalt_u8 chr[20] = {1,2,3,4,6,5,7,8,9,10,11,12,13,14,15,16,17,18,19,20} ;
//发送字符volatile static char *chr ="asdfghjkloiuytrewqzx" ;
staticvoiddone (void* handle,void* data)//DMA传输结束调用函数
{
rx_done++;
}
main()
{
intrc,cwg;
alt_dma_txchan txchan;
if((txchan = alt_dma_txchan_open("/dev/dma")) ==NULL)
{
printf ("Failed to open transmit channel\n");
exit (1);
}
cwg = alt_dma_txchan_ioctl(txchan,ALT_DMA_SET_MODE_8 ,NULL);
cwg = alt_dma_txchan_ioctl(txchan,ALT_DMA_TX_ONLY_OFF,NULL);//
cwg = alt_dma_txchan_ioctl(txchan,ALT_DMA_RX_ONLY_OFF,NULL);
cwg = alt_dma_txchan_ioctl(txchan,ALT_DMA_TX_ONLY_ON,UART1_BASE + 4);
//ALT_DMA_TX_ONLY_ON代表使用流模式,UART1_BASE + 4是要写的地址(寄存器偏移为1时,+4)
if((rc = alt_dma_txchan_send (txchan, chr , 20, done,NULL)) < 0)
{
printf ("Failed to post read request, reason = %i\n", rc);
exit (1);
}
/* Wait for transfer to complete */
while(!rx_done);
printf("%d",rx_done);
rx_done = 0;
}
程序二,memory to memory的程序如下:
在NIOS II的HAL DMA设备模式中,DMA传输被分为两类:transmit 和 receive。NIOS提供两种设备驱动实现transmit channels和receive channels,transmit channels把缓冲区数据发送到目标设备,receive channels读取设备数据存放到缓冲区。
为了适应大家不同的开发环境,下面我们完成一个相对简单的DMA操作,复制SDRAM内存缓冲区到on_chip_memory中,如果我们在库工程属性中设置了SDRAM为主内存,那么程序中分配的数组缓冲区就在SDRAM中,我们用指针赋值让指针指向on_chip_memory。这个操作完全可以在程序中用memcpy来实现,我们趋简就繁,就是为了尝试一下DMAJ。
首先我们在SOPC Builder中增加一个名字为dma_0的DMA设备。两个表单设置都选默认。
第二步,DMA设备有三个PORT,两个MASTER PORT:read_master、write_master,一个SLAVE PORT:control_port_slave。需要在SOPC BUILDER中设置AVALONE交换总线,设置read_master和sdram连接,write_master和on_chip_memory连接,具体见下图(交叉点为黑色)。
在sopc builder中生成系统,并在Quartus II中编译下载,硬件部分就OK了。如果你的DMA操作不是内存到内存的,而是内存到设备,或者设备到内存,那么你需要在上面这一步中加以设置,设备只支持读写,是CPU读写还是DMA读写设备不加以区分。
在程序中,我们要使用DMA必须包含:sys/alt_dma.h。
因为是内存DMA操作,所以我们必须实现transmit channels