本文博客链接:http://blog.csdn.net/jdh99,作者:jdh,转载请注明.
环境:
开发环境:MDK5.23
rt-thread版本:2.1.0
lwip版本:1.4.1
单片机型号:stm32f407
phy芯片型号:dp83848
配置步骤:
PHY的时钟是50M,产生这个时钟有两个方法:
-
用50M有源晶振给PHY
-
单片机产生50M信号给PHY
本文用单片机产生50M信号给PHY,使用的引脚是单片机的PA8。
步骤1:
配置单片机主频为100M
步骤2:修改rtconfig.h文件,启动lwip
/* SECTION: lwip, a lighwight TCP/IP protocol stack */
#define RT_USING_LWIP
#define RT_USING_LWIP141
步骤3:修改stm32f4xx_eth.h文件,打开dp83848的相关宏定义
/**
* @}
*/
/** @defgroup PHY_status_register
* @{
*/
/* The PHY status register value change from a PHY to another so the user have
to update this value depending on the used external PHY */
/**
* @brief For LAN8700
*/
/*#define PHY_SR 31 */ /*!< Tranceiver Status Register */
/**
* @brief For DP83848
*/
#define PHY_SR 16 /*!< Tranceiver Status Register */
/* The Speed and Duplex mask values change from a PHY to another so the user have to update
this value depending on the used external PHY */
/**
* @brief For LAN8700
*/
/*#define PHY_Speed_Status ((uint16_t)0x0004)*/ /*!< Configured information of Speed: 10Mbps */
/*#define PHY_Duplex_Status ((uint16_t)0x0010)*/ /*!< Configured information of Duplex: Full-duplex */
/**
* @brief For DP83848
*/
#define PHY_Speed_Status ((uint16_t)0x0002) /*!< Configured information of Speed: 10Mbps */
#define PHY_Duplex_Status ((uint16_t)0x0004) /*!< Configured information of Duplex: Full-duplex */
#define IS_ETH_PHY_ADDRESS(ADDRESS) ((ADDRESS) <= 0x20)
#define IS_ETH_PHY_REG(REG) ((REG) <= 0x1F)
步骤4:修改stm32f4xx_eth.c文件,设置为RMII模式
/* STM32F ETH dirver options */
#define RMII_MODE /* MII_MODE or RMII_MODE */
#define RMII_TX_GPIO_GROUP 1 /* 1:GPIOB or 2:GPIOG */
步骤5:修改stm32f4xx_eth.c文件中的GPIO_Configuration()函数,使用PA8输出50M时钟
/*
* GPIO Configuration for ETH
*/
static void GPIO_Configuration(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
/* Enable SYSCFG clock */
RCC_APB2PeriphClockCmd(RCC_APB2Periph_SYSCFG, ENABLE);
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA | RCC_AHB1Periph_GPIOC, ENABLE);
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;
/* config MDIO and MDC. */
GPIO_PinAFConfig(GPIOA, GPIO_PinSource2, GPIO_AF_ETH); /* config ETH_MDIO */
GPIO_PinAFConfig(GPIOC, GPIO_PinSource1, GPIO_AF_ETH); /* config ETH_MDC */
/* config PA2: MDIO */
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_2;
GPIO_Init(GPIOA, &GPIO_InitStructure);
/* config PC1: MDC */
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1;
GPIO_Init(GPIOC, &GPIO_InitStructure);
/* Ethernet pins configuration ************************************************/
#if defined(MII_MODE)
/*
ETH_MDIO ------------> PA2
ETH_MDC -------------> PC1
ETH_MII_CRS ---------> PA0
ETH_MII_COL ---------> PA3
ETH_MII_RX_CLK ------> PA1
ETH_MII_RX_ER -------> PB10
ETH_MII_RX_ER -------> PI10
ETH_MII_RX_DV -------> PA7
ETH_MII_RXD0 --------> PC4
ETH_MII_RXD1 --------> PC5
ETH_MII_RXD2 --------> PB0
ETH_MII_RXD3 --------> PB1
ETH_MII_TX_EN -------> PB11
ETH_MII_TX_EN -------> PG11
ETH_MII_TX_CLK ------> PC3
ETH_MII_TXD0 --------> PB12
ETH_MII_TXD0 --------> PG13
ETH_MII_TXD1 --------> PB13
ETH_MII_TXD1 --------> PG14
ETH_MII_TXD2 --------> PC2
ETH_MII_TXD3 --------> PB8
ETH_MII_TXD3 -------> PE2
*/
#error insert MII GPIO initial.
#elif defined(RMII_MODE)
/*
ETH_MDIO ------------> PA2
ETH_MDC -------------> PC1
ETH_RMII_REF_CLK ----> PA1
ETH_RMII_CRS_DV -----> PA7
ETH_RMII_RXD0 -------> PC4
ETH_RMII_RXD1 -------> PC5
ETH_RMII_TX_EN ------> PG11
ETH_RMII_TXD0 -------> PG13
ETH_RMII_TXD1 -------> PG14
ETH_RMII_TX_EN ------> PB11
ETH_RMII_TXD0 -------> PB12
ETH_RMII_TXD1 -------> PB13
PA8输出MCO1 50M
*/
// PA8输出时钟 start
/* Configure MCO (PA8) */
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL ;
GPIO_Init(GPIOA, &GPIO_InitStructure);
/* Output PLL clock divided by 2 (50MHz) on MCO pin (PA8) to clock the PHY */
RCC_MCO1Config(RCC_MCO1Source_PLLCLK, RCC_MCO1Div_2);
SYSCFG_ETH_MediaInterfaceConfig(SYSCFG_ETH_MediaInterface_RMII);
// end
GPIO_PinAFConfig(GPIOA, GPIO_PinSource1, GPIO_AF_ETH); /* RMII_REF_CLK */
GPIO_PinAFConfig(GPIOA, GPIO_PinSource7, GPIO_AF_ETH); /* RMII_CRS_DV */
/* configure PA1:RMII_REF_CLK, PA7:RMII_CRS_DV. */
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1 | GPIO_Pin_7;
GPIO_Init(GPIOA, &GPIO_InitStructure);
GPIO_PinAFConfig(GPIOC, GPIO_PinSource4, GPIO_AF_ETH); /* RMII_RXD0 */
GPIO_PinAFConfig(GPIOC, GPIO_PinSource5, GPIO_AF_ETH); /* RMII_RXD1 */
/* configure PC4:RMII_RXD0, PC5:RMII_RXD1. */
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_4 | GPIO_Pin_5;
GPIO_Init(GPIOC, &GPIO_InitStructure);
# if RMII_TX_GPIO_GROUP == 1
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOB, ENABLE);
GPIO_PinAFConfig(GPIOB, GPIO_PinSource11, GPIO_AF_ETH); /* RMII_TX_EN */
GPIO_PinAFConfig(GPIOB, GPIO_PinSource12, GPIO_AF_ETH); /* RMII_TXD0 */
GPIO_PinAFConfig(GPIOB, GPIO_PinSource13, GPIO_AF_ETH); /* RMII_TXD1 */
/* configure PB11:RMII_TX_EN, PB12:RMII_TXD0, PB13:RMII_TXD1 */
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_11 | GPIO_Pin_12 | GPIO_Pin_13;
GPIO_Init(GPIOB, &GPIO_InitStructure);
# elif RMII_TX_GPIO_GROUP == 2
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOG, ENABLE);
GPIO_PinAFConfig(GPIOG, GPIO_PinSource11, GPIO_AF_ETH); /* RMII_TX_EN */
GPIO_PinAFConfig(GPIOG, GPIO_PinSource13, GPIO_AF_ETH); /* RMII_TXD0 */
GPIO_PinAFConfig(GPIOG, GPIO_PinSource14, GPIO_AF_ETH); /* RMII_TXD1 */
/* configure PG11:RMII_TX_EN, PG13:RMII_TXD0, PG14:RMII_TXD1 */
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_11 | GPIO_Pin_13 | GPIO_Pin_14;
GPIO_Init(GPIOG, &GPIO_InitStructure);
# else
# error RMII_TX_GPIO_GROUP setting error!
# endif /*RMII_TX_GPIO_GROUP */
#endif /* RMII_MODE */
}
步骤6:修改stm32f4xx_eth.c文件中的phy_monitor_thread_entry()函数。
本函数存在bug,还是使用LAN8700寄存器,应该使用DP83848的寄存器。
static void phy_monitor_thread_entry(void *parameter)
{
uint8_t phy_addr = 0xFF;
uint8_t phy_speed_new = 0;
/* phy search */
{
rt_uint32_t i;
rt_uint16_t temp;
for(i=0; i<=0x1F; i++)
{
temp = ETH_ReadPHYRegister(i, 0x02);
if( temp != 0xFFFF )
{
phy_addr = i;
break;
}
}
} /* phy search */
if(phy_addr == 0xFF)
{
STM32_ETH_PRINTF("phy not probe!\r\n");
return;
}
else
{
STM32_ETH_PRINTF("found a phy, address:0x%02X\r\n", phy_addr);
}
/* RESET PHY */
STM32_ETH_PRINTF("RESET PHY!\r\n");
ETH_WritePHYRegister(phy_addr, PHY_BCR, PHY_Reset);
rt_thread_delay(RT_TICK_PER_SECOND * 2);
ETH_WritePHYRegister(phy_addr, PHY_BCR, PHY_AutoNegotiation);
while(1)
{
uint16_t status = ETH_ReadPHYRegister(phy_addr, PHY_BSR);
STM32_ETH_PRINTF("LAN8720 status:0x%04X\r\n", status);
phy_speed_new = 0;
if(status & (PHY_AutoNego_Complete | PHY_Linked_Status))
{
uint16_t SR;
// SR = ETH_ReadPHYRegister(phy_addr, 31);
SR = ETH_ReadPHYRegister(phy_addr, 16);
STM32_ETH_PRINTF("DP83848 REG 16:0x%04X\r\n", SR);
SR = (SR >> 2) & 0x07; /* LAN8720, REG31[4:2], Speed Indication. */
phy_speed_new = PHY_LINK_MASK;
// if((SR & 0x03) == 2)
if((SR & 0x02) == 0)
{
phy_speed_new |= PHY_100M_MASK;
}
if(SR & 0x04)
{
phy_speed_new |= PHY_DUPLEX_MASK;
}
}
/* linkchange */
if(phy_speed_new != phy_speed)
{
if(phy_speed_new & PHY_LINK_MASK)
{
STM32_ETH_PRINTF("link up ");
if(phy_speed_new & PHY_100M_MASK)
{
STM32_ETH_PRINTF("100Mbps");
stm32_eth_device.ETH_Speed = ETH_Speed_100M;
}
else
{
stm32_eth_device.ETH_Speed = ETH_Speed_10M;
STM32_ETH_PRINTF("10Mbps");
}
if(phy_speed_new & PHY_DUPLEX_MASK)
{
STM32_ETH_PRINTF(" full-duplex\r\n");
stm32_eth_device.ETH_Mode = ETH_Mode_FullDuplex;
}
else
{
STM32_ETH_PRINTF(" half-duplex\r\n");
stm32_eth_device.ETH_Mode = ETH_Mode_HalfDuplex;
}
rt_stm32_eth_init((rt_device_t)&stm32_eth_device);
/* send link up. */
eth_device_linkchange(&stm32_eth_device.parent, RT_TRUE);
} /* link up. */
else
{
STM32_ETH_PRINTF("link down\r\n");
/* send link down. */
eth_device_linkchange(&stm32_eth_device.parent, RT_FALSE);
} /* link down. */
phy_speed = phy_speed_new;
} /* linkchange */
rt_thread_delay(RT_TICK_PER_SECOND);
} /* while(1) */
}
修改处:
// SR = ETH_ReadPHYRegister(phy_addr, 31);
SR = ETH_ReadPHYRegister(phy_addr, 16);
STM32_ETH_PRINTF("DP83848 REG 16:0x%04X\r\n", SR);
SR = (SR >> 2) & 0x07; /* LAN8720, REG31[4:2], Speed Indication. */
phy_speed_new = PHY_LINK_MASK;
// if((SR & 0x03) == 2)
if((SR & 0x02) == 0)
{
phy_speed_new |= PHY_100M_MASK;
}
配置完成
后应该可以ping通。