生活随笔
收集整理的這篇文章主要介紹了
LWIP:RTThread + LWIP
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
1. 序言
- 今天跟大家簡單分享 LWIP + RTThread 的移植注意事項,記得以前剛接觸 LWIP 那會,是跟著野火的教程一起走,而大部分 LWIP 移植教程都是以 freeRTOS 為主,本著支持 RTThread 的想法,在當時就想著移植 LWIP 到 RTThread 上,沒想到翻車了,sockets 連接總是連接不上而 netconn 就可以,后面就放棄了…………,直到現在,把它撿起來!
- 本文僅簡單描述其中需要注意的事項,需要對 RTThread 和 LWIP 有一定的了解,詳細的移植教程無法做到一一細說,還是建議大家去看看野火的教程《LwIP 應用開發實戰指南》和 《RT-Thread 內核實現與應用開發實戰指南》,都是不錯的入門書籍(本文也引用了一些資料)。
- 基于STM32 + RTThread Nano 3.1.3 + LWIP 2.1.3,當然直接使用全功能的RT-Thread IoT 就可以直接擁有豐富的網絡協議,但是對于一些僅需要簡單的TCP/UDP應用,也是一個不錯的移植選擇方案。
2. 實現
實現phy的底層驅動文件。移植RTThread Nano 到工程。移植LWIP文件到工程,使用STM32CubeMX勾選LWIP協議,參照生成的工程實現ethernetif.c文件。移植sys_arch.c文件(非常重要)。
#include <lwip/stats.h>
#include <lwip/debug.h>
#include <string.h>
#include "lwip/def.h"
#include "lwip/sys.h"
#include <lwip/opt.h>
#include <lwip/arch.h>
#include "tcpip.h"
#include "rtthread.h"uint32_t mbox_count
=0; err_t
sys_mbox_new(sys_mbox_t
*mbox
, int size
)
{char s1
[]="RT_MBX";char s2
=mbox_count
+'0';char *s3
=s1
+s2
;mbox_count
++; *mbox
= rt_mb_create(s3
,(rt_ubase_t
)size
,RT_IPC_FLAG_PRIO
);if(*mbox
== NULL) {return ERR_MEM
;}return ERR_OK
;
}void sys_mbox_free(sys_mbox_t
*mbox
)
{rt_mb_delete(*mbox
);
}void sys_mbox_post(sys_mbox_t
*mbox
, void *msg
)
{rt_base_t ret
;while(ERR_OK
!= rt_mb_send_wait(*mbox
, (rt_uint32_t
)msg
, RT_WAITING_FOREVER
));
}err_t
sys_mbox_trypost(sys_mbox_t
*mbox
, void *msg
)
{rt_base_t ret
;ret
= rt_mb_send(*mbox
, (rt_uint32_t
)msg
);if (ret
== RT_EOK
) {return ERR_OK
;} else {return ERR_MEM
;}
}err_t
sys_mbox_trypost_fromisr(sys_mbox_t
*mbox
, void *msg
)
{return sys_mbox_trypost(mbox
, msg
);
}u32_t
sys_arch_mbox_fetch(sys_mbox_t
*mbox
, void **msg
, u32_t timeout_ms
)
{rt_base_t ret
;void *msg_dummy
;if (!msg
) {msg
= &msg_dummy
;}if (!timeout_ms
) {ret
= rt_mb_recv(*mbox
, (rt_uint32_t
*)msg
, RT_WAITING_FOREVER
);} else {rt_tick_t timeout_ticks
= timeout_ms
;ret
= rt_mb_recv(*mbox
, (rt_uint32_t
*)msg
, timeout_ticks
);if (ret
!= RT_EOK
) {*msg
= NULL;return SYS_ARCH_TIMEOUT
;}}return 1;
}u32_t
sys_arch_mbox_tryfetch(sys_mbox_t
*mbox
, void **msg
)
{rt_base_t ret
;void *msg_dummy
;if (!msg
) {msg
= &msg_dummy
;}ret
= rt_mb_recv(*mbox
, (rt_uint32_t
*)&(*msg
), 0);if (ret
!= RT_EOK
) {*msg
= NULL;return SYS_MBOX_EMPTY
;}return 1;
}int sys_mbox_valid(sys_mbox_t
*mbox
)
{if (*mbox
== NULL)return 0;elsereturn 1;
}void sys_mbox_set_invalid(sys_mbox_t
*mbox
)
{*mbox
= NULL;
}uint32_t sem_count
=0; err_t
sys_sem_new(sys_sem_t
*sem
, u8_t initial_count
)
{char s1
[]="RT_SEM";char s2
=sem_count
+'0';char *s3
=s1
+s2
;sem_count
++;*sem
= rt_sem_create(s3
,1,RT_IPC_FLAG_PRIO
);if(*sem
== NULL) {return ERR_MEM
;}if(initial_count
== 0) {rt_sem_trytake(*sem
);}else if(initial_count
== 1) {rt_base_t ret
= rt_sem_release(*sem
);}return ERR_OK
;
}u32_t
sys_arch_sem_wait(sys_sem_t
*sem
, u32_t timeout_ms
)
{rt_base_t ret
;if(!timeout_ms
) {ret
= rt_sem_take(*sem
, RT_WAITING_FOREVER
);} else {rt_tick_t timeout_ticks
= timeout_ms
;ret
= rt_sem_take(*sem
, timeout_ticks
);if (ret
!= RT_EOK
) {return SYS_ARCH_TIMEOUT
;}}return 1;
}void sys_sem_signal(sys_sem_t
*sem
)
{rt_base_t ret
;ret
= rt_sem_release(*sem
);
}void sys_sem_free(sys_sem_t
*sem
)
{rt_sem_delete(*sem
);
}int sys_sem_valid(sys_sem_t
*sem
)
{if (*sem
== NULL)return 0;elsereturn 1;
}void sys_sem_set_invalid(sys_sem_t
*sem
)
{*sem
= NULL;
}#if LWIP_COMPAT_MUTEX == 0uint32_t mutex_count
=0; err_t
sys_mutex_new(sys_mutex_t
*mutex
)
{char s1
[]="RT_MUTEX";char s2
=mutex_count
+'0';char *s3
=s1
+s2
;mutex_count
++;*mutex
= rt_mutex_create(s3
,RT_IPC_FLAG_PRIO
);if(*mutex
== NULL) {return ERR_MEM
;}return ERR_OK
;
}void sys_mutex_free(sys_mutex_t
*mutex
)
{rt_mutex_delete(*mutex
);
}void sys_mutex_lock(sys_mutex_t
*mutex
)
{rt_base_t ret
;ret
= rt_mutex_take(*mutex
, RT_WAITING_FOREVER
);
}void sys_mutex_unlock(sys_mutex_t
*mutex
)
{rt_base_t ret
;ret
= rt_mutex_release(*mutex
);
}#endifsys_thread_t
sys_thread_new(const char *name
, lwip_thread_fn thread
, void *arg
, int stacksize
, int prio
)
{rt_base_t ret
;sys_thread_t lwip_thread
;size_t rtos_stacksize
;rtos_stacksize
= (size_t
)stacksize
;lwip_thread
= rt_thread_create(name
,thread
,arg
,rtos_stacksize
,prio
,50); rt_thread_startup(lwip_thread
);return lwip_thread
;
}
#if SYS_LIGHTWEIGHT_PROT == 1sys_mutex_t lwip_sys_mutex
; void sys_init(void)
{lwip_sys_mutex
= rt_mutex_create("RT_MUTEX_PRO",RT_IPC_FLAG_PRIO
);
}sys_prot_t
sys_arch_protect(void)
{rt_base_t ret
;ret
= rt_mutex_take(lwip_sys_mutex
, RT_WAITING_FOREVER
);return 1;
}void sys_arch_unprotect(sys_prot_t pval
)
{LWIP_UNUSED_ARG(pval
);rt_base_t ret
;ret
= rt_mutex_release(lwip_sys_mutex
);}
#endifu32_t
sys_now(void)
{return rt_tick_get();
}u32_t
sys_jiffies(void)
{return rt_tick_get();
}
由于RTThread線程啟動的特殊性,main函數是在一個線程里面被調用執行的,如果在main函數里面創建更高優先級的線程,就會馬上執行高優先級線程,且一般我們會把網口的處理接收ethernetif_input單獨作為一個線程來運行,通過ETH外設中斷發送信號量使接收線程ethernetif_input運行,因此,我們需要在初始化LWIP內核和網口的初始化時,禁止中斷和線程調度,避免LWIP內核未完成初始化時,ethernetif_input線程運行或發生中斷過程中使用了內核信號量,但內核并沒初始化出信號量,就會發生錯誤。
rt_base_t ret
=rt_hw_interrupt_disable();
.....
LAN8720_Init();
tcpip_init(NULL,NULL);
....
rt_hw_interrupt_enable(ret
);
一般使用的線程優先級,讓LWIP內核線程反應更快。
宏:SYS_LIGHTWEIGHT_PROT,開啟后并用互斥量實現,能夠保護內核在申請內存時安全。(sys_init初始化互斥量、sys_arch_protect申請互斥量、sys_arch_unprotect釋放互斥量)宏:LWIP_TCPIP_CORE_LOCKING,不開啟時用戶線程發送郵箱信息到tcpip線程,tcpip線程再來處理回調,如下圖,這增加了系統開銷(線程切換,從用戶線程切換到tcpip線程),若開啟后用戶線程會申請互斥量,保護用戶線程的運行,直接調用回調函數。建議開啟。
總結
以上是生活随笔為你收集整理的LWIP:RTThread + LWIP的全部內容,希望文章能夠幫你解決所遇到的問題。
如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。