终于有个时间总结一下关于lan8720的调试过程。
调试之前也是翻阅了各大微博,各大论坛,详细的认真的看了每一位大神发表的文章。取其精华去其糟粕,最终调通了lan8720的驱动。话不多说,切入正题。
调试该款芯片有以下几个关键点:
1. STM32官方出了关于f407的以太网通信的demo例程,以太网芯片用的是DP83848。有参考价值。正点原子出了LAN8720的以太网通信教程和资料。
2. DP83848和LAN8720重要的几个寄存器是一样的,不过寄存器地址有区别。
3. LAN8720通信可以分为2路,一路是操作寄存器,一路是以太网通信。具体参看LAN8720手册第12页:
4. 如果通信出现问题,将从以上2路来进行分析,首先检查寄存器读写是否有问题,可以去读取芯片的ID寄存器值看是否是默认值,或者往某个寄存器写入值然后读出来看是否设置成功。如果寄存器读写没有问题,再去检查网络部分。
5. 关于PHY的地址,LAN8720A 可以通过 PHYAD0 引脚来配置,该引脚与 RXER 引脚复用,芯片内部自带下拉电阻,当硬复位结束后, LAN8720A 会读取该引脚电平,作为器件的 SMI 地址,接下拉电阻时(浮空也可以,因为芯片内部自带了下拉电阻),设置 SMI 地址为 0,当外接上拉电阻后,设置为 1。地址设置正确,才能对寄存器进行读写操作。
6. nINT/REFCLKO 引脚功能配置。nINT/REFCLKO 引脚可以用作中断输出,或者参考时钟输出。通过 LED2(nINTSEL)引脚设置, LED2 引脚的值在芯片复位后,被 LAN8720A 读取,当该引脚接上拉电阻(或浮空,内置上拉电阻),那么正常工作后, nINT/REFCLKO 引脚将作为中断输出引脚( REF_CLKIN 模式)。当该引脚接下拉电阻时,正常工作后, nINT/REFCLKO 引脚将作为参考时钟输出(REF_CLK OUT 模式)。
在 REF_CLK IN 模式,外部必须提供 50Mhz 参考时钟给 LAN8720A 的XTAL1(CLKIN)引脚。此时XTAL2可悬空。
在 REF_CLK OUT 模式, LAN8720A 可以外接 25Mhz 石英晶振,通过内部倍频到 50Mhz,然后通过 REFCLKO 引脚,输出 50Mhz 参考时钟给 MAC 控制器。这种方式, 可以降低 BOM成本。
我在调试初期,网购了一个LAN8720的模块,该模块采用的 REF_CLK IN 模式,通过杜邦线连接到了STM32F407的开发板上,该模块原理图参看如下:
调试该模块出现过以下问题:
- 由于杜邦线比较脆弱,其中有几根内部断掉了,我未察觉,导致寄存器读写失败。
- 寄存器读写正常,但是网络不通。
我们重点谈一下第二个问题,各大论坛上也有出现同样问题的朋友,有的是因为GPIO未初始化,或者因为参照的正点原子的例程,GPIOG或者GPIOB设置错误。比如接在了GPIOG上代码里却初始化的GPIOB。代码如下:
//配置PG11, PG14 and PG13
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_11 | GPIO_Pin_13 | GPIO_Pin_14;
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(GPIOG, &GPIO_InitStructure);
GPIO_PinAFConfig(GPIOG, GPIO_PinSource11, GPIO_AF_ETH);
GPIO_PinAFConfig(GPIOG, GPIO_PinSource13, GPIO_AF_ETH);
GPIO_PinAFConfig(GPIOG, GPIO_PinSource14, GPIO_AF_ETH);
我这边出现的什么问题呢?如下:
寄存器读写没问题,但是网络始终ping不通。查看了以下电脑端网卡设置的自动匹配百兆和10M以及全双工半双工模式。这个可以在电脑管理中查看。
再来看STM32F407端:
u8 ETH_MACDMA_Config(void)
{
u8 rval;
ETH_InitTypeDef ETH_InitStructure;
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_ETH_MAC | RCC_AHB1Periph_ETH_MAC_Tx |RCC_AHB1Periph_ETH_MAC_Rx, ENABLE);
ETH_DeInit();
ETH_SoftwareReset();
while (ETH_GetSoftwareResetStatus()