學會Zynq(12)lwIP 1.4.1庫的配置與使用
lwIP概述
lwIP是一個用於嵌入式系統的開源TCP/IP協議集,是一套可以獨立執行的棧,無需依賴作業系統,但也可以與作業系統同時使用。lwIP提供了兩套API(術語為A05PI),供使用者選擇:
- RAW API:直接訪問核心的lwIP棧;
- Socket API:通過BSD socket風格的介面訪問lwIP棧。
基於lwIP 1.4.1庫版本,SDK提供了相應適配的庫,稱作lwip 141_v1_x。這個庫為Ethernetlite、TEMAC、GigE、MAC核提供了介面卡(adapter)。Ethernetlite和TEMAC核用於MicroBlaze系統;GigE控制器和MAC核用於Zynq。想在Xilinx FPGA環境下熟練使用lwIP,不僅要了解lwIP的API用法,還要掌握xilinx介面卡的一些知識。
Xilinx中lwIP的使用可以參考xapp1026和UG650;lwIP的開發者主頁為 http://savannah.nongnu.org/projects/lwip/ ;查閱lwip的相關知識:https://lwip.fandom.com/wiki/LwIP_Wiki。
設定硬體系統
lwIP支援的硬體系統包含的關鍵元件如下:
- 處理器:MicroBlaze、Zynq中的Cortex-A9、Zynq UltraScale+ MPSoC系統中的Cortex-A53和Cortex-R5;
- MAC:lwIP支援axi_ethernetlite、axi_ethernet、GigE控制器和MAC核;
- 定時器:基於lwIP RAW API的應用需要按週期間隔呼叫某些函式,可通過一個帶定時器的中斷處理器來實現。
- DMA:對於MicroBlaze,axi_ethernet核可以配置一個軟DMA引擎或一個FIFO介面。對於Zynq,已經有嵌入的DMA,因此無需額外配置。
上圖是一個MicroBlaze系統架構的示例,使用了帶DMA的axi_ethernet核。
設定軟體系統
把Vivado的硬體平臺匯入到SDK中時,預設是不包含lwIP庫的,因此必須先做相應配置,編譯lwIP庫到應用程式中。步驟如下:
1.SDK中選擇File->New->Xilinx Board Support Package,建立新的板級支援包。
2.設定工程名稱和目錄。Zynq系列選擇FreeRTOS或裸機;MicroBlaze還可以選擇XilKernel。點選Finish,彈出配置視窗,配置BSP。
3.選中lwip 141,視窗左側會出現對lwip庫做更詳細配置的視窗。
4.配置完成後點選OK,SDK會自動構建包含lwIP的板級支援包。
lwIP的詳細配置
lwIP提供了可配置的引數,SDK中可以改變這些引數值。可配置的選項可以分為兩類:
- Xilinx介面卡的相關選項:Xilinx介面卡把這些控制設定用於乙太網核;
- 基本lwIP選項:這些選項是lwIP庫本身的一部分,包括用於TCP、UDP、IP等其它協議的引數。
1.定製lwIP API模式
lwip141_v1_x支援RAM API和Socket API。RAW API有更好的效能和更低的記憶體佔用,但由於是基於回撥機制的,因此不能與其它TCP 棧相容;Socket API提供了一個BSD socket風格的介面,因此移植性很強,但在效能和記憶體需求方面沒有RAW API效率高。
選項名稱 | 說明 | 預設值 |
---|---|---|
api_mode{RAW_API|SOCKET_API} | lwIP庫的操作模式 | RAW_API |
socket_mode_thread_prio | lwIP執行緒的優先順序,僅當使用Xilkernel的優先順序模式時才有效 | 1 |
use_axieth_on_zynq | 如果要在Zynq中使用AxiEthernet軟核IP,需要設定此選項來關閉MAC核(GigE) | 0表示使用GigE控制器;1表示使用AxiEthernet |
2.配置Xilinx介面卡選項
axi_ethernetlite介面卡(ethernetlite_adapter_options)相關的配置引數如下:
屬性 | 說明 | 預設值 |
---|---|---|
sw_rx_fifo_size | 軟體緩衝區大小,以EMAC和處理器之間接收資料的位元組為單位 | 8192 |
sw_tx_fifo_size | 軟體緩衝區大小,以處理器和EMAC之間傳送資料的位元組為單位 | 8192 |
axi_ethernet和GigE介面卡(temac_adapter_options)的相關配置引數如下:
屬性 | 預設值 | 說明 |
---|---|---|
n_tx_descriptors | 64 | 使用Tx描述符的數量,高效能系統增大此值 |
n_rx_descriptors | 64 | 使用Rx描述符的數量,高效能系統增大此值 |
n_tx_coalesce | 1 | 設定Tx中斷合併 |
n_rx_coalesce | 1 | 設定Rx中斷合併 |
tcp_rx_checksum_offload | false | 解除安裝(offload)TCP接收校驗和計算 |
tcp_tx_checksum_offload | false | 解除安裝(offload)TCP傳送校驗和計算 |
tcp_ip_rx_checksum_ofload | false | 解除安裝(offload)TCP和IP接收校驗和計算 |
tcp_ip_tx_checksum_ofload | false | 解除安裝(offload)TCP和IP傳送校驗和計算 |
phy_link_speed | AUTO | 由物理層自動協商鏈路速度,lwIP據此配置TEMAC/GigE,某些PHY可能不支援自動檢測,此時這個值必須設定正確 |
temac_use_jumbo_frames_experimental | false | 使用TEMAC巨型幀(可達9k位元組)。設定為true,TEMAC將允許傳輸和接收巨型幀。 |
3.配置記憶體選項
lwIP棧提供了不同種類的記憶體。當應用程式使用socket模式時,將使用不同的記憶體選項。所有可配置的記憶體選項都作為單獨的類別提供。
屬性 | 預設值 | 說明 |
---|---|---|
mem _size | 131072 | 可用堆記憶體的總大小(位元組),如果應用程式需要從堆中使用大量記憶體應考慮增大此值 |
memp_n_pbuf | 16 | memp結構pbuf的數量,如果應用程式需要從ROM等靜態記憶體中傳送大量資料,考慮增大此值 |
memp_n_udp_pcb | 4 | UDP協議控制塊的數量,每個活躍的UDP連線佔用一個控制塊 |
memp_n_tcp_pcb | 32 | 同上,同時活躍的TCP連線數 |
memp_n_tcp_pcb_listen | 8 | 監聽TCP連線的數量 |
memp_n_tcp_seg | 256 | 同時排隊的TCP段的數量 |
memp_n_sys_timeout | 8 | 同時活躍的超時(timeout)數量 |
memp_num_netbuf | 8 | netbufs型別的結構體例項的數量,僅在socket模式下可用 |
memp_num_netconn | 16 | netconns型別的結構體例項的數量,僅在socket模式下可用 |
memp_num_api_msg | 16 | api_msg型別的結構體例項的數量,僅在socket模式下可用 |
memp_num_tcpip_msg | 64 | TCP/IP msg結構體的數量,僅在socket模式下可用 |
4.pbuf_options
包緩衝區(Pbuf)跨TCP/IP棧的不同層,下面是lwip棧提供的pbuf記憶體選項,一般情況下無需修改該選項的預設值。
屬性 | 預設值 | 說明 |
---|---|---|
pbuf_pool_size | 256 | pbuf池中的緩衝區數目,對於高效能系統,可以考慮設定更大的值 |
pbuf_pool_bufsize | 1700 | pbuf池中每個pbuf的大小,對於支援巨型幀的系統,要設定比巨型幀更大的值 |
pbuf_link_hlen | 16 | 分配給鏈路級header的位元組數 |
5.arp_options
一般情況下無需修改該選項的預設值。
屬性 | 預設值 | 說明 |
---|---|---|
arp_table_size | 10 | 快取的硬體地址IP地址對數目 |
arp_queueing | 1 | 出站資料包在硬體地址解析期間會排隊 |
6.lwip_ip_options
下表是下級選單中的IP引數選項,一般情況下無需修改該選項的預設值。
屬性 | 預設值 | 說明 |
---|---|---|
ip_forward | 0 | 1表示啟用跨網路介面轉發IP資料包的功能在單個網路介面上執行lwIP時設定為0 |
ip_options | 0 | 1表示允許使用IP選項0表示丟棄所有帶IP選項的包 |
ip_reassembly | 1 | 重新組裝傳入的碎片IP資料包 |
ip_flag | 1 | 傳送的IP資料包大小超過MTU時對其分段 |
ip_reass_max_pbufs | 128 | 重組的pbuf佇列長度 |
ip_frag_max_mtu | 1500 | 任意介面的IP碎片緩衝區的的最大MTU |
ip_default_ttl | 255 | 傳輸層使用的全域性預設TTL值 |
7.icmp_options
該選項只可以設定ICMP的TTL值。Zynq中的GigE核不支援使用ICMP。
8.igmp_options
lwIP支援IGMP協議,該選項沒有下級選單,設定為true可以啟用IGMP協議。
9.udp_options
lwIP支援UDP協議,一般情況下無需修改該選項的預設值。
屬性 | 預設值 | 說明 |
---|---|---|
lwip_udp | true | 設定是否需要UDP |
udp_ttl | 255 | UDP TTL值 |
10.tcp_options
lwIP支援TCP協議,一般情況下無需修改該選項的預設值。
屬性 | 預設值 | 說明 |
---|---|---|
lwip_tcp | true | 設定是否需要TCP |
tcp_ttl | 255 | TCP |
tcp_wnd | 2048 | TCP視窗大小(位元組) |
tcp_maxrtx | 12 | TCP最大重傳值 |
tcp_synmaxrtx | 4 | TCP最大SYN重傳值 |
tcp_queue_ooseq | 1 | 接收順序錯誤的TCP佇列段在記憶體不足的情況下可設為0 |
tcp_mss | 1460 | TCP最大段的大小 |
tcp_snd_buf | 8192 | TCP傳送緩衝空間(位元組) |
11.dhcp_options
lwIP支援DHCP協議,一般情況下無需修改該選項的預設值。
屬性 | 預設值 | 說明 |
---|---|---|
lwip_dhcp | false | 設定是否需要DHCP |
Dhcp_does_arp_check | false | 設定ARP是否檢查提供的地址 |
12.stats_options
lwIP棧在設計上可以收集一些統計資訊,比如使用的連線數、記憶體使用量、應用程式使用的訊號量的數量。lwIP庫提供了函式stats_display()來顯示統計值。是否啟用該功能在stats選項中設定。該選項下只有一個boolean型別的lwip_stats,預設為false。
13.debug_options
lwIP可以提供除錯資訊,debug_options下包括lwip_debug、ip_debug、tcp_debug、udp_debug、icmp_debug、igmp_debug、netif_debug、sys_debug、pbuf_debug幾個選項,都是boolean型別,設定true/false來開啟/關閉對應的除錯功能。
軟體API
lwIP庫提供了兩種不同的API:RAW mode和Socket mode。
RAW API基於回撥機制,應用程式與TCP棧之間可以直接訪問。因此沒有額外的socket層,RAW API有優秀的效能表現,但不能與其它TCP棧相容。此外,Xilinx介面卡還為接收資料包提供了xemacif_input程式函式。必須經常呼叫此函式,將接收到的資料包從中斷處理程式移動到lwIP棧。根據接受包的型別,lwIP回撥相應的程式。
Socket API是一套BSD socket風格的API。該API提供了一個執行模型,它是一個阻塞的、“開啟-讀-寫-關閉(open-read-write-close)”模型。使用Socket API和Xilinx介面卡的應用程式需要生成一個單獨的執行緒xemacif_input_thread。這個執行緒將接收到的資料包從中斷處理程式移動到lwIP的tcpip_thread。必須使用lwIP的sys_thread_new API建立使用lwIP的應用程式執行緒。
Xilinx介面卡提供了一些輔助函式,以簡化lwIP API的使用,各函式簡要說明如下:
1.lwip_init
void lwip_init()
這個函式為lwIP資料結構做了初始化,會替換對初始化狀態、系統、記憶體、pbuf、ARP、IP、UDP、TCP的特定呼叫。
2.xemac_add
struct netif *xemac_add (struct netif *netif, struct ip_addr *ipaddr, struct ip_addr *netmask, struct ip_addr *gw, unsigned char *mac_ethernet_address, unsigned mac_baseaddr)
這個函式為新增任何Xilinx EMAC IP和GigE核提供了一個統一的介面。這個函式在lwIP的netif_add函式基礎上封裝的,用於初始化網路介面‘netif’,給定它的IP地址、網路掩碼、閘道器的IP地址、6位元組的乙太網地址(MAC地址),以及axi_ethernetlite或axi_ethernet MAC核的基地址。
3.xemacif_input
void xemacif_input(struct netif *netif)
該函式只在RAW模式下可用。Xlinx lwIP介面卡在中斷模式下工作。接收中斷處理程式從EMAC/GigE中將包資料移動並儲存在佇列中。xemacif_input函式從佇列中取出這些包,傳遞給lwIP。因此在RAW mode下,需要使用這個程式。下面是一個簡單示例:
while (1) {
/* receive packets */
xemacif_input(netif);
/* do application specific processing */
}
該程式會通過回撥通知已經接收到的資料。
4.xemacif_input_thread
void xemacif_input_thread(struct netif *netif)
該函式只在Socket模式下可用。Socket模式中,應用程式必須啟動一個單獨的執行緒來接收輸入包。這與RAW模式下的xemacif_input函式功能相同,只不過它駐留在獨立的執行緒中。因此,任何lwIP socket模式下的應用程式都需要有類似如下的程式碼:
sys_thread_new(“xemacif_input_thread”, xemacif_input_thread, netif,
THREAD_STACK_SIZE, DEFAULT_THREAD_PRIO);
然後,應用程式可以啟動單獨的執行緒來完成應用程式中特定的任務。xemacif_input_thread會接收中斷處理程式處理的資料,將其傳遞給lwIP tcpip_thread。
5.xemacpsif_resetrx_on_no_rxdata
void xemacpsif_resetrx_on_no_rxdata(struct netif *netif)
該函式在Raw模式和Socket模式下都可用,但只能用於Zynq系列的GigE控制器。GigE控制器上有一個與Rx路徑有關的勘誤表(errata)。該勘誤表描述了當小資料包的Rx流量過大時,GigE的Rx路徑完全沒有響應的情況。這種情況很少發生,但發生時需要對控制器中的Rx邏輯進行軟體重置。使用者的應用程式必須週期性地呼叫這個函式,以確保Rx路徑不會再超過100ms的時間內停止響應。
RAW API程式架構
使用RAW API的應用程式是單執行緒的,一般具有與下面虛擬碼類似的主架構:
int main()
{
struct netif *netif, server_netif;
struct ip_addr ipaddr, netmask, gw;
//板子的MAC地址,每個PHY都不同
unsigned char mac_ethernet_address[] =
{0x00, 0x0a, 0x35, 0x00, 0x01, 0x02};
lwip_init();
//把網路介面新增到netif_list, 並設為預設
if (!xemac_add(netif, &ipaddr, &netmask,
&gw, mac_ethernet_address, EMAC_BASEADDR)) {
printf(“Error adding N/W interface\n\r”);
return -1;
}
netif_set_default(netif);
platform_enable_interrupts(); //使能中斷
netif_set_up(netif); //指定網路是否開啟
start_application(); //啟動應用程式,設定回撥
//接收並處理包
while (1) {
xemacif_input(netif);
transfer_data(); //執行應用程式的特定功能
}
}
RAW API主要通過非同步呼叫傳送和接收的回撥函式來工作。
Socket API程式架構
Socket模式下,基於Xilkernel的應用程式可以在Xilkernel軟體平臺的設定對話方塊中指定一個靜態執行緒列表,這些執行緒會在Xilkernel啟動時生成。假設main_thread()是一個設定的由Xilkernel啟動的執行緒,在啟動Xilkernel排程後,控制權會從應用程式中的“main”轉移到這個執行緒。在main執行緒中,再建立一個執行緒(network_thread)來初始化MAC層。
對於基於FreeRTOS(Zynq-7000處理器系統)的應用程式,一旦控制權到達“main”,就會在啟動排程程式之前建立一個帶有main_thread()入口函式的任務。在FreeRTOS排程程式啟動之後,控制權到達main_thread(),在這裡進行lwIP的初始化。然後,應用程式再建立一個執行緒(network_thread)來初始化MAC層。
下面的虛擬碼展示了一個典型的Socket模式下的程式架構:
void network_thread(void *p)
{
struct netif *netif, server_netif;
struct ip_addr ipaddr, netmask, gw;
//板子的MAC地址,每個PHY都不同
unsigned char mac_ethernet_address[] =
{0x00, 0x0a, 0x35, 0x00, 0x01, 0x02};
netif = &server_netif;
//初始化使用的IP地址
IP4_ADDR(&ipaddr,192,168,1,10);
IP4_ADDR(&netmask,255,255,255,0);
IP4_ADDR(&gw,192,168,1,1);
//把網路介面新增到netif_list, 並設為預設
if (!xemac_add(netif, &ipaddr, &netmask,
&gw, mac_ethernet_address, EMAC_BASEADDR)) {
printf(“Error adding N/W interface\n\r”);
return;
}
netif_set_default(netif);
netif_set_up(netif); //指定網路是否開啟
//啟動包接收執行緒
sys_thread_new(“xemacif_input_thread”, xemacif_input_thread,
netif, THREAD_STACKSIZE, DEFAULT_THREAD_PRIO);
//啟動應用程式執行緒
sys_thread_new(“httpd” web_application_thread, 0,
THREAD_STACKSIZE DEFAULT_THREAD_PRIO);
}
int main_thread()
{
//呼叫sys_thread_new前初始化lwIP
lwip_init();
//使用lwIP的所有執行緒都要用sys_thread_new()建立
sys_thread_new(“network_thread” network_thread,
NULL, THREAD_STACKSIZE DEFAULT_THREAD_PRIO);
return 0;
}
相關文章
- 學會Zynq(10)lwIP簡介
- 學會Zynq(2)Zynq-7000處理器的配置詳解
- 學會Zynq(9)定時器使用示例(PPI)定時器
- 學會Zynq(3)Zynq的軟體開發基礎知識
- 學會Zynq(1)搭建Zynq-7000 AP SoC處理器
- 學會Zynq(8)PL中斷示例(SPI)
- 學會Zynq(7)中斷系統簡介
- Xilinx-ZYNQ7000系列-學習筆記(7):解決ZYNQ IP核自動佈線後會更改原有配置的問題筆記
- 學會Zynq(11)RAW API的TCP和UDP程式設計APITCPUDP程式設計
- 學會Zynq(6)固化程式到SD卡或QSPI FlashSD卡
- 【lwip】lwip原始碼基礎原始碼
- Zynq學習筆記(1)筆記
- ZYNQ的gpio的硬體驅動庫知識
- 1.4.1. 關於Oracle 資料庫版本號Oracle資料庫
- ZYNQ PS端IIC介面使用-筆記筆記
- ZYNQ核心板使用者手冊
- ZYNQ學習筆記(一): uboot 編譯筆記boot編譯
- LWIP裸機移植
- Xilinx-ZYNQ7000系列-學習筆記(2):私有看門狗(AWDT)的使用筆記
- Go 語言 Excel 文件類庫 excelize 釋出 1.4.1 版本GoExcelize
- 學習Spring5必知必會(4)~使用註解配置、使用java程式碼配置SpringJava
- Xilinx-ZYNQ7000系列-學習筆記(3):系統復位與啟動筆記
- 學會使用dockerDocker
- DNSmasq 的安裝、配置與使用DNS
- Go 語言 Excel 文件類庫 excelize 釋出1.4.1版本GoExcelize
- 004:ZYNQ_AXI匯流排學習筆記(1)筆記
- 15分鐘學會使用Git和遠端程式碼庫Git
- 15 分鐘學會使用 Git 和遠端程式碼庫Git
- swoft 學習筆記之資料庫配置與實體定筆記資料庫
- MySQL學習(一)資料庫安裝與配置全程圖解MySql資料庫圖解
- 學會使用 curl 命令
- JWT-配置與使用JWT
- ModelAndView 配置與使用View
- 使用rollup打包庫的一種基本配置
- Tomcat5.5.12的資料庫連線池的配置Tomcat資料庫
- VS下生成與配置靜態庫與動態庫(一)
- maven的下載、安裝與配置 倉庫配置完整版Maven
- Docker容器學習與分享12Docker