整理一下這幾天學習的一些知識,就當是一些知識概念的整理,免得以后忘記了。
一、內容
在NiosII IDE建立基於uC/OS操作系統的TCP/IP Socket Server工程,該應用工程能夠初始化LwIP(Light weight IP)stack,運行簡單的TCP Server。PC機可以通過Ethernet與開發板通信。硬件系統要求有lan91c111 Ethernet MAC。軟件有MicroC/OS-II和LwIP。把配置有Ethernet控制器的硬件系統配置到FPGA中,然后編譯運行應用程序。PC機通過Ethernet訪問開發板進行通信。
這里所用的平台是:博創UP-AR2000 Quartus II 7.2 Nios II 7.2
二、uC/OS II
uC/OS-II只是一個實時操作系統內核,它僅僅包含了任務調度,任務管理,時間管理,內存管理和任務間的通信和同步等基本功能。沒有提供輸入輸出管理,文件系統,網絡等額外的服務。但由於uC/OS-II良好的可擴展性和源碼開放,這些非必須的功能完全可以由用戶自己根據需要分別實現。
Altera的uCOS2本質上是Nios II HAL的一個超集,是uCOS2任務調度器和相關API函數在HAL環境上的擴展。在uCOS2 Project中,所有Nios II本身的HAL API都可以被調用。
三、LwIP協議棧 和 NicheStack TCP/IP協議棧
3.1 LwIP協議棧
LWIP是TCP/IP協議棧的一種實現。主要目的是減少存儲器利用量和代碼尺寸,幾十K字節的程序空間和幾十K字節的數據RAM空間就可以實現。很適合應用於小的、資源有限的處理器如嵌入式系統。可以移植到操作系統上,也可以在無操作系統的情況下獨立運行。
要實現嵌入式TCP/IP協議棧,最關鍵的一個問題就是,如何結合系統資源有限的嵌入式系統軟硬件環境以及具體的嵌入式Internet應用對標准的TCP/IP協議棧進行簡化, 從而實現一種“輕量級”的TCP/IP協議棧。這就是所謂的Light-weight IP。由瑞典計算機科學院的Adam Dunkels創建。
LwIP提供了完成的TCP/IP協議功能,支持IP,ICMP,UDP,TCP,DHCP,ARP。
Altera在Nios II上的LwIP移植基於uCOS2的多任務環境,在Nios IDE中開發LwIP應用程序需要工程首先配置為支持uCOS2。
Nios II上LwIP支持的網絡芯片為SMSC的LAN91C111。
3.2 LwIP的進程模型
協議實現的進程模型以把系統划分成為不同的進程的方法進行描述。先看下普通的TCP/IP協議的模型。
這種方法有其諸多優勢,如協議能在運行時被增加,代碼一般容易理解和調試。但也有不利因素,嚴格的分層並不總是實現協議的最好方法。
數據跨層傳遞時將不得不產生進程切換(context switch)。對於接收一個TCP段來說,將會引起三次進程切換,從網絡設備驅動層進程到IP進程,從IP進程到TCP進程,最終到應用層進程。對於大部分操作系統來說,進程切換的代價可是相當昂貴的。
lwIP所使用的進程模型是:把所有協議封裝到一個單一的進程中,從而與操作系統內核分開。
應用程序可能也駐留在lwIP處理過程中,或者在單獨的過程中。
TCP/IP棧和應用程序之間的通信可以通過函數調用實現,也可以通過更為抽象的API。
有些學者把這種方法稱為零拷貝技術。所謂“零拷貝”,是指TCP/IP協議棧沒有用於各層數據傳輸的緩沖區,協議棧各層之間傳遞的都是數據指針。
只有當數據最終要被驅動程序發送出去或者是被應用程序取走時,才進行真正的數據搬移。這樣就大大減少了系統開銷,從而提高系統性能。
3.3 NicheStack與LwIP一脈相承,技術上並無本質區別,在作產品時可能有區別。前者需要授權,后者則不需要。
四、代碼中的一些分析
(1)網絡接口的初始化
在啟動OSStart()函數進入多任務狀態之前,調用如下兩個函數完成網絡接口的初始化:
1)lwip_stack_init()
函數原型為:void lwip_stack_init(int thread_prio, void (* init_done_func)(void *), void *arg)
thread_prio:主TCP/IP線程的優先級
init_done_func():lwip_stack_init函數執行完成后就轉向執行這個指針指向的函數
arg:傳遞給init_done_func的參數,視init_done_func()而定,通常置為0
功能:創建一個TCPIP協議棧主線程,完成TCP/IP協議棧的初始化並轉向init_done_func
2)lwip_devices_init()
函數原型為:int lwip_devices_init(int rx_thread_prio)
Lwip_devices_init從system.h中遍歷所有安裝的網絡設備驅動並注冊。成功后返回一個非零值,此時如果TCPIP棧准備就緒,就可以為應用程序創建任務。
此函數創建了一個接收線程,其優先級由參數rx_thread_prio給定
此函數會調用get_mac_addr和get_ip_addr二函數,這兩個函數必須由用戶編寫。
(2)get_mac_addr和get_ip_addr
LwIP系統代碼必須根據此二函數設置網絡設備的MAC和IP地址。
通過寫這兩個函數,系統可以靈活地將MAC和IP地址存放在任意位置,而不是設備驅動的某個固定位置。如可以存放在FLASH中,也可存放在片內RAM中。
兩個函數都使用了LwIP內部使用的結構體。用戶無需知道結構體的細節,只需知道如何填充MAC和IP地址。
(3)應用程序創建四個任務
1)SSSInitialTask()
SSSInitialTask創建了兩個軟件組件層任務:
NicheStack TCP/IP Stack main task:在netmain()中創建
time-keeping task:在netmain()中創建
SSSInitialTask在創建兩個任務后刪除本任務。
1 alt_iniche_init(); //執行NicheStack網絡棧的預初始化
2 netmain(); //初始化並開始NicheStack網絡棧
3 //iniche_net_ready標明TCP/IP棧准備好,IP地址已獲取
4 while (!iniche_net_ready) TK_SLEEP(1);
5 //協議棧已開始運行,應用程序初始化, 開始應用相關的任務加載代碼塊
6 printf("\nSimple Socket Server starting up\n");
7 TK_NEWTASK(&ssstask); //創建simple socket server任務
8 SSSCreateOSDataStructs();//創建OS數據結構:隊列信號量等
9 SSSCreateTasks(); //創建其它任務
10 error_code = OSTaskDel(OS_PRIO_SELF);
2)SSSSimpleSocketServerTask()
其完成的功能為:
創建一個socket實現TCP/IP連接,綁定到socket上,偵聽客戶端的TCP/IP連接請求。
到來TCP/IP連接時,調用sss_handle_accept()。
調用sss_handle_receive()處理TCP/IP連接。如果需要多個TCP/IP連接,需要創建更多任務。
調用sss_reset_connection(), sss_send_menu()和sss_exec_command()。
當收到數據包后,LED命令被提取並通過SSSLEDCommandQ隊列送到LEDManagementTask()。
3)LEDManagementTask()
響應SSSLEDCommandQ隊列中的命令。如果命令給7段數碼管的則更改SSSLEDLightshowSem信號量。如果命令給LED燈,則修改SSSLEDEventFlag值,從而控制不同的LED燈顯
示。
4)LED7SegLightshowTask()
根據SSSLEDLightshowSem的值,在7段LED上閃爍隨機圖案或停止閃爍。
五、實驗過程與結果
實驗中自己修改的內容不算多,只要設置好MAC地址和IP地址。IP地址是要和PC機的IP地址在一個局域網中,然后用交叉線連接。需要注意的是:有的電腦上有2個網口,當需要做實驗時,需要將另外一個網口關閉,否則遠程控制會無效。關鍵還是要理解其中運行的機理。主要實現的是從PC機上遠程控制開發板上的操作。
當.sof文件下載后,運行軟件,可以在輸出窗口看到自己所設置的IP地址。
從“開始”中打開“運行”。
輸入命令和IP、端口號“telnet 192.168.0.250 30”。
只要能連接上,就能遠程控制LED燈與數碼管了。