标签:测试 计数 iar 知识点 switch links unp 选项 tip
最新教程下载:http://www.armbbs.cn/forum.php?mod=viewthread&tid=95243
本章教程为大家讲解RL-TCPnet网络协议栈的RTX5版本移植方式。
7.1 初学者重要提示
7.2 移植RL-TCPnet协议栈整体说明(必读)
7.3 第1步,安装指定的MDK软件包版本
7.4 第2步,准备一个工程模板
7.5 第3步,添加RTX5源码
7.6 第4步,添加RT-TCPnet并配置
7.7 第5步,独立添加MAC和PHY驱动文件
7.8 第6步,初始化ETH_INIT.c文件
7.9 第7步,MPU和Cache配置文件bsp.c
7.10 第8步,更新bsp_timer.c和bsp.h文件
7.12 第10步,创建应用任务
7.13 常见移植错误总结
7.14 网络调试助手和板子的调试操作步骤
7.15 总结
移植之前,有必要对移植过程有个整体的认识:
AppTaskMsgPro任务 : osPriorityNormal2
AppTaskEthCheck : osPriorityNormal3。
netCore_Thread任务 : osPriorityAboveNormal。
netEth0_Thread任务 : osPriorityAboveNormal1。
osRtxTimerThread任务: osPriorityRealtime。
注意这个定时器任务osRtxTimerThread的优先级一定要最高,因为这个是RL-TCPnet的时间基准运行任务。
总的来说,这5步就可以完成移植,这里还有一点比较重要的,需要放在开头说明,为了保证工程的独立性,教程中将RTE环境添加的HAL库文件,MAC驱动和PHY驱动独立了出来,并且单独制作了一个移植文件ETH_INIT.c,将GPIO设置,网线插拔消息,以太网中断等都汇总到这个文件里面,方便大家移植工程到自己的板子上。
下面将STM32F4的移植步骤和注意事项为大家做个说明。
移植新版RL-TCPnet网络协议栈需要大家下载指定的MDK软件包版本:
http://www.armbbs.cn/forum.php?mod=viewthread&tid=93255 。
http://www.armbbs.cn/forum.php?mod=viewthread&tid=95609 。
不管以后MDK的软件包版本如何升级,当前的软件包版本和以后的新版是可以同时安装的,也就是说可以安装多个不同版本,在这里可以选择指定版本:
首先准备好一个简单的裸机工程模板,工程模板的制作就不做讲解了。从这个帖子里面下载一个例子即可:
http://www.armbbs.cn/forum.php?mod=viewthread&tid=93255。
这里的重点是教大家移植RL-TCPnet协议栈。准备好的工程模板如下图所示(大家也可以制作其它任意的工程模板,不限制):
RTX5可以方便的通过MDK的RTE环境添加进来。对于F4版本,会添加多个F4版的HAL库文件,这些库文件我们可以使用,也可以不使用。教程配套的工程文件是不使用这些的,因为前面的工程模板里面已经添加了。所以要将这些文件全部隔离出来。
点击OK按钮后,可以看到RTX5源码已经添加到工程里面了:
添加的所有文件中,startup_stm32f407xx.s和system_stm32f4xx.c要隔离出来,隔离方法也比较简单,比如隔离startup_stm32f407xx.s文库,鼠标右击此文件选择Options for file ‘startup_stm32f429xx.s’
取消下面的对勾:
隔离这一个文件后,另一个文件system_stm32f4xx.c也被自动隔离了,隔离后的效果如下:
剩下就是配置RTX5,设置RTX_Config.h文件即可,移植阶段先按照如下设置配置好,后面章节会专门为大家讲解每个参数的配置含义:
像添加RTX5一样,也可以通过RTE环境添加RL-TCPnet相关配置。
CMSIS-Driver分组中添加MAC驱动和PHY驱动,其中PHY驱动随便选择一个即可,因为这个里面没有开发板上使用的DM9161/9162:
添加Event Recoder的支持,因为RL-TCPnet库的调试版本需要Event Recoder的支持:
选择经典驱动方式(这个里面已经包含以太网部分):
选择需要的HAL驱动:
添加网络配置:
我们需要的都已经添加好,效果如下:
根据开发板的以太网接口实际使用的引脚,可以通过文件RTE_Device.h非常方便的配置出来:
红色方框里面的这几个文件要隔离出来:
特别注意文件stm32f4xx_hal_conf.h不要隔离,否则会编译出错,对应的选项如下:
最终隔离后的效果如下:
添加完毕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使用默认配置即可。
将我们裸机模板中制作好的RL-ARM文件夹复制粘贴到大家准备好的工程模板中。
RL-ARM文件夹中有如下七个文件夹,其中只有Driver文件夹里面有文件
然后将其也添加到工程文件里面:
文件PHY_DM916x和EMAC_STM32F4xx在第6章已经做了专门说明,这里重点把文件ETH_INIT.c文件做个说明。
这个文件主要是网线插拔状态标识:
/* 以太网连接状态,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 down\r\n"); break; case netETH_LinkUp: g_ucEthLinkStatus = 2; printf_eth ("Link is up\r\n"); info = (NET_ETH_LINK_INFO *)&val; switch (info->speed) { case 0: printf_eth ("10 MBit\r\n"); break; case 1: printf_eth ("100 MBit\r\n"); break; case 2: printf_eth ("1 GBit\r\n"); break; } switch (info->duplex) { case 0: printf_eth ("Half duplex\r\n"); break; case 1: printf_eth ("Full duplex\r\n"); break; } break; case netETH_Wakeup: printf_eth ("Wakeup frame received\r\n"); break; case netETH_TimerAlarm: printf_eth ("Timer alarm\r\n"); break; } }
这里要注意变量g_ucEthLinkStatus = 1的情况。因为上电后,不管板子有没有插入网线,都会进入一次消息netETH_LinkDown,我们把这种情况用数值1来表示。
这个bsp.c文件也比较重要,移植阶段,直接将我们移植好的模板内容复制过去即可,这里把相关的内容为大家做个说明。
系统初始化,主要是系统时钟配置,需要在RTX5初始化之前调用。
/* ********************************************************************************************************* * 函 数 名: System_Init * 功能说明: 系统初始化,主要是系统时钟配置 * 形 参:无 * 返 回 值: 无 ********************************************************************************************************* */ void System_Init(void) { /* STM32H429 HAL 库初始化,此时系统用的还是F429自带的16MHz,HSI时钟: - 调用函数HAL_InitTick,初始化滴答时钟中断1ms。 - 设置NVIV优先级分组为4。 */ HAL_Init(); /* 配置系统时钟到168MHz - 切换使用HSE。 - 此函数会更新全局变量SystemCoreClock,并重新配置HAL_InitTick。 */ SystemClock_Config(); /* Event Recorder: - 可用于代码执行时间测量,MDK5.25及其以上版本才支持,IAR不支持。 - 默认不开启,如果要使能此选项,务必看V6开发板用户手册第8章 */ #if Enable_EventRecorder == 1 /* 初始化EventRecorder并开启 */ EventRecorderInitialize(EventRecordAll, 1U); EventRecorderStart(); #endif }
硬件外设的初始化,这个函数在RTX5的启动任务里面调用。
/* ********************************************************************************************************* * 函 数 名: bsp_Init * 功能说明: 初始化所有的硬件设备。该函数配置CPU寄存器和外设的寄存器并初始化一些全局变量。只需要调用一次 * 形 参: 无 * 返 回 值: 无 ********************************************************************************************************* */ void bsp_Init(void) { bsp_InitKey(); /* 按键初始化,要放在滴答定时器之前,因为按钮检测是通过滴答定时器扫描 */ bsp_InitTimer(); /* 初始化滴答定时器 */ bsp_InitUart(); /* 初始化串口 */ bsp_InitExtIO(); /* 初始化扩展IO */ bsp_InitLed(); /* 初始化LED */ }
这个函数主要是完成系统时钟配置。
/* ********************************************************************************************************* * 函 数 名: SystemClock_Config * 功能说明: 初始化系统时钟 * System Clock source = PLL (HSE) * SYSCLK(Hz) = 168000000 (CPU Clock) * HCLK = SYSCLK / 1 = 168000000 (AHB1Periph) * PCLK2 = HCLK / 2 = 84000000 (APB2Periph) * PCLK1 = HCLK / 4 = 42000000 (APB1Periph) * HSE Frequency(Hz) = 25000000 * PLL_M = 25 * PLL_N = 336 * PLL_P = 2 * PLL_Q = 4 * VDD(V) = 3.3 * Flash Latency(WS) = 5 * 形 参: 无 * 返 回 值: 无 ********************************************************************************************************* */ static void SystemClock_Config(void) { RCC_ClkInitTypeDef RCC_ClkInitStruct = {0}; RCC_OscInitTypeDef RCC_OscInitStruct = {0}; /* 芯片内部的LDO稳压器输出的电压范围,选用的PWR_REGULATOR_VOLTAGE_SCALE1 */ __HAL_RCC_PWR_CLK_ENABLE(); __HAL_PWR_VOLTAGESCALING_CONFIG(PWR_REGULATOR_VOLTAGE_SCALE1); /* 使能HSE,并选择HSE作为PLL时钟源 */ RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE; RCC_OscInitStruct.HSEState = RCC_HSE_ON; RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON; RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE; RCC_OscInitStruct.PLL.PLLM = 8; RCC_OscInitStruct.PLL.PLLN = 336; RCC_OscInitStruct.PLL.PLLP = RCC_PLLP_DIV2; RCC_OscInitStruct.PLL.PLLQ = 4; if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK) { Error_Handler(__FILE__, __LINE__); } /* 选择PLL的输出作为系统时钟 HCLK = SYSCLK / 1 (AHB1Periph) PCLK2 = HCLK / 2 (APB2Periph) PCLK1 = HCLK / 4 (APB1Periph) */ RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK |RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2; RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK; RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1; RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV4; RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV2; /* 此函数会更新SystemCoreClock,并重新配置HAL_InitTick */ if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_5) != HAL_OK) { Error_Handler(__FILE__, __LINE__); } /* 使能SYS时钟和IO补偿 */ __HAL_RCC_SYSCFG_CLK_ENABLE() ; HAL_EnableCompensationCell(); }
这个函数里面默认有个按键扫描,如果大家移植的程序里面没有按键初始化,务必要把这个按键扫描函数注释掉。
/* ********************************************************************************************************* * 函 数 名: bsp_RunPer10ms * 功能说明: 该函数每隔10ms被Systick中断调用1次。详见 bsp_timer.c的定时中断服务程序。一些处理时间要求 * 不严格的任务可以放在此函数。比如:按键扫描、蜂鸣器鸣叫控制等。 * 形 参: 无 * 返 回 值: 无 ********************************************************************************************************* */ void bsp_RunPer10ms(void) { bsp_KeyScan10ms(); }
更新bsp_timer.c文件是因为此文件跟RTX5都要使用滴答定时器,有冲突。所以大家直接将我们工程模板里面此文件覆盖移植的这个文件即可。
bsp.h文件里面要添加一个宏定义,因为bsp_timer.c文件里面做了些条件编译:
#define USE_RTX 1
由于RTX5和HAL库需要一个时间基准,而且默认都是用的滴答定时器,所有要有一个选用其它的时间基准。当前的处理方案是为HAL库提供一个时间基准文件stm32f4xx_hal_timbase_tim.c。此文件
里面做了两套方案,一个是使用TIM7做时间基准,另一个是使用RTX5的API做时间基准,通过条件编译做选择。默认是采用RTX5的API做时间基准。
/* ********************************************************************************************************* * 函 数 名: HAL_Delay * 功能说明: 重定向毫秒延迟函数。替换HAL中的函数。因为HAL中的缺省函数依赖于Systick中断,如果在USB、SD * 卡中断中有延迟函数,则会锁死。也可以通过函数HAL_NVIC_SetPriority提升Systick中断 * 形 参: 无 * 返 回 值: 无 ********************************************************************************************************* */ void HAL_Delay(uint32_t Delay) { bsp_DelayMS(Delay); } HAL_StatusTypeDef HAL_InitTick (uint32_t TickPriority) { return HAL_OK; } uint32_t HAL_GetTick (void) { static uint32_t ticks = 0U; uint32_t i; if (osKernelGetState () == osKernelRunning) { return ((uint32_t)osKernelGetTickCount ()); } /* 如果RTX5还没有运行,采用下面方式 */ for (i = (SystemCoreClock >> 14U); i > 0U; i--) { __NOP(); __NOP(); __NOP(); __NOP(); __NOP(); __NOP(); __NOP(); __NOP(); __NOP(); __NOP(); __NOP(); __NOP(); } return ++ticks; }
函数bsp_DelayMS在bsp_dwt.c文件里面,需要大家从我们配套例子中复制到我们的工程里面,DWT是时钟周期计数器,在CM3,CM4和CM7内核里面是通用的。
RTX5和RL-TCPnet都移植完毕后,就可以添加应用任务验证是否移植成功了。
有三个文件需要设计,移植阶段,直接添加到自己移植的工程里面即可。
主要功能是RTX5任务的创建和执行。
主要功能是各种头文件的汇总。
主要功能是TCPnet的应用任务设计。
常见的移植错误主要有下面几种情况:
解决办法:重新上电即可。
出现这个错误的解决办法是将新版CMSIS软件包里面Driver文件夹全部复制到工程里面的CMSIS文件夹下,并添加路径:
Error: L6200E: Symbol PendSV_Handler multiply defined (by irq_cm4f.o and stm32h7xx_it.o).
Error: L6200E: Symbol SVC_Handler multiply defined (by irq_cm4f.o and stm32h7xx_it.o).
解决办法:这是函数重定义了,直接将stm32h7xx_it.c文件里面的PendSV_Handler和SVC_Handler删掉。
Error: L6218E: Undefined symbol bsp_DelayMS (referred from bsp_fmc_io.o).
解决办法:打开bsp_dwt.C文件中的条件编译。
我们这里使用下面这款调试助手,当然,任何其它网络调试助手均可,不限制:
http://www.armbbs.cn/forum.php?mod=viewthread&tid=1568 。
测试时,网线要插到DM916X网口上:
最后,强烈推荐将网线接到路由器或者交换机上面测试,因为已经使能了DHCP,可以自动获取IP地址,而且在前面的配置中使能了局域网域名NetBIOS,用户只需在电脑端ping armfly就可以获取板子的IP地址。
如果使用固定IP方式,看附件章节A。
各种网卡、交换机等网络设备都不一样,一般来讲:绿灯分为亮或不亮(代表网络速度),黄灯分为闪烁或不闪烁(代表是否有数据收发)。
绿灯:长亮代表100M; 不亮代表10M。
黄灯:长亮代表无数据收发; 闪烁代表有数据收发。
也有些千兆网卡的灯以颜色区分,不亮代表10M / 绿色代表100M / 黄色代表1000M。现在10M的网络基本看不到了,如果一个灯长亮,基本可以说明100M网络或更高,而另一个灯时而闪烁,那代表有数据收发,具体要看网络设备了。甚至有些低等网卡如TP-LINK,只有一个灯,亮代表连通,闪烁代表数据收发。
对于开发板上面的RJ45网络变压器插座上面的灯而言,绿灯代表数据收发,长亮的话表示无数据收发,闪烁代表有数据收发。黄灯代表网络速度,长亮代表100M,不亮代表10M。
此贴对各种网线插拔情况进行了总结,并且当前配套模板程序也做了支持:
http://www.armbbs.cn/forum.php?mod=viewthread&tid=95386 。
首先,强烈推荐将网线接到路由器或者交换机上面测试,因为已经使能了DHCP,可以自动获取IP地址,而且在前面的配置中使能了局域网域名NetBIOS,用户只需在电脑端ping armfly就可以获取板子的IP地址。
ping命令的主要作用是通过发送数据包并接收应答信息来检测两台设备之间的网络是否连通。ping命令成功说明当前主机与目的主机之间存在连通的路径。如果不成功,需要查看网线是否连通、网卡设置是否正确、IP地址是否可用等。测试方法如下:
收发相同,没有数据丢失,说明ping命令也是成功的。获得IP地址是192.168.1.5。
特别说明,我们这里直接填局域网域名armfly也是没有问题的,即下面这样:
连接上后,串口软件也会打印出如下信息(波特率115200,数据位8,奇偶校验位无,停止位1):
板子和网络调试助手建立连接后就可以相互收发数据了。对于发送数据。程序中创建了三种大小的数据发送测试。
TCP服务器接收数据的测试也比较方便,我们这里通过网络调试助手给板子发送0到9,共10个字符:
点击发送后,可以看到串口软件打印出接收到的10个字符:
字符0对应的ASCII值就是48,其它字符数值依次增加。测试也是没问题的。
本章节为大家讲解了RL-TCPnet网络协议栈的RTX5版本移植方法,移植涉及到的知识点比较多,初学的话,建议实际动手操作一遍。
【STM32F407】第7章 RL-TCPnet V7.X网络协议栈移植(RTX5)
标签:测试 计数 iar 知识点 switch links unp 选项 tip
原文地址:https://www.cnblogs.com/armfly/p/13617611.html