0
  • 聊天消息
  • 系統(tǒng)消息
  • 評(píng)論與回復(fù)
登錄后你可以
  • 下載海量資料
  • 學(xué)習(xí)在線課程
  • 觀看技術(shù)視頻
  • 寫文章/發(fā)帖/加入社區(qū)
會(huì)員中心
創(chuàng)作中心

完善資料讓更多小伙伴認(rèn)識(shí)你,還能領(lǐng)取20積分哦,立即完善>

3天內(nèi)不再提示

STM32+LWIP網(wǎng)絡(luò)協(xié)議棧移植(網(wǎng)卡采用DM9000)

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

?

一、環(huán)境介紹

MCU: STM32F103ZET6

代碼開發(fā)工具: Keil5

TCP/IP協(xié)議棧: LWIP

網(wǎng)卡: DM9000

本篇文章主要講解如何在STM32F103工程里添加移植LWIP協(xié)議,最終完成TCP服務(wù)器、TCP客戶端的通信測(cè)試。 網(wǎng)卡采用的是DM9000,工程代碼中,采用STM32的FSMC接口來驅(qū)動(dòng)DM900網(wǎng)卡,DM9000是并口網(wǎng)卡,引腳多,但是速度快,也可以采用其他網(wǎng)卡,SPI協(xié)議的、UART協(xié)議的等。 比如:ENC28J60。 因?yàn)橹饕侵vLWIP協(xié)議棧的移植,所以網(wǎng)卡相關(guān)的代碼就沒有細(xì)說(需要準(zhǔn)備一個(gè)網(wǎng)卡可以正常通信的工程,再移植)。

下面進(jìn)行工程的移植代碼比較多,需要下載對(duì)應(yīng)版本的LWIP源碼,STM32本身的DM9000網(wǎng)卡代碼也比較多,文章里會(huì)講解移植的詳細(xì)的過程,代碼貼出了核心部分。

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

資料包里的內(nèi)容如下:

?

poYBAGDYdXCAWkKMAAAAK8RNs4s030.png

?

poYBAGDYdXCAWkKMAAAAK8RNs4s030.png

?

二、D9000網(wǎng)卡

2.1 DM9000簡(jiǎn)介

DM9000 是一款完全集成的、性價(jià)比高、引腳數(shù)少、帶有通用處理器接口的單芯片快速以太網(wǎng)控制器。 自帶一個(gè) 10/100M PHY 和 4K 雙字的 SRAM ,DM9000A 為適應(yīng)各種處理器提供了8位、16 位數(shù)據(jù)接口訪問內(nèi)部存儲(chǔ)器,DM9000擁有自動(dòng)協(xié)商功能,DM9000特性如下:

1、集成自適應(yīng)10/100M收發(fā)器。

2、內(nèi)置16k字節(jié)的SRAM。

3、支持硬件幀校驗(yàn)。

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

DM9000 有多種型號(hào),有 100 引腳和 48 引腳的, 開發(fā)板選擇的是 48 引腳的 DM9000,型號(hào)為 DM9000CEP。

2.2 DM9000 中斷引腳電平設(shè)置

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

poYBAGDYdXCAWkKMAAAAK8RNs4s030.png

?

2.3 DM9000 數(shù)據(jù)位寬設(shè)置

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

poYBAGDYdXCAWkKMAAAAK8RNs4s030.png

?

2.4 DM9000寄存器

寄存器

描述

寄存器地址

默認(rèn)值

NCR

網(wǎng)絡(luò)控制寄存器。

00H

00H

NSR

網(wǎng)絡(luò)狀態(tài)寄存器。

01H

00H

TCR

發(fā)送控制寄存器。

02H

00H

TSR I

發(fā)送狀態(tài)寄存器 I。

03H

00H

TSR II

發(fā)送狀態(tài)寄存器 II。

04H

00H

RCR

接收控制寄存器。

05H

00H

RSR

接收狀態(tài)寄存器。

06H

00H

ROCR

接收溢出計(jì)數(shù)寄存器。

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 數(shù)據(jù)寄存器低位。

0DH

XXH

EPDRH

EEPROM/PHY 數(shù)據(jù)寄存器高位。

0EH

XXH

WCR

喚醒控制寄存器。

0FH

00H

PAR

物理地址寄存器。

10H~15H

由 EEPROM 決定

MAR

廣播地址寄存器。

16H~1DH

XXH

GPCR

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

1EH

01H

GPR

通用目的寄存器。

1FH

XXH

TRPAL

TX SRAM 讀指針地址低字節(jié)。

22H

00H

TRPAH

TX SRAM 讀指針地址高字節(jié)。

23H

00H

RWPAL

RX SRAM 寫指針地址低字節(jié)。

24H

00H

RWRAH

RX SRAM 寫指針地址高字節(jié)。

25H

0CH

VID

廠家 ID。

28H~29H

0A46H

PID

產(chǎn)品 ID。

2AH~2BH

9000H

CHIPR

芯片版本。

2CH

18H

TCR2

發(fā)送控制寄存器 2。

2DH

00H

OCR

操作控制寄存器。

2EH

00H

SMCR

特殊模式控制寄存器。

2FH

00H

ETXCSR

即將發(fā)送控制/狀態(tài)寄存器。

30H

00H

TCSCR

發(fā)送校驗(yàn)和控制寄存器。

31H

00H

RCSCSR

接收校驗(yàn)和控制狀態(tài)寄存器。

32H

00H

MRCMDX

內(nèi)存數(shù)據(jù)預(yù)取讀命令寄存器(地址不加 1)。

F0H

XXH

MRCMDX1

內(nèi)存數(shù)據(jù)讀命令寄存器(地址不加 1)。

F1H

XXH

MRCMD

內(nèi)存數(shù)據(jù)讀命令寄存器(地址加 1)。

F2H

XXH

MRRL

內(nèi)存數(shù)據(jù)讀地址寄存器低字節(jié)。

F4H

00H

MRRH

內(nèi)存數(shù)據(jù)讀地址寄存器高字節(jié)。

F5H

00H

MWCMDX

內(nèi)存數(shù)據(jù)寫命令寄存器(地址不加 1)

F6H

XXH

MWCMD

內(nèi)存數(shù)據(jù)寫命令寄存器(地址加 1)。

F8H

XXH

MWRL

內(nèi)存數(shù)據(jù)寫地址寄存器低字節(jié)。

FAH

00H

MWRH

內(nèi)存數(shù)據(jù)寫地址寄存器高字節(jié)。

FBH

00H

TXPLL

TX 數(shù)據(jù)包長度低字節(jié)寄存器。

FCH

XXH

TXPLH

TX 數(shù)據(jù)包長度高字節(jié)寄存器。

FDH

XXH

ISR

中斷狀態(tài)寄存器。

FEH

00H

IMR

中斷屏蔽寄存器。

FFH

00H

2.5 DM9000常用寄存器介紹

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

NCR(網(wǎng)絡(luò)控制寄存器)寄存器

BIT

7

6

5

4

3

2

1

0

名稱

RESERVED

WAKEEN

RESERVED

FCOL

FDX

LBK

RST

FCOL:強(qiáng)制沖突模式,用于檢測(cè)。

FDX:內(nèi)部 PHY 全雙工模式。

LBK:回環(huán)模式(LoopBack)

00 正常;

01 MAC 內(nèi)部回環(huán);

10 內(nèi)部 PHY100M 模式數(shù)字回環(huán);

11 保留;

RST:置 1 軟件復(fù)位, 10us 后自動(dòng)清零。

NSR 寄存器(網(wǎng)絡(luò)狀態(tài)寄存器)

BIT

7

6

5

4

3

2

1

0

名 稱

SPEED

LINKST

WAKEST

RESERVED

TX2END

TX1END

RXOV

RESERVED

SPEED:網(wǎng)絡(luò)速度,在使用內(nèi)部 PHY 情況下,0 表示 100Mbps,1 表示 100Mbps,當(dāng) LINKST=0時(shí),此位無意義。

LINKST:連接狀態(tài), 0 為連接失敗, 1 位已連接。

TX2END: TX(發(fā)送)數(shù)據(jù)包 2 完成標(biāo)志,讀取或?qū)?1 將清零該位。

TX1END: TX(發(fā)送)數(shù)據(jù)包 1 完成標(biāo)志,讀取或?qū)?1 將清零該位。

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

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

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 傳輸定時(shí)器(2048 字節(jié))。

0,使能。

EXCECM:嚴(yán)重沖突模式控制

0,當(dāng)沖突計(jì)數(shù)多于 15 則終止本次數(shù)據(jù)包。

1,始終嘗試發(fā)送本次數(shù)據(jù)包。

PAD_DIS2:禁止為數(shù)據(jù)包 II 添加填充。

CRC_DIS2:禁止為數(shù)據(jù)包 II 添加 CRC 校驗(yàn)。

PAD_DIS1:禁止為數(shù)據(jù)包 I 添加填充。

CRC_DIS1:禁止為數(shù)據(jù)包 I 添加 CRC 校驗(yàn)。

TXREQ: TX(發(fā)送)請(qǐng)求,發(fā)送完成后自動(dòng)清零該位

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

BIT

7

6

5

4

3

2

1

0

名稱

RESERVED

WTDIS

DIS_LONG

DIS_CRC

ALL

RUNT

PRMSC

RXEN

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

1,進(jìn)制

0,使能

DIS_LONG:丟棄長數(shù)據(jù)包, 1,丟棄數(shù)據(jù)包長度超過 1522 字節(jié)的數(shù)據(jù)包。

DIS_CRC:丟棄 CRC 校驗(yàn)錯(cuò)誤數(shù)據(jù)包。

ALL:允許廣播。

RUNT:允許小于最小長度的數(shù)據(jù)包。

PRMSC:各種模式。

RXEN:接收使能。

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

BIT

7

6

5

4

3

2

1

0

名稱

HWOT

HWOT

HWOT

HWOT

LWOT

LWOT

LWOT

LWOT

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

當(dāng) RX SRAM 空閑空間小于該門限值時(shí)則發(fā)送一個(gè)暫停時(shí)間為 FFFFH 的暫停包,若該值為 0,則無接收控件。 1=1k 字節(jié),默認(rèn)值為 3H,即 3K 字節(jié)空閑空間,不要超過 S RAM 大小。

LWOT:RX FIFO 緩存低位溢出門限當(dāng) RX SRAM 空閑空間大于該門限值時(shí)則發(fā)送一個(gè)暫停時(shí)間為 0000H 的暫停包。

當(dāng)溢出門限最高值的暫停包發(fā)送之后,溢出門限最低值的暫停包才有效,默認(rèn)值為 8K,不要超過 SRAM 大小。

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

BIT

7

6

5

4

3

2

1

0

名稱

BPHW

JPT

BPHW:背壓閾值最高值當(dāng)接收 SRAM 空閑空間低于該閾值,則 MAC 將產(chǎn)生一個(gè)擁擠狀態(tài), 1=1k 字節(jié)。默認(rèn)值為 3H,即 3K 字節(jié)空閑空間,不要超過 SRAM 大小。

JPT:擁擠狀態(tài)時(shí)間,模式為 200us, JPT 值與其對(duì)應(yīng)的擁擠狀態(tài)時(shí)間表

JPT

擁擠狀態(tài)時(shí)間(us)

JPT

擁擠狀態(tài)時(shí)間(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 寄存器(發(fā)送控制寄存器 2)

BIT

7

6

5

4

3

2

1

0

名稱

LED

RLCP

DTU

ONEPM

IFGS

LED: LED 模式

1,設(shè)置 LED 引腳為模式 1

0,設(shè)置 LED 引腳為模式 0 或根據(jù) EEPROM 的設(shè)定。

RLCP:重試沖突延時(shí)數(shù)據(jù)包, 1 重新發(fā)送有沖突延遲的數(shù)據(jù)包。

DTU: 1 禁止重新發(fā)送“underruned”數(shù)據(jù)包。

ONEPM:?jiǎn)伟J健?/span>

1,發(fā)送完成前發(fā)送一個(gè)數(shù)據(jù)包的命令能被執(zhí)行。

0,發(fā)送完成前發(fā)送最多兩個(gè)數(shù)據(jù)包的命令能被執(zhí)行。

IFGS:幀間間隔設(shè)置。

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

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

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

ISR 寄存器(中斷狀態(tài)寄存器)

BIT

7

6

5

4

3

2

1

0

名稱

IOMODE

RESERVED

LNKCHG

UDRUN

ROO

ROS

PT

PR

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

LNKCHG:連接狀態(tài)改變。

UDRUN:發(fā)送“Underrun”

ROO:接收溢出計(jì)數(shù)器溢出

ROS:接收溢出。

PT:數(shù)據(jù)包發(fā)送。

PR:數(shù)據(jù)包接收。

IMR 寄存器(中斷狀態(tài)寄存器)

BIT

7

6

5

4

3

2

1

0

名稱

PAR

RESERVED

LNKCHGI

UDRUNI

ROOI

ROSI

PTI

PRI

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

LNKCHGI:使能連接狀態(tài)改變中斷。

UDRUNI:使能發(fā)送“Underrun”中斷。

ROOI:使能接收溢出計(jì)數(shù)器溢出中斷。

ROI:使能接收溢出中斷。

PTI:使能數(shù)據(jù)包發(fā)送中斷。

PRI:使能數(shù)據(jù)包接收中斷。

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

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

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

DM9000 數(shù)據(jù)包發(fā)送

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

DM9000 數(shù)據(jù)包接收

RX SRAM 是一個(gè)環(huán)形數(shù)據(jù)結(jié)構(gòu)。在軟件或硬件復(fù)位后, RX SRAM 的起始地址為 0X0C00。每個(gè)接收數(shù)據(jù)包都包含有 CRC 校驗(yàn)域,數(shù)據(jù)域,以及緊跟其后的 4 字節(jié)包頭域。 4 字節(jié)包頭格式為: 01h、狀態(tài)、 BYTE_COUNT 低、 BYTE_COUNT 高。請(qǐng)注意:每個(gè)接收包的起始地址處在適當(dāng)?shù)牡刂愤吔?,這取決于當(dāng)前總線操作模式(8bit 或者 16bit)

2.7 DM9000原理圖介紹

poYBAGDYdXCAWkKMAAAAK8RNs4s030.png

?

信號(hào)線描述如下:

PWRST: DM9000 復(fù)位信號(hào)。

CS: DM9000 的片選信號(hào)。

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

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

CMD: 命令/數(shù)據(jù)標(biāo)志, 0,讀寫命令; 1,讀寫數(shù)據(jù)。

SD0~SD15: 16 位雙向數(shù)據(jù)線。

信號(hào)線對(duì)應(yīng)的GPIO口對(duì)應(yīng)關(guān)系

引腳名稱

GPIO口

功能說明

PWRST-->DM9000_RST

PD7

復(fù)位信號(hào)

CS-->FSMC_NE2

PG9

片選信號(hào)

WR(IOW)-->FSMC_NWE

PD5

處理器寫命令

RD(IOR) --->FSMC_NOE

PD4

處理器讀命令

CMD—>FSMC-A7

PF13

命令/數(shù)據(jù)標(biāo)志, 0,讀寫命令; 1,讀寫數(shù)據(jù)

INT--->DM9000_INT

PG6

中斷引腳

FSMC_D0

PD14

數(shù)據(jù)線0

FSMC_D1

PD15

數(shù)據(jù)線1

FSMC_D2

PD0

數(shù)據(jù)線2

FSMC_D3

PD1

數(shù)據(jù)線3

FSMC_D4

PE7

數(shù)據(jù)線4

FSMC_D5

PE8

數(shù)據(jù)線5

FSMC_D6

PE9

數(shù)據(jù)線6

FSMC_D7

PE10

數(shù)據(jù)線7

FSMC_D8

PE11

數(shù)據(jù)線8

FSMC_D9

PE12

數(shù)據(jù)線9

FSMC_D10

PE13

數(shù)據(jù)線10

FSMC_D11

PE14

數(shù)據(jù)線11

FSMC_D12

PE15

數(shù)據(jù)線12

FSMC_D13

PD8

數(shù)據(jù)線13

FSMC_D14

PD9

數(shù)據(jù)線14

FSMC_D15

PD10

數(shù)據(jù)線15

FSMC接口框圖

poYBAGDYdXCAWkKMAAAAK8RNs4s030.png

?

DM9000網(wǎng)卡接在FSMC的第2塊上,數(shù)據(jù)線地址: 0x64000000

PA7地址線作為命令與數(shù)據(jù)線切換引腳。

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

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

0x64000000基地址:01100100000000000000000000000000

0x64000000寫數(shù)據(jù):01100100000000000000000000000000

0x64000100寫命令:01100100000000000000000100000000

2.8 DM9000時(shí)序圖介紹

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

讀時(shí)序:

poYBAGDYdXCAWkKMAAAAK8RNs4s030.png

?

寫時(shí)序:

poYBAGDYdXCAWkKMAAAAK8RNs4s030.png

?

三、LWIP(TCP/IP)網(wǎng)絡(luò)協(xié)議棧介紹

根據(jù)以太網(wǎng)幀頭攜帶的上層協(xié)議類型值傳遞數(shù)據(jù)。

以太網(wǎng)幀格式定義:

目的MAC地址 源MAC地址 類型/長度 數(shù)據(jù) 校驗(yàn)

6字節(jié) 6字節(jié) 2字節(jié) 46-1500字節(jié) 4字節(jié)

ip:0x0800

ARP:0x0806

最大幀長1518字節(jié) 最小字節(jié)64字節(jié)

3.1 LWIP介紹

lwip是瑞典計(jì)算機(jī)科學(xué)院網(wǎng)絡(luò)嵌入式系統(tǒng)小組(SICS)的Adam Dunkels(亞當(dāng)·鄧克爾) 開發(fā)的一個(gè)小型開源的TCP/IP協(xié)議棧。實(shí)現(xiàn)的重點(diǎn)是在保持TCP協(xié)議主要功能的基礎(chǔ)上減少對(duì)RAM 的占用。

LwIP是Light Weight (輕型)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)中使用。lwip提供三種API:1)RAW API 2)(NETCONN)lwip API 3)BSD API。

RAW 編程接口使得程序效率高,但是需要對(duì) LWIP 有深入的了解,而且不適合大數(shù)據(jù)量等場(chǎng)合。 NETCONN 編程接口,使用 NETCONN API 時(shí)需要有操作系統(tǒng)的支持。

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

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

BSD API提供了基于open-read-write-close模型的UNIX標(biāo)準(zhǔn)API,它的最大特點(diǎn)是使應(yīng)用程序移植到其它系統(tǒng)時(shí)比較容易,但用在嵌入式系統(tǒng)中效率比較低,占用資源多。這對(duì)于我們的嵌入式應(yīng)用有時(shí)是不能容忍的

lwIP協(xié)議棧主要關(guān)注的是怎么樣減少內(nèi)存的使用和代碼的大小,這樣就可以讓lwIP適用于資源有限的小型平臺(tái)例如嵌入式系統(tǒng)。為了簡(jiǎn)化處理過程和內(nèi)存要求,lwIP對(duì)API進(jìn)行了裁減,可以不需要復(fù)制一些數(shù)據(jù)。

其主要特性如下:

(1)支持多網(wǎng)絡(luò)接口下的IP轉(zhuǎn)發(fā);

(2)支持ICMP協(xié)議;

(3)包括實(shí)驗(yàn)性擴(kuò)展的UDP(用戶數(shù)據(jù)報(bào)協(xié)議);

(4)包括阻塞控制、RTT 估算、快速恢復(fù)和快速轉(zhuǎn)發(fā)的TCP(傳輸控制協(xié)議);

(5)提供專門的內(nèi)部回調(diào)接口(Raw API),用于提高應(yīng)用程序性能;

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

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

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

(9) 支持DHCP協(xié)議,動(dòng)態(tài)分配ip地址.

3.2 幾種開源TCPIP協(xié)議概述

1、BSD TCP/IP協(xié)議棧

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

2、uC/IP

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

3、LwIP

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

4、uIP

uIP是專門為8位和16位控制器設(shè)計(jì)的一個(gè)非常小的TCP/IP棧。完全用C編寫,因此可移植到各種不同的結(jié)構(gòu)和操作系統(tǒng)上,一個(gè)編譯過的??梢栽趲譑B ROM或幾百字節(jié)RAM中運(yùn)行。uIP中還包括一個(gè)HTTP服務(wù)器作為服務(wù)內(nèi)容。許可:BSD許用證Svensk forskning f?r h?llbar tillv?xt| RISE

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

5、TinyTcp

TinyTcp 棧是TCP/IP的一個(gè)非常小和簡(jiǎn)單的實(shí)現(xiàn),它包括一個(gè)FTP客戶。TinyTcp是為了燒入ROM設(shè)計(jì)的并且現(xiàn)在開始對(duì)大端結(jié)構(gòu)似乎是有用的(初始目標(biāo)是68000芯片)。TinyTcp也包括一個(gè)簡(jiǎn)單的以太網(wǎng)驅(qū)動(dòng)器用于3COM多總線卡http://ftp.ecs.soton.ac.uk/pub/elks/utils/tiny-tcp.txt

選擇一個(gè)開源協(xié)議??梢詮乃膫€(gè)方面來考慮:

是否提供易用的底層硬件API,即與硬件平臺(tái)的無關(guān)性;

協(xié)議棧需要調(diào)用的系統(tǒng)函數(shù)接口是否容易構(gòu)造,另一個(gè)對(duì)于應(yīng)用支持程度。

最關(guān)鍵的是占用的系統(tǒng)資源是否在可接受范圍內(nèi),有裁減優(yōu)化的空間否? 其中,

BSD ??赏暾麑?shí)現(xiàn)TCP/IP協(xié)議,但代碼龐大,70KB-150KB之間,裁減優(yōu)化有難度,

uIP和TinyTcp代碼容量小巧,實(shí)現(xiàn)功能精簡(jiǎn),限制了在一些較高要求場(chǎng)合下的應(yīng)用,如可靠性與大容量數(shù)據(jù)傳輸。

LwIP和uC/IP是同量級(jí)別的兩個(gè)開源協(xié)議棧,兩者代碼容量和實(shí)現(xiàn)功能相似,LwIP沒有操作系統(tǒng)針對(duì)性,它將協(xié)議棧與平臺(tái)相關(guān)的代碼抽象出來,用戶如果要移植到自己的系統(tǒng),需要完成該部分代碼的封裝,并為網(wǎng)絡(luò)應(yīng)用支持提供了API接口的可選性。

uC/IP協(xié)議最初是針對(duì)uC/OS設(shè)計(jì),為方便用戶移植實(shí)現(xiàn),同樣也抽象了協(xié)議棧與平臺(tái)相關(guān)代碼,但是協(xié)議棧所需調(diào)用的系統(tǒng)函數(shù)大多參照uC/OS內(nèi)核函數(shù)原型設(shè)計(jì),并提供了協(xié)議棧的函數(shù),方便用戶參考,其不足在于該協(xié)議棧對(duì)網(wǎng)絡(luò)應(yīng)用支持不足。

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

終上所述:LWIP可優(yōu)先考慮,參考的資料較多

四、LWIP協(xié)議棧移植

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文件默認(rèn)是不編譯的,該文件是網(wǎng)卡底層接口的模板文件,需要根據(jù)修改網(wǎng)卡發(fā)送接口和接收接口。

poYBAGDYdXCAWkKMAAAAK8RNs4s030.png

?

poYBAGDYdXCAWkKMAAAAK8RNs4s030.png

?

poYBAGDYdXCAWkKMAAAAK8RNs4s030.png

?

poYBAGDYdXCAWkKMAAAAK8RNs4s030.png

?

4.5 修改sys_arch.c文件

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

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

poYBAGDYdXCAWkKMAAAAK8RNs4s030.png

?

4.6 新建lwip_config.c文件

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

編寫一個(gè)LWIP初始化配置函數(shù),向LWIP協(xié)議棧添加一個(gè)新的網(wǎng)卡設(shè)備

/*
函數(shù)功能: LWIP協(xié)議棧初始化
*/
void lwip_config_init(void)
{
	ip_addr_t ipaddr;   //IP地址
	ip_addr_t netmask;  //子網(wǎng)掩碼
	ip_addr_t gw;       //網(wǎng)關(guān)
	
	//全部初始化為0  -因?yàn)槭褂昧藙?dòng)態(tài)IP地址分配
	ipaddr.addr=0;
	netmask.addr=0;
	gw.addr=0;
	
	/*1. 初始化LWIP內(nèi)核*/
	lwip_init();
	/*2. 向網(wǎng)卡列表中添加一個(gè)網(wǎng)絡(luò)設(shè)備*/
	netif_add(&lwip_netif,&ipaddr,&netmask,&gw,NULL,eernetif_init,eernet_input);
	/*3. 開啟DHCP服務(wù) */
	dhcp_start(&lwip_netif);
	/*4. 設(shè)置netif為默認(rèn)網(wǎng)口*/
	netif_set_default(&lwip_netif);
	/*5. 打開netif網(wǎng)口*/
	netif_set_up(&lwip_netif);	
}
poYBAGDYdXCAWkKMAAAAK8RNs4s030.png

編寫LWIP事物輪詢函數(shù)與DHCP處理函數(shù)

u32 TCPTimer=0;				//TCP查詢計(jì)時(shí)器
u32 ARPTimer=0;				//ARP查詢計(jì)時(shí)器
u32 DHCPfineTimer=0;	 	//DHCP精細(xì)處理計(jì)時(shí)器
u32 DHCPcoarseTimer=0; 		//DHCP粗糙處理計(jì)時(shí)器
u32 DHCP_State=1;          //保存DHCP狀態(tài) 1表示沒有分配成功 0表示分配成功

/*
函數(shù)功能:  LWIP輪詢?nèi)蝿?wù)
*/
void lwip_periodic_handle()
{
	//每250ms調(diào)用一次tcp_tmr()函數(shù)
	if(TCPTimer >= TCP_TMR_INTERVAL)
	{
		TCPTimer=0;
		tcp_tmr();  //處理TCP協(xié)議請(qǐng)求
	}
	
	//ARP每5s周期性調(diào)用一次
	if(ARPTimer >= ARP_TMR_INTERVAL)
	{
		ARPTimer=0;
		etharp_tmr();
	}
	//每500ms調(diào)用一次dhcp_fine_tmr()
	if(DHCPfineTimer >= DHCP_FINE_TIMER_MSECS)
	{
		DHCPfineTimer=0;
		dhcp_fine_tmr(); //動(dòng)態(tài)IP地址分配的事物處理
		if(DHCP_State)lwip_dhcp_process_handle();  //DHCP處理
	}

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

//lwip控制結(jié)構(gòu)體
typedef struct  
{
	u8 remoteip[4];	//服務(wù)器主機(jī)IP地址 
	u8 ip[4];        //本機(jī)IP地址
	u8 netmask[4]; 	//子網(wǎng)掩碼
	u8 gateway[4]; 	//默認(rèn)網(wǎng)關(guān)的IP地址
}__lwip_dev;

extern __lwip_dev lwipdev;	//lwip信息結(jié)構(gòu)體

__lwip_dev lwipdev;	//lwip信息結(jié)構(gòu)體


/*
函數(shù)功能: DHCP處理任務(wù)
*/
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;   //讀取子網(wǎng)掩碼
	gw=lwip_netif.gw.addr;           //讀取默認(rèn)網(wǎng)關(guān)
	
	if(ip!=0)			//正確獲取到IP地址的時(shí)候
	{
		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("動(dòng)態(tài)分配
IP:..............%d.%d.%d.%d\r\n",lwipdev.ip[0],lwipdev.ip[1],lwipdev.ip[2],lwipdev.ip[3]);
		//解析通過DHCP獲取到的子網(wǎng)掩碼地址
		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("子網(wǎng)掩
碼............%d.%d.%d.%d\r\n",lwipdev.netmask[0],lwipdev.netmask[1],lwipdev.netmask[2],lwipdev.netmask[3]);
		//解析出通過DHCP獲取到的默認(rèn)網(wǎng)關(guān)
		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("網(wǎng)
關(guān).........%d.%d.%d.%d\r\n",lwipdev.gateway[0],lwipdev.gateway[1],lwipdev.gateway[2],lwipdev.gateway[3]);
	}
}

4.7 配置一個(gè)定時(shí)器提供時(shí)間基準(zhǔn)

poYBAGDYdXCAWkKMAAAAK8RNs4s030.png

?

4.8 初始化lwip動(dòng)態(tài)獲取IP地址

poYBAGDYdXCAWkKMAAAAK8RNs4s030.png

?

4.9 LWIP內(nèi)存配置選擇

LWIP可以選擇使用系統(tǒng)庫自帶的函數(shù)malloc/free進(jìn)行管理空間,也可以使用lwip自己的內(nèi)存管理函數(shù)進(jìn)行管理,源碼默認(rèn)就是使用lwip自己的內(nèi)存管理方法,就是在初始化內(nèi)存的時(shí)候定義一個(gè)數(shù)組,數(shù)組的大小在lwipopts.h文件MEM_SIZE宏定義的。

poYBAGDYdXCAWkKMAAAAK8RNs4s030.png

?

poYBAGDYdXCAWkKMAAAAK8RNs4s030.png

?

poYBAGDYdXCAWkKMAAAAK8RNs4s030.png

?

poYBAGDYdXCAWkKMAAAAK8RNs4s030.png

?

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

5.1 LWIP初始化配置

poYBAGDYdXCAWkKMAAAAK8RNs4s030.png

?

ip_addr_t ipaddr;   //IP地址
ip_addr_t netmask;  //子網(wǎng)掩碼
ip_addr_t gw;       //網(wǎng)關(guān)

//全部初始化為0  -因?yàn)槭褂昧藙?dòng)態(tài)IP地址分配
ipaddr.addr=0;
netmask.addr=0;
gw.addr=0;

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

5.2 LWIP輪詢函數(shù)處理

LWIP輪詢期間:

1. 推薦每250ms周期性調(diào)用一次tcp_tmr()函數(shù),處理TCP協(xié)議請(qǐng)求。

超時(shí)時(shí)間LWIP使用TCP_TMR_INTERVAL宏進(jìn)行了定義。

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

超時(shí)時(shí)間LWIP使用ARP_TMR_INTERVAL宏進(jìn)行了定義。

3. (如果開啟了動(dòng)態(tài)IP分配功能)推薦每500ms周期性調(diào)用一次dhcp_fine_tmr()函數(shù),處理DHCP動(dòng)態(tài)IP地址分配請(qǐng)求。 如果IP地址獲取成功,將會(huì)放在初始化時(shí)注冊(cè)的網(wǎng)絡(luò)設(shè)備結(jié)構(gòu)體里(struct netif)。

超時(shí)時(shí)間LWIP使用DHCP_FINE_TIMER_MSECS宏進(jìn)行了定義。

4. (如果開啟了動(dòng)態(tài)IP分配功能)推薦每60s調(diào)用一次dhcp_coarse_tmr()函數(shù),用于檢查DHCP租約時(shí)間,并進(jìn)行重新綁定。

超時(shí)時(shí)間LWIP使用DHCP_COARSE_TIMER_MSECS宏進(jìn)行了定義。

5. 在LWIP運(yùn)行期間,當(dāng)網(wǎng)卡收到數(shù)據(jù)時(shí),還需要調(diào)用ethernetif_input函數(shù)讀取網(wǎng)卡數(shù)據(jù)。

在函數(shù)ethernetif_input()主要完成兩個(gè)工作

1、調(diào)用low_level_input(); 讀取網(wǎng)卡實(shí)際數(shù)據(jù)。

2、調(diào)用netif->input();

所以,為了能夠?qū)崟r(shí)的讀取數(shù)據(jù),需要最快的速度輪詢調(diào)用ethernetif_input函數(shù)。

5.3 LWIP編程RAW接口函數(shù)

tcp_new() 創(chuàng)建一個(gè) TCP 的 PCB 控制塊
tcp_bind() 為 TCP 的 PCB 控制塊綁定一個(gè)本地 IP 地址和端口號(hào)
tcp_listen() 開始 TCP 的 PCB 監(jiān)聽
tcp_accept() 控制塊 accept字段注冊(cè)的回調(diào)函數(shù),偵聽到連接時(shí)被調(diào)用
tcp_accepted() 通知 LWIP 協(xié)議棧一個(gè) TCP 連接被接受了
tcp_conect() 連接遠(yuǎn)端主機(jī)
tcp_write() 構(gòu)造一個(gè)報(bào)文并放到控制塊的發(fā)送緩沖隊(duì)列中
tcp_sent() 控制塊 sent 字段注冊(cè)的回調(diào)函數(shù),數(shù)據(jù)發(fā)送成功后被回調(diào)
tcp_output() 將發(fā)送緩沖隊(duì)列中的數(shù)據(jù)發(fā)送出去
tcp_recv()控制塊 recv 字段注冊(cè)的回調(diào)函數(shù),當(dāng)接收到新數(shù)據(jù)時(shí)被調(diào)用
tcp_recved()當(dāng)程序處理完數(shù)據(jù)后一定要調(diào)用這個(gè)函數(shù),通知內(nèi)核更新接收窗口
tcp_poll() 控制塊 poll 字段注冊(cè)的回調(diào)函數(shù),該函數(shù)周期性調(diào)用
tcp_close() 關(guān)閉一個(gè) TCP 連接
tcp_err() 控制塊 err 字段注冊(cè)的回調(diào)函數(shù),遇到錯(cuò)誤時(shí)被調(diào)用
tcp_abort() 中斷 TCP 連接
poYBAGDYdXCAWkKMAAAAK8RNs4s030.png

5.4 創(chuàng)建TCP服務(wù)器示例

下面演示了TCP服務(wù)器創(chuàng)建步驟,測(cè)試服務(wù)器是否正常。

u8 TCP_Create(u16_t port)
{
	struct tcp_pcb *pcb=NULL;
	pcb=tcp_new(); //創(chuàng)建套接字
	if(pcb==NULL)return 1;
	if(tcp_bind(pcb,IP_ADDR_ANY,port)!=ERR_OK)return 2; //綁定端口號(hào)
	pcb=tcp_listen(pcb); //開始監(jiān)聽
	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);  設(shè)置優(yōu)先級(jí)
	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("端口號(hào):%d\n",newpcb->remote_port);
	printf("當(dāng)前隊(duì)列剩余字節(jié):%d\n",tcp_sndbuf(newpcb));
	tcp_write(newpcb,"1234567890",10,1); //將要發(fā)送的數(shù)據(jù)提交到發(fā)送隊(duì)列(不會(huì)立即發(fā)送)
	tcp_output(newpcb); 								 //提示系統(tǒng)現(xiàn)在,發(fā)送數(shù)據(jù)
	tcp_sent(newpcb,TCP_sent); 					 //發(fā)送成功的回調(diào)函數(shù)
	tcp_recv(newpcb,TCP_recv);
	return ERR_OK;
}

err_t TCP_sent(void *arg, struct tcp_pcb *tpcb,u16_t len)
{
	printf("成功發(fā)送:%d字節(jié)\n",len);
	//tcp_close(tpcb); //關(guān)閉客戶端連接
	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("客戶端已經(jīng)斷開連接!\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字節(jié)\n",rx_cnt);
		printf("收到的數(shù)據(jù)=%s\n",rx_buff);
	}
	return ERR_OK;
}
poYBAGDYdXCAWkKMAAAAK8RNs4s030.png

5.5 創(chuàng)建TCP客戶端示例

u8 TCP_Create(u16_t port)
{
	struct tcp_pcb *pcb=NULL;
	pcb=tcp_new(); //創(chuàng)建套接字
	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);  設(shè)置優(yōu)先級(jí)
	printf("服務(wù)器連接成功!\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("服務(wù)器ip地址:%d.%d.%d.%d\n",addr[0],addr[1],addr[2],addr[3]);
	printf("服務(wù)器端口號(hào):%d\n",tpcb->remote_port);
	printf("當(dāng)前隊(duì)列剩余字節(jié):%d\n",tcp_sndbuf(tpcb));
	tcp_write(tpcb,"1234567890",10,1); //將要發(fā)送的數(shù)據(jù)提交到發(fā)送隊(duì)列(不會(huì)立即發(fā)送)
	tcp_output(tpcb); //提示系統(tǒng)現(xiàn)在,發(fā)送數(shù)據(jù)
	tcp_sent(tpcb,TCP_sent); //發(fā)送成功的回調(diào)函數(shù)
	tcp_recv(tpcb,TCP_recv);
	return ERR_OK;
}


err_t TCP_sent(void *arg, struct tcp_pcb *tpcb,u16_t len)
{
	printf("成功發(fā)送:%d字節(jié)\n",len);
	//tcp_close(tpcb); //關(guān)閉客戶端連接
	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("服務(wù)器已經(jīng)斷開連接!\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字節(jié)\n",rx_cnt);
		printf("收到的數(shù)據(jù)=%s\n",rx_buff);
	}
	return ERR_OK;
}
poYBAGDYdXCAWkKMAAAAK8RNs4s030.png

聲明:本文內(nèi)容及配圖由入駐作者撰寫或者入駐合作網(wǎng)站授權(quán)轉(zhuǎn)載。文章觀點(diǎn)僅代表作者本人,不代表電子發(fā)燒友網(wǎng)立場(chǎng)。文章及其配圖僅供工程師學(xué)習(xí)之用,如有內(nèi)容侵權(quán)或者其他違規(guī)問題,請(qǐng)聯(lián)系本站處理。 舉報(bào)投訴
  • 網(wǎng)卡
    +關(guān)注

    關(guān)注

    3

    文章

    301

    瀏覽量

    27312
  • STM32
    +關(guān)注

    關(guān)注

    2264

    文章

    10854

    瀏覽量

    354313
  • LwIP
    +關(guān)注

    關(guān)注

    2

    文章

    85

    瀏覽量

    27056
  • FSMC
    +關(guān)注

    關(guān)注

    0

    文章

    54

    瀏覽量

    38088
  • keil5
    +關(guān)注

    關(guān)注

    6

    文章

    44

    瀏覽量

    20626
收藏 人收藏

    評(píng)論

    相關(guān)推薦

    DM9000系列

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

    【NUCLEO-F412ZG申請(qǐng)】合作式調(diào)度器構(gòu)建以及基于DM9000LWIP移植及調(diào)試

    DM90005、移植LWIP協(xié)議,實(shí)現(xiàn)TCP/UDP通信,并通過上位機(jī)軟件同Demo板進(jìn)行數(shù)據(jù)傳輸。6、
    發(fā)表于 10-31 15:31

    lwip移植時(shí)去掉DM9000的硬件復(fù)位后不能正確移植

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

    U-Boot移植DM9000網(wǎng)卡分享!

    U-Boot移植DM9000網(wǎng)卡——西伯利亞的風(fēng) 根據(jù)書《嵌入式Linux應(yīng)用開發(fā)完全手冊(cè)》移植網(wǎng)卡驅(qū)動(dòng),對(duì)于Jz2440開發(fā)板好像并不適用
    發(fā)表于 07-29 00:06

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

    ,但是程序還是不斷通過串口打印 dm9000 rx: rx error, stop device具體的程序和電路圖[url=]圖片[/url][url=]附件[/url] 網(wǎng)絡(luò)實(shí)驗(yàn)1 LWIP無操作系統(tǒng)
    發(fā)表于 09-02 23:39

    為什么DM9000網(wǎng)卡物理地址無法設(shè)置進(jìn)環(huán)境變量中?

    原先做DM9000移植的時(shí)候都是成功的,但是在做環(huán)境變量和裁剪的時(shí)候就出了這個(gè)問題,設(shè)置成nandflash保存網(wǎng)卡的環(huán)境變量就會(huì)報(bào)這個(gè)錯(cuò),norflash不會(huì)報(bào)錯(cuò)U-Boot 2016.01
    發(fā)表于 09-20 00:10

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

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

    LWIP輸出dm9000錯(cuò)誤

    無操作系統(tǒng)的LWIP 用電腦一ping它,單片機(jī)串口就無限輸出 dm9000 rx: rx error, stop device找不到是什么原因?qū)е碌?求解答 附上程序
    發(fā)表于 03-19 01:07

    STM32F103戰(zhàn)艦DM9000LWIP例程TCP速度不快

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

    如何在STM32F103工程里添加移植LWIP協(xié)議

    完成TCP服務(wù)器、TCP客戶端的通信測(cè)試。 網(wǎng)卡采用的是DM9000,工程代碼中,采用STM32的FSMC接口來驅(qū)動(dòng)
    發(fā)表于 08-12 07:20

    dm9000/dm9000a linux驅(qū)動(dòng)程序 (Ethe

    dm9000/dm9000a以太網(wǎng)卡芯片linux驅(qū)動(dòng)程序 :dm9000/dm9000a Ethernet chips linux dri
    發(fā)表于 12-26 00:13 ?117次下載

    基于ARM和DM9000網(wǎng)卡接口設(shè)計(jì)與實(shí)現(xiàn)

    針對(duì)ARM CPU S3C2410的特點(diǎn),設(shè)計(jì)開發(fā)了外圍網(wǎng)卡接口平臺(tái),通過驅(qū)動(dòng)程序?qū)σ蕴W(wǎng)控制芯片DM9000的控制,實(shí)現(xiàn)了網(wǎng)絡(luò)數(shù)據(jù)傳輸功能。硬件方面主要涉及以太網(wǎng)網(wǎng)絡(luò)接口的設(shè)計(jì),軟件
    發(fā)表于 10-09 16:16 ?144次下載

    DM9000的以太網(wǎng)藏文信息控制平臺(tái)

    DM9000的以太網(wǎng)藏文信息控制平臺(tái) 摘要:基于DM9000的以太網(wǎng)電路,單片機(jī)端移植精簡(jiǎn)TCP/IP協(xié)議unIP,實(shí)現(xiàn)簡(jiǎn)易的TCP服務(wù)
    發(fā)表于 04-13 12:47 ?5651次閱讀
    <b class='flag-5'>DM9000</b>的以太網(wǎng)藏文信息控制平臺(tái)

    基于ARM的LwIP協(xié)議研究與移植

    提出基于ARM的LwIP協(xié)議研究與移植
    發(fā)表于 10-14 17:50 ?65次下載
    基于ARM的<b class='flag-5'>LwIP</b><b class='flag-5'>協(xié)議</b><b class='flag-5'>棧</b>研究與<b class='flag-5'>移植</b>

    單片機(jī)驅(qū)動(dòng)DM9000網(wǎng)卡芯片詳細(xì)調(diào)試過程

    單片機(jī)驅(qū)動(dòng)DM9000網(wǎng)卡芯片詳細(xì)調(diào)試過程
    發(fā)表于 11-02 11:03 ?0次下載