STM32 F49 当客户端 LWIP LWIP充当客户端,传送AD采集的数据,数据量比较大,主要使用了tcp_write 和 tcp_output 方法,主要问题有两个

1)tcpwrite 方法经常返回 ERR_MEM
2)刚开始速度还可以,后面速度就很慢了

调试心得:
其实就是一句话 主程序和以太网中断程序中对PCB->unsent 之类的处理出现了问题,tcp_write 不是没有临界保护,导致中断和主程序直接出现了共同操作
((pcb)->snd_buf)
((pcb)->snd_queuelen)
的问题,导致内存泄漏,越运行越慢

中断处理程序为

void ETH_IRQHandler(void)
{

//LwIP_Pkt_Handle();

while (ETH_CheckFrameReceived() != 0) { //检测是否收到数据包
    LwIP_Pkt_Handle();
   //tcp_enqueue(struct tcp_pcb * pcb,u8_t flags)
}


ETH_DMAClearITPendingBit(ETH_DMA_IT_R);
ETH_DMAClearITPendingBit(ETH_DMA_IT_NIS);

}
其中 LwIP_Pkt_Handle 根据服务器返回的ACK 减少((pcb)->snd_buf)
((pcb)->snd_queuelen)的数量,而主程序又通过tcp_write 增加数量,两者相互打架,导致内存的泄漏,越运行越慢。
我的设备刚开始可以到达4M/s 最后运行最多20K/S左右,最后导致崩溃。所以我建议在主程序调用tcp_write 和 tcp_output 首先把网络中断停止,运行完成后在开始中断
void Close_ethirq ()
{

 NVIC_DisableIRQ(ETH_IRQn);

}
void open_ethirq ()
{

NVIC_EnableIRQ(ETH_IRQn);
}

Close_ethirq();
wr_err = tcp_write(Globe_TCP_client_send, data, len, TCP_WRITE_FLAG_COPY);
open_ethirq();
当然 tcp_output 也同理

之前判断是否能写入,可以参照一下程序

int CheckSmallTCPData (u8 *data, int len)
{
u32 tcp_sndbufint;
u32 tcp_sndqueuelenint;
u32 SND_QUEUELEN;
u32 UU =0;
SND_QUEUELEN=TCP_SND_QUEUELEN /2;
while (1) {
tcp_sndbufint=tcp_sndbuf(Globe_TCP_client_send);
tcp_sndqueuelenint=tcp_sndqueuelen(Globe_TCP_client_send);
if (tcp_sndqueuelenint> SND_QUEUELEN )

{
if (! (isConnected()==1))
{
ErrorAdd(ERROR_TCP,1);
return -1 ;
}
delay_ms(SleepTime);
UU = UU + 1;
if (UU > TCPMAX) {
return 0 ;
}
}
else
{
return 1;
}
}
}

最后一点心得LWIp 虽然是轻量级协议,并不代表速度慢,可以适当的调整一下
#define TCP_SND_BUF
#define TCP_SND_QUEUELEN
其实也不需要过大,大了也没必要,基本在运行的时候也用不上

我目前的速度是4M ,以前最多能够保证4M的速度 10分钟,现在测试已经不知道多久了 仍然是4M ,可能跟我的主服务器有关

更多推荐