【FPGA项目】bin文件ram存取回环测试

2024-06-14 07:36

本文主要是介绍【FPGA项目】bin文件ram存取回环测试,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

🎉欢迎来到FPGA专栏~bin文件ram存取回环测试


  • ☆* o(≧▽≦)o *☆~我是小夏与酒🍹
  • 博客主页:小夏与酒的博客
  • 🎈该系列文章专栏:FPGA学习之旅
  • 文章作者技术和水平有限,如果文中出现错误,希望大家能指正🙏
  • 📜 欢迎大家关注! ❤️
    FPGQ2

CSDN

🎉 目录-bin文件ram存取回环测试

  • 一、效果演示
    • 🥝演示视频
    • 🥝结果分析
  • 二、说明
  • 三、bin文件的生成
    • 🔸bin文件介绍
    • 🔸为什么使用bin文件作为数据载体发送给FPGA
    • 🔸matlab生成bin文件
  • 四、串口收发模块
  • 五、回环系统搭建
    • 🍍系统功能描述
    • 🍍ram ip核设置
    • 🍍RTL视图
    • 🍍系统完整代码

遇见未来

一、效果演示

使用matlab生成1001-10032位随机整型数据,并将数据保存为bin文件;通过带有bin文件收发功能的串口调试助手发送给FPGA,再接收FPGA的回环数据。

🥝演示视频

演示视频-【FPGA】bin文件ram存取回环测试

🥝结果分析

matlab生成的随机数:
生成

串口助手接收结果:
结果
分析:
将串口助手接收框内的数据转换成10进制,并与matlab生成的数据进行对比,数值一致;串口助手接收框内的有效数据个数为100个,与matlab生成的数据个数一致;接收框内最后出现了FF,这个数据并不是bin文件中的数据,而是串口助手最后发送给FPGA的发送指令,该指令也被存入到了ram中(为了避免该现象的出现,可以在FPGA中对数据进行相关的判断处理,或者使用vio进行控制,即可解决)。

二、说明

需要该项目中的串口助手软件或者项目工程文件的小伙伴,直接加入QQ群,在群文件中搜索下载即可QQ群862135231
matlab版本:R2020b
vivado版本:2020.2
开发板型号:AXKU040
接口连接如下所示:
接口

三、bin文件的生成

🔸bin文件介绍

bin文件是二进制文件的缩写,通常用于存储计算机程序或数据。它们可以包含各种类型的信息,例如操作系统、应用程序和媒体文件。bin文件是计算机系统中最基本的文件类型之一,通常需要特定的软件才能打开和读取。
不同类型的bin文件可能需要不同的软件来打开,例如,图像bin文件可能需要图像查看器来打开,而文档bin文件可能需要文本编辑器来打开。

重点在这:
bin文件可以储存大量数据的二进制形式!

🔸为什么使用bin文件作为数据载体发送给FPGA

ChatGPT的回答:
bin文件作为一种固定的二进制数据格式,具有以下优点,使其成为向FPGA发送数据的常用载体:

  1. 紧凑性:bin文件通常比其他格式更紧凑,减少了数据传输的带宽和存储空间需求。
  2. 高效性:FPGA可以直接读取和处理二进制数据,而不需要进行格式转换,提高了数据处理的效率
  3. 准确性:bin文件中的数据以精确的二进制形式表示,确保了数据的准确性和完整性。
  4. 通用性:bin文件是一种广泛使用的格式,可以在不同的系统和硬件平台之间进行传输和使用。

🔸matlab生成bin文件

运行如下代码,会在matlab脚本的根目录下生成bin文件:

%% bin文件生成代码
%----------------------------------------------------
% 首先生成1-100的double类型随机整数;
% 将double类型随机整数转换为32位数据;
% 将转换后的数据保存为bin文件。
%----------------------------------------------------
clear;
clc;
close all;
% 生成1-100的double类型随机整数
random_numbers = randi([1 100], 1, 100);% 将double类型数据转换为uint32类型
random_numbers_uint32 = uint32(random_numbers);% 将数据保存为bin文件
fid = fopen('random_numbers.bin', 'wb');
fwrite(fid, random_numbers_uint32, 'uint32');
fclose(fid);disp('随机数已生成并保存为 random_numbers.bin');

四、串口收发模块

关于串口收发模块的详细讲解,请点击如下两篇文章进行学习:
串口发送模块:【FPGA零基础学习之旅#13】串口发送模块设计与验证;
串口接收模块:【FPGA零基础学习之旅#15】串口接收模块设计与验证(工业环境)。

在此附上模块代码:

串口发送模块:

//
//模块名称:串口发送模块
//
module uart_byte_tx(input 		Clk,input 		Rst_n,input [7:0]	data_byte,input 		send_en,input [2:0]	baud_set,output reg uart_tx,output reg Tx_Done,output reg uart_state
);reg bps_clk;//波特率时钟reg [15:0]div_cnt;//分频计数器reg [15:0]bps_DR;//分频计数最大值reg [3:0]bps_cnt;//波特率计数时钟//定义数据的起始位和停止位localparam START_BIT = 1'b0;localparam STOP_BIT  = 1'b1;reg [7:0]r_data_byte;//数据寄存器//--------<uart状态模块>--------	always@(posedge Clk or negedge Rst_n)beginif(!Rst_n)uart_state <= 1'b0;else if(send_en)uart_state <= 1'b1;else if(bps_cnt == 4'd11)//bps_cnt计数达到11次,即发送结束uart_state <= 1'b0;elseuart_state <= uart_state;end//--------<使能分频计数模块>-------	
//	assign en_cnt = uart_state;//--------<寄存待发送的数据,使数据保持稳定>--------always@(posedge Clk or negedge Rst_n)beginif(!Rst_n)r_data_byte <= 8'd0;else if(send_en)r_data_byte <= data_byte;elser_data_byte <= r_data_byte;end//--------<波特率查找表>--------		always@(posedge Clk or negedge Rst_n)beginif(!Rst_n)bps_DR <= 16'd5207;else begincase(baud_set)0:bps_DR <= 16'd5207;1:bps_DR <= 16'd2603;2:bps_DR <= 16'd1301;3:bps_DR <= 16'd867;4:bps_DR <= 16'd433;default:bps_DR <= 16'd5207;endcaseend	end//--------<Div_Cnt模块>--------	
//得到不同计数周期的计数器always@(posedge Clk or negedge Rst_n)beginif(!Rst_n)div_cnt <= 16'd0;else if(uart_state)begin	//	assign en_cnt = uart_state;if(div_cnt == bps_DR)div_cnt <= 16'd0;elsediv_cnt <= div_cnt + 1'b1;endelsediv_cnt <= 16'd0;end
//--------<bps_clk信号的产生>--------	always@(posedge Clk or negedge Rst_n)beginif(!Rst_n)bps_clk <= 1'b0;else if(div_cnt == 16'd1)bps_clk <= 1'b1;elsebps_clk <= 1'b0;end//--------<bps_cnt计数模块>--------		always@(posedge Clk or negedge Rst_n)beginif(!Rst_n)bps_cnt <= 4'd0;else if(bps_cnt == 4'd11)//clr信号bps_cnt <= 4'd0;else if(bps_clk)bps_cnt <= bps_cnt + 1'b1;elsebps_cnt <= bps_cnt;end//--------<Tx_Done模块>--------	always@(posedge Clk or negedge Rst_n)beginif(!Rst_n)Tx_Done <= 1'b0;else if(bps_cnt == 4'd11)Tx_Done <= 1'b1;elseTx_Done <= 1'b0;end//--------<数据位输出模块-10选1多路器>--------	always@(posedge Clk or negedge Rst_n)beginif(!Rst_n)uart_tx <= 1'b1;else begincase(bps_cnt)0:uart_tx <= 1'b1;1:uart_tx <= START_BIT;2:uart_tx <= r_data_byte[0];3:uart_tx <= r_data_byte[1];4:uart_tx <= r_data_byte[2];5:uart_tx <= r_data_byte[3];6:uart_tx <= r_data_byte[4];7:uart_tx <= r_data_byte[5];8:uart_tx <= r_data_byte[6];9:uart_tx <= r_data_byte[7];10:uart_tx <= STOP_BIT;default:uart_tx <= 1'b1;endcaseendendendmodule

串口接收模块:

//
//模块名称:串口接收模块(工业环境)
//
module uart_byte_rx(input 					Clk,//50Minput 					Rst_n,input 			[2:0]	baud_set,input 					data_rx,output 	reg 	[7:0]	data_byte,output 	reg			Rx_Done
);reg s0_Rx,s1_Rx;//同步寄存器reg tmp0_Rx,tmp1_Rx;//数据寄存器reg [15:0]bps_DR;//分频计数器计数最大值reg [15:0]div_cnt;//分频计数器reg bps_clk;//波特率时钟reg [7:0]bps_cnt;reg uart_state;reg [2:0] r_data_byte [7:0];reg [2:0]START_BIT;reg [2:0]STOP_BIT;wire nedge;//--------<同步寄存器处理>--------		
//用于消除亚稳态always@(posedge Clk or negedge Rst_n)beginif(!Rst_n)begins0_Rx <= 1'b0;s1_Rx <= 1'b0;endelse begins0_Rx <= data_rx;s1_Rx <= s0_Rx;endend//--------<数据寄存器处理>--------		always@(posedge Clk or negedge Rst_n)beginif(!Rst_n)begintmp0_Rx <= 1'b0;tmp1_Rx <= 1'b0;endelse begintmp0_Rx <= s1_Rx;tmp1_Rx <= tmp0_Rx;endend//--------<下降沿检测>--------	assign nedge = !tmp0_Rx & tmp1_Rx;//--------<div_cnt模块>--------	
//得到不同计数周期的计数器always@(posedge Clk or negedge Rst_n)beginif(!Rst_n)div_cnt <= 16'd0;else if(uart_state)beginif(div_cnt == bps_DR)div_cnt <= 16'd0;elsediv_cnt <= div_cnt + 1'b1;endelsediv_cnt <= 16'd0;end
//--------<bps_clk信号的产生>--------	always@(posedge Clk or negedge Rst_n)beginif(!Rst_n)bps_clk <= 1'b0;else if(div_cnt == 16'd1)bps_clk <= 1'b1;elsebps_clk <= 1'b0;end//--------<bps_clk计数模块>--------		always@(posedge Clk or negedge Rst_n)beginif(!Rst_n)bps_cnt <= 8'd0;else if(bps_cnt == 8'd159 || (bps_cnt == 8'd12 && (START_BIT > 2)))bps_cnt <= 8'd0;else if(bps_clk)bps_cnt <= bps_cnt + 1'b1;elsebps_cnt <= bps_cnt;end//--------<Rx_Done模块>--------	always@(posedge Clk or negedge Rst_n)beginif(!Rst_n)Rx_Done <= 1'b0;else if(bps_cnt == 8'd159)Rx_Done <= 1'b1;elseRx_Done <= 1'b0;end	//--------<波特率查找表>--------		always@(posedge Clk or negedge Rst_n)beginif(!Rst_n)bps_DR <= 16'd324;else begincase(baud_set)0:bps_DR <= 16'd324;1:bps_DR <= 16'd162;2:bps_DR <= 16'd80;3:bps_DR <= 16'd53;4:bps_DR <= 16'd26;default:bps_DR <= 16'd324;endcaseend	end//--------<采样数据接收模块>--------	always@(posedge Clk or negedge Rst_n)beginif(!Rst_n)beginSTART_BIT <= 3'd0;r_data_byte[0] <= 3'd0; r_data_byte[1] <= 3'd0;r_data_byte[2] <= 3'd0; r_data_byte[3] <= 3'd0;r_data_byte[4] <= 3'd0; r_data_byte[5] <= 3'd0;r_data_byte[6] <= 3'd0; r_data_byte[7] <= 3'd0;STOP_BIT <= 3'd0;endelse if(bps_clk)begincase(bps_cnt)0:beginSTART_BIT <= 3'd0;r_data_byte[0] <= 3'd0;r_data_byte[1] <= 3'd0;r_data_byte[2] <= 3'd0;r_data_byte[3] <= 3'd0;r_data_byte[4] <= 3'd0;r_data_byte[5] <= 3'd0;r_data_byte[6] <= 3'd0;r_data_byte[7] <= 3'd0;STOP_BIT <= 3'd0; end6,7,8,9,10,11:START_BIT <= START_BIT + s1_Rx;22,23,24,25,26,27:r_data_byte[0] <= r_data_byte[0] + s1_Rx;38,39,40,41,42,43:r_data_byte[1] <= r_data_byte[1] + s1_Rx;54,55,56,57,58,59:r_data_byte[2] <= r_data_byte[2] + s1_Rx;70,71,72,73,74,75:r_data_byte[3] <= r_data_byte[3] + s1_Rx;86,87,88,89,90,91:r_data_byte[4] <= r_data_byte[4] + s1_Rx;102,103,104,105,106,107:r_data_byte[5] <= r_data_byte[5] + s1_Rx;118,119,120,121,122,123:r_data_byte[6] <= r_data_byte[6] + s1_Rx;134,135,136,137,138,139:r_data_byte[7] <= r_data_byte[7] + s1_Rx;150,151,152,153,154,155:STOP_BIT <= STOP_BIT + s1_Rx;default:beginSTART_BIT <= START_BIT;r_data_byte[0] <= r_data_byte[0];r_data_byte[1] <= r_data_byte[1];r_data_byte[2] <= r_data_byte[2];r_data_byte[3] <= r_data_byte[3];r_data_byte[4] <= r_data_byte[4];r_data_byte[5] <= r_data_byte[5];r_data_byte[6] <= r_data_byte[6];r_data_byte[7] <= r_data_byte[7];STOP_BIT <= STOP_BIT;endendcaseendend//--------<数据状态判定模块>--------	always@(posedge Clk or negedge Rst_n)beginif(!Rst_n)data_byte <= 8'd0;else if(bps_cnt == 8'd159)begindata_byte[0] <= r_data_byte[0][2];data_byte[1] <= r_data_byte[1][2];data_byte[2] <= r_data_byte[2][2];data_byte[3] <= r_data_byte[3][2];data_byte[4] <= r_data_byte[4][2];data_byte[5] <= r_data_byte[5][2];data_byte[6] <= r_data_byte[6][2];data_byte[7] <= r_data_byte[7][2];endelse;end//--------<uart_state模块>--------	always@(posedge Clk or negedge Rst_n)beginif(!Rst_n)uart_state <= 1'b0;else if(nedge)uart_state <= 1'b1;else if(Rx_Done || (bps_cnt == 8'd12 && (START_BIT > 2)))uart_state <= 1'b0;elseuart_state <= uart_state;endendmodule

五、回环系统搭建

🍍系统功能描述

系统串口波特率设置为115200

功能描述: 为了避免使用按键等作为触发或者控制信号,本项目使用串口指令控制整个系统的运行,因此设置了十六进制的feff指令。通过串口助手发送十六进制的fe指令使能ram的储存,再通过发送十六进制的ff指令让FPGA将ram中的数据通过串口发送出来。

🍍ram ip核设置

选择普通双端口类型:
ram1
由于串口接收到的数据位宽都是8位,将ram的输入端口设置为8位便于存储和控制,深度选择为2048,一直使能:
ram2
ram中的数据也是直接通过串口输出,因此输出端口的数据位宽也设置为8位便于控制和读取,选择使用使能引脚控制ram读取数据:
ram3
Summary中可以看到每个端口访问数据的地址位宽:
ram4

🍍RTL视图

RTL

🍍系统完整代码

uart_top.v:

`timescale 1ns / 1psmodule uart_top(input 	sys_clk_p,input 	sys_clk_n,input 	rst_n,input 	uart_rx,output 	uart_tx
);localparam baud_set = 3'b100;wire locked;wire clk_r;wire clk;wire [7:0] data_byte;reg En;reg send_en;reg [11-1:0] data_in_cnt;wire Rx_Done;wire write_en;reg [10:0] addrb;wire read_en;wire [7:0] data_byte_tx;clk50MHz instance_name(// Clock out ports.clk_out1(clk_r),     // output clk_out1// Status and control signals.reset(!rst_n), // input reset.locked(locked),       // output locked// Clock in ports.clk_in1_p(sys_clk_p),    // input clk_in1_p.clk_in1_n(sys_clk_n));    // input clk_in1_nassign clk = (locked)?clk_r:1'b0;uart_byte_rx inst_uart_byte_rx(.Clk       (clk),.Rst_n     (rst_n),.baud_set  (baud_set),.data_rx   (uart_rx),.data_byte (data_byte),.Rx_Done   (Rx_Done));//--------------------<system_ctrl>--------------------------------always@(posedge clk or negedge rst_n)beginif(!rst_n)En <= 1'b0;else if(data_byte == 8'hfe)En <= 1'b1;elseEn <= En;endalways@(posedge clk or negedge rst_n)beginif(!rst_n)send_en <= 1'b0;else if(data_byte == 8'hff && addrb < 11'd2000)send_en <= 1'b1;else if(addrb == 11'd2000)send_en <= 1'b0;elsesend_en <= send_en;end
//-----------------------------------------------------------------//--------------------<data_in_cnt>--------------------------------always@(posedge clk or negedge rst_n)beginif(!rst_n)data_in_cnt <= 11'd0;else if((En) && (data_in_cnt < 11'd2047) && Rx_Done)data_in_cnt <= data_in_cnt + 1'b1;else if(data_in_cnt == 11'd2047)data_in_cnt <= 11'd0;elsedata_in_cnt <= data_in_cnt;end
//-----------------------------------------------------------------assign write_en = (En && !(send_en))?1'b1:1'b0;ram_ip ram_8_2048_8(.clka	(clk),    // input wire clka.wea	(write_en),      // input wire [0 : 0] wea.addra	(data_in_cnt),  // input wire [10 : 0] addra.dina	(data_byte),    // input wire [7 : 0] dina.clkb	(clk),    // input wire clkb.enb	(read_en),      // input wire enb.addrb	(addrb),  // input wire [10 : 0] addrb.doutb	(data_byte_tx)  // output wire [7 : 0] doutb);assign read_en = (send_en && Tx_Done)?1'b1:1'b0;always@(posedge clk or negedge rst_n)beginif(!rst_n)addrb <= 11'd0;else if(Tx_Done)addrb <= addrb + 1'b1;elseaddrb <= addrb;enduart_byte_tx inst_uart_byte_tx(.Clk        (clk),.Rst_n      (rst_n),.data_byte  (data_byte_tx),.send_en    (send_en),.baud_set   (baud_set),.uart_tx    (uart_tx),.Tx_Done    (Tx_Done),.uart_state ());endmodule

csdn

🧸结尾


  • ❤️ 感谢您的支持和鼓励! 😊🙏
  • 📜您可能感兴趣的内容:
  • 【FPGA零基础学习之旅#17】搭建串口收发与储存双口RAM系统
  • 【Python】串口通信-与FPGA、蓝牙模块实现串口通信(Python+FPGA)
  • 【Arduino TinyGo】【最新】使用Go语言编写Arduino-环境搭建和点亮LED灯
  • 【全网首发开源教程】【Labview机器人仿真与控制】Labview与Solidworks多路支配关系-四足爬行机器人仿真与控制
    遇见未来

这篇关于【FPGA项目】bin文件ram存取回环测试的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1059772

相关文章

一文教你如何将maven项目转成web项目

《一文教你如何将maven项目转成web项目》在软件开发过程中,有时我们需要将一个普通的Maven项目转换为Web项目,以便能够部署到Web容器中运行,本文将详细介绍如何通过简单的步骤完成这一转换过程... 目录准备工作步骤一:修改​​pom.XML​​1.1 添加​​packaging​​标签1.2 添加

tomcat多实例部署的项目实践

《tomcat多实例部署的项目实践》Tomcat多实例是指在一台设备上运行多个Tomcat服务,这些Tomcat相互独立,本文主要介绍了tomcat多实例部署的项目实践,具有一定的参考价值,感兴趣的可... 目录1.创建项目目录,测试文China编程件2js.创建实例的安装目录3.准备实例的配置文件4.编辑实例的

springboot集成Deepseek4j的项目实践

《springboot集成Deepseek4j的项目实践》本文主要介绍了springboot集成Deepseek4j的项目实践,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价... 目录Deepseek4j快速开始Maven 依js赖基础配置基础使用示例1. 流式返回示例2. 进阶

SpringBoot项目启动报错"找不到或无法加载主类"的解决方法

《SpringBoot项目启动报错找不到或无法加载主类的解决方法》在使用IntelliJIDEA开发基于SpringBoot框架的Java程序时,可能会出现找不到或无法加载主类com.example.... 目录一、问题描述二、排查过程三、解决方案一、问题描述在使用 IntelliJ IDEA 开发基于

SpringBoot项目使用MDC给日志增加唯一标识的实现步骤

《SpringBoot项目使用MDC给日志增加唯一标识的实现步骤》本文介绍了如何在SpringBoot项目中使用MDC(MappedDiagnosticContext)为日志增加唯一标识,以便于日... 目录【Java】SpringBoot项目使用MDC给日志增加唯一标识,方便日志追踪1.日志效果2.实现步

Ubuntu中Nginx虚拟主机设置的项目实践

《Ubuntu中Nginx虚拟主机设置的项目实践》通过配置虚拟主机,可以在同一台服务器上运行多个独立的网站,本文主要介绍了Ubuntu中Nginx虚拟主机设置的项目实践,具有一定的参考价值,感兴趣的可... 目录简介安装 Nginx创建虚拟主机1. 创建网站目录2. 创建默认索引文件3. 配置 Nginx4

SpringBoot项目启动错误:找不到或无法加载主类的几种解决方法

《SpringBoot项目启动错误:找不到或无法加载主类的几种解决方法》本文主要介绍了SpringBoot项目启动错误:找不到或无法加载主类的几种解决方法,具有一定的参考价值,感兴趣的可以了解一下... 目录方法1:更改IDE配置方法2:在Eclipse中清理项目方法3:使用Maven命令行在开发Sprin

Nginx实现高并发的项目实践

《Nginx实现高并发的项目实践》本文主要介绍了Nginx实现高并发的项目实践,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧... 目录使用最新稳定版本的Nginx合理配置工作进程(workers)配置工作进程连接数(worker_co

Vue项目的甘特图组件之dhtmlx-gantt使用教程和实现效果展示(推荐)

《Vue项目的甘特图组件之dhtmlx-gantt使用教程和实现效果展示(推荐)》文章介绍了如何使用dhtmlx-gantt组件来实现公司的甘特图需求,并提供了一个简单的Vue组件示例,文章还分享了一... 目录一、首先 npm 安装插件二、创建一个vue组件三、业务页面内 引用自定义组件:四、dhtmlx

SpringBoot项目注入 traceId 追踪整个请求的日志链路(过程详解)

《SpringBoot项目注入traceId追踪整个请求的日志链路(过程详解)》本文介绍了如何在单体SpringBoot项目中通过手动实现过滤器或拦截器来注入traceId,以追踪整个请求的日志链... SpringBoot项目注入 traceId 来追踪整个请求的日志链路,有了 traceId, 我们在排