此篇是我在学习中做的归纳与总结,其中如果存在版权或知识错误或问题请直接联系我,欢迎留言。
PS:本着知识共享的原则,此篇博客可以转载,但请标明出处!
目录
1.项目简介:
1.1 完成功能:
1.1 使用工具:
2. LWIP141+DMA上行传输数据
2.1 LWIP141
2.2 PS端代码开发
2.3 PC端网络配置
3. 高速数字系统时钟设计-AD9516
4. 高速ADC--ADS62P49
5. 测试
MATLAB读取TXT数据文件的频谱分析--FFT:
Zynq控制高速高精度ADC(ADS62P49)完成250MSPS采样率模数转换功能,并将采集的大批量数据(100000x14x2bit)通过DMA传输至DDR3,而后经过网口传输至PC机做后续处理。
Vivado2017.4;
北京太速科技ZYNQ板卡:(XC7Z100)核心处理器及外设通用板卡;
双通道高速高精密ADDA子卡(ADS62P49、AD9122)
上行传输整体实现框图:
与DMA-FIFO对接需要使用AXI接口形式将数据传输至FIFO中,因此掌握AXI-FIFO的数据流传输机制是非常关键的,在此针对AXI接口传输具体实现细节不做描述,具体实现代码如下:
module data(
output [31:0] S_AXIS_tdata ,
output [3:0] S_AXIS_tkeep,
output S_AXIS_tlast,
input S_AXIS_tready,
output S_AXIS_tvalid,
input gpio_rtl_tri_o,
input peripheral_aresetn,
input FCLK_CLK0_0 ,
output s_axis_aclk,
output s_axis_aresetn
);
reg [31:0]S_AXIS_tdata;
reg S_AXIS_tlast;
reg S_AXIS_tvalid;
wire FCLK_CLK0_0;
wire s_axis_aclk;
wire s_axis_aresetn;
wire [3: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 = 4'b1111;
assign s_axis_aclk = FCLK_CLK0_0;
assign s_axis_aresetn = peripheral_aresetn;
always@(posedge FCLK_CLK0_0) begin
if(!peripheral_aresetn) begin
S_AXIS_tvalid <= 1'b0;
S_AXIS_tdata <= 32'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 == 32'd100000) 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 <= 32'd0;
state <= 0;
end
end
default: state <=0;
endcase
end
end
endmodule
DMA数据流传输部分仿真数据图:
LWIP配置
在phy_link_speed中不建议使用Autodetect模式,容易出现问题!建议根据自身的Zynq网口、网线、PC网口速率配置,本项目选择使用100M速率网络通信。
PS端上行传输代码功能: 1、完成所需设备初始化;
2、将PS端DDR3中数据上传至PC机
PS端程序开发同时也适用于Zynq-7010、Zynq-7020等。
工程目录表如下所示:
每次启动函数:XAxiDma_SimpleTransfer()时,传输10000组ADC采集数据,分十次发送。
tcp_transmission.c
#include
#include
#include "lwip/err.h"
#include "lwip/tcp.h"
#include "lwipopts.h"
#include "xaxidma.h"
#include "xil_cache.h"
#include "xil_printf.h"
#include "sleep.h"
#define SEND_SIZE (40000)
#define PAKET_LENGTH (40048)
static struct tcp_pcb *connected_pcb = NULL;
volatile unsigned tcp_client_connected = 0;
static int tcp_trans_done = 0;
static unsigned first_trans_start = 0;
static u32_t packet_index = 0;
extern XAxiDma AxiDma;
extern u16 *RxBufferPtr[4];
extern u8_t packet_trans_done;
void send_received_data()
{
#if __arm__
int copy = 1;
#else
int copy = 0;
#endif
err_t err;
int Status;
struct tcp_pcb *tpcb = connected_pcb;
/*initial the first axdma transmission, only excuse once*/
if(!first_trans_start)
{
Status = XAxiDma_SimpleTransfer(&AxiDma, (u32)RxBufferPtr[packet_index],
(u32)(PAKET_LENGTH), XAXIDMA_DEVICE_TO_DMA);
if (Status != XST_SUCCESS)
{
xil_printf("axi dma failed! 0 %d\r\n", Status);
return;
}
/*set the flag, so this part of code will not excuse again*/
first_trans_start = 1;
}
/*if the last axidma transmission is done, the interrupt triggered, then start TCP transmission*/
if(packet_trans_done)
{
if (!connected_pcb)
return;
/* if tcp send buffer has enough space to hold the data we want to transmit from PL, then start tcp transmission*/
if (tcp_sndbuf(tpcb) > SEND_SIZE)
{
/*transmit received data through TCP*/
err = tcp_write(tpcb, RxBufferPtr[packet_index], SEND_SIZE, copy);
if (err != ERR_OK) {
xil_printf("txperf: Error on tcp_write: %d\r\n", err);
connected_pcb = NULL;
return;
}
err = tcp_output(tpcb);
if (err != ERR_OK) {
xil_printf("txperf: Error on tcp_output: %d\r\n",err);
return;
}
packet_index++ ;
// /*clear the axidma done flag*/
packet_trans_done = 0;
first_trans_start = 0;
/*initial the other axidma transmission when the current transmission is done*/
// Status = XAxiDma_SimpleTransfer(&AxiDma, (u32)RxBufferPtr[(packet_index + 1)&1],
// (u32)(PAKET_LENGTH), XAXIDMA_DEVICE_TO_DMA);
// if (Status != XST_SUCCESS)
// {
// xil_printf("axi dma %d failed! %d \r\n", (packet_index + 1), Status);
// return;
// }
}
}
}
/*this fuction just used to count the tcp transmission times*/
static err_t
tcp_sent_callback(void *arg, struct tcp_pcb *tpcb, u16_t len)
{
err_t err;
tcp_trans_done = 1;
err = tcp_output(tpcb);
if (err != ERR_OK)
{
xil_printf("txperf: Error on tcp_output: %d\r\n",err);
return -1;
}
return ERR_OK;
}
static err_t
tcp_connected_callback(void *arg, struct tcp_pcb *tpcb, err_t err)
{
xil_printf("txperf: Connected to iperf server\r\n");
/* store state */
connected_pcb = tpcb;
/* set callback values & functions */
tcp_arg(tpcb, NULL);
tcp_sent(tpcb, tcp_sent_callback);
//tcp_recv(tpcb, tcp_recv_callback);
tcp_nagle_disable(tpcb);
if(!tcp_nagle_disabled(tpcb))
{
xil_printf("tcp nagle disable failed!\r\n");
}
tcp_client_connected = 1;
/* initiate data transfer */
return ERR_OK;
}
int tcp_send_init()
{
struct tcp_pcb *pcb;
struct ip_addr ipaddr;
err_t err;
u16_t port;
port = 7; /* iperf default port */
/* create new TCP PCB structure */
pcb = tcp_new();
if (!pcb) {
xil_printf("txperf: Error creating PCB. Out of Memory\r\n");
return -1;
}
/* connect to iperf tcp server */
IP4_ADDR(&ipaddr, 192, 168, 1, 209); /* iperf server address */
tcp_client_connected = 0;
first_trans_start = 0;
packet_trans_done = 0;
packet_index = 0;
err = tcp_connect(pcb, &ipaddr, port, tcp_connected_callback);
if (err != ERR_OK) {
xil_printf("txperf: tcp_connect returned error: %d\r\n", err);
return err;
}
return 0;
}
main函数:
#include "dma_intr.h"
#include "timer_intr.h"
#include "sys_intr.h"
#include "xgpio.h"
#include "lwip/err.h"
#include "lwip/tcp.h"
#include "lwipopts.h"
#include "netif/xadapter.h"
#include "lwipopts.h"
static XScuGic Intc; //GIC
static XScuTimer Timer;//timer
XAxiDma AxiDma;
u16 *RxBufferPtr[10]; /* ping pong buffers*/
volatile u32 RX_success;
volatile u32 TX_success;
volatile u32 RX_ready=1;
volatile u32 TX_ready=1;
#define TIMER_LOAD_VALUE XPAR_CPU_CORTEXA9_0_CPU_CLK_FREQ_HZ / 8 //0.5S
#define AXIDMA_DEV_ID XPAR_AXIDMA_0_DEVICE_ID
extern void send_received_data(void);
extern unsigned tcp_client_connected;
static XGpio Gpio;
#define AXI_GPIO_DEV_ID XPAR_AXI_GPIO_0_DEVICE_ID
int init_intr_sys(void)
{
DMA_Intr_Init(&AxiDma,AXIDMA_DEV_ID);//initial interrupt system
Timer_init(&Timer,TIMER_LOAD_VALUE,TIMER_DEVICE_ID);
Init_Intr_System(&Intc); // initial DMA interrupt system
Setup_Intr_Exception(&Intc);
DMA_Setup_Intr_System(&Intc,&AxiDma,0,RX_INTR_ID);//setup dma interrpt system
Timer_Setup_Intr_System(&Intc,&Timer,TIMER_IRPT_INTR);
DMA_Intr_Enable(&Intc,&AxiDma);
}
int main(void)
{
int Status;
struct netif *netif, server_netif;
struct ip_addr ipaddr, netmask, gw;
/* the mac address of the board. this should be unique per board */
unsigned char mac_ethernet_address[] = { 0x00, 0x0a, 0x35, 0x00, 0x01, 0x02 };
/* Initialize the ping pong buffers for the data received from axidma */
RxBufferPtr[0] = (u16 *)RX_BUFFER0_BASE;
RxBufferPtr[1] = (u16 *)RX_BUFFER1_BASE;
RxBufferPtr[2] = (u16 *)RX_BUFFER2_BASE;
RxBufferPtr[3] = (u16 *)RX_BUFFER3_BASE;
RxBufferPtr[4] = (u16 *)RX_BUFFER4_BASE;
RxBufferPtr[5] = (u16 *)RX_BUFFER5_BASE;
RxBufferPtr[6] = (u16 *)RX_BUFFER6_BASE;
RxBufferPtr[7] = (u16 *)RX_BUFFER7_BASE;
RxBufferPtr[8] = (u16 *)RX_BUFFER8_BASE;
RxBufferPtr[9] = (u16 *)RX_BUFFER9_BASE;
XGpio_Initialize(&Gpio, AXI_GPIO_DEV_ID);
XGpio_SetDataDirection(&Gpio, 1, 0);
init_intr_sys();
TcpTmrFlag = 0;
netif = &server_netif;
IP4_ADDR(&ipaddr, 192, 168, 1, 10);
IP4_ADDR(&netmask, 255, 255, 255, 0);
IP4_ADDR(&gw, 192, 168, 1, 1);
/*lwip library init*/
lwip_init();
/* Add network interface to the netif_list, and set it as default */
if (!xemac_add(netif, &ipaddr, &netmask, &gw, mac_ethernet_address, XPAR_XEMACPS_0_BASEADDR)) {
xil_printf("Error adding N/W interface\r\n");
return -1;
}
netif_set_default(netif);
/* specify that the network if is up */
netif_set_up(netif);
/* initialize tcp pcb */
tcp_send_init();
XGpio_DiscreteWrite(&Gpio, 1, 1);
//oled_fresh_en();// enable oled
Timer_start(&Timer);
while (1)
{
/* call tcp timer every 250ms */
if(TcpTmrFlag) {
tcp_tmr();
TcpTmrFlag = 0;
}
/*receive input packet from emac*/
xemacif_input(netif);
/* if connected to the server, start receive data from PL through axidma, then transmit the data to the PC software by TCP*/
if(tcp_client_connected){
send_received_data();
}
if(packet_trans_done) {
XGpio_DiscreteWrite(&Gpio, 1, 0);
}
}
return 0;
}
关掉电脑网络防火墙!!!!
下载PS程序(debug下载方式)
打开网络调试助手(TCP Server;地址:192.168.1.209)
https://blog.csdn.net/m0_37779673/article/details/118459908
高速高精密ADC数据采集-ADS62P49:https://blog.csdn.net/m0_37779673/article/details/118460370
https://blog.csdn.net/m0_37779673/article/details/119285146
10MHz正弦波采集测试:
50MHz正弦波采集测试: