1.创建一个新工程,选择STM32H7,串口1,本人板子是自己做的,
stm32h750,Y版本,其实相当于stm32h743,请根据自己的板子选择芯片。
2.根据官方文档
定义ETH相关宏
Board.h中,297行
#define BSP_USING_ETH
#ifdef BSP_USING_ETH
#define PHY_USING_LAN8720A
/#define PHY_USING_DM9161CEP/
/#define PHY_USING_DP83848C/
#endif
将注释取消掉,根据自己的板子选择控制芯片。
初始化引脚和时钟,借助STM32CubeMX生成的初始化代码。这一块可以参考原子,例如MPU的初始化,将其放入void HAL_ETH_MspInit(ETH_HandleTypeDef *heth)之中。
打开HAL库对ETH的支持,修改stm32h7xx_hal_conf.h文件,打开HAL_ETH_MODULE_ENABLED宏。
实现phy_reset函数,这个根据自己板子修改,不同的 PHY 芯片复位方式不同,需要根据具体自己板卡的实际情况进行实现。
配置LWIP协议栈,先根据文章描述打开,后续再进行修改。别忘了要先保存再编译。
开始编译,此时会出现大量错误,因为工程中的drv_eth.c文件,是根据F4的HAL库制作的,放到H7上肯定编译不过……实际上F1的也编译不过,似乎只有根据F4的HAL库制作的drv_eth.c文件,所以下一步就是根据H7的库修改驱动文件。
3.具体细节不讲了,参考原子的H7例程和STM32CubeMX生成的例程,由于我本身对RTT和LWIP不是十分熟悉,前面只是常用RTT NANO,而且用KEIL居多,所以移植的可能有些简陋。重点讲下几个细节,对跟我差不多的新入坑的小伙伴可能会比较有用。
将提供的drv_eth.c复制到工程中覆盖原文件,再次编译后,会出现一个错误一个警告:
arm-none-eabi-gcc "../drivers/drv_eth.c"
../drivers/drv_eth.c6020: error: array type has incomplete element type 'struct pbuf_custom'
struct pbuf_custom rx_pbuf[ETH_RX_DESC_CNT];
^
../drivers/drv_eth.c: In function 'rt_stm32_eth_rx':
../drivers/drv_eth.c22415: warning: implicit declaration of function 'pbuf_alloced_custom' [-Wimplicit-function-declaration]
p=pbuf_alloced_custom(PBUF_RAW,framelength,PBUF_POOL,&rx_pbuf[current_pbuf_idx],RxBuff.buffer, framelength);
^
make: *** [drivers/subdir.mk66 drivers/drv_eth.o] Error 1
实际这俩是一个错误,对应的是LWIP库文件中,pbuf.h中的LWIP_SUPPORT_CUSTOM_PBUF宏,该宏的完整定义
#define LWIP_SUPPORT_CUSTOM_PBUF ((IP_FRAG && !LWIP_NETIF_TX_SINGLE_PBUF) || (LWIP_IPV6 && LWIP_IPV6_FRAG))
根据原子和CubeMX的代码,除了IP_FRAG为1外,其他的都是一样的,所以我们只需要把IP_FRAG设定为1即可,该宏定义位置为,lwipopts.h的413行。
修改后再次编译,已经可以完整通过了,但实际是不可以使用的,因为H7配置好后默认是使用dma的,但eth的dma变量使用时必须定义到0x30040000的位置,查看map文件,可以发现此时的几个变量是定义在0x20000000开始的内存,所以需要修改DMARxDscrTab、DMATxDscrTab、Rx_Buff这3个数组在RAM中的位置。由于对arm-gcc不熟悉,在这里我调试了很久,总是莫名其妙就变成在flash中的位置了,bin文件变的无比巨大,600多M!最后好不容易凑合好了,不知道写的合不合规矩,但至少是好用了。
具体修改方法:
将工程中link.lds文件,用txt打开,在MEMORY一栏,添加
SRAM3_1 (rw) : ORIGIN =0x30040000,LENGTH =32k
SRAM3_2 (rw) : ORIGIN =0x30040060,LENGTH =32k
SRAM3_3 (rw) : ORIGIN =0x30040200,LENGTH =32k
然后在下面SECTIONS中,添加
.SRAM31 (NOLOAD) : ALIGN(4)
{
. = ALIGN(4);
(.SRAM3_1) (.SRAM31.*)
. = ALIGN(4);
__SRAM3_1_free = .;
} > SRAM3_1
.SRAM32 (NOLOAD) : ALIGN(4)
{
. = ALIGN(4);
(.SRAM3_2) (.SRAM32.*)
. = ALIGN(4);
__SRAM3_2_free = .;
} > SRAM3_2
.SRAM33 (NOLOAD) : ALIGN(4)
{
. = ALIGN(4);
(.SRAM3_3) (.SRAM33.*)
. = ALIGN(4);
__SRAM3_3_free = .;
} > SRAM3_3
+ 修改完成后,在工程中双击该文件,会显示为:
![2.png](/uploads/20200716/a0ed3ccdcbd99d929a45eb00d6bc4bc6.png)
+ 然后在drv_eth.c中,在DMARxDscrTab、DMATxDscrTab、Rx_Buff这三个数组定义前面加上
attribute((section(“.SRAM31”)))
attribute((section(“.SRAM32”)))
__attribute((section(“.SRAM3_3”)))
再次编译后,查看map文件,会发现这三个数组已经定义到指定位置的内存了。
至于为何要专门定义到这三个位置……不知道,STM32CubeMX定义的,只能说可能是为了32位对齐。
我习惯使用0x24000000开始的512K的AXI SRAM,所以修改RAM为0x24000000,长度512K,最终修改后的lds文件在工程中打开如下
由于修改了RAM的起始地址,所以别忘了在board.h中,把RAM_START这个宏的值从0x20000000改为0x24000000,RAM_SIZE修改为512。
4.再次编译后通过编译,我这边取消了LWIP中的DHCP功能,并使能了几个命令:
别忘了把main函数中的Hello RT-Thread!注释掉,要不然会不断的在终端中打印。也可以自己加入一个led闪烁。
5.点下载完成后即可在终端中看到信息:
按下tab可以看到rtt支持的所有命令:
输入ifconfig可以看到:
说明网卡启动成功,因为设定的静态IP,所以IP直接就有,但如果这时候你ping自己是ping不通的:
我在这里捣鼓了好久,后来才发现,ping自己需要在LWIP中启动
是自己对LWIP不熟悉导致。
ping PC:
6.至此,整个移植结束,可以顺便加入rtt源码中的example中的tcpclient.c和tcpserver.c测试下,这两个文件需要在RT-Thread Setting中的Network下,打开这两项:
编译完成后,bin文件为233KB(233……),下载后终端输出:
同时,按下tab后增加了两个命令:
怎么用就自己查看help吧,我这边上几张图片:
Tcp Server测试:
Tcp Client测试:
加上DHCP后,需要接到路由器上,我已经测试成功,可以自己获取到ip,并ping通www.baidu.com。
虽然调通了,但还是有几个疑问:
lds前面修改了好多次,总是变成flash的地址,造成bin文件无比巨大,现在的写法应该也是不规范的,希望有大神修改下。
sram3的时钟到底需不需要使能,我这边没有使能,但却可以正常使用,库函数中有使能语句,说明应该是需要的,但为何我的代码没出问题……
我毕竟是个半新手,之前没用过studio和lwip,肯定有移植的不好的地方,希望大家一起努力,rtt真是个好系统啊!
原作者:cuphead