STM32H743用CubeMX生成裸机代码,修改支持YT8512C、LAN8742、LAN8720三种phy芯片的以太网,且底层支持选择TCP客户端、TCP服务器、UDP三种通讯模式
前言
1、使用的CubeMx版本是6.15.0
2、编程软件使用的是keil V5.33
3、函数库:STM32Cube_FW_H7 V1.12.1
4、Lwip使用版本为:2.12
注意:使用静态IP,不检测网线拔出
正文:
1、硬件相关,使用PHY芯片为YT8512C,网络标号 EBATN电压为3.3V,PA6是复位



2、硬件STM32H743相关



3、根据晶振及phy芯片周围相关信息,配置STM32CubeMx
3.1、配置工程编译器及库版本

3.2、配置选择加载的库

3.3、选择烧写模式,这个很重要,不选这个之后就不能通过常规模式烧写程序了

3.4、选择启用外部晶振

3.5、修改时钟树-原则尽可能使用最高主频、使用外部晶振

3.6、选择phy的外部复位引脚,低电平复位,默认设为高电平,开关速度调整为最高

3.7、根据硬件选择Lwip的引脚,如果自动配置的引脚不是自己设置的要改成和硬件匹配的引脚“不是说所有的引脚都可以用,只有个别引脚有替换项,单片机不是FPGA不能做到所有的IO通用”,注意要把所有的IO改成最高频率,在这个页面能直接改,点击一下,下面会弹出配置界面


3.8、开启中断

3.9、设置MAX地址及配置地址,MAX地址可以更改

4、配置STM32H743的软件部分
4.1、配置MPU部分


4.2、由于当前版本的CubeMx只有LAN8742的phy芯片,所以先按照这个配置,生成代码后做修改
4.2.1、基础配置

4.2.2、


4.2.3、

4.2.4、

5、配置完成后代码生成

6、打开代码,修改代码,加上LAN8720和YT8512C的选项
6.1、打开文件“lan8742.h”
#define YT8512Cen 1//使用PHY芯片名称 如果是为1,如果不是为0
#define LAN8742en 0//使用PHY芯片名称 如果是为1,如果不是为0
#define LAN8720en 0//使用PHY芯片名称 如果是为1,如果不是为0
#define ETH_RESET_IO_ResSet HAL_GPIO_WritePin(GPIOA, GPIO_PIN_6, GPIO_PIN_RESET)//开启硬件复位 lwip.c 中调用
#define ETH_RESET_IO_ResOver HAL_GPIO_WritePin(GPIOA, GPIO_PIN_6, GPIO_PIN_SET)//关闭硬件复位 lwip.c 中调用

#define YT8512C_PSSR ((uint16_t)0x0011U)

6.2、代开文件“lan8742.c”,找到函数“int32_t LAN8742_GetLinkState(lan8742_Object_t *pObj)”在259行
从308行删除与修改代码如下
/*新增部分YT8512C*/
#if YT8512Cen
if(pObj->IO.ReadReg(pObj->DevAddr, YT8512C_PSSR, &readval) < 0)
{
return LAN8742_STATUS_READ_ERROR;
}
if(readval & 0x4000)
{
if(readval & 0x2000)
return LAN8742_STATUS_100MBITS_FULLDUPLEX;
else
return LAN8742_STATUS_100MBITS_HALFDUPLEX;
}else
{
if(readval & 0x2000)
return LAN8742_STATUS_10MBITS_FULLDUPLEX;
else
return LAN8742_STATUS_10MBITS_HALFDUPLEX;
}
#endif
/*新增部分YT8512C*/
#if (LAN8742en | LAN8720en)
if(pObj->IO.ReadReg(pObj->DevAddr, LAN8742_PHYSCSR, &readval) < 0)
{
return LAN8742_STATUS_READ_ERROR;
}
/* Check if auto nego not done */
if((readval & LAN8742_PHYSCSR_AUTONEGO_DONE) == 0)
{
return LAN8742_STATUS_AUTONEGO_NOTDONE;
}
if((readval & LAN8742_PHYSCSR_HCDSPEEDMASK) == LAN8742_PHYSCSR_100BTX_FD)
{
return LAN8742_STATUS_100MBITS_FULLDUPLEX;
}
else if ((readval & LAN8742_PHYSCSR_HCDSPEEDMASK) == LAN8742_PHYSCSR_100BTX_HD)
{
return LAN8742_STATUS_100MBITS_HALFDUPLEX;
}
else if ((readval & LAN8742_PHYSCSR_HCDSPEEDMASK) == LAN8742_PHYSCSR_10BT_FD)
{
return LAN8742_STATUS_10MBITS_FULLDUPLEX;
}
else
{
return LAN8742_STATUS_10MBITS_HALFDUPLEX;
}
#endif


6.3、打开代码“ethernetif.c”,定位到39行的“err_t ethernetif_init(struct netif *netif)”内
#if (YT8512Cen | LAN8720en)
/*新增部分*/
struct ethernetif *ethernetif;
ethernetif = mem_malloc(sizeof(ethernetif));
if (ethernetif == NULL) {
return ERR_MEM;
}
/*新增部分*/
#endif
#if (YT8512Cen | LAN8720en)
/*新增部分*/
netif->state = ethernetif;
/*新增部分*/
#endif

6.4、打开代码“Lwip.c”,注意“AppLwip.h”这个是为了TCP两种模式和UDP通讯准备的,也为了调用gpio.h,因为用到了复位引脚,要在Lwip初始化前复位管脚
不考虑 TCP两种模式和UDP通讯 ,可以把 #include "AppLwip.h" 改成 #include "gpio.h"
#include "lan8742.h"
#include "AppLwip.h"

lwip_comm_default_ip_set(&g_lwipdev); /* 设置默认IP等信息 */
/* 默认本地IP为:192.168.1.100 */
IP_ADDRESS[0] = g_lwipdev.ip[0];
IP_ADDRESS[1] = g_lwipdev.ip[1];
IP_ADDRESS[2] = g_lwipdev.ip[2];
IP_ADDRESS[3] = g_lwipdev.ip[3];
/* 默认子网掩码:255.255.255.0 */
NETMASK_ADDRESS[0] = g_lwipdev.netmask[0];
NETMASK_ADDRESS[1] = g_lwipdev.netmask[1];
NETMASK_ADDRESS[2] = g_lwipdev.netmask[2];
NETMASK_ADDRESS[3] = g_lwipdev.netmask[3];
/* 默认网关:192.168.1.1 */
GATEWAY_ADDRESS[0] = g_lwipdev.gateway[0];
GATEWAY_ADDRESS[1] = g_lwipdev.gateway[1];
GATEWAY_ADDRESS[2] = g_lwipdev.gateway[2];
GATEWAY_ADDRESS[3] = g_lwipdev.gateway[3];
//透传 tou chuan
SCB->CACR |= 1 << 2;
ETH_RESET_IO_ResSet; /* 开启硬件复位 kai qi fu wei */
HAL_Delay(100);
ETH_RESET_IO_ResOver; /* 关闭硬件复位 guan bi fu wei */
HAL_Delay(100);

6.5、以上配置每次使用MxCube代码生成一次会被覆盖,每次都配置比较麻烦,可以在代码生成后覆盖一次
修改后,把文件保存下来,把里面的东西直接覆盖

6.6、代码修改后,修改一下MDK的配置

7、加入TCP和UDP模式,并引入时间片轮询调度
7.1、准备文件放入工程 “APP”和"BSP"

APP和BSP内部分为两个文件夹,“Inc”放头文件,“Scr”放源文件


各自的文件下的内容如下,头文件下有对应的.h文件,就不放图了


7.2、把文件导入工程
7.2.1、加载头文件目录

7.2.2、把源文件添加到工程目录

7.3、打开 “main.c”文件,找到“int main(void)”的“while (1)”附近

添加如下代码,位置不要搞错了,不然重新生成代码的时候会被屏蔽掉
InitMain();
App_task();

7.4、复制“main.c”所引用的头文件,粘贴到“main.h”文件的头文件引用出,注意“#include "lwip.h"”不要复制,用到的头文件复制,用不到的可以不用复制。再加一个头文件“#include "AppTask.h"”

注意在“main.h”的位置不要搞错,不然再一次生成的时候会被覆盖掉

8、修改完成后,介绍一下当前的代码
8.1、“AppTask.c”是一个时间片轮询调度算法,使用以太网,RunLwip函数必须开启,且要实时运行


8.2、"AppLwip.h"文件是配置界面

8.3、"AppLwip.c"文件是以太网通讯的应用文件
8.3.1、选择以太网通讯模式

8.3.2、后配置本机IP地址、网关、掩码、MAC地址暂时还是使用CubeMx生成的,这里的Max地址不作数。

8.3.3、Lwip选型通讯类型初始化

8.3.4、实时运行,保证Lwip正常运行

8.3.5、用以太网发送信息的API接口,应用层可以调用这个接口

8.3.6、以太网接收到数据后会的这个函数,并传递接收到信息

9、BSP底层的东西不需要动

10、编译烧写进入,验证
10.1、UDP模式

10.1.1、ping一下

10.1.2、udp通讯

10.2、TCP服务器模式
硬件做服务器,电脑要做客户端

10.2.1、ping一下

10.2.2、通讯一下

10.3、改成TCP客户端模式,主动发送一帧信息


10.3.1、ping,ping 的时候电脑作为TCP服务器连接着

10.3.2、通讯
打开服务器

烧录程序运行后

11、完成并分析
通过以上的操作STM32H743可以用YT8512C的PHY的芯片进行TCP客户端、TCP服务器、UDP通讯。
缺点:分析一下,电脑发送的时刻到接收到返回信号用时大约18ms,通讯延时比较严重。上一篇用正点原子的程序及Lwip的库也是有这个延时。这个延时对实时性影响还是比较大,暂时没想到方法解决...











