最近在工作中需要使用RTL8201F,在网上找了很多帖子,没有找到合适的,自己翻资料移植了一个。
模板工程使用的是正点原子的f407探索版的例程,原子使用的是LAN8720,需要把他的驱动修改成为我们自己用的RTL8201F。
1.将PHY_TYPE改成我们自己需要的RTL8201
图片
2.根据RTL8201芯片手册修改SR寄存器速度和模式
我们可以从手册看到,SR寄存器地址和speed和DUPLEX的比特位
根据手册修改成我们需要的值,
定义PHY_ID寄存器地址
通过读取该地址查找我们的PHY地址和判断PHY是否启动
定义页选择寄存器、RMII模式设置寄存器、省电模式寄存器
相关定义如下
3.在PHY初始化设置位置修改成我们自己的代码
//查找PHY_addrfor(int i = 0 ;i <31;i++){phyreg = 0;heth->Init.PhyAddress = i;HAL_ETH_ReadPHYRegister(heth, PHY_ID, &phyreg);if(phyreg == 0x1c){heth->Init.PhyAddress = i;break;}HAL_Delay(PHY_RESET_DELAY);}//设置页寄第七页准备配置RMII模式if((HAL_ETH_WritePHYRegister(heth,PHY_PAGE_ADDR,PHY_PAGE_7)) != HAL_OK)
{/* In case of write timeout */err = ETH_ERROR;/* Config MAC and DMA */ETH_MACDMAConfig(heth, err);/* Set the ETH peripheral state to READY */heth->State = HAL_ETH_STATE_READY;/* Return HAL_ERROR */return HAL_ERROR;
}
我的板子需要PHY提供REF_CLK,大家如果有外部时钟,可以直接填手册上写的7FFB
//设置RMII模式
if((HAL_ETH_WritePHYRegister(heth,PHY_PAGE_7_MODE,0x6ffb)) != HAL_OK){/* In case of write timeout */err = ETH_ERROR;/* Config MAC and DMA */ETH_MACDMAConfig(heth, err);/* Set the ETH peripheral state to READY */heth->State = HAL_ETH_STATE_READY;/* Return HAL_ERROR */return HAL_ERROR;}
回到第0页
if((HAL_ETH_WritePHYRegister(heth,PHY_PAGE_ADDR,0)) != HAL_OK)
{/* In case of write timeout */err = ETH_ERROR;/* Config MAC and DMA */ETH_MACDMAConfig(heth, err);/* Set the ETH peripheral state to READY */heth->State = HAL_ETH_STATE_READY;printf("ETH reset timeout!! \r\n");/* Return HAL_ERROR */return HAL_ERROR;
}
配置PMSR寄存器
![在这里插入图片描述](https://i-blog.csdnimg.cn/direct/3e5120700be04172a24269fb93c76cae.webp#pic_center)我这里的REF_CLK是OUTPUT模式需要关闭省电模式,如果大家不是则不需要配置该项
//```c
if((HAL_ETH_WritePHYRegister(heth,PHY_PSMR,0x8000)) != HAL_OK)
{/* In case of write timeout */err = ETH_ERROR;/* Config MAC and DMA */ETH_MACDMAConfig(heth, err);/* Set the ETH peripheral state to READY */heth->State = HAL_ETH_STATE_READY;printf("ETH reset timeout!! \r\n");/* Return HAL_ERROR */return HAL_ERROR;
}
4.配置ETH模式
在lwip_comm.c里的lwip_link_thread
这个函数是检测网线连接情况的
通过读取link status来判断网线是否插入
当有网线插入时,启动PHY自协模式,等待自协完成,读取PHY速度和双工模式,将对应的模式配置到ETH中,启动ETH
//
void lwip_link_thread( void * argument )
{uint32_t regval = 0;struct netif *netif = (struct netif *) argument;int link_again_num = 0;while(1){/* 读取PHY状态寄存器,获取链接信息 */HAL_ETH_ReadPHYRegister(&g_eth_handler,PHY_BSR, ®val);/* 判断链接状态 */if((regval & PHY_LINKED_STATUS) == 0){g_lwipdev.link_status = LWIP_LINK_OFF;link_again_num ++ ;if (link_again_num >= 2) /* 网线一段时间没有插入 */{continue;}else /* 关闭虚拟网卡及以太网中断 */{
#if LWIP_DHCP /* 如果使用DHCP的话 */g_lwip_dhcp_state = LWIP_DHCP_LINK_DOWN;dhcp_stop(netif);
#endifHAL_ETH_Stop(&g_eth_handler);netif_set_down(netif);netif_set_link_down(netif);}}else /* 网线插入检测 */{link_again_num = 0;
// printf("检测到有网线插入 \r\n");if (g_lwipdev.link_status == LWIP_LINK_OFF)/* 开启以太网及虚拟网卡 */{HAL_ETH_WritePHYRegister(&g_eth_handler, PHY_BCR, PHY_AUTONEGOTIATION);uint8_t timeout = 100;do{HAL_ETH_ReadPHYRegister(&g_eth_handler,PHY_BSR, ®val);vTaskDelay(1);timeout--;if(timeout==0){g_lwipdev.link_status = LWIP_LINK_OFF;goto exit;}}while(((regval & PHY_AUTONEGO_COMPLETE) != PHY_AUTONEGO_COMPLETE));HAL_ETH_ReadPHYRegister(&g_eth_handler, PHY_SR, ®val);if(regval & PHY_SPEED_STATUS){g_eth_handler.Init.Speed = ETH_SPEED_100M;}else{g_eth_handler.Init.Speed = ETH_SPEED_10M;}if(regval & PHY_DUPLEX_STATUS){g_eth_handler.Init.DuplexMode = ETH_MODE_FULLDUPLEX;}else{g_eth_handler.Init.DuplexMode = ETH_MODE_HALFDUPLEX;}g_lwipdev.link_status = LWIP_LINK_ON;HAL_ETH_Start(&g_eth_handler);netif_set_up(netif);netif_set_link_up(netif);exit:;}}vTaskDelay(100);}
}
5.设置IP
正点原子的工程默认打开DHCP,如果想使用静态IP需要在,lwipopts.h关闭
在lwip_comm.c的lwip_comm_default_ip_set函数设置成自己需要的ip
6.测试
以上步骤做完之后,编译程序下载到板子里面,我们通过串口助手可以查看到初始化信息
打开命令行PING 一下看看
可以ping通的
我们继续使用网络助手
可以连接上
串口助手页提示有ip连接到
我们的移植工作就完成了。