PL2PS2PL v2.0 数据输入的实现

主要借鉴了米联客的dma传输方案。

纯菜狗,代码和设计中有很多冗余操作,突出一个勉强实现,不会优化,记录一下学习过程,大佬见谅。

Block Design

模块配置和作用分析:

主要根据自己的需要配置。

1.负责输入1k和10k的正弦信号作为测试信号,每1024个64bit数据输出一个last信号2。

2.fifo_in,负责不同时钟域的数据传输,由40M变为120M,每积累1024个数据就进行一次传输。

3.dma负责数据在PS和PL之间的传输。

4.fifo_out,同2,配置稍微改改。

5.音频数据输出,自己写的rtl代码

6.PS端。

7.gpio接口,负责使能1数据输入模块

VITIS代码编写

主要代码借鉴了米联客zynq裸机篇2019版第22章

 主要添加了filter模块进行滤波操作,并对main.c文件进行了部分修改,删去了计时测速功能,filter模块放在下一篇说。

main.c


/*
 *
 * www.osrc.cn
 * copyright by liyang mi lian dian zi www.osrc.cn
 * axi dma test
 *
*/
//mrd -bin -file input.bin 0x10300000 2048


#include "dma_intr.h"
#include "timer_intr.h"
#include "sys_intr.h"
#include "xgpio.h"
#include "filter.h"

extern double filterDirectI_singlejoint(double DataIn, double *a, double *b, double *xDelay,double *yDelay ,int numjoint);
//extern double filterDirectI_multjoint(double DataIn, double **a, double **b, double *xDelay,double *yDelay, int numStages);
//extern double filter_single(const double* x, double* y, int xlen, double* a, double* b, int nfilt);
static XScuGic Intc; //GIC
static  XAxiDma AxiDma;
static  XScuTimer Timer;//timer

volatile u32 RX_ready=1;
volatile u32 TX_ready=1;

int i;
u32 RxBuffer[1024];
u8 *TxBufferPtr= (u8 *)TX_BUFFER_BASE;
u8 *RxBufferPtr=(u8 *)RX_BUFFER_BASE;
u8 *RxBufferPtr2 = (u8 *)RX_BUFFER2_BASE;
u8 *TxBufferPtr2 = (u8 *)TX_BUFFER2_BASE;

//u8 *buffer_temp=(u8 *)BUFFER_TEMP;
u8 Value=0;
double speed_tx;
double speed_rx;
static XGpio Gpio;

#define AXI_GPIO_DEV_ID	        XPAR_AXI_GPIO_0_BASEADDR

int axi_dma_test()
{
	int Status;

	TxDone = 0;
	RxDone = 0;
	Error = 0;
	int cnt;			//计数0-1
	cnt = 0;

	while(1)//无限循环一直传输
	{
		//RX DMA Transfer

		if(RX_ready)
		{
		   RX_ready=0;
		    if(cnt){		//进行乒乓缓存,奇数帧和偶数帧存入不同地址,防止滤波操作延时对缓存数据的影响
			    Status = XAxiDma_SimpleTransfer(&AxiDma,(u32)(RxBufferPtr2),
		 				(u32)(MAX_PKT_LEN), XAXIDMA_DEVICE_TO_DMA);
		    }
		    else
			   Status = XAxiDma_SimpleTransfer(&AxiDma,(u32)(RxBufferPtr),
						(u32)(MAX_PKT_LEN), XAXIDMA_DEVICE_TO_DMA);


		   if (Status != XST_SUCCESS) {return XST_FAILURE;}
		}


		if(RxDone)
		{

//			Xil_DCacheInvalidateRange((u32)RxBufferPtr, MAX_PKT_LEN);
//			xil_printf("Rx1=%ld,Rxn=%ld\r\n",*((u32*)RxBufferPtr),*((u32*)(RxBufferPtr+1023*8)) );



			RxDone=0;
			RX_ready=1;
			if(cnt){
				filter_all((double*) (RxBufferPtr2), (double*) (TxBufferPtr2));


			}
			else{
				filter_all((double*) (RxBufferPtr), (double*) (TxBufferPtr));

			}

		}



		//TX DMA Transfer
		if(TX_ready)
		{
			TX_ready=0;

		   if(cnt){
			   Status = XAxiDma_SimpleTransfer(&AxiDma,(u32)(TxBufferPtr2),
						(u32)(MAX_PKT_LEN), XAXIDMA_DEVICE_TO_DMA);
			   cnt = 0;
		   }
		   else{

			   Status = XAxiDma_SimpleTransfer(&AxiDma,(u32)(TxBufferPtr),
						(u32)(MAX_PKT_LEN), XAXIDMA_DEVICE_TO_DMA);
			   cnt = 1;
		   }

			if (Status != XST_SUCCESS) {return XST_FAILURE;}
		}
		if(TxDone)
		{
			TxDone=0;
			TX_ready=1;

		}

		if (Error) {
			xil_printf("Failed test transmit%s done, "
			"receive%s done\r\n", TxDone? "":" not",
							RxDone? "":" not");
			goto Done;
		}


	}

	/* Disable TX and RX Ring interrupts and return success */
	DMA_DisableIntrSystem(&Intc, TX_INTR_ID, RX_INTR_ID);
Done:
	xil_printf("--- Exiting Test --- \r\n");

	return XST_SUCCESS;

}



int init_intr_sys(void)
{
	DMA_Intr_Init(&AxiDma,0);//initial interrupt system
	Init_Intr_System(&Intc); // initial DMA interrupt system
	Setup_Intr_Exception(&Intc);
	DMA_Setup_Intr_System(&Intc,&AxiDma,TX_INTR_ID,RX_INTR_ID);//setup dma interrpt system
	DMA_Intr_Enable(&Intc,&AxiDma);

}

int main(void)
{
	int data_len = 1024;

	double PI = 3.1415926;
	double fs = 31250;
	int numjoint = 13;


	int i,frame;
	frame = 0;
	double datain[data_len];
	double dataout[data_len];


//	while(1) //滤波器代码简单测试
//	{
//		frame++;
//		for (i = 0; i < data_len; ++i)
//		{
//			datain[i] = 0.5 * (sin(2 * PI * 20 * (frame*data_len + i) / fs) + cos(2 * PI * 10000 * (frame*data_len + i) / fs + PI / 4));
//		}
//
		filter_single_use(datain, dataout);
//		filter_all(datain, dataout);
//	}


//mrd -bin -file output.bin 0x00111a48 2048
//mrd -bin -file input.bin 0x00113a48 2048



	XGpio_Initialize(&Gpio, AXI_GPIO_DEV_ID);
	XGpio_SetDataDirection(&Gpio, 1, 0);
	init_intr_sys();
	XGpio_DiscreteWrite(&Gpio, 1, 1);
	axi_dma_test();




}


 

axi_dma_test();中的cnt主要是为了实现乒乓缓存,防止滤波处理延迟导致数据还未发送就被新数据覆盖,如果速度仍不够可以采用三级缓存。

dma_intr.h

/*
 *
 * www.osrc.cn
 * www.milinker.com
 * copyright by nan jin mi lian dian zi www.osrc.cn
*/
#ifndef DMA_INTR_H
#define DMA_INTR_H
#include "xaxidma.h"
#include "xparameters.h"
#include "xil_exception.h"
#include "xdebug.h"
#include "xscugic.h"

/************************** Constant Definitions *****************************/
/*
 * Device hardware build related constants.
 */
#define DMA_DEV_ID		XPAR_AXIDMA_0_DEVICE_ID

#define MEM_BASE_ADDR		0x10000000


#define RX_INTR_ID		XPAR_FABRIC_AXI_DMA_0_S2MM_INTROUT_INTR
#define TX_INTR_ID		XPAR_FABRIC_AXI_DMA_0_MM2S_INTROUT_INTR


#define TX_BUFFER_BASE		(MEM_BASE_ADDR + 0x00100000) //乒乓缓存地址1/2
#define TX_BUFFER2_BASE		(MEM_BASE_ADDR + 0x00200000)
#define RX_BUFFER2_BASE     (MEM_BASE_ADDR + 0x00400000)
#define RX_BUFFER_BASE		(MEM_BASE_ADDR + 0x00300000)
#define RX_BUFFER_HIGH		(MEM_BASE_ADDR + 0x004FFFFF)


/* Timeout loop counter for reset
 */
#define RESET_TIMEOUT_COUNTER	10000
/* test start value
 */
#define TEST_START_VALUE	0xC
/*
 * Buffer and Buffer Descriptor related constant definition
 */
#define MAX_PKT_LEN		8196  //单位为字节,输入1024个64bit数据 = 1024*64/8
/*
 * transfer times
 */
#define NUMBER_OF_TRANSFERS	100000

extern volatile int TxDone;
extern volatile int RxDone;
extern volatile int Error;

int  DMA_CheckData(int Length, u8 StartValue);
int  DMA_Setup_Intr_System(XScuGic * IntcInstancePtr,XAxiDma * AxiDmaPtr, u16 TxIntrId, u16 RxIntrId);
int  DMA_Intr_Enable(XScuGic * IntcInstancePtr,XAxiDma *DMAPtr);
int  DMA_Intr_Init(XAxiDma *DMAPtr,u32 DeviceId);
#endif

 dma_intr.c

XAxiDma *AxiDmaInst = (XAxiDma *)Callback;这句代码是为了获取当前中断的对象。void *Callback 是一个无符号的指针,传递进来的阐述可以强制转换成其他任何的对象,这里就是强制转换成 XAxiDma 对象了。 IrqStatus =XAxiDma_IntrGetIrq(AxiDmaInst, XAXIDMA_DMA_TO_DEVICE)这个函数获取当前中断号。 XAxiDma_IntrAckIrq(AxiDmaInst, IrqStatus, XAXIDMA_DMA_TO_DEVICE);这个函数是响应当前中断, 通知CPU 当前中断已经被接收,并且清除中断标志位。如果中断全部正确,TxDone将被置为1表示发送中断完成。 如果有错误,则复位DMA,并且设置超时参数.

接收中断函数的原理和发送一样 XAxiDma *AxiDmaInst = (XAxiDma *)Callback;这句代码是为了获取当前中断的对象。void *Callback 是一个无符号的指针,传递进来的阐述可以强制转换成其他任何的对象,这里就是强制转换成 XAxiDma 对象了。 IrqStatus = XAxiDma_IntrGetIrq(AxiDmaInst, XAXIDMA_DEVICE_TO_DMA);这个函数是获取当前中断号。 XAxiDma_IntrAckIrq(AxiDmaInst, IrqStatus, XAXIDMA_DEVICE_TO_DMA);这个函数是响应当前中 断,通知CPU 当前中断已经被接收,并且清除中断标志位。 如果中断全部正确,RxDone将被置为1表示接收中断完成。如果有错误,则复位DMA,并且设置超时参数


/*
 *
 * www.osrc.cn
 * www.milinker.com
 * copyright by nan jin mi lian dian zi www.osrc.cn
*/
#include "dma_intr.h"

volatile int TxDone;
volatile int RxDone;
volatile int Error;
/*****************************************************************************/
/*
*
* This function checks data buffer after the DMA transfer is finished.
*
* We use the static tx/rx buffers.
*
* @param	Length is the length to check
* @param	StartValue is the starting value of the first byte
*
* @return
*		- XST_SUCCESS if validation is successful
*		- XST_FAILURE if validation is failure.
*
* @note		None.
*
******************************************************************************/
 int DMA_CheckData(int Length, u8 StartValue)
{
	u8 *RxPacket;
	int Index = 0;
	u8 Value;

	RxPacket = (u8 *) RX_BUFFER_BASE;
	Value = StartValue;

	/* Invalidate the DestBuffer before receiving the data, in case the
	 * Data Cache is enabled
	 */
#ifndef __aarch64__
	Xil_DCacheInvalidateRange((u32)RxPacket, Length);
#endif

	for(Index = 0; Index < Length; Index++) {
		if (RxPacket[Index] != Value) {
			xil_printf("Data error %d: %x/%x\r\n",
			    Index, RxPacket[Index], Value);

			return XST_FAILURE;
		}
		Value = (Value + 1) & 0xFF;
	}

	return XST_SUCCESS;
}
/*****************************************************************************/
/**
*
* This function disables the interrupts for DMA engine.
*
* @param	IntcInstancePtr is the pointer to the INTC component instance
* @param	TxIntrId is interrupt ID associated w/ DMA TX channel
* @param	RxIntrId is interrupt ID associated w/ DMA RX channel
*
* @return	None.
*
* @note		None.
*
******************************************************************************/
 void DMA_DisableIntrSystem(XScuGic * IntcInstancePtr,
					u16 TxIntrId, u16 RxIntrId)
{
#ifdef XPAR_INTC_0_DEVICE_ID
	/* Disconnect the interrupts for the DMA TX and RX channels */
	XIntc_Disconnect(IntcInstancePtr, TxIntrId);
	XIntc_Disconnect(IntcInstancePtr, RxIntrId);
#else
	XScuGic_Disconnect(IntcInstancePtr, TxIntrId);
	XScuGic_Disconnect(IntcInstancePtr, RxIntrId);
#endif
}
/*****************************************************************************/
/*
*
* This is the DMA TX Interrupt handler function.
*
* It gets the interrupt status from the hardware, acknowledges it, and if any
* error happens, it resets the hardware. Otherwise, if a completion interrupt
* is present, then sets the TxDone.flag
*
* @param	Callback is a pointer to TX channel of the DMA engine.
*
* @return	None.
*
* @note		None.
*
******************************************************************************/
static void DMA_TxIntrHandler(void *Callback)
{

	u32 IrqStatus;
	int TimeOut;
	XAxiDma *AxiDmaInst = (XAxiDma *)Callback;

	/* Read pending interrupts */
	IrqStatus = XAxiDma_IntrGetIrq(AxiDmaInst, XAXIDMA_DMA_TO_DEVICE);

	/* Acknowledge pending interrupts */


	XAxiDma_IntrAckIrq(AxiDmaInst, IrqStatus, XAXIDMA_DMA_TO_DEVICE);

	/*
	 * If no interrupt is asserted, we do not do anything
	 */
	if (!(IrqStatus & XAXIDMA_IRQ_ALL_MASK)) {

		return;
	}

	/*
	 * If error interrupt is asserted, raise error flag, reset the
	 * hardware to recover from the error, and return with no further
	 * processing.
	 */
	if ((IrqStatus & XAXIDMA_IRQ_ERROR_MASK)) {

		Error = 1;

		/*
		 * Reset should never fail for transmit channel
		 */
		XAxiDma_Reset(AxiDmaInst);

		TimeOut = RESET_TIMEOUT_COUNTER;

		while (TimeOut) {
			if (XAxiDma_ResetIsDone(AxiDmaInst)) {
				break;
			}

			TimeOut -= 1;
		}

		return;
	}

	/*
	 * If Completion interrupt is asserted, then set the TxDone flag
	 */
	if ((IrqStatus & XAXIDMA_IRQ_IOC_MASK)) {

		TxDone = 1;
	}
}

/*****************************************************************************/
/*
*
* This is the DMA RX interrupt handler function
*
* It gets the interrupt status from the hardware, acknowledges it, and if any
* error happens, it resets the hardware. Otherwise, if a completion interrupt
* is present, then it sets the RxDone flag.
*
* @param	Callback is a pointer to RX channel of the DMA engine.
*
* @return	None.
*
* @note		None.
*
******************************************************************************/
static void DMA_RxIntrHandler(void *Callback)
{
	u32 IrqStatus;
	int TimeOut;
	XAxiDma *AxiDmaInst = (XAxiDma *)Callback;

	/* Read pending interrupts */
	IrqStatus = XAxiDma_IntrGetIrq(AxiDmaInst, XAXIDMA_DEVICE_TO_DMA);

	/* Acknowledge pending interrupts */
	XAxiDma_IntrAckIrq(AxiDmaInst, IrqStatus, XAXIDMA_DEVICE_TO_DMA);

	/*
	 * If no interrupt is asserted, we do not do anything
	 */
	if (!(IrqStatus & XAXIDMA_IRQ_ALL_MASK)) {
		return;
	}

	/*
	 * If error interrupt is asserted, raise error flag, reset the
	 * hardware to recover from the error, and return with no further
	 * processing.
	 */
	if ((IrqStatus & XAXIDMA_IRQ_ERROR_MASK)) {

		Error = 1;

		/* Reset could fail and hang
		 * NEED a way to handle this or do not call it??
		 */
		XAxiDma_Reset(AxiDmaInst);

		TimeOut = RESET_TIMEOUT_COUNTER;

		while (TimeOut) {
			if(XAxiDma_ResetIsDone(AxiDmaInst)) {
				break;
			}

			TimeOut -= 1;
		}

		return;
	}

	/*
	 * If completion interrupt is asserted, then set RxDone flag
	 */
	if ((IrqStatus & XAXIDMA_IRQ_IOC_MASK)) {

		RxDone = 1;
	}
}

/*****************************************************************************/
/*
*
* This function setups the interrupt system so interrupts can occur for the
* DMA, it assumes INTC component exists in the hardware system.
*
* @param	IntcInstancePtr is a pointer to the instance of the INTC.
* @param	AxiDmaPtr is a pointer to the instance of the DMA engine
* @param	TxIntrId is the TX channel Interrupt ID.
* @param	RxIntrId is the RX channel Interrupt ID.
*
* @return
*		- XST_SUCCESS if successful,
*		- XST_FAILURE.if not succesful
*
* @note		None.
*
******************************************************************************/
int DMA_Setup_Intr_System(XScuGic * IntcInstancePtr,XAxiDma * AxiDmaPtr, u16 TxIntrId, u16 RxIntrId)
{
	int Status;
	XScuGic_SetPriorityTriggerType(IntcInstancePtr, TxIntrId, 0xA0, 0x3);

	XScuGic_SetPriorityTriggerType(IntcInstancePtr, RxIntrId, 0xA0, 0x3);
	/*
	 * Connect the device driver handler that will be called when an
	 * interrupt for the device occurs, the handler defined above performs
	 * the specific interrupt processing for the device.
	 */
	Status = XScuGic_Connect(IntcInstancePtr, TxIntrId,
				(Xil_InterruptHandler)DMA_TxIntrHandler,
				AxiDmaPtr);
	if (Status != XST_SUCCESS) {
		return Status;
	}

	Status = XScuGic_Connect(IntcInstancePtr, RxIntrId,
				(Xil_InterruptHandler)DMA_RxIntrHandler,
				AxiDmaPtr);
	if (Status != XST_SUCCESS) {
		return Status;
	}

	XScuGic_Enable(IntcInstancePtr, TxIntrId);
	XScuGic_Enable(IntcInstancePtr, RxIntrId);
	return XST_SUCCESS;
}



int DMA_Intr_Enable(XScuGic * IntcInstancePtr,XAxiDma *DMAPtr)
{

	/* Disable all interrupts before setup */

	XAxiDma_IntrDisable(DMAPtr, XAXIDMA_IRQ_ALL_MASK,
						XAXIDMA_DMA_TO_DEVICE);

	XAxiDma_IntrDisable(DMAPtr, XAXIDMA_IRQ_ALL_MASK,
				XAXIDMA_DEVICE_TO_DMA);

	/* Enable all interrupts */
	XAxiDma_IntrEnable(DMAPtr, XAXIDMA_IRQ_ALL_MASK,
							XAXIDMA_DMA_TO_DEVICE);

	XAxiDma_IntrEnable(DMAPtr, XAXIDMA_IRQ_ALL_MASK,
							XAXIDMA_DEVICE_TO_DMA);
	return XST_SUCCESS;

}


int DMA_Intr_Init(XAxiDma *DMAPtr,u32 DeviceId)
{
	int Status;
	XAxiDma_Config *Config=NULL;

	Config = XAxiDma_LookupConfig(DeviceId);
	if (!Config) {
		xil_printf("No config found for %d\r\n", DeviceId);
		return XST_FAILURE;
	}

	/* Initialize DMA engine */
	Status = XAxiDma_CfgInitialize(DMAPtr, Config);

	if (Status != XST_SUCCESS) {
		xil_printf("Initialization failed %d\r\n", Status);
		return XST_FAILURE;
	}

	if(XAxiDma_HasSg(DMAPtr)){
		xil_printf("Device configured as SG mode \r\n");
		return XST_FAILURE;
	}
	return XST_SUCCESS;

}

sys_intr.h

sys_intr.c、sys_intr.h 包含了系统中断控制器的驱动程 序。

 /*sys_intr.h
 * Created on: 2016年11月22日
 * www.osrc.cn
 * copyright by liyang mi lian dian zi www.osrc.cn
*/

#ifndef SYS_INTR_H_
#define SYS_INTR_H_

#include "xparameters.h"
#include "xil_exception.h"
#include "xdebug.h"
#include "xscugic.h"


#define INTC_DEVICE_ID          XPAR_SCUGIC_SINGLE_DEVICE_ID

int Init_Intr_System(XScuGic * IntcInstancePtr);
void setup_Intr_Exception(XScuGic * IntcInstancePtr);

#endif /* SYS_INTR_H_ */

sys_intr.c

 /*sys_intr.c
 * Created on: 2016年11月22日
 * www.osrc.cn
 * copyright by liyang mi lian dian zi www.osrc.cn
*/
#include "sys_intr.h"
void Setup_Intr_Exception(XScuGic * IntcInstancePtr)
{
	/* Enable interrupts from the hardware */
	Xil_ExceptionInit();
	Xil_ExceptionRegisterHandler(XIL_EXCEPTION_ID_INT,
			(Xil_ExceptionHandler)XScuGic_InterruptHandler,
			(void *)IntcInstancePtr);

	Xil_ExceptionEnable();
}

int Init_Intr_System(XScuGic * IntcInstancePtr)
{
	int Status;

	XScuGic_Config *IntcConfig;
	/*
	 * Initialize the interrupt controller driver so that it is ready to
	 * use.
	 */
	IntcConfig = XScuGic_LookupConfig(INTC_DEVICE_ID);
	if (NULL == IntcConfig) {
		return XST_FAILURE;
	}

	Status = XScuGic_CfgInitialize(IntcInstancePtr, IntcConfig,
					IntcConfig->CpuBaseAddress);
	if (Status != XST_SUCCESS) {
		return XST_FAILURE;
	}
	return XST_SUCCESS;
}

 输入数据时序分析

由于项目中的输入模块是老师直接发给我的,所以相当于半个黑盒子,故采用米联课的输入代码进行输入数据时序的分析。

S_AXIS_tready、S_AXIS_tvalid、S_AXIS_tlast重点关注这三者信号的时序关系。

`timescale 1ns / 1ps
//
// Company: 
// Engineer: 
// 
// Create Date: 2019/05/24 00:27:58
// Design Name: 
// Module Name: system_dma_top
// Project Name: 
// Target Devices: 
// Tool Versions: 
// Description: 
// 
// Dependencies: 
// 
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
// 
//


module system_dma_top(
  inout [14:0]DDR_addr,
  inout [2:0]DDR_ba,
  inout DDR_cas_n,
  inout DDR_ck_n,
  inout DDR_ck_p,
  inout DDR_cke,
  inout DDR_cs_n,
  inout [3:0]DDR_dm,
  inout [31:0]DDR_dq,
  inout [3:0]DDR_dqs_n,
  inout [3:0]DDR_dqs_p,
  inout DDR_odt,
  inout DDR_ras_n,
  inout DDR_reset_n,
  inout DDR_we_n,
  inout FIXED_IO_ddr_vrn,
  inout FIXED_IO_ddr_vrp,
  inout [53:0]FIXED_IO_mio,
  inout FIXED_IO_ps_clk,
  inout FIXED_IO_ps_porb,
  inout FIXED_IO_ps_srstb,
  output i2s_sck_o,
  output i2s_sdata_o,
  output i2s_ws_o
);

  reg [64:0]S_AXIS_tdata;
  reg  S_AXIS_tlast;
  reg S_AXIS_tvalid; 
  wire FCLK_CLK0;
  wire s_axis_aclk;
  wire s_axis_aresetn;
  wire [7:0]S_AXIS_tkeep;
  wire S_AXIS_tready;
  wire [0:0]gpio_rtl_tri_o;
  wire [0:0]peripheral_aresetn;
  reg [1:0] state;
  
assign S_AXIS_tkeep = 8'b11111111;  
assign s_axis_aclk =  FCLK_CLK1;
assign s_axis_aresetn = peripheral_aresetn;
  
always@(posedge FCLK_CLK1)
   begin
       if(!peripheral_aresetn) begin
           S_AXIS_tvalid <= 1'b0;
           S_AXIS_tdata <= 64'd0;
           S_AXIS_tlast <= 1'b0;
           state <=0;
       end
       else begin
          case(state)
            0: begin
                if(gpio_rtl_tri_o&& S_AXIS_tready) begin
                   S_AXIS_tvalid <= 1'b1;
                   state <= 1;
                end
                else begin
                   S_AXIS_tvalid <= 1'b0;
                   state <= 0;
                end
              end
            1:begin
                 if(S_AXIS_tready) begin
                     S_AXIS_tdata <= S_AXIS_tdata + 1'b1;   //非阻塞赋值
                     if(S_AXIS_tdata == 16'd1022) begin
                        S_AXIS_tlast <= 1'b1;
                        state <= 2;
                     end
                     else begin
                        S_AXIS_tlast <= 1'b0;
                        state <= 1;
                     end
                 end
                 else begin
                    S_AXIS_tdata <= S_AXIS_tdata;                   
                    state <= 1;
                 end
              end       
            2:begin
                 if(!S_AXIS_tready) begin
                    S_AXIS_tvalid <= 1'b1;
                    S_AXIS_tlast <= 1'b1;
                    S_AXIS_tdata <= S_AXIS_tdata;
                    state <= 2;
                 end
                 else begin
                    S_AXIS_tvalid <= 1'b0;
                    S_AXIS_tlast <= 1'b0;
                    S_AXIS_tdata <= 64'd0;
                    state <= 0;
                 end
              end
           default: state <=0;
           endcase
       end              
   end  




  system system_i
       (.DDR_addr(DDR_addr),
        .DDR_ba(DDR_ba),
        .DDR_cas_n(DDR_cas_n),
        .DDR_ck_n(DDR_ck_n),
        .DDR_ck_p(DDR_ck_p),
        .DDR_cke(DDR_cke),
        .DDR_cs_n(DDR_cs_n),
        .DDR_dm(DDR_dm),
        .DDR_dq(DDR_dq),
        .DDR_dqs_n(DDR_dqs_n),
        .DDR_dqs_p(DDR_dqs_p),
        .DDR_odt(DDR_odt),
        .DDR_ras_n(DDR_ras_n),
        .DDR_reset_n(DDR_reset_n),
        .DDR_we_n(DDR_we_n),
        .FCLK_CLK1(FCLK_CLK1),
        .FIXED_IO_ddr_vrn(FIXED_IO_ddr_vrn),
        .FIXED_IO_ddr_vrp(FIXED_IO_ddr_vrp),
        .FIXED_IO_mio(FIXED_IO_mio),
        .FIXED_IO_ps_clk(FIXED_IO_ps_clk),
        .FIXED_IO_ps_porb(FIXED_IO_ps_porb),
        .FIXED_IO_ps_srstb(FIXED_IO_ps_srstb),
        .S_AXIS_tdata(S_AXIS_tdata),
        .S_AXIS_tkeep(S_AXIS_tkeep),
        .S_AXIS_tlast(S_AXIS_tlast),
        .S_AXIS_tready(S_AXIS_tready),
        .S_AXIS_tvalid(S_AXIS_tvalid),
        .gpio_rtl_tri_o(gpio_rtl_tri_o),
        .peripheral_aresetn(peripheral_aresetn),
        .s_axis_aclk(s_axis_aclk),
        .i2s_sck_o(i2s_sck_o),
        .i2s_sdata_o(i2s_sdata_o),
        .i2s_ws_o(i2s_ws_o),
        .s_axis_aresetn(s_axis_aresetn));
        
endmodule

 初始状态

            0: begin
                if(gpio_rtl_tri_o&& S_AXIS_tready) begin
                   S_AXIS_tvalid <= 1'b1;
                   state <= 1;
                end
                else begin
                   S_AXIS_tvalid <= 1'b0;
                   state <= 0;
                end
              end

根据vitis中的代码,gpio信号会在dma传输开始前拉高,当gpio拉高且fifo处于ready状态时,将valid信号拉高,表明数据有效,开始第一帧数据的传输。

传输状态

            1:begin
                 if(S_AXIS_tready) begin
                     S_AXIS_tdata <= S_AXIS_tdata + 1'b1;   //非阻塞赋值
                     if(S_AXIS_tdata == 16'd1022) begin
                        S_AXIS_tlast <= 1'b1;
                        state <= 2;
                     end
                     else begin
                        S_AXIS_tlast <= 1'b0;
                        state <= 1;
                     end
                 end
                 else begin
                    S_AXIS_tdata <= S_AXIS_tdata;                   
                    state <= 1;
                 end
              end    

传输1024个递增的64bit数组,由于采用的是非阻塞赋值,虽然在第1023个数据时,对tlast进行拉高,且state转变为结束状态,但只有在下一时钟周期才会变化,即第1024个数据,进行last拉高和状态转变。

结束状态

            2:begin
                 if(!S_AXIS_tready) begin
                    S_AXIS_tvalid <= 1'b1;
                    S_AXIS_tlast <= 1'b1;
                    S_AXIS_tdata <= S_AXIS_tdata;
                    state <= 2;
                 end
                 else begin
                    S_AXIS_tvalid <= 1'b0;
                    S_AXIS_tlast <= 1'b0;
                    S_AXIS_tdata <= 64'd0;
                    state <= 0;
                 end
              end

结束状态对fifo状态进行判断,如果fifo非满,也就是处于ready状态,拉低last和valid信号,直接进入初始状态进行下一轮传输。如果fifo满,继续保持valid和last信号为高,等待fifo传输完毕。

总结

要输入自己的数据只要满足上述时序就可以,即在传输第一个数据时将valid拉高,在最后一个数据将last拉高,ready信号只和fifo有关,fifo为满时为0,ready为0时,所有传输停止,valid和last信号保持不变;valid持续到该组数据的last信号拉低为止,last信号理论上只持续一个时钟周期(除非last拉高时候ready为低)。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值