【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

相关文章

部署Vue项目到服务器后404错误的原因及解决方案

《部署Vue项目到服务器后404错误的原因及解决方案》文章介绍了Vue项目部署步骤以及404错误的解决方案,部署步骤包括构建项目、上传文件、配置Web服务器、重启Nginx和访问域名,404错误通常是... 目录一、vue项目部署步骤二、404错误原因及解决方案错误场景原因分析解决方案一、Vue项目部署步骤

golang内存对齐的项目实践

《golang内存对齐的项目实践》本文主要介绍了golang内存对齐的项目实践,内存对齐不仅有助于提高内存访问效率,还确保了与硬件接口的兼容性,是Go语言编程中不可忽视的重要优化手段,下面就来介绍一下... 目录一、结构体中的字段顺序与内存对齐二、内存对齐的原理与规则三、调整结构体字段顺序优化内存对齐四、内

配置springboot项目动静分离打包分离lib方式

《配置springboot项目动静分离打包分离lib方式》本文介绍了如何将SpringBoot工程中的静态资源和配置文件分离出来,以减少jar包大小,方便修改配置文件,通过在jar包同级目录创建co... 目录前言1、分离配置文件原理2、pom文件配置3、使用package命令打包4、总结前言默认情况下,

python实现简易SSL的项目实践

《python实现简易SSL的项目实践》本文主要介绍了python实现简易SSL的项目实践,包括CA.py、server.py和client.py三个模块,文中通过示例代码介绍的非常详细,对大家的学习... 目录运行环境运行前准备程序实现与流程说明运行截图代码CA.pyclient.pyserver.py参

IDEA运行spring项目时,控制台未出现的解决方案

《IDEA运行spring项目时,控制台未出现的解决方案》文章总结了在使用IDEA运行代码时,控制台未出现的问题和解决方案,问题可能是由于点击图标或重启IDEA后控制台仍未显示,解决方案提供了解决方法... 目录问题分析解决方案总结问题js使用IDEA,点击运行按钮,运行结束,但控制台未出现http://

解决IDEA使用springBoot创建项目,lombok标注实体类后编译无报错,但是运行时报错问题

《解决IDEA使用springBoot创建项目,lombok标注实体类后编译无报错,但是运行时报错问题》文章详细描述了在使用lombok的@Data注解标注实体类时遇到编译无误但运行时报错的问题,分析... 目录问题分析问题解决方案步骤一步骤二步骤三总结问题使用lombok注解@Data标注实体类,编译时

C语言小项目实战之通讯录功能

《C语言小项目实战之通讯录功能》:本文主要介绍如何设计和实现一个简单的通讯录管理系统,包括联系人信息的存储、增加、删除、查找、修改和排序等功能,文中通过代码介绍的非常详细,需要的朋友可以参考下... 目录功能介绍:添加联系人模块显示联系人模块删除联系人模块查找联系人模块修改联系人模块排序联系人模块源代码如下

SpringBoot项目中Maven剔除无用Jar引用的最佳实践

《SpringBoot项目中Maven剔除无用Jar引用的最佳实践》在SpringBoot项目开发中,Maven是最常用的构建工具之一,通过Maven,我们可以轻松地管理项目所需的依赖,而,... 目录1、引言2、Maven 依赖管理的基础概念2.1 什么是 Maven 依赖2.2 Maven 的依赖传递机

Vue项目中Element UI组件未注册的问题原因及解决方法

《Vue项目中ElementUI组件未注册的问题原因及解决方法》在Vue项目中使用ElementUI组件库时,开发者可能会遇到一些常见问题,例如组件未正确注册导致的警告或错误,本文将详细探讨这些问题... 目录引言一、问题背景1.1 错误信息分析1.2 问题原因二、解决方法2.1 全局引入 Element

Python 中 requests 与 aiohttp 在实际项目中的选择策略详解

《Python中requests与aiohttp在实际项目中的选择策略详解》本文主要介绍了Python爬虫开发中常用的两个库requests和aiohttp的使用方法及其区别,通过实际项目案... 目录一、requests 库二、aiohttp 库三、requests 和 aiohttp 的比较四、requ