FreeRTOS+LWIP+STM32F CUBEMX心得
2019-07-24 来源:eefocus
近段时间有个项目,需要用到操作系统。之前用过ucos,但是经过多方考虑后,还是决定使用Freerots。
项目需要用到以太网,处理器决定使用STM32F。ST做得还是不错的,STM32CubeMX解决了很多底层的问题,但是因为之前我用的基本库,没有用到HAL库,所以在使用HAL库的时候也遇到了不少问题,还好都一一化解。唯一最大的问题是LWIP,之前用的1.4.1版本的,前后台系统,用起来很顺畅,也没出现问题。而STM32CubeMX只支持2.0的,那就用2.0的呗。结果出现了很多问题,例如死机,网络中断等等。先总结如下:
1. 第一次使用Freertos的话,因为对该系统不是很熟,所以,务必使用串口打印系统所有任务的信息,这样子对所有任务一目了然,容易发现问题。一开始我没去做这件事情,有个TCP端口的任务总是在跑了一两天后出问题,然后一头转到LWIP协议栈是找问题,结果浪费了很多时间,也没能解决。最后把任务打印出来后,发现任务异常,堆栈不够,调整好堆栈就解决了,很冤。
TaskName Status Priority Availiable TaskId
Sts_Task R 3 178 6
IDLE R 0 106 19
Beep_Task B 3 98 8
uartTask4 B 3 102 4
uartTask3 B 3 132 3
uartTask2 B 3 132 2
ADC_Task B 3 50 11
dido_Task B 3 98 10
LinkThr B 3 222 22
tcpip_thread B 3 878 20
KEY_Task B 3 100 7
Led_Task B 3 98 9
uartTask1 B 3 224 1
defaultTask B 3 174 5
httpd_Task S 3 248 12
Tcp5_Task S 3 244 18
Tcp2_Task S 3 196 15
Tcp1_Task S 3 72 14
EthIf S 3 288 21
Tcp4_Task S 3 204 17
Tcp3_Task S 3 238 16
Telnet_Task S 3 284 13
TaskName RunCounts CpuRate
Sts_Task 3898 1%
IDLE 353364 94%
tcpip_thread 739 <1%
uartTask4 1305 <1%
dido_Task 264 <1%
uartTask3 1272 <1%
uartTask2 1585 <1%
Beep_Task 43 <1%
KEY_Task 6 <1%
Led_Task 8 <1%
uartTask1 3 <1%
ADC_Task 6627 1%
LinkThr 66 <1%
defaultTask 3788 1%
Tcp5_Task 195 <1%
Tcp2_Task 84 <1%
Tcp1_Task 93 <1%
EthIf 249 <1%
Tcp4_Task 182 <1%
Tcp3_Task 196 <1%
Telnet_Task 0 <1%
httpd_Task 509 <1%
System Heap Available: 10880
2. LWIP2.0相对于1.0来讲,增加了很多功能,但是有些问题还是没有彻底解决,例如在某种阶段情况下,可能会卡在CLOSE_WAIT状态无法退出,导致占用端口,占用内存等。
3. 官方提供的例程,“udptcp_echo_server_netconn”,它只是一个例程,只能用于入门使用,毕竟NETCOMM写得不够完善,需要自己增加条件去做些维护,确保在异常、极端情况下不会导致端口无法通信。例如下方红色部分,如果端口不是正常关闭的话,对导致TCP内存得不到释放,久而久之内存就不够导致死机。
/*-----------------------------------------------------------------------------------*/
static void tcpecho_thread(void *arg)
{
struct netconn *conn, *newconn;
err_t err;
LWIP_UNUSED_ARG(arg);
/* Create a new connection identifier. */
conn = netconn_new(NETCONN_TCP);
if (conn!=NULL)
{
/* Bind connection to well known port number 7. */
err = netconn_bind(conn, NULL, 7);
if (err == ERR_OK)
{
/* Tell connection to go into listening mode. */
netconn_listen(conn);
while (1)
{
/* Grab new connection. */
newconn = netconn_accept(conn);
/* Process the new connection. */
if (newconn)
{
struct netbuf *buf;
void *data;
u16_t len;
while ((buf = netconn_recv(newconn)) != NULL)
{
do
{
netbuf_data(buf, &data, &len);
netconn_write(newconn, data, len, NETCONN_COPY);
}
while (netbuf_next(buf) >= 0);
netbuf_delete(buf);
}
/* Close connection and discard connection identifier. */
netconn_close(newconn); //调用该函数,如果客户端已经不存在的话,内存或端口将得不到释放
netconn_delete(newconn);
}
}
}
else
{
printf(' can not bind TCP netconn');
}
}
else
{
printf('can not create TCP netconn');
}
}