FPGA - 以太网UDP通信(二)

一,引言

前文链接:FPGA - 以太网UDP通信(一)

在上文章中介绍了以太网简介,以太网UDP通信硬件结构,以及PHY芯片RGMII接口-GMII接口转换逻辑,接下来介绍UDP通信结构框图以及数据链路层(MAC层)接受发送逻辑。

二,以太网UDP通信结构框图

在上一篇文章中介绍了以太网UDP通信组包过程图:

可以看到用户数据通过UDP层添加udp头部,然后经过IP层添加ip头部,在经过数据链路层(MAC层)添加mac头部,送到PHY芯片物理层。一步步完成组包发送过程。同样的,从PHT芯片输出的数据经过MAC层IP层UDP层一步步完成解包校验过程。因此根据此思路画出简易结构框图如下:

在上篇文章中实现了rgmii_interface(rgmii_receive和rgmii_send)模块,接下来实现mac_layermac_receivemac_send)模块。

三,数据链路层(MAC层)

MAC不是物理层,MAC层是数据链路层的两个子层之一。

以太网V2的MAC帧格式:

------------------------------------- mac数据包头  22byte  -------------------------------------      

|     前导码(前同步码) 7 byte                                                                           |  
|     8'h55             ​​​​​​​        ​​​​​​​        ​​​​​​​        ​​​​​​​        ​​​​​​​        ​​​​​​​                                              ​​​​​​​        ​​​​​​​   |

|     SFD(帧开始定结符)  1byte     ​​​​​​​        ​​​​​​​        ​​​​​​​        ​​​​​​​        ​​​​​​​        ​​​​​​​        ​​​​​​​        ​​​​​​​        ​​​​​​​   |
|     8'hd5     ​​​​​​​        ​​​​​​​        ​​​​​​​        ​​​​​​​        ​​​​​​​        ​​​​​​​        ​​​​​​​        ​​​​​​​        ​​​​​​​                                         |

|     目的mac地址 6byte     ​​​​​​​        ​​​​​​​        ​​​​​​​        ​​​​​​​        ​​​​​​​        ​​​​​​​        ​​​​​​​        ​​​​​​​        ​​​​​​​            ​​​​​​​      |

|     源mac地址   6byte     ​​​​​​​        ​​​​​​​        ​​​​​​​        ​​​​​​​        ​​​​​​​        ​​​​​​​        ​​​​​​​        ​​​​​​​        ​​​​​​​                    |

|     类型/长度   2byte     ​​​​​​​        ​​​​​​​        ​​​​​​​        ​​​​​​​        ​​​​​​​        ​​​​​​​        ​​​​​​​        ​​​​​​​        ​​​​​​​            ​​​​​​​        ​​​​​​​   |
|     小于1536表示长度,     ​​​​​​​        ​​​​​​​        ​​​​​​​        ​​​​​​​        ​​​​​​​        ​​​​​​​        ​​​​​​​        ​​​​​​​        ​​​​​​​            ​​​​​​​     |
|     大于1536表示类型 arp:16'h0806 , ip: 16'h0800     ​​​​​​​        ​​​​​​​        ​​​​​​​        ​​​​​​​        ​​​​​​​        ​​​​​​​|

|     数据 46-1500byte     ​​​​​​​        ​​​​​​​        ​​​​​​​        ​​​​​​​        ​​​​​​​        ​​​​​​​        ​​​​​​​        ​​​​​​​        ​​​​​​​                      |

|     FCS(帧校验序列CRC) 4byte     ​​​​​​​        ​​​​​​​        ​​​​​​​        ​​​​​​​        ​​​​​​​        ​​​​​​​        ​​​​​​​        ​​​​​​​        ​​​​​​​|

---------------------------------------------------------------------------------------------------------- 

四,MAC层代码设计

在上面的结构框图中,可以看到,mac_layer中包括mac_receivemac_send模块。

----------------------------------------------------------  思路 ------------------------------------------------------------

1,在MAC帧格式中,最后4byte 是FCS(帧校验序列CRC), 所以在接受和发送过程中必须把帧校验序列前面的数据存储(fifo)起来,等到CRC校验完成,再进行数据传输。

2,在以太网UDP通信中,用户端数据传输是在用户时钟下进行的,而PHY芯片数据传输是在PHY芯片的时钟下进行的。所以在这里我们要做一个跨时钟域的处理。

3,跨时钟域处理:在多bit信号跨时钟域中常常使用异步fifo来处理,但如何很好的设计这一处理过程呢?在这里我们进行双fifo跨时钟域(其实在之前文章中也用过这样的处理方式)。

首先第一个是数据fifo,缓存有效数据+last数据(用来指示有效数据的最后一个数据)

其次第二个是控制fifo,缓存数据对应的地址,长度,类型.....(在mac_layer中缓存的是帧类型和CRC校验结果)

然后判断fifo非空(rdemoty信号为低), 就把有效数据和控制信息从fifo里面读出来,

控制fifo的读使能rden只需要拉高一拍,数据fifo读使能rden要一直拉高,直到读出来最后一个数据,通过判断读出来的last信号,来拉低rden。

4,CRC校验

5,如何准确有效的进行数据组包,解包校验呢?

设置计数器,接受端设置rx_cnt,发送端设置tx_cnt。用计数器控制组包解包校验过程。

下图是mac_lay层的结构框图:

-----------------------------------------------------------------------------------------------------------------------------

五,MAC层代码编写

CRC32校验:

CRC校验

`timescale 1ns / 1psmodule crc32_d8(input				clk,input               reset,input               crc_din_vld,input   [7:0]       crc_din    ,input               crc_done   ,output  [31:0]      crc_dout   );wire [7:0]  crc_din_r;
reg  [31:0] crc_dout_r;
wire [31:0] crc_data;assign crc_din_r = {crc_din[0],crc_din[1],crc_din[2],crc_din[3],crc_din[4],crc_din[5],crc_din[6],crc_din[7]};
assign crc_dout  = ~{crc_dout_r[0],crc_dout_r[1],crc_dout_r[2],crc_dout_r[3],crc_dout_r[4],crc_dout_r[5],crc_dout_r[6],crc_dout_r[7],crc_dout_r[8],crc_dout_r[9],crc_dout_r[10],crc_dout_r[11],crc_dout_r[12],crc_dout_r[13],crc_dout_r[14],crc_dout_r[15],crc_dout_r[16],crc_dout_r[17],crc_dout_r[18],crc_dout_r[19],crc_dout_r[20],crc_dout_r[21],crc_dout_r[22],crc_dout_r[23],crc_dout_r[24],crc_dout_r[25],crc_dout_r[26],crc_dout_r[27],crc_dout_r[28],crc_dout_r[29],crc_dout_r[30],crc_dout_r[31]};assign crc_data[0] = crc_din_r[6] ^ crc_din_r[0] ^ crc_dout_r[24] ^ crc_dout_r[30];
assign crc_data[1] = crc_din_r[7] ^ crc_din_r[6] ^ crc_din_r[1] ^ crc_din_r[0] ^ crc_dout_r[24] ^ crc_dout_r[25] ^ crc_dout_r[30] ^ crc_dout_r[31];
assign crc_data[2] = crc_din_r[7] ^ crc_din_r[6] ^ crc_din_r[2] ^ crc_din_r[1] ^ crc_din_r[0] ^ crc_dout_r[24] ^ crc_dout_r[25] ^ crc_dout_r[26] ^ crc_dout_r[30] ^ crc_dout_r[31];
assign crc_data[3] = crc_din_r[7] ^ crc_din_r[3] ^ crc_din_r[2] ^ crc_din_r[1] ^ crc_dout_r[25] ^ crc_dout_r[26] ^ crc_dout_r[27] ^ crc_dout_r[31];
assign crc_data[4] = crc_din_r[6] ^ crc_din_r[4] ^ crc_din_r[3] ^ crc_din_r[2] ^ crc_din_r[0] ^ crc_dout_r[24] ^ crc_dout_r[26] ^ crc_dout_r[27] ^ crc_dout_r[28] ^ crc_dout_r[30];
assign crc_data[5] = crc_din_r[7] ^ crc_din_r[6] ^ crc_din_r[5] ^ crc_din_r[4] ^ crc_din_r[3] ^ crc_din_r[1] ^ crc_din_r[0] ^ crc_dout_r[24] ^ crc_dout_r[25] ^ crc_dout_r[27] ^ crc_dout_r[28] ^ crc_dout_r[29] ^ crc_dout_r[30] ^ crc_dout_r[31];
assign crc_data[6] = crc_din_r[7] ^ crc_din_r[6] ^ crc_din_r[5] ^ crc_din_r[4] ^ crc_din_r[2] ^ crc_din_r[1] ^ crc_dout_r[25] ^ crc_dout_r[26] ^ crc_dout_r[28] ^ crc_dout_r[29] ^ crc_dout_r[30] ^ crc_dout_r[31];
assign crc_data[7] = crc_din_r[7] ^ crc_din_r[5] ^ crc_din_r[3] ^ crc_din_r[2] ^ crc_din_r[0] ^ crc_dout_r[24] ^ crc_dout_r[26] ^ crc_dout_r[27] ^ crc_dout_r[29] ^ crc_dout_r[31];
assign crc_data[8] = crc_din_r[4] ^ crc_din_r[3] ^ crc_din_r[1] ^ crc_din_r[0] ^ crc_dout_r[0] ^ crc_dout_r[24] ^ crc_dout_r[25] ^ crc_dout_r[27] ^ crc_dout_r[28];
assign crc_data[9] = crc_din_r[5] ^ crc_din_r[4] ^ crc_din_r[2] ^ crc_din_r[1] ^ crc_dout_r[1] ^ crc_dout_r[25] ^ crc_dout_r[26] ^ crc_dout_r[28] ^ crc_dout_r[29];
assign crc_data[10] = crc_din_r[5] ^ crc_din_r[3] ^ crc_din_r[2] ^ crc_din_r[0] ^ crc_dout_r[2] ^ crc_dout_r[24] ^ crc_dout_r[26] ^ crc_dout_r[27] ^ crc_dout_r[29];
assign crc_data[11] = crc_din_r[4] ^ crc_din_r[3] ^ crc_din_r[1] ^ crc_din_r[0] ^ crc_dout_r[3] ^ crc_dout_r[24] ^ crc_dout_r[25] ^ crc_dout_r[27] ^ crc_dout_r[28];
assign crc_data[12] = crc_din_r[6] ^ crc_din_r[5] ^ crc_din_r[4] ^ crc_din_r[2] ^ crc_din_r[1] ^ crc_din_r[0] ^ crc_dout_r[4] ^ crc_dout_r[24] ^ crc_dout_r[25] ^ crc_dout_r[26] ^ crc_dout_r[28] ^ crc_dout_r[29] ^ crc_dout_r[30];
assign crc_data[13] = crc_din_r[7] ^ crc_din_r[6] ^ crc_din_r[5] ^ crc_din_r[3] ^ crc_din_r[2] ^ crc_din_r[1] ^ crc_dout_r[5] ^ crc_dout_r[25] ^ crc_dout_r[26] ^ crc_dout_r[27] ^ crc_dout_r[29] ^ crc_dout_r[30] ^ crc_dout_r[31];
assign crc_data[14] = crc_din_r[7] ^ crc_din_r[6] ^ crc_din_r[4] ^ crc_din_r[3] ^ crc_din_r[2] ^ crc_dout_r[6] ^ crc_dout_r[26] ^ crc_dout_r[27] ^ crc_dout_r[28] ^ crc_dout_r[30] ^ crc_dout_r[31];
assign crc_data[15] = crc_din_r[7] ^ crc_din_r[5] ^ crc_din_r[4] ^ crc_din_r[3] ^ crc_dout_r[7] ^ crc_dout_r[27] ^ crc_dout_r[28] ^ crc_dout_r[29] ^ crc_dout_r[31];
assign crc_data[16] = crc_din_r[5] ^ crc_din_r[4] ^ crc_din_r[0] ^ crc_dout_r[8] ^ crc_dout_r[24] ^ crc_dout_r[28] ^ crc_dout_r[29];
assign crc_data[17] = crc_din_r[6] ^ crc_din_r[5] ^ crc_din_r[1] ^ crc_dout_r[9] ^ crc_dout_r[25] ^ crc_dout_r[29] ^ crc_dout_r[30];
assign crc_data[18] = crc_din_r[7] ^ crc_din_r[6] ^ crc_din_r[2] ^ crc_dout_r[10] ^ crc_dout_r[26] ^ crc_dout_r[30] ^ crc_dout_r[31];
assign crc_data[19] = crc_din_r[7] ^ crc_din_r[3] ^ crc_dout_r[11] ^ crc_dout_r[27] ^ crc_dout_r[31];
assign crc_data[20] = crc_din_r[4] ^ crc_dout_r[12] ^ crc_dout_r[28];
assign crc_data[21] = crc_din_r[5] ^ crc_dout_r[13] ^ crc_dout_r[29];
assign crc_data[22] = crc_din_r[0] ^ crc_dout_r[14] ^ crc_dout_r[24];
assign crc_data[23] = crc_din_r[6] ^ crc_din_r[1] ^ crc_din_r[0] ^ crc_dout_r[15] ^ crc_dout_r[24] ^ crc_dout_r[25] ^ crc_dout_r[30];
assign crc_data[24] = crc_din_r[7] ^ crc_din_r[2] ^ crc_din_r[1] ^ crc_dout_r[16] ^ crc_dout_r[25] ^ crc_dout_r[26] ^ crc_dout_r[31];
assign crc_data[25] = crc_din_r[3] ^ crc_din_r[2] ^ crc_dout_r[17] ^ crc_dout_r[26] ^ crc_dout_r[27];
assign crc_data[26] = crc_din_r[6] ^ crc_din_r[4] ^ crc_din_r[3] ^ crc_din_r[0] ^ crc_dout_r[18] ^ crc_dout_r[24] ^ crc_dout_r[27] ^ crc_dout_r[28] ^ crc_dout_r[30];
assign crc_data[27] = crc_din_r[7] ^ crc_din_r[5] ^ crc_din_r[4] ^ crc_din_r[1] ^ crc_dout_r[19] ^ crc_dout_r[25] ^ crc_dout_r[28] ^ crc_dout_r[29] ^ crc_dout_r[31];
assign crc_data[28] = crc_din_r[6] ^ crc_din_r[5] ^ crc_din_r[2] ^ crc_dout_r[20] ^ crc_dout_r[26] ^ crc_dout_r[29] ^ crc_dout_r[30];
assign crc_data[29] = crc_din_r[7] ^ crc_din_r[6] ^ crc_din_r[3] ^ crc_dout_r[21] ^ crc_dout_r[27] ^ crc_dout_r[30] ^ crc_dout_r[31];
assign crc_data[30] = crc_din_r[7] ^ crc_din_r[4] ^ crc_dout_r[22] ^ crc_dout_r[28] ^ crc_dout_r[31];
assign crc_data[31] = crc_din_r[5] ^ crc_dout_r[23] ^ crc_dout_r[29];always @(posedge clk) beginif (reset) crc_dout_r <= 32'hffffffff;else if (crc_done) crc_dout_r <= 32'hffffffff;else if (crc_din_vld)crc_dout_r <= crc_data;else crc_dout_r <= crc_dout_r; 
endendmodule

mac_receive

mac_receive代码:

//功能 :  ①完成校验,将有效数据和MAC头部分离出来
//        ②跨时钟域
// -----------------------------------------------------------------------------
`timescale 1ns / 1psmodule mac_receive #(parameter	LOCAL_MAC_ADDR = 48'hffffff_ffffff,parameter   CRC_CHACK_EN   = 1)(input								clk             , //用户接受端时钟input                               phy_rx_clk      , //phy芯片提供的时钟input                               reset            , //用户端复位信号input                               phy_rx_reset     , //phy接受端复位/*-------rgmii_recive模块交互的信号----------------*/input                               gmii_rx_data_vld ,input       [7:0]                   gmii_rx_data     ,/*-------mac_to_arp_ip模块交互的信号----------------*/	output  reg                         mac_rx_data_vld  ,output  reg                         mac_rx_data_last ,output  reg [7:0]                   mac_rx_data      ,output  reg [15:0]                  mac_rx_frame_type,/*-------rx_crc32_d8模块交互的信号----------------*/	   output  reg 					    rx_crc_din_vld   ,output  reg [7:0]                   rx_crc_din       ,output  reg                         rx_crc_done      ,input       [31:0]                  rx_crc_dout         );endmodule

mac_send

mac_send代码:

//功能    ① 完成crc校验 mac头部 有效数据 crc校验 ...等组包
//        ② 跨时钟域 
// -----------------------------------------------------------------------------
`timescale 1ns / 1ps
module mac_send #(parameter	LOCAL_MAC_ADDR  = 48'hffffff_ffffff,parameter   TARGET_MAC_ADDR = 48'hffffff_ffffff	)(input								clk             , //用户发送端时钟input                               phy_tx_clk      , input                               reset            , input                               phy_tx_reset     , /*-------rgmii_send模块交互的信号----------------*/output  reg                         gmii_tx_data_vld ,output  reg [7:0]                   gmii_tx_data     ,/*-------ip_send模块交互的信号--------------------*/	input                               mac_tx_data_vld  ,input                               mac_tx_data_last ,input       [7:0]                   mac_tx_data      ,input       [15:0]                  mac_tx_frame_type,input       [15:0]                  mac_tx_length    ,/*-------tx_crc32_d8模块交互的信号----------------*/	   output  reg 					    tx_crc_din_vld   ,output      [7:0]                   tx_crc_din       ,output  reg                         tx_crc_done      ,input       [31:0]                  tx_crc_dout    	);endmodule 

顶层设计

mac层分别实现了接收和发送两部分,将两部分例化封装顶层mac_layer

`timescale 1ns / 1psmodule mac_layer #(parameter	LOCAL_MAC_ADDR  = 48'hffffff_ffffff   ,parameter   TARGET_MAC_ADDR = 48'hffffff_ffffff	,	parameter   CRC_CHACK_EN    = 1                )(input                               app_tx_clk       ,input                               app_rx_clk       ,input                               phy_tx_clk       , input                               phy_rx_clk       , 	input                               app_tx_reset     ,input                               app_rx_reset     ,input                               phy_tx_reset     , input                               phy_rx_reset     , input                               gmii_rx_data_vld ,input       [7:0]                   gmii_rx_data     ,output                              gmii_tx_data_vld ,output      [7:0]                   gmii_tx_data     ,	output                              mac_rx_data_vld  ,output                              mac_rx_data_last ,output      [7:0]                   mac_rx_data      ,output      [15:0]                  mac_rx_frame_type,		input                               mac_tx_data_vld  ,input                               mac_tx_data_last ,input       [7:0]                   mac_tx_data      ,input       [15:0]                  mac_tx_frame_type,input       [15:0]                  mac_tx_length    );wire        tx_crc_din_vld;wire  [7:0] tx_crc_din    ;wire        tx_crc_done   ;wire [31:0] tx_crc_dout   ;wire        rx_crc_din_vld;wire  [7:0] rx_crc_din    ;wire        rx_crc_done   ;wire [31:0] rx_crc_dout   ;mac_send #(.LOCAL_MAC_ADDR(LOCAL_MAC_ADDR),.TARGET_MAC_ADDR(TARGET_MAC_ADDR)) mac_send (.clk               (app_tx_clk),.phy_tx_clk        (phy_tx_clk),.reset             (app_tx_reset),.phy_tx_reset      (phy_tx_reset),.gmii_tx_data_vld  (gmii_tx_data_vld),.gmii_tx_data      (gmii_tx_data),.mac_tx_data_vld   (mac_tx_data_vld),.mac_tx_data_last  (mac_tx_data_last),.mac_tx_data       (mac_tx_data),.mac_tx_frame_type (mac_tx_frame_type),.mac_tx_length     (mac_tx_length),.tx_crc_din_vld    (tx_crc_din_vld),.tx_crc_din        (tx_crc_din),.tx_crc_done       (tx_crc_done),.tx_crc_dout       (tx_crc_dout));mac_receive #(.LOCAL_MAC_ADDR(LOCAL_MAC_ADDR),.CRC_CHACK_EN  (CRC_CHACK_EN)) mac_receive (.clk               (app_rx_clk),.phy_rx_clk        (phy_rx_clk),.reset             (app_rx_reset),.phy_rx_reset      (phy_rx_reset),.gmii_rx_data_vld  (gmii_rx_data_vld),.gmii_rx_data      (gmii_rx_data),.mac_rx_data_vld   (mac_rx_data_vld),.mac_rx_data_last  (mac_rx_data_last),.mac_rx_data       (mac_rx_data),.mac_rx_frame_type (mac_rx_frame_type),.rx_crc_din_vld    (rx_crc_din_vld),.rx_crc_din        (rx_crc_din),.rx_crc_done       (rx_crc_done),.rx_crc_dout       (rx_crc_dout));crc32_d8 tx_crc32_d8(.clk         (phy_tx_clk),.reset       (phy_tx_reset),.crc_din_vld (tx_crc_din_vld),.crc_din     (tx_crc_din),.crc_done    (tx_crc_done),.crc_dout    (tx_crc_dout));crc32_d8 rx_crc32_d8(.clk         (phy_rx_clk),.reset       (phy_rx_reset),.crc_din_vld (rx_crc_din_vld),.crc_din     (rx_crc_din),.crc_done    (rx_crc_done),.crc_dout    (rx_crc_dout));endmodule

 六,总结

至此,我们完成了以太网发送过程中最底层 ,也是最重要的部分MAC层的发送与接受。 关于本节中的CRC校验部分没有过多介绍,这部分可通过CRC生成网页来生成CRC校验代码。

接下来,在下一篇博客中将会实现ip层的接收与发送。

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

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

全面学习SpringCloud框架指南

要深入学习Spring Cloud框架,你需要系统地掌握其核心组件和概念,并了解如何在实际项目中应用这些知识。以下是一些关键的学习点和相应的学习内容: 一共分为10个模块包括: 1、微服务架构基础: 理解微服务架构的概念和优势。 学习单体架构向微服务架构演进的过程。 掌握…

逆向案例二十一——遇到混淆怎么办

开始新的板块尝试&#xff0c;混淆了怎么办 网址&#xff1a;极简壁纸_海量电脑桌面壁纸美图_4K超高清_最潮壁纸网站 抓包抓到&#xff0c;好久没做解密了&#xff0c;奥里给干他&#xff01;&#xff1a; 搜索关键字&#xff0c;打上断点&#xff0c;点击第二页。 _0x10a345…

网工内推 | 网安、AGV测试网络工程师,厂商认证优先,应届可投

01 神州数码 招聘岗位&#xff1a;网络工程师 职责描述&#xff1a; 1、负责国内外主流安全产品&#xff08;如防火墙、入侵防御、WAF、安全审计等&#xff09;的上线安装、调试、测试、割接、运维等工作。 2、能够独立进行安全类项目实施、问题排查及处理。 3、在出现网络攻…

数据分析——数据规范化

数据规范化是数据分析中的一个重要步骤&#xff0c;其目的在于确保数据的一致性和可比性&#xff0c;提高数据质量和分析结果的准确性。以下是一些数据规范化的常见方法和技术&#xff1a; 数据清洗&#xff1a;此步骤主要清除数据中的重复项、空格、格式错误等&#xff0c;确…

史上首位阿贝尔奖、图灵奖双得主!2023图灵奖授予随机性大佬Avi Wigderson

ChatGPT狂飙160天&#xff0c;世界已经不是之前的样子。 新建了免费的人工智能中文站https://ai.weoknow.com 新建了收费的人工智能中文站https://ai.hzytsoft.cn/ 更多资源欢迎关注 这位多产的研究者发现了随机性和计算之间的深刻联系&#xff0c;其贡献影响了密码学、复杂性…

二叉树练习day.7

530.二叉搜索树的最小绝对差 链接&#xff1a;. - 力扣&#xff08;LeetCode&#xff09; 题目描述&#xff1a; 给你一个二叉搜索树的根节点 root &#xff0c;返回 树中任意两不同节点值之间的最小差值 。 差值是一个正数&#xff0c;其数值等于两值之差的绝对值。 示例 1&…

【简明图文教程】Node.js的下载、安装、环境配置及测试

文章目录 前言下载Node.js安装Node.js配置Node.js配置环境变量测试后言 前言 本教程适用于小白第一次从零开始进行Node.js的下载、安装、环境配置及测试。 如果你之前已经安装过了Node.js或删除掉了Node.js想重新安装&#xff0c;需要先参考以下博客进行处理后&#xff0c;再根…

Harmony鸿蒙南向驱动开发-MIPI DSI接口使用

功能简介 DSI&#xff08;Display Serial Interface&#xff09;是由移动行业处理器接口联盟&#xff08;Mobile Industry Processor Interface (MIPI) Alliance&#xff09;制定的规范&#xff0c;旨在降低移动设备中显示控制器的成本。它以串行的方式发送像素数据或指令给外…

基于SpringBoot+vue网上点餐系统包含万字文档

基于SpringBoot的网上点餐系统包含万字文档 项目视频演示: springboot027网上点餐系统包含万字文档 开发系统:Windows 架构模式:MVC/前后端分离 JDK版本: Java JDK1.8 开发工具:IDEA 数据库版本: mysql8.0 数据库可视化工具: navicat 服务器: SpringBoot自带 apache tomcat 主要…

【文献管理】Zotero

软件介绍 文献管理软件Zotero功能强大、免费、使用便捷、可自由扩展功能&#xff0c;能极大地提升我们的学习、科研效率。 下载软件 Zotero官方网址 功能介绍 收集题录 管理题录 插入引文 同步文献 插件与常见问题 茉莉花 翻译 抓取失败编译器更新 样式下载地址 CNKI编译器…

6.12物联网RK3399项目开发实录-驱动开发之UART 串口的使用(wulianjishu666)

嵌入式实战开发例程【珍贵收藏&#xff0c;开发必备】&#xff1a; 链接&#xff1a;https://pan.baidu.com/s/1tkDBNH9R3iAaHOG1Zj9q1Q?pwdt41u UART 使用 简介 AIO-3399J 支持 SPI 桥接/扩展 4 个增强功能串口&#xff08;UART&#xff09;的功能&#xff0c;分别为 UA…

Python 全栈体系【四阶】(二十六)

第五章 深度学习 四、OpenCV 1. OpenCV安装 执行以下命令安装opencv-python库&#xff08;核心库&#xff09;和opencv-contrib-python库&#xff08;贡献库&#xff09;。注意&#xff1a;命令拷贝后要合成一行执行&#xff0c;中间不要换行。 # 安装opencv核心库 pip3 in…