本人正进行LwIP的编程学习,发现在探索者开发板用STM32CubeMX完成STM32F407和LAN8720的配置设计十分便利,先利用网上他人分享的配置步骤生成的程序框架,经Keil编译后下载到开发板,一连上网线就可以ping通。和所有经历过的人一样都会遇到两个现实问题:一个是初始化时忘记插网线,会导致初始化失败,后续的TCP服务无法进行;二是连接中出现断线的情况,也会导致连接失败,即使再次连好网线也会造成后续通信故障。本帖重点分享本人通过试验、调试的初始化时未联网线的软件处理方法,连线后的断线处理网上已有有效地解决方法,本帖不赘述。
初始化时未联网线的处理方法网上实例不多,而且本人也未遇到他人介绍HAL库环境下的处理方法,因此,本人只能通过读代码和调试跟踪的方式来寻求解决方法。
由于未联网线就进行初始化会导致后续服务无法正常进行,一般情况都是必须等待网线连接正常后再次初始化ETH及LwIP才能解决。本人解决的方法是在ETH初始化程序中插入自己的代码,在检测到网线未连接时,循环进行ETH初始化,直到网线联通位置。代码的插入位置也必须有讲究,首先必须位于用户安全区,否则再次用STM32CubeMX生成代码的时候会被系统覆盖;另外就是不能影响系统程序分配的内存,否则可能引起重复申请内存,导致内存溢出。本人修改源码插入自己代码的文件选择由MX_LWIP_Init()调用的ethernetif.c文件包含负责ETH的初始化工作函数low_level_init(),其原始代码为:
static void low_level_init(struct netif *netif)
{
HAL_StatusTypeDef hal_eth_init_status;
/* Init ETH */
uint8_t MACAddr[6] ;
heth.Instance = ETH;
heth.Init.AutoNegotiation = ETH_AUTONEGOTIATION_ENABLE;
heth.Init.PhyAddress = LAN8720A_PHY_ADDRESS;
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.RxMode = ETH_RXINTERRUPT_MODE;
heth.Init.ChecksumMode = ETH_CHECKSUM_BY_HARDWARE;
heth.Init.MediaInterface = ETH_MEDIA_INTERFACE_RMII;
/* USER CODE BEGIN MACADDRESS */
/* USER CODE END MACADDRESS */
hal_eth_init_status = HAL_ETH_Init(&heth);
if (hal_eth_init_status == HAL_OK)
{
/* Set netif link flag */
netif->flags |= NETIF_FLAG_LINK_UP;
}
其中,函数内的 hal_eth_init_status = HAL_ETH_Init(&heth);负责检测网线的连接及自动协商功能,只影响部分寄存器,不牵涉内存分配的问题。该函数HAL_ETH_Init在连线正常的情况下返回值为HAL_OK,其他情况下当然是非HAL_OK啦。本人插入的二行语句位于/* USER CODE BEGIN MACADDRESS */和/* USER CODE END MACADDRESS */之间,可以不被STM32CubeM再次生成新文件是清除掉。插入的二行代码是hal_eth_init_status = HAL_ERROR;while(hal_eth_init_status != HAL_OK),这样一来新代码和源程序合称为
/* USER CODE BEGIN MACADDRESS */
hal_eth_init_status = HAL_ERROR; // 使hal_eth_init_status为非HAL_OK,使得至少运行一次HAL_ETH_Init。Keil4.74可以不省略这行代码,hal_eth_init_status初值为0x9D,不影响循环。而Keil5缺了这行会发出警告,本人未在Keil5下具体调试,不能确定缺少这一行的后果。
while(hal_eth_init_status != HAL_OK) //利用此行循环语句使的下一条hal_eth_init_status = HAL_ETH_Init(&heth);成为循环体
/* USER CODE END MACADDRESS */
hal_eth_init_status = HAL_ETH_Init(&heth); // 这条语句被循环执行,直到网线连线正常
使得如果HAL_ETH_Init函数的返回值不为HAL_OK的话,hal_eth_init_status = HAL_ETH_Init(&heth)语句成为循环体被有条件循环执行,直到网线正常连上hal_eth_init_status == HAL_OK为止,程序正常完成初始化工作。
还应注意一点,在无系统的环境下,该循环可能导致总程序无法继续,而有系统的情况下,执行MX_LWIP_Init()的任务优先级必须设为较低,才能让其他任务正常运行。 |