Zynq—AD9238数据采集DDR3缓存千兆以太网发送实验(二)
- 创业
- 2025-08-02 20:57:01

Zynq—AD9238数据采集DDR3缓存千兆以太网发送实验(前导)
Zynq—AD9238数据采集DDR3缓存千兆以太网发送实验(一)
Zynq—AD9238数据采集DDR3缓存千兆以太网发送实验(三)
五、实验目的
本次实验使用电脑上的网络调试助手,将命令帧通过以太网芯片RTL8211(RGMII接口)发送至ACZ7015开发板,提取UDP报文内容转换成控制命令,从而实现对ACM9238模块采样频率、数据采样个数以及采样通道的配置。
配置完成之后,ACM9238模块开始采集数据,将采集的数据存储至DDR3中,然后通过网口以UDP协议传输到电脑。用户可以在电脑上通过网口调试工具进行指令的下发,并以文件的形式保存接收到的数据,然后使用MATLAB软件进行进一步的数据处理分析。
PL 部分的模块说明如下:
pll 模块: 锁相环模块, 输入时钟 50M, 由 PS 输出给 PL; 输出 100M 的时钟给到 DDR3 控制器使用; 输出 50M 的时钟给其它模块使用。eth_receive_cmd 模块: 以太网接收命令模块, 对以太网接收到的数据进行分析, 将接收的数据转换成相应的控制数据并输出到对应的模块。ad9238_ctrl 模块: ACM9238 控制器模块, 该模块内部包含速度控制模块,以及数据位宽转换模块。state_ctrl 模块: ADC 采集数据 DDR3 缓存以太网发送状态控制模块, 协调各个模块的信号控制, 程序状态的总控制模块。fifo_axi4_adapter 模块: fifo 接口到 AXI4 接口的转换模块(含 2 个 FIFO)。 六、ACM9238模块两路,
采样上限50Msps,如果期望以1Msps 的采样速率采样, 则只需要每间隔 50 个采样数据取一个结果存储或使用, 其他 49 个数据直接舍弃。不建议降低ADC芯片的时钟信号。
七、设计实例 7.1模块设计 7.1.1 eth_receive_cmd模块将以太网接收到的数据进行解析, 得到控制命令。
(1)eth_udp_rx_gmii模块和rgmii_to_gmii模块 (2)mmcm模块
锁相环模块,将 rgmii 接口时钟信号 rgmii_rx_clk_i 偏移90 °得到 rgmii_rx_clk 时钟信号。(为了在时钟信号的上升沿/下降沿取数据时,取得数据刚好是数据信号 rgmii_rxd 的正中间, 使得采样的数据处于最稳定的状态。)
锁相环IP配置
(3)fifo_rx模块使用该 IP 核解决采集过程中会出现的跨时钟域数据交互问题(以太网125MHz,ACM9238-50MHz)。
(4)eth_cmd模块接收转命令模块。
//非空时产生FIFO读请求信号 always@(posedge clk or negedge reset_n) if(!reset_n) fifo_rd_req <= 1'b0; else if(!rx_empty) fifo_rd_req <= 1'b1; else fifo_rd_req <= 1'b0; //获得帧命令数据 always@(posedge clk) if(fifo_rd_req)begin data_0[7] <= #1 fifodout; data_0[6] <= #1 data_0[7]; data_0[5] <= #1 data_0[6]; data_0[4] <= #1 data_0[5]; data_0[3] <= #1 data_0[4]; data_0[2] <= #1 data_0[3]; data_0[1] <= #1 data_0[2]; data_0[0] <= #1 data_0[1]; end //判断帧命令数据 always@(posedge clk or negedge reset_n) if(!reset_n)begin address <= 0; cmd_data <= 32'd0; cmdvalid <= 1'b0; end else if(fifo_rx_done)begin if((data_0[0]==8'h55)&&(data_0[1]==8'hA5)&&(data_0[7]==8'hF0)) begin cmd_data[7:0] <= #1 data_0[6]; cmd_data[15:8] <= #1 data_0[5]; cmd_data[23:16] <= #1 data_0[4]; cmd_data[31:24] <= #1 data_0[3]; address <= #1 data_0[2]; cmdvalid <= #1 1; end else cmdvalid <= #1 0; end else cmdvalid <= #1 0; (5)cmd_rx模块接收数据转换为控制数据。
寄存器说明:
always@(posedge clk or negedge reset_n) if(!reset_n)begin ChannelSel <= 2'b00; DataNum <= 32'd0; ADC_Speed_Set <= 32'd0; RestartReq <= 1'b0; end else if(cmdvalid)begin case(cmd_addr) 0: RestartReq <= 1'b1; 1: ChannelSel <= cmd_data[1:0]; 2: DataNum <= cmd_data[31:0]; 3: ADC_Speed_Set <= cmd_data[31:0]; default:; endcase end else RestartReq <= 1'b0; 7.1.2 ad9238_ctrl 模块控制ADC的采样速率,将12位数据转换为16位数据。
(1)speed_ctrl模块 always@(posedge clk or negedge reset_n) if(!reset_n) div_cnt <= 0; else if(ad_sample_en)begin if(div_cnt >= div_set) div_cnt <= 0; else div_cnt <= div_cnt + 1'd1; end else div_cnt <= 0; always@(posedge clk or negedge reset_n) if(!reset_n) adc_data_en <= 0; else if(div_cnt == div_set) adc_data_en <= 1; else adc_data_en <= 0; (2)ad_12bit_to_16bit模块 always @(posedge clk) ad_out_valid <= ad_sample_en; assign s_ad_in1 = ad_in1 + 12'd2048; assign s_ad_in2 = ad_in2 + 12'd2048; always @(posedge clk) if(ad_sample_en && ch_sel == 2'b01) ad_out<={4'd0,s_ad_in1};//这样补 0 为了适应上位机 else if(ad_sample_en && ch_sel == 2'b10) ad_out<={4'd0,s_ad_in2};// else if(ad_sample_en && ch_sel == 2'b00) ad_out<={4'd0,adc_test_data}; else ad_out <= 16'd0; 7.1.3 state_ctrl 模块控制信号的产生以及 ADC 何时启动数据传输。
localparam IDLE = 4'd0; //空闲状态 localparam DDR_WR_FIFO_CLEAR = 4'd1; //DDR 写 FIFO 清除状态 localparam ADC_SAMPLE = 4'd2; //ADC 采样数据状态 localparam DDR_RD_FIFO_CLEAR = 4'd3; //DDR 读 FIFO 清除状态 localparam DATA_SEND_START = 4'd4; //数据发送状态 localparam DATA_SEND_WORKING = 4'd5; //数据发送完成状态(1)IDLE
//ADC 模块开始采样标志信号寄存 always@(posedge clk or posedge reset)begin if(reset) start_sample_rm <= 1'b0; else if(state==IDLE) start_sample_rm <= start_sample; else start_sample_rm <= 1'b0; end /*状态切换IDLE->DDR_WR_FIFO_CLEAR begin if(start_sample_rm) begin //DDR 初始化完成并且产生启动采样信号 state <= DDR_WR_FIFO_CLEAR; //进入写 FIFO 清除状态 end else begin state <= state; end end */(2)DDR_WR_FIFO_CLEAR
//延时10个节拍 always@(posedge clk or posedge reset)begin if(reset) wrfifo_clr_cnt<=0; else if(state==DDR_WR_FIFO_CLEAR)//如果进入了清 fifo 状态 begin if(wrfifo_clr_cnt==9) wrfifo_clr_cnt<=5'd9; else wrfifo_clr_cnt<=wrfifo_clr_cnt+1'b1; end else wrfifo_clr_cnt<=5'd0; end //给清FIFO信号足够的拉高时间 always@(posedge clk or posedge reset)begin if (reset) wrfifo_clr<=0; else if(state==DDR_WR_FIFO_CLEAR) begin if(wrfifo_clr_cnt==0||wrfifo_clr_cnt==1||wrfifo_clr_cnt==2) wrfifo_clr<=1'b1; else wrfifo_clr<=1'b0; end else wrfifo_clr<=1'b0; end /*状态切换DDR_WR_FIFO_CLEAR->ADC_SAMPLE begin if(!wrfifo_full && (wrfifo_clr_cnt==9)) state<=ADC_SAMPLE; else state<=DDR_WR_FIFO_CLEAR; end */(3)ADC_SAMPLE
//根据ADC输出使能信号计数 always@(posedge clk or posedge reset)begin if(reset) adc_sample_cnt<=1'b0; else if(state==ADC_SAMPLE)begin if(adc_data_en) adc_sample_cnt<=adc_sample_cnt+1'b1; else adc_sample_cnt<=adc_sample_cnt; end else adc_sample_cnt<=1'b0; end //产生采样使能信号给其他模块 always@(posedge clk or posedge reset)begin if(reset) ad_sample_en<=0; else if(state==ADC_SAMPLE) ad_sample_en<=1; else ad_sample_en<=0; end /*状态切换ADC_SAMPLE->DDR_RD_FIFO_CLEAR begin if((adc_sample_cnt>=set_sample_num-1'b1)&& adc_data_en) state<=DDR_RD_FIFO_CLEAR; else state<=state; end */(4)DDR_RD_FIFO_CLEAR
//延时10个节拍 always@(posedge clk or posedge reset)begin if(reset) rdfifo_clr_cnt<=0; else if(state==DDR_RD_FIFO_CLEAR)//如果进入了清 fifo 状态 begin if(rdfifo_clr_cnt==9) rdfifo_clr_cnt<=5'd9; else rdfifo_clr_cnt<=rdfifo_clr_cnt+1'b1; end else rdfifo_clr_cnt<=5'd0; end //给清FIFO信号足够的拉高时间 always@(posedge clk or posedge reset)begin if (reset) rdfifo_clr<=0; else if(state==DDR_RD_FIFO_CLEAR) begin if(rdfifo_clr_cnt==0||rdfifo_clr_cnt==1||rdfifo_clr_cnt==2) rdfifo_clr<=1'b1; else rdfifo_clr<=1'b0; end else rdfifo_clr<=1'b0; end /*状态切换DDR_RD_FIFO_CLEAR->DATA_SEND_START begin if(!rdfifo_empty && (rdfifo_clr_cnt==9))begin state<=DATA_SEND_START; end else state<=state; end */(5)DATA_SEND_START
/*状态切换DATA_SEND_START->DATA_SEND_WORKING begin state <= DATA_SEND_WORKING; end */(6)DATA_SEND_WORKING
//发送数据计数 always@(posedge clk or posedge reset)begin if(reset) send_data_cnt<=32'd0; else if(state==IDLE) send_data_cnt<=32'd0; else if(rdfifo_rden) send_data_cnt<=send_data_cnt+1; else send_data_cnt<=send_data_cnt; end //DDR数据存到以太网缓存 always@(posedge clk or posedge reset) if(reset) begin eth_fifo_wrreq <= 1'b0; eth_fifo_wrdata <= 'd0; end else if(rdfifo_rden) begin eth_fifo_wrreq <= 1'b1; eth_fifo_wrdata <= rdfifo_dout; end else begin eth_fifo_wrreq <= 1'b0; eth_fifo_wrdata <= 'd0; end /*状态切换DATA_SEND_WORKING->IDLE、DATA_SEND_WORKING->DATA_SEND_WORKING begin if(send_data_cnt >= set_sample_num-1'b1) begin rdfifo_rden <= 1'b0; state <= IDLE; end else begin rdfifo_rden <= 1'b1; state <= DATA_SEND_WORKING; end end */ 7.1.4 fifo_axi_adapter模块看文章开头:Zynq—AD9238数据采集DDR3缓存千兆以太网发送实验(一)。
S_IDLE: begin if(start) next_state = S_ARB; else next_state = S_IDLE; end module fifo_axi4_adapter #( parameter FIFO_DW = 16 , parameter WR_AXI_BYTE_ADDR_BEGIN = 0 , parameter WR_AXI_BYTE_ADDR_END = 1023 , parameter RD_AXI_BYTE_ADDR_BEGIN = 0 , parameter RD_AXI_BYTE_ADDR_END = 1023 , parameter AXI_DATA_WIDTH = 128 , parameter AXI_ADDR_WIDTH = 28 , parameter AXI_ID = 4'b0000, parameter AXI_BURST_LEN = 8'd31 //burst length = 32 ) ( input start , // clock reset input clk , input reset , // wr_fifo wr Interface input wrfifo_clr , input wrfifo_clk , input wrfifo_wren , input [FIFO_DW-1:0] wrfifo_din , output wrfifo_full , output [15:0] wrfifo_wr_cnt , // rd_fifo rd Interface input rdfifo_clr , input rdfifo_clk , input rdfifo_rden , output [FIFO_DW-1:0] rdfifo_dout , output rdfifo_empty , output [15:0] rdfifo_rd_cnt , // Master Interface Write Address Ports output [3:0] m_axi_awid , output [AXI_ADDR_WIDTH-1:0] m_axi_awaddr , output [7:0] m_axi_awlen , output [2:0] m_axi_awsize , output [1:0] m_axi_awburst , output [0:0] m_axi_awlock , output [3:0] m_axi_awcache , output [2:0] m_axi_awprot , output [3:0] m_axi_awqos , output [3:0] m_axi_awregion, output m_axi_awvalid , input m_axi_awready , // Master Interface Write Data Ports output [AXI_DATA_WIDTH-1:0] m_axi_wdata , output [AXI_DATA_WIDTH/8-1:0] m_axi_wstrb , output m_axi_wlast , output m_axi_wvalid , input m_axi_wready , // Master Interface Write Response Ports input [3:0] m_axi_bid , input [1:0] m_axi_bresp , input m_axi_bvalid , output m_axi_bready , // Master Interface Read Address Ports output [3:0] m_axi_arid , output [AXI_ADDR_WIDTH-1:0] m_axi_araddr , output [7:0] m_axi_arlen , output [2:0] m_axi_arsize , output [1:0] m_axi_arburst , output [0:0] m_axi_arlock , output [3:0] m_axi_arcache , output [2:0] m_axi_arprot , output [3:0] m_axi_arqos , output [3:0] m_axi_arregion, output m_axi_arvalid , input m_axi_arready , // Master Interface Read Data Ports input [3:0] m_axi_rid , input [AXI_DATA_WIDTH-1:0] m_axi_rdata , input [1:0] m_axi_rresp , input m_axi_rlast , input m_axi_rvalid , output m_axi_rready ); 7.1.5 eth_send_data 模块将DDR读出的ADC数据发送到电脑端。
(1)fifo_tx模块First Word Fall Through( FWFT)可以不需要读命令, 自动将最新的数据放在 dout 上。
(2)eth_send_ctrl模块以太网帧最大长度 1518 字节(数据段 1500 字节) , 其中数据段 1500 字节还包括 20 字节 IP 报文头部和 8 字节 UDP 报文头部, 所以数据帧发送的ACM9238 采集的数据最大长度为 1472 字节。
always@(posedge clk125M or negedge reset_n) if(!reset_n) begin pkt_tx_en <= 1'd0; pkt_length <= 16'd0; data_num <= 32'd0; state <= 0; cnt_dly_time <= 28'd0; end else begin case(state) 0://得到 pkt_length 信号的初始值 begin if(restart_req)begin data_num <= total_data_num; if((total_data_num << 1) >= 16'd1472)begin pkt_length <= 16'd1472; //一个数据2个字节 state <= 1; end else if((total_data_num << 1) > 0)begin pkt_length <= total_data_num << 1; //一个数据2个字节 state <= 1; end else begin state <= 0; end end end 1: begin if(fifo_rd_cnt >= (pkt_length -2)) begin pkt_tx_en <= 1'd1; state <= 2; end else begin state <= 1; pkt_tx_en <= 1'd0; end end 2: begin pkt_tx_en <= 1'd0; if(eth_tx_done)begin data_num <= data_num - pkt_length/2; state <= 3; end end 3: if(cnt_dly_time >= cnt_dly_min)begin state <= 4; cnt_dly_time <= 28'd0; end else begin cnt_dly_time <= cnt_dly_time + 1'b1; state <= 3; end 4: begin if(data_num * 2 >= 16'd1472)begin pkt_length <= 16'd1472; state <= 1; end else if(data_num * 2 > 0)begin pkt_length <= data_num * 2; state <= 1; end else begin state <= 0; end end default:state <= 0; endcase endZynq—AD9238数据采集DDR3缓存千兆以太网发送实验(二)由讯客互联创业栏目发布,感谢您对讯客互联的认可,以及对我们原创作品以及文章的青睐,非常欢迎各位朋友分享到个人网站或者朋友圈,但转载请说明文章出处“Zynq—AD9238数据采集DDR3缓存千兆以太网发送实验(二)”