基于stm32cubeIDE的lwip进行TCP、UDP组播通讯
一、ETH配置
采用LAN8720A的PHY芯片,原理图为:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-iea2Tmkw-1652691553020)(LAN8720A原理图.png)]
需注意reset脚
在初始化PHY芯片前,拉高拉低下reset脚
HAL_GPIO_WritePin(GPIOC, GPIO_PIN_0, GPIO_PIN_RESET);
HAL_Delay(55);
HAL_GPIO_WritePin(GPIOC, GPIO_PIN_0, GPIO_PIN_SET);
HAL_Delay(55);
该PHY芯片采用RMII接口
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-w79kKbB3-1652691553022)(./PHY%E9%85%8D%E7%BD%AE.png)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-MBtxCjIU-1652691553023)(./PHY%E9%85%8D%E7%BD%AE1.png)]
二、配置LWIP
1、platform设置
因PHY芯片采用的是LAN8720A则,platform参数选择同系列的LAN8742
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-5d2s2N04-1652691553023)(./lwip_platform%E8%AE%BE%E7%BD%AE.png)]
2、网络配置
-
固定IP的话就配置DHCP disable
-
并配置IP地址、子网掩码,网关地址
-
开启UDP组播
首先勾选Key option里的show advantage parameters选项
只有这两项开启,才能开启IGMP模式
RawAPI进行UDP组播通讯
err_t Medom_UDP_Midcast_init(void)
{
err_t error;
ip_addr_t ipgroup_rev,ipgroup_send;//组播地址
IP4_ADDR(&ipgroup_rev, 239,255,255,1);//初始化组播收地址
IP4_ADDR(&ipgroup_send, 239,255,255,1);//初始化组播发地址
Modemudp=udp_new();//创建UDP连接
if(Modemudp==NULL)
{
goto exit;
}
error= igmp_joingroup(IP_ADDR_ANY,&ipgroup_rev);//加入组播
if(error!=ERR_OK)
{
goto exit;
}
error = udp_bind(Modemudp,IP_ADDR_ANY,ModemUdpPort);
if(error!=ERR_OK)
{
goto bind_error;
}
LogInfo("udp bind ok");
udp_recv(Modemudp,udp_server_rev,NULL);
LogInfo("udp ok");
return ERR_OK;
bind_error:
igmp_leavegroup(IP_ADDR_ANY,&ipgroup_rev);
exit:
udp_remove(Modemudp);
return -1;
}
在初始化UDP前将组播地址加入组播组,调用 igmp_joingroup(IP_ADDR_ANY,&ipgroup_rev)
还有一个坑就是,stm32HAL MAC库默认是将组播地址给过滤掉的,所以要配置下MAC,关闭组播的MAC过滤,在low_level_init函数里添加以下代码:
netif->flags |=NETIF_FLAG_IGMP;
HAL_ETH_GetMACFilterConfig(&heth,&Mac_Fliter);
Mac_Fliter.PassAllMulticast=ENABLE;
HAL_ETH_SetMACFilterConfig(&heth,&Mac_Fliter);
具体的low_leve_init函数见下:
static void low_level_init(struct netif *netif)
{
HAL_StatusTypeDef hal_eth_init_status = HAL_OK;
/* USER CODE BEGIN OS_THREAD_ATTR_CMSIS_RTOS_V2 */
osThreadAttr_t attributes;
ETH_MACFilterConfigTypeDef Mac_Fliter;
/* USER CODE END OS_THREAD_ATTR_CMSIS_RTOS_V2 */
uint32_t duplex, speed = 0;
int32_t PHYLinkState = 0;
ETH_MACConfigTypeDef MACConf = {0};
/* Start ETH HAL Init */
uint8_t MACAddr[6] ;
heth.Instance = ETH;
MACAddr[0] = 0x00;
MACAddr[1] = 0x80;
MACAddr[2] = 0xE1;
MACAddr[3] = 0x00;
MACAddr[4] = 0x00;
MACAddr[5] = 0x00;
heth.Init.MACAddr = &MACAddr[0];
heth.Init.MediaInterface = HAL_ETH_RMII_MODE;
heth.Init.TxDesc = DMATxDscrTab;
heth.Init.RxDesc = DMARxDscrTab;
heth.Init.RxBuffLen = 1536;
/* USER CODE BEGIN MACADDRESS */
HAL_GPIO_WritePin(GPIOC, GPIO_PIN_0, GPIO_PIN_RESET);
HAL_Delay(55);
HAL_GPIO_WritePin(GPIOC, GPIO_PIN_0, GPIO_PIN_SET);
HAL_Delay(55);
/* USER CODE END MACADDRESS */
hal_eth_init_status = HAL_ETH_Init(&heth);
memset(&TxConfig, 0 , sizeof(ETH_TxPacketConfig));
TxConfig.Attributes = ETH_TX_PACKETS_FEATURES_CSUM | ETH_TX_PACKETS_FEATURES_CRCPAD;
TxConfig.ChecksumCtrl = ETH_CHECKSUM_IPHDR_PAYLOAD_INSERT_PHDR_CALC;
TxConfig.CRCPadCtrl = ETH_CRC_PAD_INSERT;
/* End ETH HAL Init */
/* Initialize the RX POOL */
LWIP_MEMPOOL_INIT(RX_POOL);
#if LWIP_ARP || LWIP_ETHERNET
/* set MAC hardware address length */
netif->hwaddr_len = ETH_HWADDR_LEN;
/* set MAC hardware address */
netif->hwaddr[0] = heth.Init.MACAddr[0];
netif->hwaddr[1] = heth.Init.MACAddr[1];
netif->hwaddr[2] = heth.Init.MACAddr[2];
netif->hwaddr[3] = heth.Init.MACAddr[3];
netif->hwaddr[4] = heth.Init.MACAddr[4];
netif->hwaddr[5] = heth.Init.MACAddr[5];
/* maximum transfer unit */
netif->mtu = ETH_MAX_PAYLOAD;
/* Accept broadcast address and ARP traffic */
/* don't set NETIF_FLAG_ETHARP if this device is not an ethernet one */
#if LWIP_ARP
netif->flags |= NETIF_FLAG_BROADCAST | NETIF_FLAG_ETHARP;
#else
netif->flags |= NETIF_FLAG_BROADCAST;
#endif /* LWIP_ARP */
/* create a binary semaphore used for informing ethernetif of frame reception */
RxPktSemaphore = osSemaphoreNew(1, 1, NULL);
/* create a binary semaphore used for informing ethernetif of frame transmission */
TxPktSemaphore = osSemaphoreNew(1, 1, NULL);
/* create the task that handles the ETH_MAC */
/* USER CODE BEGIN OS_THREAD_NEW_CMSIS_RTOS_V2 */
netif->flags |=NETIF_FLAG_IGMP;
memset(&attributes, 0x0, sizeof(osThreadAttr_t));
attributes.name = "EthIf";
attributes.stack_size = INTERFACE_THREAD_STACK_SIZE;
attributes.priority = osPriorityRealtime;
osThreadNew(ethernetif_input, netif, &attributes);
/* USER CODE END OS_THREAD_NEW_CMSIS_RTOS_V2 */
/* USER CODE BEGIN PHY_PRE_CONFIG */
HAL_ETH_GetMACFilterConfig(&heth,&Mac_Fliter);
Mac_Fliter.PassAllMulticast=ENABLE;
HAL_ETH_SetMACFilterConfig(&heth,&Mac_Fliter);
/* USER CODE END PHY_PRE_CONFIG */
/* Set PHY IO functions */
LAN8742_RegisterBusIO(&LAN8742, &LAN8742_IOCtx);
/* Initialize the LAN8742 ETH PHY */
LAN8742_Init(&LAN8742);
if (hal_eth_init_status == HAL_OK)
{
PHYLinkState = LAN8742_GetLinkState(&LAN8742);
/* Get link state */
if(PHYLinkState <= LAN8742_STATUS_LINK_DOWN)
{
netif_set_link_down(netif);
netif_set_down(netif);
}
else
{
switch (PHYLinkState)
{
case LAN8742_STATUS_100MBITS_FULLDUPLEX:
duplex = ETH_FULLDUPLEX_MODE;
speed = ETH_SPEED_100M;
break;
case LAN8742_STATUS_100MBITS_HALFDUPLEX:
duplex = ETH_HALFDUPLEX_MODE;
speed = ETH_SPEED_100M;
break;
case LAN8742_STATUS_10MBITS_FULLDUPLEX:
duplex = ETH_FULLDUPLEX_MODE;
speed = ETH_SPEED_10M;
break;
case LAN8742_STATUS_10MBITS_HALFDUPLEX:
duplex = ETH_HALFDUPLEX_MODE;
speed = ETH_SPEED_10M;
break;
default:
duplex = ETH_FULLDUPLEX_MODE;
speed = ETH_SPEED_100M;
break;
}
/* Get MAC Config MAC */
HAL_ETH_GetMACConfig(&heth, &MACConf);
MACConf.DuplexMode = duplex;
MACConf.Speed = speed;
HAL_ETH_SetMACConfig(&heth, &MACConf);
HAL_ETH_Start_IT(&heth);
netif_set_up(netif);
netif_set_link_up(netif);
/* USER CODE BEGIN PHY_POST_CONFIG */
/* USER CODE END PHY_POST_CONFIG */
}
}
else
{
Error_Handler();
}
#endif /* LWIP_ARP || LWIP_ETHERNET */
/* USER CODE BEGIN LOW_LEVEL_INIT */
/* USER CODE END LOW_LEVEL_INIT */
}
这样就解除了MAC的过滤
再完善下UDP的接收RAW API接收函数就可以了