7.1 初学者重要提示
学习本章节前,务必要优先学习第6章的底层驱动讲解。
测试时,请将网线接到路由器或者交换机上面测试,因为已经使能了DHCP,可以自动获取IP地址。而且使能了NetBIOS局域网域名,用户只需在电脑端ping armfly,就可以获得板子的IP地址。
如果要使用固定IP进行测试,请看附件章节A。
网口使用的是DM9161/9162(紧挨着9帧串口座的网口),而不是DM9000。
测试例子,务必看本章7.14小节的操作步骤。
7.2 移植RL-TCPnet协议栈整体说明(必读)
移植之前,有必要对移植过程有个整体的认识:
第1步,准备一个工程模板。
第2步,移植RTX5。
移植RTX5是采用MDK的RTE环境直接添加。当前H7芯片使用RTX5强制运行STM32CubeMX,所以需要大家提前安装好STM32CubeMX V5.4或者以上版本。
特别注意几个网络任务的优先级安排。
AppTaskMsgPro任务 : osPriorityNormal2
AppTaskEthCheck : osPriorityNormal3。
netCore_Thread任务 : osPriorityAboveNormal。
netEth0_Thread任务 : osPriorityAboveNormal1。
osRtxTimerThread任务: osPriorityRealtime。
注意这个定时器任务osRtxTimerThread的优先级一定要最高,因为这个是RL-TCPnet的时间基准运行任务。
第3步,移植RL-TCPnet。
第4步,处理HAL库时间基准,以太网收发描述符内存区的MPU配置以及MAC,PHY驱动等相关问题。
第5步,创建应用。
总的来说,这5步就可以完成移植,这里还有一点比较重要的,需要放在开头说明,为了保证工程的独立性,教程中将RTE环境添加的HAL库文件,MAC驱动和PHY驱动独立了出来,并且单独制作了一个移植文件ETH_INIT.c,将GPIO设置,网线插拔消息,以太网中断等都汇总到这个文件里面,方便大家移植工程到自己的板子上。
下面将STM32H7的移植步骤和注意事项为大家做个说明。
7.3 第1步,安装指定的MDK软件包版本
移植新版RL-TCPnet网络协议栈需要大家下载指定的MDK软件包版本:
CMSIS 软件包使用当前最新的:V5.6.0
STM32H7使用当前最新的:V2.3.1
CMSIS-Driver使用当前最新的:V10.2.0
MDK中间件使用当前最新的:V7.12.0
STM32CubeMX使用当前最新的:V5.4
ARM_Compiler使用当前最新的:V1.6.1
这些软件包的安装在STM32H7用户手册的第2章2.3小节有详细说明。
http://www.armbbs.cn/forum.php?mod=viewthread&tid=86980 。
所有这些软件包汇总下载地址:
http://www.armbbs.cn/forum.php?mod=viewthread&tid=95609 。
不管以后MDK的软件包版本如何升级,当前的软件包版本和以后的新版是可以同时安装的,也就是说可以安装多个不同版本,在这里可以选择指定版本:
7.4 第2步,准备一个工程模板
首先准备好一个简单的裸机工程模板,工程模板的制作就不做讲解了。这里要注意一点,由于我们要使用当前最新的HAL库软件包V1.6.0,需要大家使用这个帖子里面提供的例子:
http://www.armbbs.cn/forum.php?mod=viewthread&tid=95244。
这里的重点是教大家移植RL-TCPnet协议栈。
7.5 第3步,添加RTX5并配置
RTX5可以方便的通过MDK的RTE环境添加进来。对于H7版本,MDK会强制运行一次CubeMX,并添加很多H7的HAL库文件,这些库文件我们可以使用,也可以不使用。教程配套的工程文件是不使用这些的,因为前面的工程模板里面已经添加了。所以要将这些文件全部隔离出来。
7.5.1 添加RTX5源码
点击OK按钮后,弹出如下界面:
点击Start STM32CubeMX,这里需要大家电脑上已经安装了STM32CubeMX,并且为其安装了H7的软件包。
打开后,用户仅需配置如下地方即可:
然后点击右上角的GENERATE CODE:
然后弹出如下对话框,点击Close即可,然后关闭STM32CubeMX。
重新回到MDK,会有一个对话框,点击是即可:
最后就可以看到RTX5源码已经添加到工程里面了:
7.5.2 将自动添加的库文件隔离出来
添加的所有文件中,仅RTX5和文件stm32h7xx_hal_msp.c留下,其它文件全部隔离出来,隔离方法也比较简单,比如隔离生成的main.c函数,鼠标右击此文件选择Options for file ‘main.c’
然后取消掉include Target Build前的对勾,点击OK:
看到main.c文件上有个红色横杠,就表示已经隔离出来了:
同样的方法,将stm32h7xx_it.c文件也隔离出来,文件stm32h7xx_it.h不用管。
Device下面的这些文件也是同样的隔离方法:
只是鼠标右击弹出的界面有些不同:
注意stm32h7xx_hal_msp.c无需隔离,其它所有的文件全部隔离,stm32h7xx_hal_msp.c对于的隔离配置是STM32CubeMX,如果也隔离了,编译会有问题:
隔离后的效果如下:
7.5.3 RTX5配置
剩下就是配置RTX5,设置RTX_Config.h文件即可,移植阶段先按照如下设置配置好,后面章节会专门为大家讲解每个参数的配置含义
7.6 第4步,添加RL-TCPnet并配置
像添加RTX5一样,也可以通过RTE环境添加RL-TCPnet相关配置。
7.6.1 RL-TCPnet相关文件和驱动
CMSIS-Driver分组中添加MAC驱动和PHY驱动,其中PHY驱动随便选择一个即可,因为这个里面没有开发板上使用的DM9161/9162:
添加Event Recoder的支持,因为RL-TCPnet库的调试版本需要Event Recoder的支持:
添加ETH驱动:
添加网络配置:
我们需要的都已经添加好,效果如下:
红色方框里面的PHY和MAC驱动要隔离出来,通过下一步单独添加。
7.6.2 将自动添加的库文件隔离出来
文件stm32h7xx_hal_eth.c和stm32h7xx_hal_eth_ex.c也要隔离出来,我们单独在分组HAL_Driver里面添加:
7.6.3 RL-TCPnet配置
添加完毕RL-TCPnet所需的文件后,就是配置RL-TCPnet,具体每个配置所代表的含义,会在后面章节专为大家讲解。
Net_Config.c文件配置:
注意这个文件里面还有一个RL-TCPnet内核线程的优先级配置,当前是将其配置为:
osPriorityNormal:
Net_Config_ETH_0.h文件的配置如下:
这个文件里面有一个以太网接口任务的优先级配置,当前是将其配置为:osPriorityAboveNormal1。
其它文件Net_Config_TCP.h,Net_Config_UDP.h和Net_Debug.c使用默认配置即可。
7.7 第5步,独立添加MAC和PHY驱动文件
将我们裸机模板中制作好的RL-ARM文件夹复制粘贴到大家准备好的工程模板中。
RL-ARM文件夹中有如下七个文件夹,其中只有Driver文件夹里面有文件
然后将其也添加到工程文件里面:
文件PHY_DM916x和EMAC_STM32H7xx在第6章已经做了专门说明,这里重点把文件ETH_INIT.c文件做个说明。
7.8 第6步,初始化文件ETH_INIT.c
这个文件比较重要,将以太网收发缓冲,引脚配置,网线插拔状态和以太网中断设置都整理到了里面,方便大家将网络协议栈移植到自己的板子上。
这里将此文件为大家做个说明。
7.8.1 以太网描述符和收发缓冲区定义
以太网描述符和收发缓冲区定义如下:
/* Ethernet Rx DMA 描述符 */
__attribute__((at(0x30040000))) ETH_DMADescTypeDef DMARxDscrTab[ETH_RX_DESC_CNT];
/* Ethernet Tx DMA 描述符 */
__attribute__((at(0x30040060))) ETH_DMADescTypeDef DMATxDscrTab[ETH_TX_DESC_CNT];
/* Ethernet 接收缓冲 */
__attribute__((at(0x30040200))) uint8_t Rx_Buff[ETH_RX_DESC_CNT][ETH_MAX_PACKET_SIZE];
以太网发送描述是定义在EMAC_STM32H7xx.c文件里面:
#ifndef EMAC_TXBUF_ADDRESS
#define EMAC_TXBUF_ADDRESS 0x30042000
#endif
static uint8_t TX_Buff[ETH_TX_DESC_CNT][ETH_MAX_PACKET_SIZE] __MEMORY_AT(EMAC_TXBUF_ADDRESS);
宏定义ETH_TX_DESC_CNT和ETH_RX_DESC_CNT在stm32h7xx_hal_conf.h文件里面:
#define ETH_TX_DESC_CNT 4 /* number of Ethernet Tx DMA descriptors */
#define ETH_RX_DESC_CNT 4 /* number of Ethernet Rx DMA descriptors */
宏定义ETH_MAX_PACKET_SIZE在文件stm32h7xx_hal_eth.h里面定义:
#define ETH_MAX_PACKET_SIZE ((uint32_t)1528U) /*!< ETH_HEADER + 2*VLAN_TAG + MAX_ETH_PAYLOAD + ETH_CRC */
有了这些认识后,还有一个关键点要认识到,H7的以太网收发描述符和收发缓存最好都定义到D2域的SRAM3空间,首地址是0x3004 0000,总大小32KB。
7.8.2 以太网消息通知函数
以太网消息通知函数如下:
/* 以太网连接状态,0和1都表示初始临时状态,2表示连接上,3表示断开 */
__IO uint8_t g_ucEthLinkStatus = 0;
/*
*********************************************************************************************************
* 函 数 名: netETH_Notify
* 功能说明: 以太网状态消息
* 形 参: ---
* 返 回 值: 无
*********************************************************************************************************
*/
void netETH_Notify (uint32_t if_num, netETH_Event event, uint32_t val)
{
NET_ETH_LINK_INFO *info;
switch (event)
{
case netETH_LinkDown:
if(g_ucEthLinkStatus == 2)
{
g_ucEthLinkStatus = 3;
}
else
{
g_ucEthLinkStatus = 1;
}
printf_eth ("Link is downrn");
break;
case netETH_LinkUp:
g_ucEthLinkStatus = 2;
printf_eth ("Link is uprn");
info = (NET_ETH_LINK_INFO *)&val;
switch (info->speed)
{
case 0:
printf_eth ("10 MBitrn");
break;
case 1:
printf_eth ("100 MBitrn");
break;
case 2:
printf_eth ("1 GBitrn");
break;
}
switch (info->duplex)
{
case 0:
printf_eth ("Half duplexrn");
break;
case 1:
printf_eth ("Full duplexrn");
break;
}
break;
case netETH_Wakeup:
printf_eth ("Wakeup frame receivedrn");
break;
case netETH_TimerAlarm:
printf_eth ("Timer alarmrn");
break;
}
}
这里要注意变量g_ucEthLinkStatus = 1的情况。因为上电后,不管板子有没有插入网线,都会进入一次消息netETH_LinkDown,我们把这种情况用数值1来表示。
7.8.3 以太网引脚,时钟和中断配置
初始化部分:
/*
*********************************************************************************************************
* 函 数 名: HAL_ETH_MspInit
* 功能说明: 以太网初始化调用的底层回调,用于初始化IO,时钟和中断
* 形 参: ---
* 返 回 值: 无
*********************************************************************************************************
*/
void HAL_ETH_MspInit(ETH_HandleTypeDef* heth)
{
GPIO_InitTypeDef GPIO_InitStruct;
/*
PC1 ------> ETH_MDC
PA1 ------> ETH_REF_CLK
PA2 ------> ETH_MDIO
PA7 ------> ETH_CRS_DV
PC4 ------> ETH_RXD0
PC5 ------> ETH_RXD1
PB13 ------> ETH_TXD1
PG11 ------> ETH_TX_EN
PG13 ------> ETH_TXD0
*/
if(heth->Instance==ETH)
{
/* 使能外设时钟 */
__HAL_RCC_ETH1MAC_CLK_ENABLE();
__HAL_RCC_ETH1TX_CLK_ENABLE();
__HAL_RCC_ETH1RX_CLK_ENABLE();
/* 使能时钟 */
__HAL_RCC_GPIOA_CLK_ENABLE();
__HAL_RCC_GPIOB_CLK_ENABLE();
__HAL_RCC_GPIOC_CLK_ENABLE();
__HAL_RCC_GPIOG_CLK_ENABLE();
/* 配置PA1, PA2 , PA7 */