2020.5.20 Xilinx FPGA Zynq DMA驅動

PL端參考本文:
http://www.fpgadeveloper.com/2014/08/using-the-axi-dma-in-vivado.html
https://blog.csdn.net/qq_20091945/article/details/70194026
github:
*使用 vivado2018.2 ,linaro15.4,設備樹卡一半內存,設置一半留給操作系統,一半留給FPGA做共享內存,參考微博: https://blog.csdn.net/weixin_40604731/article/details/88751053
*本文爲在linux操作系統下的DMA操作,裸機可直接調用API。如有錯誤之處還請不吝賜教!
1、PL端連接圖(參考PL端參考文本)
在這裏插入圖片描述
2、DMA驅動
*本文DDR爲1G,卡一本內存512MB,所以從物理基地址 0x20000000 開始,到0x40000000 爲FPGA共享內存。

驅動程序,需要在vivado sdk中創建新的linux 應用,生成./elf,直接在linux系統中運行。

#define AXIDMA_MM2S_BASEADDR 0x20000000
#define AXIDMA_S2MM_BASEADDR 0x20001000
//AXI DMA Simple
#define MM2S_DMACR 0x00
#define MM2S_DMASR 0x04
#define MM2S_SA 0x18
#define MM2S_LENGTH 0x28
#define S2MM_DMACR 0x30
#define S2MM_DMASR 0x34
#define S2MM_DA 0x48
#define S2MM_LENGTH 0x58
//Reset AXI DMA MM2S 
void DMA_MM2S_Reset()
{
	int map_len = 0x60;
	int fd = open("/dev/mem", O_RDWR);

	unsigned char *dma_base_address;
	dma_base_address = (unsigned char *)mmap(NULL, map_len, PROT_READ | PROT_WRITE, MAP_SHARED, fd, (off_t)AXIDMA_MM2S_BASEADDR);
	if(dma_base_address == MAP_FAILED)
	{
		perror("DMA MM2S Reset Mapping memory for absolute memory access failed.\n");
		return;
	}

	REG_WRITE(dma_base_address, MM2S_DMACR,  0x04);
	printf("MM2S_DMACR = %x\n", REG_READ(dma_base_address, MM2S_DMACR));
	munmap((void *)dma_base_address, map_len);
	close(fd);	
}

//Reset AXI DMA S2MM
void DMA_S2MM_Reset()
{
	int map_len = 0x60;
	int fd = open("/dev/mem", O_RDWR);

	unsigned char *dma_base_address;
	dma_base_address = (unsigned char *)mmap(NULL, map_len, PROT_READ | PROT_WRITE, MAP_SHARED, fd, (off_t)AXIDMA_S2MM_BASEADDR);
	if(dma_base_address == MAP_FAILED)
	{
		perror("DMA Reset Mapping memory for absolute memory access failed.\n");
		return;
	}

	REG_WRITE(dma_base_address, S2MM_DMACR , 0x04);
	printf("S2MM_DMACR = %x\n", REG_READ(dma_base_address, S2MM_DMACR));

	munmap((void *)dma_base_address, map_len);
	close(fd);
}


//Init AXI DMA MM2S (Simple Mode)
void DMA_MM2S_Init(unsigned int mm2s_sa_addr)
{
	int map_len = 0x60;
	int fd = open("/dev/mem", O_RDWR);

	unsigned char *dma_base_address;
	dma_base_address = (unsigned char *)mmap(NULL, map_len, PROT_READ | PROT_WRITE, MAP_SHARED, fd, (off_t)AXIDMA_MM2S_BASEADDR);
	if(dma_base_address == MAP_FAILED)
	{
		perror("DMA Reset Mapping memory for absolute memory access failed.\n");
		return;
	}

	REG_WRITE(dma_base_address, MM2S_DMACR,  0x5001);
	REG_WRITE(dma_base_address, MM2S_SA,  mm2s_sa_addr);
	

	printf("MM2S_DMACR = %x\n", REG_READ(dma_base_address, MM2S_DMACR));
	printf("MM2S_SA = %x\n", REG_READ(dma_base_address, MM2S_SA));

	munmap((void *)dma_base_address, map_len);
	close(fd);
}


//Init AXI DMA S2MM  (Simple Mode)
void DMA_S2MM_Init(unsigned int s2mm_da_addr)
{
	int map_len = 0x60;
	int fd = open("/dev/mem", O_RDWR);

	unsigned char *dma_base_address;
	dma_base_address = (unsigned char *)mmap(NULL, map_len, PROT_READ | PROT_WRITE, MAP_SHARED, fd, (off_t)AXIDMA_S2MM_BASEADDR);
	if(dma_base_address == MAP_FAILED)
	{
		perror("DMA Reset Mapping memory for absolute memory access failed.\n");
		return;
	}

	REG_WRITE(dma_base_address, S2MM_DMACR , 0x5001);

	REG_WRITE(dma_base_address, S2MM_DA , s2mm_da_addr);

	printf("S2MM_DMACR = %x\n", REG_READ(dma_base_address, S2MM_DMACR));

	printf("S2MM_DA = %x\n", REG_READ(dma_base_address, S2MM_DA));

	munmap((void *)dma_base_address, map_len);
	close(fd);
}

//Start AXI DMA MM2S (Simple Mode)
void DMA_MM2S_Start(unsigned int mm2s_len)
{
	int map_len = 0x60;
	int fd = open("/dev/mem", O_RDWR);

	unsigned char *dma_base_address;
	dma_base_address = (unsigned char *)mmap(NULL, map_len, PROT_READ | PROT_WRITE, MAP_SHARED, fd, (off_t)AXIDMA_MM2S_BASEADDR);
	if(dma_base_address == MAP_FAILED)
	{
		perror("DMA Reset Mapping memory for absolute memory access failed.\n");
		return;
	}

	REG_WRITE(dma_base_address, MM2S_LENGTH,  mm2s_len);

	printf("MM2S_LENGTH = %x\n", REG_READ(dma_base_address, MM2S_LENGTH));

	munmap((void *)dma_base_address, map_len);
	close(fd);
}

//Start AXI DMA S2MM (Simple Mode)
void DMA_S2MM_Start(unsigned int s2mm_len)
{
	int map_len = 0x60;
	int fd = open("/dev/mem", O_RDWR);

	unsigned char *dma_base_address;
	dma_base_address = (unsigned char *)mmap(NULL, map_len, PROT_READ | PROT_WRITE, MAP_SHARED, fd, (off_t)AXIDMA_S2MM_BASEADDR);
	if(dma_base_address == MAP_FAILED)
	{
		perror("DMA Reset Mapping memory for absolute memory access failed.\n");
		return;
	}

	REG_WRITE(dma_base_address, S2MM_LENGTH , s2mm_len);

	printf("S2MM_LENGTH = %x\n", REG_READ(dma_base_address, S2MM_LENGTH));

	munmap((void *)dma_base_address, map_len);
	close(fd);
}


//AXI DMA Control Bus MM2S Channel Wait (Simple Mode)
void DMA_MM2S_Wait()
{
	int map_len = 0x60;
	int fd = open("/dev/mem", O_RDWR);

	unsigned char *dma_base_address;
	dma_base_address = (unsigned char *)mmap(NULL, map_len, PROT_READ | PROT_WRITE, MAP_SHARED, fd, (off_t)AXIDMA_MM2S_BASEADDR);
	if(dma_base_address == MAP_FAILED)
	{
		perror("DMA Reset Mapping memory for absolute memory access failed.\n");
		return;
	}
	while(!(REG_READ(dma_base_address, MM2S_DMASR)&0x1000));

	munmap((void *)dma_base_address, map_len);
	close(fd);
}

//AXI DMA Control Bus S2MM Channel Wait (Simple Mode)
void DMA_S2MM_Wait()
{
	int map_len = 0x60;
	int fd = open("/dev/mem", O_RDWR);

	unsigned char *dma_base_address;
	dma_base_address = (unsigned char *)mmap(NULL, map_len, PROT_READ | PROT_WRITE, MAP_SHARED, fd, (off_t)AXIDMA_S2MM_BASEADDR);
	if(dma_base_address == MAP_FAILED)
	{
		perror("DMA Reset Mapping memory for absolute memory access failed.\n");
		return;
	}
	while(!(REG_READ(dma_base_address, S2MM_DMASR)&0x1000));

	munmap((void *)dma_base_address, map_len);
	close(fd);
}

3、測試程序可以參考:https://blog.csdn.net/weixin_40604731/article/details/92700634
或者自己寫一下吧 balabala

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章