用AD9361开发板+Matlab做一个频谱分析仪

本文详细介绍如何用AD9361实现一个简易频谱分析仪的方案。数据流向为AD9361->FFT计算->网口UDP传输->Matlab显示FFT结果。
本文重点介绍如何实现UDP的数据传输,AD9361相关配置和数据接口可以看前面发布的文章。
第一步我们先设置好ZYNQ相关的设计,主要是启用网口,串口等外设,另外构建一个DMA的数据通道,将数据从FIFO传输到ZYNQ的HP接口。Block design结构如图:
在这里插入图片描述

首先对AD9361 RX接受的基带信号做FFT运算,并计算信号能量:

    /***************************FFT****************************/    
    wire            fft_in_last;
    wire            fft_in_valid;
    wire    [15:0]  fft_in_i,fft_in_q;
    wire            fft_in_ready;

    wire signed[23:0]	fft_out_i,fft_out_q;
    wire            fft_out_valid;		 	 
    wire            fft_out_last;     
    
    //FFT组帧
    wire    [31:0]  fft_frame_data = {{4{dac_data_q[11]}},dac_data_q,{4{dac_data_i[11]}},dac_data_i};
    
    fft_frame_gen fft_frame_gen_inst(
        .clk        (clk),
        .rst_n      (rst_n),
        .in_valid   (1'b1),
        .in_data    (fft_frame_data),        
        .out_valid  (fft_in_valid),
        .out_data   ({fft_in_q,fft_in_i}),
        .out_last   (fft_in_last),
        .out_ready  (fft_in_ready));
 
    //FFT
    fft fft_inst(
        .aclk					 (clk			        ),//: IN STD_LOGIC;
        .aresetn				 (rst_n				    ),
        .s_axis_config_tdata	 (8'd1					),//: IN STD_LOGIC_VECTOR(15 DOWNTO 0);
        .s_axis_config_tvalid	 (1'b1					),//: IN STD_LOGIC;
        .s_axis_config_tready	 (						),//: OUT STD_LOGIC;
        .s_axis_data_tdata		 ({fft_in_q,fft_in_i}   ),//: IN STD_LOGIC_VECTOR(31 DOWNTO 0);
        .s_axis_data_tvalid		 (fft_in_valid		    ),//: IN STD_LOGIC;
        .s_axis_data_tlast		 (fft_in_last			),//: IN STD_LOGIC;	
        .s_axis_data_tready		 (fft_in_ready		    ),//: OUT STD_LOGIC;
        .m_axis_data_tdata		 ({fft_out_q,fft_out_i} ),//: OUT STD_LOGIC_VECTOR(63 DOWNTO 0);
        .m_axis_data_tvalid		 (fft_out_valid			),//: OUT STD_LOGIC;
        .m_axis_data_tready		 (1'b1					),//: IN STD_LOGIC;
        .m_axis_data_tlast		 (fft_out_last			) //: OUT STD_LOGIC;
    );
	
	reg	[48:0]	pwr_sum_out_data;
	reg			pwr_sum_out_valid;
	reg			pwr_sum_out_last;
	always @ (posedge clk)
	begin
		pwr_sum_out_last<=fft_out_last;
		pwr_sum_out_valid<=fft_out_valid;
		pwr_sum_out_data<=fft_out_i*fft_out_i+fft_out_q*fft_out_q;
	end

然后将结果截断之后,作为前面Block design的输入。这里截断的原因主要受限于网口的传输带宽。数据带宽=40Msps*24bit=960 bit/s<1Gbsp。

    reg         fifo_valid;   
    reg	[23:0]  fifo_data;   
    reg         fifo_last;
    wire        fifo_ready;
    wire [31:0]	fifo_data_count; 
	wire		fifo_prog_full;

    always @ (posedge clk)
    begin
		fifo_valid<=pwr_sum_out_valid;
		fifo_data<=pwr_sum_out_data[48:25];
		fifo_last<=pwr_sum_out_last;
    end

硬件相关的设置就完成了。接下来完成SDK软件相关的内容。
软件主要的工作就是完成网口以及dma的配置。然后不停的启动dma,等待dma传输完成,然后将数据通过udp传输出去。
新建一个lwip UDP Perf server的示例代码,然后替换main.c代码如下
在这里插入图片描述

#include <stdio.h>
#include "xparameters.h"
#include "netif/xadapter.h"
#include "platform.h"
#include "platform_config.h"
#include "lwipopts.h"
#include "xil_printf.h"
#include "sleep.h"
#include "lwip/priv/tcp_priv.h"
#include "lwip/init.h"
#include "lwip/inet.h"
#include "xil_cache.h"
#include "dma_intr.h"
#include "sys_intr.h"

#if LWIP_DHCP==1
#include "lwip/dhcp.h"
extern volatile int dhcp_timoutcntr;
#endif

extern volatile int TcpFastTmrFlag;
extern volatile int TcpSlowTmrFlag;

#define DEFAULT_IP_ADDRESS	"192.168.200.10"
#define DEFAULT_IP_MASK		"255.255.255.0"
#define DEFAULT_GW_ADDRESS	"192.168.200.1"

void platform_enable_interrupts(void);
void start_application(void);
void print_app_header(void);


struct netif server_netif;

static void print_ip(char *msg, ip_addr_t *ip)
{
	print(msg);
	xil_printf("%d.%d.%d.%d\r\n", ip4_addr1(ip), ip4_addr2(ip),
			ip4_addr3(ip), ip4_addr4(ip));
}

static void print_ip_settings(ip_addr_t *ip, ip_addr_t *mask, ip_addr_t *gw)
{
	print_ip("Board IP:       ", ip);
	print_ip("Netmask :       ", mask);
	print_ip("Gateway :       ", gw);
}

static void assign_default_ip(ip_addr_t *ip, ip_addr_t *mask, ip_addr_t *gw)
{
	int err;

	xil_printf("Configuring default IP %s \r\n", DEFAULT_IP_ADDRESS);

	err = inet_aton(DEFAULT_IP_ADDRESS, ip);
	if (!err)
		xil_printf("Invalid default IP address: %d\r\n", err);

	err = inet_aton(DEFAULT_IP_MASK, mask);
	if (!err)
		xil_printf("Invalid default IP MASK: %d\r\n", err);

	err = inet_aton(DEFAULT_GW_ADDRESS, gw);
	if (!err)
		xil_printf("Invalid default gateway address: %d\r\n", err);
}

int start;
static struct udp_pcb *pcb;

/** Receive data on a udp session */
static void udp_recv_perf_traffic(void *arg, struct udp_pcb *tpcb,
		struct pbuf *p, const ip_addr_t *addr, u16_t port)
{
	pcb->remote_ip = *addr;
	pcb->remote_port = port;
	start=1;
	pbuf_free(p);
	return;
}

void start_application(void)
{
	err_t err;
	/* Create Server PCB */
	pcb = udp_new();
	if (!pcb) {
		xil_printf("UDP server: Error creating PCB. Out of Memory\r\n");
		return;
	}
	err = udp_bind(pcb, IP_ADDR_ANY, 5001);
	if (err != ERR_OK) {
		xil_printf("UDP server: Unable to bind to port");
		xil_printf(" %d: err = %d\r\n", 5001, err);
		udp_remove(pcb);
		return;
	}
	/* specify callback to use for incoming connections */
	udp_recv(pcb, udp_recv_perf_traffic, NULL);
	return;
}

static XScuGic Intc;
static XAxiDma AxiDma;
u8 *RxBufferPtr = (u8 *) RX_BUFFER_BASE;
int main(void)
{
	start=1;
	struct netif *netif;
	int Status;
	RxDone = 1;
	Error = 0;
	unsigned int dma_loop=0;
	struct pbuf send_p;
	send_p.payload=RxBufferPtr;
	send_p.len=MAX_PKT_LEN;
    send_p.tot_len=MAX_PKT_LEN;
    send_p.flags=0;
    send_p.next=0;
    send_p.ref=1;
    send_p.type=3;

	/* the mac address of the board. this should be unique per board */
	unsigned char mac_ethernet_address[] = {
		0x00, 0x0a, 0x35, 0x00, 0x01, 0x02 };

	netif = &server_netif;

	init_platform();

	DMA_Intr_Init(&AxiDma, XPAR_AXI_DMA_0_DEVICE_ID); //DMA初始化
	Init_Intr_System(&Intc); //系统初始化
	Setup_Intr_Exception(&Intc); //使能硬件中断
	DMA_Setup_Intr_System(&Intc, &AxiDma, XPAR_FABRIC_AXI_DMA_0_S2MM_INTROUT_INTR); //注册DMA收发中断
	DMA_Intr_Enable(&Intc, &AxiDma); //使能系统中断

	/* initialize lwIP */
	lwip_init();

	/* Add network interface to the netif_list, and set it as default */
	if (!xemac_add(netif, NULL, NULL, NULL, mac_ethernet_address,
				PLATFORM_EMAC_BASEADDR)) {
		xil_printf("Error adding N/W interface\r\n");
		return -1;
	}
	netif_set_default(netif);

	/* now enable interrupts */
	platform_enable_interrupts();

	/* specify that the network if is up */
	netif_set_up(netif);
	assign_default_ip(&(netif->ip_addr), &(netif->netmask), &(netif->gw));
	print_ip_settings(&(netif->ip_addr), &(netif->netmask), &(netif->gw));

	/* print app header */
	print_app_header();

	/* start the application*/
	start_application();

	while (1) {
		if(RxDone) {
			Xil_DCacheInvalidateRange((u32) RxBufferPtr, MAX_PKT_LEN); //刷新cache,观察DDR的最新数据
	        if(start)
	        {
	        	//udp_send(pcb, &send_p);
	        	if(1)//(dma_loop%4096==0)
	        	{
	        		printf("dma_loop=%d\n",dma_loop);
	        		print_ip("remote ip is",&pcb->remote_ip);
	        	}
	        	dma_loop++;
	        }
			RxDone = 0;
			Status = XAxiDma_SimpleTransfer(&AxiDma, (u32) RxBufferPtr,MAX_PKT_LEN, XAXIDMA_DEVICE_TO_DMA);
			if (Status != XST_SUCCESS) {
				return XST_FAILURE;
				printf("dma err\n");
			}
		}
		if (TcpFastTmrFlag) {
			tcp_fasttmr();
			TcpFastTmrFlag = 0;
		}
		if (TcpSlowTmrFlag) {
			tcp_slowtmr();
			TcpSlowTmrFlag = 0;
		}
		xemacif_input(netif);
	}

	/* never reached */
	cleanup_platform();

	return 0;
}

接下来就是在matlab上获取udp数据,然后画图,代码比较简单,直接贴了

clear all;
loop=0;
while(1)
    u = udp('192.168.200.10', 5001);
    bf_size=4096;
    u.InputBufferSize = bf_size;    
    fopen(u);
    fprintf(u, 'get data:');
    A = fread(u,bf_size);
    sig=zeros(1024,1);
    for v = 0:1023
       sig(v+1)=bitshift(A(4.*v+1),0)+bitshift(A(4.*v+2),8)+bitshift(A(4.*v+3),16)+bitshift(A(4.*v+4),24);
    end
    p=figure(1);
    plot([1:1024],sig);
    title(['loop is ',num2str(loop)])
    fclose(u);
    loop=loop+1;
end

频谱仪

阅读终点,创作起航,您可以撰写心得或摘录文章要点写篇博文。去创作
  • 1
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 8
    评论
### 回答1: AD9361是一款宽带无线电频率转换器,用于软件无线电系统中。开发板则是用于快速原型设计和开发,以帮助工程师和开发人员快速上手使用AD9361芯片。开发板原理图是展示AD9361开发板电路连接和信号传输的图纸。 开发板原理图包含了AD9361芯片与其他电路组件之间的连接,以及电源和传输线路的布局。原理图通常包括芯片引脚连接、电源线路、时钟生成电路、滤波器和放大器电路等。通过原理图,开发人员可以了解到芯片在电路中的具体位置,以及与其他组件的电气连接方式。 AD9361开发板原理图一般由多个模块组成,例如基带处理模块、射频前端模块、时钟模块和控制模块等。这些模块之间存在复杂的电气连接关系,原理图能够清晰地展示出整个电路的结构和信号传输路径。 在开发过程中,开发板原理图是重要的参考资料。工程师可以根据原理图了解芯片与其他组件的连接方式,并将其转化为电路板的布局和连接线路。同时,原理图还可以作为故障排除和维修的参考,帮助工程师分析和解决问题。 总之,AD9361开发板原理图是展示AD9361芯片与其他电路组件连接、信号传输路径的图纸。它在开发过程中起着重要的作用,帮助工程师理解电路结构和信号传输关系,加快产品开发的速度。 ### 回答2: ad9361开发板原理图是一种用于无线通信系统开发的电路板。它采用了ADI公司的ad9361芯片作为主要核心器件,该芯片是一款集成了RF收发功能的高性能通信芯片。 在ad9361开发板的原理图中,主要包含了与ad9361芯片相关的外围电路和连接接口。其中包括了射频前端的接收和发送电路、时钟电路、电源管理电路、扩展接口等。这些电路的设计和连接方式都是为了实现ad9361芯片的正常工作。 在射频前端电路中,主要包括了滤波器、放大器、混频器、低噪声放大器等。它们的作用是将输入的射频信号进行滤波、放大和变频处理,以适应ad9361芯片的工作需求。 时钟电路是为ad9361芯片提供工作时钟信号。它包括了时钟发生器、时钟分频器等。通过合理的时钟设计,可以确保ad9361芯片正常运行。 电源管理电路用于为ad9361芯片和其他外围电路提供稳定的电源供应。它包括了电源滤波器、电压调节器等。这些电路可以提供稳定的电源,以保证ad9361芯片工作的可靠性和稳定性。 扩展接口是为了方便开发者进行测试和扩展。它包括了各种接口,如UART、SPI、I2C、GPIO等,可以与其他设备进行通信和数据交换。 综上所述,ad9361开发板原理图是一种用于无线通信系统开发的电路板,通过合理的设计和连接方式,实现了ad9361芯片的正常工作。它包括了射频前端电路、时钟电路、电源管理电路和扩展接口等,为开发者提供了一个方便、稳定和可扩展的开发平台。 ### 回答3: ad9361开发板原理图是指基于ad9361芯片设计的开发板的电路原理图。ad9361是ADI(Analog Devices Inc.)推出的一款高性能RF收发器芯片,广泛应用于软件无线电(SDR)领域。 原理图通常包含了ad9361芯片以及周边电路的连接方式和电路设计方案。ad9361开发板的原理图会罗列出芯片的各个引脚以及引脚之间的连接关系,方便开发者理解和调试。 通常,ad9361开发板原理图会包含以下几个部分: 1. 电源部分:包括芯片的供电方式以及与芯片相关的稳压电路、滤波电路等。 2. 时钟部分:包括芯片的时钟输入以及相关的时钟调节电路。 3. 射频部分:包括与ad9361芯片连接的射频电路,如滤波器、功率放大器、天线接口等。 4. 控制部分:包括与芯片通信的控制电路,如SPI接口、GPIO接口等。 5. 接口部分:包括与外部设备连接的接口电路,如USB接口、以太网接口、显示接口等。 以上部分构成了ad9361开发板的基本电路框架。 通过阅读ad9361开发板原理图,开发者可以了解到板上各个组件之间的电气连接方式,理解ad9361芯片与板上其他电路之间的交互关系,为后续的硬件调试和软件开发提供了重要的参考。因此,认真研究和理解ad9361开发板原理图对于开发者来说是非常重要的。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

冰冻土卫二

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值