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

  • Post author:
  • Post category:其他




前言

之前我写了一个用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的代码加入工程,但我没试过,如果有试过的,希望能做成一期博客分享给我。

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



版权声明:本文为lrqblack原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。