|

楼主 |
发表于 2021-11-19 09:09:05
|
显示全部楼层
本帖最后由 szttg 于 2021-11-19 09:17 编辑
找到问题所在了。我这个LWIP是1.3.1的版本,在 http_send_data() 函数中处理SSI标签时,多次调用http_write()写入内容,http_write() 调用 tcp_write() 往发送缓冲区写入时, 由tcp_euqueue()函数放入队列,都要分配 一个pbuf进行链接,虽然 总体长度不超过MSS(Max segment size), 但链拉的pbuf数量达几十个之多。正是这么多的pbuf导致 low_level_output函数判断pbuf超出DMA发送描述符数量 ,没有发出这个数据包,导致数据包缺失。
下面是low_level_output 的常见写法,这种处理方式,要求pbuf链的数量不能超过发送描述符数量。一旦超过,就直接返回,不进行发送。
err_t low_level_output(struct netif *netif, struct pbuf *p)
{
uint32_t i=0;
struct pbuf *q;
err_t errval=ERR_OK;
ETH_BufferTypeDef Txbuffer[ETH_TX_DESC_CNT];
memset(Txbuffer, 0 , ETH_TX_DESC_CNT*sizeof(ETH_BufferTypeDef));
for(q=p;q!=NULL;q=q->next)
{
if(i>=ETH_TX_DESC_CNT) // 此句导致pbuf数量超出DMA发送描述符数量时直接返回
return ERR_IF;
Txbuffer.buffer=q->payload;
Txbuffer.len=q->len;
if(i>0)
{
Txbuffer[i-1].next=&Txbuffer;
}
if(q->next == NULL)
{
Txbuffer.next=NULL;
}
i++;
}
TxConfig.Length = p->tot_len;
TxConfig.TxBuffer=Txbuffer;
SCB_CleanInvalidateDCache(); //无效化并清除Dcache
errval = HAL_ETH_Transmit(D_Handle,&TxConfig, 20);
if(HAL_OK != errval )
{
printf("low_level_output error: %d\r\n",errval);
}
return errval;
}
下面是改进后的写法,把所有的pbuf都拷贝进一个发送缓冲区内,这样就不会有任何问题了。uint8_t Tx_Buff[ETH_RX_BUFFER_SIZE]; // 发送缓冲区
static err_t low_level_output(struct netif *netif, struct pbuf *p)
{
u16 total_len = 0;
struct pbuf *q = p;
err_t errval=ERR_OK;
ETH_BufferTypeDef Txbuffer = {Tx_Buff, 0, 0};
for (; q != NULL; q = q->next)
{
memcpy(&Tx_Buff[total_len], q->payload, q->len);
total_len += q->len;
}
Txbuffer.len = total_len;
TxConfig.Length = total_len;
TxConfig.TxBuffer = &Txbuffer;
SCB_CleanInvalidateDCache(); //无效化并清除Dcache
errval = HAL_ETH_Transmit(D_Handle,&TxConfig, 20);
if(HAL_OK != errval )
{
printf("low_level_output error: %d\r\n",errval);
}
return errval;
}
|
|