目录
最近用单片机搞网络通信一直ping不通,看了很多教程都没搞好,踩了一些坑最后调出来了,来记录一下,我最开始是用野火的板子上的LAN8720去测试CUBEMX配置,后面转到自己手上的YT8512C板子上,但是踩坑的地方基本都是自己的板子,所以我主要用自己板子的设置来写这篇博客。
使用的CUBEMX版本是6.15.0,使用的H7包版本是1.12.1。
1、硬件连接
首先贴一下硬件连接,我用的是RMII。这里简单说一下MII和RMII以及RGMII的通信速率,MII和RMII支持的是10M和100M网络,RGMII才能支持千兆,反正大家只要知道,带G的才能支持千兆就行了,目前的STM32的单片机只支持10M和100M,千兆的N系列还没上市,国产单片机倒是有支持千兆的。

需要注意的是,REF_CLK_50M这个引脚是需要50MHz的时钟输入,有两种方式去提供这个50M时钟。但无论哪种方式,芯片本身都需要25Mhz时钟源工作。
第一种是外接50MHz的时钟,有两个方式去得到这个时钟,第一个是用单片机的能够用做 MCO 输出的引脚去提供,也就是说你还必须把MCO引脚连接到REF_CLK,第二个是你直接外接50MHz的晶振。这个很重要,如果大家直接购买带座子的模块的话,模块的连接图你是看不出来的,我这边做板子的硬件工程师没注意这点,板子飞了线才解决。
第二种是这个50MHz由PHY芯片提供,我这里用的芯片是YT8512C,要设置这种模式,就得去配置芯片的引脚。对于YT8512C而言,配置RX_DV,RXD3两个引脚为1,0即可,但我手上的的板子用的是集成模块,这两个引脚没有引出来不能配置,所以大家如果用集成座子的模块的话,要注意这点。
另外,PHY芯片的SMI通信地址是由PHY_AD0和PHY_AD1两个引脚来提供的,芯片内部有下拉,不接的情况下就是00。



2、CUBEMX设置
(1)ETH的设置
选择mode,我用的是RMII,大的红框是接收和发送描述符的地址以及接收缓冲区的地址,这个我没有深入研究,直接抄的野火的设置。野火和正点的例程里还有MPU Cache的设置。我也贴一下好了,抄他们的CUBEMX设置如下图,我完整的项目里用了很多DMA做ADC传输,发现Cache的设置会影响DMA的传输,会有一些数据读不到。这个问题我还没有解决,不开Cache的话暂时我没发现会对网络通信有啥影响,看别人的帖子说,不开网速会慢一点。


然后是端口的设置,GPIO口一定要和自己的板子对应,另外就是设置GPIO的输出速度,全部设置成最高,这个得在GPIO的那个选项里改,ETH里面改不了。


中断不用也可以开着,省事,免得后续还得打开。

(2)LWIP的设置
打开LWIP,关闭DHCP(自动获取IP地址),使用静态ip,然后设置IP、掩码、网关,这里要和通信的机子设置到同一个网段才行,我自己的电脑设置的是192.168.1.54的IP,所以我板子的设置一定是192.168.1.xxx的ip和网关。

checksum全关,把红框的disabled就行。

这里的没啥可选的,只提供LAN8742,如果你用的是LAN8720,就是能直接兼容的。我用的是YT8512C,生成的芯片驱动里面还得改点东西。
这里我的设置我都是默认的,红框的内容可以看到这是和前面Cache的内容对应的。有时间我会去研究一下再更。

(3)MCO的设置(如果你需要用)
MCO的意思是时钟输出生成,H743有两个IO PA8和PC9 可以用作这个功能


设置如图所示,开启外部高速时钟输入,和MCO输出。这里我着重讲一下GPIO的输出速度,一定要根据你的输出时钟频率来,low的情况下是不能输出50Mhz的,原则是越高越好。

我的MCO2输出50MHz是这样配的,大家可以参考参考,反正方式肯定不止一种

3、keil代码部分
记得把微库打开,LWIP的DEBUG信息用的都是printf。不开容易出问题

(1)main函数
这是主函数里的代码,比较简单,自动生成之后,就往while里面加MX_LWIP_Process就行。如果你用了Cache,记得加透传。不用的话,SCB这几行注释掉也不影响的。我自己的代码加了串口有重定向,不开有无影响没有调试。
#include <stdio.h>
int fputc(int ch, FILE *f)
{
HAL_UART_Transmit(&huart1, (uint8_t *)&ch, 1, 0xffff);
return ch;
}
int main(void)
{
/* USER CODE BEGIN 1 */
/* USER CODE END 1 */
/* MPU Configuration--------------------------------------------------------*/
MPU_Config();
/* Enable the CPU Cache */
/* Enable I-Cache---------------------------------------------------------*/
SCB_EnableICache();
/* Enable D-Cache---------------------------------------------------------*/
SCB_EnableDCache();
/*** 透传 ***/
SCB->CACR|=1<<2;
/* MCU Configuration--------------------------------------------------------*/
/* Reset of all peripherals, Initializes the Flash interface and the Systick. */
HAL_Init();
/* USER CODE BEGIN Init */
/* USER CODE END Init */
/* Configure the system clock */
SystemClock_Config();
/* Configure the peripherals common clocks */
PeriphCommonClock_Config();
/* USER CODE BEGIN SysInit */
/* USER CODE END SysInit */
/* Initialize all configured peripherals */
MX_GPIO_Init();
MX_LWIP_Init();
MX_USART1_UART_Init();
/* USER CODE BEGIN 2 */
// SCB->CACR |= 1 << 2;
//printf("dara:\r\n");
/* USER CODE END 2 */
/* Infinite loop */
/* USER CODE BEGIN WHILE */
while (1)
{
MX_LWIP_Process();
/* USER CODE END WHILE */
/* USER CODE BEGIN 3 */
}
/* USER CODE END 3 */
}
(2) LAN8720的适配
虽然说LAN8720和LAN8740理论上完全可以适配,有的博客也是这样说的,但我用野火的板子自动生成的CUBEMX代码并不能不改东西ping通,不知道是不是因为我的CUBE版本和他们的不一样。操作如下。
跳转

跳转

增加红框的代码内容,然后就可以ping通了。

(3)YT8512C的适配
调网络我们主要关注三个寄存器,BCR(基本控制寄存器),BSR(基本状态寄存器),PHY特殊功能寄存器(PHYSCSR)。而HAL库是适配的LAN8740/LAN8720的,我给出LAN8720和YT8512C的寄存器对比。
YT8512C和LAN8720的差异
首先是BCR,上面的是8512C,下面的是LAN8720,寄存器地址都是00H,除了bit7、bit6其他都一样


BSR,依旧是上面YT8512C,下面LAN8720,寄存器地址都是01H。可以看到基本一致。


到了特殊功能寄存器,依旧是上面YT8512C,下面LAN8720。可以看到,这里二者的差异就比较大了,不仅bit位很多不同,而且YT8512C的寄存器地址是11H,LAN8720的寄存器地址是1FH。


YT8512C需要做适配的更改
介绍差异就是为了告诉大家要怎么改,和前面一样,先改这里。

跳转low_level_init

跳转ethernet_link_check_state

跳转LAN8742_GetLinkState

把原先的内容注释掉,加上红框的内容。这么做的原因就是因为这部分代码内容是读特殊功能寄存器内容更新LWIP的网络接口配置。但是LAN8720和YT8512的特殊功能寄存器有差异,所以这个地方必须要改。

红框这个宏是我自己加的,为了以后看起来方便点,不写宏就把用YT8512C_PSSR的地方替换成0x0011是一样的。

这样配置下来,我的板子上的YT8512C就能ping通了。
4、电脑的网络配置
把这里改改就好了,我的电脑不需要关闭防火墙也能ping通,实在ping不通可以试试把防火墙关了。


5、使用过的debug方式
读取PHY芯片的寄存器,PHY_ADDRESS就是由PHY_AD0和PHY_AD1两个引脚来提供的SMI地址。把读到的值打印出来可以很直观的看到芯片的状态,和芯片手册上的寄存器说明对照着看能找到很多问题。如果读不出来说明你芯片的硬件连接方面可能有问题。相反如果各个寄存器的值都正常,那就得找找软件上以及PC通信的问题了。
uint32_t reg_value;
HAL_ETH_ReadPHYRegister(&heth, PHY_ADDRESS, REG_ADDRESS, ®_value); // 0x01是BSR地址
printf("PHY BCR: 0x%04X\n", reg_value);
1万+

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



