在线观看www成人影院-在线观看www日本免费网站-在线观看www视频-在线观看操-欧美18在线-欧美1级

0
  • 聊天消息
  • 系統消息
  • 評論與回復
登錄后你可以
  • 下載海量資料
  • 學習在線課程
  • 觀看技術視頻
  • 寫文章/發帖/加入社區
會員中心
創作中心

完善資料讓更多小伙伴認識你,還能領取20積分哦,立即完善>

3天內不再提示

STM32+LWIP網絡協議棧移植(網卡采用DM9000)

DS小龍哥-嵌入式技術 ? 來源:DS小龍哥-嵌入式技術 ? 作者:DS小龍哥-嵌入式技 ? 2022-03-11 09:49 ? 次閱讀

?

一、環境介紹

MCU: STM32F103ZET6

代碼開發工具: Keil5

TCP/IP協議棧: LWIP

網卡: DM9000

本篇文章主要講解如何在STM32F103工程里添加移植LWIP協議,最終完成TCP服務器、TCP客戶端的通信測試。 網卡采用的是DM9000,工程代碼中,采用STM32的FSMC接口來驅動DM900網卡,DM9000是并口網卡,引腳多,但是速度快,也可以采用其他網卡,SPI協議的、UART協議的等。 比如:ENC28J60。 因為主要是講LWIP協議棧的移植,所以網卡相關的代碼就沒有細說(需要準備一個網卡可以正常通信的工程,再移植)。

下面進行工程的移植代碼比較多,需要下載對應版本的LWIP源碼,STM32本身的DM9000網卡代碼也比較多,文章里會講解移植的詳細的過程,代碼貼出了核心部分。

為了方便大家下載體驗,下面給了個下載鏈接,里面包含了本次文章移植的工程、LWIP源碼,移植文檔等,方便直接體驗。地址在這里https://download.csdn.net/download/xiaolong1126626497/19907087

資料包里的內容如下:

?

poYBAGDYdXCAWkKMAAAAK8RNs4s030.png

?

poYBAGDYdXCAWkKMAAAAK8RNs4s030.png

?

二、D9000網卡

2.1 DM9000簡介

DM9000 是一款完全集成的、性價比高、引腳數少、帶有通用處理器接口的單芯片快速以太網控制器。 自帶一個 10/100M PHY 和 4K 雙字的 SRAM ,DM9000A 為適應各種處理器提供了8位、16 位數據接口訪問內部存儲器,DM9000擁有自動協商功能,DM9000特性如下:

1、集成自適應10/100M收發器。

2、內置16k字節的SRAM。

3、支持硬件幀校驗。

4、兼容3.3V和5.0V輸入輸出電壓。

DM9000 有多種型號,有 100 引腳和 48 引腳的, 開發板選擇的是 48 引腳的 DM9000,型號為 DM9000CEP。

2.2 DM9000 中斷引腳電平設置

DM9000的34(INT)引腳為中斷輸出引腳,默認情況下該引腳高電平有效??梢酝ㄟ^設置DM9000 的 20(EECK)引腳來改變 INT 的有效電平,當 EECK 拉高以后, INT 低電平有效,否則的話 INT 是高電平有效的。開發板上 R66 電阻為 EECK 的上拉電阻,因此開發板上 DM9000 的 INT 引腳是低電平有效的。

poYBAGDYdXCAWkKMAAAAK8RNs4s030.png

?

2.3 DM9000 數據位寬設置

前面我們提了一下 DM9000 支持 8 位和 16 位兩種數據位寬,可以通過 DM9000 的 21(EECS)引腳設置其數據位寬,當 EECS 上拉的時候 DM9000 選擇 8 位數據位寬,否則的話選擇 16 位數據位寬。開發板上的 R65 電阻為 EECS 的上拉電阻,但是此電阻并未焊接! DM9000 芯片的數據位寬為 16 位。

poYBAGDYdXCAWkKMAAAAK8RNs4s030.png

?

2.4 DM9000寄存器

寄存器

描述

寄存器地址

默認值

NCR

網絡控制寄存器。

00H

00H

NSR

網絡狀態寄存器。

01H

00H

TCR

發送控制寄存器。

02H

00H

TSR I

發送狀態寄存器 I。

03H

00H

TSR II

發送狀態寄存器 II。

04H

00H

RCR

接收控制寄存器。

05H

00H

RSR

接收狀態寄存器。

06H

00H

ROCR

接收溢出計數寄存器。

07H

00H

BPTR

背壓門限寄存器。

08H

37H

FCTR

溢出控制門限寄存器。

09H

38H

FCR

TX/RX 流量控制寄存器。

0AH

00H

EPCR

EEPROM/PHY 控制寄存器。

0BH

00H

EPAR

EEPROM/PHY 地址寄存器。

0CH

40H

EPDRL

EEPROM/PHY 數據寄存器低位。

0DH

XXH

EPDRH

EEPROM/PHY 數據寄存器高位。

0EH

XXH

WCR

喚醒控制寄存器。

0FH

00H

PAR

物理地址寄存器。

10H~15H

由 EEPROM 決定

MAR

廣播地址寄存器。

16H~1DH

XXH

GPCR

通用目的控制寄存器(8bit 模式)。

1EH

01H

GPR

通用目的寄存器。

1FH

XXH

TRPAL

TX SRAM 讀指針地址低字節。

22H

00H

TRPAH

TX SRAM 讀指針地址高字節。

23H

00H

RWPAL

RX SRAM 寫指針地址低字節。

24H

00H

RWRAH

RX SRAM 寫指針地址高字節。

25H

0CH

VID

廠家 ID。

28H~29H

0A46H

PID

產品 ID。

2AH~2BH

9000H

CHIPR

芯片版本。

2CH

18H

TCR2

發送控制寄存器 2。

2DH

00H

OCR

操作控制寄存器。

2EH

00H

SMCR

特殊模式控制寄存器。

2FH

00H

ETXCSR

即將發送控制/狀態寄存器。

30H

00H

TCSCR

發送校驗和控制寄存器。

31H

00H

RCSCSR

接收校驗和控制狀態寄存器。

32H

00H

MRCMDX

內存數據預取讀命令寄存器(地址不加 1)。

F0H

XXH

MRCMDX1

內存數據讀命令寄存器(地址不加 1)。

F1H

XXH

MRCMD

內存數據讀命令寄存器(地址加 1)。

F2H

XXH

MRRL

內存數據讀地址寄存器低字節。

F4H

00H

MRRH

內存數據讀地址寄存器高字節。

F5H

00H

MWCMDX

內存數據寫命令寄存器(地址不加 1)

F6H

XXH

MWCMD

內存數據寫命令寄存器(地址加 1)。

F8H

XXH

MWRL

內存數據寫地址寄存器低字節。

FAH

00H

MWRH

內存數據寫地址寄存器高字節。

FBH

00H

TXPLL

TX 數據包長度低字節寄存器。

FCH

XXH

TXPLH

TX 數據包長度高字節寄存器。

FDH

XXH

ISR

中斷狀態寄存器。

FEH

00H

IMR

中斷屏蔽寄存器。

FFH

00H

2.5 DM9000常用寄存器介紹

NCR、 NSR、 TCR、 RCR、 FCTR、 BPTR、 TCR2、 ISR、 IMR。

NCR(網絡控制寄存器)寄存器

BIT

7

6

5

4

3

2

1

0

名稱

RESERVED

WAKEEN

RESERVED

FCOL

FDX

LBK

RST

FCOL:強制沖突模式,用于檢測。

FDX:內部 PHY 全雙工模式。

LBK:回環模式(LoopBack)

00 正常;

01 MAC 內部回環;

10 內部 PHY100M 模式數字回環;

11 保留;

RST:置 1 軟件復位, 10us 后自動清零。

NSR 寄存器(網絡狀態寄存器)

BIT

7

6

5

4

3

2

1

0

名 稱

SPEED

LINKST

WAKEST

RESERVED

TX2END

TX1END

RXOV

RESERVED

SPEED:網絡速度,在使用內部 PHY 情況下,0 表示 100Mbps,1 表示 100Mbps,當 LINKST=0時,此位無意義。

LINKST:連接狀態, 0 為連接失敗, 1 位已連接。

TX2END: TX(發送)數據包 2 完成標志,讀取或寫 1 將清零該位。

TX1END: TX(發送)數據包 1 完成標志,讀取或寫 1 將清零該位。

RXOV: RX(接收)FIFO 溢出標志。

TCR 寄存器(發送控制寄存器)

BIT

7

6

5

4

3

2

1

0

名 稱

RESERVED

TJDIS

EXCECM

PAD_DIS2

CRC_DIS2

PAD_DIS1

CRC_DIS1

TXREQ

TJDIS: Jabber 傳輸禁止。

1,禁止 Jabber 傳輸定時器(2048 字節)。

0,使能。

EXCECM:嚴重沖突模式控制

0,當沖突計數多于 15 則終止本次數據包。

1,始終嘗試發送本次數據包。

PAD_DIS2:禁止為數據包 II 添加填充。

CRC_DIS2:禁止為數據包 II 添加 CRC 校驗。

PAD_DIS1:禁止為數據包 I 添加填充。

CRC_DIS1:禁止為數據包 I 添加 CRC 校驗。

TXREQ: TX(發送)請求,發送完成后自動清零該位

RCR 寄存器(發送控制寄存器)

BIT

7

6

5

4

3

2

1

0

名稱

RESERVED

WTDIS

DIS_LONG

DIS_CRC

ALL

RUNT

PRMSC

RXEN

WTDIS:看門狗定時器(2048 字節)禁止。

1,進制

0,使能

DIS_LONG:丟棄長數據包, 1,丟棄數據包長度超過 1522 字節的數據包。

DIS_CRC:丟棄 CRC 校驗錯誤數據包。

ALL:允許廣播。

RUNT:允許小于最小長度的數據包。

PRMSC:各種模式。

RXEN:接收使能。

FCTR 寄存器(流控制閾值寄存器)

BIT

7

6

5

4

3

2

1

0

名稱

HWOT

HWOT

HWOT

HWOT

LWOT

LWOT

LWOT

LWOT

HWOT:RX FIFO 緩存高位溢出門限

當 RX SRAM 空閑空間小于該門限值時則發送一個暫停時間為 FFFFH 的暫停包,若該值為 0,則無接收控件。 1=1k 字節,默認值為 3H,即 3K 字節空閑空間,不要超過 S RAM 大小。

LWOT:RX FIFO 緩存低位溢出門限當 RX SRAM 空閑空間大于該門限值時則發送一個暫停時間為 0000H 的暫停包。

當溢出門限最高值的暫停包發送之后,溢出門限最低值的暫停包才有效,默認值為 8K,不要超過 SRAM 大小。

BPTR 寄存器(背壓閾值寄存器)

BIT

7

6

5

4

3

2

1

0

名稱

BPHW

JPT

BPHW:背壓閾值最高值當接收 SRAM 空閑空間低于該閾值,則 MAC 將產生一個擁擠狀態, 1=1k 字節。默認值為 3H,即 3K 字節空閑空間,不要超過 SRAM 大小。

JPT:擁擠狀態時間,模式為 200us, JPT 值與其對應的擁擠狀態時間表

JPT

擁擠狀態時間(us)

JPT

擁擠狀態時間(us)

0000

5

1000

250

0001

10

1001

300

0010

15

1010

350

0011

25

1011

400

0100

50

1100

450

0101

100

1101

500

0110

150

1110

550

0111

200

1111

600

TCR2 寄存器(發送控制寄存器 2)

BIT

7

6

5

4

3

2

1

0

名稱

LED

RLCP

DTU

ONEPM

IFGS

LED: LED 模式

1,設置 LED 引腳為模式 1

0,設置 LED 引腳為模式 0 或根據 EEPROM 的設定。

RLCP:重試沖突延時數據包, 1 重新發送有沖突延遲的數據包。

DTU: 1 禁止重新發送“underruned”數據包。

ONEPM:單包模式。

1,發送完成前發送一個數據包的命令能被執行。

0,發送完成前發送最多兩個數據包的命令能被執行。

IFGS:幀間間隔設置。

0XXX 為 96bit, 1000 為 64bit, 1001 為 72bit

1010 為 80bit, 1011 為 88bit, 1100 為 96bit

1101 為 104bit, 1110 位 112bit, 1111 為 120bit

ISR 寄存器(中斷狀態寄存器)

BIT

7

6

5

4

3

2

1

0

名稱

IOMODE

RESERVED

LNKCHG

UDRUN

ROO

ROS

PT

PR

IOMODE: 0,16 位模式; 1,8 位模式。

LNKCHG:連接狀態改變。

UDRUN:發送“Underrun”

ROO:接收溢出計數器溢出

ROS:接收溢出。

PT:數據包發送。

PR:數據包接收。

IMR 寄存器(中斷狀態寄存器)

BIT

7

6

5

4

3

2

1

0

名稱

PAR

RESERVED

LNKCHGI

UDRUNI

ROOI

ROSI

PTI

PRI

PAR:使能 SRAM 的讀/寫指針在指針地址超過 SRAM 的大小時自動跳回起始位置。需要驅動程序設置該位,若設置該位, REG_F5 將自動置為 0XH。

LNKCHGI:使能連接狀態改變中斷。

UDRUNI:使能發送“Underrun”中斷。

ROOI:使能接收溢出計數器溢出中斷。

ROI:使能接收溢出中斷。

PTI:使能數據包發送中斷。

PRI:使能數據包接收中斷。

2.6 DM9000 直接內存訪問控制(DMAC)

DM9000 直接內存訪問控制(DMAC)

DM9000 支持 DMA 方式簡化對內部存儲器的訪問。在我們編程寫好內部存儲器地址后,就可以用一個讀/寫命令偽指令把當前數據加載到內部數據緩沖區,這樣,內部存儲器指定位置就可以被讀/寫命令寄存器訪問。存儲器地址將會自動增加,增加的大小與當前總線操作模式相同(比如:8-bit、 16-bit 或 32-bit),接著下一個地址數據將會自動加載到內部數據緩沖區。要注意的是在連續突發式第一次訪問的數據應該被忽略,因為,這個數據是最后一次讀寫命令的內容。內部存儲器空間大小 16K 字節。前 3K 字節單元用作發送包的緩沖區,其他 13K 字節用作接收包的緩沖區。所以在寫存儲器操作時,如果地址越界(即超出 3K 空間),在 IMR 寄存器 bit7 置位的情況下,地址指針將會返回到存儲器 0 地址處。同樣,在讀存儲器操作時,如果地址越界(即超出 16K 空間),在 IMR 寄存器 bit7 置位的情況下,地址指針將會返回到存儲器 0x0C00 地址處。

DM9000 數據包發送

DM9000 有兩個發送數據包: index1 和 index2,同時存儲在 TX SRAM 中。發送控制寄存器(02h)控制循環冗余校驗碼(CRC)和填充(pads)的插入,其狀態分別記錄在發送狀態寄存器I(03H)和發送狀態寄存器 II(04H)中。發送器的起始地址為 0x00H,在軟件或硬件復位后,默認的數據發送包為 index1。首先,使用 DMA 端口將數據寫 TX SRAM 中,然后,在發送數據包長度寄存器中把數據字節數寫入字節計數寄存器。置位發送控制寄存器的 bit0 位,則 DM9000 開始發送 index1 數據包。在 index1數據包發送結束之前,數據發送包 index2 被移入 TX SRAM 中。在 index1 數據包發送結束后,將 index2 數據字節數寫入字節計數寄存器中,然后,置位發送控制寄存器的 bit0 位,則 index2數據包開始發送。以此類推,后面的數據包都以此方式進行發送。

DM9000 數據包接收

RX SRAM 是一個環形數據結構。在軟件或硬件復位后, RX SRAM 的起始地址為 0X0C00。每個接收數據包都包含有 CRC 校驗域,數據域,以及緊跟其后的 4 字節包頭域。 4 字節包頭格式為: 01h、狀態、 BYTE_COUNT 低、 BYTE_COUNT 高。請注意:每個接收包的起始地址處在適當的地址邊界,這取決于當前總線操作模式(8bit 或者 16bit)

2.7 DM9000原理圖介紹

poYBAGDYdXCAWkKMAAAAK8RNs4s030.png

?

信號線描述如下:

PWRST: DM9000 復位信號。

CS: DM9000 的片選信號。

WR(IOW): 處理器寫命令。

RD(IOR): 處理器讀命令。

CMD: 命令/數據標志, 0,讀寫命令; 1,讀寫數據。

SD0~SD15: 16 位雙向數據線。

信號線對應的GPIO口對應關系

引腳名稱

GPIO口

功能說明

PWRST-->DM9000_RST

PD7

復位信號

CS-->FSMC_NE2

PG9

片選信號

WR(IOW)-->FSMC_NWE

PD5

處理器寫命令

RD(IOR) --->FSMC_NOE

PD4

處理器讀命令

CMD—>FSMC-A7

PF13

命令/數據標志, 0,讀寫命令; 1,讀寫數據

INT--->DM9000_INT

PG6

中斷引腳

FSMC_D0

PD14

數據線0

FSMC_D1

PD15

數據線1

FSMC_D2

PD0

數據線2

FSMC_D3

PD1

數據線3

FSMC_D4

PE7

數據線4

FSMC_D5

PE8

數據線5

FSMC_D6

PE9

數據線6

FSMC_D7

PE10

數據線7

FSMC_D8

PE11

數據線8

FSMC_D9

PE12

數據線9

FSMC_D10

PE13

數據線10

FSMC_D11

PE14

數據線11

FSMC_D12

PE15

數據線12

FSMC_D13

PD8

數據線13

FSMC_D14

PD9

數據線14

FSMC_D15

PD10

數據線15

FSMC接口框圖

poYBAGDYdXCAWkKMAAAAK8RNs4s030.png

?

DM9000網卡接在FSMC的第2塊上,數據線地址: 0x64000000

PA7地址線作為命令與數據線切換引腳。

外接16位寬度存儲器:HADDR[25:1] ? FSMC_A[24:0]

外接8位寬度存儲器: HADDR[25:0] ? FSMC_A[25:0]

0x64000000基地址:01100100000000000000000000000000

0x64000000寫數據:01100100000000000000000000000000

0x64000100寫命令:01100100000000000000000100000000

2.8 DM9000時序圖介紹

IOR和IOW是DM9000的讀寫選擇引腳,低電平有效,即低電平時進行讀(IOR)寫(IOW)操作;AEN是芯片選通引腳,低電平有效,該引腳為低時才能進行讀寫操作;CMD的命令/數據切換引腳,低電平時讀寫命令操作,高電平時讀寫數據操作。

讀時序:

poYBAGDYdXCAWkKMAAAAK8RNs4s030.png

?

寫時序:

poYBAGDYdXCAWkKMAAAAK8RNs4s030.png

?

三、LWIP(TCP/IP)網絡協議棧介紹

根據以太網幀頭攜帶的上層協議類型值傳遞數據。

以太網幀格式定義:

目的MAC地址 源MAC地址 類型/長度 數據 校驗

6字節 6字節 2字節 46-1500字節 4字節

ip:0x0800

ARP:0x0806

最大幀長1518字節 最小字節64字節

3.1 LWIP介紹

lwip是瑞典計算機科學院網絡嵌入式系統小組(SICS)的Adam Dunkels(亞當·鄧克爾) 開發的一個小型開源的TCP/IP協議棧。實現的重點是在保持TCP協議主要功能的基礎上減少對RAM 的占用。

LwIP是Light Weight (輕型)IP協議,有無操作系統的支持都可以運行。LwIP實現的重點是在保持TCP協議主要功能的基礎上減少對RAM 的占用,它只需十幾KB的RAM和40K左右的ROM就可以運行,這使LwIP協議棧適合在低端的嵌入式系統中使用。lwip提供三種API:1)RAW API 2)(NETCONN)lwip API 3)BSD API。

RAW 編程接口使得程序效率高,但是需要對 LWIP 有深入的了解,而且不適合大數據量等場合。 NETCONN 編程接口,使用 NETCONN API 時需要有操作系統的支持。

RAW API把協議棧和應用程序放到一個進程里邊,該接口基于函數回調技術,使用該接口的應用程序可以不用進行連續操作。不過,這會使應用程序編寫難度加大且代 碼不易被理解。為了接收數據,應用程序會向協議棧注冊一個回調函數。該回調函數與特定的連接相關聯,當該關聯的連接到達一個信息包,該回調函數就會被協議 棧調用。這既有優點也有缺點。優點是既然應用程序和TCP/IP協議棧駐留在同一個進程中,那么發送和接收數據就不再產生進程切換。主要缺點是應用程序不 能使自己陷入長期的連續運算中,這樣會導致通訊性能下降,原因是TCP/IP處理與連續運算是不能并行發生的。這個缺點可以通過把應用程序分為兩部分來克 服,一部分處理通訊,一部分處理運算。

lwip API把接收與處理放在一個線程里面。這樣只要處理流程稍微被延遲,接收就會被阻塞,直接造成頻繁丟包、響應不及時等嚴重問題。因此,接收與協議處理必須 分開。LwIP的作者顯然已經考慮到了這一點,他為我們提供了 tcpip_input() 函數來處理這個問題, 雖然他并沒有在 rawapi 一文中說明。 講到這里,讀者應該知道tcpip_input()函數投遞的消息從哪里來的答案了吧,沒錯,它們來自于由底層網絡驅動組成的接收線程。我們在編寫網絡驅動時, 其接收部分以任務的形式創建。 數據包到達后, 去掉以太網包頭得到IP包, 然后直接調用tcpip_input()函數將其 投遞到mbox郵箱。投遞結束,接收任務繼續下一個數據包的接收,而被投遞得IP包將由TCPIP線程繼續處理。這樣,即使某個IP包的處理時間過長也不 會造成頻繁丟包現象的發生。這就是lwip API。

BSD API提供了基于open-read-write-close模型的UNIX標準API,它的最大特點是使應用程序移植到其它系統時比較容易,但用在嵌入式系統中效率比較低,占用資源多。這對于我們的嵌入式應用有時是不能容忍的

lwIP協議棧主要關注的是怎么樣減少內存的使用和代碼的大小,這樣就可以讓lwIP適用于資源有限的小型平臺例如嵌入式系統。為了簡化處理過程和內存要求,lwIP對API進行了裁減,可以不需要復制一些數據。

其主要特性如下:

(1)支持多網絡接口下的IP轉發;

(2)支持ICMP協議;

(3)包括實驗性擴展的UDP(用戶數據報協議);

(4)包括阻塞控制、RTT 估算、快速恢復和快速轉發的TCP(傳輸控制協議);

(5)提供專門的內部回調接口(Raw API),用于提高應用程序性能;

(6)可選擇的Berkeley接口API (在多線程情況下使用) 。

(7)在最新的版本中支持ppp

(8) 新版本中增加了的IP fragment(IP分片)的支持.

(9) 支持DHCP協議,動態分配ip地址.

3.2 幾種開源TCPIP協議概述

1、BSD TCP/IP協議棧

BSD棧歷史上是商業棧的起點,大多數專業TCP/IP棧(VxWorks內嵌的TCP/IP棧)是BSD棧派生的。這是因為BSD棧在BSD許可協議下提供了這些專業棧的雛形,BSD許用證允許BSD棧以修改或未修改的形式結合這些專業棧的代碼而無須向創建者付版稅。同時,BSD也是許多TCP/IP協議中的創新(如廣域網中餓擁塞控制和避免)的點。

2、uC/IP

uC/IP是由Guy Lancaster編寫的一套基于uC/OS且開放源碼的TCP/IP協議棧,亦可移植到操作系統,是一套完全免費的、可供研究的TCP/IP協議棧,uC/IP大部分源碼是從公開源碼BSD發布站點和KA9Q(一個基于DOS單任務環境運行的TCP/IP協議棧)移植過來。uC/IP具有如下一些特點:帶身份驗證和報頭壓縮支持的PPP協議,優化的單一請求/回復交互過程,支持IP/TCP/UDP協議,可實現的網絡功能較為強大,并可裁減。UCIP協議棧被為一個帶最小化用戶接口及可應用串行鏈路網絡模塊。根據采用CPU、編譯器和系統所需實現協議的多少,協議棧需要的代碼容量空間在30-60KB之間。http://ucip.sourceforge.net

3、LwIP

LwIP是瑞士計算機科學院(Swedish Institute of Computer Science)的Adam Dunkels等開發的一套用于嵌入式系統的開放源代碼TCP/IP協議棧。LwIP的含義是Light Weight(輕型)IP協議,相對于uip。LwIP可以移植到操作系統上,也可以在無操作系統的情況下獨立運行。LwIP TCP/IP實現的重點是在保持TCP協議主要功能的基礎上減少對RAM的占用,一般它只需要幾十K的RAM和40K左右的ROM就可以運行,這使LwIP協議棧適合在低端嵌入式系統中使用。LwIP的特性如下:支持多網絡接口下的IP轉發,支持ICMP協議 ,包括實驗性擴展的的UDP(用戶數據報協議),包括阻塞控制,RTT估算和快速恢復和快速轉發的TCP(傳輸控制協議),提供專門的內部回調接口(Raw API)用于提高應用程序性能,并提供了可選擇的Berkeley接口API。Svensk forskning f?r h?llbar tillv?xt| RISE或lwIP - A Lightweight TCP/IP stack - Summary [Savannah]

4、uIP

uIP是專門為8位和16位控制器設計的一個非常小的TCP/IP棧。完全用C編寫,因此可移植到各種不同的結構和操作系統上,一個編譯過的棧可以在幾KB ROM或幾百字節RAM中運行。uIP中還包括一個HTTP服務器作為服務內容。許可:BSD許用證Svensk forskning f?r h?llbar tillv?xt| RISE

uIP是一個完全由C語言編寫的開源軟件, 它的文檔和源代碼可用于商業和非商業用途, 它已經移植到了大部分的8位微控制器, 而且已在很多的嵌入式產品和項目中使用.

5、TinyTcp

TinyTcp 棧是TCP/IP的一個非常小和簡單的實現,它包括一個FTP客戶。TinyTcp是為了燒入ROM設計的并且現在開始對大端結構似乎是有用的(初始目標是68000芯片)。TinyTcp也包括一個簡單的以太網驅動器用于3COM多總線卡http://ftp.ecs.soton.ac.uk/pub/elks/utils/tiny-tcp.txt

選擇一個開源協議??梢詮乃膫€方面來考慮:

是否提供易用的底層硬件API,即與硬件平臺的無關性;

協議棧需要調用的系統函數接口是否容易構造,另一個對于應用支持程度。

最關鍵的是占用的系統資源是否在可接受范圍內,有裁減優化的空間否? 其中,

BSD ??赏暾麑崿FTCP/IP協議,但代碼龐大,70KB-150KB之間,裁減優化有難度,

uIP和TinyTcp代碼容量小巧,實現功能精簡,限制了在一些較高要求場合下的應用,如可靠性與大容量數據傳輸。

LwIP和uC/IP是同量級別的兩個開源協議棧,兩者代碼容量和實現功能相似,LwIP沒有操作系統針對性,它將協議棧與平臺相關的代碼抽象出來,用戶如果要移植到自己的系統,需要完成該部分代碼的封裝,并為網絡應用支持提供了API接口的可選性。

uC/IP協議最初是針對uC/OS設計,為方便用戶移植實現,同樣也抽象了協議棧與平臺相關代碼,但是協議棧所需調用的系統函數大多參照uC/OS內核函數原型設計,并提供了協議棧的函數,方便用戶參考,其不足在于該協議棧對網絡應用支持不足。

根據以上分析,從應用和開發的角度看,似乎LWIP更得到了網上很多朋友使用的青睞;uC/IP在文檔支持與軟件升級管理上有很多不足,但是它最初是針對UC/OS而設計,如果選用UC/OS作為軟件基礎的話,在系統函數構造方面有優勢。當然你選擇其他操作系統的話,可參照OS_NULL文件夾下的文件修改。 以上的這些開源協議棧也并非免費,拿來就可以用,據我所知,UC/OS的母公司推出UC/OS-TCP/IP花了6人*2年的工作量,國內某公司使用LWIP作為移植的參照,花了4-5人*2年的工作量來測試與優化協議,使用商用TCP/IP棧的高費用就不足為奇了。 作為廣大的愛好者學習而言,如果只是跑跑原型,實驗一下效果,以上的幾種開源協議棧都提供了測試的例子,應該是不錯的選擇。

終上所述:LWIP可優先考慮,參考的資料較多

四、LWIP協議棧移植

4.1 LWIP源碼下載

源碼下載地址: http://ftp.yzu.edu.tw/nongnu/lwip/

poYBAGDYdXCAWkKMAAAAK8RNs4s030.png

?

下載LWIP1.4.1版本、并下載contrib-1.4.1版本。

poYBAGDYdXCAWkKMAAAAK8RNs4s030.png

?

4.2 將LWIP源碼加入到工程目錄

poYBAGDYdXCAWkKMAAAAK8RNs4s030.png

?

poYBAGDYdXCAWkKMAAAAK8RNs4s030.png

?

poYBAGDYdXCAWkKMAAAAK8RNs4s030.png

?

poYBAGDYdXCAWkKMAAAAK8RNs4s030.png

?

poYBAGDYdXCAWkKMAAAAK8RNs4s030.png

?

poYBAGDYdXCAWkKMAAAAK8RNs4s030.png

?

poYBAGDYdXCAWkKMAAAAK8RNs4s030.png

?

poYBAGDYdXCAWkKMAAAAK8RNs4s030.png

?

poYBAGDYdXCAWkKMAAAAK8RNs4s030.png

?

poYBAGDYdXCAWkKMAAAAK8RNs4s030.png

?

poYBAGDYdXCAWkKMAAAAK8RNs4s030.png

?

poYBAGDYdXCAWkKMAAAAK8RNs4s030.png

?

4.3 配置lwipopts.h文件

?

poYBAGDYdXCAWkKMAAAAK8RNs4s030.png

?

poYBAGDYdXCAWkKMAAAAK8RNs4s030.png

?

poYBAGDYdXCAWkKMAAAAK8RNs4s030.png

?

4.4 修改ethernetif.c文件

ethernetif.c文件默認是不編譯的,該文件是網卡底層接口的模板文件,需要根據修改網卡發送接口和接收接口。

poYBAGDYdXCAWkKMAAAAK8RNs4s030.png

?

poYBAGDYdXCAWkKMAAAAK8RNs4s030.png

?

poYBAGDYdXCAWkKMAAAAK8RNs4s030.png

?

poYBAGDYdXCAWkKMAAAAK8RNs4s030.png

?

4.5 修改sys_arch.c文件

修改sys_arch.c只是留下sys_now()函數,其他代碼全部刪除掉。刪除windows.h頭文件。

sys_now()函數用于返回一個32位的系統時鐘,單位是ms。沒有操作系統的情況下,使用定時器提供時間即可。

poYBAGDYdXCAWkKMAAAAK8RNs4s030.png

?

4.6 新建lwip_config.c文件

在LWIP/app目錄下新建一個lwip_config.c/lwip_config.h文件。用于編寫動態IP地址分配處理代碼,和LWIP事物輪詢、初始化代碼。

編寫一個LWIP初始化配置函數,向LWIP協議棧添加一個新的網卡設備

/*
函數功能: LWIP協議棧初始化
*/
void lwip_config_init(void)
{
	ip_addr_t ipaddr;   //IP地址
	ip_addr_t netmask;  //子網掩碼
	ip_addr_t gw;       //網關
	
	//全部初始化為0  -因為使用了動態IP地址分配
	ipaddr.addr=0;
	netmask.addr=0;
	gw.addr=0;
	
	/*1. 初始化LWIP內核*/
	lwip_init();
	/*2. 向網卡列表中添加一個網絡設備*/
	netif_add(&lwip_netif,&ipaddr,&netmask,&gw,NULL,eernetif_init,eernet_input);
	/*3. 開啟DHCP服務 */
	dhcp_start(&lwip_netif);
	/*4. 設置netif為默認網口*/
	netif_set_default(&lwip_netif);
	/*5. 打開netif網口*/
	netif_set_up(&lwip_netif);	
}
poYBAGDYdXCAWkKMAAAAK8RNs4s030.png

編寫LWIP事物輪詢函數與DHCP處理函數

u32 TCPTimer=0;				//TCP查詢計時器
u32 ARPTimer=0;				//ARP查詢計時器
u32 DHCPfineTimer=0;	 	//DHCP精細處理計時器
u32 DHCPcoarseTimer=0; 		//DHCP粗糙處理計時器
u32 DHCP_State=1;          //保存DHCP狀態 1表示沒有分配成功 0表示分配成功

/*
函數功能:  LWIP輪詢任務
*/
void lwip_periodic_handle()
{
	//每250ms調用一次tcp_tmr()函數
	if(TCPTimer >= TCP_TMR_INTERVAL)
	{
		TCPTimer=0;
		tcp_tmr();  //處理TCP協議請求
	}
	
	//ARP每5s周期性調用一次
	if(ARPTimer >= ARP_TMR_INTERVAL)
	{
		ARPTimer=0;
		etharp_tmr();
	}
	//每500ms調用一次dhcp_fine_tmr()
	if(DHCPfineTimer >= DHCP_FINE_TIMER_MSECS)
	{
		DHCPfineTimer=0;
		dhcp_fine_tmr(); //動態IP地址分配的事物處理
		if(DHCP_State)lwip_dhcp_process_handle();  //DHCP處理
	}

	//每60s執行一次DHCP粗糙處理
	if(DHCPcoarseTimer >= DHCP_COARSE_TIMER_MSECS)
	{
		DHCPcoarseTimer=0;
		dhcp_coarse_tmr();
	}  
}

//lwip控制結構體
typedef struct  
{
	u8 remoteip[4];	//服務器主機IP地址 
	u8 ip[4];        //本機IP地址
	u8 netmask[4]; 	//子網掩碼
	u8 gateway[4]; 	//默認網關的IP地址
}__lwip_dev;

extern __lwip_dev lwipdev;	//lwip信息結構體

__lwip_dev lwipdev;	//lwip信息結構體


/*
函數功能: DHCP處理任務
*/
void lwip_dhcp_process_handle(void)
{
	u32 ip=0,netmask=0,gw=0;
	ip=lwip_netif.ip_addr.addr;			//讀取新IP地址
	netmask=lwip_netif.netmask.addr;   //讀取子網掩碼
	gw=lwip_netif.gw.addr;           //讀取默認網關
	
	if(ip!=0)			//正確獲取到IP地址的時候
	{
		DHCP_State=0; //表示分配成功
	  //解析出通過DHCP獲取到的IP地址
		lwipdev.ip[3]=(uint8_t)(ip>>24); 
		lwipdev.ip[2]=(uint8_t)(ip>>16);
		lwipdev.ip[1]=(uint8_t)(ip>>8);
		lwipdev.ip[0]=(uint8_t)(ip);
		printf("動態分配
IP:..............%d.%d.%d.%d\r\n",lwipdev.ip[0],lwipdev.ip[1],lwipdev.ip[2],lwipdev.ip[3]);
		//解析通過DHCP獲取到的子網掩碼地址
		lwipdev.netmask[3]=(uint8_t)(netmask>>24);
		lwipdev.netmask[2]=(uint8_t)(netmask>>16);
		lwipdev.netmask[1]=(uint8_t)(netmask>>8);
		lwipdev.netmask[0]=(uint8_t)(netmask);
		printf("子網掩
碼............%d.%d.%d.%d\r\n",lwipdev.netmask[0],lwipdev.netmask[1],lwipdev.netmask[2],lwipdev.netmask[3]);
		//解析出通過DHCP獲取到的默認網關
		lwipdev.gateway[3]=(uint8_t)(gw>>24);
		lwipdev.gateway[2]=(uint8_t)(gw>>16);
		lwipdev.gateway[1]=(uint8_t)(gw>>8);
		lwipdev.gateway[0]=(uint8_t)(gw);
		printf("網
關.........%d.%d.%d.%d\r\n",lwipdev.gateway[0],lwipdev.gateway[1],lwipdev.gateway[2],lwipdev.gateway[3]);
	}
}

4.7 配置一個定時器提供時間基準

poYBAGDYdXCAWkKMAAAAK8RNs4s030.png

?

4.8 初始化lwip動態獲取IP地址

poYBAGDYdXCAWkKMAAAAK8RNs4s030.png

?

4.9 LWIP內存配置選擇

LWIP可以選擇使用系統庫自帶的函數malloc/free進行管理空間,也可以使用lwip自己的內存管理函數進行管理,源碼默認就是使用lwip自己的內存管理方法,就是在初始化內存的時候定義一個數組,數組的大小在lwipopts.h文件MEM_SIZE宏定義的。

poYBAGDYdXCAWkKMAAAAK8RNs4s030.png

?

poYBAGDYdXCAWkKMAAAAK8RNs4s030.png

?

poYBAGDYdXCAWkKMAAAAK8RNs4s030.png

?

poYBAGDYdXCAWkKMAAAAK8RNs4s030.png

?

五、LWIP函數使用(RAW編程接口)

5.1 LWIP初始化配置

poYBAGDYdXCAWkKMAAAAK8RNs4s030.png

?

ip_addr_t ipaddr;   //IP地址
ip_addr_t netmask;  //子網掩碼
ip_addr_t gw;       //網關

//全部初始化為0  -因為使用了動態IP地址分配
ipaddr.addr=0;
netmask.addr=0;
gw.addr=0;

/*1. 初始化LWIP內核*/
lwip_init();
/*2. 向網卡列表中添加一個網絡設備*/
netif_add(&lwip_netif,&ipaddr,&netmask,&gw,NULL,eernetif_init,eernet_input);
/*3. 開啟DHCP服務 */
dhcp_start(&lwip_netif);
/*4. 設置netif為默認網口*/
netif_set_default(&lwip_netif);
/*5. 打開netif網口*/
netif_set_up(&lwip_netif);	
poYBAGDYdXCAWkKMAAAAK8RNs4s030.png

5.2 LWIP輪詢函數處理

LWIP輪詢期間:

1. 推薦每250ms周期性調用一次tcp_tmr()函數,處理TCP協議請求。

超時時間LWIP使用TCP_TMR_INTERVAL宏進行了定義。

2. 推薦每5s周期性調用一次etharp_tmr()函數,清除ARP表中過期的數據。

超時時間LWIP使用ARP_TMR_INTERVAL宏進行了定義。

3. (如果開啟了動態IP分配功能)推薦每500ms周期性調用一次dhcp_fine_tmr()函數,處理DHCP動態IP地址分配請求。 如果IP地址獲取成功,將會放在初始化時注冊的網絡設備結構體里(struct netif)。

超時時間LWIP使用DHCP_FINE_TIMER_MSECS宏進行了定義。

4. (如果開啟了動態IP分配功能)推薦每60s調用一次dhcp_coarse_tmr()函數,用于檢查DHCP租約時間,并進行重新綁定。

超時時間LWIP使用DHCP_COARSE_TIMER_MSECS宏進行了定義。

5. 在LWIP運行期間,當網卡收到數據時,還需要調用ethernetif_input函數讀取網卡數據。

在函數ethernetif_input()主要完成兩個工作

1、調用low_level_input(); 讀取網卡實際數據。

2、調用netif->input();

所以,為了能夠實時的讀取數據,需要最快的速度輪詢調用ethernetif_input函數。

5.3 LWIP編程RAW接口函數

tcp_new() 創建一個 TCP 的 PCB 控制塊
tcp_bind() 為 TCP 的 PCB 控制塊綁定一個本地 IP 地址和端口號
tcp_listen() 開始 TCP 的 PCB 監聽
tcp_accept() 控制塊 accept字段注冊的回調函數,偵聽到連接時被調用
tcp_accepted() 通知 LWIP 協議棧一個 TCP 連接被接受了
tcp_conect() 連接遠端主機
tcp_write() 構造一個報文并放到控制塊的發送緩沖隊列中
tcp_sent() 控制塊 sent 字段注冊的回調函數,數據發送成功后被回調
tcp_output() 將發送緩沖隊列中的數據發送出去
tcp_recv()控制塊 recv 字段注冊的回調函數,當接收到新數據時被調用
tcp_recved()當程序處理完數據后一定要調用這個函數,通知內核更新接收窗口
tcp_poll() 控制塊 poll 字段注冊的回調函數,該函數周期性調用
tcp_close() 關閉一個 TCP 連接
tcp_err() 控制塊 err 字段注冊的回調函數,遇到錯誤時被調用
tcp_abort() 中斷 TCP 連接
poYBAGDYdXCAWkKMAAAAK8RNs4s030.png

5.4 創建TCP服務器示例

下面演示了TCP服務器創建步驟,測試服務器是否正常。

u8 TCP_Create(u16_t port)
{
	struct tcp_pcb *pcb=NULL;
	pcb=tcp_new(); //創建套接字
	if(pcb==NULL)return 1;
	if(tcp_bind(pcb,IP_ADDR_ANY,port)!=ERR_OK)return 2; //綁定端口號
	pcb=tcp_listen(pcb); //開始監聽
	tcp_accept(pcb,TCP_accept);//等待連接
	return 0;
}

err_t TCP_accept(void *arg, struct tcp_pcb *newpcb, err_t err)
{
	u8 addr[4];
	//tcp_setprio(newpcb, TCP_PRIO_MIN);  設置優先級
	printf("有新的客戶端連接!\n");
	addr[3]=(newpcb->remote_ip.addr>>24)&0xFF;
	addr[2]=(newpcb->remote_ip.addr>>16)&0xFF;
	addr[1]=(newpcb->remote_ip.addr>>8)&0xFF;
	addr[0]=(newpcb->remote_ip.addr>>0)&0xFF;
	printf("ip地址:%d.%d.%d.%d\n",addr[0],addr[1],addr[2],addr[3]);
	printf("端口號:%d\n",newpcb->remote_port);
	printf("當前隊列剩余字節:%d\n",tcp_sndbuf(newpcb));
	tcp_write(newpcb,"1234567890",10,1); //將要發送的數據提交到發送隊列(不會立即發送)
	tcp_output(newpcb); 								 //提示系統現在,發送數據
	tcp_sent(newpcb,TCP_sent); 					 //發送成功的回調函數
	tcp_recv(newpcb,TCP_recv);
	return ERR_OK;
}

err_t TCP_sent(void *arg, struct tcp_pcb *tpcb,u16_t len)
{
	printf("成功發送:%d字節\n",len);
	//tcp_close(tpcb); //關閉客戶端連接
	return ERR_OK;
}

u8 rx_buff[1024];
err_t TCP_recv(void *arg, struct tcp_pcb *tpcb,struct pbuf *p, err_t err)
{
	u32 rx_cnt=0;
	struct pbuf *q;
	memset(rx_buff,0,sizeof(rx_buff));
	if(p==NULL)
	{
	  printf("客戶端已經斷開連接!\n");
	}
	else
	{
	  for(q=p;q!=NULL;q=q->next)
	  {
			memcpy(rx_buff+rx_cnt,q->payload,q->len);
			rx_cnt+=q->len;
	  }
       pbuf_free(p); //釋放PUFF
		printf("成功接收:%d字節\n",rx_cnt);
		printf("收到的數據=%s\n",rx_buff);
	}
	return ERR_OK;
}
poYBAGDYdXCAWkKMAAAAK8RNs4s030.png

5.5 創建TCP客戶端示例

u8 TCP_Create(u16_t port)
{
	struct tcp_pcb *pcb=NULL;
	pcb=tcp_new(); //創建套接字
	ip_addr_t ipaddr;
	if(pcb==NULL)return 1;
	IP4_ADDR(&ipaddr,192,168,31,54); //在ip_addr.h里定義
	tcp_connect(pcb,&ipaddr,port,TCP_connected);
	return 0;
}


err_t TCP_connected(void *arg, struct tcp_pcb *tpcb, err_t err)
{
	u8 addr[4];
	//tcp_setprio(newpcb, TCP_PRIO_MIN);  設置優先級
	printf("服務器連接成功!\n");
	addr[3]=(tpcb->remote_ip.addr>>24)&0xFF;
	addr[2]=(tpcb->remote_ip.addr>>16)&0xFF;
	addr[1]=(tpcb->remote_ip.addr>>8)&0xFF;
	addr[0]=(tpcb->remote_ip.addr>>0)&0xFF;
	printf("服務器ip地址:%d.%d.%d.%d\n",addr[0],addr[1],addr[2],addr[3]);
	printf("服務器端口號:%d\n",tpcb->remote_port);
	printf("當前隊列剩余字節:%d\n",tcp_sndbuf(tpcb));
	tcp_write(tpcb,"1234567890",10,1); //將要發送的數據提交到發送隊列(不會立即發送)
	tcp_output(tpcb); //提示系統現在,發送數據
	tcp_sent(tpcb,TCP_sent); //發送成功的回調函數
	tcp_recv(tpcb,TCP_recv);
	return ERR_OK;
}


err_t TCP_sent(void *arg, struct tcp_pcb *tpcb,u16_t len)
{
	printf("成功發送:%d字節\n",len);
	//tcp_close(tpcb); //關閉客戶端連接
	return ERR_OK;
}


u8 rx_buff[1024];
err_t TCP_recv(void *arg, struct tcp_pcb *tpcb,struct pbuf *p, err_t err)
{
	u32 rx_cnt=0;
	struct pbuf *q;
	memset(rx_buff,0,sizeof(rx_buff));
	if(p==NULL)
	{
		printf("服務器已經斷開連接!\n");
	}
	else
	{
		for(q=p;q!=NULL;q=q->next)
		{
			  memcpy(rx_buff+rx_cnt,q->payload,q->len);
			  rx_cnt+=q->len;
		}
		printf("成功接收:%d字節\n",rx_cnt);
		printf("收到的數據=%s\n",rx_buff);
	}
	return ERR_OK;
}
poYBAGDYdXCAWkKMAAAAK8RNs4s030.png

聲明:本文內容及配圖由入駐作者撰寫或者入駐合作網站授權轉載。文章觀點僅代表作者本人,不代表電子發燒友網立場。文章及其配圖僅供工程師學習之用,如有內容侵權或者其他違規問題,請聯系本站處理。 舉報投訴
  • 網卡
    +關注

    關注

    4

    文章

    311

    瀏覽量

    27384
  • STM32
    +關注

    關注

    2270

    文章

    10900

    瀏覽量

    356006
  • LwIP
    +關注

    關注

    2

    文章

    86

    瀏覽量

    27172
  • FSMC
    +關注

    關注

    0

    文章

    55

    瀏覽量

    38151
  • keil5
    +關注

    關注

    6

    文章

    44

    瀏覽量

    20672
收藏 人收藏

    評論

    相關推薦

    stm32vct6驅動dm9000aep,移植lwip協議,ping不通是哪里出了問題?

    我用stm32vct6驅動dm9000aep,移植lwip協議,芯片的ID讀取沒有任何問題,插上網線筆記本電腦也可以檢測到網口,網口的綠燈
    發表于 03-20 07:09

    DM9000系列

    是在低功耗和高性能進程的3.3V與5V的支持寬容?! ?b class='flag-5'>DM9000還提供了介質無關的接口,來連接所有提供支持介質無關接口功能的家用電話線網絡設備或其他收發器。該DM9000支持8位, 16位和32 -位
    發表于 05-17 10:17

    【NUCLEO-F412ZG申請】合作式調度器構建以及基于DM9000LWIP移植及調試

    DM90005、移植LWIP協議,實現TCP/UDP通信,并通過上位機軟件同Demo板進行數據傳輸。6、
    發表于 10-31 15:31

    lwip移植時去掉DM9000的硬件復位后不能正確移植

    DM9000_Reset(void){DM9000_RST = 0;//DM9000硬件復位delay_ms(10);DM9000_RST = 1; //
    發表于 06-27 04:35

    U-Boot移植DM9000網卡分享!

    U-Boot移植DM9000網卡——西伯利亞的風 根據書《嵌入式Linux應用開發完全手冊》移植網卡驅動,對于Jz2440開發板好像并不適用
    發表于 07-29 00:06

    為什么通過杜邦線連接DM9000模塊程序能獲取到IP地址?

    ,但是程序還是不斷通過串口打印 dm9000 rx: rx error, stop device具體的程序和電路圖[url=]圖片[/url][url=]附件[/url] 網絡實驗1 LWIP無操作系統
    發表于 09-02 23:39

    為什么DM9000網卡物理地址無法設置進環境變量中?

    原先做DM9000移植的時候都是成功的,但是在做環境變量和裁剪的時候就出了這個問題,設置成nandflash保存網卡的環境變量就會報這個錯,norflash不會報錯U-Boot 2016.01
    發表于 09-20 00:10

    為什么uboot移植DM9000后ftfp不能下載uImage?

    注意:如果點擊空白處無法輸入,則點擊字會有輸入提示符 | 則可以使用鍵盤進行輸入!此板塊為 [uboot開發]問題所在章節:畢業班第2課第3.5節_移植最新u-boot之修改代碼支持DM9000網卡
    發表于 09-26 05:45

    LWIP輸出dm9000錯誤

    無操作系統的LWIP 用電腦一ping它,單片機串口就無限輸出 dm9000 rx: rx error, stop device找不到是什么原因導致的 求解答 附上程序
    發表于 03-19 01:07

    STM32F103戰艦DM9000LWIP例程TCP速度不快

    我用的STM32F103戰艦開發板LWIP例程,搭載DM9000的TCP協議,使用發現TCP Server發包速度慢,發送間隔太長(抓包顯示大約250ms),我編程通過tcp_serv
    發表于 04-08 04:35

    如何在STM32F103工程里添加移植LWIP協議

    完成TCP服務器、TCP客戶端的通信測試。 網卡采用的是DM9000,工程代碼中,采用STM32的FSMC接口來驅動
    發表于 08-12 07:20

    dm9000/dm9000a linux驅動程序 (Ethe

    dm9000/dm9000a以太網卡芯片linux驅動程序 :dm9000/dm9000a Ethernet chips linux dri
    發表于 12-26 00:13 ?117次下載

    基于ARM和DM9000網卡接口設計與實現

    針對ARM CPU S3C2410的特點,設計開發了外圍網卡接口平臺,通過驅動程序對以太網控制芯片DM9000的控制,實現了網絡數據傳輸功能。硬件方面主要涉及以太網網絡接口的設計,軟件
    發表于 10-09 16:16 ?144次下載

    DM9000的以太網藏文信息控制平臺

    DM9000的以太網藏文信息控制平臺 摘要:基于DM9000的以太網電路,單片機端移植精簡TCP/IP協議unIP,實現簡易的TCP服務
    發表于 04-13 12:47 ?5692次閱讀
    <b class='flag-5'>DM9000</b>的以太網藏文信息控制平臺

    單片機驅動DM9000網卡芯片詳細調試過程

    單片機驅動DM9000網卡芯片詳細調試過程
    發表于 11-02 11:03 ?0次下載
    主站蜘蛛池模板: 国产精品免费视频拍拍拍| 亚洲国产影视| 天天干天天干天天| 丁香六月啪啪| 四虎www.| 国产单男| 6080午夜| 天堂资源在线官网| www视频在线观看com| 欧美在线小视频| 夜夜干天天操| 在线免费亚洲| 日本黄大乳片免费观看| 午夜精| 中文字幕一区在线观看| 国产伦精品一区二区三区女| h视频在线免费| 色多多网站| 午夜在线观看免费| 亚洲欧美一区二区三区图片 | 国产在线操| 亚洲一区二区三区免费看| 三级在线观看| 五月婷婷网址| 成人中文字幕一区二区三区 | 久久精品亚洲青青草原| 狠狠色综合色综合网络| 亚洲宅男天堂a在线| 爱草免费视频| 2345成人高清毛片| 免费黄色网址网站| 福利视频入口| 色在线免费观看| 天堂最新资源在线| 亚洲综合第一区| 最新午夜| 国产性老妇女做爰在线| 国产国语videosex另类| 22eee在线播放成人免费视频| 免费人成年短视频在线观看免费网站| 精品午夜久久影视|