打开正点原子阿波罗开发板STM32H743扩展例程下RAW_TCPClient工程示例。在此工程下修改。
所用方式参考正点原子LAN8720芯片驱动的写法,工程可任意切换LAN8720和YT8512C。
新建YT8512C.c/.h文件
将YT8512C.h的寄存器声明如下:
/* Define to prevent recursive inclusion -------------------------------------*/
#ifndef YT8512C_H
#define YT8512C_H
#ifdef __cplusplus
extern "C" {
#endif
/* Includes ------------------------------------------------------------------*/
#include <stdint.h>
#include "sys.h"
extern ETH_HandleTypeDef YT8520_ETHHandle;
//以太网描述符和缓冲区
extern __attribute__((at(0x30040000))) ETH_DMADescTypeDef DMARxDscrTab[ETH_RX_DESC_CNT]; //以太网Rx DMA描述符
extern __attribute__((at(0x30040060))) ETH_DMADescTypeDef DMATxDscrTab[ETH_TX_DESC_CNT]; //以太网Tx DMA描述符
extern __attribute__((at(0x30040200))) uint8_t Rx_Buff[ETH_RX_DESC_CNT][ETH_MAX_PACKET_SIZE]; //以太网接收缓冲区
#define YT8512C_ADDR 0 //YT8520地址为0
#define YT8512C_TIMEOUT ((uint32_t)500) //YT8520超时时间
/* PHY芯片寄存器映射表 */
#define YT8512C_BCR ((uint16_t)0x0000U)
#define YT8512C_BSR ((uint16_t)0x0001U)
#define YT8512C_PHYI1R ((uint16_t)0x0002U)
#define YT8512C_PHYI2R ((uint16_t)0x0003U)
//#define PHY_REGISTER2 ((uint16_t)0x0002U)
//#define PHY_REGISTER3 ((uint16_t)0x0003U)
/* 操作SCR寄存器的值(一般不需要修改) */
#define YT8512C_BCR_SOFT_RESET ((uint16_t)0x8000U)
#define YT8512C_BCR_LOOPBACK ((uint16_t)0x4000U)
#define YT8512C_BCR_SPEED_SELECT ((uint16_t)0x2000U)
#define YT8512C_BCR_AUTONEGO_EN ((uint16_t)0x1000U)
#define YT8512C_BCR_POWER_DOWN ((uint16_t)0x0800U)
#define YT8512C_BCR_ISOLATE ((uint16_t)0x0400U)
#define YT8512C_BCR_RESTART_AUTONEGO ((uint16_t)0x0200U)
#define YT8512C_BCR_DUPLEX_MODE ((uint16_t)0x0100U)
/* 操作BSR寄存器的值(一般不需要修改) */
#define YT8512C_BSR_100BASE_T4 ((uint16_t)0x8000U)
#define YT8512C_BSR_100BASE_TX_FD ((uint16_t)0x4000U)
#define YT8512C_BSR_100BASE_TX_HD ((uint16_t)0x2000U)
#define YT8512C_BSR_10BASE_T_FD ((uint16_t)0x1000U)
#define YT8512C_BSR_10BASE_T_HD ((uint16_t)0x0800U)
#define YT8512C_BSR_100BASE_T2_FD ((uint16_t)0x0400U)
#define YT8512C_BSR_100BASE_T2_HD ((uint16_t)0x0200U)
#define YT8512C_BSR_EXTENDED_STATUS ((uint16_t)0x0100U)
#define YT8512C_BSR_AUTONEGO_CPLT ((uint16_t)0x0020U)
#define YT8512C_BSR_REMOTE_FAULT ((uint16_t)0x0010U)
#define YT8512C_BSR_AUTONEGO_ABILITY ((uint16_t)0x0008U)
#define YT8512C_BSR_LINK_STATUS ((uint16_t)0x0004U)
#define YT8512C_BSR_JABBER_DETECT ((uint16_t)0x0002U)
#define YT8512C_BSR_EXTENDED_CAP ((uint16_t)0x0001U)
/* PHY芯片进程状态 */
#define YT8512C_STATUS_READ_ERROR ((int32_t)-5)
#define YT8512C_STATUS_WRITE_ERROR ((int32_t)-4)
#define YT8512C_STATUS_ADDRESS_ERROR ((int32_t)-3)
#define YT8512C_STATUS_RESET_TIMEOUT ((int32_t)-2)
#define YT8512C_STATUS_ERROR ((int32_t)-1)
#define YT8512C_STATUS_OK ((int32_t) 0)
#define YT8512C_STATUS_LINK_DOWN ((int32_t) 1)
#define YT8512C_STATUS_100MBITS_FULLDUPLEX ((int32_t) 2)
#define YT8512C_STATUS_100MBITS_HALFDUPLEX ((int32_t) 3)
#define YT8512C_STATUS_10MBITS_FULLDUPLEX ((int32_t) 4)
#define YT8512C_STATUS_10MBITS_HALFDUPLEX ((int32_t) 5)
#define YT8512C_STATUS_AUTONEGO_NOTDONE ((int32_t) 6)
/* PHY寄存器的数量 */
#define YT8512C_PHY_COUNT ((uint16_t)0x001FU)
#define YT8512C_PHYSCSR ((uint16_t)0x11) /*!< tranceiver status register */
#define YT8512C_SPEED_STATUS ((uint16_t)0x4010) /*!< configured information of speed: 100Mbit/s */
#define YT8512C_DUPLEX_STATUS ((uint16_t)0x2000) /*!< configured information of duplex: full-duplex */
int32_t YT8512C_Init(void);
int32_t YT8512C_ReadPHY(u16 reg,u32 *regval);
int32_t YT8512C_WritePHY(u16 reg,u16 value);
void YT8512C_EnablePowerDownMode(void);
void YT8512C_DisablePowerDownMode(void);
void YT8512C_StartAutoNego(void);
void YT8512C_EnableLoopbackMode(void);
void YT8512C_DisableLoopbackMode(void);
void YT8512C_EnableIT(u32 interrupt);
void YT8512C_DisableIT(u32 interrupt);
void YT8512C_ClearIT(u32 interrupt);
u8 YT8512C_GetITStatus(u32 interrupt);
u32 YT8512C_GetLinkState(void);
void YT8512C_SetLinkState(u32 linkstate);
#ifdef __cplusplus
}
#endif
#endif /* YT8512C_H */
将YT8512C.c编写如下:
#include "lwip_comm.h"
#include "pcf8574.h"
#include "delay.h"
#include "usart.h"
#include "YT8512C.h"
#include "ethernet.h"
ETH_HandleTypeDef YT8512C_ETHHandle;
//以太网描述符和缓冲区
extern __attribute__((at(0x30040000))) ETH_DMADescTypeDef DMARxDscrTab[ETH_RX_DESC_CNT]; //以太网Rx DMA描述符
extern __attribute__((at(0x30040060))) ETH_DMADescTypeDef DMATxDscrTab[ETH_TX_DESC_CNT]; //以太网Tx DMA描述符
extern __attribute__((at(0x30040200))) uint8_t Rx_Buff[ETH_RX_DESC_CNT][ETH_MAX_PACKET_SIZE]; //以太网接收缓冲区
//初始化YT8512C
int32_t YT8512C_Init(void)
{
u8 macaddress[6];
u32 timeout=0;
u32 regval=0;
u32 phylink=0;
int32_t status=YT8512C_STATUS_OK;
PHY_ETHHandle = &YT8512C_ETHHandle;
macaddress[0]=lwipdev.mac[0];
macaddress[1]=lwipdev.mac[1];
macaddress[2]=lwipdev.mac[2];
macaddress[3]=lwipdev.mac[3];
macaddress[4]=lwipdev.mac[4];
macaddress[5]=lwipdev.mac[5];
YT8512C_ETHHandle.Instance=ETH; //ETH
YT8512C_ETHHandle.Init.MACAddr=macaddress; //mac地址
YT8512C_ETHHandle.Init.MediaInterface=HAL_ETH_RMII_MODE; //RMII接口
YT8512C_ETHHandle.Init.RxDesc=DMARxDscrTab; //发送描述符
YT8512C_ETHHandle.Init.TxDesc=DMATxDscrTab; //接收描述如
YT8512C_ETHHandle.Init.RxBuffLen=ETH_MAX_PACKET_SIZE; //接收长度
HAL_ETH_Init(&YT8512C_ETHHandle); //初始化ETH
HAL_ETH_SetMDIOClockRange(&YT8512C_ETHHandle);
if(YT8512C_WritePHY(YT8512C_BCR,YT8512C_BCR_SOFT_RESET)>=0) //YT8512C软件复位
{
//等待软件复位完成
if(YT8512C_ReadPHY(YT8512C_BCR,®val)>=0)
{
while(regval&YT8512C_BCR_SOFT_RESET)
{
if(YT8512C_ReadPHY(YT8512C_BCR,®val)<0)
{
status=YT8512C_STATUS_READ_ERROR;
break;
}
delay_ms(10);
timeout++;
if(timeout>=YT8512C_TIMEOUT) break; //超时跳出,5S
}
}
else
{
status=YT8512C_STATUS_READ_ERROR;
}
}
else
{
status=YT8512C_STATUS_WRITE_ERROR;
}
YT8512C_StartAutoNego(); //开启自动协商功能
if(status==YT8512C_STATUS_OK) //如果前面运行正常就延时1s
delay_ms(1000); //等待1s
//等待网络连接成功
timeout=0;
while(YT8512C_GetLinkState()<=YT8512C_STATUS_LINK_DOWN)
{
delay_ms(10);
timeout++;
if(timeout>=YT8512C_TIMEOUT)
{
status=YT8512C_STATUS_LINK_DOWN;
break; //超时跳出,5S
}
}
phylink=YT8512C_GetLinkState();
if(phylink==YT8512C_STATUS_100MBITS_FULLDUPLEX)
printf("YT8512C:100Mb/s FullDuplex\r\n");
else if(phylink==YT8512C_STATUS_100MBITS_HALFDUPLEX)
printf("YT8512C:100Mb/s HalfDuplex\r\n");
else if(phylink==YT8512C_STATUS_10MBITS_FULLDUPLEX)
printf("YT8512C:10Mb/s FullDuplex\r\n");
else if(phylink==YT8512C_STATUS_10MBITS_HALFDUPLEX)
printf("YT8512C:10Mb/s HalfDuplex\r\n");
return status;
}
extern void lwip_pkt_handle(void);
//读取PHY寄存器值
//reg要读取的寄存器地址
//返回值:0 读取成功,-1 读取失败
int32_t YT8512C_ReadPHY(u16 reg,u32 *regval)
{
if(HAL_ETH_ReadPHYRegister(&YT8512C_ETHHandle,YT8512C_ADDR,reg,regval)!=HAL_OK)
return -1;
return 0;
}
//向YT8512C指定寄存器写入值
//reg:要写入的寄存器
//value:要写入的值
//返回值:0 写入正常,-1 写入失败
int32_t YT8512C_WritePHY(u16 reg,u16 value)
{
u32 temp=value;
if(HAL_ETH_WritePHYRegister(&YT8512C_ETHHandle,YT8512C_ADDR,reg,temp)!=HAL_OK)
return -1;
return 0;
}
//打开YT8512C Power Down模式
void YT8512C_EnablePowerDownMode(void)
{
u32 readval=0;
YT8512C_ReadPHY(YT8512C_BCR,&readval);
readval|=YT8512C_BCR_POWER_DOWN;
YT8512C_WritePHY(YT8512C_BCR,readval);
}
//关闭YT8512C Power Down模式
void YT8512C_DisablePowerDownMode(void)
{
u32 readval=0;
YT8512C_ReadPHY(YT8512C_BCR,&readval);
readval&=~YT8512C_BCR_POWER_DOWN;
YT8512C_WritePHY(YT8512C_BCR,readval);
}
//开启YT8512C的自协商功能
void YT8512C_StartAutoNego(void)
{
u32 readval=0;
YT8512C_ReadPHY(YT8512C_BCR,&readval);
readval|=YT8512C_BCR_AUTONEGO_EN;
YT8512C_WritePHY(YT8512C_BCR,readval);
}
//使能回测模式
void YT8512C_EnableLoopbackMode(void)
{
u32 readval=0;
YT8512C_ReadPHY(YT8512C_BCR,&readval);
readval|=YT8512C_BCR_LOOPBACK;
YT8512C_WritePHY(YT8512C_BCR,readval);
}
//关闭YT8512C的回测模式
void YT8512C_DisableLoopbackMode(void)
{
u32 readval=0;
YT8512C_ReadPHY(YT8512C_BCR,&readval);
readval&=~YT8512C_BCR_LOOPBACK;
YT8512C_WritePHY(YT8512C_BCR,readval);
}
//获取YT8512C的连接状态
//返回值:YT8512C_STATUS_LINK_DOWN 连接断开
// YT8512C_STATUS_AUTONEGO_NOTDONE 自动协商完成
// YT8512C_STATUS_100MBITS_FULLDUPLEX 100M全双工
// YT8512C_STATUS_100MBITS_HALFDUPLEX 100M半双工
// YT8512C_STATUS_10MBITS_FULLDUPLEX 10M全双工
// YT8512C_STATUS_10MBITS_HALFDUPLEX 10M半双工
u32 YT8512C_GetLinkState(void)
{
u32 readval=0;
//读取两遍,确保读取正确!!!
YT8512C_ReadPHY(YT8512C_BSR,&readval);
YT8512C_ReadPHY(YT8512C_BSR,&readval);
//获取连接状态(硬件,网线的连接,不是TCP、UDP等软件连接!)
if((readval&YT8512C_BSR_LINK_STATUS)==0)
return YT8512C_STATUS_LINK_DOWN;
//获取自动协商状态
YT8512C_ReadPHY(YT8512C_BCR,&readval);
if((readval&YT8512C_BCR_AUTONEGO_EN)!=YT8512C_BCR_AUTONEGO_EN) //未使能自动协商
{
if(((readval&YT8512C_BCR_SPEED_SELECT)==YT8512C_BCR_SPEED_SELECT)&&
((readval&YT8512C_BCR_DUPLEX_MODE)==YT8512C_BCR_DUPLEX_MODE))
return YT8512C_STATUS_100MBITS_FULLDUPLEX;
else if((readval&YT8512C_BCR_SPEED_SELECT)==YT8512C_BCR_SPEED_SELECT)
return YT8512C_STATUS_100MBITS_HALFDUPLEX;
else if((readval&YT8512C_BCR_DUPLEX_MODE)==YT8512C_BCR_DUPLEX_MODE)
return YT8512C_STATUS_10MBITS_FULLDUPLEX;
else
return YT8512C_STATUS_10MBITS_HALFDUPLEX;
}
else //使能了自动协商
{
YT8512C_ReadPHY(YT8512C_PHYSCSR,&readval);
if (((readval & YT8512C_SPEED_STATUS) != YT8512C_SPEED_STATUS) && ((readval & YT8512C_DUPLEX_STATUS) != 0))
{
return YT8512C_STATUS_100MBITS_FULLDUPLEX;
}
else if (((readval & YT8512C_SPEED_STATUS) != YT8512C_SPEED_STATUS))
{
return YT8512C_STATUS_100MBITS_HALFDUPLEX;
}
else if (((readval & YT8512C_BCR_DUPLEX_MODE) != YT8512C_BCR_DUPLEX_MODE))
{
return YT8512C_STATUS_10MBITS_FULLDUPLEX;
}
else
{
return YT8512C_STATUS_10MBITS_HALFDUPLEX;
}
}
}
//设置YT8512C的连接状态
//参数linkstate:YT8512C_STATUS_100MBITS_FULLDUPLEX 100M全双工
// YT8512C_STATUS_100MBITS_HALFDUPLEX 100M半双工
// YT8512C_STATUS_10MBITS_FULLDUPLEX 10M全双工
// YT8512C_STATUS_10MBITS_HALFDUPLEX 10M半双工
void YT8512C_SetLinkState(u32 linkstate)
{
u32 bcrvalue=0;
YT8512C_ReadPHY(YT8512C_BCR,&bcrvalue);
//关闭连接配置,比如自动协商,速度和双工
bcrvalue&=~(YT8512C_BCR_AUTONEGO_EN|YT8512C_BCR_SPEED_SELECT|YT8512C_BCR_DUPLEX_MODE);
if(linkstate==YT8512C_STATUS_100MBITS_FULLDUPLEX) //100M全双工
bcrvalue|=(YT8512C_BCR_SPEED_SELECT|YT8512C_BCR_DUPLEX_MODE);
else if(linkstate==YT8512C_STATUS_100MBITS_HALFDUPLEX) //100M半双工
bcrvalue|=YT8512C_BCR_SPEED_SELECT;
else if(linkstate==YT8512C_STATUS_10MBITS_FULLDUPLEX) //10M全双工
bcrvalue|=YT8512C_BCR_DUPLEX_MODE;
YT8512C_WritePHY(YT8512C_BCR,bcrvalue);
}
为了兼容两款PHY芯片,再创建个程序文件ethernet.c/.h
其中ethernet.h定义如下:
/* Define to prevent recursive inclusion -------------------------------------*/
#ifndef ETHERNET_H
#define ETHERNET_H
#ifdef __cplusplus
extern "C" {
#endif
/* Includes ------------------------------------------------------------------*/
#include <stdint.h>
#include "sys.h"
//#define PHY_CHIP_LAN8720
#define PHY_CHIP_YT8512
extern ETH_HandleTypeDef *PHY_ETHHandle;
//以太网描述符和缓冲区
extern __attribute__((at(0x30040000))) ETH_DMADescTypeDef DMARxDscrTab[ETH_RX_DESC_CNT]; //以太网Rx DMA描述符
extern __attribute__((at(0x30040060))) ETH_DMADescTypeDef DMATxDscrTab[ETH_TX_DESC_CNT]; //以太网Tx DMA描述符
extern __attribute__((at(0x30040200))) uint8_t Rx_Buff[ETH_RX_DESC_CNT][ETH_MAX_PACKET_SIZE]; //以太网接收缓冲区
#if defined (PHY_CHIP_YT8512)
#include "YT8512C.h"
#define PHY_CHIP_STATUS_100MBITS_FULLDUPLEX YT8512C_STATUS_100MBITS_FULLDUPLEX
#define PHY_CHIP_STATUS_100MBITS_HALFDUPLEX YT8512C_STATUS_100MBITS_HALFDUPLEX
#define PHY_CHIP_STATUS_10MBITS_FULLDUPLEX YT8512C_STATUS_10MBITS_FULLDUPLEX
#define PHY_CHIP_STATUS_10MBITS_HALFDUPLEX YT8512C_STATUS_10MBITS_HALFDUPLEX
#define PHY_CHIP_STATUS_LINK_DOWN YT8512C_STATUS_LINK_DOWN
#elif defined(PHY_CHIP_LAN8720)
#include "lan8720.h"
#define PHY_CHIP_STATUS_100MBITS_FULLDUPLEX LAN8720_STATUS_100MBITS_FULLDUPLEX
#define PHY_CHIP_STATUS_100MBITS_HALFDUPLEX LAN8720_STATUS_100MBITS_HALFDUPLEX
#define PHY_CHIP_STATUS_10MBITS_FULLDUPLEX LAN8720_STATUS_10MBITS_FULLDUPLEX
#define PHY_CHIP_STATUS_10MBITS_HALFDUPLEX LAN8720_STATUS_10MBITS_HALFDUPLEX
#define PHY_CHIP_STATUS_LINK_DOWN LAN8720_STATUS_LINK_DOWN
#endif
void NETMPU_Config(void);
int32_t Ethernet_Init(void);
#ifdef __cplusplus
}
#endif
#endif
ethernet.c代码如下:
#include "lwip_comm.h"
#include "ethernet.h"
#include "pcf8574.h"
#include "usart.h"
#include "delay.h"
ETH_HandleTypeDef *PHY_ETHHandle;
//以太网描述符和缓冲区
__attribute__((at(0x30040000))) ETH_DMADescTypeDef DMARxDscrTab[ETH_RX_DESC_CNT]; //以太网Rx DMA描述符
__attribute__((at(0x30040060))) ETH_DMADescTypeDef DMATxDscrTab[ETH_TX_DESC_CNT]; //以太网Tx DMA描述符
__attribute__((at(0x30040200))) uint8_t Rx_Buff[ETH_RX_DESC_CNT][ETH_MAX_PACKET_SIZE]; //以太网接收缓冲区
//设置网络所使用的0X30040000的ram内存保护
void NETMPU_Config(void)
{
MPU_Region_InitTypeDef MPU_InitStruct;
HAL_MPU_Disable();
MPU_InitStruct.Enable=MPU_REGION_ENABLE;
MPU_InitStruct.BaseAddress=0x30040000;
MPU_InitStruct.Size=MPU_REGION_SIZE_256B;
MPU_InitStruct.AccessPermission=MPU_REGION_FULL_ACCESS;
MPU_InitStruct.IsBufferable=MPU_ACCESS_BUFFERABLE;
MPU_InitStruct.IsCacheable=MPU_ACCESS_NOT_CACHEABLE;
MPU_InitStruct.IsShareable=MPU_ACCESS_SHAREABLE;
MPU_InitStruct.Number=MPU_REGION_NUMBER5;
MPU_InitStruct.TypeExtField=MPU_TEX_LEVEL0;
MPU_InitStruct.SubRegionDisable=0x00;
MPU_InitStruct.DisableExec=MPU_INSTRUCTION_ACCESS_ENABLE;
HAL_MPU_ConfigRegion(&MPU_InitStruct);
HAL_MPU_Enable(MPU_PRIVILEGED_DEFAULT);
}
//中断服务函数
void ETH_IRQHandler(void)
{
lwip_pkt_handle();
//清除中断标志位
__HAL_ETH_DMA_CLEAR_IT(PHY_ETHHandle,ETH_DMA_NORMAL_IT); //清除DMA中断标志位
__HAL_ETH_DMA_CLEAR_IT(PHY_ETHHandle,ETH_DMA_RX_IT); //清除DMA接收中断标志位
__HAL_ETH_DMA_CLEAR_IT(PHY_ETHHandle,ETH_DMA_TX_IT); //清除DMA接收中断标志位
}
//ETH底层驱动,引脚配置,时钟使能
//此函数会被HAL_ETH_Init()调用
//heth:ETH句柄
void HAL_ETH_MspInit(ETH_HandleTypeDef *heth)
{
GPIO_InitTypeDef GPIO_Initure;
__HAL_RCC_GPIOA_CLK_ENABLE(); //开启GPIOA时钟
__HAL_RCC_GPIOB_CLK_ENABLE(); //开启GPIOB时钟
__HAL_RCC_GPIOC_CLK_ENABLE(); //开启GPIOC时钟
__HAL_RCC_GPIOG_CLK_ENABLE(); //开启GPIOG时钟
__HAL_RCC_ETH1MAC_CLK_ENABLE(); //使能ETH1 MAC时钟
__HAL_RCC_ETH1TX_CLK_ENABLE(); //使能ETH1发送时钟
__HAL_RCC_ETH1RX_CLK_ENABLE(); //使能ETH1接收时钟
GPIO_Initure.Pin=GPIO_PIN_1|GPIO_PIN_2|GPIO_PIN_7;
GPIO_Initure.Mode=GPIO_MODE_AF_PP; //推挽复用
GPIO_Initure.Pull=GPIO_NOPULL; //不带上下拉
GPIO_Initure.Speed=GPIO_SPEED_FREQ_HIGH; //高速
GPIO_Initure.Alternate=GPIO_AF11_ETH; //复用为ETH功能
HAL_GPIO_Init(GPIOA,&GPIO_Initure); //初始化
//PB11
GPIO_Initure.Pin=GPIO_PIN_11; //PB11
HAL_GPIO_Init(GPIOB,&GPIO_Initure); //始化
//PC1,4,5
GPIO_Initure.Pin=GPIO_PIN_1|GPIO_PIN_4|GPIO_PIN_5; //PC1,4,5
HAL_GPIO_Init(GPIOC,&GPIO_Initure); //初始化
//PG13,14
GPIO_Initure.Pin=GPIO_PIN_13|GPIO_PIN_14; //PG13,14
HAL_GPIO_Init(GPIOG,&GPIO_Initure); //初始化
HAL_NVIC_SetPriority(ETH_IRQn,1,0); //网络中断优先级应该高一点
HAL_NVIC_EnableIRQ(ETH_IRQn);
}
int32_t Ethernet_Init(void)
{
#if defined (PHY_CHIP_YT8512)
//硬件复位
INTX_DISABLE(); //关闭所有中断,复位过程不能被打断!
PCF8574_WriteBit(ETH_RESET_IO,0); //硬件复位
delay_ms(100);
PCF8574_WriteBit(ETH_RESET_IO,1); //复位结束
delay_ms(100);
INTX_ENABLE(); //开启所有中断
NETMPU_Config(); //MPU保护设置
YT8512C_Init();
#elif defined(PHY_CHIP_LAN8720)
//硬件复位
INTX_DISABLE(); //关闭所有中断,复位过程不能被打断!
PCF8574_WriteBit(ETH_RESET_IO,1); //硬件复位
delay_ms(100);
PCF8574_WriteBit(ETH_RESET_IO,0); //复位结束
delay_ms(100);
INTX_ENABLE(); //开启所有中断
NETMPU_Config(); //MPU保护设置
LAN8720_Init();
#endif
}
修改原有LAN8720.c文件,修改后如下:
#include "lwip_comm.h"
#include "pcf8574.h"
#include "delay.h"
#include "usart.h"
#include "lan8720.h"
//////////////////////////////////////////////////////////////////////////////////
//本程序只供学习使用,未经作者许可,不得用于其它任何用途
//ALIENTEK STM32H7开发板
//LAN8720驱动代码
//正点原子@ALIENTEK
//技术论坛:www.openedv.com
//创建日期:2018/7/6
//版本:V1.0
//版权所有,盗版必究。
//Copyright(C) 广州市星翼电子科技有限公司 2014-2024
//All rights reserved
//////////////////////////////////////////////////////////////////////////////////
ETH_HandleTypeDef LAN8720_ETHHandle;
//以太网描述符和缓冲区
extern __attribute__((at(0x30040000))) ETH_DMADescTypeDef DMARxDscrTab[ETH_RX_DESC_CNT]; //以太网Rx DMA描述符
extern __attribute__((at(0x30040060))) ETH_DMADescTypeDef DMATxDscrTab[ETH_TX_DESC_CNT]; //以太网Tx DMA描述符
extern __attribute__((at(0x30040200))) uint8_t Rx_Buff[ETH_RX_DESC_CNT][ETH_MAX_PACKET_SIZE]; //以太网接收缓冲区
//初始化LAN8720
int32_t LAN8720_Init(void)
{
u8 macaddress[6];
u32 timeout=0;
u32 regval=0;
u32 phylink=0;
int32_t status=LAN8720_STATUS_OK;
PHY_ETHHandle = &LAN8720_ETHHandle;
macaddress[0]=lwipdev.mac[0];
macaddress[1]=lwipdev.mac[1];
macaddress[2]=lwipdev.mac[2];
macaddress[3]=lwipdev.mac[3];
macaddress[4]=lwipdev.mac[4];
macaddress[5]=lwipdev.mac[5];
LAN8720_ETHHandle.Instance=ETH; //ETH
LAN8720_ETHHandle.Init.MACAddr=macaddress; //mac地址
LAN8720_ETHHandle.Init.MediaInterface=HAL_ETH_RMII_MODE; //RMII接口
LAN8720_ETHHandle.Init.RxDesc=DMARxDscrTab; //发送描述符
LAN8720_ETHHandle.Init.TxDesc=DMATxDscrTab; //接收描述如
LAN8720_ETHHandle.Init.RxBuffLen=ETH_MAX_PACKET_SIZE; //接收长度
HAL_ETH_Init(&LAN8720_ETHHandle); //初始化ETH
HAL_ETH_SetMDIOClockRange(&LAN8720_ETHHandle);
if(LAN8720_WritePHY(LAN8720_BCR,LAN8720_BCR_SOFT_RESET)>=0) //LAN8720软件复位
{
//等待软件复位完成
if(LAN8720_ReadPHY(LAN8720_BCR,®val)>=0)
{
while(regval&LAN8720_BCR_SOFT_RESET)
{
if(LAN8720_ReadPHY(LAN8720_BCR,®val)<0)
{
status=LAN8720_STATUS_READ_ERROR;
break;
}
delay_ms(10);
timeout++;
if(timeout>=LAN8720_TIMEOUT) break; //超时跳出,5S
}
}
else
{
status=LAN8720_STATUS_READ_ERROR;
}
}
else
{
status=LAN8720_STATUS_WRITE_ERROR;
}
LAN8720_StartAutoNego(); //开启自动协商功能
if(status==LAN8720_STATUS_OK) //如果前面运行正常就延时1s
delay_ms(1000); //等待1s
//等待网络连接成功
timeout=0;
while(LAN8720_GetLinkState()<=LAN8720_STATUS_LINK_DOWN)
{
delay_ms(10);
timeout++;
if(timeout>=LAN8720_TIMEOUT)
{
status=LAN8720_STATUS_LINK_DOWN;
break; //超时跳出,5S
}
}
phylink=LAN8720_GetLinkState();
if(phylink==LAN8720_STATUS_100MBITS_FULLDUPLEX)
printf("LAN8720:100Mb/s FullDuplex\r\n");
else if(phylink==LAN8720_STATUS_100MBITS_HALFDUPLEX)
printf("LAN8720:100Mb/s HalfDuplex\r\n");
else if(phylink==LAN8720_STATUS_10MBITS_FULLDUPLEX)
printf("LAN8720:10Mb/s FullDuplex\r\n");
else if(phylink==LAN8720_STATUS_10MBITS_HALFDUPLEX)
printf("LAN8720:10Mb/s HalfDuplex\r\n");
return status;
}
extern void lwip_pkt_handle(void);
//读取PHY寄存器值
//reg要读取的寄存器地址
//返回值:0 读取成功,-1 读取失败
int32_t LAN8720_ReadPHY(u16 reg,u32 *regval)
{
if(HAL_ETH_ReadPHYRegister(&LAN8720_ETHHandle,LAN8720_ADDR,reg,regval)!=HAL_OK)
return -1;
return 0;
}
//向LAN8720指定寄存器写入值
//reg:要写入的寄存器
//value:要写入的值
//返回值:0 写入正常,-1 写入失败
int32_t LAN8720_WritePHY(u16 reg,u16 value)
{
u32 temp=value;
if(HAL_ETH_WritePHYRegister(&LAN8720_ETHHandle,LAN8720_ADDR,reg,temp)!=HAL_OK)
return -1;
return 0;
}
//打开LAN8720 Power Down模式
void LAN8720_EnablePowerDownMode(void)
{
u32 readval=0;
LAN8720_ReadPHY(LAN8720_BCR,&readval);
readval|=LAN8720_BCR_POWER_DOWN;
LAN8720_WritePHY(LAN8720_BCR,readval);
}
//关闭LAN8720 Power Down模式
void LAN8720_DisablePowerDownMode(void)
{
u32 readval=0;
LAN8720_ReadPHY(LAN8720_BCR,&readval);
readval&=~LAN8720_BCR_POWER_DOWN;
LAN8720_WritePHY(LAN8720_BCR,readval);
}
//开启LAN8720的自协商功能
void LAN8720_StartAutoNego(void)
{
u32 readval=0;
LAN8720_ReadPHY(LAN8720_BCR,&readval);
readval|=LAN8720_BCR_AUTONEGO_EN;
LAN8720_WritePHY(LAN8720_BCR,readval);
}
//使能回测模式
void LAN8720_EnableLoopbackMode(void)
{
u32 readval=0;
LAN8720_ReadPHY(LAN8720_BCR,&readval);
readval|=LAN8720_BCR_LOOPBACK;
LAN8720_WritePHY(LAN8720_BCR,readval);
}
//关闭LAN8720的回测模式
void LAN8720_DisableLoopbackMode(void)
{
u32 readval=0;
LAN8720_ReadPHY(LAN8720_BCR,&readval);
readval&=~LAN8720_BCR_LOOPBACK;
LAN8720_WritePHY(LAN8720_BCR,readval);
}
//使能中断,中断源可选:LAN8720_ENERGYON_IT
// LAN8720_AUTONEGO_COMPLETE_IT
// LAN8720_REMOTE_FAULT_IT
// LAN8720_LINK_DOWN_IT
// LAN8720_AUTONEGO_LP_ACK_IT
// LAN8720_PARALLEL_DETECTION_FAULT_IT
// LAN8720_AUTONEGO_PAGE_RECEIVED_IT
void LAN8720_EnableIT(u32 interrupt)
{
u32 readval=0;
LAN8720_ReadPHY(LAN8720_IMR,&readval);
readval|=interrupt;
LAN8720_WritePHY(LAN8720_IMR,readval);
}
//关闭中断,中断源可选:LAN8720_ENERGYON_IT
// LAN8720_AUTONEGO_COMPLETE_IT
// LAN8720_REMOTE_FAULT_IT
// LAN8720_LINK_DOWN_IT
// LAN8720_AUTONEGO_LP_ACK_IT
// LAN8720_PARALLEL_DETECTION_FAULT_IT
// LAN8720_AUTONEGO_PAGE_RECEIVED_IT
void LAN8720_DisableIT(u32 interrupt)
{
u32 readval=0;
LAN8720_ReadPHY(LAN8720_IMR,&readval);
readval&=~interrupt;
LAN8720_WritePHY(LAN8720_IMR,readval);
}
//清除中断标志位,读寄存器ISFR就可清除中断标志位
void LAN8720_ClearIT(u32 interrupt)
{
u32 readval=0;
LAN8720_ReadPHY(LAN8720_ISFR,&readval);
}
//获取中断标志位
//返回值,1 中断标志位置位,
// 0 中断标志位清零
u8 LAN8720_GetITStatus(u32 interrupt)
{
u32 readval=0;
u32 status=0;
LAN8720_ReadPHY(LAN8720_ISFR,&readval);
if(readval&interrupt) status=1;
else status=0;
return status;
}
//获取LAN8720的连接状态
//返回值:LAN8720_STATUS_LINK_DOWN 连接断开
// LAN8720_STATUS_AUTONEGO_NOTDONE 自动协商完成
// LAN8720_STATUS_100MBITS_FULLDUPLEX 100M全双工
// LAN8720_STATUS_100MBITS_HALFDUPLEX 100M半双工
// LAN8720_STATUS_10MBITS_FULLDUPLEX 10M全双工
// LAN8720_STATUS_10MBITS_HALFDUPLEX 10M半双工
u32 LAN8720_GetLinkState(void)
{
u32 readval=0;
//读取两遍,确保读取正确!!!
LAN8720_ReadPHY(LAN8720_BSR,&readval);
LAN8720_ReadPHY(LAN8720_BSR,&readval);
//获取连接状态(硬件,网线的连接,不是TCP、UDP等软件连接!)
if((readval&LAN8720_BSR_LINK_STATUS)==0)
return LAN8720_STATUS_LINK_DOWN;
//获取自动协商状态
LAN8720_ReadPHY(LAN8720_BCR,&readval);
if((readval&LAN8720_BCR_AUTONEGO_EN)!=LAN8720_BCR_AUTONEGO_EN) //未使能自动协商
{
if(((readval&LAN8720_BCR_SPEED_SELECT)==LAN8720_BCR_SPEED_SELECT)&&
((readval&LAN8720_BCR_DUPLEX_MODE)==LAN8720_BCR_DUPLEX_MODE))
return LAN8720_STATUS_100MBITS_FULLDUPLEX;
else if((readval&LAN8720_BCR_SPEED_SELECT)==LAN8720_BCR_SPEED_SELECT)
return LAN8720_STATUS_100MBITS_HALFDUPLEX;
else if((readval&LAN8720_BCR_DUPLEX_MODE)==LAN8720_BCR_DUPLEX_MODE)
return LAN8720_STATUS_10MBITS_FULLDUPLEX;
else
return LAN8720_STATUS_10MBITS_HALFDUPLEX;
}
else //使能了自动协商
{
LAN8720_ReadPHY(LAN8720_PHYSCSR,&readval);
if((readval&LAN8720_PHYSCSR_AUTONEGO_DONE)==0)
return LAN8720_STATUS_AUTONEGO_NOTDONE;
if((readval&LAN8720_PHYSCSR_HCDSPEEDMASK)==LAN8720_PHYSCSR_100BTX_FD)
return LAN8720_STATUS_100MBITS_FULLDUPLEX;
else if ((readval&LAN8720_PHYSCSR_HCDSPEEDMASK)==LAN8720_PHYSCSR_100BTX_HD)
return LAN8720_STATUS_100MBITS_HALFDUPLEX;
else if ((readval&LAN8720_PHYSCSR_HCDSPEEDMASK)==LAN8720_PHYSCSR_10BT_FD)
return LAN8720_STATUS_10MBITS_FULLDUPLEX;
else
return LAN8720_STATUS_10MBITS_HALFDUPLEX;
}
}
//设置LAN8720的连接状态
//参数linkstate:LAN8720_STATUS_100MBITS_FULLDUPLEX 100M全双工
// LAN8720_STATUS_100MBITS_HALFDUPLEX 100M半双工
// LAN8720_STATUS_10MBITS_FULLDUPLEX 10M全双工
// LAN8720_STATUS_10MBITS_HALFDUPLEX 10M半双工
void LAN8720_SetLinkState(u32 linkstate)
{
u32 bcrvalue=0;
LAN8720_ReadPHY(LAN8720_BCR,&bcrvalue);
//关闭连接配置,比如自动协商,速度和双工
bcrvalue&=~(LAN8720_BCR_AUTONEGO_EN|LAN8720_BCR_SPEED_SELECT|LAN8720_BCR_DUPLEX_MODE);
if(linkstate==LAN8720_STATUS_100MBITS_FULLDUPLEX) //100M全双工
bcrvalue|=(LAN8720_BCR_SPEED_SELECT|LAN8720_BCR_DUPLEX_MODE);
else if(linkstate==LAN8720_STATUS_100MBITS_HALFDUPLEX) //100M半双工
bcrvalue|=LAN8720_BCR_SPEED_SELECT;
else if(linkstate==LAN8720_STATUS_10MBITS_FULLDUPLEX) //10M全双工
bcrvalue|=LAN8720_BCR_DUPLEX_MODE;
LAN8720_WritePHY(LAN8720_BCR,bcrvalue);
}
修改原有lwip_comm.c文件,修改位置如下:
//LWIP初始化(LWIP启动的时候使用)
//返回值:0,成功
// 1,内存错误
// 2,ethernet初始化失败
// 3,网卡添加失败.
u8 lwip_comm_init(void)
{
u8 retry=0;
struct netif *Netif_Init_Flag; //调用netif_add()函数时的返回值,用于判断网络初始化是否成功
struct ip_addr ipaddr; //ip地址
struct ip_addr netmask; //子网掩码
struct ip_addr gw; //默认网关
lwip_comm_default_ip_set(&lwipdev); //设置默认IP等信
while(Ethernet_Init()) //初始化ethernet,如果失败的话就重试5次
{
retry++;
if(retry>5) {retry=0;return 3;} //ethernet初始化失败
}
....
修改原有ethernetif.c,修改位置如下:
switch (PHYLinkState)
{
case PHY_CHIP_STATUS_100MBITS_FULLDUPLEX: //100M全双工
duplex=ETH_FULLDUPLEX_MODE;
speed=ETH_SPEED_100M;
break;
case PHY_CHIP_STATUS_100MBITS_HALFDUPLEX: //100M半双工
duplex=ETH_HALFDUPLEX_MODE;
speed=ETH_SPEED_100M;
break;
case PHY_CHIP_STATUS_10MBITS_FULLDUPLEX: //10M全双工
duplex=ETH_FULLDUPLEX_MODE;
speed=ETH_SPEED_10M;
break;
case PHY_CHIP_STATUS_10MBITS_HALFDUPLEX: //10M半双工
duplex=ETH_HALFDUPLEX_MODE;
speed=ETH_SPEED_10M;
break;
default:
break;
}
//网络连接状态检查
void ethernet_link_check_state(struct netif *netif)
{
ETH_MACConfigTypeDef MACConf;
u32 PHYLinkState;
u32 linkchanged=0,speed=0,duplex=0;
#if defined (PHY_CHIP_YT8512)
PHYLinkState=YT8512C_GetLinkState(); //获取连接状态
#elif defined(PHY_CHIP_LAN8720)
PHYLinkState=LAN8720_GetLinkState(); //获取连接状态
#endif
将原有的LAN8720相关引用,修改成ethernet的引用后就可以实现通信。
源码工程资源地址:STM32H743阿波罗开发板YT8512C网口驱动代码,兼容LAN8720和YT8512C两个驱动-CSDN博客
1万+

被折叠的 条评论
为什么被折叠?



