系列文章目录
前言
在上一篇中,我们已经讲述了AXI-Stream(以下简写AXIS)的相关信号和对应的缓冲模块设计;
在本篇中,将给出后续的上板实验过程;
一、环境
本次上板基于Xilinx 的Zynq 7010 FPGA,Digilent 的Zybo Z7板卡,Vivado集成开发环境;采用软硬协同的方式进行逻辑验证;
板卡图片:
二、验证SOC搭建
2.1 系统框图
在设计验证系统时,我们参考正点原子的AXI-DMA实验,只不过将其中的FIFO替换成我们自己编写的AXI-Stream-test模块;
正点原子系统框图: AXIS验证系统框图:
验证需要zynq硬核的参与,PS端的HP内存映射接口与AXI DMA进行数据流的通信,GP接口与AXI DMA进行AXI-Lite通信,DMA将数据流以AXIS协议发送给AXI-Stream-test IP,并将AXI-Stream-test IP处理后的数据通过HP接口写入DDR3;
2.2 IP核打包
若想进行Block Design设计,则需要将AXI_Stream_test逻辑打包成IP;
1.选择Tools->Creat and Package New IP 2.选择Package a specified directory
首先进行File Groups,然后选择Ports and Interfaces,点击+号
选择axis_trl接口,取名M_AXIS,Mode选择master 点击Port Mapping,绑定信号,绑定信息如下:
继续绑定S_AXIS接口;
其端口映射如下:
4.点击Customization GUI,将C_M_Axis_Burst_Len参数托到Page0;
5.点击Review and Package完成IP打包
2.3 SOC系统硬件设计
在Vivado中,SOC的BD设计如下所示:
其中,DMA配置如下:
取消勾选 Enable Scatter Gather Engine 选项;
配置地址位宽为32;
配置数据流数据位宽为32;
其中,AXI_Stream_test IP配置如下:
C_M_Axis_Burst_Len:为8(最大传输为8,每8个数据就拉高一次TLAST信号)
Comb_Len:为4,缓冲4个数据(128bit);
2.4 SOC系统软件设计
先后点击export和Launch SDK;
创建一个新工程;
在新工程中添加一个main.c文件,其中代码如下:
#include "xaxidma.h"
#include "xparameters.h"
#include "xil_exception.h"
#include "xscugic.h"
#include "../user/headfile.h"
/************************** Constant Definitions *****************************/
#define DMA_DEV_ID XPAR_AXIDMA_0_DEVICE_ID
#define RX_INTR_ID XPAR_FABRIC_AXIDMA_0_S2MM_INTROUT_VEC_ID
#define TX_INTR_ID XPAR_FABRIC_AXIDMA_0_MM2S_INTROUT_VEC_ID
#define INTC_DEVICE_ID XPAR_SCUGIC_SINGLE_DEVICE_ID
#define DDR_BASE_ADDR XPAR_PS7_DDR_0_S_AXI_BASEADDR //0x00100000
#define MEM_BASE_ADDR (DDR_BASE_ADDR + 0x1000000) //0x01100000
#define TX_BUFFER_BASE (MEM_BASE_ADDR + 0x00100000) //0x01200000
#define RX_BUFFER_BASE (MEM_BASE_ADDR + 0x00300000) //0x01400000
#define RESET_TIMEOUT_COUNTER 10000
#define TEST_START_VALUE 0x0
#define MAX_PKT_LEN 32
/************************** Function Prototypes ******************************/
static int check_data(int length, u8 start_value);
static void tx_intr_handler(void *callback);
static void rx_intr_handler(void *callback);
static int setup_intr_system(XScuGic * int_ins_ptr, XAxiDma * axidma_ptr,
u16 tx_intr_id, u16 rx_intr_id);
static void disable_intr_system(XScuGic * int_ins_ptr, u16 tx_intr_id,
u16 rx_intr_id);
/************************** Variable Definitions *****************************/
static XAxiDma axidma;
static XScuGic intc;
volatile int tx_done;
volatile int rx_done;
volatile int error;
/************************** Function Definitions *****************************/
int main(void)
{
int i;
int status;
u8 value;
u8 *tx_buffer_ptr;
u8 *rx_buffer_ptr;
XAxiDma_Config *config;
tx_buffer_ptr = (u8 *) TX_BUFFER_BASE;
rx_buffer_ptr = (u8 *) RX_BUFFER_BASE;
xil_printf("\r\n--- Entering main() --- \r\n");
config = XAxiDma_LookupConfig(DMA_DEV_ID);
// if (!config) {
// xil_printf("No config found for %d\r\n", DMA_DEV_ID);
// return XST_FAILURE;
// }
status = XAxiDma_CfgInitialize(&axidma, config);
// if (status != XST_SUCCESS) {
// xil_printf("Initialization failed %d\r\n", status);
// return XST_FAILURE;
// }
//
// if (XAxiDma_HasSg(&axidma)) {
// xil_printf("Device configured as SG mode \r\n");
// return XST_FAILURE;
// }
status = setup_intr_system(&intc, &axidma, TX_INTR_ID, RX_INTR_ID);
// if (status != XST_SUCCESS) {
// xil_printf("Failed intr setup\r\n");
// return XST_FAILURE;
// }
tx_done = 0;
rx_done = 0;
error = 0;
value = TEST_START_VALUE;
for (i = 0; i < MAX_PKT_LEN; i++) {
tx_buffer_ptr[i] = value;
value = (value + 1) & 0xFF;
}
Xil_DCacheFlushRange((UINTPTR) tx_buffer_ptr, MAX_PKT_LEN);
status = XAxiDma_SimpleTransfer(&axidma, (UINTPTR) tx_buffer_ptr,MAX_PKT_LEN, XAXIDMA_DMA_TO_DEVICE);
XAxiDma_SimpleTransfer(&axidma, (UINTPTR) rx_buffer_ptr,MAX_PKT_LEN, XAXIDMA_DEVICE_TO_DMA);
while(1)
{
while(!tx_done);
xil_printf("tx_done\n");
while(!rx_done);
usleep(100000);
xil_printf("Finish!\n");
Xil_DCacheFlushRange((UINTPTR) rx_buffer_ptr, MAX_PKT_LEN);
int i;
xil_printf("RES:");
for(i = 0;i< MAX_PKT_LEN;i++)
{
xil_printf("%x,",rx_buffer_ptr[i]);
}
xil_printf("\n");
sleep(5);
XAxiDma_SimpleTransfer(&axidma, (UINTPTR) tx_buffer_ptr,MAX_PKT_LEN, XAXIDMA_DMA_TO_DEVICE);
XAxiDma_SimpleTransfer(&axidma, (UINTPTR) rx_buffer_ptr,MAX_PKT_LEN, XAXIDMA_DEVICE_TO_DMA);
}
return XST_SUCCESS;
}
static void tx_intr_handler(void *callback)
{
int timeout;
u32 irq_status;
XAxiDma *axidma_inst = (XAxiDma *) callback;
irq_status = XAxiDma_IntrGetIrq(axidma_inst, XAXIDMA_DMA_TO_DEVICE);
XAxiDma_IntrAckIrq(axidma_inst, irq_status, XAXIDMA_DMA_TO_DEVICE);
if ((irq_status & XAXIDMA_IRQ_ERROR_MASK))
{
error = 1;
XAxiDma_Reset(axidma_inst);
timeout = RESET_TIMEOUT_COUNTER;
while (timeout)
{
if (XAxiDma_ResetIsDone(axidma_inst))
break;
timeout -= 1;
}
return;
}
//Tx 完成
if ((irq_status & XAXIDMA_IRQ_IOC_MASK))
tx_done = 1;
}
//DMA RX 中断处理函数
static void rx_intr_handler(void *callback)
{
u32 irq_status;
int timeout;
XAxiDma *axidma_inst = (XAxiDma *) callback;
irq_status = XAxiDma_IntrGetIrq(axidma_inst, XAXIDMA_DEVICE_TO_DMA);
XAxiDma_IntrAckIrq(axidma_inst, irq_status, XAXIDMA_DEVICE_TO_DMA);
//Rx 出错
if ((irq_status & XAXIDMA_IRQ_ERROR_MASK))
{
error = 1;
XAxiDma_Reset(axidma_inst);
timeout = RESET_TIMEOUT_COUNTER;
while (timeout)
{
if (XAxiDma_ResetIsDone(axidma_inst))
break;
timeout -= 1;
}
return;
}
//Rx 完成
if ((irq_status & XAXIDMA_IRQ_IOC_MASK))
rx_done = 1;
}
static int setup_intr_system(XScuGic * int_ins_ptr, XAxiDma * axidma_ptr,
u16 tx_intr_id, u16 rx_intr_id)
{
int status;
XScuGic_Config *intc_config;
//初始化中断控制器驱动
intc_config = XScuGic_LookupConfig(INTC_DEVICE_ID);
if (NULL == intc_config) {
return XST_FAILURE;
}
status = XScuGic_CfgInitialize(int_ins_ptr, intc_config,
intc_config->CpuBaseAddress);
if (status != XST_SUCCESS) {
return XST_FAILURE;
}
//设置优先级和触发类型
XScuGic_SetPriorityTriggerType(int_ins_ptr, tx_intr_id, 0xA0, 0x3);
XScuGic_SetPriorityTriggerType(int_ins_ptr, rx_intr_id, 0xA0, 0x3);
//为中断设置中断处理函数
status = XScuGic_Connect(int_ins_ptr, tx_intr_id,
(Xil_InterruptHandler) tx_intr_handler, axidma_ptr);
if (status != XST_SUCCESS) {
return status;
}
status = XScuGic_Connect(int_ins_ptr, rx_intr_id,
(Xil_InterruptHandler) rx_intr_handler, axidma_ptr);
if (status != XST_SUCCESS) {
return status;
}
XScuGic_Enable(int_ins_ptr, tx_intr_id);
XScuGic_Enable(int_ins_ptr, rx_intr_id);
//启用来自硬件的中断
Xil_ExceptionInit();
Xil_ExceptionRegisterHandler(XIL_EXCEPTION_ID_INT,
(Xil_ExceptionHandler) XScuGic_InterruptHandler,
(void *) int_ins_ptr);
Xil_ExceptionEnable();
//使能 DMA 中断
XAxiDma_IntrEnable(&axidma, XAXIDMA_IRQ_ALL_MASK, XAXIDMA_DMA_TO_DEVICE);
XAxiDma_IntrEnable(&axidma, XAXIDMA_IRQ_ALL_MASK, XAXIDMA_DEVICE_TO_DMA);
return XST_SUCCESS;
}
连接开发板,并打开终端;下载硬件和软件程序,观察终端打印情况;
打印数据为0-31,结果正确;