使用多路DMA进行数据传输

DMA的设置

FIFO的设置,第二页默认

这里特别注意,fifo的复位一定要来自DMA的复位out,这个示例里使用全局复位影响不大,但其他有些情况下会带来问题

DMA读时钟100MHz

FIFO写时钟250MHz,模拟高速ADC数据产生

同样的的情况,模拟四路数据传输,模拟多通道情况。MMCM IP核的locked作为generate rtl数据产生模块的复位信号

MMCM设置,输入100Mhz,输出250MHz。未展示部分默认

使用xlconcat和intc形成多级中断

使用AXI GPIO产生开始信号,data_generate模块里对开始信号做处理,以便形成完整的数据传输

点击查看代码
reg     GPIO_start_flag_delay;
wire    start_flag;

assign start_flag = ((GPIO_start_flag)&&(!GPIO_start_flag_delay));

always @(posedge M_AXIS_ACLK) begin
    if (!M_AXIS_ARESETN) begin
        GPIO_start_flag_delay <= 1'd0;
    end else begin
        GPIO_start_flag_delay <= GPIO_start_flag;
    end
end

reg wr_en;

always @(posedge M_AXIS_ACLK) begin
    if (!M_AXIS_ARESETN) begin
        wr_en <= 1'd0;
    end else    if (start_flag) begin
        wr_en <= 1'd1;
    end else    if (tx_done) begin
        wr_en <= 1'd0;
    end
end

	//tvalid generation
	//axis_tvalid is asserted when the control state machine's state is SEND_STREAM and
	//number of output streaming data is less than the NUMBER_OF_OUTPUT_WORDS.
	assign axis_tvalid = ((wr_en)&&(mst_exec_state == SEND_STREAM) && (read_pointer < NUMBER_OF_OUTPUT_WORDS));
	                                                                                               
	// AXI tlast generation                                                                        
	// axis_tlast is asserted number of output streaming data is NUMBER_OF_OUTPUT_WORDS-1          
	// (0 to NUMBER_OF_OUTPUT_WORDS-1)                                                             
	assign axis_tlast = ((read_pointer == NUMBER_OF_OUTPUT_WORDS-1)&&(tx_en));  

0号ila用来观察PS对dma的axi-lite通信

1号ila用来观察DMA对fifo的读取情况

2号ila用来观察DMA对数据的传输情况

最后是地址分配

综合,实现,生成bit流,导出硬件文件,进入vitis
创建工程后,进入bsp,如下所示,dma驱动 intc驱动,gpio驱动都在

编写代码后(代码在最后面),进入调试界面,下面是某一次dma接收之后的情况,18007FF0这个地址这行是上一次接收的末尾,红色这次接收的开始,正好是1-0x1000,共计4096个数,main函数里运行了三次传输,均为正确,第四次是错误传输的示例,表明开始信号是上升沿

DMA传输错误情况下不会产生DMA中断

下面是PL端ila的信号,感兴趣的可以自己设置触发条件查看通信情况,这里不再细说,毕竟功能上已经实现了。

最后是vitis的代码

点击查看代码
globals.h
#ifndef GLOBALS_H
#define GLOBALS_H

#include "xparameters.h"
#include "xil_printf.h"
#include "xil_cache.h"
#include "xaxidma.h"
#include "xgpio.h"
#include "xscugic.h"
#include "xintc.h"
#include "xil_io.h"

#define DDR_BASE_ADDR XPAR_PSU_DDR_0_S_AXI_BASEADDR //0x00000000    DDR基地址
#define AXI_DMA_0_ADDR  DDR_BASE_ADDR               //0x0000_0000-0x07FF_FFFF
#define AXI_DMA_1_ADDR (DDR_BASE_ADDR + 0x08000000) //0x0800_0000-0x0FFF_FFFF
#define AXI_DMA_2_ADDR (DDR_BASE_ADDR + 0x10000000) //0x1000_0000-0x17FF_FFFF
#define AXI_DMA_3_ADDR (DDR_BASE_ADDR + 0x18000000) //0x1800_0000-0x1FFF_FFFF

#define ONE_PKT_LENGTH  0x8000  //单次接收包长度

#define NUMBER_RECEIVE  0x1000  //总接收次数

typedef struct {
    u8  DMA_ID;
    XAxiDma *dma_inst;
    u8 *base_addr;
    u8 *current_addr;
    u16 transfer_count;
    u32 len;
    volatile int transfer_end_flag;
    unsigned int rx_intr_ID;
} DmaChannel;

DmaChannel dma_channels[4];

typedef struct {
    XIntc *intc;      // INTC控制器实例
    DmaChannel *dma_channels;     // DMA实例
} IntrContext;

IntrContext intrcontext[4];

// 全局变量
XAxiDma axi_dma_0;                         //AXI_DMA_0 实例
XAxiDma axi_dma_1;                         //AXI_DMA_1 实例
XAxiDma axi_dma_2;                         //AXI_DMA_2 实例
XAxiDma axi_dma_3;                         //AXI_DMA_3 实例

XGpio Gpio; 

XScuGic intc;                              // 中断控制器
XIntc InterruptController;                 //* Instance of the Interrupt Controller */                          

int status;

// 状态标志
volatile int dma_transfer_start_flag;       // DMA传输启动标志            

#endif // GLOBALS_H
点击查看代码
my_init.h
#ifndef MY_INIT_H
#define MY_INIT_H

#include "globals.h"

#define DMA_0_DEV_ID            XPAR_AXIDMA_0_DEVICE_ID     //AXI_DMA_0-4的器件 ID
#define DMA_1_DEV_ID            XPAR_AXIDMA_1_DEVICE_ID
#define DMA_2_DEV_ID            XPAR_AXIDMA_2_DEVICE_ID
#define DMA_3_DEV_ID            XPAR_AXIDMA_3_DEVICE_ID

#define GPIO_EXAMPLE_DEVICE_ID  XPAR_GPIO_0_DEVICE_ID

#define DMA_0_RX_INTR_ID        XPAR_INTC_0_AXIDMA_0_VEC_ID
#define DMA_1_RX_INTR_ID        XPAR_INTC_0_AXIDMA_1_VEC_ID
#define DMA_2_RX_INTR_ID        XPAR_INTC_0_AXIDMA_2_VEC_ID
#define DMA_3_RX_INTR_ID        XPAR_INTC_0_AXIDMA_3_VEC_ID

/************************** Function Prototypes ******************************/
int	dma_init_for_four_adc_dma(XAxiDma *axi_dma_0, XAxiDma *axi_dma_1, XAxiDma *axi_dma_2, XAxiDma *axi_dma_3,
    DmaChannel *dma_channels_0,  DmaChannel *dma_channels_1,  DmaChannel *dma_channels_2,  DmaChannel *dma_channels_3);
int GPIO_init(XGpio *Gpio);
#endif // MY_INIT_H
点击查看代码
my_init.c
#include "my_init.h"
int	dma_init_for_four_adc_dma(XAxiDma *axi_dma_0, XAxiDma *axi_dma_1, XAxiDma *axi_dma_2, XAxiDma *axi_dma_3,
     DmaChannel *dma_channels_0,  DmaChannel *dma_channels_1,  DmaChannel *dma_channels_2,  DmaChannel *dma_channels_3);
	static int dma_init(XAxiDma *axi_dma, u32 DMA_DEV_ID) ;

int	dma_init_for_four_adc_dma(XAxiDma *axi_dma_0, XAxiDma *axi_dma_1, XAxiDma *axi_dma_2, XAxiDma *axi_dma_3, 
    DmaChannel *dma_channels_0,  DmaChannel *dma_channels_1,  DmaChannel *dma_channels_2,  DmaChannel *dma_channels_3){
	// DMA初始化
	dma_init(axi_dma_0, DMA_0_DEV_ID);
	dma_init(axi_dma_1, DMA_1_DEV_ID);
	dma_init(axi_dma_2, DMA_2_DEV_ID);
	dma_init(axi_dma_3, DMA_3_DEV_ID);
    *dma_channels_0 = (DmaChannel){0, axi_dma_0, (u8 *)AXI_DMA_0_ADDR, (u8 *)AXI_DMA_0_ADDR, 0, ONE_PKT_LENGTH, 0, DMA_0_RX_INTR_ID};
	*dma_channels_1 = (DmaChannel){1, axi_dma_1, (u8 *)AXI_DMA_1_ADDR, (u8 *)AXI_DMA_1_ADDR, 0, ONE_PKT_LENGTH, 0, DMA_1_RX_INTR_ID};
	*dma_channels_2 = (DmaChannel){2, axi_dma_2, (u8 *)AXI_DMA_2_ADDR, (u8 *)AXI_DMA_2_ADDR, 0, ONE_PKT_LENGTH, 0, DMA_2_RX_INTR_ID};
	*dma_channels_3 = (DmaChannel){3, axi_dma_3, (u8 *)AXI_DMA_3_ADDR, (u8 *)AXI_DMA_3_ADDR, 0, ONE_PKT_LENGTH, 0, DMA_3_RX_INTR_ID};

    return XST_SUCCESS;
}

static int dma_init(XAxiDma *axi_dma, u32 DMA_DEV_ID) {
    static XAxiDma_Config *config;
    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(axi_dma, config);
    if (status != XST_SUCCESS) {
        xil_printf("Initialization failed %d\r\n", status);
        return XST_FAILURE;
    }
    if (XAxiDma_HasSg(axi_dma)) {
        xil_printf("Device configured as SG mode\r\n");
        return XST_FAILURE;
    }
    return XST_SUCCESS;
}


int GPIO_init(XGpio *Gpio){
    	/* Initialize the GPIO driver */
    int Status;
	Status = XGpio_Initialize(Gpio, GPIO_EXAMPLE_DEVICE_ID);
	if (Status != XST_SUCCESS) {
		xil_printf("Gpio Initialization Failed\r\n");
		return XST_FAILURE;
	}
	XGpio_SetDataDirection(Gpio, 1, 0);
    return XST_SUCCESS;
}
点击查看代码
my_intr.h
#ifndef MY_INTR_H
#define MY_INTR_H

#include "globals.h"

#define INTC_DEVICE_ID		        XPAR_SCUGIC_SINGLE_DEVICE_ID    //SCUGIC的器件 ID 

#define INTC_Controller_DEVICE_ID   XPAR_INTC_0_DEVICE_ID           //INTC Controller的设备ID
#define INTC_Controller_INTR_ID     XPAR_FABRIC_INTC_0_VEC_ID

#define RESET_TIMEOUT_COUNTER 10000 //复位时间

#define INTR_PRIORITY     0xA0
#define TRIGGER_TYPE      0x3



/************************** Function Prototypes ******************************/
int my_setup_XScuGic_init(XScuGic *xscugic_inst);
int	my_Interrupt_Controller_init(XIntc *Interrupt_Controller, IntrContext *intrcontext_0, IntrContext *intrcontext_1, IntrContext *intrcontext_2, IntrContext *intrcontext_3,
    DmaChannel *dma_channels_0,  DmaChannel *dma_channels_1,  DmaChannel *dma_channels_2,  DmaChannel *dma_channels_3);
int	my_Exception_start(void);
int setup_interrupts(XScuGic *intc, XIntc *InterruptController);
int platform_enable_interrupts(XScuGic *intc, XIntc *InterruptController, DmaChannel *dma_channels_0,  DmaChannel *dma_channels_1,  DmaChannel *dma_channels_2,  DmaChannel *dma_channels_3);
int platform_disable_interrupts(XIntc *InterruptController, DmaChannel *dma_channels_0,  DmaChannel *dma_channels_1,  DmaChannel *dma_channels_2,  DmaChannel *dma_channels_3);


#endif // MY_INTR_H
点击查看代码
my_intr.c
#include "my_intr.h"
int my_setup_XScuGic_init(XScuGic *xscugic_inst);
int	my_Interrupt_Controller_init(XIntc *Interrupt_Controller, IntrContext *intrcontext_0, IntrContext *intrcontext_1, IntrContext *intrcontext_2, IntrContext *intrcontext_3,
    DmaChannel *dma_channels_0,  DmaChannel *dma_channels_1,  DmaChannel *dma_channels_2,  DmaChannel *dma_channels_3);
int	my_Exception_start(void);
int setup_interrupts(XScuGic *intc, XIntc *InterruptController);
    static void dma_rx_intr_handler(void *callback);
        static void handle_dma_error(XAxiDma *axi_dma);
int platform_enable_interrupts(XScuGic *intc, XIntc *InterruptController, DmaChannel *dma_channels_0,  DmaChannel *dma_channels_1,  DmaChannel *dma_channels_2,  DmaChannel *dma_channels_3);
int platform_disable_interrupts(XIntc *InterruptController, DmaChannel *dma_channels_0,  DmaChannel *dma_channels_1,  DmaChannel *dma_channels_2,  DmaChannel *dma_channels_3);

int my_setup_XScuGic_init(XScuGic *xscugic_inst){
    static XScuGic_Config *IntcConfig;
    IntcConfig = XScuGic_LookupConfig(INTC_DEVICE_ID);
    status = XScuGic_CfgInitialize(xscugic_inst, IntcConfig, IntcConfig -> CpuBaseAddress);
	if (status != XST_SUCCESS) {
        xil_printf("XScuGic_init failed %d\r\n", status);
        return XST_FAILURE;
    }
	return XST_SUCCESS;
}

int	my_Interrupt_Controller_init(XIntc *Interrupt_Controller, IntrContext *intrcontext_0, IntrContext *intrcontext_1, IntrContext *intrcontext_2, IntrContext *intrcontext_3,
                     DmaChannel *dma_channels_0,  DmaChannel *dma_channels_1,  DmaChannel *dma_channels_2,  DmaChannel *dma_channels_3){
	status = XIntc_Initialize(Interrupt_Controller, INTC_Controller_DEVICE_ID);
    *intrcontext_0 = (IntrContext){Interrupt_Controller, dma_channels_0};
	*intrcontext_1 = (IntrContext){Interrupt_Controller, dma_channels_1};
	*intrcontext_2 = (IntrContext){Interrupt_Controller, dma_channels_2};
	*intrcontext_3 = (IntrContext){Interrupt_Controller, dma_channels_3};
	if (status != XST_SUCCESS) {
		return XST_FAILURE;
	}
	return XST_SUCCESS;
}

int	my_Exception_start(void){
	Xil_ExceptionInit();
    Xil_ExceptionRegisterHandler(XIL_EXCEPTION_ID_INT, (Xil_ExceptionHandler)XScuGic_InterruptHandler, &intc);
    Xil_ExceptionEnable();
    return XST_SUCCESS;
}

// 建立中断系统

int setup_interrupts(XScuGic *intc, XIntc *InterruptController) {
    status = XScuGic_Connect(intc,INTC_Controller_INTR_ID, (Xil_ExceptionHandler)XIntc_InterruptHandler, InterruptController);
    if (status != XST_SUCCESS) {
        xil_printf("Failed to connect GIC_InterruptHandler\r\n");
        return XST_FAILURE;
    }
    //设置INTC中断控制器的优先级
    XScuGic_SetPriorityTriggerType(intc,INTC_Controller_INTR_ID,0xA0,0x03);
    // 注册中断服务程序(示例:4个DMA中断)
    status = XIntc_Connect(InterruptController, dma_channels[0].rx_intr_ID, (XInterruptHandler)dma_rx_intr_handler, &intrcontext[0]);
    if (status != XST_SUCCESS) {
        xil_printf("Failed to connect dma_0_rx_intr_handler\r\n");
        return XST_FAILURE;
    }
    status = XIntc_Connect(InterruptController, dma_channels[1].rx_intr_ID, (XInterruptHandler)dma_rx_intr_handler, &intrcontext[1]);
    if (status != XST_SUCCESS) {
        xil_printf("Failed to connect dma_1_rx_intr_handler\r\n");
        return XST_FAILURE;
    }
    status = XIntc_Connect(InterruptController, dma_channels[2].rx_intr_ID, (XInterruptHandler)dma_rx_intr_handler, &intrcontext[2]);
    if (status != XST_SUCCESS) {
        xil_printf("Failed to connect dma_2_rx_intr_handler\r\n");
        return XST_FAILURE;
    }
    status = XIntc_Connect(InterruptController, dma_channels[3].rx_intr_ID, (XInterruptHandler)dma_rx_intr_handler, &intrcontext[3]);
    if (status != XST_SUCCESS) {
        xil_printf("Failed to connect dma_3_rx_intr_handler\r\n");
        return XST_FAILURE;
    }
    return XST_SUCCESS;
}

// 中断处理函数
static void dma_rx_intr_handler(void *callback) {
    IntrContext *ctx = (IntrContext *)callback;
    XIntc *intc = ctx->intc;
    DmaChannel *dma_channels = ctx->dma_channels;
    XAxiDma *axi_dma = dma_channels->dma_inst;
    u32 irq_status = XAxiDma_IntrGetIrq(axi_dma, XAXIDMA_DEVICE_TO_DMA);
    XAxiDma_IntrAckIrq(axi_dma, irq_status, XAXIDMA_DEVICE_TO_DMA);
    //xil_printf("irq_status_0 is: 0x%08X\n", irq_status);
	if (!(irq_status  & XAXIDMA_IRQ_ALL_MASK)) {
		return;
	}
    if (irq_status & XAXIDMA_IRQ_ERROR_MASK) {
        handle_dma_error(axi_dma);
    }
    if (irq_status & XAXIDMA_IRQ_IOC_MASK) {
        dma_channels->transfer_count++;
        dma_channels->current_addr += dma_channels->len;
        xil_printf("dma_0_rx_done_cnt is: %d\n", dma_channels->transfer_count);
        dma_channels->transfer_end_flag   =   1;   
    }
    XIntc_Acknowledge(intc, dma_channels->rx_intr_ID);
}
static void handle_dma_error(XAxiDma *axi_dma) {
    XAxiDma_Reset(axi_dma);
    
    int timeout = RESET_TIMEOUT_COUNTER;
    while (timeout) {
        if(XAxiDma_ResetIsDone(axi_dma)) {
            break;
        }
        timeout -= 1;
    }
    if (!timeout) {
    }
}

int platform_enable_interrupts(XScuGic *intc, XIntc *InterruptController, 
                                    DmaChannel *dma_channels_0,  DmaChannel *dma_channels_1,  DmaChannel *dma_channels_2,  DmaChannel *dma_channels_3){
	/* Start the interrupt controller */
	status = XIntc_Start(InterruptController, XIN_REAL_MODE);
	if (status != XST_SUCCESS) {
		xil_printf("Failed to start intc\r\n");
		return XST_FAILURE;
	}
    XScuGic_Enable(intc, INTC_Controller_INTR_ID); //使能 GIC 中的 INTC 中断
    XIntc_Enable(InterruptController, dma_channels_0->rx_intr_ID);
    XIntc_Enable(InterruptController, dma_channels_1->rx_intr_ID);
    XIntc_Enable(InterruptController, dma_channels_2->rx_intr_ID);
    XIntc_Enable(InterruptController, dma_channels_3->rx_intr_ID);

    XAxiDma_IntrDisable(dma_channels_0->dma_inst, XAXIDMA_IRQ_ALL_MASK, XAXIDMA_DMA_TO_DEVICE);
    XAxiDma_IntrDisable(dma_channels_1->dma_inst, XAXIDMA_IRQ_ALL_MASK, XAXIDMA_DMA_TO_DEVICE);
    XAxiDma_IntrDisable(dma_channels_2->dma_inst, XAXIDMA_IRQ_ALL_MASK, XAXIDMA_DMA_TO_DEVICE);
    XAxiDma_IntrDisable(dma_channels_3->dma_inst, XAXIDMA_IRQ_ALL_MASK, XAXIDMA_DMA_TO_DEVICE);

    XAxiDma_IntrDisable(dma_channels_0->dma_inst, XAXIDMA_IRQ_ALL_MASK, XAXIDMA_DEVICE_TO_DMA);
    XAxiDma_IntrDisable(dma_channels_1->dma_inst, XAXIDMA_IRQ_ALL_MASK, XAXIDMA_DEVICE_TO_DMA);
    XAxiDma_IntrDisable(dma_channels_2->dma_inst, XAXIDMA_IRQ_ALL_MASK, XAXIDMA_DEVICE_TO_DMA);
    XAxiDma_IntrDisable(dma_channels_3->dma_inst, XAXIDMA_IRQ_ALL_MASK, XAXIDMA_DEVICE_TO_DMA);

    //XAxiDma_IntrEnable(&axi_dma, XAXIDMA_IRQ_ALL_MASK, XAXIDMA_DMA_TO_DEVICE);
    XAxiDma_IntrEnable(dma_channels_0->dma_inst, XAXIDMA_IRQ_ALL_MASK, XAXIDMA_DEVICE_TO_DMA);
    XAxiDma_IntrEnable(dma_channels_1->dma_inst, XAXIDMA_IRQ_ALL_MASK, XAXIDMA_DEVICE_TO_DMA);
    XAxiDma_IntrEnable(dma_channels_2->dma_inst, XAXIDMA_IRQ_ALL_MASK, XAXIDMA_DEVICE_TO_DMA);
    XAxiDma_IntrEnable(dma_channels_3->dma_inst, XAXIDMA_IRQ_ALL_MASK, XAXIDMA_DEVICE_TO_DMA);

    /* Enable interrupts from the hardware */

    return XST_SUCCESS;
}

int platform_disable_interrupts(XIntc *InterruptController, DmaChannel *dma_channels_0,  DmaChannel *dma_channels_1,  DmaChannel *dma_channels_2,  DmaChannel *dma_channels_3) {
    // 先禁用DMA中断
    XAxiDma_IntrDisable(dma_channels_0->dma_inst, XAXIDMA_IRQ_ALL_MASK, XAXIDMA_DEVICE_TO_DMA);
    XAxiDma_IntrDisable(dma_channels_1->dma_inst, XAXIDMA_IRQ_ALL_MASK, XAXIDMA_DEVICE_TO_DMA);
    XAxiDma_IntrDisable(dma_channels_2->dma_inst, XAXIDMA_IRQ_ALL_MASK, XAXIDMA_DEVICE_TO_DMA);
    XAxiDma_IntrDisable(dma_channels_3->dma_inst, XAXIDMA_IRQ_ALL_MASK, XAXIDMA_DEVICE_TO_DMA);

	XIntc_Disconnect(InterruptController, dma_channels_0->rx_intr_ID);
    XIntc_Disconnect(InterruptController, dma_channels_1->rx_intr_ID);
    XIntc_Disconnect(InterruptController, dma_channels_2->rx_intr_ID);
    XIntc_Disconnect(InterruptController, dma_channels_3->rx_intr_ID);

    //XAxiDma_IntrDisable(&axi_dma, XAXIDMA_IRQ_ALL_MASK, XAXIDMA_DMA_TO_DEVICE);
    //XAxiDma_IntrDisable(&axi_dma, XAXIDMA_IRQ_ALL_MASK, XAXIDMA_DEVICE_TO_DMA);
    //XScuGic_Disconnect(&intc, DMA_TX_INTR_ID);
    //XScuGic_Disconnect(&intc, DMA_RX_INTR_ID);
    //XScuGic_Disable(&intc, DMA_TX_INTR_ID);
    //XScuGic_Disable(&intc, DMA_RX_INTR_ID);
    return XST_SUCCESS;
}

点击查看代码
my_code.h
#ifndef MY_CODE_H
#define MY_CODE_H
#include "globals.h"

/************************** Function Prototypes ******************************/

int dma_receive_for_four_adc_data();
#endif // MY_CODE_H
点击查看代码
my_code.c
#include "my_code.h"
int dma_receive_for_four_adc_data();

int dma_receive_for_four_adc_data(){
    // 启动初始传输
    for(int i = 0; i < 4; i++) {
        xil_printf("XAxiDma_SimpleTransfer at address %08X and length %d\n", dma_channels[i].current_addr, dma_channels[i].len);
        status = XAxiDma_SimpleTransfer(dma_channels[i].dma_inst, (UINTPTR)dma_channels[i].current_addr, dma_channels[i].len, XAXIDMA_DEVICE_TO_DMA);
        if(status != XST_SUCCESS) {
            xil_printf("XAxiDma_SimpleTransfer %d failed at 0x%08X \n", i ,status);
            return XST_FAILURE;
        }
        Xil_DCacheFlushRange((UINTPTR)dma_channels[i].current_addr, dma_channels[i].len);
        //dma_channels[i].transfer_count++;
        //dma_channels[i].current_addr += 256;
        //xil_printf("XAxiDma_SimpleTransfer %d start \n", i);
    }
    return XST_SUCCESS;
}
点击查看代码
main.c
#include "my_init.h"
#include "my_intr.h"
#include "my_code.h"
#include "globals.h"

int main( ){

    Xil_ICacheEnable();
    Xil_DCacheEnable();
    xil_printf("\r\n--- Entering main() --- \r\n");

// 1.4个DMA以及GPIO初始化
    dma_init_for_four_adc_dma(&axi_dma_0, &axi_dma_1, &axi_dma_2, &axi_dma_3,&dma_channels[0], &dma_channels[1],&dma_channels[2],&dma_channels[3]);
    GPIO_init(&Gpio);
// 2.初始化 XScuGIC、Interrupt_Controller、注册异常以及建立中断系统
    my_setup_XScuGic_init(&intc);
    my_Interrupt_Controller_init(&InterruptController, &intrcontext[0], &intrcontext[1], &intrcontext[2], &intrcontext[3],
                                        &dma_channels[0], &dma_channels[1], &dma_channels[2], &dma_channels[3]);
    my_Exception_start();
    setup_interrupts(&intc, &InterruptController);
// 3.开启其他中断
    platform_enable_interrupts(&intc, &InterruptController, &dma_channels[0], &dma_channels[1], &dma_channels[2], &dma_channels[3]);
    xil_printf("\r\n--- start first --- \r\n");
    XGpio_DiscreteWrite(&Gpio, 1, 0x1);
    xil_printf("\r\n--- fifo is ok --- \r\n");
    dma_receive_for_four_adc_data();
    xil_printf("\r\n--- dma_receive is ok --- \r\n");
    XGpio_DiscreteWrite(&Gpio, 1, 0x0);
    xil_printf("\r\n--- start secend --- \r\n");
    XGpio_DiscreteWrite(&Gpio, 1, 0x1);
    xil_printf("\r\n--- fifo is ok --- \r\n");
    dma_receive_for_four_adc_data();
    xil_printf("\r\n--- dma_receive is ok --- \r\n");
    XGpio_DiscreteWrite(&Gpio, 1, 0x0);
    xil_printf("\r\n--- start third --- \r\n");
    XGpio_DiscreteWrite(&Gpio, 1, 0x1);
    xil_printf("\r\n--- fifo is ok --- \r\n");
    dma_receive_for_four_adc_data();
    xil_printf("\r\n--- dma_receive is ok --- \r\n");

    xil_printf("\r\n--- start fourth for error --- \r\n");
    XGpio_DiscreteWrite(&Gpio, 1, 0x1);
    xil_printf("\r\n--- fifo is ok --- \r\n");
    dma_receive_for_four_adc_data();
    xil_printf("\r\n--- dma_receive is ok --- \r\n");


//开始循环
    return XST_SUCCESS;
}

点击查看代码
`timescale 1ns / 1ps
//////////////////////////////////////////////////////////////////////////////////
// Company: 
// Engineer: 
// 
// Create Date: 2025/04/04 18:45:06
// Design Name: 
// Module Name: data_generate
// Project Name: 
// Target Devices: 
// Tool Versions: 
// Description: 
// 
// Dependencies: 
// 
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
// 
//////////////////////////////////////////////////////////////////////////////////



`timescale 1 ns / 1 ps

	module data_generate #(
		// Users to add parameters here

		// User parameters ends
		// Do not modify the parameters beyond this line

		// Width of S_AXIS address bus. The slave accepts the read and write addresses of width C_M_AXIS_TDATA_WIDTH.
		parameter integer C_M_AXIS_TDATA_WIDTH	= 64,
		// Start count is the number of clock cycles the master will wait before initiating/issuing any transaction.
		parameter integer C_M_START_COUNT	= 32
	)
	(
		// Users to add ports here
        input wire  GPIO_start_flag,
		// User ports ends
		// Do not modify the ports beyond this line

		// Global ports
		input wire  M_AXIS_ACLK,
		// 
		input wire  M_AXIS_ARESETN,
		// Master Stream Ports. TVALID indicates that the master is driving a valid transfer, A transfer takes place when both TVALID and TREADY are asserted. 
		output wire  M_AXIS_TVALID,
		// TDATA is the primary payload that is used to provide the data that is passing across the interface from the master.
		output wire [C_M_AXIS_TDATA_WIDTH-1 : 0] M_AXIS_TDATA,
		// TSTRB is the byte qualifier that indicates whether the content of the associated byte of TDATA is processed as a data byte or a position byte.
		output wire [(C_M_AXIS_TDATA_WIDTH/8)-1 : 0] M_AXIS_TSTRB,
		// TLAST indicates the boundary of a packet.
		output wire  M_AXIS_TLAST,
		// TREADY indicates that the slave can accept a transfer in the current cycle.
		input wire  M_AXIS_TREADY
	);
	// Total number of output data                                                 
	localparam NUMBER_OF_OUTPUT_WORDS = 4096;                                               
	                                                                                     
	// function called clogb2 that returns an integer which has the                      
	// value of the ceiling of the log base 2.                                           
	function integer clogb2 (input integer bit_depth);                                   
	  begin                                                                              
	    for(clogb2=0; bit_depth>0; clogb2=clogb2+1)                                      
	      bit_depth = bit_depth >> 1;                                                    
	  end                                                                                
	endfunction                                                                          
	                                                                                     
	// WAIT_COUNT_BITS is the width of the wait counter.                                 
	localparam integer WAIT_COUNT_BITS = clogb2(C_M_START_COUNT-1);                      
	                                                                                     
	// bit_num gives the minimum number of bits needed to address 'depth' size of FIFO.  
	localparam bit_num  = clogb2(NUMBER_OF_OUTPUT_WORDS);                                
	                                                                                     
	// Define the states of state machine                                                
	// The control state machine oversees the writing of input streaming data to the FIFO,
	// and outputs the streaming data from the FIFO                                      
	localparam [1:0] IDLE = 2'b00,        // This is the initial/idle state               
	                                                                                     
	                INIT_COUNTER  = 2'b01, // This state initializes the counter, once   
	                                // the counter reaches C_M_START_COUNT count,        
	                                // the state machine changes state to SEND_STREAM     
	                SEND_STREAM   = 2'b10; // In this state the                          
	                                     // stream data is output through M_AXIS_TDATA   
	// State variable                                                                    
	reg [1:0] mst_exec_state;                                                            
	// Example design FIFO read pointer                                                  
	reg [bit_num-1:0] read_pointer;                                                      

	// AXI Stream internal signals
	//wait counter. The master waits for the user defined number of clock cycles before initiating a transfer.
	reg [WAIT_COUNT_BITS-1 : 0] 	count;
	//streaming data valid
	wire  	axis_tvalid;
	//streaming data valid delayed by one clock cycle
	reg  	axis_tvalid_delay;
	//Last of the streaming data 
	wire  	axis_tlast;
	//Last of the streaming data delayed by one clock cycle
	reg  	axis_tlast_delay;
	//FIFO implementation signals
	reg [C_M_AXIS_TDATA_WIDTH-1 : 0] 	stream_data_out;
	wire  	tx_en;
	//The master has issued all the streaming data stored in FIFO
	reg  	tx_done;


	// I/O Connections assignments

	assign M_AXIS_TVALID	= axis_tvalid_delay;
	assign M_AXIS_TDATA	= stream_data_out;
	assign M_AXIS_TLAST	= axis_tlast_delay;
	assign M_AXIS_TSTRB	= {(C_M_AXIS_TDATA_WIDTH/8){1'b1}};


	// Control state machine implementation                             
	always @(posedge M_AXIS_ACLK)                                             
	begin                                                                     
	  if (!M_AXIS_ARESETN)                                                    
	  // Synchronous reset (active low)                                       
	    begin                                                                 
	      mst_exec_state <= IDLE;                                             
	      count    <= 0;                                                      
	    end                                                                   
	  else                                                                    
	    case (mst_exec_state)                                                 
	      IDLE:                                                               
	        // The slave starts accepting tdata when                          
	        // there tvalid is asserted to mark the                           
	        // presence of valid streaming data                               
	        //if ( count == 0 )                                                 
	        begin                                                           
	            mst_exec_state  <= INIT_COUNTER;
                count    <= 0;                               
	        end                                                             
	        //else                                                              
	        //  begin                                                           
	        //    mst_exec_state  <= IDLE;                                      
	        //  end                                                             
	                                                                          
	      INIT_COUNTER:                                                       
	        // The slave starts accepting tdata when                          
	        // there tvalid is asserted to mark the                           
	        // presence of valid streaming data                               
	        if ( count == C_M_START_COUNT - 1 )                               
	          begin                                                           
	            mst_exec_state  <= SEND_STREAM;                               
	          end                                                             
	        else                                                              
	          begin                                                           
	            count <= count + 1;                                           
	            mst_exec_state  <= INIT_COUNTER;                              
	          end                                                             
	                                                                          
	      SEND_STREAM:                                                        
	        // The example design streaming master functionality starts       
	        // when the master drives output tdata from the FIFO and the slave
	        // has finished storing the S_AXIS_TDATA                          
	        if (tx_done)                                                      
	          begin                                                           
	            mst_exec_state <= IDLE;                                       
	          end                                                             
	        else                                                              
	          begin                                                           
	            mst_exec_state <= SEND_STREAM;                                
	          end                                                             
	    endcase                                                               
	end                                                                       

reg     GPIO_start_flag_delay;
wire    start_flag;

assign start_flag = ((GPIO_start_flag)&&(!GPIO_start_flag_delay));

always @(posedge M_AXIS_ACLK) begin
    if (!M_AXIS_ARESETN) begin
        GPIO_start_flag_delay <= 1'd0;
    end else begin
        GPIO_start_flag_delay <= GPIO_start_flag;
    end
end

reg wr_en;

always @(posedge M_AXIS_ACLK) begin
    if (!M_AXIS_ARESETN) begin
        wr_en <= 1'd0;
    end else    if (start_flag) begin
        wr_en <= 1'd1;
    end else    if (tx_done) begin
        wr_en <= 1'd0;
    end
end

	//tvalid generation
	//axis_tvalid is asserted when the control state machine's state is SEND_STREAM and
	//number of output streaming data is less than the NUMBER_OF_OUTPUT_WORDS.
	assign axis_tvalid = ((wr_en)&&(mst_exec_state == SEND_STREAM) && (read_pointer < NUMBER_OF_OUTPUT_WORDS));
	                                                                                               
	// AXI tlast generation                                                                        
	// axis_tlast is asserted number of output streaming data is NUMBER_OF_OUTPUT_WORDS-1          
	// (0 to NUMBER_OF_OUTPUT_WORDS-1)                                                             
	assign axis_tlast = ((read_pointer == NUMBER_OF_OUTPUT_WORDS-1)&&(tx_en));                                
	                                                                                               
	                                                                                               
	// Delay the axis_tvalid and axis_tlast signal by one clock cycle                              
	// to match the latency of M_AXIS_TDATA                                                        
	always @(posedge M_AXIS_ACLK)                                                                  
	begin                                                                                          
	  if (!M_AXIS_ARESETN)                                                                         
	    begin                                                                                      
	      axis_tvalid_delay <= 1'b0;                                                               
	      axis_tlast_delay <= 1'b0;                                                                
	    end                                                                                        
	  else                                                                                         
	    begin                                                                                      
	      axis_tvalid_delay <= axis_tvalid;                                                        
	      axis_tlast_delay <= axis_tlast;                                                          
	    end                                                                                        
	end                                                                                            
	//read_pointer pointer

always@(posedge M_AXIS_ACLK)   begin                                                                            
	    if(!M_AXIS_ARESETN)   begin                                                                        
	      read_pointer  <= 0;                                                         
	      tx_done       <= 1'b0;                                                           
	    end else  case (mst_exec_state)
        SEND_STREAM :begin
            if (read_pointer <= NUMBER_OF_OUTPUT_WORDS-1)   begin               
              tx_done <= 1'b0;                                                           
              if (tx_en)                                                               
                // read pointer is incremented after every read from the FIFO          
                // when FIFO read signal is enabled.                                   
                begin                                                                  
                  read_pointer <= read_pointer + 1;                                                                                     
                end                                                                    
            end else    begin                                                                      
              // tx_done is asserted when NUMBER_OF_OUTPUT_WORDS numbers of streaming data
              // has been out.                                                      
              tx_done 	 <= 1'b1;                                                         
            end                        
        end
        default: begin
            read_pointer    <= 0;
            tx_done         <= 1'b0;  
        end
      endcase                                                                           
end 

	//FIFO read enable generation 

	assign tx_en = M_AXIS_TREADY && axis_tvalid;   
	                                                     
	    // Streaming output data is read from FIFO       
	    always @( posedge M_AXIS_ACLK )                  
	    begin                                            
	      if(!M_AXIS_ARESETN)                            
	        begin                                        
	          stream_data_out <= 1;                      
	        end                                          
	      else if (tx_en)// && M_AXIS_TSTRB[byte_index]  
	        begin                                        
	          stream_data_out <= read_pointer + 32'b1;   
	        end                                          
	    end                                              

	// Add user logic here

	// User logic ends

	endmodule