近几年,项目需要,在多款单片机上使用了以太网外设。
本文为阶段知识整理,查缺补漏,方便以后再次遇到相关任务时,可以游刃有余的完成工作。
#define ETH_MAX_PACKET_SIZE 1524U /*!< ETH_HEADER + ETH_EXTRA + ETH_VLAN_TAG + ETH_MAX_ETH_PAYLOAD + ETH_CRC */
/* Definition of the Ethernet driver buffers size and count */
#define ETH_RX_BUF_SIZE ETH_MAX_PACKET_SIZE /* buffer size for receive */
#define ETH_TX_BUF_SIZE ETH_MAX_PACKET_SIZE /* buffer size for transmit */
#define ETH_RXBUFNB 8U /* 4 Rx buffers of size ETH_RX_BUF_SIZE */
#define ETH_TXBUFNB 4U /* 4 Tx buffers of size ETH_TX_BUF_SIZE */
__ALIGN_BEGIN ETH_DMADescTypeDef DMARxDscrTab[ETH_RXBUFNB] __ALIGN_END;/* Ethernet Rx MA Descriptor */
__ALIGN_BEGIN ETH_DMADescTypeDef DMATxDscrTab[ETH_TXBUFNB] __ALIGN_END;/* Ethernet Tx DMA Descriptor */
__ALIGN_BEGIN uint8_t Rx_Buff[ETH_RXBUFNB][ETH_RX_BUF_SIZE] __ALIGN_END; /* Ethernet Receive Buffer */
__ALIGN_BEGIN uint8_t Tx_Buff[ETH_TXBUFNB][ETH_TX_BUF_SIZE] __ALIGN_END; /* Ethernet Transmit Buffer */
/* Initialize Tx Descriptors list: Chain Mode */
HAL_ETH_DMATxDescListInit(&heth, DMATxDscrTab, &Tx_Buff[0][0], ETH_TXBUFNB);
/* Initialize Rx Descriptors list: Chain Mode */
HAL_ETH_DMARxDescListInit(&heth, DMARxDscrTab, &Rx_Buff[0][0], ETH_RXBUFNB);
函数声明:HAL_StatusTypeDef HAL_ETH_Init(ETH_HandleTypeDef *heth); 用于初始化MAC和DMA。
/* Init the low level hardware : GPIO, CLOCK, NVIC. */
HAL_ETH_MspInit(heth);
/* Select MII or RMII Mode*/
AFIO->MAPR &= ~(AFIO_MAPR_MII_RMII_SEL);
AFIO->MAPR |= (uint32_t) heth->Init.MediaInterface; //ETH_MEDIA_INTERFACE_MII 0x00000000
//ETH_MEDIA_INTERFACE_RMII 0x00800000
/* Ethernet Software reset */
/* Set the SWR bit: resets all MAC subsystem internal registers and logic */
/* After reset all the registers holds their respective reset values */
(heth->Instance)->DMABMR |= ETH_DMABMR_SR;
/* Get tick */
tickstart = HAL_GetTick();
/* Wait for software reset */
while (((heth->Instance)->DMABMR & ETH_DMABMR_SR) != (uint32_t)RESET)
{
/* Check for the Timeout */
if ((HAL_GetTick() - tickstart) > ETH_TIMEOUT_SWRESET)
{
heth->State = HAL_ETH_STATE_TIMEOUT;
/* Process Unlocked */
__HAL_UNLOCK(heth);
/* Note: The SWR is not performed if the ETH_RX_CLK or the ETH_TX_CLK are
not available, please check your external PHY or the IO configuration */
//注意:如果ETH_RX_CLK或ETH_TX_CLK不可用,则不执行SWR,请检查您的外部PHY或IO配置
return HAL_TIMEOUT;
}
}
/*-------------------------------- MAC Initialization ----------------------*/
/* Get the ETHERNET MACMIIAR value */
tmpreg1 = (heth->Instance)->MACMIIAR;
/* Clear CSR Clock Range CR[2:0] bits */
tmpreg1 &= ETH_MACMIIAR_CR_MASK;
/* Get hclk frequency value */
hclk = HAL_RCC_GetHCLKFreq();
/* Set CR bits depending on hclk value */
if ((hclk >= 20000000U) && (hclk < 35000000U))
{
/* CSR Clock Range between 20-35 MHz */
tmpreg1 |= (uint32_t)ETH_MACMIIAR_CR_DIV16;
}
else if ((hclk >= 35000000U) && (hclk < 60000000U))
{
/* CSR Clock Range between 35-60 MHz */
tmpreg1 |= (uint32_t)ETH_MACMIIAR_CR_DIV26;
}
else
{
/* CSR Clock Range between 60-72 MHz */
tmpreg1 |= (uint32_t)ETH_MACMIIAR_CR_DIV42;
}
/* Write to ETHERNET MAC MIIAR: Configure the ETHERNET CSR Clock Range */
(heth->Instance)->MACMIIAR = (uint32_t)tmpreg1;
/* Put the PHY in reset mode */
HAL_ETH_WritePHYRegister(heth, PHY_BCR, PHY_RESET));
/* Delay to assure PHY reset */
HAL_Delay(PHY_RESET_DELAY);
if ((heth->Init).AutoNegotiation != ETH_AUTONEGOTIATION_DISABLE)
{
......
}
else /* AutoNegotiation Disable */
{
/* Set MAC Speed and Duplex Mode */
HAL_ETH_WritePHYRegister(heth, PHY_BCR, ((uint16_t)((heth->Init).DuplexMode >> 3U) | (uint16_t)((heth->Init).Speed >> 1U) );
/* Delay to assure PHY configuration */
HAL_Delay(PHY_CONFIG_DELAY);
}
/* Config MAC and DMA */
ETH_MACDMAConfig(heth, err);
/* Set ETH HAL State to Ready */
heth->State = HAL_ETH_STATE_READY;
/* Initialize Tx Descriptors list: Chain Mode */
HAL_ETH_DMATxDescListInit(&heth, DMATxDscrTab, &Tx_Buff[0][0], ETH_TXBUFNB);
/* Initialize Rx Descriptors list: Chain Mode */
HAL_ETH_DMARxDescListInit(&heth, DMARxDscrTab, &Rx_Buff[0][0], ETH_RXBUFNB);
/* create a binary semaphore used for informing ethernetif of frame reception */
gRxSem = rt_sem_create("gRxSem", 0, RT_IPC_FLAG_FIFO);
mytask = rt_thread_create("if_input", ethernetif_input, &gnetif, 512, 4, 1);
if(mytask != NULL)
{
rt_thread_startup(mytask);
}
void ethernetif_input(void* argument)
{
struct pbuf *p;
struct netif *netif = (struct netif *) argument;
struct eth_hdr *ethhdr;
for( ;; )
{
// if (osSemaphoreAcquire(s_xSemaphore, TIME_WAITING_FOR_INPUT) == osOK)
waitEthData(); //等待信号量
{
do
{
LOCK_TCPIP_CORE();
p = low_level_input( netif );
if (p != NULL)
{
ethhdr = p->payload;//指向数据包有效负载,它以以太网报头开始
switch (htons(ethhdr->type))
{
/* IP or ARP packet? */
case ETHTYPE_IP:
case ETHTYPE_ARP:
/* 将完整数据包发送到tcpip_thread以进行处理 */
//tcpip_input(p, netif) --> sys_mbox_trypost(&mbox, msg) 发送邮箱信息,tcpip主线程接收邮箱信息
if (netif->input(p, netif)!=ERR_OK)
{
pbuf_free(p);
p = NULL;
}
break;
default:
pbuf_free(p);
p = NULL;
break;
}//end of switch
}//end of if (p != NULL)
UNLOCK_TCPIP_CORE();
} while(p!=NULL);
}//end of if (osSem...
}//end of for(;;)
}
/* Enable MAC and DMA transmission and reception */
HAL_ETH_Start(&heth);
__IO ETH_DMADescTypeDef *DmaTxDesc = heth.TxDesc;
uint8_t *buffer = (uint8_t *)(heth.TxDesc->Buffer1Addr);
/* Is this buffer available? If not, goto error */
if((DmaTxDesc->Status & ETH_DMATXDESC_OWN) != (uint32_t)RESET)
{
errval = ERR_USE;
goto error;
}
//遍历全部pbuf数据块
for(q = p; q != NULL; q = q->next)
{
//(1) 检查当前的驱动发送缓冲区能否访问
... ...
//(2) 获取当前 lwIP的pbuf 缓冲区的字节长度
byteslefttocopy = q->len;
payloadoffset = 0;
//(3) 检查 剩余需要复制的字节长度是否超过驱动设备缓冲区的长度,如果超过,则一次搬运 ETH_TX_BUF_SIZE 字节的数据
while( (byteslefttocopy + bufferoffset) > ETH_TX_BUF_SIZE )
{
//(3.1) 将数据从pbuf 拷贝到 驱动发送缓冲区buffer ,bufferoffset=0
memcpy( (uint8_t*)((uint8_t*)buffer + bufferoffset), (uint8_t*)((uint8_t*)q->payload + payloadoffset), (ETH_TX_BUF_SIZE - bufferoffset) );
//(3.2) 指向下一个驱动发送缓冲区块
DmaTxDesc = (ETH_DMADescTypeDef *)(DmaTxDesc->Buffer2NextDescAddr);
//(3.3) 检查能否被访问
... ...
//(3.4) 获取驱动发送缓冲区
buffer = (uint8_t *)(DmaTxDesc->Buffer1Addr);
byteslefttocopy = byteslefttocopy - (ETH_TX_BUF_SIZE - bufferoffset);
payloadoffset = payloadoffset + (ETH_TX_BUF_SIZE - bufferoffset);
framelength = framelength + (ETH_TX_BUF_SIZE - bufferoffset);
bufferoffset = 0;
}
//(4) 复制转移剩余的字节
memcpy( (uint8_t*)((uint8_t*)buffer + bufferoffset), (uint8_t*)((uint8_t*)q->payload + payloadoffset), byteslefttocopy );
bufferoffset = bufferoffset + byteslefttocopy;
framelength = framelength + byteslefttocopy;
}
/* Prepare transmit descriptors to give to DMA */
HAL_ETH_TransmitFrame(&heth, framelength);
HAL_ETH_GetReceivedFrame_IT(&heth)
len = heth.RxFrameInfos.length;
buffer = (uint8_t *)heth.RxFrameInfos.buffer;
/* We allocate a pbuf chain of pbufs from the Lwip buffer pool */
p = pbuf_alloc(PBUF_RAW, len, PBUF_POOL);
dmarxdesc = heth.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*/
//(1) 检查 剩余的需要转移的数据字节 是否 大于 当前的pbuf空间大小
while( (byteslefttocopy + bufferoffset) > ETH_RX_BUF_SIZE )
{
/* Copy data to pbuf */
memcpy( (uint8_t*)((uint8_t*)q->payload + payloadoffset), (uint8_t*)((uint8_t*)buffer + bufferoffset), (ETH_RX_BUF_SIZE - bufferoffset));
//获取驱动接收缓冲区
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;
}
//(2) 拷贝剩余的数据,到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 = heth.RxFrameInfos.FSRxDesc;
/* Set Own bit in Rx descriptors: gives the buffers back to DMA */
for (i=0; i< heth.RxFrameInfos.SegCount; i++)
{
dmarxdesc->Status |= ETH_DMARXDESC_OWN;
dmarxdesc = (ETH_DMADescTypeDef *)(dmarxdesc->Buffer2NextDescAddr);
}
/* Clear Segment_Count */
heth.RxFrameInfos.SegCount =0;
/* When Rx Buffer unavailable flag is set: clear it and resume reception */
if ((heth.Instance->DMASR & ETH_DMASR_RBUS) != (uint32_t)RESET)
{
/* Clear RBUS ETHERNET DMA flag */
heth.Instance->DMASR = ETH_DMASR_RBUS;
/* Resume DMA reception */
heth.Instance->DMARPDR = 0;
}
return p;
u32_t sys_now(void);
u32_t sys_jiffies(void);
在函数rt_hw_hhd_eth_init中定义了MAC地址。
/* 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). */
mark_mac = get_mark();
stm32_eth_device.dev_addr[3] = ETH_MAC3;
stm32_eth_device.dev_addr[4] = ETH_MAC4;
stm32_eth_device.dev_addr[5] = (mark_mac & 0x0F) + ETH_MAC5;
在调用rt_stm32_eth_init时,会将MAC地址写入到相应的寄存器中。
ETH_MACAddressConfig(ETH_MAC_Address0, (u8*)&stm32_eth->dev_addr[0]);
void ETH_MACAddressConfig(uint32_t MacAddr, uint8_t *Addr)
{
uint32_t tmpreg;
/* Calculate the selectecd MAC address high register */
tmpreg = ((uint32_t)Addr[5] << 8) | (uint32_t)Addr[4];
/* Load the selectecd MAC address high register */
(*(__IO uint32_t *) (ETH_MAC_ADDR_HBASE + MacAddr)) = tmpreg;
/* Calculate the selectecd MAC address low register */
tmpreg = ((uint32_t)Addr[3] << 24) | ((uint32_t)Addr[2] << 16) | ((uint32_t)Addr[1] << 8) | Addr[0];
/* Load the selectecd MAC address low register */
(*(__IO uint32_t *) (ETH_MAC_ADDR_LBASE + MacAddr)) = tmpreg;
}
(1)空间大小定义
#define ETH_MAX_PACKET_SIZE 1520 /*!< ETH_HEADER + ETH_EXTRA + MAX_ETH_PAYLOAD + ETH_CRC */
#define ETH_RXBUFNB 6
#define ETH_TXBUFNB 4
(2)数组定义
static ETH_DMADESCTypeDef DMARxDscrTab[ETH_RXBUFNB], DMATxDscrTab[ETH_TXBUFNB];
static rt_uint8_t Rx_Buff[ETH_RXBUFNB][ETH_MAX_PACKET_SIZE], Tx_Buff[ETH_TXBUFNB][ETH_MAX_PACKET_SIZE];
(3)初始化
/* Initialize Tx Descriptors list: Chain Mode */
ETH_DMATxDescChainInit(DMATxDscrTab, &Tx_Buff[0][0], ETH_TXBUFNB);
/* Initialize Rx Descriptors list: Chain Mode */
ETH_DMARxDescChainInit(DMARxDscrTab, &Rx_Buff[0][0], ETH_RXBUFNB);
(4)启用 DMA 接收描述块的 接收中断标志。
/* Enable Ethernet Rx interrrupt */
int i;
for(i=0; i<ETH_RXBUFNB; i++)
{
ETH_DMARxDescReceiveITConfig(&DMARxDscrTab[i], ENABLE);
}
/* Enable MAC and DMA transmission and reception */
ETH_Start();
void ETH_Start(void)
{
/* Enable transmit state machine of the MAC for transmission on the MII */
ETH_MACTransmissionCmd(ENABLE);
/* Flush Transmit FIFO */
ETH_FlushTransmitFIFO();
/* Enable receive state machine of the MAC for reception from the MII */
ETH_MACReceptionCmd(ENABLE);
/* Start DMA reception */
ETH_DMAReceptionCmd(ENABLE);
/* Start DMA transmission */
ETH_DMATransmissionCmd(ENABLE);
}
uint8_t *buffer = (rt_uint8_t*)ETH_GetCurrentTxBuffer();
u32 ETH_GetCurrentTxBuffer(void)
{
/* Return Buffer address */
return (DMATxDescToSet->Buffer1Addr);
}
for(q = p; q != NULL; q = q->next)
{
memcpy((rt_uint8_t*)&buffer[offset], q->payload, q->len);
offset = offset + q->len;
}
ETH_TxPkt_ChainMode(offset);
/* Check if the descriptor is owned by the ETHERNET DMA (when set) or CPU (when reset) */
if((DMATxDescToSet->Status & ETH_DMATxDesc_OWN) != (u32)RESET)
{
/* Return ERROR: OWN bit set */
return RT_ERROR;
}
/* Setting the Frame Length: bits[12:0] */
DMATxDescToSet->ControlBufferSize = (FrameLength & ETH_DMATxDesc_TBS1);
/* Setting the last segment and first segment bits (in this case a frame is transmitted in one descriptor) */
DMATxDescToSet->ControlBufferSize |= ETH_DMATxDesc_LS | ETH_DMATxDesc_FS;
DMATxDescToSet->ControlBufferSize |= ETH_DMATxDesc_TCH; // /*!< Second Address Chained 和ST不一样
/* Set Own bit of the Tx descriptor Status: gives the buffer back to ETHERNET DMA */
DMATxDescToSet->Status |= ETH_DMATxDesc_OWN;
/* When Tx Buffer unavailable flag is set: clear it and resume transmission */
if ((HHD_ETH->DMASR & ETH_DMASR_TBUS) != (u32)RESET)
{
/* Clear TBUS ETHERNET DMA flag */
HHD_ETH->DMASR = ETH_DMASR_TBUS;
/* Resume DMA transmission*/
HHD_ETH->DMATPDR = 0;
}
/* Update the ETHERNET DMA global Tx descriptor with next Tx decriptor */
/* Chained Mode */
/* Selects the next DMA Tx descriptor list for next buffer to send */
if((DMATxDescToSet->ControlBufferSize & ETH_DMATxDesc_TCH) != (uint32_t)RESET)
{
DMATxDescToSet = (ETH_DMADESCTypeDef*) (DMATxDescToSet->Buffer2NextDescAddr);
}
p = RT_NULL;
/* Check if the descriptor is owned by the ETHERNET DMA (when set) or CPU (when reset) */
if(((DMARxDescToGet->Status & ETH_DMARxDesc_OWN) != (uint32_t)RESET))
return p;
if (((DMARxDescToGet->Status & ETH_DMARxDesc_ES) == (uint32_t)RESET) &&
((DMARxDescToGet->Status & ETH_DMARxDesc_LS) != (uint32_t)RESET) &&
((DMARxDescToGet->Status & ETH_DMARxDesc_FS) != (uint32_t)RESET))
{
/* Get the Frame Length of the received packet: substruct 4 bytes of the CRC */
framelength = ((DMARxDescToGet->Status & ETH_DMARxDesc_FL) >> ETH_DMARXDESC_FRAME_LENGTHSHIFT) - 4;
//rt_kprintf("%pkg len %d\n", framelength);
/* allocate buffer */
p = pbuf_alloc(PBUF_LINK, framelength, PBUF_RAM);
if (p != RT_NULL)
{
struct pbuf* q;
for (q = p; q != RT_NULL; q= q->next)
{
/* Copy the received frame into buffer from memory pointed by the current ETHERNET DMA Rx descriptor */
memcpy(q->payload, (uint8_t *)((DMARxDescToGet->Buffer1Addr) + offset), q->len);
offset += q->len;
}
}
}
/* Set Own bit of the Rx descriptor Status: gives the buffer back to ETHERNET DMA */
DMARxDescToGet->Status = ETH_DMARxDesc_OWN;
/* When Rx Buffer unavailable flag is set: clear it and resume reception */
if ((HHD_ETH->DMASR & ETH_DMASR_RBUS) != (uint32_t)RESET)
{
/* Clear RBUS ETHERNET DMA flag */
HHD_ETH->DMASR = ETH_DMASR_RBUS;
/* Resume DMA reception */
HHD_ETH->DMARPDR = 0;
}
/* Update the ETHERNET DMA global Rx descriptor with next Rx decriptor */
/* Chained Mode */
if((DMARxDescToGet->ControlBufferSize & ETH_DMARxDesc_RCH) != (uint32_t)RESET)
{
/* Selects the next DMA Rx descriptor list for next buffer to read */
DMARxDescToGet = (ETH_DMADESCTypeDef*) (DMARxDescToGet->Buffer2NextDescAddr);
}
else /* Ring Mode */
{
if((DMARxDescToGet->ControlBufferSize & ETH_DMARxDesc_RER) != (uint32_t)RESET)
{
/* Selects the first DMA Rx descriptor for next buffer to read: last Rx descriptor was used */
DMARxDescToGet = (ETH_DMADESCTypeDef*) (HHD_ETH->DMARDLAR);
}
else
{
/* Selects the next DMA Rx descriptor list for next buffer to read */
DMARxDescToGet = (ETH_DMADESCTypeDef*) ((uint32_t)DMARxDescToGet + 0x10 + ((HHD_ETH->DMABMR & ETH_DMABMR_DSL) >> 2));
}
}
eth_device_init(&(stm32_eth_device.parent), "NT");
struct netif* netif;
netif = (struct netif*) rt_malloc (sizeof(struct netif));
if (netif == RT_NULL)
{
rt_kprintf("malloc netif failed\n");
return -RT_ERROR;
}
rt_memset(netif, 0, sizeof(struct netif));
dev->netif = netif;
/* register to rt-thread device manager */
rt_device_register(&(dev->parent), name, RT_DEVICE_FLAG_RDWR);
dev->parent.type = RT_Device_Class_NetIf;
rt_sem_init(&(dev->tx_ack), name, 0, RT_IPC_FLAG_FIFO);
/* set name */
netif->name[0] = name[0];//N
netif->name[1] = name[1];//T
/* set hw address to 6 */
netif->hwaddr_len = 6;
/* maximum transfer unit */
netif->mtu = ETHERNET_MTU;
/* broadcast capability */
netif->flags = NETIF_FLAG_BROADCAST | NETIF_FLAG_ETHARP;
/* get hardware address */
rt_device_control(&(dev->parent), NIOCTL_GADDR, netif->hwaddr);
/* set output */
netif->output = etharp_output;
netif->linkoutput = ethernetif_linkoutput;
参考3.1.1。
在调用rt_stm32_eth_init时,会将MAC地址写入到相应的寄存器中。
enet_mac_address_set(ENET_MAC_ADDRESS0, (uint8_t*)&stm32_eth->dev_addr[0]);//netif->hwaddr
low_level_init();
参考3.1.2。
(1)初始化
/* Initialize Tx Descriptors list: Chain Mode */
enet_descriptors_chain_init(ENET_DMA_TX);
/* Initialize Rx Descriptors list: Chain Mode */
enet_descriptors_chain_init(ENET_DMA_RX);
(2)启用 DMA 接收描述块的 接收中断标志。
/* enable ethernet Rx interrrupt */
{ int i;
for(i=0; i<ENET_RXBUF_NUM; i++){
enet_rx_desc_immediate_receive_complete_interrupt(&rxdesc_tab[i]);
}
}
/* Enable MAC and DMA transmission and reception */
enet_enable();
void enet_enable(void)
{
enet_tx_enable();
enet_rx_enable();
}
uint8_t *buffer = (uint8_t *)(enet_desc_information_get(dma_current_txdesc, TXDESC_BUFFER_1_ADDR));
uint32_t enet_desc_information_get(enet_descriptors_struct *desc, enet_descstate_enum info_get)
{
uint32_t reval = 0xFFFFFFFFU;
switch(info_get){
case RXDESC_BUFFER_1_SIZE:
reval = GET_RDES1_RB1S(desc->control_buffer_size);
break;
case RXDESC_BUFFER_2_SIZE:
reval = GET_RDES1_RB2S(desc->control_buffer_size);
break;
case RXDESC_FRAME_LENGTH:
reval = GET_RDES0_FRML(desc->status);
if(reval > 4U){
reval = reval - 4U;
/* if is a type frame, and CRC is not included in forwarding frame */
if((RESET != (ENET_MAC_CFG & ENET_MAC_CFG_TFCD)) && (RESET != (desc->status & ENET_RDES0_FRMT))){
reval = reval + 4U;
}
}else{
reval = 0U;
}
break;
case RXDESC_BUFFER_1_ADDR:
reval = desc->buffer1_addr;
break;
case TXDESC_BUFFER_1_ADDR:
reval = desc->buffer1_addr;
break;
case TXDESC_COLLISION_COUNT:
reval = GET_TDES0_COCNT(desc->status);
break;
default:
break;
}
return reval;
}
for(q = p; q != NULL; q = q->next)
{
memcpy((rt_uint8_t*)&buffer[offset], q->payload, q->len);
offset = offset + q->len;
}
参考3.2.3。
ETH_TxPkt_ChainMode(offset);
uint32_t ETH_TxPkt_ChainMode(uint16_t FrameLength)
{
return ENET_NOCOPY_FRAME_TRANSMIT(FrameLength);
}
/* init p pointer */
p = RT_NULL;
/* 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;
}
}
ENET_NOCOPY_FRAME_RECEIVE();//enet_frame_receive(NULL, 0U)