🧾 简介
从以太网 DMA 接收缓冲区中取出收到的帧数据,拷贝到 lwIP 的 pbuf链 中,然后释放 DMA 描述符以供硬件继续接收数据。
🔎 逻辑分析
接收数据:
- 调用
ETH_Get_Received_Frame_interrupt()获取一个接收帧(包含长度、缓冲区地址、描述符指针)。 - 读取帧长度
len,为其分配一个 pbuf链(来自 lwIP 的内存池)。 - 遍历 pbuf链表:
- 如果数据超过 DMA Rx 缓冲区大小,就需要分段从多个描述符中拷贝。
- 否则直接拷贝到 pbuf。
- 释放 DMA 描述符(设置 OWN 位),让硬件能继续接收数据。
- 如果 Rx DMA 因 缓冲区不可用(RBUS) 挂起,则清标志并写
DMARPDR触发继续接收。 - 返回填充好的 pbuf。
[!note] 核心
从 DMA 接收描述符中拷贝数据到 lwIP pbuf,并释放描述符。
💎 总结
从 DMA Rx 描述符中取出数据帧,填充 pbuf 返回给 lwIP 协议栈。
📁 附言
原型
/**
* Should allocate a pbuf and transfer the bytes of the incoming
* packet from the interface into the pbuf.
*
* @param netif the lwip network interface structure for this ethernetif
* @return a pbuf filled with the received packet (including MAC header)
* NULL on memory error
*/
static struct pbuf *low_level_input(struct netif *netif)
{
struct pbuf *p = NULL, *q;
uint32_t l = 0;
u16_t len;
uint8_t *buffer;
/* obtain the size of the packet and put it into the "len" variable. */
len = enet_desc_information_get(dma_current_rxdesc, RXDESC_FRAME_LENGTH);
buffer = (uint8_t *)(enet_desc_information_get(dma_current_rxdesc, RXDESC_BUFFER_1_ADDR));
if (len > 0)
{
/* We allocate a pbuf chain of pbufs from the Lwip buffer pool */
p = pbuf_alloc(PBUF_RAW, len, PBUF_POOL);
}
if (p != NULL)
{
for (q = p; q != NULL; q = q->next)
{
memcpy((uint8_t *)q->payload, (u8_t *)&buffer[l], q->len);
l = l + q->len;
}
}
#ifdef SELECT_DESCRIPTORS_ENHANCED_MODE
ENET_NOCOPY_PTPFRAME_RECEIVE_ENHANCED_MODE(NULL);
#else
ENET_NOCOPY_FRAME_RECEIVE();
#endif /* SELECT_DESCRIPTORS_ENHANCED_MODE */
return p;
}