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

news2024/11/18 3:41:49

最近和 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.coloradmin.cn/o/899129.html

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

相关文章

【C语言】通讯录(文件) -- 详解

⚪前言 前面介绍了【C语言】静态通讯录 -- 详解_炫酷的伊莉娜的博客-CSDN博客和【C语言】动态通讯录 -- 详解_炫酷的伊莉娜的博客-CSDN博客。当通讯录运行起来时&#xff0c;可以对通讯录中的数据进行增加、删除或修改等。此时数据是存放在内存中&#xff0c;当程序退出时&…

不可忽略:冒烟测试到底有多重要?

冒烟测试介绍 冒烟测试一词&#xff0c;来源于电路板测试&#xff1a;电路板拼接或组装完成后&#xff0c;进行通电测试&#xff0c;如果冒烟&#xff0c;则说明存在缺陷。 而软件应用中&#xff0c;对其的定义为&#xff1a;在软件开发过程中的一种针对软件版本包的快速基本…

双亲委派机制,懂吧~ 那什么情况下需要破坏它,知道吗?

一、什么是双亲委派机制&#xff1f; 我们要获得一个类的Class实例&#xff0c;可以采用如下方式&#xff1a; 那么在Class的forName(className)方法中&#xff0c;会根据是谁调用了Class.forName(className)这个方法&#xff0c;那么就获得当时加载了它的那个ClassLoader&…

uniapp选择只选择月份demo效果(整理)

<template><view style"margin-top: 200rpx;"><!-- mode"multiSelector" 多列选择器 --><view><picker :range"years" :value"echoVal" change"yearChange" mode"multiSelector">{…

【面试题】2、Docker和Spring相关

1、Docker是什么&#xff1f; &#xff08;1&#xff09;Docker是一个快速交互、运行应用的技术&#xff0c;可以将程序及其依赖、运行环境一起打包为一个镜像&#xff0c;该镜像可以迁移到任意的Linux操作系统 &#xff08;2&#xff09;运行时利用沙箱机制形成隔离容器&…

【JasperReports笔记04】如何使用Jasper Studio制作父子报表,并且通过Java + Parameters参数填充模板文件

这篇文章&#xff0c;主要介绍如何使用Jasper Studio制作父子报表&#xff0c;并且通过Java Parameters参数填充模板文件。 目录 一、JasperReports实现父子报表 1.1、运行效果 1.2、制作模板 &#xff08;1&#xff09;制作子报表 &#xff08;2&#xff09;制作子报表的…

计算机竞赛 图像检索算法

文章目录 1 前言2 图像检索介绍(1) 无监督图像检索(2) 有监督图像检索 3 图像检索步骤4 应用实例5 最后 1 前言 &#x1f525; 优质竞赛项目系列&#xff0c;今天要分享的是 图像检索算法 该项目较为新颖&#xff0c;适合作为竞赛课题方向&#xff0c;学长非常推荐&#xff…

0101读写分离测试-jdbc-shardingsphere-中间件

文章目录 1 前言2、创建SpringBoot程序2.1、创建项目2.2、添加依赖2.3、生成实体类、service与Mapper1.5、配置读写分离 2、测试2.1、读写分离测试2.2、事务测试2.3、负载均衡测试 结语 1 前言 shardingshpere-jdbc定位为轻量级 Java 框架&#xff0c;在 Java 的 JDBC 层提供的…

处理Selenium3+python3定位鼠标悬停才显示的元素

这篇文章主要介绍了Selenium3python3--如何定位鼠标悬停才显示的元素 &#xff0c;文中通过简单代码给大家介绍的非常详细,需要的朋友可以参考下 先给大家介绍下Selenium3python3--如何定位鼠标悬停才显示的元素 定位鼠标悬停才显示的元素&#xff0c;要引入新模块 # coding…

Tableau画图

目录 蝴蝶图 四象图 排序图 盒型图/散点图 圆环图 火柴图 直方图 瀑布图 地理图 面积图 树地图 面积图 条形图 词云图 双轴图 填充地图 tableau2023.2 须知 蝴蝶图 拉好数据之后 创建新字段正负销售额&#xff0c;并拖入第一个颜色标记卡 四象图 智能推荐 散…

使用句子嵌入的无监督文本摘要

一、说明 这是一个AI研究生班的作业练习&#xff0c; 在本文中&#xff0c;我将描述我用来在 Python 中执行文本摘要的方法&#xff0c;这是我在导师分配给我的很棒的任务列表之一。 二、什么是文本摘要&#xff1f; 文本摘要是从一个或多个源中提取最重要的信息以生成特定用户…

华为ENSP网络设备配置实战4(OSPF+BGP+VPN+单臂路由)

题目要求 1、loopback口通过OSPF连通&#xff0c;合理规划OSPF开销&#xff0c;通过设置AR1->AR2->AR4链路&#xff0c;来消除负载链路。 2、AR3、AR4分别与AR1、AR2建立BGP邻居 3、AR3、AR4作为PC机网关设备 4、PC1、PC3由VPN-spi承载&#xff0c;PC2、PC4由VPN-spims承…

【算法挨揍日记】day03——双指针算法_有效三角形的个数、和为s的两个数字

611. 有效三角形的个数 611. 有效三角形的个数https://leetcode.cn/problems/valid-triangle-number/ 题目描述&#xff1a; 给定一个包含非负整数的数组 nums &#xff0c;返回其中可以组成三角形三条边的三元组个数。 解题思路&#xff1a; 本题是一个关于三角形是否能成立…

通过爬虫抓取上市企业利润表并在睿思BI中展示

睿思BI从v5.3开始支持网络爬虫&#xff0c;可以从指定URL抓取表格数据&#xff0c;本示例实现从网络上抓取上市企业招商银行的利润表数据&#xff0c;并在睿思BI中进行展现。 首先&#xff1a;从搜狐财经抓取招商银行利润表数据&#xff0c;操作过程如下&#xff1a; 1.在睿思…

提示词4大经典框架;将AI融入动画工作流的案例和实践经验;构建基于LLM的系统和产品的模式;提示工程的艺术 | ShowMeAI日报

&#x1f440;日报&周刊合集 | &#x1f3a1;生产力工具与行业应用大全 | &#x1f9e1; 点赞关注评论拜托啦&#xff01; &#x1f916; 高效提示词的4大经典框架&#xff1a;ICIO、CRISPE、BROKE、RASCEF ICIO 框架 Intruction (任务) &#xff1a;你希望AI去做的任务&am…

软件测试中如何测试算法?

广义的算法是指解决问题的方案,小到求解数学题,大到制定商业策略,都可以叫做算法。而我们 今天讨论的软件测试中的算法,对应的英文单词为Algorithm ,专指计算机处理复杂问题的程序或 指令。 随着最近几年人工智能等领域的快速发展,算法受到前所未有的重视,算法测试也随之兴起。…

异步电机IM-改进的电压模型磁链观测器学习

导读&#xff1a;本期文章主要介绍异步电机的改进型电压模型磁链观测器。传统纯积分形式的积分器在低速区域存在初始值问题和直流偏置问题&#xff0c;所以在实际应用中必须对电压模型进行改进。本期文章中的对电压模型改进是借鉴一篇IEEE中的方法。 如果需要文章中对应的仿真…

gcc make cmake ninja的区别

理清C编译过程用到的工具概念 ref: 知乎 早先学C的时候&#xff0c;因为只需要点击IDE的运行按钮&#xff0c;程序就可以跑起来&#xff0c;写过最复杂的只不过是几个文件的学生管理系统。 现在要重新拾起C&#xff0c;看的项目和之前的不可同日而语&#xff0c;构建系统也复…

最优化方法Python计算:牛顿算法

设函数 f ( x ) f(\boldsymbol{x}) f(x)&#xff0c; x ∈ R n \boldsymbol{x}\in\text{ℝ}^n x∈Rn二阶连续可微&#xff0c;记 g ( x ) ∇ f ( x ) \boldsymbol{g}(\boldsymbol{x})\nabla f(\boldsymbol{x}) g(x)∇f(x)&#xff0c; H ( x ) ∇ 2 f ( x ) \boldsymbol{H}(\…

【数据结构OJ题】用栈实现队列

原题链接&#xff1a;https://leetcode.cn/problems/implement-queue-using-stacks/ 目录 1. 题目描述 2. 思路分析 3. 代码实现 1. 题目描述 2. 思路分析 用两个栈实现&#xff0c;一个栈进行入队操作&#xff0c;另一个栈进行出队操作。 出队操作&#xff1a; 当出队的栈…