日韩黑丝制服一区视频播放|日韩欧美人妻丝袜视频在线观看|九九影院一级蜜桃|亚洲中文在线导航|青草草视频在线观看|婷婷五月色伊人网站|日本一区二区在线|国产AV一二三四区毛片|正在播放久草视频|亚洲色图精品一区

分享

Uip + Stm32移植問題總結

 細寒 2014-04-22

作者:Changing發(fā)表時間:07-26 21:37分類:電子相關3 Comments

uIP 由瑞典計算機科學學院(網絡嵌入式系統(tǒng)小組)的Adam Dunkels (http:///adam/uip/)開發(fā)。其源代碼由C 語言編寫,并完全公開,有了這個TCP/IP協(xié)議棧,讓嵌入式可以實現(xiàn)的功能更為豐富??梢宰鳛?a href="http://www./uip-webclient.html" target="_blank" style="color:#6D6D6D;-webkit-transition:color 0.3s linear, background-color 0.3s linear;">WebClient 向指定網站提交數據,可以作為WebServer作為網頁服務器,提供一個小型的動態(tài)頁面訪問功能。由于是開源的免費協(xié)議棧,據說Uip沒有考慮協(xié)議安全的問題。
首先介紹下移植的環(huán)境: stm32 + ENC28J60網絡模塊 
IMG_20100101_103506.jpg
Enc28j60是帶SPI 接口的獨立以太網控制器,可以用mcu控制spi來實現(xiàn)tcp/ip數據流的收發(fā),所以要先完成Enc28j60的驅動程序,再整合Uip。Uip是用標準的C語言實現(xiàn),所以移植Uip在51單片機和stm32上類似。
經過幾天的琢磨,已經將Uip的幾個示例穩(wěn)定運行。Uip中apps下的例子相互之間存在沖突,源程序中也有一些Error 要修改,我將Uip的文件結構做了一些調整。


Uip文件結構
先介紹下Uip下各個目錄文件的功能:
├─apps                               apps目錄 下為uip提供的一些應用示例
│  ├─dhcpc
│  ├─hello-world
│  ├─resolv
│  ├─smtp
│  ├─telnetd
│  ├─webclient
│  └─webserver
│      └─httpd-fs
├─doc                              doc下放置的為說明文檔,程序中用不上  
│  └─html
├─lib                                lib下為內存塊管理函數源碼
├─uip                               uip下為uip和核心實現(xiàn)源碼 
└─unix                              unix環(huán)境里的uip應用例子,可以參照這個例子實現(xiàn)應用
Uip+stm32 MDK下工程建立
QQ截圖20120726204704.png
stm32的目錄結構建立可以參考 stm32 開發(fā)環(huán)境MDK+庫文件配置 
User 放置 stm32 SPI配置以及Uip配置和Enc28j60和Uip的接口函數
uip下為uip的核心實現(xiàn)源碼以及內存管理源碼(即為Uip/uip+Uip/lib)
dev下為Enc28j60的驅動函數源碼
apps為uip的各個示例應用源碼(Uip/apps下的文件)包括smtp,rsolve,dhcp,telnetd,以及webclient
webserver 的文件結構較為復雜,獨立一個文件夾
Uip移
Uip的移植可以參考uip的unix的文件結構。
1. Uip的數據通過網卡Enc28j60從物理層剝離,所以需要先配置Uip和Enc28j60的數據交互。這個部分在tapdev.c文件中:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
#include "uip.h"
#include "ENC28J60.h"
/*---------------------------------------------------------------------------*/
void
tapdev_init(unsigned char *my_mac)
{
    enc28j60Init(my_mac);
}
/*---------------------------------------------------------------------------*/
unsigned int
tapdev_read(void)
{
    return enc28j60PacketReceive(UIP_CONF_BUFFER_SIZE,uip_buf);
}
/*---------------------------------------------------------------------------*/
void
tapdev_send(void)
{
    enc28j60PacketSend(uip_len,uip_buf);
}
/*---------------------------------------------------------------------------*/
寫網卡驅動程序,與具體硬件相關。這一步比較費點時間,不過好在大部分網卡芯片的驅動程序都有代碼借鑒或移植。驅動需要提供三個函數,以Enc28j60 驅動為例。
tapdev_init():網卡初始化函數,初始化網卡的工作模式。
tapdev_read(void):讀包函數。將網卡收到的數據放入全局緩存區(qū)uip_buf 中,返回包的長度,賦給uip_len。
void tapdev_send(void):發(fā)包函數。將全局緩存區(qū)uip_buf 里的數據(長度放在uip_len 中)發(fā)送出去。
2.由于uIP 協(xié)議棧需要使用時鐘,為TCP 和ARP 的定時器服務。因此使用單片機的定時器或是stm32的滴答定時器用作時鐘,每20ms 讓計數tick_cnt 加1,這樣,25 次計數(0.5S)滿了后可以調用TCP 的定時處理程序。10S 后可以調用ARP 老化程序。uIP1.0 版本,增加了timer.c/timer.h,專門用來管理時鐘,修改clock-arch.c如下:
1
2
3
4
5
6
7
8
9
10
11
#include "clock-arch.h"
#include "stm32f10x.h"
extern __IO int32_t g_RunTime;
/*---------------------------------------------------------------------------*/
clock_time_t
clock_time(void)
{
    return g_RunTime;
}
/*---------------------------------------------------------------------------*/
使用stm32 滴答定時器中斷代碼:
User/stm32f10x_it.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
__IO int32_t g_RunTime = 0;
void SysTick_Handler(void)
{
    static uint8_t s_count = 0;
    if (++s_count >= 10)
    {
        s_count = 0;
        g_RunTime++;    /* 全局運行時間每10ms增1 */
        if (g_RunTime == 0x80000000)
        {
            g_RunTime = 0;
        }      
    }
}
3.uipopt.h/uip-conf.h 是配置文件,用來設置本地的IP 地址、網關地址、MAC 地址、全局緩沖區(qū)的大小、支持的最大連接數、偵聽數、ARP 表大小等??梢愿鶕枰渲?。
#define UIP_FIXEDADDR 1
決定uIP是否使用一個固定的IP地址。
如果uIP使用一個固定的IP地址,應該置位(set)這些uipopt.h中的選項。如果不的話,則應該使用宏uip_sethostaddr(),uip_setdraddr() 和 uip_setnetmask()。
#define UIP_PINGADDRCONF 0            Ping IP地址賦值。
#define UIP_FIXEDETHADDR 0            指明uIP ARP模塊是否在編譯時使用一個固定的以太網MAC地址。
#define UIP_TTL 255                           uIP發(fā)送的IP packets的IP TTL (time to live)。
#define UIP_REASSEMBLY 0                uIP支持IP packets的分片和重組。
#define UIP_REASS_MAXAGE 40          一個IP fragment在被丟棄之前可以在重組緩沖區(qū)中存在的最大時間。
#define UIP_UDP 0                              是否編譯UDP的開關。
#define UIP_ACTIVE_OPEN 1                決定是否支持uIP打開一個連接。
#define UIP_CONNS 10                        同時可以打開的TCP連接的最大數目。由于TCP連接是靜態(tài)分配的,減小這個數目將占用更少的RAM。每一個TCP連接需要大約30字節(jié)的內存。
#define UIP_LISTENPORTS 10                同時監(jiān)聽的TCP端口的最大數目。每一個TCP監(jiān)聽端口需要2個字節(jié)的內存。
#define UIP_RECEIVE_WINDOW 32768   建議的接收窗口的大小。如果應用程序處理到來的數據比較慢,那么應該設置的小一點(即,相對與uip_buf緩沖區(qū)的大小來說),相反如果應用程序處理數據很快,可以設置的大一點(32768字節(jié))。
#define UIP_URGDATA 1                       決定是否支持TCP urgent data notification。
#define UIP_RTO 3                                The initial retransmission timeout counted in timer pulses.不要改變
#define UIP_MAXRTX 8                         在中止連接之前,應該重發(fā)一個段的最大次數。不要改變
#define UIP_TCP_MSS (UIP_BUFSIZE – UIP_LLH_LEN – 40)             TCP段的最大長度。它不能大于UIP_BUFSIZE – UIP_LLH_LEN – 40.
#define UIP_TIME_WAIT_TIMEOUT 120    一個連接應該在TIME_WAIT狀態(tài)等待多長。不要改變
#define UIP_ARPTAB_SIZE 8                    ARP表的大小。如果本地網絡中有許多到這個uIP節(jié)點的連接,那么這個選項應該設置為一個比較大的值。
#define UIP_BUFSIZE 1500                        uIP packet緩沖區(qū)不能小于60字節(jié),但也不必大于1500字節(jié)。
#define UIP_STATISTICS 1                        決定是否支持統(tǒng)計數字。統(tǒng)計數字對調試很有幫助,并展示給用戶。
#define UIP_LOGGING 0                        輸出uIP登陸信息。
#define UIP_LLH_LEN 14                        鏈接層頭部長度。對于SLIP,應該設置成0。
uip-conf.h 中增加幾個主要結構體定義,不include任何應用
1
2
3
4
5
6
7
8
9
10
11
12
13
14
#define UIP_CONF_LOGGING         0                //logging off
typedef int uip_tcp_appstate_t;         //出錯可注釋
typedef int uip_udp_appstate_t;         //出錯可注釋
/*#include "smtp.h"*/
/*#include "hello-world.h"*/
/*#include "telnetd.h"*/
/*#include "webserver.h"*/
/*#include "dhcpc.h"*/
/*#include "resolv.h"*/
/*#include "webclient.h"*/
#include "app_call.h"                    //加入一個Uip的數據接口文件
uIP 在接受到底層傳來的數據包后,調用UIP_APPCALL( ),將數據送到上層應用程序處理。
User/app_call.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
#include "stm32f10x.h"
#ifndef UIP_APPCALL
    #define UIP_APPCALL                 Uip_Appcall
#endif
#ifndef UIP_UDP_APPCALL
    #define UIP_UDP_APPCALL             Udp_Appcall
#endif
void Uip_Appcall(void);
void Udp_Appcall(void);
void Uip_Appcall(void)
{
     
}
void Udp_Appcall(void)
{
     
}
4.加入uIP 的的主循環(huán)代碼架構
User/main.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
#include "stm32f10x.h"
#include "stdio.h"
#include "string.h"
#include "uip.h"
#include "uip_arp.h"
#include "tapdev.h"
#include "timer.h"
#include "ENC28J60.h"
#include "SPI.h"
#define  PRINTF_ON  1
#define BUF ((struct uip_eth_hdr *)&uip_buf[0])
#ifndef NULL
#define NULL (void *)0
#endif /* NULL */
static unsigned char mymac[6] = {0x04,0x02,0x35,0x00,0x00,0x01};
void RCC_Configuration(void);
void GPIO_Configuration(void);
void USART_Configuration(void);
int main(void)
{
    int i;
    uip_ipaddr_t ipaddr;
    struct timer periodic_timer, arp_timer;
    RCC_Configuration();
    GPIO_Configuration();
    USART_Configuration();
    SPInet_Init();
    timer_set(&periodic_timer, CLOCK_SECOND / 2);
    timer_set(&arp_timer, CLOCK_SECOND * 10);
    SysTick_Config(72000);          //配置滴答計時器
    //以太網控制器驅動初始化
    tapdev_init(mymac);
   
    //Uip 協(xié)議棧初始化
    uip_init();
    uip_ipaddr(ipaddr, 192, 168, 1, 15);     //配置Ip
    uip_sethostaddr(ipaddr);
    uip_ipaddr(ipaddr, 192, 168, 1, 1);     //配置網關
    uip_setdraddr(ipaddr);
    uip_ipaddr(ipaddr, 255, 255, 255, 0);   //配置子網掩碼
    uip_setnetmask(ipaddr);
    while(1){
   
        uip_len = tapdev_read();                                //從網卡讀取數據
         
        if(uip_len > 0)
        {                                                       //如果數據存在則按協(xié)議處理
            if(BUF->type == htons(UIP_ETHTYPE_IP)) {         //如果收到的是IP數據,調用uip_input()處理
                uip_arp_ipin();                                    
                uip_input();
                /* If the above function invocation resulted in data that
                   should be sent out on the network, the global variable uip_len is set to a value > 0. */
                if(uip_len > 0)
                {
                  uip_arp_out();
                  tapdev_send();
                }
            }else if(BUF->type == htons(UIP_ETHTYPE_ARP)){    //如果收到的是ARP數據,調用uip_arp_arpin處理
                uip_arp_arpin();
                /* If the above function invocation resulted in data that
                   should be sent out on the network, the global variable uip_len is set to a value > 0. */
                if(uip_len > 0)
                {
                  tapdev_send();
                }
            }
     
        }else if(timer_expired(&periodic_timer)){           //查看0.5s是否到了,調用uip_periodic處理TCP超時程序
              timer_reset(&periodic_timer);
              for(i = 0; i < UIP_CONNS; i++) {
     
                    uip_periodic(i);
     
                    /* If the above function invocation resulted in data that
                       should be sent out on the network, the global variable uip_len is set to a value > 0. */
     
                    if(uip_len > 0)
                    {
                      uip_arp_out();
                      tapdev_send();
                    }
              }
                                 
              for(i = 0; i < UIP_UDP_CONNS; i++)
              {
     
                    uip_udp_periodic(i);                                //處理udp超時程序
     
                    /* If the above function invocation resulted in data that
                       should be sent out on the network, the global variable uip_len is set to a value > 0. */
     
                    if(uip_len > 0)
                    {
                      uip_arp_out();
                      tapdev_send();
                    }
              }
           
              /* Call the ARP timer function every 10 seconds. */            //10s到了就處理ARP
              if(timer_expired(&arp_timer))
              {
                    timer_reset(&arp_timer);
                    uip_arp_timer();
              }
        }
    }
}
/*******************************Stm32 Set***************************************/
void GPIO_Configuration(void)
{
    GPIO_InitTypeDef GPIO_InitStructure;                                                                                                                                                                                                                                                       
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;        
    GPIO_Init(GPIOA , &GPIO_InitStructure);
     
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;          
    GPIO_Init(GPIOA , &GPIO_InitStructure);
}
void RCC_Configuration(void)
{
    /* 定義枚舉類型變量 HSEStartUpStatus */
    ErrorStatus HSEStartUpStatus;
    /* 復位系統(tǒng)時鐘設置*/
    RCC_DeInit();
    /* 開啟HSE*/
    RCC_HSEConfig(RCC_HSE_ON);
    /* 等待HSE起振并穩(wěn)定*/
    HSEStartUpStatus = RCC_WaitForHSEStartUp();
    /* 判斷HSE起是否振成功,是則進入if()內部 */
    if(HSEStartUpStatus == SUCCESS)
    {
        /* 選擇HCLK(AHB)時鐘源為SYSCLK 1分頻 */
        RCC_HCLKConfig(RCC_SYSCLK_Div1);
        /* 選擇PCLK2時鐘源為 HCLK(AHB) 1分頻 */
        RCC_PCLK2Config(RCC_HCLK_Div1);
        /* 選擇PCLK1時鐘源為 HCLK(AHB) 2分頻 */
        RCC_PCLK1Config(RCC_HCLK_Div2);
        /* 設置FLASH延時周期數為2 */
        FLASH_SetLatency(FLASH_Latency_2);
        /* 使能FLASH預取緩存 */
        FLASH_PrefetchBufferCmd(FLASH_PrefetchBuffer_Enable);
        /* 選擇鎖相環(huán)(PLL)時鐘源為HSE 1分頻,倍頻數為9,則PLL輸出頻率為 8MHz * 9 = 72MHz */
        RCC_PLLConfig(RCC_PLLSource_HSE_Div1, RCC_PLLMul_9);
        /* 使能PLL */
        RCC_PLLCmd(ENABLE);
        /* 等待PLL輸出穩(wěn)定 */
        while(RCC_GetFlagStatus(RCC_FLAG_PLLRDY) == RESET);
        /* 選擇SYSCLK時鐘源為PLL */
        RCC_SYSCLKConfig(RCC_SYSCLKSource_PLLCLK);
        /* 等待PLL成為SYSCLK時鐘源 */
        while(RCC_GetSYSCLKSource() != 0x08);
    }
    /* 打開APB2總線上的GPIOA時鐘*/
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA|RCC_APB2Periph_USART1, ENABLE);
         
}
  
void USART_Configuration(void)
{
    USART_InitTypeDef USART_InitStructure;
    USART_ClockInitTypeDef USART_ClockInitStructure;
    USART_ClockInitStructure.USART_Clock = USART_Clock_Disable;
    USART_ClockInitStructure.USART_CPOL = USART_CPOL_Low;
    USART_ClockInitStructure.USART_CPHA = USART_CPHA_2Edge;                                                                                                                                                     
    USART_ClockInitStructure.USART_LastBit = USART_LastBit_Disable;
    USART_ClockInit(USART1 , &USART_ClockInitStructure);
    USART_InitStructure.USART_BaudRate = 9600;
    USART_InitStructure.USART_WordLength = USART_WordLength_8b;
    USART_InitStructure.USART_StopBits = USART_StopBits_1;
    USART_InitStructure.USART_Parity = USART_Parity_No;
    USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
    USART_InitStructure.USART_Mode = USART_Mode_Rx|USART_Mode_Tx;
    USART_Init(USART1,&USART_InitStructure);
    USART_Cmd(USART1,ENABLE);
}
#if  PRINTF_ON
int fputc(int ch,FILE *f)
{
    USART_SendData(USART1,(u8) ch);
    while(USART_GetFlagStatus(USART1,USART_FLAG_TC) == RESET);
    return ch;
}
#endif
5.解決編譯過程中的錯誤。歸總如下:
  • Uip/uip-split.c  注釋所有的 tcpip_output()函數  消除uip_fw_output()函數的注釋
  • Uip/memb.c 中 memb_free()函數 返回值 return -1 改為 return 1
  • Apps/resolv.c 中resolv_conf() 中 
                 //resolv_conn = uip_udp_new(dnsserver, HTONS(53));
                  resolv_conn = uip_udp_new((uip_ipaddr_t*)dnsserver, HTONS(53));
解決完所有問題后,編譯成功后下載到stm32,ping 測試。。
QQ截圖20120726201101.png

    本站是提供個人知識管理的網絡存儲空間,所有內容均由用戶發(fā)布,不代表本站觀點。請注意甄別內容中的聯(lián)系方式、誘導購買等信息,謹防詐騙。如發(fā)現(xiàn)有害或侵權內容,請點擊一鍵舉報。
    轉藏 分享 獻花(0

    0條評論

    發(fā)表

    請遵守用戶 評論公約

    類似文章 更多