ZYNQ—vitis—网口传输信号波形数据

ZYNQ—vitis—网口传输信号波形数据

工程功能:ADC采集信号,将波形数据通过BRAM传输到PS端,然后用UDP以太网发送。(附加:ILA观察信号,发送的数据包含帧头,)

FPGA端——用BRAM将信号传输到PS

BD设计:

在这里插入图片描述

上图分析:

一共四个模块构成:

1.bram_ctrl: bram控制写模块

  • ADC_A0 是将要传输的数据,也就是ADC采集的信号
  • 200M时钟、复位
  • bram_data_valid 是输入数据有效信号
  • PL_IRQ 是一个输出的中断信号,当检测到输入信号时拉高一拍

代码:

module bram_ctrl(
	input       clk,
	input 		rst_n,
	input		valid,
	input    	[31:0]	in_data,
	
	output   	[31:0]	addrb,
	output reg 	[31:0]	dinb ,
	output reg 	[3:0] 	web  ,
	output reg			PL_IRQ0
	); 
/************** 		 **************/	
/**************    信号定义      **************/
/************** 		 **************/		
	//PL写RAM
	wire [31:0]AddrEndValueVio; //控制写的地址范围
	wire [31:0]dinbValueVio;	//控制写的数据数值
	wire [3:0] webVio;			//控制写的有效字节位
	wire [0:0] valid;		//启动写数据
	
	reg [0:0]valid1;//对writeEnVio延迟一个clk
	reg [0:0]wrState;    //写数据状态:0代表IDLE.1代表正在写
	reg [31:0]addrbWrite;//写数据地址
	
	//Ohter signals
	assign    addrb = wrState?addrbWrite:32'd0;
	reg  [0:0]wrStateReg;
	
/**************			  **************/		
/**************    PL 写入BRAM    **************/		
/**************			  **************/			

always@(posedge clk)begin
	if(!rst_n)begin
		valid1 <= 1'b0;	
	end 
	else begin
		valid1 <= valid;		
	end
end

always@(posedge clk)begin
	if(!rst_n)begin
		dinb[31:0]        <= 32'd0;
		web[3:0]          <=  4'd0;
		wrState           <= 1'b0;
		addrbWrite[31:0]  <= 32'd0;
	end 
	else begin 
		case(wrState)
		1'b0:
			if(valid&~valid1)begin//边沿检测,检测到上升沿启动写过程	
				wrState           <= 1'b1;
				web[3:0]          <= 4'b1111;
				addrbWrite[31:0]  <= 32'd0;
				dinb[31:0]        <= in_data[31:0];	
			end else begin
				wrState           <= wrState;
				web[3:0]          <= 4'd0;
				addrbWrite[31:0]  <= 32'd0;
				dinb[31:0]        <= 32'd0;
			end
			
		1'b1:
			if(valid && addrbWrite[31:0] < 32'hffff)begin
				wrState		      <= wrState;
				web[3:0]          <= 4'b1111;
				addrbWrite[31:0]  <= addrbWrite[31:0] + 32'd4;
				dinb[31:0]        <= in_data[31:0];
			end
			else begin
				wrState		 <= 1'b0;
				web[3:0]     <= 4'b0;
				addrbWrite[31:0]  <= 32'd0;
				// dinb[31:0]   <= in_data[31:0];//写入每个地址相同数据
				//dinb[31:0]   <= dinb[31:0] + 32'd1;   //写入每个地址数据累加1
				dinb[31:0]   <= 32'd0;   //保持
			end
		endcase
	end
end

//中断
always@(posedge clk)begin
	if(!rst_n)begin
		PL_IRQ0 <= 1'b0;	
	end 
	else if(valid&~valid1) begin
		PL_IRQ0 <= 1'b1;		
	end
	else 
		PL_IRQ0 <= 1'b0;
end

endmodule

2.axi_bram_ctrl: BRAM控制器,现成的IP核

配置:

在这里插入图片描述

3.blk_mem_gen: BRAM IP核

配置:

在这里插入图片描述

其余没展示的部分默认

其中,xlconstant是一个常数,值为1bit的1

4.ILA: 观察信号

PS端——处理数据

宏定义:我一共用了13个ADC采样,发送13路数据

//中断编号		BRAM地址
#define  INTC_DEVICE_ID          XPAR_SCUGIC_0_DEVICE_ID		//中断
#define ADC_A0_ADDR       XPAR_ADC_A0_AXI_BRAM_CTRL_0_S_AXI_BASEADDR	//BRAM
#define ADC_A1_ADDR       XPAR_ADC_A1_AXI_BRAM_CTRL_0_S_AXI_BASEADDR
#define ADC_A2_ADDR       XPAR_ADC_A2_AXI_BRAM_CTRL_0_S_AXI_BASEADDR
#define ADC_A3_ADDR       XPAR_ADC_A3_AXI_BRAM_CTRL_0_S_AXI_BASEADDR
#define ADC_A4_ADDR       XPAR_ADC_A4_AXI_BRAM_CTRL_0_S_AXI_BASEADDR
#define ADC_A5_ADDR       XPAR_ADC_A5_AXI_BRAM_CTRL_0_S_AXI_BASEADDR
#define ADC_A6_ADDR       XPAR_ADC_A6_AXI_BRAM_CTRL_0_S_AXI_BASEADDR
#define ADC_A7_ADDR		  XPAR_ADC_A7_AXI_BRAM_CTRL_0_S_AXI_BASEADDR

#define ADC_B1_ADDR		  XPAR_ADC_B1_AXI_BRAM_CTRL_0_S_AXI_BASEADDR
#define ADC_B2_ADDR		  XPAR_ADC_B2_AXI_BRAM_CTRL_0_S_AXI_BASEADDR
#define ADC_B3_ADDR		  XPAR_ADC_B3_AXI_BRAM_CTRL_0_S_AXI_BASEADDR
#define ADC_B4_ADDR		  XPAR_ADC_B4_AXI_BRAM_CTRL_0_S_AXI_BASEADDR
#define ADC_B5_ADDR		  XPAR_ADC_B5_AXI_BRAM_CTRL_0_S_AXI_BASEADDR

关键代码:指定一个地址,给地址赋值,最后用网口把地址发送出去

    u8 Ver,BID;
    Ver = 0x01;
    BID = 0x23;
	u32 samp_time = 250;
	u32 delay_time;
	u32 cnt = 0;
	u16 phase_ADC1;

	u16 *header = (u16*) 0x10000000;
	//拼接
	*(header) = Ver | (BID<<8);
	*(header+1) = samp_time&0xffff;
	*(header+2) = (samp_time&0xffff0000)>>16;
	*(header+3) = (delay_time&0xffff);
	*(header+4) = (delay_time&0xffff0000)>>16;
	*(header+5) = cnt&0xffff;
	*(header+6) = (cnt&0xffff0000)>>16;
	*(header+7) = phase_ADC1;
	*(header+8) = phase_ADC2;
	*(header+9) = phase_ADC3;
	*(header+10) = phase_ADC4;
	*(header+11) = phase_ADC5;
	*(header+12) = phase_ADC6;
	*(header+13) = phase_ADC7;
	*(header+14) = phase_ADC8;
	*(header+15) = phase_ADC9;
	*(header+16) = phase_ADC10;
	*(header+17) = phase_ADC11;
	*(header+18) = phase_ADC12;
	*(header+19) = phase_ADC13;
	*(header+20) = BoTimeSet&0xffff;
	*(header+21) = (BoTimeSet&0xffff0000)>>16;	

	int *data_point = (int*)(0x1000002c);
	//将13个通道的数据赋值给指定地址
    for (int j = 0; j < BoTimeSet; j++)
	{
		*(data_point) = Xil_In32(ADC_A0_ADDR + 4*(j));
		*(data_point + BoTimeSet * 1) = Xil_In32(ADC_A1_ADDR + 4*(j));
		*(data_point + BoTimeSet * 2) = Xil_In32(ADC_A2_ADDR + 4*(j));
		*(data_point + BoTimeSet * 3) = Xil_In32(ADC_A3_ADDR + 4*(j));
		*(data_point + BoTimeSet * 4) = Xil_In32(ADC_A4_ADDR + 4*(j));
		*(data_point + BoTimeSet * 5) = Xil_In32(ADC_A5_ADDR + 4*(j));
		*(data_point + BoTimeSet * 6) = Xil_In32(ADC_A6_ADDR + 4*(j));
		*(data_point + BoTimeSet * 7) = Xil_In32(ADC_A7_ADDR + 4*(j));
		*(data_point + BoTimeSet * 8) = Xil_In32(ADC_B1_ADDR + 4*(j));
		*(data_point + BoTimeSet * 9) = Xil_In32(ADC_B2_ADDR + 4*(j));
		*(data_point + BoTimeSet * 10) = Xil_In32(ADC_B3_ADDR + 4*(j));
		*(data_point + BoTimeSet * 11) = Xil_In32(ADC_B4_ADDR + 4*(j));
		*(data_point + BoTimeSet * 12) = Xil_In32(ADC_B5_ADDR + 4*(j));
		data_point++;
	}
	//网口发送
    udp_tx_data((u8*)(header),44 + 13 * BoTimeSet * 4);

代码分析:

  • 首先,定义一个u16的变量 header ,并且指定它的地址是 0x10000000

  • 将需要发送的帧头等依次赋值拼接给 header:Ver是u8,值为0x01,BID是u8,值为0x23;将它们按照高低位拼接起来,剩下的同理。

  • 接着定义 data_point,指定地址为 0x1000002c。理由为:上面的那些数据长度加起来刚好是0x2c,这样前面的数据发送完接着就是data_point

  • 通过 for 循环,将13个通道的数据填到data_point 对应的地址中。其中,BoTimeSet 是采样时间,即一个通道发送的数据个数

  • 最后,用网口发送函数 udp_tx_data 将地址发送出去。起始地址为 header 的地址,地址长度为 44 + 13 * BoTimeSet * 4 ;上面的那些数据长度加起来刚好是0x2c,十进制44,13个通道,每个通道 BoTimeSet 个字节。

UDP发送功能函数:

//UDP发送功能函数
void udp_tx_data(u8 *buffer_ptr,unsigned int len)
{
    static struct pbuf *ptr;

    ptr = pbuf_alloc(PBUF_TRANSPORT, len, PBUF_POOL); /* 申请内存 */

    if (ptr)
    {
        pbuf_take(ptr, buffer_ptr,len); /* 将buffer_ptr中的数据打包进pbuf结构中 */
        udp_send(pcb, ptr);              /* udp发送数据 */
        pbuf_free(ptr);                  /* 释放内存 */
    }
}

调试结果分析

用vitis的debug功能,查看寄存器地址:

在这里插入图片描述

再根据上面的代码u8 Ver,BID;Ver = 0x01; BID = 0x23;u32 samp_time = 250;0x10000000 地址开始,注意按照正确的方式,把数据读出来。

0x1000002c 开始,就是通道一的波形数据了,我赋上ILA采集的数据:

在这里插入图片描述

可以看出,通道一数据正确地传上去了。

通道二数据:

在这里插入图片描述

通道三数据:

在这里插入图片描述

我再赋上ILA ADC采样数据的末端:

在这里插入图片描述


并且相邻通道间起始地址相差 600*4=2400

  • 3
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Zynq千兆网口实验是一种基于Zynq系列处理器的网络通信实验。Zynq是Xilinx公司推出的一款集成了ARM处理器和可编程逻辑资源的可扩展处理器平台。 在进行Zynq千兆网口实验之前,首先需要准备一块Zynq开发板和软件开发工具。然后,我们可以通过Vivado软件进行Zynq处理器的设计和配置。 在这个实验中,我们将主要关注如何使用Zynq的千兆网口实现网络通信。我们可以利用Zynq的可编程逻辑资源和处理器来实现网络协议栈的功能。Zynq处理器可以通过软件实现网络协议的处理,例如使用TCP/IP协议栈来进行网络通信。 首先,我们需要配置Zynq的千兆网口,包括设置IP地址和子网掩码等网络参数。然后,我们可以使用Zynq网口来进行数据的发送和接收。可以通过编写相应的驱动程序来控制和操作网口的发送和接收功能。 接下来,我们可以编写应用程序来使用Zynq的千兆网口进行网络通信。我们可以利用Zynq的处理器来实现网络应用,例如网络服务器或客户端。我们可以使用Zynq网口接收来自其他设备的数据,并对数据进行处理和响应。 在Zynq千兆网口实验中,我们可以通过观察网络数据包的传输和接收情况来验证实验效果。我们可以使用网络调试工具来监控网络数据传输和接收,并分析数据包的内容。 总之,Zynq千兆网口实验是一种基于Zynq处理器的网络通信实验,通过配置Zynq的千兆网口开发相关的软件程序,可以实现数据的发送和接收,并验证网络通信的功能和效果。这个实验可以帮助我们更深入地了解Zynq处理器的应用领域和网络通信的原理。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值