大家好,又见面了,我是你们的朋友全栈君。如果您正在找激活码,请点击查看最新教程,关注关注公众号 “全栈程序员社区” 获取激活教程,可能之前旧版本教程已经失效.最新Idea2022.1教程亲测有效,一键激活。
Jetbrains全家桶1年46,售后保障稳定
1:环境
STM32F407
RT-thread
2:结构体使用
最上层:struct rt_stm32_eth
struct rt_stm32_eth
{
/* inherit from ethernet device */
struct eth_device parent;
/* interface address info, hw address */
rt_uint8_t dev_addr[MAX_ADDR_LEN];
/* ETH_Speed */
uint32_t ETH_Speed;
/* ETH_Duplex_Mode */
uint32_t ETH_Mode;
};
下一层:struct eth_device parent;
struct eth_device
{
/* inherit from rt_device */
struct rt_device parent;
/* network interface for lwip */
struct netif *netif;
struct rt_semaphore tx_ack;
rt_uint16_t flags;
rt_uint8_t link_changed;
rt_uint8_t link_status;
/* eth device interface */
struct pbuf* (*eth_rx)(rt_device_t dev);
rt_err_t (*eth_tx)(rt_device_t dev, struct pbuf* p);
};
一般来说struct rt_device paren是最终被用来向RT-thread进行注册的。
eth_rx 和eth_tx 这两个是比较重要的函数指针,需要再自己的驱动重来实现。
3:DMA描述符
在LWIP内部使用一种结构叫做DMA描述符。
STM32F407以太网模块中的接收/发送FIFO和内存之间的以太网数据包传输是DMA使用DMA描述符完成的。一共两个描述符列表:一个用于接收,一个用于发送,两个列表的基址分别写入ETH_DMARDLAR寄存器和ETH_DMATDLAR寄存器中。
在 ST 提供的以太网驱
动库 stm32f4x7_eth.c 中使用的是链 接结构,DMA 描述符连接结构的具体描述如图
1、一个以太网数据包可以跨越一个或多个 DMA 描述符。
2、一个 DMA 描述符只能用于一个以太网数据包
3、DMA 描述符列表中的最后一个描述符指向第一个,形成链式结构。
在 ST 的以太网驱动库 stm32f4x7_eth.h 中有个结构体 ETH_DMADESCTypeDef,这个结构
体定义了 DMA 描述符,ETH_DMADESCTypeDef 结构体代码如下。
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 */
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 */
} ETH_DMADescTypeDef;
DMA 描述符分为增强描述符和常规描述符,本教程中我们使用的是常规描述符,如果使
用常规描述符的话就只使用 ETH_DMADESCTypeDef 结构体的前四个成员变量
STM32F407 的描述符分为发送描述符和接收描述符,发送描述符和接收描述符
都用 ETH_DMADESCTypeDef 这个结构体来定义,我们这里只以发送描述符(常规 Tx DMA 描
述符)为例讲解一下,接收描述符(常规 Rx DMA 描述符)与其类似。常规 Tx DMA 描述符可以用
可以从图 中看到好像常规 Tx DMA 描述符有 4 个“寄存器”:TDES0、TDES1、
TDES2 和 TDES3,如果是增强描述符的话就会有 8 个“寄存器”。这里一定要注意这 4 个“寄
存器”并不是 STM32F407 真实存在的,你在 STM32F407 的寄存器列表里面是找不到的,这 4
个“寄存器”是由 ETH_DMADESCTypeDef 这个结构体描述的,我将它们称之为“软件寄存器”,
这些“寄存器”也叫做描述符字,描述符字和 ETH_DMADESCTypeDef 这个结构体的关系如表
所示(此处以 Tx DMA 描述符为例)
以 太网描述符结 构体 ETH_DMADESCTypeDef 中 Buffer1Addr 就 是缓冲 区的地址,
Buffer2NextDescAddr 就是下一个描述符的地址
在 stm32f4x7_eth.c 文件中为了追踪 Rx/Tx DMA 描述符还定义了两个非常重要的全局指针
变量,如下代码。
__IO ETH_DMADESCTypeDef *DMATxDescToSet;
__IO ETH_DMADESCTypeDef *DMARxDescToGet;
这两个指针变量指向 ETH_DMADESCTypeDef 结构体,在使用中他们两个分别指向下一个
要发送或者接受的数据包
4:函数分析
4.1 初始化函数
static int rt_hw_stm32_eth_init(void)
{
rt_err_t state = RT_EOK;
/* Prepare receive and send buffers */
Rx_Buff = (rt_uint8_t *)rt_calloc(ETH_RXBUFNB, ETH_MAX_PACKET_SIZE);
if (Rx_Buff == RT_NULL)
{
LOG_E("No memory");
state = -RT_ENOMEM;
goto __exit;
}
Tx_Buff = (rt_uint8_t *)rt_calloc(ETH_TXBUFNB, ETH_MAX_PACKET_SIZE);
if (Rx_Buff == RT_NULL)
{
LOG_E("No memory");
state = -RT_ENOMEM;
goto __exit;
}
DMARxDscrTab = (ETH_DMADescTypeDef *)rt_calloc(ETH_RXBUFNB, sizeof(ETH_DMADescTypeDef));
if (DMARxDscrTab == RT_NULL)
{
LOG_E("No memory");
state = -RT_ENOMEM;
goto __exit;
}
DMATxDscrTab = (ETH_DMADescTypeDef *)rt_calloc(ETH_TXBUFNB, sizeof(ETH_DMADescTypeDef));
if (DMATxDscrTab == RT_NULL)
{
LOG_E("No memory");
state = -RT_ENOMEM;
goto __exit;
}
stm32_eth_device.ETH_Speed = ETH_SPEED_100M;
stm32_eth_device.ETH_Mode = ETH_MODE_FULLDUPLEX;
/* OUI 00-80-E1 STMICROELECTRONICS. */
stm32_eth_device.dev_addr[0] = 0x00;
stm32_eth_device.dev_addr[1] = 0x80;
stm32_eth_device.dev_addr[2] = 0xE1;
/* generate MAC addr from 96bit unique ID (only for test). */
stm32_eth_device.dev_addr[3] = *(rt_uint8_t *)(UID_BASE + 4);
stm32_eth_device.dev_addr[4] = *(rt_uint8_t *)(UID_BASE + 2);
stm32_eth_device.dev_addr[5] = *(rt_uint8_t *)(UID_BASE + 0);
stm32_eth_device.parent.parent.init = rt_stm32_eth_init;
stm32_eth_device.parent.parent.open = rt_stm32_eth_open;
stm32_eth_device.parent.parent.close = rt_stm32_eth_close;
stm32_eth_device.parent.parent.read = rt_stm32_eth_read;
stm32_eth_device.parent.parent.write = rt_stm32_eth_write;
stm32_eth_device.parent.parent.control = rt_stm32_eth_control;
stm32_eth_device.parent.parent.user_data = RT_NULL;
stm32_eth_device.parent.eth_rx = rt_stm32_eth_rx;
stm32_eth_device.parent.eth_tx = rt_stm32_eth_tx;
/* register eth device */
state = eth_device_init(&(stm32_eth_device.parent), "e0");
if (RT_EOK == state)
{
LOG_D("emac device init success");
}
else
{
LOG_E("emac device init faild: %d", state);
state = -RT_ERROR;
goto __exit;
}
/* start phy monitor */
rt_thread_t tid;
tid = rt_thread_create("phy",
phy_monitor_thread_entry,
RT_NULL,
1024,
RT_THREAD_PRIORITY_MAX - 2,
2);
if (tid != RT_NULL)
{
rt_thread_startup(tid);
}
else
{
state = -RT_ERROR;
}
__exit:
if (state != RT_EOK)
{
if (Rx_Buff)
{
rt_free(Rx_Buff);
}
if (Tx_Buff)
{
rt_free(Tx_Buff);
}
if (DMARxDscrTab)
{
rt_free(DMARxDscrTab);
}
if (DMATxDscrTab)
{
rt_free(DMATxDscrTab);
}
}
return state;
}
INIT_DEVICE_EXPORT(rt_hw_stm32_eth_init);
1:动态分配了Tx,Rx 的buffer 和 DMA描述符
2:对stm32_eth_device结构体进行赋值, 包括速度,模式,mac地址,操作函数,还有eth_tx,eth_rx发送接收函数
3:注册网络设备,命名e0
4:创建了新的线程phy
其中比较重要的是rt_stm32_eth_init,eth_tx,eth_rx这两个函数必须要进行初始化赋值!
4.2 rt_stm32_eth_init
这个函数要来做一些初始化
/* EMAC initialization function */
static rt_err_t rt_stm32_eth_init(rt_device_t dev)
{
__HAL_RCC_ETH_CLK_ENABLE(); 初始化时钟
phy_reset(); reset PHY 向拉低再拉高
/* ETHERNET Configuration */
EthHandle.Instance = ETH;
EthHandle.Init.MACAddr = (rt_uint8_t *)&stm32_eth_device.dev_addr[0];
EthHandle.Init.AutoNegotiation = ETH_AUTONEGOTIATION_DISABLE;
EthHandle.Init.Speed = ETH_SPEED_100M;
EthHandle.Init.DuplexMode = ETH_MODE_FULLDUPLEX;
EthHandle.Init.MediaInterface = ETH_MEDIA_INTERFACE_RMII;
EthHandle.Init.RxMode = ETH_RXINTERRUPT_MODE;
#ifdef RT_LWIP_USING_HW_CHECKSUM
EthHandle.Init.ChecksumMode = ETH_CHECKSUM_BY_HARDWARE;
#else
EthHandle.Init.ChecksumMode = ETH_CHECKSUM_BY_SOFTWARE;
#endif
HAL_ETH_DeInit(&EthHandle); 清除ETH的配置
/* configure ethernet peripheral (GPIOs, clocks, MAC, DMA) */
if (HAL_ETH_Init(&EthHandle) != HAL_OK) 配置ETH的一些参数
{
LOG_E("eth hardware init failed");
return -RT_ERROR;
}
else
{
LOG_D("eth hardware init success");
}
下面这两个函数时把DMA Tx Rx的描述符进行初始化串联起来
/* Initialize Tx Descriptors list: Chain Mode */
HAL_ETH_DMATxDescListInit(&EthHandle, DMATxDscrTab, Tx_Buff, ETH_TXBUFNB);
/* Initialize Rx Descriptors list: Chain Mode */
HAL_ETH_DMARxDescListInit(&EthHandle, DMARxDscrTab, Rx_Buff, ETH_RXBUFNB);
/* ETH interrupt Init*/ 中断初始化
HAL_NVIC_SetPriority(ETH_IRQn, 0x07, 0);
HAL_NVIC_EnableIRQ(ETH_IRQn);
/* Enable MAC and DMA transmission and reception */使能MAC和DMA
if (HAL_ETH_Start(&EthHandle) == HAL_OK)
{
LOG_D("emac hardware start");
}
else
{
LOG_E("emac hardware start faild");
return -RT_ERROR;
}
return RT_EOK;
}
4.2.1 HAL_ETH_DMATxDescListInit
HAL_StatusTypeDef HAL_ETH_DMATxDescListInit(ETH_HandleTypeDef *heth, ETH_DMADescTypeDef *DMATxDescTab, uint8_t *TxBuff, uint32_t TxBuffCount)
{
uint32_t i = 0U;
ETH_DMADescTypeDef *dmatxdesc;
/* Process Locked */
__HAL_LOCK(heth);
/* Set the ETH peripheral state to BUSY */
heth->State = HAL_ETH_STATE_BUSY; 设置状态等于busy
/* Set the DMATxDescToSet pointer with the first one of the DMATxDescTab list */
heth->TxDesc = DMATxDescTab;获取第一个描述符
/* Fill each DMATxDesc descriptor with the right values */
for(i=0U; 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 */给描述符的buffer赋值地址
dmatxdesc->Buffer1Addr = (uint32_t)(&TxBuff[i*ETH_TX_BUF_SIZE]);
if ((heth->Init).ChecksumMode == ETH_CHECKSUM_BY_HARDWARE)
{
/* Set the DMA Tx descriptors checksum insertion */
dmatxdesc->Status |= ETH_DMATXDESC_CHECKSUMTCPUDPICMPFULL;
}
/* Initialize the next descriptor with the Next Descriptor Polling Enable */
if(i < (TxBuffCount-1U))如果小于最大值,描述符的next就指向下一个,否则就指向第一个描述符
{
/* Set next descriptor address register with next descriptor base address */
dmatxdesc->Buffer2NextDescAddr = (uint32_t)(DMATxDescTab+i+1U);
}
else
{
/* For last descriptor, set next descriptor address register equal to the first descriptor base address */
dmatxdesc->Buffer2NextDescAddr = (uint32_t) DMATxDescTab;
}
}
/* Set Transmit Descriptor List Address Register */ 把描述符的地址赋值给DMA的寄存器
(heth->Instance)->DMATDLAR = (uint32_t) DMATxDescTab;
/* Set ETH HAL State to Ready */设置状态等于ready
heth->State= HAL_ETH_STATE_READY;
/* Process Unlocked */
__HAL_UNLOCK(heth);
/* Return function status */
return HAL_OK;
}
4.3 eth_tx
/* ethernet device interface */
/* transmit data*/
rt_err_t rt_stm32_eth_tx(rt_device_t dev, struct pbuf *p)
{
rt_err_t ret = RT_ERROR;
HAL_StatusTypeDef state;
struct pbuf *q;
uint8_t *buffer = (uint8_t *)(EthHandle.TxDesc->Buffer1Addr);
__IO ETH_DMADescTypeDef *DmaTxDesc;
uint32_t framelength = 0;
uint32_t bufferoffset = 0;
uint32_t byteslefttocopy = 0;
uint32_t payloadoffset = 0;
DmaTxDesc = EthHandle.TxDesc;
bufferoffset = 0;
/* copy frame from pbufs to driver buffers */
for (q = p; q != NULL; q = q->next) 遍历pbuf来获取其中的数据
{
/* Is this buffer available? If not, goto error */
if ((DmaTxDesc->Status & ETH_DMATXDESC_OWN) != (uint32_t)RESET)
{
LOG_D("buffer not valid");
ret = ERR_USE;
goto error;
}
/* Get bytes in current lwIP buffer */
byteslefttocopy = q->len;
payloadoffset = 0;
/* Check if the length of data to copy is bigger than Tx buffer size*/
while ((byteslefttocopy + bufferoffset) > ETH_TX_BUF_SIZE)当要copy的数据和剩余数据之和大于DMA描述符buffer中最大值的时候
{
/* Copy data to Tx buffer*/
memcpy((uint8_t *)((uint8_t *)buffer + bufferoffset), (uint8_t *)((uint8_t *)q->payload + payloadoffset), (ETH_TX_BUF_SIZE - bufferoffset));//向DMA buffer的复制数据
/* Point to next descriptor */
DmaTxDesc = (ETH_DMADescTypeDef *)(DmaTxDesc->Buffer2NextDescAddr);//让描述符指向下一个描述符
/* Check if the buffer is available */
if ((DmaTxDesc->Status & ETH_DMATXDESC_OWN) != (uint32_t)RESET)//判断一下描述符的状态是否空闲
{
LOG_E("dma tx desc buffer is not valid");
ret = ERR_USE;
goto error;
}
buffer = (uint8_t *)(DmaTxDesc->Buffer1Addr);//buffer又指向了DMA描述符的buffer地址
byteslefttocopy = byteslefttocopy - (ETH_TX_BUF_SIZE - bufferoffset);计算剩余要复制的数据
payloadoffset = payloadoffset + (ETH_TX_BUF_SIZE - bufferoffset);计算已经发送的数据
framelength = framelength + (ETH_TX_BUF_SIZE - bufferoffset);计算已经发送的数据
bufferoffset = 0;
}
/* Copy the remaining bytes */剩余的数据不大于DMA描述符的buffer
memcpy((uint8_t *)((uint8_t *)buffer + bufferoffset), (uint8_t *)((uint8_t *)q->payload + payloadoffset), byteslefttocopy);剩余数据复制到buffer中
bufferoffset = bufferoffset + byteslefttocopy;每个pbuf分次传输后,当最后剩余的小大未将一个描述符的大小未被填满时,可以利用这个值来定位剩余空间的起始位置。
便于下一个pbuf的数据,从这个位置继续填充
framelength = framelength + byteslefttocopy;帧长度总量
}
#ifdef ETH_TX_DUMP
dump_hex(buffer, p->tot_len);
#endif
/* Prepare transmit descriptors to give to DMA */
/* TODO Optimize data send speed*/
LOG_D("transmit frame lenth :%d", framelength);
/* wait for unlocked */
while (EthHandle.Lock == HAL_LOCKED);
state = HAL_ETH_TransmitFrame(&EthHandle, framelength);调用这个函数进行描述符的发送
if (state != HAL_OK)
{
LOG_E("eth transmit frame faild: %d", state);
}
ret = ERR_OK;
error:
/* When Transmit Underflow flag is set, clear it and issue a Transmit Poll Demand to resume transmission */
if ((EthHandle.Instance->DMASR & ETH_DMASR_TUS) != (uint32_t)RESET)
{
/* Clear TUS ETHERNET DMA flag */
EthHandle.Instance->DMASR = ETH_DMASR_TUS;
/* Resume DMA transmission*/
EthHandle.Instance->DMATPDR = 0;
}
return ret;
}
这个函数主要的功能就是填充DMA描述符里面的buffer。
这里用到了一个结构体pbuf,payload指向具体的数据,数据存放到描述符中buffer。
4.3.1 pbuf
/** Main packet buffer struct */
struct pbuf {
/** next pbuf in singly linked pbuf chain */
struct pbuf *next;
/** pointer to the actual data in the buffer */
void *payload;
/** * total length of this buffer and all next buffers in chain * belonging to the same packet. * * For non-queue packet chains this is the invariant: * p->tot_len == p->len + (p->next? p->next->tot_len: 0) */
u16_t tot_len;
/** length of this buffer */
u16_t len;
/** pbuf_type as u8_t instead of enum to save space */
u8_t /*pbuf_type*/ type;
/** misc flags */
u8_t flags;
/** * the reference count always equals the number of pointers * that refer to this pbuf. This can be pointers from an application, * the stack itself, or pbuf->next pointers from a chain. */
u16_t ref;
};
调用HAL库函数的HAL_ETH_TransmitFrame进行真正的传输。
HAL_StatusTypeDef HAL_ETH_TransmitFrame(ETH_HandleTypeDef *heth, uint32_t FrameLength)
{
uint32_t bufcount = 0U, size = 0U, i = 0U;
/* Process Locked */
__HAL_LOCK(heth);
/* Set the ETH peripheral state to BUSY */
heth->State = HAL_ETH_STATE_BUSY;
if (FrameLength == 0U)
{
/* Set ETH HAL state to READY */
heth->State = HAL_ETH_STATE_READY;
/* Process Unlocked */
__HAL_UNLOCK(heth);
return HAL_ERROR;
}
/* Check if the descriptor is owned by the ETHERNET DMA (when set) or CPU (when reset) */
if(((heth->TxDesc)->Status & ETH_DMATXDESC_OWN) != (uint32_t)RESET)
{
/* OWN bit set */
heth->State = HAL_ETH_STATE_BUSY_TX;
/* Process Unlocked */
__HAL_UNLOCK(heth);
return HAL_ERROR;
}
/* Get the number of needed Tx buffers for the current frame */
if (FrameLength > ETH_TX_BUF_SIZE)
{
bufcount = FrameLength/ETH_TX_BUF_SIZE;
if (FrameLength % ETH_TX_BUF_SIZE)
{
bufcount++;
}
}
else
{
bufcount = 1U;
}
if (bufcount == 1U)
{
/* Set LAST and FIRST segment */
heth->TxDesc->Status |=ETH_DMATXDESC_FS|ETH_DMATXDESC_LS;
/* Set frame size */
heth->TxDesc->ControlBufferSize = (FrameLength & ETH_DMATXDESC_TBS1);
/* Set Own bit of the Tx descriptor Status: gives the buffer back to ETHERNET DMA */
heth->TxDesc->Status |= ETH_DMATXDESC_OWN;
/* Point to next descriptor */
heth->TxDesc= (ETH_DMADescTypeDef *)(heth->TxDesc->Buffer2NextDescAddr);
}
else
{
for (i=0U; i< bufcount; i++)
{
/* Clear FIRST and LAST segment bits */
heth->TxDesc->Status &= ~(ETH_DMATXDESC_FS | ETH_DMATXDESC_LS);
if (i == 0U)
{
/* Setting the first segment bit */
heth->TxDesc->Status |= ETH_DMATXDESC_FS;
}
/* Program size */
heth->TxDesc->ControlBufferSize = (ETH_TX_BUF_SIZE & ETH_DMATXDESC_TBS1);
if (i == (bufcount-1U))
{
/* Setting the last segment bit */
heth->TxDesc->Status |= ETH_DMATXDESC_LS;
size = FrameLength - (bufcount-1U)*ETH_TX_BUF_SIZE;
heth->TxDesc->ControlBufferSize = (size & ETH_DMATXDESC_TBS1);
}
/* Set Own bit of the Tx descriptor Status: gives the buffer back to ETHERNET DMA */
heth->TxDesc->Status |= ETH_DMATXDESC_OWN;
/* point to next descriptor */
heth->TxDesc = (ETH_DMADescTypeDef *)(heth->TxDesc->Buffer2NextDescAddr);
}
}
/* When Tx Buffer unavailable flag is set: clear it and resume transmission */
if (((heth->Instance)->DMASR & ETH_DMASR_TBUS) != (uint32_t)RESET)
{
/* Clear TBUS ETHERNET DMA flag */
(heth->Instance)->DMASR = ETH_DMASR_TBUS;
/* Resume DMA transmission*/
(heth->Instance)->DMATPDR = 0U;
}
/* Set ETH HAL State to Ready */
heth->State = HAL_ETH_STATE_READY;
/* Process Unlocked */
__HAL_UNLOCK(heth);
/* Return function status */
return HAL_OK;
}
4.4 etx_rx
这个函数会先通过HAL_ETH_GetReceivedFrame_IT来获取DMA的描述符
/* receive data*/
struct pbuf *rt_stm32_eth_rx(rt_device_t dev)
{
struct pbuf *p = NULL;
struct pbuf *q = NULL;
HAL_StatusTypeDef state;
uint16_t len = 0;
uint8_t *buffer;
__IO ETH_DMADescTypeDef *dmarxdesc;
uint32_t bufferoffset = 0;
uint32_t payloadoffset = 0;
uint32_t byteslefttocopy = 0;
uint32_t i = 0;
/* Get received frame */
state = HAL_ETH_GetReceivedFrame_IT(&EthHandle);获取描述符
if (state != HAL_OK)
{
LOG_D("receive frame faild");
return NULL;
}
/* Obtain the size of the packet and put it into the "len" variable. */
len = EthHandle.RxFrameInfos.length;得到数据长度
buffer = (uint8_t *)EthHandle.RxFrameInfos.buffer;得到buffer首地址
LOG_D("receive frame len : %d", len);
if (len > 0)
{
/* We allocate a pbuf chain of pbufs from the Lwip buffer pool */
p = pbuf_alloc(PBUF_RAW, len, PBUF_POOL);给pbuf的指针分配空间
}
#ifdef ETH_RX_DUMP
dump_hex(buffer, p->tot_len);
#endif
if (p != NULL)
{
dmarxdesc = EthHandle.RxFrameInfos.FSRxDesc;
bufferoffset = 0;
for (q = p; q != NULL; q = q->next)
{
byteslefttocopy = q->len;
payloadoffset = 0;
/* Check if the length of bytes to copy in current pbuf is bigger than Rx buffer size*/
while ((byteslefttocopy + bufferoffset) > ETH_RX_BUF_SIZE)数据长度大于结束buffer的最大值
{
/* Copy data to pbuf */把数据从描述符的buffer重复制到pbuf中去
memcpy((uint8_t *)((uint8_t *)q->payload + payloadoffset), (uint8_t *)((uint8_t *)buffer + bufferoffset), (ETH_RX_BUF_SIZE - bufferoffset));
/* Point to next descriptor */描述符指向下一个
dmarxdesc = (ETH_DMADescTypeDef *)(dmarxdesc->Buffer2NextDescAddr);
buffer = (uint8_t *)(dmarxdesc->Buffer1Addr);
byteslefttocopy = byteslefttocopy - (ETH_RX_BUF_SIZE - bufferoffset);
payloadoffset = payloadoffset + (ETH_RX_BUF_SIZE - bufferoffset);
bufferoffset = 0;
}
/* Copy remaining data in pbuf */复制剩下的数据
memcpy((uint8_t *)((uint8_t *)q->payload + payloadoffset), (uint8_t *)((uint8_t *)buffer + bufferoffset), byteslefttocopy);
bufferoffset = bufferoffset + byteslefttocopy;
}
}
/* Release descriptors to DMA */
/* Point to first descriptor */
dmarxdesc = EthHandle.RxFrameInfos.FSRxDesc;
/* Set Own bit in Rx descriptors: gives the buffers back to DMA */
for (i = 0; i < EthHandle.RxFrameInfos.SegCount; i++)
{
dmarxdesc->Status |= ETH_DMARXDESC_OWN;
dmarxdesc = (ETH_DMADescTypeDef *)(dmarxdesc->Buffer2NextDescAddr);
}
/* Clear Segment_Count */
EthHandle.RxFrameInfos.SegCount = 0;
/* When Rx Buffer unavailable flag is set: clear it and resume reception */
if ((EthHandle.Instance->DMASR & ETH_DMASR_RBUS) != (uint32_t)RESET)
{
/* Clear RBUS ETHERNET DMA flag */
EthHandle.Instance->DMASR = ETH_DMASR_RBUS;
/* Resume DMA reception */
EthHandle.Instance->DMARPDR = 0;
}
return p;把数据pbuf的指针返回
}
这个函数只要的功能就是,从DMA的描述符中获取数据并存放到pbuf中去。最后把pbuf的指针返回。
发布者:全栈程序员-用户IM,转载请注明出处:https://javaforall.cn/227254.html原文链接:https://javaforall.cn
【正版授权,激活自己账号】: Jetbrains全家桶Ide使用,1年售后保障,每天仅需1毛
【官方授权 正版激活】: 官方授权 正版激活 支持Jetbrains家族下所有IDE 使用个人JB账号...