FreeRTOS+LWIP+STM32F CUBEMX心得
近段时间有个项目,需要用到操作系统。之前用过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"); } }
