工程文件已上传资源,需要可以自行下载。工程文件
原理图
功能 | IO |
---|---|
RMII_TX_EN | PB11 |
RMII_TXD0 | PG13 |
RMII_TXD1 | PG14 |
RMII_RXD0 | PC4 |
RMII_RXD1 | PC5 |
RMII_CRS_DV | PA7 |
RMII_REF_CLK | PA1 |
ETH_MDC | PC1 |
ETH_MDIO | PA2 |
ETH_RESET | PA3 |
MCO2 | PC9 |
其中LAN8742A的时钟由MCU的MCO2提供50MHZ。
STM32CubeMX工程
SYS
选择Serial Wire下载方式
RCC
这里选择MCO2位LAN8742A提供时钟源,注意MCO2需要配置成VERY_HIGH模式,即超快速模式,否则时钟源出问题,网线识别不到。
时钟树
设置如图所示,为了满足后面USB时钟为48M,这里MCO2从PLLI2SCLK取时钟。
ETH
这里选择RMII精简模式,LAN8742地址线悬空,所以设置为0。注意:这里选择RMII方式时,默认配置的PIN脚TXD0,TXD1与原理图不同。需要手动改过来。
LWIP
这里我们选择不使用DHCP,使能ICMP即可使用ping指令ping开发板。
复位引脚设置
堆栈设置
代码修改
main.c
在主函数中添加处理函数
int main(void)
{
/* USER CODE BEGIN 1 */
/* USER CODE END 1 */
/* MCU Configuration--------------------------------------------------------*/
/* Reset of all peripherals, Initializes the Flash interface and the Systick. */
HAL_Init();
/* USER CODE BEGIN Init */
/* USER CODE END Init */
/* Configure the system clock */
SystemClock_Config();
/* USER CODE BEGIN SysInit */
/* USER CODE END SysInit */
/* Initialize all configured peripherals */
MX_GPIO_Init();
MX_LWIP_Init();
/* USER CODE BEGIN 2 */
/* USER CODE END 2 */
/* Infinite loop */
/* USER CODE BEGIN WHILE */
while (1)
{
MX_LWIP_Process();
/* USER CODE END WHILE */
/* USER CODE BEGIN 3 */
}
/* USER CODE END 3 */
}
ethernetif.c
添加LAN8742复位程序
void HAL_ETH_MspInit(ETH_HandleTypeDef* ethHandle)
{
GPIO_InitTypeDef GPIO_InitStruct = {0};
if(ethHandle->Instance==ETH)
{
/* USER CODE BEGIN ETH_MspInit 0 */
/* USER CODE END ETH_MspInit 0 */
/* Enable Peripheral clock */
__HAL_RCC_ETH_CLK_ENABLE();
__HAL_RCC_GPIOC_CLK_ENABLE();
__HAL_RCC_GPIOA_CLK_ENABLE();
__HAL_RCC_GPIOB_CLK_ENABLE();
__HAL_RCC_GPIOG_CLK_ENABLE();
/**ETH GPIO Configuration
PC1 ------> ETH_MDC
PA1 ------> ETH_REF_CLK
PA2 ------> ETH_MDIO
PA7 ------> ETH_CRS_DV
PC4 ------> ETH_RXD0
PC5 ------> ETH_RXD1
PB11 ------> ETH_TX_EN
PG13 ------> ETH_TXD0
PG14 ------> ETH_TXD1
*/
GPIO_InitStruct.Pin = GPIO_PIN_1|GPIO_PIN_4|GPIO_PIN_5;
GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
GPIO_InitStruct.Alternate = GPIO_AF11_ETH;
HAL_GPIO_Init(GPIOC, &GPIO_InitStruct);
GPIO_InitStruct.Pin = GPIO_PIN_1|GPIO_PIN_2|GPIO_PIN_7;
GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
GPIO_InitStruct.Alternate = GPIO_AF11_ETH;
HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
GPIO_InitStruct.Pin = GPIO_PIN_11;
GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
GPIO_InitStruct.Alternate = GPIO_AF11_ETH;
HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);
GPIO_InitStruct.Pin = GPIO_PIN_13|GPIO_PIN_14;
GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
GPIO_InitStruct.Alternate = GPIO_AF11_ETH;
HAL_GPIO_Init(GPIOG, &GPIO_InitStruct);
/* USER CODE BEGIN ETH_MspInit 1 */
HAL_GPIO_WritePin(ETH_RESET_GPIO_Port,ETH_RESET_Pin,GPIO_PIN_RESET);
HAL_Delay(50);
HAL_GPIO_WritePin(ETH_RESET_GPIO_Port,ETH_RESET_Pin,GPIO_PIN_SET);
HAL_Delay(50);
/* USER CODE END ETH_MspInit 1 */
}
}
lwip.c
确认IP参数正确
void MX_LWIP_Init(void)
{
/* IP addresses initialization */
IP_ADDRESS[0] = 192;
IP_ADDRESS[1] = 168;
IP_ADDRESS[2] = 0;
IP_ADDRESS[3] = 10;
NETMASK_ADDRESS[0] = 255;
NETMASK_ADDRESS[1] = 255;
NETMASK_ADDRESS[2] = 255;
NETMASK_ADDRESS[3] = 0;
GATEWAY_ADDRESS[0] = 192;
GATEWAY_ADDRESS[1] = 168;
GATEWAY_ADDRESS[2] = 0;
GATEWAY_ADDRESS[3] = 1;
/* Initilialize the LwIP stack without RTOS */
lwip_init();
/* IP addresses initialization without DHCP (IPv4) */
IP4_ADDR(&ipaddr, IP_ADDRESS[0], IP_ADDRESS[1], IP_ADDRESS[2], IP_ADDRESS[3]);
IP4_ADDR(&netmask, NETMASK_ADDRESS[0], NETMASK_ADDRESS[1] , NETMASK_ADDRESS[2], NETMASK_ADDRESS[3]);
IP4_ADDR(&gw, GATEWAY_ADDRESS[0], GATEWAY_ADDRESS[1], GATEWAY_ADDRESS[2], GATEWAY_ADDRESS[3]);
/* add the network interface (IPv4/IPv6) without RTOS */
netif_add(&gnetif, &ipaddr, &netmask, &gw, NULL, ðernetif_init, ðernet_input);
/* Registers the default network interface */
netif_set_default(&gnetif);
if (netif_is_link_up(&gnetif))
{
/* When the netif is fully configured this function must be called */
netif_set_up(&gnetif);
}
else
{
/* When the netif link is down this function must be called */
netif_set_down(&gnetif);
}
/* Set the link callback function, this function is called on change of link status*/
netif_set_link_callback(&gnetif, ethernetif_update_config);
/* Create the Ethernet link handler thread */
/* USER CODE BEGIN 3 */
/* USER CODE END 3 */
}
以上程序无误之后,编译下载。接通网线到电脑端,电脑端设置静态IP与开发板在同一网段,在DOS命令下即可ping通开发板。
问题总结
在调试过程中遇到很多问题,导致开发板无法ping通。这里为大家提供一下调试思路:
- 首先确认时钟频率是否正确,示波器测量。保证REF_CLK和LAN8742A的pin5都有50M时钟。在硬件没问题的情况下,时钟源没问题,LAN8742就可以工作,此时电脑端能够识别到网线。
- 确保RMII的IO配置与原理图一致,默认的可能不同
- MCO2一定要配置成VERY_HIGH模式
- 复位引脚正确
- LAN8742A的地址线如果悬空,地址应为0
- 尽量保证CubeMX软件和库是最新的,旧版可能出问题