【以太网通信】RS232 串口转以太网

最近和 RK 研发同事在调试通信接口,排查与定位 RK3399 接收数据出错的问题。FPGA 与 RK3399 之间使用一路 RS232 串口进行通信,由于串口数据没有分包,不方便排查问题,想到可以开发一个 RS232 串口转以太网的工具,将串口接收到的数据封装为 UDP 数据报文,并通过网线传输到电脑,再进行后续问题的定位。

以下是串口转以太网工具,调试的效果图。

 

目录

1 模块设计

1.1 串口接收模块

1.2 以太网发送模块

2 上板调试


1 模块设计

1.1 串口接收模块

 

        串口接收模块电路需要实现的功能包括:

(1)串口数据接收;

(2)串口数据缓存。

        uart_rx_slice 是串口底层模块,负责接收单个 byte 数据。规定串口每帧传输的数据长度不超过 2048,需要例化一个深度为 4096,位宽为 8bit 的 Block RAM,并实现串口数据的乒乓缓存。

 

top_uart 模块代码:

`timescale 1ns / 1ps

module top_uart #(
   parameter       FREQ_SYS_CLK    = 32'd200_000_000,
   parameter       BAUD_RATE       = 32'd256_000     
)(
   // System level
   input           sys_rst         ,
   input           sys_clk         ,

   // Uart received data flow
   output [7:0]    uart_rcv_data   ,
   output          uart_rcv_valid  ,

   // Uart Interface
   input           uart_rxd        ,
   output          uart_txd        
);

wire               frame_ss        ;
wire [7:0]         rcv_data        ;
wire               rcv_valid       ;

reg                frame_ss_r1     ;
reg                frame_ss_r2     ;
reg  [7:0]         blk_mem_wdata   ;
reg  [11:0]        blk_mem_waddr   ;
reg  [11:0]        blk_mem_waddr_r ;
reg  [0:0]         blk_mem_wren    ;
reg                blk_mem_rd_busy ;
reg  [11:0]        blk_mem_raddr   ;
wire [7:0]         blk_mem_rdata   ;
reg                blk_mem_rdvld   ;

// uart_rx_slice: Uart receive module
uart_rx_slice uart_rx_slice_inst (
   .sys_rst        (sys_rst       ), // input
   .sys_clk        (sys_clk       ), // input
   .frame_ss       (frame_ss      ), // output
   .rcv_data       (rcv_data      ), // output
   .rcv_valid      (rcv_valid     ), // output
   .uart_rxd       (uart_rxd      )  // input
);

defparam uart_rx_slice_inst.FREQ_SYS_CLK = FREQ_SYS_CLK;
defparam uart_rx_slice_inst.BAUD_RATE    = BAUD_RATE;
// End of uart_rx_slice instantiation

// blk_mem_4096x8b: Block Memory generator
blk_mem_4096x8b blk_mem_4096x8b_inst (
   .clka          (sys_clk        ), // input
   .ena           (1'b1           ), // input
   .wea           (blk_mem_wren   ), // input
   .addra         (blk_mem_waddr  ), // input
   .dina          (blk_mem_wdata  ), // input
   .clkb          (sys_clk        ), // input
   .rstb          (sys_rst        ), // input
   .enb           (1'b1           ), // input
   .addrb         (blk_mem_raddr  ), // input
   .doutb         (blk_mem_rdata  ), // output
   .rsta_busy     (               ), // output
   .rstb_busy     (               )  // output
);
// End of blk_mem_4096x8b_inst instantiation

always @(posedge sys_rst or posedge sys_clk) begin
   if (sys_rst == 1'b1) begin
      frame_ss_r1 <= 1'b0;
      frame_ss_r2 <= 1'b0;
   end
   else begin
      frame_ss_r1 <= frame_ss;
      frame_ss_r2 <= frame_ss_r1;
   end
end

always @(posedge sys_rst or posedge sys_clk) begin
   if (sys_rst == 1'b1) begin
      blk_mem_waddr <= 12'd0;
      blk_mem_wdata <= 8'd0;
      blk_mem_wren  <= 1'b0;
   end
   else begin
      blk_mem_wdata <= rcv_data;
      blk_mem_wren[0] <= rcv_valid;

      if (frame_ss_r2 == 1'b1 && frame_ss_r1 == 1'b0) begin
         blk_mem_waddr[11] <= ~blk_mem_waddr[11];
         blk_mem_waddr[10:0] <= {11{1'b0}};
      end
      else if (blk_mem_wren[0] == 1'b1) begin
         blk_mem_waddr[11] <= blk_mem_waddr[11];
         blk_mem_waddr[10:0] <= blk_mem_waddr[10:0] + 1'b1;
      end
   end
end

always @(posedge sys_rst or posedge sys_clk) begin
   if (sys_rst == 1'b1) begin
      blk_mem_waddr_r <= 12'd0;
      blk_mem_raddr   <= 12'd0;
      blk_mem_rd_busy <= 1'b0;
      blk_mem_rdvld   <= 1'b0;
   end
   else begin
      if (blk_mem_rd_busy == 1'b0 && frame_ss_r2 == 1'b1 && frame_ss_r1 == 1'b0) begin
         blk_mem_waddr_r <= blk_mem_waddr - 1'b1;
         blk_mem_rd_busy <= 1'b1;
      end
      else if (blk_mem_rd_busy == 1'b1) begin
         if (blk_mem_raddr == blk_mem_waddr_r) begin
            blk_mem_raddr[11] <= ~blk_mem_raddr[11];
            blk_mem_raddr[10:0] <= {11{1'b0}};
            blk_mem_rd_busy <= 1'b0;
         end
         else begin
            blk_mem_raddr[11] <= blk_mem_raddr[11];
            blk_mem_raddr[10:0] <= blk_mem_raddr[10:0] + 1'b1;
         end
      end
      blk_mem_rdvld <= blk_mem_rd_busy;
   end
end

assign uart_rcv_data  = blk_mem_rdata;
assign uart_rcv_valid = blk_mem_rdvld;

endmodule

1.2 以太网发送模块

        以太网网络层使用 IPv4 协议,传输层使用 UDP 协议。

以太网发送模块电路需要实现的功能包括:

(1)IPv4 与 UDP 协议校验;

(2)以太网帧组帧(包括 CRC 校验);

(3)GMII 与 RGMII 桥接。

        同样例化一个深度为 4096,位宽为 8bit 的 Block RAM,实现以太网帧数据的乒乓缓存,在初始化文件中写入以太网帧头,MAC 地址等信息。

使用 Python 代码生成 coe 文件,代码如下:

# 以太网帧头数据
f = b'\x55\x55\x55\x55\x55\x55\x55\xd5\xd4\x5d\x64\xad\x16\x47\x11\x22\x33\x44\x55\x66\x08\x00\x45\x00\x00\x00\x00\x00\x40\x00\x40\x11\xff\xff\xc0\xa8\x01\x08\xc0\xa8\x01\x09\x1f\x90\x1f\x90\x00\x00\x00\x00'
raw_data = list(map(lambda e: "{:02X}".format(e), f))

while len(raw_data) < 2048:
   raw_data.append('00')

# 写入coe文件
with open('blk_mem_4096x8b_MAC.coe', 'w') as f:
   f.write('memory_initialization_radix = 16;\n')
   f.write('memory_initialization_vector = \n')
   for i,e in enumerate(raw_data*2):
      if i != len(raw_data*2)-1:
         f.write("{:s},\n".format(e))
      else:
         f.write("{:s};".format(e))

 

在 IP 核配置界面,选择 coe 初始化文件,点击 Edit 查看数据。

 

top_ethernet 模块代码:

`timescale 1ns / 1ps

module top_ethernet #(
   parameter       local_ip_addr   = 32'hC0A80109,
   parameter       remote_ip_addr  = 32'hC0A8010A,
   parameter       local_udp_port  = 16'h1F90,
   parameter       remote_udp_port = 16'h1F90
)(
   // System level
   input           sys_rst         ,
   input           sys_clk         ,

   // RGMII Interface
   input           rgmii_rxc       ,
   input  [3:0]    rgmii_rxd       ,
   input           rgmii_rx_ctl    ,
   output          rgmii_txc       ,
   output [3:0]    rgmii_txd       ,
   output          rgmii_tx_ctl    ,

   // UDP data input ports
   input  [7:0]    eth_udp_txd     ,
   input           eth_udp_txen     
);

wire               gmii_tx_clk;
wire [7:0]         eth_mac_txd;
wire               eth_mac_txen;

// mac_tx_slice: MAC data pack and transmit module
mac_tx_slice mac_tx_slice_inst(
   .sys_rst        (sys_rst        ), // input
   .sys_clk        (sys_clk        ), // input
   .gmii_tx_clk    (gmii_tx_clk    ), // input
   .eth_udp_txd    (eth_udp_txd    ), // input
   .eth_udp_txen   (eth_udp_txen   ), // input
   .eth_mac_txd    (eth_mac_txd    ), // output
   .eth_mac_txen   (eth_mac_txen   )  // output
);

defparam mac_tx_slice_inst.local_ip_addr   = local_ip_addr;
defparam mac_tx_slice_inst.remote_ip_addr  = remote_ip_addr;
defparam mac_tx_slice_inst.local_udp_port  = local_udp_port;
defparam mac_tx_slice_inst.remote_udp_port = remote_udp_port;
// End of mac_tx_slice_inst instantiation

// gmii_rgmii_bright: GMII to RGMII bridge
util_gmii_to_rgmii util_gmii_to_rgmii (
   .reset          (sys_rst        ), // input
   .rgmii_td       (rgmii_txd      ), // output
   .rgmii_tx_ctl   (rgmii_tx_ctl   ), // output
   .rgmii_txc      (rgmii_txc      ), // output
   .rgmii_rd       (rgmii_rxd      ), // input
   .rgmii_rx_ctl   (rgmii_rx_ctl   ), // input
   .rgmii_rxc      (rgmii_rxc      ), // input
   .gmii_txd       (eth_mac_txd    ), // input
   .gmii_tx_en     (eth_mac_txen   ), // input
   .gmii_tx_er     (1'b0           ), // input
   .gmii_tx_clk    (gmii_tx_clk    ), // output
   .gmii_crs       (               ), // output
   .gmii_col       (               ), // output
   .gmii_rxd       (               ), // output
   .gmii_rx_dv     (               ), // output
   .gmii_rx_er     (               ), // output
   .gmii_rx_clk    (               ), // output
   .speed_selection(2'b10          ), // input
   .duplex_mode    (1'b1           )  // input
);
// End of util_gmii_to_rgmii_inst instantiation

endmodule

2 上板调试

        使用 ALINX AX7035 开发板,进行工程调试。红色的线接 USB 转串口接口,蓝色的线接入千兆网口。使用电脑模拟发送串口数据,并接收以太网数据。

 

 

         电脑端同时打开串口调试助手,和 wireshark 工具,开始抓包。

在串口调试助手中输入待发送数据,选择定时 1s 发送,观察 wireshark 界面是否间隔 1s 收到数据包。

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

nginx部署时http接口正常,ws接口404

可以这么配置 map $http_upgrade $connection_upgrade {default upgrade; close; }upstream wsbackend{server ip1:port1;server ip2:port2;keepalive 1000; }server {listen 20038;location /{ proxy_http_version 1.1;proxy_pass http://wsbackend;proxy_redirect off;proxy…

谷歌浏览器插件篇之console Importer

前言 作为一名前端开发者&#xff0c;相信在开发实践中&#xff0c;使用过诸多第三方库。譬如&#xff1a;lodash、moment、dayjs、antd等数不胜数。 然每每使用&#xff0c;经起繁琐&#xff0c;便令人有反抗之意。其步骤如下&#xff1a;首先要在搭建好的项目里&#xff0c…

学习笔记:Opencv实现限制对比度得自适应直方图均衡CLAHE

2023.8.19 为了完成深度学习的进阶&#xff0c;得学习学习传统算法拓展知识面&#xff0c;记录自己的学习心得 CLAHE百科&#xff1a; 一种限制对比度自适应直方图均衡化方法&#xff0c;采用了限制直方图分布的方法和加速的插值方法 clahe&#xff08;限制对比度自适应直方图…

C++ string类详解

⭐️ string string 是表示字符串的字符串类&#xff0c;该类的接口与常规容器的接口基本一致&#xff0c;还有一些额外的操作 string 的常规操作&#xff0c;在使用 string 类时&#xff0c;需要使用 #include <string> 以及 using namespace std;。 ✨ 帮助文档&…

4 STM32标准库函数 之 FLASH存储器(FLASH)所有函数的介绍及使用

3 STM32标准库函数 之 FLASH存储器所有函数的介绍及使用 1. 图片有格式2 文字无格式二、FLASH 库函数固件库函数预览2.1 函数FLASH_SetLatency2.2 函数FLASH_HalfCycleAccessCmd2.3 函数FLASH_PrefetchBufferCmd2.4 函数FLASH_Unlock2.5 函数FLASH_Lock2.6 函数FLASH_ErasePage…

音视频 FFmpeg音视频处理流程

ffmpeg -i test_1920x1080.mp4 -acodec copy -vcodec libx264 -s 1280x720 test_1280x720.flv推荐一个零声学院项目课&#xff0c;个人觉得老师讲得不错&#xff0c;分享给大家&#xff1a; 零声白金学习卡&#xff08;含基础架构/高性能存储/golang云原生/音视频/Linux内核&am…

GAN!生成对抗网络GAN全维度介绍与实战

目录 一、引言1.1 生成对抗网络简介1.2 应用领域概览1.3 GAN的重要性 二、理论基础2.1 生成对抗网络的工作原理2.1.1 生成器生成过程 2.1.2 判别器判别过程 2.1.3 训练过程训练代码示例 2.1.4 平衡与收敛 2.2 数学背景2.2.1 损失函数生成器损失判别器损失 2.2.2 优化方法优化代…

Linux设置临时目录路径的解决方案

大家好,我是爱编程的喵喵。双985硕士毕业,现担任全栈工程师一职,热衷于将数据思维应用到工作与生活中。从事机器学习以及相关的前后端开发工作。曾在阿里云、科大讯飞、CCF等比赛获得多次Top名次。现为CSDN博客专家、人工智能领域优质创作者。喜欢通过博客创作的方式对所学的…

第 7 章 排序算法(1)(介绍,分类,时间复杂度,空间复杂度)

7.1排序算法的介绍 排序也称排序算法(Sort Algorithm)&#xff0c;排序是将一组数据&#xff0c;依指定的顺序进行排列的过程。 7.2排序的分类&#xff1a; 内部排序: 指将需要处理的所有数据都加载到**内部存储器(内存)**中进行排序。外部排序法&#xff1a; 数据量过大&am…

安全学习DAY18_信息打点-APP资产搜集

信息打点-APP资产&静态提取&动态抓包&动态调试 文章目录 信息打点-APP资产&静态提取&动态抓包&动态调试本节知识&思维导图本节使用到的链接&工具 如何获取目标APP从名称中获取APP从URL获取APP APP搜集资产信息APP提取信息分类信息提取方式信息…

RPA机器人《国网电力》电力行业实施案例-基层减负 提质增效

背景&#xff1a;随着国网战略目标加速落地&#xff0c;数字化转型和精益化管理深化推进&#xff0c;各供电公司亟待突破精细化管控不深入、执行标准不够统一、系统数据不够融通等制约工作质效提升的能力瓶颈&#xff0c;针对这些问题&#xff0c;决定引入诸如RPA、OCR等技术&a…

深入探索:Kali Linux 网络安全之旅

目录 前言 访问官方网站 导航到下载页面 启动后界面操作 前言 "Kali" 可能指的是 Kali Linux&#xff0c;它是一种基于 Debian 的 Linux 发行版&#xff0c;专门用于渗透测试、网络安全评估、数字取证和相关的安全任务。Kali Linux 旨在提供一系列用于测试网络和…

C语言刷题指南(二)

&#x1f4d9;作者简介&#xff1a; 清水加冰&#xff0c;目前大二在读&#xff0c;正在学习C/C、Python、操作系统、数据库等。 &#x1f4d8;相关专栏&#xff1a;C语言初阶、C语言进阶、C语言刷题训练营、数据结构刷题训练营、有感兴趣的可以看一看。 欢迎点赞 &#x1f44d…

回归预测 | MATLAB实现WOA-BP鲸鱼优化算法优化BP神经网络多输入单输出回归预测(多指标,多图)

回归预测 | MATLAB实现WOA-BP鲸鱼优化算法优化BP神经网络多输入单输出回归预测&#xff08;多指标&#xff0c;多图&#xff09; 目录 回归预测 | MATLAB实现WOA-BP鲸鱼优化算法优化BP神经网络多输入单输出回归预测&#xff08;多指标&#xff0c;多图&#xff09;效果一览基本…

Linux 内存管理 pt.1

今天我们来学习一下 Linux 操作系统核心之一&#xff1a;内存 跟 CPU 一样&#xff0c;内存也是操作系统最核心的功能之一&#xff0c;内存主要用来存储系统和程序的指令、数据、缓存等 关于内存的学习&#xff0c;我会尽量以通俗易懂的方式且分成多篇文章去讲解 那么今天在 pt…

史上最简洁实用人工神经元网络c++编写202301

这是史上最简单、清晰…… C语言编写的 带正向传播、反向传播(Forward ……和Back Propagation&#xff09;……任意Nodes数的人工神经元神经网络……。 大一学生、甚至中学生可以读懂。 适合于&#xff0c;没学过高数的程序员……照猫画虎编写人工智能、深度学习之神经网络……

学习笔记230816---vue项目中使用第三方组件{el-dropdown}如何设置禁止事件功能

问题描述 使用第三方组件elementui&#xff0c;在导航菜单el-menu的el-menu-item中嵌入一个下拉菜框el-dropdown。点击...icon弹出下拉菜单el-dropdown-menu&#xff0c;那么这时会触发事件冒泡&#xff0c;el-menu-item菜单项的点击事件也会触发。 解决方法 阻止事件冒泡&am…

Pycharm找不到Conda可执行文件路径(Pycharm无法导入Anaconda已有环境)

在使用Pycharm时发现无法导入Anaconda创建好的环境&#xff0c;会出现找不到Conda可执行文件路径的问题。 解决 在输入框内输入D:\anaconda3\Scripts\conda.exe&#xff0c;点击加载环境。 注意前面目录是自己Anaconda的安装位置&#xff0c;之后就可以找到Anaconda的现有环…

C++ 的关键字(保留字)完整介绍

1. asm asm (指令字符串)&#xff1a;允许在 C 程序中嵌入汇编代码。 2. auto auto&#xff08;自动&#xff0c;automatic&#xff09;是存储类型标识符&#xff0c;表明变量"自动"具有本地范围&#xff0c;块范围的变量声明&#xff08;如for循环体内的变量声明…

腾讯云3年轻量应用服务器2核4G5M和2核2G4M详细介绍

腾讯云轻量应用服务器3年配置&#xff0c;目前可以选择三年的轻量配置为2核2G4M和2核4G5M&#xff0c;2核2G4M和2核4G5M带宽&#xff0c;当然也可以选择选一年&#xff0c;第二年xufei会比较gui&#xff0c;腾讯云百科分享腾讯云轻量应用服务器3年配置表&#xff1a; 目录 腾…