DP83848
- 先上原理图
- 也是用的RMII接口,但是应该注意这个开发板选用的是有源晶振
- 开发板上的Reset 引脚是和单片机 复位连接在一起的,不受我控制
- 配置代码及寄存器设置代码
- 配置代码同8720A
- 寄存器配置代码这里面需要对照DataSheet看一下
- 对应修改 Hal 中的寄存器配置位 和 drv_eth.h 中的配置位
/* DP83848_PHY_ADDRESS Address*/
#define DP83848_PHY_ADDRESS 1U
/* PHY Reset delay these values are based on a 1 ms Systick interrupt*/
#define PHY_RESET_DELAY ((uint32_t)0x00FFFFFFU)
/* PHY Configuration delay */
#define PHY_CONFIG_DELAY ((uint32_t)0x00000FFFU)
#define PHY_READ_TO ((uint32_t)0x0000FFFFU)
#define PHY_WRITE_TO ((uint32_t)0x0000FFFFU)
/* Section 3: Common PHY Registers */
#define PHY_BCR ((uint16_t)0x00U) /*!< Transceiver Basic Control Register */
#define PHY_BSR ((uint16_t)0x01U) /*!< Transceiver Basic Status Register */
#define PHY_RESET ((uint16_t)0x8000U) /*!< PHY Reset */
#define PHY_LOOPBACK ((uint16_t)0x4000U) /*!< Select loop-back mode */
#define PHY_FULLDUPLEX_100M ((uint16_t)0x2100U) /*!< Set the full-duplex mode at 100 Mb/s */
#define PHY_HALFDUPLEX_100M ((uint16_t)0x2000U) /*!< Set the half-duplex mode at 100 Mb/s */
#define PHY_FULLDUPLEX_10M ((uint16_t)0x0100U) /*!< Set the full-duplex mode at 10 Mb/s */
#define PHY_HALFDUPLEX_10M ((uint16_t)0x0000U) /*!< Set the half-duplex mode at 10 Mb/s */
#define PHY_AUTONEGOTIATION ((uint16_t)0x1000U) /*!< Enable auto-negotiation function */
#define PHY_RESTART_AUTONEGOTIATION ((uint16_t)0x0200U) /*!< Restart auto-negotiation function */
#define PHY_POWERDOWN ((uint16_t)0x0800U) /*!< Select the power down mode */
#define PHY_ISOLATE ((uint16_t)0x0400U) /*!< Isolate PHY from MII */
#define PHY_AUTONEGO_COMPLETE ((uint16_t)0x0020U) /*!< Auto-Negotiation process completed */
#define PHY_LINKED_STATUS ((uint16_t)0x0004U) /*!< Valid link established */
#define PHY_JABBER_DETECTION ((uint16_t)0x0002U) /*!< Jabber condition detected */
/* Section 4: Extended PHY Registers */
#define PHY_SR ((uint16_t)0x10U) /*!< PHY status register Offset */
#define PHY_LINK_STATUS ((uint16_t)0x0001U) /*!< PHY Link mask */
#define PHY_SPEED_STATUS ((uint16_t)0x0002U) /*!< PHY Speed mask */
#define PHY_DUPLEX_STATUS ((uint16_t)0x0004U) /*!< PHY Duplex mask */
// 为了防止寄存器配置错误,我把不使用的配置寄存器都屏蔽了
/* The PHY basic control register */
#define PHY_BASIC_CONTROL_REG 0x00U
#define PHY_RESET_MASK (1<<15)
#define PHY_AUTO_NEGOTIATION_MASK (1<<12)
/* The PHY basic status register */
#define PHY_BASIC_STATUS_REG 0x01U
#define PHY_LINKED_STATUS_MASK (1<<2)
#define PHY_AUTONEGO_COMPLETE_MASK (1<<5)
/* The PHY ID one register */
#define PHY_ID1_REG 0x02U
///* The PHY ID two register */
//#define PHY_ID2_REG 0x03U
///* The PHY auto-negotiate advertise register */
//#define PHY_AUTONEG_ADVERTISE_REG 0x04U
#ifdef PHY_USING_DP83848C
#define PHY_Status_REG 0x10U
#define PHY_10M_MASK (1<<1)
#define PHY_FULL_DUPLEX_MASK (1<<2)
#define PHY_Status_SPEED_10M(sr) ((sr) & PHY_10M_MASK)
#define PHY_Status_SPEED_100M(sr) (!PHY_Status_SPEED_10M(sr))
#define PHY_Status_FULL_DUPLEX(sr) ((sr) & PHY_FULL_DUPLEX_MASK)
/* The PHY interrupt source flag register. */
//#define PHY_INTERRUPT_FLAG_REG 0x12U
//#define PHY_LINK_CHANGE_FLAG (1<<13)
///* The PHY interrupt control register. */
//#define PHY_INTERRUPT_CTRL_REG 0x11U
//#define PHY_INTERRUPT_EN ((1<<0)|(1<<1))
///* The PHY interrupt mask register. */
//#define PHY_INTERRUPT_MASK_REG 0x12U
//#define PHY_INT_MASK (1<<5)
#endif /* PHY_USING_DP83848C */
- 修改 1
- 配置代码关闭自适应
__HAL_RCC_ETH_CLK_ENABLE();
/* ETHERNET Configuration */
EthHandle.Instance = ETH;
EthHandle.Init.MACAddr = (rt_uint8_t *)&stm32_eth_device.dev_addr[0];
EthHandle.Init.AutoNegotiation = ETH_AUTONEGOTIATION_DISABLE;
EthHandle.Init.Speed = ETH_SPEED_100M;
EthHandle.Init.DuplexMode = ETH_MODE_FULLDUPLEX;
EthHandle.Init.MediaInterface = ETH_MEDIA_INTERFACE_RMII;
EthHandle.Init.RxMode = ETH_RXINTERRUPT_MODE;
#ifdef RT_LWIP_USING_HW_CHECKSUM
EthHandle.Init.ChecksumMode = ETH_CHECKSUM_BY_HARDWARE;
#else
EthHandle.Init.ChecksumMode = ETH_CHECKSUM_BY_SOFTWARE;
#endif
- Rtthread 线程中关闭自适应
static void phy_monitor_thread_entry(void *parameter)
{
uint8_t phy_addr = 0xFF;
uint8_t detected_count = 0;
while(phy_addr == 0xFF)
{
/* phy search */
rt_uint32_t i, temp;
for (i = 0; i <= 0x1F; i++)
{
EthHandle.Init.PhyAddress = i;
HAL_ETH_ReadPHYRegister(&EthHandle, PHY_ID1_REG, (uint32_t *)&temp);
if (temp != 0xFFFF && temp != 0x00)
{
phy_addr = i;
break;
}
}
detected_count++;
rt_thread_mdelay(1000);
if (detected_count > 10)
{
LOG_E("No PHY device was detected, please check hardware!");
}
}
LOG_D("Found a phy, address:0x%02X", phy_addr);
// /* RESET PHY */
// LOG_D("RESET PHY!");
// HAL_ETH_WritePHYRegister(&EthHandle, PHY_BASIC_CONTROL_REG, PHY_RESET_MASK);
// rt_thread_mdelay(2000);
// HAL_ETH_WritePHYRegister(&EthHandle, PHY_BASIC_CONTROL_REG, PHY_AUTO_NEGOTIATION_MASK);
phy_linkchange();
#ifdef PHY_USING_INTERRUPT_MODE
/* configuration intterrupt pin */
rt_pin_mode(PHY_INT_PIN, PIN_MODE_INPUT_PULLUP);
rt_pin_attach_irq(PHY_INT_PIN, PIN_IRQ_MODE_FALLING, eth_phy_isr, (void *)"callbackargs");
rt_pin_irq_enable(PHY_INT_PIN, PIN_IRQ_ENABLE);
/* enable phy interrupt */
HAL_ETH_WritePHYRegister(&EthHandle, PHY_INTERRUPT_MASK_REG, PHY_INT_MASK);
#if defined(PHY_INTERRUPT_CTRL_REG)
HAL_ETH_WritePHYRegister(&EthHandle, PHY_INTERRUPT_CTRL_REG, PHY_INTERRUPT_EN);
#endif
#else /* PHY_USING_INTERRUPT_MODE */
stm32_eth_device.poll_link_timer = rt_timer_create("phylnk", (void (*)(void*))phy_linkchange,
NULL, RT_TICK_PER_SECOND, RT_TIMER_FLAG_PERIODIC);
if (!stm32_eth_device.poll_link_timer || rt_timer_start(stm32_eth_device.poll_link_timer) != RT_EOK)
{
LOG_E("Start link change detection timer failed");
}
#endif /* PHY_USING_INTERRUPT_MODE */
}
- 修改1-实验结果
- 此时可以发现 100M 半双工
- BSR(01) = 0x786D; PHY_Status_REG(10) = 0
- 正常触发中断
- 可以ping通
- 修改 2
- 修改配置代码为 自适应
__HAL_RCC_ETH_CLK_ENABLE();
/* ETHERNET Configuration */
EthHandle.Instance = ETH;
EthHandle.Init.MACAddr = (rt_uint8_t *)&stm32_eth_device.dev_addr[0];
EthHandle.Init.AutoNegotiation = ETH_AUTONEGOTIATION_ENABLE;
EthHandle.Init.Speed = ETH_SPEED_100M;
EthHandle.Init.DuplexMode = ETH_MODE_FULLDUPLEX;
EthHandle.Init.MediaInterface = ETH_MEDIA_INTERFACE_RMII;
EthHandle.Init.RxMode = ETH_RXINTERRUPT_MODE;
#ifdef RT_LWIP_USING_HW_CHECKSUM
EthHandle.Init.ChecksumMode = ETH_CHECKSUM_BY_HARDWARE;
#else
EthHandle.Init.ChecksumMode = ETH_CHECKSUM_BY_SOFTWARE;
#endif
- 开启 Rtthread 线程中的Reset 和自适应
static void phy_monitor_thread_entry(void *parameter)
{
uint8_t phy_addr = 0xFF;
uint8_t detected_count = 0;
while(phy_addr == 0xFF)
{
/* phy search */
rt_uint32_t i, temp;
for (i = 0; i <= 0x1F; i++)
{
EthHandle.Init.PhyAddress = i;
HAL_ETH_ReadPHYRegister(&EthHandle, PHY_ID1_REG, (uint32_t *)&temp);
if (temp != 0xFFFF && temp != 0x00)
{
phy_addr = i;
break;
}
}
detected_count++;
rt_thread_mdelay(1000);
if (detected_count > 10)
{
LOG_E("No PHY device was detected, please check hardware!");
}
}
LOG_D("Found a phy, address:0x%02X", phy_addr);
/* RESET PHY */
LOG_D("RESET PHY!");
HAL_ETH_WritePHYRegister(&EthHandle, PHY_BASIC_CONTROL_REG, PHY_RESET_MASK);
rt_thread_mdelay(2000);
HAL_ETH_WritePHYRegister(&EthHandle, PHY_BASIC_CONTROL_REG, PHY_AUTO_NEGOTIATION_MASK);
phy_linkchange();
#ifdef PHY_USING_INTERRUPT_MODE
/* configuration intterrupt pin */
rt_pin_mode(PHY_INT_PIN, PIN_MODE_INPUT_PULLUP);
rt_pin_attach_irq(PHY_INT_PIN, PIN_IRQ_MODE_FALLING, eth_phy_isr, (void *)"callbackargs");
rt_pin_irq_enable(PHY_INT_PIN, PIN_IRQ_ENABLE);
/* enable phy interrupt */
HAL_ETH_WritePHYRegister(&EthHandle, PHY_INTERRUPT_MASK_REG, PHY_INT_MASK);
#if defined(PHY_INTERRUPT_CTRL_REG)
HAL_ETH_WritePHYRegister(&EthHandle, PHY_INTERRUPT_CTRL_REG, PHY_INTERRUPT_EN);
#endif
#else /* PHY_USING_INTERRUPT_MODE */
stm32_eth_device.poll_link_timer = rt_timer_create("phylnk", (void (*)(void*))phy_linkchange,
NULL, RT_TICK_PER_SECOND, RT_TIMER_FLAG_PERIODIC);
if (!stm32_eth_device.poll_link_timer || rt_timer_start(stm32_eth_device.poll_link_timer) != RT_EOK)
{
LOG_E("Start link change detection timer failed");
}
#endif /* PHY_USING_INTERRUPT_MODE */
}
- 修改2 实验结果
- 此时可以发现 100M 半双工
- BSR(01) = 0x786D; PHY_Status_REG(10) = 0
- 这个时候 无法触发中断
- 这个时候 不可以ping通
- 后期修改
- 我思考了一下,在配置中我已经开启了自适应,后面应该就不需要了呀,我修改了,将Rtthread 线程中,的芯片复位和开启 自适应,可惜实验结果同上,不触发中断无法ping通。
- 后面我发现只要将配置代码中的
EthHandle.Init.AutoNegotiation = ETH_AUTONEGOTIATION_ENABLE;
修改为
EthHandle.Init.AutoNegotiation = ETH_AUTONEGOTIATION_DISABLE;
就可以正常触发中断,正常ping通,无论Rtthread线程中的 phy 寄存器是否配置位自适应。
疑问
- 无论是 8720A 还是 83848,我再读取 PHY_Status_REG() 时为啥都是0;当然8720 寄存器地址是1F;83848 是 10;
- 8720 无论是否开启自适应都能ping通,正常触发中断,即使是100M,可能是硬件没达标等。
- 为啥 我的83848 配置中是否开启自适应,会影响最终的联网成功失败。
恳请 各位大佬 各位大神指点。。。。
测试环境
- 计算机发送数据帧,MCU电路板回应,查看发送数与接收数看是否丢包
- 从左至右分别是 83848 启明开发板;8720A自己画的电路板;8720A EC20Plus 开发板;
- 测试结果表现为,83848 老是掉线;两块8720A 不掉线,不丢包
恳请 大神 大佬们指点,项目比较急,万分感谢!!!
问 RTthread 网络之 8720A DP83848