当前位置:   article > 正文

LWIP学习系列(二):STM32中ETH外设的配置与LWIP的结合使用_lwip光纤调试 stm32

lwip光纤调试 stm32

目录

一、STM32中ETH外设的配置流程(HAL库)

(1)ETH大致初始化与使用流程

(2)访问外部PHY寄存器相关函数

二、LWIP关于ethernet的底层驱动移植

(1)LWIP网卡需要由用户实现的函数部分

(2)ethernetif_init 函数相关内容整理

(3)ethernetif_input 函数相关整理

(4)low_level_init 相关内容整理

(5)low_level_input 相关内容整理

(6)low_level_output 相关内容整理

三、总结


一、STM32中ETH外设的配置流程(HAL库

(1)ETH大致初始化与使用流程

  1. 声明 ETH_HandleTypeDef hethETH外设句柄
  2. 对ETH句柄根据实际情况进行赋值、然后调用 HAL_ETH_Init() 来初始ETH外设(MAC,DMA, ......)
  3. 通过 HAL_ETH_MspInit() 来初始化ETH的底层资源:(1)ETH时钟ETH的GPIO时钟 (2)ETH的GPIO管脚(3)ETH的中断向量NVIC       
  4. 初始化ETH DMA 描述符 并指向分配好的buffer 
    1. HAL_ETH_DMATxDescListInit();
    2. HAL_ETH_DMARxDescListInit();
  5.  启动ETH外设           
    HAL_ETH_Start();
  6. 接受数据帧或者发送数据帧
    1. 发送:HAL_ETH_TransmitFrame();
    2. 接收:HAL_ETH_GetReceivedFrame();(应该放入死循环中,不停接受数据)
    3. 从中断中接收:HAL_ETH_GetReceivedFrame_IT();
    4.                                                                                                

(2)访问外部PHY寄存器相关函数

  1. 读取PHY 寄存器函数:
    HAL_ETH_ReadPHYRegister();
  2. 写PHY 指定寄存器函数:
    HAL_ETH_WritePHYRegister();
  3. 初始化ETH后,调整ethernet MAC函数
    HAL_ETH_ConfigMAC(); 
  4. 初始化ETH后,调整ETH DMA函数
    HAL_ETH_ConfigDMA();

二、LWIP关于ethernet的底层驱动移植

(1)LWIP网卡需要由用户实现的函数部分

注:LWIP提供了有关网卡接口的一系列函数需要用户自己实现。

需要用户自己实现的内容有:

  1. err_t  ethernetif_init(struct netif *netif) 【网卡初始化函数,具体初始化由 low_level_init 来实现
  2. void  ethernetif_input(struct netif *netif); 【从网卡中读取接收到的数据,具体接收函数由low_level_input来实现
  3. void low_level_init(struct netif *netif) 【网卡的底层初始化函数】

  4. struct pbuf * low_level_input(struct netif *netif)【网卡的底层接收函数】

  5. err_t low_level_output(struct netif *netif, struct pbuf *p)【网卡的底层发送函数】

(2)ethernetif_init 函数相关内容整理

ethernetif_init  函数,主要是给netif 网卡结构体进行赋值,将底层的输入函数传给netif 网卡结构体中

  • STM32CubeMX生成的lwIP ethernetif_init
  1. err_t ethernetif_init(struct netif *netif)
  2. {
  3. LWIP_ASSERT("netif != NULL", (netif != NULL));
  4. #if LWIP_NETIF_HOSTNAME
  5. /* Initialize interface hostname */
  6. netif->hostname = "lwip";
  7. #endif /* LWIP_NETIF_HOSTNAME */
  8. netif->name[0] = IFNAME0;
  9. netif->name[1] = IFNAME1;
  10. /* We directly use etharp_output() here to save a function call.
  11. * You can instead declare your own function an call etharp_output()
  12. * from it if you have to do some checks before sending (e.g. if link
  13. * is available...) */
  14. #if LWIP_IPV4
  15. #if LWIP_ARP || LWIP_ETHERNET
  16. #if LWIP_ARP
  17. netif->output = etharp_output;
  18. #else
  19. /* The user should write ist own code in low_level_output_arp_off function */
  20. netif->output = low_level_output_arp_off;
  21. #endif /* LWIP_ARP */
  22. #endif /* LWIP_ARP || LWIP_ETHERNET */
  23. #endif /* LWIP_IPV4 */
  24. #if LWIP_IPV6
  25. netif->output_ip6 = ethip6_output;
  26. #endif /* LWIP_IPV6 */
  27. netif->linkoutput = low_level_output;
  28. /* initialize the hardware */
  29. low_level_init(netif);
  30. return ERR_OK;
  31. }
  •  由lwip官方下载的示例代码
  1. err_t
  2. ethernetif_init(struct netif *netif)
  3. {
  4. struct ethernetif *ethernetif;
  5. LWIP_ASSERT("netif != NULL", (netif != NULL));
  6. ethernetif = mem_malloc(sizeof(struct ethernetif));
  7. if (ethernetif == NULL) {
  8. LWIP_DEBUGF(NETIF_DEBUG, ("ethernetif_init: out of memory\n"));
  9. return ERR_MEM;
  10. }
  11. #if LWIP_NETIF_HOSTNAME
  12. /* Initialize interface hostname */
  13. netif->hostname = "lwip";
  14. #endif /* LWIP_NETIF_HOSTNAME */
  15. /*
  16. * Initialize the snmp variables and counters inside the struct netif.
  17. * The last argument should be replaced with your link speed, in units
  18. * of bits per second.
  19. */
  20. MIB2_INIT_NETIF(netif, snmp_ifType_ethernet_csmacd, LINK_SPEED_OF_YOUR_NETIF_IN_BPS);
  21. netif->state = ethernetif;
  22. netif->name[0] = IFNAME0;
  23. netif->name[1] = IFNAME1;
  24. /* We directly use etharp_output() here to save a function call.
  25. * You can instead declare your own function an call etharp_output()
  26. * from it if you have to do some checks before sending (e.g. if link
  27. * is available...) */
  28. #if LWIP_IPV4
  29. netif->output = etharp_output;
  30. #endif /* LWIP_IPV4 */
  31. #if LWIP_IPV6
  32. netif->output_ip6 = ethip6_output;
  33. #endif /* LWIP_IPV6 */
  34. netif->linkoutput = low_level_output;
  35. ethernetif->ethaddr = (struct eth_addr *) & (netif->hwaddr[0]);
  36. /* initialize the hardware */
  37. low_level_init(netif);
  38. return ERR_OK;
  39. }

小结:由上面两种程序对比,可以看出大同小异。基本上都是对netif 网卡结构体进行赋值,然后真正的初始化交由low_level_init 来进行。

(3)ethernetif_input 函数相关整理

ethernetif_input  主要是用于接收eth传来的数据包。

  • 在RTOS中,一般需要设置一个优先级很高的线程来一直循环调用该函数(主要是循环调用其真正的接收实现函数low_level_input
  • 在裸机环境中,一般设置在主函数中设置死循环调用该函数。
  • STM32CubeMX生成的lwIP的 ethernetif_input
  1. void ethernetif_input(void const * argument)
  2. {
  3. struct pbuf *p;
  4. struct netif *netif = (struct netif *) argument;
  5. for( ;; )
  6. {
  7. if (osSemaphoreWait(s_xSemaphore, TIME_WAITING_FOR_INPUT) == osOK)
  8. {
  9. do
  10. {
  11. p = low_level_input( netif );
  12. if (p != NULL)
  13. {
  14. if (netif->input( p, netif) != ERR_OK )
  15. {
  16. pbuf_free(p);
  17. }
  18. }
  19. } while(p!=NULL);
  20. }
  21. }
  22. }
  • lwIP官网下载的示例代码
  1. static void
  2. ethernetif_input(struct netif *netif)
  3. {
  4. struct ethernetif *ethernetif;
  5. struct eth_hdr *ethhdr;
  6. struct pbuf *p;
  7. ethernetif = netif->state;
  8. /* move received packet into a new pbuf */
  9. p = low_level_input(netif);
  10. /* if no packet could be read, silently ignore this */
  11. if (p != NULL) {
  12. /* pass all packets to ethernet_input, which decides what packets it supports */
  13. if (netif->input(p, netif) != ERR_OK) {
  14. LWIP_DEBUGF(NETIF_DEBUG, ("ethernetif_input: IP input error\n"));
  15. pbuf_free(p);
  16. p = NULL;
  17. }
  18. }
  19. }

小结:对比上面两种程序,可以发现也是大同小异。真正的接收函数是由low_level_input 来实现。同时在带有RTOS的情况下,是将ethernetif_input 当成一个线程一直进行,通过对信号量资源的检测来判断是否数据传入,然后再将通过low_level_input 来接收数据。而lwip官网的程序,是不带操作系统的例程,所以直接交由low_level_input 来接收数据,如果要一直接收数据,则需要将ethernetif_input 放入死循环中。

(4)low_level_init 相关内容整理

low_level_init 主要任务

  • 主要是对STM32中的ETH外设进行初始化(较为具体的流程可以查看上面的ETH配置流程
  • 然后继续对 netif 网卡结构体 进行初始化赋值操作
  • 创建 二值信号量 Semaphore 用于 ethernetif_input 网卡接收线程使用
  • 然后创建 ethernetif_input  最高优先级的线程,使能ETH
  • (然后看情况配置ETH的寄存器)

注:其实就大致四个部分(带RTOS情况下) STM32的ETH外设初始化netif网卡结构体初始化、ETH数据接收线程(看需求)ETH寄存器进行的设置

  • STM32CubeMX生成的lwIP的 low_level_init
  1. static void low_level_init(struct netif *netif)
  2. {
  3. uint32_t regvalue = 0;
  4. HAL_StatusTypeDef hal_eth_init_status;
  5. /* Init ETH */
  6. uint8_t MACAddr[6] ;
  7. heth.Instance = ETH;
  8. heth.Init.AutoNegotiation = ETH_AUTONEGOTIATION_ENABLE;
  9. heth.Init.PhyAddress = LAN8742A_PHY_ADDRESS;
  10. MACAddr[0] = 0x00;
  11. MACAddr[1] = 0x80;
  12. MACAddr[2] = 0xE1;
  13. MACAddr[3] = 0x00;
  14. MACAddr[4] = 0x00;
  15. MACAddr[5] = 0x00;
  16. heth.Init.MACAddr = &MACAddr[0];
  17. heth.Init.RxMode = ETH_RXINTERRUPT_MODE;
  18. heth.Init.ChecksumMode = ETH_CHECKSUM_BY_HARDWARE;
  19. heth.Init.MediaInterface = ETH_MEDIA_INTERFACE_RMII;
  20. /* USER CODE BEGIN MACADDRESS */
  21. /* USER CODE END MACADDRESS */
  22. hal_eth_init_status = HAL_ETH_Init(&heth);
  23. if (hal_eth_init_status == HAL_OK)
  24. {
  25. /* Set netif link flag */
  26. netif->flags |= NETIF_FLAG_LINK_UP;
  27. }
  28. /* Initialize Tx Descriptors list: Chain Mode */
  29. HAL_ETH_DMATxDescListInit(&heth, DMATxDscrTab, &Tx_Buff[0][0], ETH_TXBUFNB);
  30. /* Initialize Rx Descriptors list: Chain Mode */
  31. HAL_ETH_DMARxDescListInit(&heth, DMARxDscrTab, &Rx_Buff[0][0], ETH_RXBUFNB);
  32. #if LWIP_ARP || LWIP_ETHERNET
  33. /* set MAC hardware address length */
  34. netif->hwaddr_len = ETH_HWADDR_LEN;
  35. /* set MAC hardware address */
  36. netif->hwaddr[0] = heth.Init.MACAddr[0];
  37. netif->hwaddr[1] = heth.Init.MACAddr[1];
  38. netif->hwaddr[2] = heth.Init.MACAddr[2];
  39. netif->hwaddr[3] = heth.Init.MACAddr[3];
  40. netif->hwaddr[4] = heth.Init.MACAddr[4];
  41. netif->hwaddr[5] = heth.Init.MACAddr[5];
  42. /* maximum transfer unit */
  43. netif->mtu = 1500;
  44. /* Accept broadcast address and ARP traffic */
  45. /* don't set NETIF_FLAG_ETHARP if this device is not an ethernet one */
  46. #if LWIP_ARP
  47. netif->flags |= NETIF_FLAG_BROADCAST | NETIF_FLAG_ETHARP;
  48. #else
  49. netif->flags |= NETIF_FLAG_BROADCAST;
  50. #endif /* LWIP_ARP */
  51. /* create a binary semaphore used for informing ethernetif of frame reception */
  52. osSemaphoreDef(SEM);
  53. s_xSemaphore = osSemaphoreCreate(osSemaphore(SEM), 1);
  54. /* create the task that handles the ETH_MAC */
  55. osThreadDef(EthIf, ethernetif_input, osPriorityRealtime, 0, INTERFACE_THREAD_STACK_SIZE);
  56. osThreadCreate (osThread(EthIf), netif);
  57. /* Enable MAC and DMA transmission and reception */
  58. HAL_ETH_Start(&heth);
  59. /* USER CODE BEGIN PHY_PRE_CONFIG */
  60. /* USER CODE END PHY_PRE_CONFIG */
  61. /* Read Register Configuration */
  62. HAL_ETH_ReadPHYRegister(&heth, PHY_ISFR, &regvalue);
  63. regvalue |= (PHY_ISFR_INT4);
  64. /* Enable Interrupt on change of link status */
  65. HAL_ETH_WritePHYRegister(&heth, PHY_ISFR , regvalue );
  66. /* Read Register Configuration */
  67. HAL_ETH_ReadPHYRegister(&heth, PHY_ISFR , &regvalue);
  68. /* USER CODE BEGIN PHY_POST_CONFIG */
  69. /* USER CODE END PHY_POST_CONFIG */
  70. #endif /* LWIP_ARP || LWIP_ETHERNET */
  71. /* USER CODE BEGIN LOW_LEVEL_INIT */
  72. /* USER CODE END LOW_LEVEL_INIT */
  73. }
  • lwIP官网下载的示例代码
  1. low_level_init(struct netif *netif)
  2. {
  3. struct ethernetif *ethernetif = netif->state;
  4. /* set MAC hardware address length */
  5. netif->hwaddr_len = ETHARP_HWADDR_LEN;
  6. /* set MAC hardware address */
  7. netif->hwaddr[0] = ;
  8. ...
  9. netif->hwaddr[5] = ;
  10. /* maximum transfer unit */
  11. netif->mtu = 1500;
  12. /* device capabilities */
  13. /* don't set NETIF_FLAG_ETHARP if this device is not an ethernet one */
  14. netif->flags = NETIF_FLAG_BROADCAST | NETIF_FLAG_ETHARP | NETIF_FLAG_LINK_UP;
  15. #if LWIP_IPV6 && LWIP_IPV6_MLD
  16. /*
  17. * For hardware/netifs that implement MAC filtering.
  18. * All-nodes link-local is handled by default, so we must let the hardware know
  19. * to allow multicast packets in.
  20. * Should set mld_mac_filter previously. */
  21. if (netif->mld_mac_filter != NULL) {
  22. ip6_addr_t ip6_allnodes_ll;
  23. ip6_addr_set_allnodes_linklocal(&ip6_allnodes_ll);
  24. netif->mld_mac_filter(netif, &ip6_allnodes_ll, NETIF_ADD_MAC_FILTER);
  25. }
  26. #endif /* LWIP_IPV6 && LWIP_IPV6_MLD */
  27. /* Do whatever else is needed to initialize interface. */
  28. }

小结:对比两种程序,可以看到注释中大致的流程是相同的。基本上是都是 STM32ETH外设初始化、 继续对netif 网卡结构体的初始化、(信号量的创建与ETH接收数据线程的创建、 ETH寄存器部分位修改及使能)

(5)low_level_input 相关内容整理

low_level_input 主要任务

  • 通过STM32 ETH外设的 HAL_ETH_GetReceivedFrame_IT接收从以太网接口传来的数据包
  • 将接收到的数据包封装成pbuf的形式(最终需要返回该pbuf的地址
  • 释放 DMA 接收描述符(为下一次接收做准备)
  • STM32CubeMX生成的lwIP的 low_level_input
  1. static struct pbuf * low_level_input(struct netif *netif)
  2. {
  3. struct pbuf *p = NULL;
  4. struct pbuf *q = NULL;
  5. uint16_t len = 0;
  6. uint8_t *buffer;
  7. __IO ETH_DMADescTypeDef *dmarxdesc;
  8. uint32_t bufferoffset = 0;
  9. uint32_t payloadoffset = 0;
  10. uint32_t byteslefttocopy = 0;
  11. uint32_t i=0;
  12. /* get received frame */
  13. if (HAL_ETH_GetReceivedFrame_IT(&heth) != HAL_OK)
  14. return NULL;
  15. /* Obtain the size of the packet and put it into the "len" variable. */
  16. len = heth.RxFrameInfos.length;
  17. buffer = (uint8_t *)heth.RxFrameInfos.buffer;
  18. if (len > 0)
  19. {
  20. /* We allocate a pbuf chain of pbufs from the Lwip buffer pool */
  21. p = pbuf_alloc(PBUF_RAW, len, PBUF_POOL);
  22. }
  23. if (p != NULL)
  24. {
  25. dmarxdesc = heth.RxFrameInfos.FSRxDesc;
  26. bufferoffset = 0;
  27. for(q = p; q != NULL; q = q->next)
  28. {
  29. byteslefttocopy = q->len;
  30. payloadoffset = 0;
  31. /* Check if the length of bytes to copy in current pbuf is bigger than Rx buffer size*/
  32. while( (byteslefttocopy + bufferoffset) > ETH_RX_BUF_SIZE )
  33. {
  34. /* Copy data to pbuf */
  35. memcpy( (uint8_t*)((uint8_t*)q->payload + payloadoffset), (uint8_t*)((uint8_t*)buffer + bufferoffset), (ETH_RX_BUF_SIZE - bufferoffset));
  36. /* Point to next descriptor */
  37. dmarxdesc = (ETH_DMADescTypeDef *)(dmarxdesc->Buffer2NextDescAddr);
  38. buffer = (uint8_t *)(dmarxdesc->Buffer1Addr);
  39. byteslefttocopy = byteslefttocopy - (ETH_RX_BUF_SIZE - bufferoffset);
  40. payloadoffset = payloadoffset + (ETH_RX_BUF_SIZE - bufferoffset);
  41. bufferoffset = 0;
  42. }
  43. /* Copy remaining data in pbuf */
  44. memcpy( (uint8_t*)((uint8_t*)q->payload + payloadoffset), (uint8_t*)((uint8_t*)buffer + bufferoffset), byteslefttocopy);
  45. bufferoffset = bufferoffset + byteslefttocopy;
  46. }
  47. }
  48. /* Release descriptors to DMA */
  49. /* Point to first descriptor */
  50. dmarxdesc = heth.RxFrameInfos.FSRxDesc;
  51. /* Set Own bit in Rx descriptors: gives the buffers back to DMA */
  52. for (i=0; i< heth.RxFrameInfos.SegCount; i++)
  53. {
  54. dmarxdesc->Status |= ETH_DMARXDESC_OWN;
  55. dmarxdesc = (ETH_DMADescTypeDef *)(dmarxdesc->Buffer2NextDescAddr);
  56. }
  57. /* Clear Segment_Count */
  58. heth.RxFrameInfos.SegCount =0;
  59. /* When Rx Buffer unavailable flag is set: clear it and resume reception */
  60. if ((heth.Instance->DMASR & ETH_DMASR_RBUS) != (uint32_t)RESET)
  61. {
  62. /* Clear RBUS ETHERNET DMA flag */
  63. heth.Instance->DMASR = ETH_DMASR_RBUS;
  64. /* Resume DMA reception */
  65. heth.Instance->DMARPDR = 0;
  66. }
  67. return p;
  68. }
  • lwIP官网下载的示例代码
  1. static struct pbuf *
  2. low_level_input(struct netif *netif)
  3. {
  4. struct ethernetif *ethernetif = netif->state;
  5. struct pbuf *p, *q;
  6. u16_t len;
  7. /* Obtain the size of the packet and put it into the "len"
  8. variable. */
  9. len = ;
  10. #if ETH_PAD_SIZE
  11. len += ETH_PAD_SIZE; /* allow room for Ethernet padding */
  12. #endif
  13. /* We allocate a pbuf chain of pbufs from the pool. */
  14. p = pbuf_alloc(PBUF_RAW, len, PBUF_POOL);
  15. if (p != NULL) {
  16. #if ETH_PAD_SIZE
  17. pbuf_remove_header(p, ETH_PAD_SIZE); /* drop the padding word */
  18. #endif
  19. /* We iterate over the pbuf chain until we have read the entire
  20. * packet into the pbuf. */
  21. for (q = p; q != NULL; q = q->next) {
  22. /* Read enough bytes to fill this pbuf in the chain. The
  23. * available data in the pbuf is given by the q->len
  24. * variable.
  25. * This does not necessarily have to be a memcpy, you can also preallocate
  26. * pbufs for a DMA-enabled MAC and after receiving truncate it to the
  27. * actually received size. In this case, ensure the tot_len member of the
  28. * pbuf is the sum of the chained pbuf len members.
  29. */
  30. read data into(q->payload, q->len);
  31. }
  32. acknowledge that packet has been read();
  33. MIB2_STATS_NETIF_ADD(netif, ifinoctets, p->tot_len);
  34. if (((u8_t *)p->payload)[0] & 1) {
  35. /* broadcast or multicast packet*/
  36. MIB2_STATS_NETIF_INC(netif, ifinnucastpkts);
  37. } else {
  38. /* unicast packet*/
  39. MIB2_STATS_NETIF_INC(netif, ifinucastpkts);
  40. }
  41. #if ETH_PAD_SIZE
  42. pbuf_add_header(p, ETH_PAD_SIZE); /* reclaim the padding word */
  43. #endif
  44. LINK_STATS_INC(link.recv);
  45. } else {
  46. drop packet();
  47. LINK_STATS_INC(link.memerr);
  48. LINK_STATS_INC(link.drop);
  49. MIB2_STATS_NETIF_INC(netif, ifindiscards);
  50. }
  51. return p;
  52. }

小结:可以看到两种程序的框架都是差不多的。主要都是使用底层接收函数接收数据,然后将接收到的数据封装成pbuf,以供接下来上层协议的使用。

(6)low_level_output 相关内容整理

low_level_output 主要任务

  • 将要发送的信息装填到 ETH 的 DMA 发送描述符中
  • 将数据从pbuf从拷贝到 ETH 的 DMA Tx buffer 中
  • 最后通过 HAL_ETH_TransmitFrame 将数据从 Tx buffer 中发送出去
  • STM32CubeMX生成的lwIP的 low_level_output
  1. static err_t low_level_output(struct netif *netif, struct pbuf *p)
  2. {
  3. err_t errval;
  4. struct pbuf *q;
  5. uint8_t *buffer = (uint8_t *)(heth.TxDesc->Buffer1Addr);
  6. __IO ETH_DMADescTypeDef *DmaTxDesc;
  7. uint32_t framelength = 0;
  8. uint32_t bufferoffset = 0;
  9. uint32_t byteslefttocopy = 0;
  10. uint32_t payloadoffset = 0;
  11. DmaTxDesc = heth.TxDesc;
  12. bufferoffset = 0;
  13. /* copy frame from pbufs to driver buffers */
  14. for(q = p; q != NULL; q = q->next)
  15. {
  16. /* Is this buffer available? If not, goto error */
  17. if((DmaTxDesc->Status & ETH_DMATXDESC_OWN) != (uint32_t)RESET)
  18. {
  19. errval = ERR_USE;
  20. goto error;
  21. }
  22. /* Get bytes in current lwIP buffer */
  23. byteslefttocopy = q->len;
  24. payloadoffset = 0;
  25. /* Check if the length of data to copy is bigger than Tx buffer size*/
  26. while( (byteslefttocopy + bufferoffset) > ETH_TX_BUF_SIZE )
  27. {
  28. /* Copy data to Tx buffer*/
  29. memcpy( (uint8_t*)((uint8_t*)buffer + bufferoffset), (uint8_t*)((uint8_t*)q->payload + payloadoffset), (ETH_TX_BUF_SIZE - bufferoffset) );
  30. /* Point to next descriptor */
  31. DmaTxDesc = (ETH_DMADescTypeDef *)(DmaTxDesc->Buffer2NextDescAddr);
  32. /* Check if the buffer is available */
  33. if((DmaTxDesc->Status & ETH_DMATXDESC_OWN) != (uint32_t)RESET)
  34. {
  35. errval = ERR_USE;
  36. goto error;
  37. }
  38. buffer = (uint8_t *)(DmaTxDesc->Buffer1Addr);
  39. byteslefttocopy = byteslefttocopy - (ETH_TX_BUF_SIZE - bufferoffset);
  40. payloadoffset = payloadoffset + (ETH_TX_BUF_SIZE - bufferoffset);
  41. framelength = framelength + (ETH_TX_BUF_SIZE - bufferoffset);
  42. bufferoffset = 0;
  43. }
  44. /* Copy the remaining bytes */
  45. memcpy( (uint8_t*)((uint8_t*)buffer + bufferoffset), (uint8_t*)((uint8_t*)q->payload + payloadoffset), byteslefttocopy );
  46. bufferoffset = bufferoffset + byteslefttocopy;
  47. framelength = framelength + byteslefttocopy;
  48. }
  49. /* Prepare transmit descriptors to give to DMA */
  50. HAL_ETH_TransmitFrame(&heth, framelength);
  51. errval = ERR_OK;
  52. error:
  53. /* When Transmit Underflow flag is set, clear it and issue a Transmit Poll Demand to resume transmission */
  54. if ((heth.Instance->DMASR & ETH_DMASR_TUS) != (uint32_t)RESET)
  55. {
  56. /* Clear TUS ETHERNET DMA flag */
  57. heth.Instance->DMASR = ETH_DMASR_TUS;
  58. /* Resume DMA transmission*/
  59. heth.Instance->DMATPDR = 0;
  60. }
  61. return errval;
  62. }
  • lwIP官网下载的示例代码
  1. static err_t
  2. low_level_output(struct netif *netif, struct pbuf *p)
  3. {
  4. struct ethernetif *ethernetif = netif->state;
  5. struct pbuf *q;
  6. initiate transfer();
  7. #if ETH_PAD_SIZE
  8. pbuf_remove_header(p, ETH_PAD_SIZE); /* drop the padding word */
  9. #endif
  10. for (q = p; q != NULL; q = q->next) {
  11. /* Send the data from the pbuf to the interface, one pbuf at a
  12. time. The size of the data in each pbuf is kept in the ->len
  13. variable. */
  14. send data from(q->payload, q->len);
  15. }
  16. signal that packet should be sent();
  17. MIB2_STATS_NETIF_ADD(netif, ifoutoctets, p->tot_len);
  18. if (((u8_t *)p->payload)[0] & 1) {
  19. /* broadcast or multicast packet*/
  20. MIB2_STATS_NETIF_INC(netif, ifoutnucastpkts);
  21. } else {
  22. /* unicast packet */
  23. MIB2_STATS_NETIF_INC(netif, ifoutucastpkts);
  24. }
  25. /* increase ifoutdiscards or ifouterrors on error */
  26. #if ETH_PAD_SIZE
  27. pbuf_add_header(p, ETH_PAD_SIZE); /* reclaim the padding word */
  28. #endif
  29. LINK_STATS_INC(link.xmit);
  30. return ERR_OK;
  31. }

小结:可以看出大致程序框架是差不多的。主要的流程就是先将数据拷贝到ETH的发送buffer中,然后再通过HAL_ETH_TransmitFrame 来发送数据,最后再清理一下ETH的寄存器标志位。

三、总结

  从上面的相关内容整理可以得知,lwip的提供low_level_init、low_level_input、low_level_output 的接口函数,其本质上都是通过对STM32 eth 外设的初始化、输入、输出的封装并将数据整理成pbuf的形式来进行lwip中上下层中的数据传递。

  所以,在学习lwip的过程中,首先要熟悉STM32 eth 外设的相关内容,还有eth PHY的一些信息,包括寄存器的使用,以及相关标志位的判断!!!

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/从前慢现在也慢/article/detail/618756
推荐阅读
相关标签
  

闽ICP备14008679号