LWIP是嵌入式设备的网络微协议,基本上实现了标准的TCP/IP的功能,它没有项标准的TCP/IP协议那样有很严格的分层。主要原因是由于嵌入式设别的资源有限,所以避免了每层的COPY动作,在不同层之间是之间共用同一内存操作。那么下面我们来介绍下数据到底是怎么从网卡接收,然后吧数据交给协议处理的:
首先说明下,我用的平台是STM32F207+DP83848平台的,lwip1.4.1。
1、首先我们初始化网卡,这里涉及的是硬件上面的配置,在这里就不做详细说明。在配置好了后,我们需要初始化相关参数。由于我们的STM32F207用的是DMA从PHY那里获取数据,然后也是通过DMA把发送的数据送到PHY。所以在这里我们首先需要初始化好DMA的数据接收缓存和发送缓存。
1-1.在这里我们需要知道这两个全局变量:
ETH_DMADESCTypeDef *DMATxDescToSet;//发送缓冲区指针,指向当前发送数据的首地址。
ETH_DMADESCTypeDef *DMARxDescToGet;//接收缓冲区指针,指向当前接收缓冲区的首地址。
结构体成员变量如下:
typedef struct {
__IO uint32_t Status; /*!< Status */
uint32_t ControlBufferSize; /*!< Control and Buffer1, Buffer2 lengths */
uint32_t Buffer1Addr; /*!< Buffer1 address pointer */
uint32_t Buffer2NextDescAddr; /*!< Buffer2 or next descriptor address pointer */
/* Enhanced ETHERNET DMA PTP Descriptors */
#ifdef USE_ENHANCED_DMA_DESCRIPTORS//这个红没有打开,所以我们只关心上面几个变量
uint32_t ExtendedStatus; /* Extended status for PTP receive descriptor */
uint32_t Reserved1; /* Reserved */
uint32_t TimeStampLow; /* Time Stamp Low value for transmit and receive */
uint32_t TimeStampHigh; /* Time Stamp High value for transmit and receive */
#endif /* USE_ENHANCED_DMA_DESCRIPTORS */
} ETH_DMADESCTypeDef;
首先来讲解下发送缓冲区:由于rt-thread用到的是一个两维数组做为发送数据的缓冲区,而且是把这个二维数组做成了一个环形的链表,这个就是在初始化需要完成的事情。
下面具体看代码实现:
void ETH_DMATxDescChainInit(ETH_DMADESCTypeDef *DMATxDescTab, uint8_t* TxBuff, uint32_t TxBuffCount)
{
uint32_t i = 0;
ETH_DMADESCTypeDef *DMATxDesc;
/* Set the DMATxDescToSet pointer with the first one of the DMATxDescTab list */
DMATxDescToSet = DMATxDescTab;//首先是把数组DMATxDescTab的首地址传入
/* Fill each DMATxDesc descriptor with the right values */
for(i=0; i < TxBuffCount; i++)//这个for循环就是把数据缓冲区形成一个单项链表
{
/* Get the pointer on the ith member of the Tx Desc list */
DMATxDesc = DMATxDescTab + i;
/* Set Second Address Chained bit */
DMATxDesc->Status = ETH_DMATxDesc_TCH;
/* Set Buffer1 address pointer */
DMATxDesc->Buffer1Addr = (uint32_t)(&TxBuff[i*ETH_TX_BUF_SIZE]);
/* Initialize the next descriptor with the Next Descriptor Polling Enable */
if(i < (TxBuffCount-1))//这里是连接TxBuffCount-1个接收缓冲区,形成的只是一个单项链表
{
/* Set next descriptor address register with next descriptor base address */
DMATxDesc->Buffer2NextDescAddr = (uint32_t)(DMATxDescTab+i+1);//每个结构体
}
else //这里才是形成一个环形链表,具体操作是把最后一个最后一个描述符的Buffer2NextDescAddr 指向了第一个描述符,这样就形成了一个环形链表