之前用的w5500,无奈芯片越来越贵了,正好手头上有100来颗lan8720a,直接将方案改了吧。
以前在深圳工作时公司的网关正好用的这个方案,直接抄吧。
硬件设计网口无晶振,由mcu的mco脚输出,50Mhz模式,其他都是通用连接方式
接下来入正题:由于以前用的标准库,现在试一试hal库。打开cubemx,一顿骚操作后配置完成,生成代码。
第一个问题,调试口,官方默认如果不设置就关闭swd和jtag,造成无法2次下载程序,需要将system core->sys->debug改成对应模式,我用的serial wire,即swd。
接下来可以正常调试了,功能上仅仅使能了dhcp,但代码跑起来完全失败。
第二个问题,地址设置,需要将eth->parameter settings->general:ethernet configuration->phy address改成对应的值,我这边是0.
好了,再试,依然不行,接下来我用示波器看了一下mco脚,也确实有50mhz
第三个问题,代码都是采用的默认参数,有些参数偏小,修改的部分有默认任务栈空间调大,操作系统堆空间加大,当然这个可能和结果无关,过程得记录下来
还是不行,无奈将之前标准库代码拿来试一下,完全没问题。
对比代码,加入了几个打印信息,确定芯片id能否识别。由于cubemx并没有生成其id寄存器偏移地址,所以这里直接写死
uint32_t id_0,id_1;HAL_ETH_ReadPHYRegister(&heth,2,&id_0);HAL_ETH_ReadPHYRegister(&heth,3,&id_1);printf("PHY_ID = %X\n", (id_0<<16) | (id_1));
其中寄存器地址2和3分别对应文档以下说明
最后id读出来了,完全没问题。
于是第四个问题,又从lwip内部着手,但是我查了半天也没看到cubemx怎么将lwip的debug功能开启,只能开启全局的,各功能模块根本没有,于是找到lwipopts.h文件,添加以下内容
#define DHCP_DEBUG 0xf7
#define UDP_DEBUG 0xf7
#define NETIF_DEBUG 0xf7
这里千万别让第4位为1,即0x08,因为这个位是是否阻塞功能的,看下面代码段
好了,继续看结果吧,总的来说就是dhcp一直在广播,没收到回复而超时。
那就只能对比以前的代码了。最终发现
最后关键问题。生成的代码在自动协商速率完成后读取的是寄存器1的结果,然后我看网上有的说是31,我看手册上也确实有说31可以读到
这里我就断点调试查看了一下读出来的值,结果是0x04(00000100),即速度那儿是001 ,对应的是10m 半双工,这就不对了。
反过来我看之前的代码,读取的是地址1,确实也有速度指示
于是,我就改成以前的方式再试,果不其然,成功了。
文件stm32f1xx_hal_eth.c
函数HAL_ETH_Init
在auto-negotiation完成后
/* Read the result of the auto-negotiation */if ((HAL_ETH_ReadPHYRegister(heth, PHY_BSR, &phyreg)) != 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;}//上面是原生成代码//HAL_ETH_ReadPHYRegister(&heth, PHY_BSR, ®value);if((phyreg & PHY_100M_T4) != (uint32_t)RESET){/* Set Ethernet duplex mode to FullDuplex following the autonegotiation */(heth->Init).DuplexMode = ETH_MODE_FULLDUPLEX;(heth->Init).Speed = ETH_SPEED_100M;}else if((phyreg & PHY_100M_Duplex) != (uint32_t)RESET){/* Set Ethernet duplex mode to FullDuplex following the autonegotiation */(heth->Init).DuplexMode = ETH_MODE_FULLDUPLEX;(heth->Init).Speed = ETH_SPEED_100M;}else if((phyreg & PHY_100M_Half) != (uint32_t)RESET){/* Set Ethernet duplex mode to FullDuplex following the autonegotiation */(heth->Init).DuplexMode = ETH_MODE_HALFDUPLEX;(heth->Init).Speed = ETH_SPEED_100M;}else if((phyreg & PHY_10M_Duplex) != (uint32_t)RESET){/* Set Ethernet duplex mode to FullDuplex following the autonegotiation */(heth->Init).DuplexMode = ETH_MODE_FULLDUPLEX;(heth->Init).Speed = ETH_SPEED_10M;}else if((phyreg & PHY_10M_Half) != (uint32_t)RESET){/* Set Ethernet duplex mode to FullDuplex following the autonegotiation */(heth->Init).DuplexMode = ETH_MODE_HALFDUPLEX;(heth->Init).Speed = ETH_SPEED_10M;}#if 0 //原生成代码/* Configure the MAC with the Duplex Mode fixed by the auto-negotiation process */if ((phyreg & PHY_DUPLEX_STATUS) != (uint32_t)RESET){/* Set Ethernet duplex mode to Full-duplex following the auto-negotiation */(heth->Init).DuplexMode = ETH_MODE_FULLDUPLEX;}else{/* Set Ethernet duplex mode to Half-duplex following the auto-negotiation */(heth->Init).DuplexMode = ETH_MODE_HALFDUPLEX;}/* Configure the MAC with the speed fixed by the auto-negotiation process */if ((phyreg & PHY_SPEED_STATUS) == PHY_SPEED_STATUS){/* Set Ethernet speed to 10M following the auto-negotiation */(heth->Init).Speed = ETH_SPEED_10M;}else{/* Set Ethernet speed to 100M following the auto-negotiation */(heth->Init).Speed = ETH_SPEED_100M;}#endif
其中几个宏定义如下
#define PHY_100M_Duplex (0x4000)
#define PHY_100M_Half (0x2000)
#define PHY_10M_Duplex (0x1000)
#define PHY_10M_Half (0x0800)
#define PHY_100M_T4 (0x8000)
另外修改的地方不止这一个,还有一个地方在连接状态更新那儿,这个我就不细说了
回过头来思考,其实寄存器31也可以,但为啥就是不对呢,值得注意的是这个是special修饰了的,难到是要进入某个模式吗,这个我现在反正没搞懂
另外可以考虑修改以下定义,以免动原生库文件
根据代码分析应该不难,这里也不再研究