🧾 简介

从以太网 DMA 接收缓冲区中取出收到的帧数据,拷贝到 lwIP 的 pbuf链 中,然后释放 DMA 描述符以供硬件继续接收数据。


🔎 逻辑分析

接收数据:

  1. 调用 ETH_Get_Received_Frame_interrupt() 获取一个接收帧(包含长度、缓冲区地址、描述符指针)。
  2. 读取帧长度 len,为其分配一个 pbuf链(来自 lwIP 的内存池)。
  3. 遍历 pbuf链表:
    • 如果数据超过 DMA Rx 缓冲区大小,就需要分段从多个描述符中拷贝。
    • 否则直接拷贝到 pbuf。
  4. 释放 DMA 描述符(设置 OWN 位),让硬件能继续接收数据。
  5. 如果 Rx DMA 因 缓冲区不可用(RBUS) 挂起,则清标志并写 DMARPDR 触发继续接收。
  6. 返回填充好的 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;
}