Stm32F407 FreeRTOS+TCP 移植

FreeRTOS 版本: FreeRTOSv10.2.1

HAL 版本:  Keil.STM32F4xx_DFP_HAL.2.13.0

版本无所谓,只是记录下,FreeRTOS 10.0之后会多实现一个网络序列化回调函数。

FreeRTOSv10.2.1 TCP 文件目录

官方使用手册:https://www.freertos.org/FreeRTOS-Plus/FreeRTOS_Plus_TCP/index.html

移植好FreeRTOS系统。因为TCP是多任务。

需要用到的文件:

1.上图9个C文件。

2.include目录头文件。

3.portable\ BufferManagement\ BufferAllocation_2.c 内存管理方案。

4.portable\Compiler\GCC\pack_struct_end.h和pack_struct_start.h 字节对齐(对应编译器)可以直接放到自己的头文件目录中去。

     start.h 添加 一句 #pragma pack(1)

     end.h 添加一句 __attribute__( (packed) );  #pragma pack()

5.portable\NetworkInterface\STM32Fxx\NetworkInterface.c (对应架构) stm32fxx系列网络接口文件。

6.portable\NetworkInterface\Common\phyHandling.c和portable\NetworkInterface\include\phyHandling.h

                              

需要新建添加FreeRTOSIPConfig.h 配置头文件,主要是定义功能开关,物理地址,默认IP、网关等。直接复制。

(占篇幅 分开链接) https://blog.csdn.net/wy212670/article/details/105968537

 

工程添加完文件编译,当然会有很多错误。

主要是NetworkInterface.c 接口文件,首先修改引入#include "stm32f4xx_hal.h",#include "stm32f4xx_hal_eth.h"头文件,缺什么引什么。

有几个函数体内函数找不到,不重要的可以屏蔽。

修改了xNetworkInterfaceInitialise(),添加PHY 初始化函数,使用的是LAN8720。

// 网络接口初始化,其中初始化硬件,然后初始化发送和接收描述符,最后开启MAC层中断处理任务
BaseType_t xNetworkInterfaceInitialise( void )
{
HAL_StatusTypeDef hal_eth_init_status;
BaseType_t xResult;

	if( xEMACTaskHandle == NULL )
	{
			if( xTXDescriptorSemaphore == NULL )
			{
				xTXDescriptorSemaphore = xSemaphoreCreateCounting( ( UBaseType_t ) ETH_TXBUFNB, ( UBaseType_t ) ETH_TXBUFNB );
				configASSERT( xTXDescriptorSemaphore );
			}

		/* Initialise ETH */

		//Lan8720初始化
		Lan8720_Init();
			
		xETH.Instance = ETH;
		xETH.Init.AutoNegotiation = ETH_AUTONEGOTIATION_ENABLE;
		xETH.Init.Speed = ETH_SPEED_100M;
		xETH.Init.DuplexMode = ETH_MODE_FULLDUPLEX;
		/* Value of PhyAddress doesn't matter, will be probed for. */
		xETH.Init.PhyAddress = 0;

		xETH.Init.MACAddr = ( uint8_t *)FreeRTOS_GetMACAddress();
		xETH.Init.RxMode = ETH_RXINTERRUPT_MODE;

		/* using the ETH_CHECKSUM_BY_HARDWARE option:
		both the IP and the protocol checksums will be calculated
		by the peripheral. */
		xETH.Init.ChecksumMode = ETH_CHECKSUM_BY_HARDWARE;

//		#if( ipconfigUSE_RMII != 0 )
//		{
//			xETH.Init.MediaInterface = ETH_MEDIA_INTERFACE_RMII;
//		}
//		#else
//		{
//		xETH.Init.MediaInterface = ETH_MEDIA_INTERFACE_MII;
//		}
//		#endif /* ipconfigUSE_RMII */
		xETH.Init.MediaInterface = ETH_MEDIA_INTERFACE_RMII;
		hal_eth_init_status = HAL_ETH_Init( &xETH );

		/* Only for inspection by debugger. */
		( void ) hal_eth_init_status;

		/* Set the TxDesc and RxDesc pointers. */
		xETH.TxDesc = DMATxDscrTab;
		xETH.RxDesc = DMARxDscrTab;

		/* Make sure that all unused fields are cleared. */
		memset( &DMATxDscrTab, '\0', sizeof( DMATxDscrTab ) );
		memset( &DMARxDscrTab, '\0', sizeof( DMARxDscrTab ) );

			/* Initialize Tx Descriptors list: Chain Mode */
			DMATxDescToClear = DMATxDscrTab;

		/* Initialise TX-descriptors. */
		prvDMATxDescListInit();

		/* Initialise RX-descriptors. */
		prvDMARxDescListInit();

		#if( ipconfigUSE_LLMNR != 0 )
		{
			/* Program the LLMNR address at index 1. */
			prvMACAddressConfig( &xETH, ETH_MAC_ADDRESS1, ( uint8_t *) xLLMNR_MACAddress );
		}
		#endif

		/* Force a negotiation with the Switch or Router and wait for LS. */
		prvEthernetUpdateConfig( pdTRUE );

		/* The deferred interrupt handler task is created at the highest
		possible priority to ensure the interrupt handler can return directly
		to it.  The task's handle is stored in xEMACTaskHandle so interrupts can
		notify the task when there is something to process. */
		xTaskCreate( prvEMACHandlerTask, "EMAC", configEMAC_TASK_STACK_SIZE, NULL, niEMAC_HANDLER_TASK_PRIORITY, &xEMACTaskHandle );
	} /* if( xEMACTaskHandle == NULL ) */
	
//检查PHY连接状态
	xSTM32_PhyRead( 0x00,0x01, &ulPHYLinkStatus);
	xPhyObject.ulLinkStatusMask = ulPHYLinkStatus;
	return ( ulPHYLinkStatus & BMSR_LINK_STATUS ) != 0;
	
//	if( xPhyObject.ulLinkStatusMask != 0 )
//	{
//		xETH.Instance->DMAIER |= ETH_DMA_ALL_INTS;
//		xResult = pdPASS;
//		FreeRTOS_printf( ( "Link Status is high\n" ) ) ;
//	}
//	else
//	{
//		/* For now pdFAIL will be returned. But prvEMACHandlerTask() is running
//		and it will keep on checking the PHY and set 'ulLinkStatusMask' when necessary. */
//		xResult = pdFAIL;
//		FreeRTOS_printf( ( "Link Status still low\n" ) ) ;
//	}
//	/* When returning non-zero, the stack will become active and
//    start DHCP (in configured) */
//	return xResult;
}

 解决了函数问题,就剩下回调函数需要实现,再次编译会报错9个函数未定义,我们自己实现就好了。

新建NetWorkConfig.c 实现这些函数,其中ulApplicationGetNextSequenceNumber()和 uxRand()需要使用随机数,所以自己添加RNG生成随机数返回。完整代码如下。

(NetWorkConfig.c)https://blog.csdn.net/wy212670/article/details/105968368

总结:

    1.修改官方文件 NetworkInterface.c ,添加LAN8720初始化。

     2.需要我们自己添加的有,PHY初始化函数,RNG随机数生成函数,9个回调函数实现。

问题:

     1.调试发现收发冲突导致不能发送,修改stm32f4xx_hal_eth.c 的 HAL_ETH_IRQHandler中断函数,if( )..else if( )改成 if( )..if( )。

      2.FreeRTOSConfig.h 中需要注意的问题:

              #define configMAX_PRIORITIES       ( 12 )   任务优先级适当调大 默认5,任务多了不够用

              #define configTOTAL_HEAP_SIZE     ( ( size_t ) ( 50 * 1024 ) )  堆空间默认20*1024,太小网络任务无法运行但是不报错。

 

到此需要的工作都做完,编译应该没错了。就可以试试能不能用。

插网线,连接到路由器网络获取IP。

调用IP_Init(), RNG_Init(),初始化网络相关,会自动通过路由器获取DHCP静态地址。所以需要查看是否获取的地址,可以调试查看 xDefaultPartUDPPacketHeader. ulWords(搜索变量名查看位置) 变量第五个字节保存的是获取到的地址。

或者通过路由器界面,例如 192.168.31.1查看连接设备是否有开发板。在回调文件NetWorkConfig.c 中定义开发板名称,例如我的是“WY-STM32”,如果有并且地址也分配了,网口灯也亮了,说明移植成功。

下面开始网络数据收发。也就是编写TCPClient和TCPServer通过网络调试助手进行数据收发。

TCPClient客户端代码如下:创建两个任务,发送和接收任务。发送时创建套接字,连接服务器,连接成功循环发送数据,接收任务中通过发送创建的套接字循环接收数据。

相关API函数查看官方手册。

1.创建套接字,xSocket =FreeRTOS_socket(FREERTOS_AF_INET, FREERTOS_SOCK_STREAM, FREERTOS_IPPROTO_TCP)。

2.设置接收、发送超时时间,FreeRTOS_setsockopt()。

3.if ipconfigALLOW_SOCKET_SEND_WITHOUT_BIND is set to 1 in FreeRTOSIPConfig.h 就不需要bind 绑定函数,直接使用连接函数FreeRTOS_connect(套接字,服务器地址,地址长度)。

4.连接成功后,FreeRTOS_send()发送数据。

5.连接成功后,FreeRTOS_recv()接收数据。

(代码链接 TCPClient.c)https://blog.csdn.net/wy212670/article/details/105970402

用网络调试助手开启服务器,执行vStartTCPClientTasks(512, 2),开启客户端。如果连接成功,服务器串口循环打印客户端发过来的数据,服务器发送stop客户端接收停止发送。

 

TCPServer 服务器代码如下:开启任务创建套接字,绑定服务器地址,监听套接字,循环接收监听,当都客户端连接成功,开启任务循环处理接收客户端发送过来的数据。

1.创建套接字,xListeningSocket = FreeRTOS_socket( FREERTOS_AF_INET, FREERTOS_SOCK_STREAM, FREERTOS_IPPROTO_TCP );

2.设置连接超时,FreeRTOS_setsockopt()。

3.绑定,FreeRTOS_bind( xListeningSocket, &xBindAddress, sizeof( xBindAddress ) );

4.监听,FreeRTOS_listen( xListeningSocket, xBacklog );

5.接收,xConnectedSocket = FreeRTOS_accept( xListeningSocket, &xClient, &xSize );

6.接收到客户端套接字,处理客户端接收和发送。

             FreeRTOS_recv( xConnectedSocket, pucRxBuffer, ipconfigTCP_MSS, 0 );,

             FreeRTOS_send( xConnectedSocket, pucRxBuffer, lBytes - lTotalSent, 0 );

(TCPServer.c)https://blog.csdn.net/wy212670/article/details/105971657

网络调试助手开启客户端连接服务器成功,客户端发送数据给服务器,服务器接收到再重新发给客户端。

STM32F407是一款32位ARM Cortex-M4内核的微控制器,拥有丰富的周边设备和高性能。FreeRTOS是一款用于嵌入式系统的实时操作系统,提供了任务调度、内存管理、定时器等功能,使得开发者能够创建复杂的多任务应用程序。TCP客户端是指在TCP/IP协议栈的应用层,通过TCP协议与服务器进行通信的客户端程序。 将STM32F407FreeRTOSTCP客户端结合起来,可以创建一个具有实时性能的TCP客户端应用。首先,我们需要将FreeRTOS移植STM32F407上,这可以通过使用STM32CubeMX和FreeRTOS内核文件进行配置和生成来实现。接下来,我们需要编写TCP客户端代码,使用TCP/IP协议栈的相关API进行连接服务器、发送和接收数据等操作。在编写TCP客户端代码时,我们需要创建一个或多个任务,用于处理与服务器的TCP连接和数据通信。这些任务可以使用FreeRTOS提供的任务调度器进行管理和调度。 在使用STM32F407FreeRTOSTCP客户端时,还需要注意一些重要的方面。首先,需要根据应用需求进行系统资源的合理配置,包括内存大小、任务优先级等。其次,需要注意任务之间的同步和通信,以避免竞争条件和数据一致性的问题。还需要考虑网络连接的稳定性,处理网络异常和错误情况的方法。最后,还需要进行性能测试和调优,以确保系统在给定约束条件下的稳定工作。 综上所述,将STM32F407FreeRTOSTCP客户端结合起来,可以实现一个具有实时性能的嵌入式TCP客户端应用程序。这种应用可以广泛应用于物联网、智能家居、远程监测等领域。
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值