完善资料让更多小伙伴认识你,还能领取20积分哦, 立即完善>
做一个,串口收到数据然后通过tcp主动发送出去的东西,但是目前遇到以下问题,当tcp初始化后连接也建立好了,此时如果每即使毫秒就向串口扔一组数据,串口收到数据后主动发送tcp出去,但是如果发送频率很快(感觉100ms内的话)发个一段时间,程序就会死,debug了一下,死在了tcp_write_check函数里的断言这里
if (pcb-》snd_queuelen != 0) { LWIP_ASSERT(“tcp_write: pbufs on queue =》 at least one queue non-empty”, pcb-》unacked != NULL || pcb-》unsent != NULL); } else { LWIP_ASSERT(“tcp_write: no pbufs on queue =》 both queues empty”, pcb-》unacked == NULL && pcb-》unsent == NULL); } 求助 主动发送tcp 频率很快的情况下怎么样才能不死。。。 ps:如果是客户端主动发送tcp给我,我在tcp收的回调函数里再调用tcp_write,把数据丢回去,无论多快,都没问题。。。 方法:1 1,增加TCP发送缓冲区大小。 2,向串口扔数据的速度超过了TCP主动发的速度,如果有可能应该握手控制一下。这个还可能与客户端接收处理速度不够有关,应该排查一下。 其他的内容: //***************************************************************************** // ---------- Memory options ---------- #define MEM_ALIGNMENT 4 // default is 1 #define MEM_SIZE (22 * 1024) // default is 1600, was 16K //***************************************************************************** // ---------- Internal Memory Pool Sizes ---------- #define MEMP_NUM_PBUF 24 // Default 16, was 16 #define MEMP_NUM_TCP_PCB 1 // Default 5, was 12 //***************************************************************************** // ---------- TCP options ---------- LWIP_TCP 1 #define TCP_WND 4096 // default is 2048 #define TCP_MSS 1024 // default is 128 #define TCP_SND_BUF (16 * TCP_MSS// default is 256, was 6 * //#define TCP_SND_QUEUELEN (4 * (TCP_SND_BUF/TCP_MSS)) 前段时间一直在调试lwip协议栈的问题,在stm32F107上实现一个C/S 架构的通信程序。项目初期的时候设计的是B/S架构的控制,然后在使用过程中发现了些限制,因为芯片自身的RAM有限,所以跑B/S的server端略显压力,为了处理类似动态网页内容,开辟一个5K的缓冲区,然后一次tcp_write就可以将内容发送给浏览器了,当然网页内容也是比较简单,考虑到后续可能会有更多的数据处理,故决定开发一个C/S架构的控制。 上位机client倒是没什么太多可说的,自己封装下基本的winsock操作。考虑到用TCP协议传输简单地封装了下数据封包和拆包的协议,然后MFC作为图形界面。在stm32端主要采用lwip的RAW API,然后利用callback的方式处理接收上位机命令、数据后的处理,初始化服务器的代码如下: void Server_init(void) { struct tcp_pcb *pcb; pcb = tcp_new(); // 动态创建一个pcb tcp_bind(pcb, IP_ADDR_ANY, 8082); // 绑定端口8082 pcb = tcp_listen(pcb); // 开始监听 tcp_accept(pcb, Server_accept); // accept成功时的回调函数 } 然后在Server_accept中也主要是初始化一些回调函数, static err_t Server_accept(void *arg, struct tcp_pcb *pcb, err_t err) { tcp_err(pcb, Server_conn_err); // 错误时的回调函数 tcp_recv(pcb, Server_recv); // 接收到数据后的回调函数 tcp_sent(pcb, Server_sent); // tcp_write数据成功发送后的回调函数 gRemoteIp = pcb-》remote_ip; // 获取远程客户端的地址 return ERR_OK; } 最重要的函数就是Server_recv()了,在这个函数中,根据客户端不同的命令,然后处理相应的数据发送给客户端,但这时问题就暴露出来了。截取一段发送数据的简化代码: for(i = 0; i 《 WMFlag.WM_Record_Num; ++i) { SendCharBuff(pcb, WMTempData, strlen(WMTempData), PT_TEXT); } 其中SendCharBuff主要是调用tcp_write函数,这个当WM_Record_Num这个数值很大时,客户端总是接收不全,后来经过反复地进行实验发现,然来是tcp_write这个函数在循环到12次的时候会返回ERR_MEM的内存错误,这个问题让我百思不得其解,然后通过网上的一些资料,很多人说是lwip协议栈有BUG,然后我姑且相信了这个结论,但是有BUG也得继续调呀。于是便想到了winsock里面有个WSAGetLastError()这个函数,但是lwip里面却没有,网上找了找说可以开启lwip的调试功能,于是乎就开始设置lwip的调试功能了。 关于开启LWIP的调试功能主要的设置如下: 1、 在src/include/lwip目录中找到debug.h这个文件,然后在里面添加如下代码 // Add By 风格独特 2012-06-28 // 增加串口调试功能 // 声明外部的USART2_Printf串口输出调试信息函数 extern void USART2_Printf(const char *format, 。..); // 定义格式化内容的宏 // PS 通过调试这个宏发现了以前不知道的一个小知识,那就是字符串可以这样表示 // “aaaa” “bbb” == “aaaabbb” #define U8_F “c” #define S8_F “c” #define X8_F “x” #define U16_F “u” #define S16_F “d” #define X16_F “x” #define U32_F “u” #define S32_F “d” #define X32_F “x” // 设置调试的宏,注释这个宏可以关闭调试功能 #define LWIP_DEBUG #define LWIP_PLATFORM_DIAG(x) USART2_Printf x // Add End 2、 在src/include/lwip目录中找到opt.h这个文件,然后找到如下代码 #ifndef TCP_OUTPUT_DEBUG #define TCP_OUTPUT_DEBUG LWIP_DBG_OFF #endif 其中将LWIP_DBG_OFF改为LWIP_DBG_ON,即开启了TCP_OUT_DEBUG的调试,当然如果想开启其他的调试输出,就可以将相应的地方改为LWIP_DBG_ON即可。 3、 实现USART2_Printf这个函数,代码如下 void USART2_Printf(const char *format,。..) { int iOutLen; char buf[256]; va_list arg_ptr; va_start(arg_ptr, format); iOutLen = vsprintf(buf, format, arg_ptr); va_end(arg_ptr); USART_SendStr(buf, iOutLen); } 开启调试后得到如下的调试输出信息: tcp_enqueue: 12 (after enqueued) tcp_write(pcb=20009c1c, data=08003a24, len=6, apiflags=1) tcp_enqueue(pcb=20009c1c, arg=08003a24, len=6, flags=0, apiflags=1) tcp_enqueue: queuelen: 12 tcp_enqueue: too long queue 12 (max 12) tcp_output_segment: 6848:6920 State: ESTABLISHED 可以看出在tcp_enqueue第12次的时候输出了too long queue 12 (max 12),超出最大的列队次数,于是在工程中搜索too long queue这句话,在tcp_out.c文件中找到了如下代码: if ((queuelen 》 TCP_SND_QUEUELEN) || (queuelen 》 TCP_SNDQUEUELEN_OVERFLOW)) { LWIP_DEBUGF(TCP_OUTPUT_DEBUG | 2, (“tcp_enqueue: queue too long %”U16_F“ (%”U16_F“)n”, queuelen, TCP_SND_QUEUELEN)); goto memerr; } 然后发现TCP_SND_QUEUELEN的值为12,跟到TCP_SND_QUEUELEN的定义代码: #define TCP_SND_BUF (2*TCP_MSS) // 发送缓冲区,为两个MSS的大小 // 此参数限制了tcp_write的次数,系数默认为6, 改为3000 #define TCP_SND_QUEUELEN (3000 * TCP_SND_BUF)/TCP_MSS 于是将那个默认的系数由6改为3000,再次测试时发现可以连续tcp_write超过12次了,于是解决了tcp_write的连续多次调用后失败的问题。 最后补充一下tcp_write这个函数的最后一个参数的说明,该函数的声明如下 err_t tcp_write(struct tcp_pcb *pcb, void *dataptr, u16_t len, u8_t copy); 其中第四个参数是一个copy参数,当为0时为不拷贝数据,也就是在dataptr所指的缓冲区里面发送数据,因为调用tcp_write成功后数据并不会立即发送,所以要确保dataptr所指的缓冲区内容保持不变,如果调用tcp_write成功后,再改变dataptr缓冲区可能就会和预期发送的数据不相符,当时我也碰到过这个问题,后来将最后的参数改为1,为1时即拷贝缓冲区内容,当执行tcp_write时,会将dataptr所指向的缓冲区内容先拷贝到发送的缓冲区中,这样的话执行tcp_write之后再改变dataptr所指的内容是不影响数据的正确发送的。 其他:tcp_receive出错的问题。 LWIP+FREERTOS在STM32F107上运行,在TCP通信发送数据,一段时间之后出现断言死循环。 报错:Assertion tcp_recive:valid queue length failed at line 957 in F:。..。..。..tcp_in.c 请问下,上面情况是不是opt.h里面配置的问题呢? 在公司里面,通过远程上网的,无法上传东西。 1.上面的问题应该是接受函数里面处理的问题,在中断触发的接收函数里面判断是否有数据,用的if(ETH_GetRxPKtSize()!=0),改为while后正常了。 2.现在碰到一个新的问题:在连接一段时间之后(这个时间不定,有时1个小时以内,有时候几天时间才出现),无法进入以太网的中断。还在调试中。 其他:STM32F407+lwip的速度提升问 1、尽量不要使用delay延时函数!应用程序中的延时函数对于速度的影响很大的。 2、尽量减少数据拷贝,数据拷贝也会浪费大量的时间。 3、就像别人说的,将缓存开大一点,你如果使用了ST的官方以太网库的话,有下面几个地方需要改打一点。 1 2 3 //STM32内部MAC发送和接收BUF个数 #define ETH_RXBUFNB 10 #define ETH_TXBUFNB 10 #define MEM_SIZE 20000 //内存堆heap大小 #define MEMP_NUM_PBUF 30 //MEMP_NUM_PBUF:memp结构的pbuf数量,如果应用从ROM或者静态存储区发送大量数据时 //这个值应该设置大一点 #define MEMP_NUM_TCP_SEG 300 //MEMP_NUM_TCP_SEG:最多同时在队列中的TCP段数量 #define PBUF_POOL_SIZE 30 //PBUF_POOL_SIZE:pbuf内存池个数 #define PBUF_POOL_BUFSIZE 512 //PBUF_POOL_BUFSIZE:每个pbuf内存池大小 #define TCP_MSS (1500 - 40) //最大TCP分段,TCP_MSS = (MTU - IP报头大小 - TCP报头大小 #define TCP_SND_BUF (25*TCP_MSS) //TCP发送缓冲区大小(bytes)。 #define TCP_SND_QUEUELEN (10* TCP_SND_BUF/TCP_MSS) //TCP_SND_QUEUELEN: TCP发送缓冲区大小(pbuf)。这个值最 //小为(2 * TCP_SND_BUF/TCP_MSS) #define TCP_WND (8*TCP_MSS) //TCP发送窗口 注意:TCP_WND是发送窗口,这个值对于LWIP的速度影响非常大。 |
|
|
|
只有小组成员才能发言,加入小组>>
调试STM32H750的FMC总线读写PSRAM遇到的问题求解?
1752 浏览 1 评论
X-NUCLEO-IHM08M1板文档中输出电流为15Arms,15Arms是怎么得出来的呢?
1611 浏览 1 评论
1052 浏览 2 评论
STM32F030F4 HSI时钟温度测试过不去是怎么回事?
721 浏览 2 评论
ST25R3916能否对ISO15693的标签芯片进行分区域写密码?
1666 浏览 2 评论
1926浏览 9评论
STM32仿真器是选择ST-LINK还是选择J-LINK?各有什么优势啊?
711浏览 4评论
STM32F0_TIM2输出pwm2后OLED变暗或者系统重启是怎么回事?
560浏览 3评论
584浏览 3评论
stm32cubemx生成mdk-arm v4项目文件无法打开是什么原因导致的?
544浏览 3评论
小黑屋| 手机版| Archiver| 电子发烧友 ( 湘ICP备2023018690号 )
GMT+8, 2024-12-18 20:37 , Processed in 0.585839 second(s), Total 48, Slave 41 queries .
Powered by 电子发烧友网
© 2015 bbs.elecfans.com
关注我们的微信
下载发烧友APP
电子发烧友观察
版权所有 © 湖南华秋数字科技有限公司
电子发烧友 (电路图) 湘公网安备 43011202000918 号 电信与信息服务业务经营许可证:合字B2-20210191 工商网监 湘ICP备2023018690号