国产 无码 综合区,色欲AV无码国产永久播放,无码天堂亚洲国产AV,国产日韩欧美女同一区二区

【正點(diǎn)原子FPGA連載】第三十一章基于lwip的echo server實(shí)驗(yàn) 摘自【正點(diǎn)原子】DFZU2EG_4EV MPSoC之嵌入式Vitis開發(fā)指南

這篇具有很好參考價(jià)值的文章主要介紹了【正點(diǎn)原子FPGA連載】第三十一章基于lwip的echo server實(shí)驗(yàn) 摘自【正點(diǎn)原子】DFZU2EG_4EV MPSoC之嵌入式Vitis開發(fā)指南。希望對(duì)大家有所幫助。如果存在錯(cuò)誤或未考慮完全的地方,請(qǐng)大家不吝賜教,您也可以點(diǎn)擊"舉報(bào)違法"按鈕提交疑問。

第三十一章基于lwip的echo server實(shí)驗(yàn)

隨著物聯(lián)網(wǎng)的興起,萬物互聯(lián)需要一個(gè)強(qiáng)大而又靈活的協(xié)議體系,TCP/IP協(xié)議得天獨(dú)厚,而在嵌入式網(wǎng)絡(luò)設(shè)備中,由于硬件資源的限制,需要特殊的實(shí)現(xiàn)方式。LWIP作為TCP/IP協(xié)議的一種輕量級(jí)實(shí)現(xiàn)方式,滿足了這一要求。本章我們利用VITIS軟件自帶的lwIP Echo Server例程模板,初步了解lwip的使用。本章包括以下幾個(gè)部分:
3131.1簡(jiǎn)介
31.2實(shí)驗(yàn)任務(wù)
31.3硬件設(shè)計(jì)
31.4軟件設(shè)計(jì)
31.5下載驗(yàn)證

31.1簡(jiǎn)介

1)TCP/IP協(xié)議簡(jiǎn)介
TCP/IP協(xié)議中文名為傳輸控制協(xié)議/因特網(wǎng)互聯(lián)協(xié)議,又名網(wǎng)絡(luò)通訊協(xié)議,是Internet最基本的協(xié)議、Internet國(guó)際互聯(lián)網(wǎng)絡(luò)的基礎(chǔ),由網(wǎng)絡(luò)層的IP協(xié)議和傳輸層的TCP協(xié)議組成。TCP/IP定義了電子設(shè)備如何連入因特網(wǎng),以及數(shù)據(jù)如何在它們之間傳輸?shù)臉?biāo)準(zhǔn)。協(xié)議采用了4層的層級(jí)結(jié)構(gòu),每一層都呼叫它的下一層所提供的協(xié)議來完成自己的需求。通俗而言:TCP負(fù)責(zé)發(fā)現(xiàn)傳輸?shù)膯栴},一有問題就發(fā)出信號(hào),要求重新傳輸,直到所有數(shù)據(jù)安全正確地傳輸?shù)侥康牡亍6鳬P是給因特網(wǎng)的每一臺(tái)聯(lián)網(wǎng)設(shè)備規(guī)定一個(gè)地址。
TCP/IP協(xié)議不是TCP和IP這兩個(gè)協(xié)議的合稱,而是指因特網(wǎng)整個(gè)TCP/IP協(xié)議族。從協(xié)議分層模型方面來講,TCP/IP由四個(gè)層次組成:網(wǎng)絡(luò)接口層、網(wǎng)絡(luò)層、傳輸層、應(yīng)用層。OSI(Open System Interconnection)是開放式系統(tǒng)互連參考模型,該模型將TCP/IP分為七層:物理層、數(shù)據(jù)鏈路層、網(wǎng)絡(luò)層、傳輸層、會(huì)話層、表示層和應(yīng)用層。TCP/IP模型與OSI模型對(duì)比如表32.1.1所示。
表32.1.1 OSI模型與TCP/IP模塊
fpga lwip,正點(diǎn)原子,fpga開發(fā),網(wǎng)絡(luò),tcp/ip

2)LWIP簡(jiǎn)介
LWIP是瑞典計(jì)算機(jī)科學(xué)院(SICS)的Adam Dunkels等開發(fā)的一個(gè)小型開源的TCP/IP協(xié)議棧,是TCP/IP的一種實(shí)現(xiàn)方式。LWIP是輕量級(jí)IP協(xié)議,有無操作系統(tǒng)的支持都可以運(yùn)行。LWIP實(shí)現(xiàn)的重點(diǎn)是在保持TCP協(xié)議主要功能的基礎(chǔ)上減少對(duì) RAM的占用,它只需十幾KB的RAM和40K左右的ROM就可以運(yùn)行,這使LWIP協(xié)議棧適合在低端的嵌入式系統(tǒng)中使用。關(guān)于LWIP的詳細(xì)信息大家可以去http://savannah.nongnu.org/projects/lwip/這個(gè)網(wǎng)站去查閱。
LWIP 的主要特性如下:
?IGMP 協(xié)議,用于網(wǎng)絡(luò)組管理,可以實(shí)現(xiàn)多播數(shù)據(jù)的接收
?Internet協(xié)議(IP),包括 IPv4 和 IPv6,支持 IP 分片與重裝,包括通過多個(gè)網(wǎng)絡(luò)接口的數(shù)據(jù)包轉(zhuǎn)發(fā)
?用于網(wǎng)絡(luò)維護(hù)和調(diào)試的Internet控制消息協(xié)議(ICMP)
?用戶數(shù)據(jù)報(bào)協(xié)議(UDP)
?傳輸控制協(xié)議(TCP)擁塞控制,往返時(shí)間(RTT)估計(jì),快速恢復(fù)和重傳
?DNS,域名解析
?SNMP,簡(jiǎn)單網(wǎng)絡(luò)管理協(xié)議
?動(dòng)態(tài)主機(jī)配置協(xié)議(DHCP)
?以太網(wǎng)地址解析協(xié)議(ARP)
?AUTOIP,IP 地址自動(dòng)配置
?PPP,點(diǎn)對(duì)點(diǎn)協(xié)議,支持 PPPoE
我們本次使用的lwip212_v1_1是一個(gè)基于開源lwIP庫(kù)版本2.1.2構(gòu)建的庫(kù)(Vivado 2019.2版本)。lwip212_v1_1庫(kù)為Ethernetlite(axi_ethernetlite)、TEMAC(axi_ethernet)以及千兆以太網(wǎng)控制器和MAC(GigE)內(nèi)核提供適配器。該庫(kù)可以在MicroBlaze、ARM Cortex-A9、ARM Cortex-A53和ARM Cortex-R5處理器上運(yùn)行。Ethernetlite和TEMAC核心適用于MicroBlaze系統(tǒng)。千兆以太網(wǎng)控制器和MAC(GigE)內(nèi)核僅適用于ARM Cortex-A9(MPSOC-7000處理器設(shè)備)、ARM Cortex-A53和ARM Cortex-R5系統(tǒng)(MPSOC UltraScale+ MPSoC)。
lwip212_v1_1提供二種用戶編程接口方式:raw API和socket API。
Raw API:是為高性能和低內(nèi)存開銷而定制的。這種類型的API把網(wǎng)絡(luò)協(xié)議棧和應(yīng)用程序放在一個(gè)進(jìn)程里,連接網(wǎng)絡(luò)協(xié)議和應(yīng)用程序的紐帶是回調(diào)函數(shù),回調(diào)函數(shù)實(shí)際上是一個(gè)普通的C函數(shù)。為了接收數(shù)據(jù),應(yīng)用程序會(huì)首先向協(xié)議棧注冊(cè)一個(gè)回調(diào)函數(shù),當(dāng)關(guān)聯(lián)的連接有一個(gè)信息到達(dá)時(shí),該回調(diào)函數(shù)就被協(xié)議棧調(diào)用。這種實(shí)現(xiàn)方式即有優(yōu)點(diǎn)也有缺點(diǎn)。優(yōu)點(diǎn)是數(shù)據(jù)的接收和發(fā)送不會(huì)導(dǎo)致進(jìn)程的切換,提供了最好的性能,執(zhí)行速度快,而且消耗的內(nèi)存資源少;缺點(diǎn)是應(yīng)用程序無法進(jìn)行連續(xù)運(yùn)算,因?yàn)榫W(wǎng)絡(luò)協(xié)議的處理和運(yùn)算是在同一進(jìn)程中完成的,二者無法并行發(fā)生。Raw API是資源較少的嵌入式系統(tǒng)的首選方法,也是在沒有操作系統(tǒng)的情況下運(yùn)行l(wèi)wIP時(shí)唯一可用的API。
Socket API:提供了一個(gè)基于open-read-write-close 模塊的BSD socket-style接口,需要操作系統(tǒng)。此接口在性能和內(nèi)存要求方面不如Raw API高效,不適用于小型嵌入式系統(tǒng),但移植性更好。
本章我們使用無需操作系統(tǒng)(standalone)的RAW API編程接口。
3)PS的千兆以太網(wǎng)控制器
在介紹PS的千兆以太網(wǎng)控制器之前,我們首先了解下MAC與PHY芯片及GMII與RGMII接口。
以太網(wǎng)卡工作在OSI模型的最后兩層,物理層和數(shù)據(jù)鏈路層,物理層定義了數(shù)據(jù)傳送與接收所需要的電與光信號(hào)、線路狀態(tài)、時(shí)鐘基準(zhǔn)、數(shù)據(jù)編碼和電路等,并向數(shù)據(jù)鏈路層設(shè)備提供標(biāo)準(zhǔn)接口。物理層的芯片稱之為 PHY。此外PHY還提供了和對(duì)端設(shè)備連接的重要功能并通過LED燈顯示出當(dāng)前的連接的狀態(tài)和工作狀態(tài)。當(dāng)我們給網(wǎng)卡接入網(wǎng)線的時(shí)候,PHY不斷發(fā)出的脈沖信號(hào)檢測(cè)到對(duì)端有設(shè)備,它們通過一套標(biāo)準(zhǔn)的語(yǔ)言交流,互相協(xié)商并確定連接速度、工作模式、是否采用流控等。通常情況下,協(xié)商的結(jié)果是兩個(gè)設(shè)備中能同時(shí)支持的最大速度和最好的雙工模式。這個(gè)技術(shù)被稱為AutoNegotiation,即自協(xié)商。
數(shù)據(jù)鏈路層則提供尋址機(jī)構(gòu)、數(shù)據(jù)幀的構(gòu)建、數(shù)據(jù)差錯(cuò)檢查、傳送控制、向網(wǎng)絡(luò)層提供標(biāo)準(zhǔn)的數(shù)據(jù)接口等功能。以太網(wǎng)卡中數(shù)據(jù)鏈路層的芯片稱之為MAC控制器。
MAC控制器與PHY通過MII(Medium Independent Interface)接口進(jìn)行連接。MII接口有很多類型,千兆以太網(wǎng)多使用GMII(Gigabit Medium Independent Interface)或RGMII(Reduced Gigabit Media Independent Interface)接口進(jìn)行連接。
fpga lwip,正點(diǎn)原子,fpga開發(fā),網(wǎng)絡(luò),tcp/ip

圖 32.1.1 GMII接口
GMII接口提供了8位數(shù)據(jù)通道,125MHz的時(shí)鐘速率,從而具有1000Mbps的數(shù)據(jù)傳輸速率。除MDC和MDIO外,有24根接口信號(hào)線,如圖 32.1.1所示。
GMII接口主要包括四個(gè)部分。一是從MAC層到物理層(PHY)的發(fā)送數(shù)據(jù)接口,二是從物理層到MAC層的接收數(shù)據(jù)接口,三是從物理層到MAC層的狀態(tài)指示信號(hào),四是MAC 層和物理層之間傳送控制和狀態(tài)信息的MDIO接口。各部分接口信號(hào)說明見下表:
表32.1.2 GMII接口信號(hào)
fpga lwip,正點(diǎn)原子,fpga開發(fā),網(wǎng)絡(luò),tcp/ip

RGMII接口即Reduced GMII,是GMII接口的簡(jiǎn)化版本。RGMII采用4位數(shù)據(jù)接口,工作時(shí)鐘125MHz,并且在上升沿和下降沿同時(shí)傳輸數(shù)據(jù),因此傳輸速率可達(dá)1000Mbps。采用 RGMII的目的是降低電路成本,使實(shí)現(xiàn)這種接口的器件的引腳數(shù)從24個(gè)減少到14個(gè)(不包括MDC和MDIO),接口信號(hào)如下圖所示:
fpga lwip,正點(diǎn)原子,fpga開發(fā),網(wǎng)絡(luò),tcp/ip

圖 32.1.2 RGMII接口
可以看到RGMII接口相對(duì)于GMII 接口,在TXD和RXD上總共減少8根數(shù)據(jù)線。TX_CTL信號(hào)線上傳送TX_EN和TX_ER兩種信息,在TX_CLK的上升沿發(fā)送TX_EN,下降沿發(fā)送TX_ER;同樣的,RX_CTL信號(hào)線上傳送RX_DV和RX_ER兩種信息,在RX_CLK的上升沿發(fā)送RX_DV,下降沿發(fā)送RX_ER。進(jìn)一步減少了2根數(shù)據(jù)線。其他信號(hào)同GMII接口。
現(xiàn)在我們來看下PS的千兆以太網(wǎng)控制器(GEM)。PS的千兆以太網(wǎng)控制器實(shí)現(xiàn)了與IEEE 802.3-2008標(biāo)準(zhǔn)兼容的10/100/1000 Mb/s以太網(wǎng)MAC,在10/100Mb/s速度下,能夠在半雙工或全雙工模式下運(yùn)行,在1000Mb/s速度下全雙工運(yùn)行。PS配備四個(gè)千兆以太網(wǎng)控制器。每個(gè)控制器都可以獨(dú)立配置,其內(nèi)部原理圖如下:
fpga lwip,正點(diǎn)原子,fpga開發(fā),網(wǎng)絡(luò),tcp/ip

圖 32.1.3 以太網(wǎng)控制器
DMA控制器通過AXI接口連接到存儲(chǔ)器。MAC控制器與FIFO接口的連接為嵌入式處理系統(tǒng)中的分組數(shù)據(jù)存儲(chǔ)提供scatter-gather類型的功能。另外從圖 32.1.3中可以看到,如果通過MIO連接至PS端的以太網(wǎng)PHY芯片,則每個(gè)控制器使用RGMII接口以節(jié)省引腳。如果通過EMIO連接至PL端的以太網(wǎng)PHY芯片,則每個(gè)控制器使用GMII接口。
可以通過APB總線訪問千兆以太網(wǎng)控制器的寄存器。寄存器用于配置MAC的功能、選擇不同的操作模式、以及啟用和監(jiān)控網(wǎng)絡(luò)管理統(tǒng)計(jì)信息。每個(gè)控制器為管理PHY芯片提供MDIO接口。

31.2實(shí)驗(yàn)任務(wù)

本章的實(shí)驗(yàn)任務(wù)是建立PS的以太網(wǎng)的硬件環(huán)境,使用VITIS軟件自帶的Lwip Echo Server模板了解LWIP的使用。

31.3硬件設(shè)計(jì)

MPSOC開發(fā)板上有一個(gè)PS端RJ45以太網(wǎng)接口,用于連接以太網(wǎng)線,其原理圖如圖 32.3.1所示:
fpga lwip,正點(diǎn)原子,fpga開發(fā),網(wǎng)絡(luò),tcp/ip

圖 32.3.1 RJ45接口原理圖
以太網(wǎng)的數(shù)據(jù)傳輸離不開以太網(wǎng)PHY(物理層)芯片的支持。我們的MPSOC開發(fā)板上使用的PHY芯片為裕太車通公司的YT8521S,其部分原理圖如圖 32.3.2所示:
fpga lwip,正點(diǎn)原子,fpga開發(fā),網(wǎng)絡(luò),tcp/ip

圖 32.3.2 YT8521S原理圖
YT8521S是高度集成的以太網(wǎng)收發(fā)器,符合10Base-T、100Base-TX和1000Base-T IEEE 802.3標(biāo)準(zhǔn),提供了所有必要的物理層功能。YT8521S采用最先進(jìn)的 DSP 技術(shù)和模擬前端(AFE),實(shí)現(xiàn)了交叉檢測(cè)和自動(dòng)校正、極性校正、自適應(yīng)均衡、串音消除、回聲消除、定時(shí)恢復(fù)和糾錯(cuò)等功能,以提供10Mbps、100Mbps或1000Mbps的強(qiáng)大傳輸和接收能力。
在圖 32.3.2中,YT8521S右側(cè)引腳連接到開發(fā)板的RJ45接口,左側(cè)引腳通過RGMII接口與PS端相連接。MDC/MDIO接口用來配置YT8521S。其復(fù)位信號(hào)與PS的PS_POR_B相連接,在PS的上電復(fù)位時(shí)同時(shí)復(fù)位YT8521S,不需要通過MIO來控制。YT8521S與PS的MIO引腳的連接如下圖所示,從中可以看到,YT8521S的RGMII接口通過MIO64-75引腳與PS相連接,MDC/MDIO連接到PS的MIO76-77引腳。
fpga lwip,正點(diǎn)原子,fpga開發(fā),網(wǎng)絡(luò),tcp/ip

圖 32.3.3 PHY芯片同PS接口連接
根據(jù)實(shí)驗(yàn)任務(wù)我們可以畫出本次實(shí)驗(yàn)的系統(tǒng)框圖,如下圖所示:
fpga lwip,正點(diǎn)原子,fpga開發(fā),網(wǎng)絡(luò),tcp/ip

圖 32.3.4 系統(tǒng)框圖
在圖 32.3.4中,UART用于打印程序相關(guān)的信息,千兆以太網(wǎng)控制器GEM通過MIO與外部以太網(wǎng)進(jìn)行連接。
step1:創(chuàng)建Vivado工程
本次實(shí)驗(yàn)的硬件設(shè)計(jì)可以在《第一章Hello World》實(shí)驗(yàn)的基礎(chǔ)上進(jìn)行。
1-1 我們先打開《第一章Hello World》實(shí)驗(yàn)的Vivado工程,打開后將工程另存為 “l(fā)wip_echo_server”工程,如下圖所示,然后點(diǎn)擊“OK”按鈕。
fpga lwip,正點(diǎn)原子,fpga開發(fā),網(wǎng)絡(luò),tcp/ip

圖 32.3.5 另存為工程為lwip_echo
step2:使用IP Integrator創(chuàng)建Processing System
2-1 在Flow Navigator中,點(diǎn)擊IP INTEGRATOR下的Open Block Design,如下圖所示:
fpga lwip,正點(diǎn)原子,fpga開發(fā),網(wǎng)絡(luò),tcp/ip

圖 32.3.6 打開Block Design
2-2 在打開的下圖Diagram窗口,雙擊打開Zynq UltraScale+ MPSOC重定義窗口。
fpga lwip,正點(diǎn)原子,fpga開發(fā),網(wǎng)絡(luò),tcp/ip

圖 32.3.7 重定義Zynq UltraScale+ MPSOC
2-3 在打開的重定義窗口中,點(diǎn)擊左側(cè)的I/O Configuration,在右側(cè)的界面中依次展開High Speed->GEM,勾選“GEM3”并選擇“MIO64…75”,同時(shí)勾選“MDIO”并選擇“MIO76…77”。這里選擇“MIO64至MIO77”是為了和開發(fā)板硬件對(duì)應(yīng),如下圖所示:
fpga lwip,正點(diǎn)原子,fpga開發(fā),網(wǎng)絡(luò),tcp/ip

圖 32.3.8 PS以太網(wǎng)接口配置界面
2-4 同樣是在剛才界面中,依次展開Low Speed->TTC,勾選TTC0至TTC3,完成后,點(diǎn)擊右下角的“OK”,如下圖所示:
fpga lwip,正點(diǎn)原子,fpga開發(fā),網(wǎng)絡(luò),tcp/ip

圖 32.3.9配置三路定時(shí)器
2-5 由于不需要添加其它IP,點(diǎn)擊Validate Design驗(yàn)證無誤后,按Ctrl+S快捷鍵保存Diagram。此時(shí)我們的第二步完成,進(jìn)入第三步。
step3:生成頂層HDL
在sources面板中,右鍵點(diǎn)擊Block Design設(shè)計(jì)文件“design_1.bd”,然后執(zhí)行“Generate Output Products”。因?yàn)槲覀冊(cè)趧?chuàng)建Hello World實(shí)驗(yàn)時(shí)創(chuàng)建頂層HDL Wrapper使用的是Let Vivado manage wrapper and auto-update選項(xiàng),所以此處無需再創(chuàng)建頂層HDL Wrapper,Vivado會(huì)自動(dòng)更新頂層HDL Wrapper
step4:生成Bitstream文件并導(dǎo)出到VITIS
由于本實(shí)驗(yàn)未用到PL部分,所以無需生成Bitstream文件,只需導(dǎo)出到VITIS即可。如果使用到PL,則需要添加引腳約束以及對(duì)該系統(tǒng)進(jìn)行綜合、實(shí)現(xiàn)并生成Bitstream文件。
4-1 導(dǎo)出硬件。
在菜單欄中選擇 File > Export > Export hardware,并在彈出的對(duì)話框中,取消勾選“Include bitstream”,直接點(diǎn)擊“OK”按鈕。將導(dǎo)出的design_1_wrapper.xsa文件放到vitis文件夾中。
4-2 硬件導(dǎo)出完成后,選擇菜單Tools->Launch Vitis,啟動(dòng)VITIS開發(fā)環(huán)境。
31.4軟件設(shè)計(jì)
step5:在VITIS中創(chuàng)建應(yīng)用工程
5-1 在菜單欄中選擇File->New->Application Project, 新建一個(gè)VITIS應(yīng)用工程。
5-2 在彈出的下圖所示界面中,輸入工程名“l(fā)wip_echo_server”。點(diǎn)擊“Next”,在接下來的平臺(tái)(platform)界面中,點(diǎn)擊“Create a new platform from hardware(XSA)”標(biāo)簽頁(yè),添加硬件平臺(tái)文件。
fpga lwip,正點(diǎn)原子,fpga開發(fā),網(wǎng)絡(luò),tcp/ip

圖 32.4.1 創(chuàng)建工程
5-3 繼續(xù)點(diǎn)擊“Next”,在接下來的模板界面中(templates),選擇“l(fā)wIP Echo Server”工程模版,然后點(diǎn)擊“Finish”按鈕,完成工程創(chuàng)建,如圖 32.4.2所示。
lwIP Echo Server應(yīng)用程序提供了如何使用輕量級(jí)IP堆棧(lwIP)的簡(jiǎn)單演示。此應(yīng)用程序?qū)PSOC開發(fā)板MAC地址設(shè)置為00:0a:35:00:01:02,默認(rèn)使用DHCP獲取動(dòng)態(tài)IP地址,如果DHCP失敗,則使用默認(rèn)設(shè)置的靜態(tài)IPv4地址192.168.1.10或IPv6地址FE80:0:0:0:20??A:35FF:FE00:102。服務(wù)器在端口7處偵聽輸入,并簡(jiǎn)單地回傳發(fā)送到該端口的任何數(shù)據(jù)。
這里簡(jiǎn)單的介紹下DHCP。DHCP(Dynamic Host Configuration Protocol)即動(dòng)態(tài)主機(jī)配置協(xié)議,通常應(yīng)用在大型的局域網(wǎng)絡(luò)環(huán)境中,主要作用是集中的管理、分配IP地址,使網(wǎng)絡(luò)環(huán)境中的主機(jī)動(dòng)態(tài)的獲得IP地址、Gateway地址、DNS服務(wù)器地址等信息,并能夠提升地址的使用率。
fpga lwip,正點(diǎn)原子,fpga開發(fā),網(wǎng)絡(luò),tcp/ip

圖 32.4.2 選擇“l(fā)wIP Echo Server”模版
5-4 展開lwip_echo_server應(yīng)用工程目錄下的src目錄,可以看到很多源文件,如圖 32.4.4所示,其中大多是平臺(tái)相關(guān)的文件(platform開頭的文件)。下面我們簡(jiǎn)單的介紹下各文件的作用。
echo.c:Echo服務(wù)的的主要實(shí)現(xiàn)代碼。
i2c_access.c:IIC訪問PHY的功能實(shí)現(xiàn),本實(shí)驗(yàn)不用。
iic_phyreset.c:IIC復(fù)位PHY,本實(shí)驗(yàn)不用。
main.c:main函數(shù)所在文件。
platform_config.h:平臺(tái)配置相關(guān)文件,主要是宏定義所使用的平臺(tái)。
我們打開“platform_config.h”文件,內(nèi)容如下:
fpga lwip,正點(diǎn)原子,fpga開發(fā),網(wǎng)絡(luò),tcp/ip

圖 32.4.3 platform_config.h文件內(nèi)容
可以看到宏定義了 PLATFORM_ZYNQMP,也就是說本實(shí)驗(yàn)是與ZYNQMP平臺(tái)相關(guān)的。所以本實(shí)驗(yàn)需要的是platform_zynqmp.c文件,而以下的與其它平臺(tái)相關(guān)的platform_mb.c、platform_ppc.c、platform_zynq.c、platform.c都無需使用。
platform_config.h是基于硬件設(shè)計(jì)生成的。
sfp.c和si5324.c分別用于sfp PHY和si5324芯片,用于官方特定的開發(fā)板,與我們使用的MPSOC開發(fā)板不相關(guān)。
fpga lwip,正點(diǎn)原子,fpga開發(fā),網(wǎng)絡(luò),tcp/ip

圖 32.4.4 src目錄
5-5 為了方便分析,我們將src文件夾與本實(shí)驗(yàn)不相關(guān)的平臺(tái)文件刪除,刪除后的src文件夾內(nèi)容如下圖所示:
fpga lwip,正點(diǎn)原子,fpga開發(fā),網(wǎng)絡(luò),tcp/ip

圖 32.4.5 刪除不相關(guān)文件后的src文件夾內(nèi)容
5-6 現(xiàn)在我們打開main.c文件,為了方便分析源代碼,在main.c文件中將帶有下圖箭頭所指的預(yù)編譯指令刪除。
fpga lwip,正點(diǎn)原子,fpga開發(fā),網(wǎng)絡(luò),tcp/ip

圖 32.4.6 刪除不需要的預(yù)編譯指令
刪除不適用的預(yù)編譯指令后的main.c代碼如下:

1   #include <stdio.h>
2   
3   #include "xparameters.h"
4   
5   #include "netif/xadapter.h"
6   
7   #include "platform.h"
8   #include "platform_config.h"
9   #if defined (__arm__) || defined(__aarch64__)
10  #include "xil_printf.h"
11  #endif
12  
13  #include "lwip/tcp.h"
14  #include "xil_cache.h"
15  
16  #if LWIP_IPV6==1
17  #include "lwip/ip.h"
18  #else
19  #if LWIP_DHCP==1
20  #include "lwip/dhcp.h"
21  #endif
22  #endif
23  
24  /* defined by each RAW mode application */
25  void print_app_header();
26  int start_application();
27  int transfer_data();
28  void tcp_fasttmr(void);
29  void tcp_slowtmr(void);
30  
31  /* missing declaration in lwIP */
32  void lwip_init();
33  
34  #if LWIP_IPV6==0
35  #if LWIP_DHCP==1
36  extern volatile int dhcp_timoutcntr;
37  err_t dhcp_start(struct netif *netif);
38  #endif
39  #endif
40  
41  extern volatile int TcpFastTmrFlag;
42  extern volatile int TcpSlowTmrFlag;
43  static struct netif server_netif;
44  struct netif *echo_netif;
45  
46  #if LWIP_IPV6==1
47  void print_ip6(char *msg, ip_addr_t *ip)
48  {
49      print(msg);
50      xil_printf(" %x:%x:%x:%x:%x:%x:%x:%x\n\r",
51              IP6_ADDR_BLOCK1(&ip->u_addr.ip6),
52              IP6_ADDR_BLOCK2(&ip->u_addr.ip6),
53              IP6_ADDR_BLOCK3(&ip->u_addr.ip6),
54              IP6_ADDR_BLOCK4(&ip->u_addr.ip6),
55              IP6_ADDR_BLOCK5(&ip->u_addr.ip6),
56              IP6_ADDR_BLOCK6(&ip->u_addr.ip6),
57              IP6_ADDR_BLOCK7(&ip->u_addr.ip6),
58              IP6_ADDR_BLOCK8(&ip->u_addr.ip6));
59  
60  }
61  #else
62  void
63  print_ip(char *msg, ip_addr_t *ip)
64  {
65      print(msg);
66      xil_printf("%d.%d.%d.%d\n\r", ip4_addr1(ip), ip4_addr2(ip),
67              ip4_addr3(ip), ip4_addr4(ip));
68  }
69  
70  void
71  print_ip_settings(ip_addr_t *ip, ip_addr_t *mask, ip_addr_t *gw)
72  {
73  
74      print_ip("Board IP: ", ip);
75      print_ip("Netmask : ", mask);
76      print_ip("Gateway : ", gw);
77  }
78  #endif
79  
80  int main()
81  {
82  #if LWIP_IPV6==0
83      ip_addr_t ipaddr, netmask, gw;
84  
85  #endif
86      /* the mac address of the board. this should be unique per board */
87      unsigned char mac_ethernet_address[] =
88      { 0x00, 0x0a, 0x35, 0x00, 0x01, 0x02 };
89  
90      echo_netif = &server_netif;
91  #if defined (__arm__) && !defined (ARMR5)
92  #if XPAR_GIGE_PCS_PMA_SGMII_CORE_PRESENT == 1 || XPAR_GIGE_PCS_PMA_1000BASEX_CORE_PRESENT == 1
93      ProgramSi5324();
94      ProgramSfpPhy();
95  #endif
96  #endif
97  
98  /* Define this board specific macro in order perform PHY reset on ZCU102 */
99  #ifdef XPS_BOARD_ZCU102
100     if(IicPhyReset()) {
101         xil_printf("Error performing PHY reset \n\r");
102         return -1;
103     }
104 #endif
105 
106     init_platform();
107 
108 #if LWIP_IPV6==0
109 #if LWIP_DHCP==1
110     ipaddr.addr = 0;
111     gw.addr = 0;
112     netmask.addr = 0;
113 #else
114     /* initialize IP addresses to be used */
115     IP4_ADDR(&ipaddr,  192, 168,   1, 10);
116     IP4_ADDR(&netmask, 255, 255, 255,  0);
117     IP4_ADDR(&gw,      192, 168,   1,  1);
118 #endif
119 #endif
120     print_app_header();
121 
122     lwip_init();
123 
124 #if (LWIP_IPV6 == 0)
125     /* Add network interface to the netif_list, and set it as default */
126     if (!xemac_add(echo_netif, &ipaddr, &netmask,
127                         &gw, mac_ethernet_address,
128                         PLATFORM_EMAC_BASEADDR)) {
129         xil_printf("Error adding N/W interface\n\r");
130         return -1;
131     }
132 #else
133     /* Add network interface to the netif_list, and set it as default */
134     if (!xemac_add(echo_netif, NULL, NULL, NULL, mac_ethernet_address,
135                         PLATFORM_EMAC_BASEADDR)) {
136         xil_printf("Error adding N/W interface\n\r");
137         return -1;
138     }
139     echo_netif->ip6_autoconfig_enabled = 1;
140 
141     netif_create_ip6_linklocal_address(echo_netif, 1);
142     netif_ip6_addr_set_state(echo_netif, 0, IP6_ADDR_VALID);
143 
144     print_ip6("\n\rBoard IPv6 address ", &echo_netif->ip6_addr[0].u_addr.ip6);
145 
146 #endif
147     netif_set_default(echo_netif);
148 
149     /* now enable interrupts */
150     platform_enable_interrupts();
151 
152     /* specify that the network if is up */
153     netif_set_up(echo_netif);
154 
155 #if (LWIP_IPV6 == 0)
156 #if (LWIP_DHCP==1)
157     /* Create a new DHCP client for this interface.
158      * Note: you must call dhcp_fine_tmr() and dhcp_coarse_tmr() at
159      * the predefined regular intervals after starting the client.
160      */
161     dhcp_start(echo_netif);
162     dhcp_timoutcntr = 24;
163 
164     while(((echo_netif->ip_addr.addr) == 0) && (dhcp_timoutcntr > 0))
165         xemacif_input(echo_netif);
166 
167     if (dhcp_timoutcntr <= 0) {
168         if ((echo_netif->ip_addr.addr) == 0) {
169             xil_printf("DHCP Timeout\r\n");
170             xil_printf("Configuring default IP of 192.168.1.10\r\n");
171             IP4_ADDR(&(echo_netif->ip_addr),  192, 168,   1, 10);
172             IP4_ADDR(&(echo_netif->netmask), 255, 255, 255,  0);
173             IP4_ADDR(&(echo_netif->gw),      192, 168,   1,  1);
174         }
175     }
176 
177     ipaddr.addr = echo_netif->ip_addr.addr;
178     gw.addr = echo_netif->gw.addr;
179     netmask.addr = echo_netif->netmask.addr;
180 #endif
181 
182     print_ip_settings(&ipaddr, &netmask, &gw);
183 
184 #endif
185     /* start the application (web server, rxtest, txtest, etc..) */
186     start_application();
187 
188     /* receive and process packets */
189     while (1) {
190         if (TcpFastTmrFlag) {
191             tcp_fasttmr();
192             TcpFastTmrFlag = 0;
193         }
194         if (TcpSlowTmrFlag) {
195             tcp_slowtmr();
196             TcpSlowTmrFlag = 0;
197         }
198         xemacif_input(echo_netif);
199         transfer_data();
200     }
201 
202     /* never reached */
203     cleanup_platform();
204 
205     return 0;
206 }

可以看到代碼中有很多的#if LWIP_IPV60和#if LWIP_DHCP1這類預(yù)編譯指令,這是因?yàn)閘wip既支持IPv4也支持IPv6,IPv4和DHCP默認(rèn)支持。如果想重新配置lwip如取消DHCP,可以通過以下方式重配置lwip。
雙擊硬件平臺(tái)工程“platform.spr”,在右側(cè)打開的界面中點(diǎn)擊psu_cortexa_53_0裸機(jī)開發(fā)下的板級(jí)支持包(Board Support Package),然后在板級(jí)支持包界面中選擇“Modify BSP Settings”,如下圖所示:
fpga lwip,正點(diǎn)原子,fpga開發(fā),網(wǎng)絡(luò),tcp/ip

圖 32.4.7 Board Support Package Settings
在彈出的界面中點(diǎn)擊左側(cè)standalone下的lwip211,右側(cè)就是lwip的配置面板。如下圖所示,箭頭所指的兩處分別是配置啟用DHCP和使能IPv6,可以看到,dhcp默認(rèn)為true,ipv6默認(rèn)為false。
fpga lwip,正點(diǎn)原子,fpga開發(fā),網(wǎng)絡(luò),tcp/ip

圖 32.4.8 lwip的配置面板
main函數(shù)可以說是使用lwip的一個(gè)標(biāo)準(zhǔn)函數(shù),可以在不修改main函數(shù)的情況下就可實(shí)現(xiàn)其它的應(yīng)用功能。main函數(shù)主要完成以下功能:
1)在代碼的88行設(shè)置MPSOC開發(fā)板的MAC地址為00:0a:35:00:01:02。
2)通過調(diào)用init_platform函數(shù)配置定時(shí)器和建立中斷以初始化平臺(tái),定時(shí)器產(chǎn)生周期性中斷。
3)調(diào)用lwip_init函數(shù)完成對(duì)lwip協(xié)議棧的初始化,代碼第122行。
4)初始化lwIP后,使用xemac_add函數(shù)添加以太網(wǎng)MAC到協(xié)議棧中。
5)使用platform_enable_interrupts函數(shù)使能中斷和啟動(dòng)定時(shí)器。
6)從代碼第156~174行,啟動(dòng)DHCP服務(wù)獲取動(dòng)態(tài)IP地址,如果超時(shí)未獲取到動(dòng)態(tài)IP地址,則使用默認(rèn)的靜態(tài)IP設(shè)置:
IP Address: 192.168.1.10
Netmask : 255.255.255.0
Gateway : 192.168.1.1
我們也可以根據(jù)需要修改代碼第171~173行的值,從而使用不同的靜態(tài)IP地址。
7)start_application函數(shù)是用戶應(yīng)用函數(shù),當(dāng)我們使用lwip實(shí)現(xiàn)不同的應(yīng)用功能時(shí),可以在保持main函數(shù)不變的情況下,修改start_application函數(shù)的實(shí)現(xiàn)即可。本實(shí)驗(yàn)的start_application函數(shù)在echo.c文件中定義,該函數(shù)創(chuàng)建了一個(gè)TCP服務(wù)并設(shè)定了對(duì)應(yīng)該服務(wù)的回調(diào)函數(shù)。當(dāng)一個(gè)TCP連接請(qǐng)求被接收時(shí),回調(diào)函數(shù)對(duì)客戶端發(fā)送來的數(shù)據(jù)原封不動(dòng)的發(fā)送回去,從而實(shí)現(xiàn)echo服務(wù)器的功能。由于本實(shí)驗(yàn)的目的在于初步了解lwip的使用,對(duì)于涉及到的TCP協(xié)議的使用,我們將在下一章講解,本實(shí)驗(yàn)我們不多做介紹。
8)程序進(jìn)入while(1)循環(huán)執(zhí)行數(shù)據(jù)包接收操作,以及它需要執(zhí)行的任何其他特定于應(yīng)用程序的操作。TcpFastTmrFlag和TcpSlowTmrFlag是TCP TX處理所必需的,定時(shí)器中斷分別以250ms和500ms的周期來改變這兩個(gè)標(biāo)志位。數(shù)據(jù)包接收函數(shù)xemacif_input處理由中斷處理程序接收的數(shù)據(jù)包,并將它們傳遞給lwIP,然后lwIP為每個(gè)接收到的數(shù)據(jù)包調(diào)用適當(dāng)?shù)幕卣{(diào)處理程序。transfer_data函數(shù)無實(shí)際意義,可以刪除。
5-7 程序修改完成后,按快捷鍵Ctrl+S保存main.c文件,右擊應(yīng)用工程名選擇Build Project進(jìn)行編譯。編譯完成后控制臺(tái)(Console)中會(huì)出現(xiàn)提示信息“Build Finished”,同時(shí)在應(yīng)用工程的Binaries目錄下可以看到生成的elf文件。

31.5下載驗(yàn)證

首先將下載器與開發(fā)板上的JTAG接口連接,下載器另外一端與電腦連接。再使用USB連接線將USB_UART(開發(fā)板PS PORT)接口與電腦連接,用于串口通信。使用網(wǎng)線一端連接開發(fā)板的PS以太網(wǎng)接口(PS_ETH),另一端與電腦或路由器連接。最后連接開發(fā)板的電源,給開發(fā)板上電,如下圖所示:
fpga lwip,正點(diǎn)原子,fpga開發(fā),網(wǎng)絡(luò),tcp/ip

圖 32.5.1 MPSOC開發(fā)板實(shí)物圖
現(xiàn)在進(jìn)入最后一步。
step6:板級(jí)驗(yàn)證
6-1打開Vitis Terminal終端,設(shè)置并連接串口。
6-2 下載程序。
6-3 可以看到串口打印的結(jié)果如下:
fpga lwip,正點(diǎn)原子,fpga開發(fā),網(wǎng)絡(luò),tcp/ip

圖 32.5.2 顯示打印結(jié)果
在打印出“l(fā)ink speed for phy address 7: 1000”后要等一段時(shí)間進(jìn)行DHCP服務(wù)。因?yàn)槲覀儗㈤_發(fā)板的以太網(wǎng)接口與電腦進(jìn)行連接,所以出現(xiàn)了DHCP Timeout,開發(fā)板的IP地址為默認(rèn)設(shè)置的靜態(tài)IP地址192.168.1.10。如果和路由器進(jìn)行連接,開發(fā)板的IP則是由DHCP獲取的動(dòng)態(tài)IP設(shè)置。TCP應(yīng)答服務(wù)的端口號(hào)為7。另外需要說明的是串口打印的“TCP packets sent to port 6001 will be echoed back”可能是該模板最初版本使用的是6001端口,后面更新的時(shí)候使用了端口7,而該語(yǔ)句沒有修改或刪除,所以這是無意義的語(yǔ)句,可以找到print_app_header函數(shù)從而刪除該語(yǔ)句。
在打印信息的第三行出現(xiàn)一個(gè)警告,這是因?yàn)閘wip模板默認(rèn)phy芯片是Marvell、TI或Realtek Ethernet這三家的,而我們開發(fā)板上使用的是其它廠家的,不影響正常工作,所以這個(gè)地方的警告忽略就可以了。
在使用靜態(tài)IP地址時(shí),需要確保同網(wǎng)段內(nèi)沒有主機(jī)使用192.168.1.10 的IP地址,否則會(huì)造成IP沖突。可以在開發(fā)板未上電前或未下載程序前在CMD里輸入“ping 192.168.1.10”命令查看是否能ping通,如果能ping通,說明網(wǎng)絡(luò)中有此IP地址,此時(shí)需要更改靜態(tài)IP地址為其他值,如192.168.1.123等。
6-4 使用網(wǎng)絡(luò)調(diào)試助手發(fā)送數(shù)據(jù)。在使用網(wǎng)絡(luò)助手調(diào)試之前需要按照本章實(shí)驗(yàn)的步驟6-7設(shè)置網(wǎng)絡(luò)適配器。設(shè)置完后在電腦端打開網(wǎng)絡(luò)調(diào)試助手,設(shè)置協(xié)議類型為:TCP Client,服務(wù)器IP地址為串口打印的地址,此處為:192.168.1.10,服務(wù)器端口號(hào)為:7,然后點(diǎn)擊連接,即可連上開發(fā)板的TCP Sever,如下圖所示:
fpga lwip,正點(diǎn)原子,fpga開發(fā),網(wǎng)絡(luò),tcp/ip

圖 32.5.3 電腦端網(wǎng)絡(luò)調(diào)試助手TCP Client測(cè)試界面
6-5 本實(shí)驗(yàn)除了可以使用網(wǎng)絡(luò)調(diào)試助手軟件外,還可以使用telnet。
我們打開電腦的CMD(按win+r鍵后輸入cmd),輸入“telnet 192.168.1.10 7”,如下圖所示:
fpga lwip,正點(diǎn)原子,fpga開發(fā),網(wǎng)絡(luò),tcp/ip

圖 32.5.4 進(jìn)行telnet連接
回車后,進(jìn)入下圖所示界面:
fpga lwip,正點(diǎn)原子,fpga開發(fā),網(wǎng)絡(luò),tcp/ip

圖 32.5.5 連接成功后的界面
如果回車后出現(xiàn)像下圖所示界面所示“telnet不是內(nèi)部或外部命令,也不是可運(yùn)行的程序或批處理文件”,則表明未開啟Windows的telnet客戶端功能,開啟方式見6-6。
fpga lwip,正點(diǎn)原子,fpga開發(fā),網(wǎng)絡(luò),tcp/ip

圖 32.5.6 未啟用telnet客戶端時(shí)的界面
此時(shí)我們按鍵盤上的字母和數(shù)字鍵,如123abc,控制臺(tái)顯示如下:
fpga lwip,正點(diǎn)原子,fpga開發(fā),網(wǎng)絡(luò),tcp/ip

圖 32.5.7 控制臺(tái)顯示
可以看到除了1只有一個(gè)外,其它字符都顯示兩個(gè),一個(gè)是我們按下的,另一個(gè)是開發(fā)板的lwip echo server應(yīng)答的??梢姽δ芑菊_,不過從使用上看還是有問題的,一是第一次按下的字符沒有回顯;二是不能輸入字符串,這些問題主要是windows自帶的telnet的問題。如果使用第三方提供的telnet工具,例如使用Win10系統(tǒng)的讀者可以開啟WSL,從而使用linux系統(tǒng)提供的telnet功能進(jìn)行連接,如下圖(通過WSL使用Ubuntu系統(tǒng)):
fpga lwip,正點(diǎn)原子,fpga開發(fā),網(wǎng)絡(luò),tcp/ip

圖 32.5.8 功能完全正常
可以看到一點(diǎn)問題也沒有。按“Ctrl+]”可以退出輸入界面,然后輸入“quit”即可退出telnet連接。
注:Telnet協(xié)議是TCP/IP協(xié)議族中的一員,是Internet遠(yuǎn)程登錄服務(wù)的標(biāo)準(zhǔn)協(xié)議和主要方式。它為用戶提供了在本地計(jì)算機(jī)上完成遠(yuǎn)程主機(jī)工作的能力。在終端使用者的電腦上使用telnet程序,用它連接到服務(wù)器。終端使用者可以在telnet程序中輸入命令,這些命令會(huì)在服務(wù)器上運(yùn)行,就像直接在服務(wù)器的控制臺(tái)上輸入一樣??梢栽诒镜鼐湍芸刂品?wù)器。
6-6 下面我們介紹一下如何開啟Windows的telnet客戶端功能。在Win10或Win7系統(tǒng)中,按“Win+r”快捷鍵后,在下圖所示界面中輸入“control”。
fpga lwip,正點(diǎn)原子,fpga開發(fā),網(wǎng)絡(luò),tcp/ip

圖 32.5.9 打開控制面板界面
進(jìn)入下圖所示控制面板界面,將查看方式設(shè)置為“類別”,單擊“程序”下的“卸載程序”,如下圖所示:
fpga lwip,正點(diǎn)原子,fpga開發(fā),網(wǎng)絡(luò),tcp/ip

圖 32.5.10 點(diǎn)擊進(jìn)入“程序和功能”界面
在彈出的界面中,單擊“啟用或關(guān)閉Windows功能”,如下圖所示:
fpga lwip,正點(diǎn)原子,fpga開發(fā),網(wǎng)絡(luò),tcp/ip

圖 32.5.11 點(diǎn)擊“啟用或關(guān)閉Windows功能”
在彈出的“Windows功能”界面中,找到“Telnet Client”,并勾選,如下圖所示:
fpga lwip,正點(diǎn)原子,fpga開發(fā),網(wǎng)絡(luò),tcp/ip

圖 32.5.12 勾選telnet client
單擊確定后,如果出現(xiàn)“Windows需要重啟電腦才能完成安裝所請(qǐng)求的更改”字樣,重新啟動(dòng)電腦即可,至此,Windows的telnet客戶端服務(wù)已啟用。
此時(shí)我們進(jìn)行telnet連接會(huì)連接成功,但也有部分電腦會(huì)出現(xiàn)下圖所示現(xiàn)象:
fpga lwip,正點(diǎn)原子,fpga開發(fā),網(wǎng)絡(luò),tcp/ip

圖 32.5.13 無法連接
出現(xiàn)這種情況是因?yàn)楸镜剡B接(Win10為以太網(wǎng))設(shè)置有問題,需要重新設(shè)置。
6-7 更改適配器設(shè)置。在控制面板界面,單擊“網(wǎng)絡(luò)和Internet”下的“查看網(wǎng)絡(luò)狀態(tài)和任務(wù)”,如下圖所示:
fpga lwip,正點(diǎn)原子,fpga開發(fā),網(wǎng)絡(luò),tcp/ip

圖 32.5.14 打開“查看網(wǎng)絡(luò)和狀態(tài)”
進(jìn)入下圖所示界面:
fpga lwip,正點(diǎn)原子,fpga開發(fā),網(wǎng)絡(luò),tcp/ip

圖 32.5.15 更改適配器設(shè)置
點(diǎn)擊箭頭所指的“更改適配器設(shè)置”,進(jìn)入下圖所示界面:
fpga lwip,正點(diǎn)原子,fpga開發(fā),網(wǎng)絡(luò),tcp/ip

圖 32.5.16 打開屬性界面
點(diǎn)擊“以太網(wǎng)”(或者本地連接,如果有)后出現(xiàn)“更改此連接的設(shè)置”,點(diǎn)擊“更改此連接的設(shè)置”,進(jìn)入“屬性”界面,點(diǎn)擊“Internet協(xié)議版本4(TCP/IPv4)”,如下圖所示:
fpga lwip,正點(diǎn)原子,fpga開發(fā),網(wǎng)絡(luò),tcp/ip

圖 32.5.17 進(jìn)入IPv4設(shè)置
進(jìn)入下圖所示界面后,按下圖的設(shè)置進(jìn)行修改。
fpga lwip,正點(diǎn)原子,fpga開發(fā),網(wǎng)絡(luò),tcp/ip

圖 32.5.18 設(shè)置IPv4
經(jīng)過這些設(shè)置后,基本上就可以使用telnet了。
至此,本實(shí)驗(yàn)完成。文章來源地址http://www.zghlxwxcb.cn/news/detail-622804.html

到了這里,關(guān)于【正點(diǎn)原子FPGA連載】第三十一章基于lwip的echo server實(shí)驗(yàn) 摘自【正點(diǎn)原子】DFZU2EG_4EV MPSoC之嵌入式Vitis開發(fā)指南的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!

本文來自互聯(lián)網(wǎng)用戶投稿,該文觀點(diǎn)僅代表作者本人,不代表本站立場(chǎng)。本站僅提供信息存儲(chǔ)空間服務(wù),不擁有所有權(quán),不承擔(dān)相關(guān)法律責(zé)任。如若轉(zhuǎn)載,請(qǐng)注明出處: 如若內(nèi)容造成侵權(quán)/違法違規(guī)/事實(shí)不符,請(qǐng)點(diǎn)擊違法舉報(bào)進(jìn)行投訴反饋,一經(jīng)查實(shí),立即刪除!

領(lǐng)支付寶紅包贊助服務(wù)器費(fèi)用

相關(guān)文章

覺得文章有用就打賞一下文章作者

支付寶掃一掃打賞

博客贊助

微信掃一掃打賞

請(qǐng)作者喝杯咖啡吧~博客贊助

支付寶掃一掃領(lǐng)取紅包,優(yōu)惠每天領(lǐng)

二維碼1

領(lǐng)取紅包

二維碼2

領(lǐng)紅包