【LWIP】(补充)STM32H743(M7内核)CubeMX配置LWIP并ping通

前言

之前我写了一个用CubeMX配置LWIP以太网通讯的博客:
【LWIP】stm32用CubeMX配置LwIP+Ping+TCPclient+TCPserver发送信息到PC(操作部分)
当时用的是F207、F407加上LAN8720、DP83848做了测试,效果都是很好的。但是当我第一次在STM32H743的时候突然傻眼了,H743用CubeMX配置以太网方法与其他内核的芯片有很大不同,估计很多同学在从F1\F2\F4转到STM32 M7系列配置以太网的时候都和我一样,一开始信心满满,然后一头雾水。
于是我经过两天琢磨,搞出来一个STM32H743(M7内核)的CubeMX配置LWIP以太网的ping通教程。包教包会!

接下来开始做事(由于某些特殊原因~,无法上传高清图片,很抱歉,请各位摘下眼镜将就看看)

1、配置CubeMX

打开CubeMX,选择完芯片后:
在CORTEX_M7里面:使能DCache。MPU控制模第三个“only+disable”
(M7内核相对于其他常见的学习板不同,是有缓存的,而且芯片内部有两段内存是不允许外设访问的,所以你不配置这mpu就绝对ping不通。)
第一个配置如图,主要是先开起来MPU功能,随便配置一个就好,这样生成的代码就带有MPU的设置和初始化,后面我们替换成自己写好的MPU代码。
在这里插入图片描述
RCC:因为我这块板子上只有外部高速晶振,所以使能外部高速晶振,各位按实际硬件的来就好。
然后把电源调节器电压范围选择scale0,这样我们就能把主频调到最高。(很多刚用H7的新手会发现主频率调不高,大概就是这里的问题)。
这里把时钟配置到400,因为我的项目之前是这么配的,所以要一致。这里配480完全可以。
在这里插入图片描述

直接自动配置,很方便!
在这里插入图片描述
为了调试,必然要打开串口,根据实际硬件进行配置。
在这里插入图片描述
ETH:因为硬件是RMII,所以选择RMII。你硬件是MII就可以选MII。(但特别注意,MII需要在CLK引脚上提供25M时钟,而RMII需要50M时钟,如果没有配置外部晶振,就要在时钟配置中用MCO给这条线上供给时钟,不同的PHY芯片对外部晶振提供的时钟又有不同的处理方式,比如8720能把外部25M时钟内部倍频出50M,而DP83848RMII模式下就得老老实实焊一个50M晶振,这里很容易出错)
注意IO口和硬件要对应,速度一定要是高速,我有一次忘记配置,默认低速就无法ping通。
然后接收和发送缓存描述符默认就行,注意接收缓存地址我选择30040200才ping通,心里要稍微记住这几个数值,有需要可以研究着改改。
在这里插入图片描述在这里插入图片描述
姑且把中断勾起来,这样想用中断的时候就能直接用了。
在这里插入图片描述
配置LWIP:
只有LAN8742,别无选择,,8720可以通用,如果不是8742系列,后面我会带着大家修改寄存器。
在这里插入图片描述
为了方便,开发板改成静态IP,这个IP一定要和你的主机在同一个子网下,也就是主机号相同,我这边是192.168.0,这个可以在自己电脑上查一下。ICMP(ping功能)和TCP开起来,这俩应该是默认开的。
在这里插入图片描述
这个回调功能打开来,就可以自己在这里写点函数,应该都是默认的。
在这里插入图片描述
生成keil代码!
在这里插入图片描述

2、接下来是配置MDK!

打开keil5(MDK),勾上这两个,其他的常规配置不用多说了,大家都懂的,前面的教程也说过。
在这里插入图片描述
串口重定向,不用多说!
养成好习惯,串口设置好后编译一下,看看能不能正常输出,这也是为了之后方便打开.h头文件。
#include "stdio.h"放在需要用到串口打印的文件中(都是十分基础的东西)。

int fputc(int ch, FILE *f)
{
//具体哪个串口可以更改huart1为其它串口
HAL_UART_Transmit(&huart1 , (uint8_t *)&ch, 1 , 0x0f);
return ch;
}

在这里插入图片描述
主循环加入这个功能。这就在主循环里轮询检查了,当然这样更耗资源,但我们不是勾选了中断嘛,先ping通,后面再说怎么用中断。
MX_LWIP_Process();

在这里插入图片描述
在时钟配置之后加入一个100毫秒的延时,我在这里出过BUG,不知道是啥原因,反正延时了就好了,不碍事就加上吧!
在这里插入图片描述

在PHY层芯片初始化(GPIO、CLOCK、NVIC和传输模式配置)之前加入一个复位!其实就是连接PHY芯片复位引脚的那个GPIO拉低拉高一下。
在这里插入图片描述

复制替换MPU配置代码!我们在cubeMX中打开了MPU,这个函数就会出现,我们灵活根据需要修改就好了。我这边是设立了两个MPU,这很关键!
在这里插入图片描述
MPU代码复制:

void MPU_Config(void)
{
MPU_Region_InitTypeDef MPU_InitStruct;

/* Disable the MPU */
HAL_MPU_Disable();

/* Configure the MPU attributes as Device not cacheable
for ETH DMA descriptors */
MPU_InitStruct.Enable = MPU_REGION_ENABLE;
MPU_InitStruct.BaseAddress = 0x30040000;
MPU_InitStruct.Size = MPU_REGION_SIZE_256B;
MPU_InitStruct.AccessPermission = MPU_REGION_FULL_ACCESS;
MPU_InitStruct.IsBufferable = MPU_ACCESS_BUFFERABLE;
MPU_InitStruct.IsCacheable = MPU_ACCESS_NOT_CACHEABLE;
MPU_InitStruct.IsShareable = MPU_ACCESS_NOT_SHAREABLE;
MPU_InitStruct.Number = MPU_REGION_NUMBER0;
MPU_InitStruct.TypeExtField = MPU_TEX_LEVEL0;
MPU_InitStruct.SubRegionDisable = 0x00;
MPU_InitStruct.DisableExec = MPU_INSTRUCTION_ACCESS_ENABLE;

HAL_MPU_ConfigRegion(&MPU_InitStruct);

/* Configure the MPU attributes as Cacheable write through
for LwIP RAM heap which contains the Tx buffers */
MPU_InitStruct.Enable = MPU_REGION_ENABLE;
MPU_InitStruct.BaseAddress = 0x30044000;
MPU_InitStruct.Size = MPU_REGION_SIZE_16KB;
MPU_InitStruct.AccessPermission = MPU_REGION_FULL_ACCESS;
MPU_InitStruct.IsBufferable = MPU_ACCESS_NOT_BUFFERABLE;
MPU_InitStruct.IsCacheable = MPU_ACCESS_CACHEABLE;
MPU_InitStruct.IsShareable = MPU_ACCESS_NOT_SHAREABLE;
MPU_InitStruct.Number = MPU_REGION_NUMBER1;
MPU_InitStruct.TypeExtField = MPU_TEX_LEVEL0;
MPU_InitStruct.SubRegionDisable = 0x00;
MPU_InitStruct.DisableExec = MPU_INSTRUCTION_ACCESS_ENABLE;

HAL_MPU_ConfigRegion(&MPU_InitStruct);

  /* Enables the MPU */
  HAL_MPU_Enable(MPU_PRIVILEGED_DEFAULT);

}

在lwip.c的头文件下找到lwipopt.h,加入debug代码,这样就能在串口看到你的网络出什么问题了(注意在实际工程中要关闭debug代码,否则打印太耗资源,ping通时间会长达100ms,关闭后就正常1ms ping通了)
在这里插入图片描述LWIP调试代码如下,很好用!

#define LWIP_DEBUG

#define LWIP_DBG_TYPES_ON               LWIP_DBG_ON
/* USER CODE BEGIN 1 */
#define LWIP_DBG_MIN_LEVEL              LWIP_DBG_LEVEL_OFF
//#define LWIP_DBG_MIN_LEVEL              LWIP_DBG_LEVEL_WARNING
//#define LWIP_DBG_MIN_LEVEL              LWIP_DBG_LEVEL_SERIOUS
//#define LWIP_DBG_MIN_LEVEL              LWIP_DBG_LEVEL_SEVERE
 
#define LWIP_DBG_TYPES_ON               LWIP_DBG_ON
//#define LWIP_DBG_TYPES_ON               (LWIP_DBG_ON|LWIP_DBG_TRACE|LWIP_DBG_STATE|LWIP_DBG_FRESH)
 
#define ETHARP_DEBUG                    LWIP_DBG_ON     
#define NETIF_DEBUG                     LWIP_DBG_ON     
#define PBUF_DEBUG                      LWIP_DBG_ON
#define API_LIB_DEBUG                   LWIP_DBG_ON
#define API_MSG_DEBUG                   LWIP_DBG_ON
#define SOCKETS_DEBUG                   LWIP_DBG_ON
#define ICMP_DEBUG                      LWIP_DBG_ON
#define IGMP_DEBUG                      LWIP_DBG_ON
#define INET_DEBUG                      LWIP_DBG_ON
#define IP_DEBUG                        LWIP_DBG_ON     
#define IP_REASS_DEBUG                  LWIP_DBG_ON
#define RAW_DEBUG                       LWIP_DBG_ON
#define MEM_DEBUG                       LWIP_DBG_ON
#define MEMP_DEBUG                      LWIP_DBG_ON
#define SYS_DEBUG                       LWIP_DBG_ON
#define TCP_DEBUG                       LWIP_DBG_ON
#define TCP_INPUT_DEBUG                 LWIP_DBG_ON
#define TCP_FR_DEBUG                    LWIP_DBG_ON
#define TCP_RTO_DEBUG                   LWIP_DBG_ON
#define TCP_CWND_DEBUG                  LWIP_DBG_ON
#define TCP_WND_DEBUG                   LWIP_DBG_ON
#define TCP_OUTPUT_DEBUG                LWIP_DBG_ON
#define TCP_RST_DEBUG                   LWIP_DBG_ON
#define TCP_QLEN_DEBUG                  LWIP_DBG_ON
#define UDP_DEBUG                       LWIP_DBG_ON     
#define TCPIP_DEBUG                     LWIP_DBG_ON
#define PPP_DEBUG                       LWIP_DBG_ON
#define SLIP_DEBUG                      LWIP_DBG_ON
#define DHCP_DEBUG                      LWIP_DBG_ON     
#define AUTOIP_DEBUG                    LWIP_DBG_ON
#define SNMP_MSG_DEBUG                  LWIP_DBG_ON
#define SNMP_MIB_DEBUG                  LWIP_DBG_ON
#define DNS_DEBUG                       LWIP_DBG_ON

重头戏来了,因为cubeMX只预置了LAN8742的配置,而我们用的是DP83848,应该是ping不通的,所以寄存器要更改。
首先,在配置cube的时候会发现,在207、407的配置里,会要求填写PHY Address,这个和上电时PHYAD引脚上的电平有关,但H7系列配置的时候并没有要求填写,为什么呢?我们来看这一段程序,在lan8720.c中。
在这里插入图片描述

原来cube中用了这一段程序来循环检查PHY芯片中存有PHY地址的寄存器,实现自动读取,这个寄存器在lan8742中偏移18,而在DP83848中偏移0x19,所以我们要把红圈部分修改为0x19。(如果你对你的硬件很有把握,知道上电后PHYAD引脚的状态,可以直接注释掉上面截图中的所有代码,用两行代码直接给下面两个变量赋值。pObj->DevAddr = DP83848_PHY_ADDRESS; status = LAN8742_STATUS_OK; 这里的DP83848_PHY_ADDRESS是你的PHY地址值,比如83848,五根PHYADx引脚,上电时如果没有硬件拉高或拉低,那就由于PHYAD0内部弱上拉,其余四根内部弱下拉,所以就是1)

本来到了这一步网上一些教程说可以ping通了,但是我依然没有ping通,果然网上的东西还是不靠谱,得多自己研究!

后来发现,LAN8742_PHYSCSR寄存器有问题,在LAN8742中是特殊功能寄存器,它在LAN8742.h代码中是这样显示的:
在这里插入图片描述在这里插入图片描述
在这里插入图片描述

很显然,里面有一位用于开启自适应,有3位用于配置速度以及单/双工

这时候来看看我们DP83848的这个寄存器:↓↓↓
在这里插入图片描述
发现了不一样,于是我们在代码上进行修改:
在这里插入图片描述
在这里插入图片描述

最后烧录开机,完全OK!
在这里插入图片描述
特别注意,因为我开了lwip的debug,会进行大量串口输出,所以ping的时间长达200ms,这时候我们已经调通了,debug代码就完全不需要了,我回到lwipopt.h中注释掉它们,再ping一次,发现完全正常了。
在这里插入图片描述

3、ping通之后我还有一些要补充的:

3.1 高速通讯要清除缓存

我们实际项目中往往需要高速发送,这时候 及时清除缓存就有必要了。注意在需要高速数据发送的情况下,在ethernetif.c中加入两行缓存清除代码:
在这里插入图片描述在这里插入图片描述
在这里插入图片描述

3.2 字符串发送出现乱码解决

在我以前的博客里,有用407给大家配置一个客户端和服务器端,这两个代码我试了一下都可以用,但就是莫名其妙的没在407上这么好用,会出现一些问题。于是我研究着改了改。
首先是tcpserver部分代码,字符串传输回电脑会看见乱码。
在这里插入图片描述
但我们只要做出一些小小的修改就行了,如图:
在这里插入图片描述
把字符串输出的size的长度减一,这样显示就正常了!

3.3 中断接收

我们上面展示的程序是在主循环里不断地轮询,但是轮询是很消耗资源的,所以我们来尝试一下使用中断来接收信息。
还记得我在上面说过的嘛,配置CubeMX的时候要顺手勾选以太网中断,这下就能用上了!
首先在ethernetif.c里把方框里的改掉
在这里插入图片描述在这里插入图片描述

然后,我们在lwip.c中注释掉这一行,并把这一行放在stm32h7xx_it.c的ETH_IRQHandler函数中,并在这个函数中注释掉HAL_ETH_IRQHandler(&heth);
在这里插入图片描述在这里插入图片描述
可以看到这里报错了,是没有添加头文件的原因,我们只要在stm32h7xx_it.c的头部添上这两行就行了
在这里插入图片描述
最后直接ping通了!
在这里插入图片描述注意,中断模式并不只是为了节约资源,更重要的一点是解决丢包。在轮询模式ping通后,很多人就忘乎所以拿去用了,其实如果你们测一测丢包率,会发现存在%5的丢包,这在实际项目中是非常致命的!但是改用中断接收后,丢包率下降为0(如下图)。

在这里插入图片描述在这里插入图片描述可以看见确实通过改轮询方式为中断方式后,丢包消失了!

3.4 ping不通,但debug显示了前面一大段,但后面没动静了,这是怎么回事?

出现这种情况我碰见过两种原因:
第一种是你的缓冲区忘记更改了,也许你把缓冲区大小从C0改为200就行了。
第二种是芯片复位的问题,因为有些程序你不会给网卡PHY芯片配置RESET也能用,但有时候是不行的,这时候你需要给你的开发板断电然后上电,网络就能用了。

总结

以上我们就实现了一个基于cubeMX生成的代码修改后的H743+lwip的ping通程序,比207、407芯片的配置有较大不同,因为内核不同,速度也更快了,所以加入了缓存和内存保护MPU,同时代码上也有一些些不同,最重要的是只有LAN8742的配置,除此之外的所有PHY芯片都会因为引脚不同或者寄存器不同而需要或多或少的修改。
我这里主要是一个ping通操作,所以改动了两个寄存器,但是你不可能光ping通而不进行其他操作,如果你需要用到中断之类的功能,你就要去查找相应的功能的8742寄存器代码段,然后对应着DP83848手册把这些寄存器的偏移量和它里面不同功能的掩码修改成DP83848的数值。
可以用keil5自带的CMSIS生成83848头文件里的寄存器设置进行参考辅助。当然,有厉害的人可以直接利用CMSIS的代码加入工程,但我没试过,如果有试过的,希望能做成一期博客分享给我。

希望能帮上大家,希望大家踊跃留言,有建议和优化请在评论区留言,我都会看并及时回复并更正的,谢谢!

猜你喜欢

转载自blog.csdn.net/lrqblack/article/details/124353217