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

news2024/11/14 16:46:58

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

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2043608.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

如何在一个页面上定位多个关键词?

我应该针对多个关键词优化我的页面吗&#xff1f; 对于大多数网站来说&#xff0c;答案都是肯定的。 如果你制定的策略是仅针对一个关键字优化你的网页&#xff0c;这可能会导致一些问题。例如&#xff0c;如果一个网页只能使用一个关键字&#xff0c;那么他们可能会开发出非…

vue2利用html2canvas+jspdf动态生成多页PDF

业务需求中&#xff0c;前端把页面上的内容导出为图片&#xff0c;pdf&#xff0c;excel是常有的事。当然&#xff0c;这些工作后端也是能做。秉着前端是万能的理念&#xff0c;今天就站在前端的角度上&#xff0c;来实现将页面内容导出为pdf&#xff0c;实现指定div内容导出&a…

【数据结构篇】~复杂度

标题【数据结构篇】~复杂度 前言 C语言已经学完了&#xff0c;不知道大家的基础都打得怎么样了&#xff1f; 无论怎么说大家还是要保持持续学习的状态&#xff0c;来迎接接下来的挑战&#xff01; 现在进入数据结构的学习了&#xff0c;希望大家还是和之前一样积极学习新知识…

ESP32人脸识别开发--人脸识别模型(六)

ESP-DL ESP-DL 为**神经网络推理**、**图像处理**、**数学运算**以及一些**深度学习模型**提供 API&#xff0c;通过 ESP-DL 能够快速便捷地将乐鑫各系列芯片产品用于人工智能应用 ESP-DL 无需借助任何外围设备&#xff0c;因此可作为一些项目的组件&#xff0c;例如可将其作…

使用Python制作贪吃蛇小游戏

引言 贪吃蛇游戏是一款经典的电子游戏&#xff0c;玩家通过控制一条不断增长的蛇在格子内移动&#xff0c;并吃掉随机出现的食物来获得分数。随着分数的增加&#xff0c;蛇的身体也会越来越长&#xff0c;游戏的难度也随之提升。在本文中&#xff0c;我们将详细介绍如何使用Py…

天途推出无人机软硬件定制服务

近年&#xff0c;随着低空经济高速发展&#xff0c;无人机已成为千行百业的生产和工作辅助工具&#xff0c;很多行业用户都有信息化数字化的软件需求&#xff0c;以及不同负载的集成设计需求。 天途拥有云平台开发、自主飞控系统、控制算法、无人机AI数据系统等核心技术研发团队…

Flink常见面试题整理

Flink常见面试题整理 文章目录 Flink常见面试题整理1. 数据倾斜问题怎么解决&#xff1f;2、什么是Flink中的窗口3、Flink中的水位线&#xff08;Watermarks&#xff09;是什么&#xff1f;4、Flink中的定时器实现机制是什么&#xff1f;有什么作用&#xff1f;5、Flink中的状态…

llama3.1本地部署方式

llama3.1 资源消耗情况 &#xfeff;Llama 3.1 - 405B、70B 和 8B 的多语言与长上下文能力解析&#xfeff; &#xfeff; 70B版本&#xff0c;FP1616K token需要的资源约为75G&#xff1b;FP16128K token需要的资源约为110G &#xfeff; 1、ollama ollama工具部署及使用…

力扣面试经典算法150题:找出字符串中第一个匹配项的下标

找出字符串中第一个匹配项的下标 今天的题目是力扣面试经典150题中的数组的简单题: 找出字符串中第一个匹配项的下标 题目链接&#xff1a;https://leetcode.cn/problems/find-the-index-of-the-first-occurrence-in-a-string/description/?envTypestudy-plan-v2&envIdto…

免费远程控制电脑的软件有哪些?

什么是远程控制&#xff1f; 远程控制是一种通过网络从一台设备操作另一台设备的技术。连接后&#xff0c;用户可以直接远程操作那台电脑进行各种操作。随着科技的不断进步和用户需求的增加&#xff0c;远程控制市场日益蓬勃。远程控制不仅应用于远程办公和远程教学&#xff0…

Windows11下wsl闪退的解决

wsl闪退 1. 原因分析 解释&#xff1a;WSL&#xff08;Windows Subsystem for Linux&#xff09;闪退通常指的是在Windows操作系统中运行的Linux环境突然关闭。这可能是由于多种原因造成的&#xff0c;包括系统资源不足、WSL配置问题、兼容性问题或者是Linux内核的问题。&…

STM32—PWR电源控制

1.PWR简介 PWR负责管理STM32内部的电源供电部分&#xff0c;可以实现可编程电压监测器和低功耗模式的功能 可编程电压监测器(PVD)可以监控VDD电源电压&#xff0c;当VDD下降到PVD阀值一下或上升到PVD阀值之上时&#xff0c;PVD会触发中断&#xff0c;用于执行紧急关闭任务 低…

HamronyOS开发5.0【埋点】方案讲解

大多数软件产品上线前&#xff0c;都会采用有规则的日志来对软件进行相关数据的采集&#xff0c;这个过程称为&#xff1a;[埋点]&#xff0c;采集的数据主要用于产品分析。 埋点技术已在PC端, 移动端非常成熟&#xff0c;并且有大批量以此为生的公司。 本篇将探究一下Harmon…

STM32—RTC实时时钟

1.Unix时间戳 Unix时间戳定义为从UTC/GMT的1970年1月1日0时0分0秒开始所经过的秒数&#xff0c;不考虑闰秒 时间戳存储在一个秒计数器中&#xff0c;秒计数器为32位/64位的整形变量 世界上所有时区的秒计数器相同&#xff0c;不同时区通过添加偏移来得到当地时间 2.时间戳转…

函数(子程序)的常见、易混淆概念详解【对初学者有帮助】

C语⾔中的函数也被称做子程序&#xff0c;意思就是⼀个完成某项特定的任务的⼀小段代码。 C语⾔标准中提供了许多库函数&#xff0c;点击下面的链接可以查看c语言的库函数和头文件。 C/C官⽅的链接&#xff1a;https://zh.cppreference.com/w/c/header 目录 一、函数头与函…

VsCode配置Cph实现高效刷题教程

cph作用 : 自动创建文件自动获取题目案例自动测试样例自动配置模板 在vscode中安装cph插件 : 在扩展的搜素框中输入Competitive Programming Helper(cph)&#xff0c;点击下载即可 在浏览器中安装Competitive Companion 浏览器插件 这里推荐离线下载 : 网址 : Competit…

2024/8/15 不上电测伺服端子是否正常

拿3线220V举例&#xff0c;拿两种测量表举例&#xff0c;下图均为正常情况 L1和L2测量&#xff0c;L3不用管&#xff08;空的&#xff09;。 1.先测输入L1/2是否短路&#xff0c;输出UVW是短路为正常&#xff08;与变频器相反&#xff09; 2.正&#xff08;红&#xff09;—RS…

PL/SQL是什么软件 PL/SQL最新版本功能介绍

PL/SQL是什么软件&#xff1f;PL/SQL软件多指PL/SQL Developer&#xff0c;这是一款专业的PL/SQL开发工具&#xff0c;它可以帮助开发者编写、调试和优化PL/SQL代码&#xff0c;提高开发效率和质量。本文将介绍PL/SQL Developer 15最新版本的主要功能和特点。 一、PL/SQL是什么…

华为od统一考试B卷【比赛】python实现

def split_params(param_str): return list(map(int, param_str.split(,))) def main(): # 获取输入 target_str input().strip() # 输入验证&#xff0c;拆分并转换为整数 try: m, n split_params(target_str) except ValueError: print(-1) return # 检查 M 和 …

opencascade Adaptor3d_Curve源码学习

opencascade Adaptor3d_Curve 前言 用于几何算法工作的3D曲线的根类。 适配曲线是曲线提供的服务与使用该曲线的算法所需服务之间的接口。 提供了两个派生具体类&#xff1a; GeomAdaptor_Curve&#xff0c;用于Geom包中的曲线Adaptor3d_CurveOnSurface&#xff0c;用于Geom包…