使用keil5中的RL_TCPNet中間件--建立篇

前言

RL_TCPnet也算是一個比較有名的小型協議棧,相比於LwIP,它支持非常多的應用協議。並且這是ARM自家出的中間件,專門針對自家內核做過優化,性能強勁。所以學一下它非常有必要。這次搞以太網算是第二次了,去年開始嘗試玩了一下,自己畫了一套F107以太網開發板,但是最後是沒調出來。後來發現是硬件電路畫的有問題,就沒接下去弄了。這次又拿起來搞,總結上次電路失敗的經驗,我又重新設計了一塊電路板。嗯,這次是一次成功啊^_^!所以在學習網絡應用之前,得首先確保你的硬件是可以用的啊,不然車底盤不穩,開的再快遲早是要翻車的呀!先上一份我做好的成品。最終學習目地是做一個串口服務器:)
這裏寫圖片描述

硬件電路設計

嵌入式以太網接口一般有以下幾種模式:
- 1.MCU內部自帶MAC+PHY,比如TI的LM3S6911,此款芯片是自帶MAC和PHY,外部接上RJ45接口電路就可以使用了。
- 2.MCU內部自帶MAC,需要外接PHY。比如我使用的STM32F107,外接一個DP83848物理芯片和添加RJ45接口電路就可以使用了。當然PHY有很多LA8720、DM9162等都可以使用。
- 3.MCU內部既不帶MAC也不帶MAC和PHY,這就是一般低端的單片機了,這種情況下可以使用SPI接口網絡芯片,典型的就是enc28j60。像F103不帶MAC的就可以使用SPI驅動該芯片,以實現網絡應用。

MAC即媒體訪問控制,處於鏈路層的下方。MAC的作用是使設備在多節點應用中,不會引起訪問衝突。

PHY即端口物理層,是OSI參考模型中的最底層。常用的PHY基本寄存器都一樣,不一樣的是各個廠家提供的擴展寄存器和專門設置的寄存器。所以驅動成功立一種PHY,驅動另一種PHY也就很簡單。

底層驅動接口

(1)獨立於介質的接口:MII

這裏寫圖片描述
該接口有16根線,使用25MHz外部晶振驅動時鐘系統。支持10Mbps和100Mbps的運行速率。

(2)精簡的獨立於介質的接口:RMII

這裏寫圖片描述
RMII將標準減少到7根線,支持10Mbps和100Mbps運行速率;時鐘信號需提高到50MHz;MAC和PHY需要使用同樣的時鐘源;使用2位寬的數據收發。

(3)DP83848的RMII應用電路

我所使用的接口就是RMII,使用該接口就沒有MII那麼多線看着頭暈的麻煩。具體電路如下,DP83848其它的引腳功能需要自行查閱數據手冊了
這裏寫圖片描述

創建工程

在確保硬件可以使用的情況下,接下來就要開始創建工程來驅動這個PHY。自keil5發佈以來,創建和使用中間件就非常方便,特別是在使用中間件的時候,省去了很多移植的花費的時間。你可能會看到我就是不停的勾選,勾選勾選,一個工程例子代碼就創建好了。。。(我使用的版本是5.23,組件都是最新版本)

(1)新建UDP例子工程

1.CMSIS驅動選擇

新建一個工程,創建工程名,選擇芯片F107RC(具體芯片具體選擇),接下來就跳到“Manage Run-Time Environment”窗口。這是重點,選好依賴整個創建過程就很快。驅動選擇如下:
這裏寫圖片描述
這裏說明一下,在勾選時,選項卡變黃是因爲缺少相應的依賴,依賴齊全後,就變成綠色。因爲RL_TCPnet這個版本需要使用RTX,所以RTOS必選。因爲我使用的是MAC+PHY,所以MAC驅動必選,PHY按所選用的芯片來選擇。像其它的PHY芯片,因爲基本寄存器都一樣,所以可以在keil5提供的一種PHY驅動文件中來更改驅動文件,以適應自己的PHY。選擇UASRT驅動是用來Debug輸出時使用的。

2.STM32驅動選擇

圖中的DMA和GPIO是keil提供的驅動文件,目的是與CMSIS Driver相互依賴。使用STM32的標準庫的GPIO是用來初始化PHY的復位引腳的。
這裏寫圖片描述

3.STDIO調試選擇

使能STDOUT後,在程序中就可以使用printf函數。keil爲F1提供相應的串口驅動,所以我們不必編寫相應的串口驅動程序。
這裏寫圖片描述

4.NetWork選擇

具體的選擇如圖所示,內核選擇Debug STDIO調試版本,正式發佈後可選擇發行版本。接口使用的ETH,序號1表示有一個MAC物理IP.其它2個是供串行接口使用。現在這個例子不使用服務,我們使用UDP做測試。
這裏寫圖片描述

(2)文件配置

以上工程依賴配置好後,就要添加相應的文件,配置文件了。

1.添加模板代碼

鼠標右鍵“Source Group1”向該組增加文件。
這裏寫圖片描述

增加UDP模板代碼文件
這裏寫圖片描述

增添stoutio模板文件
這裏寫圖片描述

去掉main函數註釋
這裏寫圖片描述

編譯一下工程,會錯誤提示,然後按着錯誤來解決相應的問題。
這裏寫圖片描述

上圖中提示出了2個錯誤,分別是ETH和USART找不到。那需要配置“RTE_Device.h”文件,進入此文件的配置視圖模式。具體配置如下:
這裏寫圖片描述

ETH接口有使用重映射的方式,要具體選擇。系統的時鐘一定不要配置錯誤。選擇好後,再編譯一次,還有一個錯誤 ,如下圖:
這裏寫圖片描述

這個提示是stdout_usart使用的串口號沒有選擇,配置如下:
這裏寫圖片描述

因爲我使用的是串口1,所以編號要選擇對應的,波特率選擇115200,打印速度多少會快點。

2.配置RTX

再編譯一次就沒啥錯誤了。你以爲這就完了?其實還有很多。接下來配置RTX:
這裏寫圖片描述

配置啓動文件的中斷調用堆棧
這裏寫圖片描述

RTX系統配置要注意以下幾點:1.RTOS kernel Timer要和系統時鐘頻率相同。2.RL_TCPnet在初始化時會創建2個線程,每個線程給它分配1k的棧空間,”Number of threads whith usr-provied stack size “設置爲2;”Total stack size for threads whith user-provied stack size “設置2048,總共2K。待會兒調試窗口看到線程的運行狀況。3.定時器線程運行棧設置爲512。

中斷服務程序使用堆棧介紹
這裏寫圖片描述

RL_TCPnet在RTXv4中使用的堆棧需求
這裏寫圖片描述

3.配置NetWork

RTX配置好後,接下來就是配置網絡。

NetConfig.c配置基本上不用改。“Local Host Name”可以改成自定義。作用可以不使用IP地址就行訪問。如:ping my_host 指令
這裏寫圖片描述

Net_Config_ETH_0.h的配置:改IP地址和網關,不開啓DHCP,將該線程棧設置1024。IPV6可以關掉,其它默認。
這裏寫圖片描述

Net_Config_UDP.h配置使用默認配置5個socket
這裏寫圖片描述

Net_Debug.c配置開啓相應的服務報警,該報警有3個級別,我選擇全部顯示,當然也可以只選擇errors 級別
這裏寫圖片描述

4.更改必要的代碼

現在大體上基本上配置完了,接下來配置一下復位腳,向udp_socket.c添加代碼。注意stdio需要初始化,外部聲明stdout_init(),然後在main函數進行初始化。

#include "rl_net.h"
#include "GPIO_STM32F10x.h"//需要手動添加
#include <stdio.h>  //需要手動添加

int32_t udp_sock;                       // UDP socket handle

extern int stdout_init (void);//需要手動添加
void send_udp_data (void);


static void delay_ms (int ms) {
  ms *= (SystemCoreClock/10000);
  while (ms--) { __nop(); __nop(); __nop(); __nop(); __nop(); __nop(); }
} 

void GPIO_Configuration(void)
{
    GPIO_InitTypeDef GPIO_InitStructure;

    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);

    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_Init(GPIOA,&GPIO_InitStructure);
}

void PHY_Reset(void)
{
    GPIO_ResetBits(GPIOA,GPIO_Pin_6);
    delay_ms(100);
    GPIO_SetBits(GPIOA,GPIO_Pin_6);
}

更改一下例子代碼,這個例子代碼的作用是本地UDP接收到0x01 0xAA指令就向目標UDP回顯數據。目標IP和端口是192.168.1.220:77,當然這可以自己隨意改動

// Notify the user application about UDP socket events.
uint32_t udp_cb_func (int32_t socket, const  NET_ADDR *addr, const uint8_t *buf, uint32_t len) {

  // Data received
  if ((buf[0] == 0x01) && (len == 2)) {
    // Switch LEDs on and off
    // LED_out (buf[1]);
        send_udp_data();
  }
  return (0);
}

// Send UDP data to destination client.
void send_udp_data (void) {

  if (udp_sock > 0) {
    // IPv4 address: 192.168.0.1
    NET_ADDR addr = { NET_ADDR_IP4, 77, 192, 168, 1, 220 };//可以根據自己的IP地址來
    // IPv6 address: [fe80::1c30:6cff:fea2:455e]
//  NET_ADDR addr = { NET_ADDR_IP6, 2000,
//                    0xfe, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
//                    0x1c, 0x30, 0x6c, 0xff, 0xfe, 0xa2, 0x45, 0x5e };
    uint8_t *sendbuf;

    sendbuf = netUDP_GetBuffer (2);
    sendbuf[0] = 0x01;
    sendbuf[1] = 0xAA;

    netUDP_Send (udp_sock, &addr, sendbuf, 2);
  }
}

主函數添加復位引腳初始化代碼

int main (void) {

    stdout_init();
    GPIO_Configuration();
    PHY_Reset();
    printf("PHY_RESET!\r\n");
    netInitialize ();

  // Initialize UDP socket and open port 2000
  udp_sock = netUDP_GetSocket (udp_cb_func);
  if (udp_sock > 0) {
    netUDP_Open (udp_sock, 2000);
  }
}

調試

編譯一下沒有錯誤,配置一下工程,生成Hex文件就可以測試啦!
這裏寫圖片描述

進入Debug調試模式,打開線程窗口可以看到系統創建的2個線程。如果使能其它服務,將會創建其它線程,對應的RTX的Number of Threads的相關配置要更改設置。
這裏寫圖片描述

連接好串口,查看串口調試助手打印的信息,可以很層次的看見系統運行的情況。可以很清晰的看到,數據通信是按模型層次來一步步傳遞的。
這裏寫圖片描述

打開網絡調試助手,設置本地IP和遠程目標IP。發送數據,就可以看到數據回顯,表示通信成功
這裏寫圖片描述

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章