• 在stm32f4空工程文件夹下创建FreeRTOS文件夹用来存放FreeRTOS源码,将FreeRTOS文件源码中FreeRTOS\Source路径下的全部文件拷贝到新建的FreeRTOS文件夹中。
  • 打开stm32f4空工程,添加分组FreeRTOS/Source,用来存放FreeRTOS源码。添加分组FreeRTOS/Ports,用来存放端口和内存分配方案。将FreeRTOS路径下的文件timers.c、croutine.c、list.c、queue.c、event_groups.c、task.c添加到FreeRTOS/Source中。将FreeRTOS\portable\MemMang路径下的内存管理文件heap_4.c和FreeRTOS\portable\RVDS\ARM_CM4F路径下的接口文件port.c添加到FreeRTOS/Ports中。
  • 将路径FreeRTOS\ include和 FreeRTOS\portable\RVDS\ARM_CM4F添加到工程头文件路径中 。
  • 将FreeRTOS\Demo\CORTEX_M4F_STM32F407ZG-SKl路径下的配置文件FreeRTOSConfig.h复制到User文件夹下,并在工程中添加到User分组中。
  • 在main.c中添加FreeRTOS.h、task.h、queue.h三个头文件,编译。出现一个错误,提示SystemCoreClock没有定义,如下图。

  • 因为__ICCARM__是IAR编译工具链的相关宏定义,而这个工程使用的ARM编译工具链,所以将FreeRTOSConfig.h文件将宏定义__ICCARM__改为__CC_ARM,再次编译,发现出现四个错误。如下图。

  • 这四个错误是没有相关回调函数定义,vApplicationIdleHook()是空闲状态回调函数,vApplicationTickHook()是时间片轮转回调函数,vApplicationStackOverflowHook()是堆栈溢出回调函数,vApplicationMallocFailedHook()是内存分配失败回调函数。在main.c中定义这四个回调函数。
#include "stm32f4xx.h"#include "FreeRTOS.h"#include "task.h"#include "queue.h"int main(void){while(1);}//空闲状态回调函数
void vApplicationIdleHook( void )
{}//时间片轮转回调函数
void vApplicationTickHook( void )
{}//堆栈溢出回调函数
void vApplicationStackOverflowHook( TaskHandle_t xTask, char *pcTaskName )
{}//内存分配失败回调函数
void vApplicationMallocFailedHook( void )
{}
  • 再次编译发现没有错误了,移植完成。
  • 创建FreeRTOS-TCP文件夹用来存放TCP源码,将FreeRTOS-Plus文件源码中FreeRTOS-Plus\Source\FreeRTOS-Plus-TCP路径下的全部文件拷贝到新建的FreeRTOS-TCP文件夹中。
  • 打开工程,添加分组FreeRTOS_TCP,用来存放TCP源码。添加分组FreeRTOS_TCP/Ports,用来存放端口和内存分配方案。将FreeRTOS_TCP路径下的C文件添加到FreeRTOS_TCP分组中。将FreeRTOS-TCP\portable\BufferManagement路径下的内存管理文件BufferAllocation_2.c、FreeRTOS-TCP\portable\NetworkInterface\STM32Fxx路径下的接口文件NetworkInterface.c和FreeRTOS-TCP\portable\NetworkInterface\Common路径下的物理层处理文件添加到FreeRTOS_TCP/Ports中。
  • 将路径FreeRTOS-TCP\include和 FreeRTOS-TCP\portable\NetworkInterface\include添加到工程头文件路径中 。
  • 将FreeRTOS-Plus\Demo\FreeRTOS_Plus_TCP_Minimal_Windows_Simulator路径下的配置文件FreeRTOSIPConfig.h复制到User文件夹下,并在工程中添加到User分组中。
  • 联网需要用到以太网物理层芯片,此案例采用LAN8720,用户需要编写LAN8720驱动函数。这里我们创建bsp_eth.c和bsp_eth.h两个文件,在文件里完成LAN8720驱动。将文件添加到工程中。参考下面代码。
#include "bsp_eth.h"void LAN8720_Init(void){GPIO_InitTypeDef GPIO_Init;__HAL_RCC_SYSCFG_CLK_ENABLE();__HAL_RCC_GPIOA_CLK_ENABLE();__HAL_RCC_GPIOC_CLK_ENABLE();__HAL_RCC_GPIOD_CLK_ENABLE();__HAL_RCC_GPIOG_CLK_ENABLE();__HAL_RCC_ETH_CLK_ENABLE();/*RMII接口引脚ETH_MDIO -------------------------> PA2ETH_MDC --------------------------> PC1ETH_RMII_REF_CLK------------------> PA1ETH_RMII_CRS_DV ------------------> PA7ETH_RMII_RXD0 --------------------> PC4ETH_RMII_RXD1 --------------------> PC5ETH_RMII_TX_EN -------------------> PG11ETH_RMII_TXD0 --------------------> PG13ETH_RMII_TXD1 --------------------> PG14ETH_RESET-------------------------> PD3*/GPIO_Init.Mode=GPIO_MODE_AF_PP;GPIO_Init.Pin=GPIO_PIN_1 | GPIO_PIN_2 | GPIO_PIN_7;GPIO_Init.Pull=GPIO_NOPULL;GPIO_Init.Speed=GPIO_SPEED_FREQ_VERY_HIGH;GPIO_Init.Alternate=GPIO_AF11_ETH;HAL_GPIO_Init(GPIOA,&GPIO_Init);GPIO_Init.Pin=GPIO_PIN_1 | GPIO_PIN_4 | GPIO_PIN_5;HAL_GPIO_Init(GPIOC,&GPIO_Init); GPIO_Init.Pin=GPIO_PIN_11 | GPIO_PIN_14 | GPIO_PIN_13;HAL_GPIO_Init(GPIOG,&GPIO_Init); GPIO_Init.Mode=GPIO_MODE_OUTPUT_PP;GPIO_Init.Pin=GPIO_PIN_3;GPIO_Init.Pull=GPIO_NOPULL;GPIO_Init.Speed=GPIO_SPEED_FREQ_VERY_HIGH;HAL_GPIO_Init(GPIOD,&GPIO_Init);//复位HAL_GPIO_WritePin(GPIOD,GPIO_PIN_3,GPIO_PIN_RESET);  vTaskDelay(100/portTICK_PERIOD_MS);HAL_GPIO_WritePin(GPIOD,GPIO_PIN_3,GPIO_PIN_SET);vTaskDelay(100/portTICK_PERIOD_MS);HAL_NVIC_SetPriority(ETH_IRQn,6,0);HAL_NVIC_EnableIRQ(ETH_IRQn);}TCP协议里需要用到随机数,这个随机数需要用户提供。随机数的创建参考下面代码。
#include "randomnum.h"/* RNG handler declaration */RNG_HandleTypeDef RngHandle;static void Error_Handler(){while(1){}}void RNG_init(void){__HAL_RCC_RNG_CLK_ENABLE();/*## Configure the RNG peripheral #######################################*/RngHandle.Instance = RNG;/* DeInitialize the RNG peripheral */if (HAL_RNG_DeInit(&RngHandle) != HAL_OK){/* DeInitialization Error */Error_Handler();}   /* Initialize the RNG peripheral */if (HAL_RNG_Init(&RngHandle) != HAL_OK){/* Initialization Error */Error_Handler();}}uint32_t Random_GetNumber(){uint32_t num;if (HAL_RNG_GenerateRandomNumber(&RngHandle, &num) != HAL_OK){/* Random number generation error */Error_Handler();     }return num;}void getRandomNumTo(uint32_t * num){if (HAL_RNG_GenerateRandomNumber(&RngHandle, num) != HAL_OK){/* Random number generation error */Error_Handler();     }}配置文件FreeRTOSIPConfig.h,参考下面代码。
#ifndef FREERTOS_IP_CONFIG_H#define FREERTOS_IP_CONFIG_H#ifdef __cplusplusextern "C" {#endif#include "stm32f4xx.h"#define ipconfigBYTE_ORDER pdFREERTOS_LITTLE_ENDIAN#define ipconfigDRIVER_INCLUDED_TX_IP_CHECKSUM      ( 1 )#define ipconfigDRIVER_INCLUDED_RX_IP_CHECKSUM      ( 1 )#define ipconfigSOCK_DEFAULT_RECEIVE_BLOCK_TIME ( 1000 )#define   ipconfigSOCK_DEFAULT_SEND_BLOCK_TIME  ( 1000 )#define ipconfigZERO_COPY_RX_DRIVER          ( 0 )#define ipconfigZERO_COPY_TX_DRIVER          ( 0 )#define ipconfigUSE_LLMNR                    ( 1 )#define ipconfigUSE_NBNS                 ( 0 )#define ipconfigUSE_DNS_CACHE                ( 1 )#define ipconfigDNS_CACHE_NAME_LENGTH       ( 16 )#define ipconfigDNS_CACHE_ENTRIES            ( 4 )#define ipconfigDNS_REQUEST_ATTEMPTS     ( 4 )#define ipconfigIP_TASK_PRIORITY         ( configMAX_PRIORITIES - 2 )#define ipconfigIP_TASK_STACK_SIZE_WORDS ( configMINIMAL_STACK_SIZE * 5 )extern uint32_t Random_GetNumber(void);#define ipconfigRAND32() Random_GetNumber()#define ipconfigUSE_NETWORK_EVENT_HOOK 1#define ipconfigUDP_MAX_SEND_BLOCK_TIME_TICKS ( 5000 / portTICK_PERIOD_MS )#define ipconfigUSE_DHCP                             1#define ipconfigDHCP_REGISTER_HOSTNAME  1#define ipconfigDHCP_USES_UNICAST       1#define ipconfigMAXIMUM_DISCOVER_TX_PERIOD      ( pdMS_TO_TICKS( 30000 ) )#define ipconfigARP_CACHE_ENTRIES        6#define ipconfigMAX_ARP_RETRANSMISSIONS ( 5 )#define ipconfigMAX_ARP_AGE          150#define ipconfigINCLUDE_FULL_INET_ADDR  1#if( ipconfigZERO_COPY_RX_DRIVER != 0 )#define ipconfigNUM_NETWORK_BUFFER_DESCRIPTORS        ( 25 + 6 )#else#define ipconfigNUM_NETWORK_BUFFER_DESCRIPTORS        25#endif#define ipconfigEVENT_QUEUE_LENGTH       ( ipconfigNUM_NETWORK_BUFFER_DESCRIPTORS + 5 )#define ipconfigALLOW_SOCKET_SEND_WITHOUT_BIND 1#define ipconfigUDP_TIME_TO_LIVE     128#define ipconfigTCP_TIME_TO_LIVE     128 /* also defined in FreeRTOSIPConfigDefaults.h */#define ipconfigUSE_TCP              ( 1 )#define ipconfigUSE_TCP_WIN          ( 0 )#define ipconfigNETWORK_MTU                  1500#define ipconfigUSE_DNS                              1#define ipconfigREPLY_TO_INCOMING_PINGS             1#define ipconfigSUPPORT_OUTGOING_PINGS              1#define ipconfigSUPPORT_SELECT_FUNCTION             1#define ipconfigFILTER_OUT_NON_ETHERNET_II_FRAMES  1#define ipconfigETHERNET_DRIVER_FILTERS_FRAME_TYPES 1#define configWINDOWS_MAC_INTERRUPT_SIMULATOR_DELAY ( 2 / portTICK_PERIOD_MS )#define ipconfigPACKET_FILLER_SIZE 2#define ipconfigTCP_WIN_SEG_COUNT 64#define ipconfigTCP_RX_BUFFER_LENGTH         ( 3 * 1460 )#define ipconfigTCP_TX_BUFFER_LENGTH         ( 2 * 1460 )#define ipconfigIS_VALID_PROG_ADDRESS(x) ( (x) != NULL )#define ipconfigTCP_HANG_PROTECTION              ( 1 )#define ipconfigTCP_HANG_PROTECTION_TIME    ( 30 )#define ipconfigTCP_KEEP_ALIVE               ( 1 )#define ipconfigTCP_KEEP_ALIVE_INTERVAL     ( 20 ) /* in seconds */#define ipconfigUSE_FTP                      0#define ipconfigUSE_HTTP                 0#define ipconfigFTP_TX_BUFSIZE               ( 4 * ipconfigTCP_MSS )#define ipconfigFTP_TX_WINSIZE               ( 2 )#define ipconfigFTP_RX_BUFSIZE               ( 8 * ipconfigTCP_MSS )#define ipconfigFTP_RX_WINSIZE               ( 4 )#define ipconfigHTTP_TX_BUFSIZE              ( 3 * ipconfigTCP_MSS )#define ipconfigHTTP_TX_WINSIZE              ( 2 )#define ipconfigHTTP_RX_BUFSIZE              ( 4 * ipconfigTCP_MSS )#define ipconfigHTTP_RX_WINSIZE              ( 4 )extern int lUDPLoggingPrintf( const char *pcFormatString, ... );#define ipconfigHAS_DEBUG_PRINTF 0#if( ipconfigHAS_DEBUG_PRINTF == 1 )#define FreeRTOS_debug_printf(X)   lUDPLoggingPrintf X#endif#define ipconfigHAS_PRINTF           0#if( ipconfigHAS_PRINTF == 1 )#define FreeRTOS_printf(X)         lUDPLoggingPrintf X#endif#define ipconfigDNS_USE_CALLBACKS            1#define ipconfigSUPPORT_SIGNALS              0#define   TCP_SERVER              0#define TCP_CLIENT           1#if(  TCP_CLIENT == 1 )#define CLIENT_PORT 0#endif#define configMAC_ADDR0      0x00#define configMAC_ADDR1      0x51#define configMAC_ADDR2      0x51#define configMAC_ADDR3      0x51#define configMAC_ADDR4      0x51#ifdef TCP_CLIENT#define configMAC_ADDR5        0x50#else#define configMAC_ADDR5        (0x50+ CLIENT_PORT)#endif#define configIP_ADDR0       192#define configIP_ADDR1       168#define configIP_ADDR2       31#define configIP_ADDR3       130#define configGATEWAY_ADDR0  0#define configGATEWAY_ADDR1  0#define configGATEWAY_ADDR2  0#define configGATEWAY_ADDR3  0#define configDNS_SERVER_ADDR0   0#define configDNS_SERVER_ADDR1   0#define configDNS_SERVER_ADDR2   0#define configDNS_SERVER_ADDR3   0#define configNET_MASK0      0#define configNET_MASK1      0#define configNET_MASK2      0#define configNET_MASK3      0#define configECHO_SERVER_ADDR0  192#define configECHO_SERVER_ADDR1 168#define configECHO_SERVER_ADDR2 31#define configECHO_SERVER_ADDR3 237#define configHTTP_ROOT "/websrc"#define configINCLUDE_DEMO_DEBUG_STATS      0#define configINCLUDE_QUERY_HEAP_COMMAND 0#define configUDP_LOGGING_NEEDS_CR_LF  ( 0 )#define configUDP_LOGGING_STRING_LENGTH ( 200 )#define   configUDP_LOGGING_MAX_MESSAGES_IN_BUFFER  ( 20 )#define   configUDP_LOGGING_TASK_STACK_SIZE      ( 512 )#define configUDP_LOGGING_TASK_PRIORITY      ( tskIDLE_PRIORITY + 1 )#define configUDP_LOGGING_PORT_LOCAL 1499#define configUDP_LOGGING_PORT_REMOTE   1500#define configUDP_LOGGING_ADDR0  192#define configUDP_LOGGING_ADDR1  168#define configUDP_LOGGING_ADDR2  0#define configUDP_LOGGING_ADDR3  100#ifdef __cplusplus} /* extern "C" */#endif#endif
  • 修改接口文件NetworkInterface.c。具体修改请参考如下代码。
#include "NetworkInterface.h"BaseType_t xSTM32_PhyRead( BaseType_t xAddress, BaseType_t xRegister, uint32_t *pulValue );#ifndef   BMSR_LINK_STATUS#define BMSR_LINK_STATUS            0x0004UL#endif#ifndef   PHY_LS_HIGH_CHECK_TIME_MS#define PHY_LS_HIGH_CHECK_TIME_MS  15000#endif#ifndef   PHY_LS_LOW_CHECK_TIME_MS#define PHY_LS_LOW_CHECK_TIME_MS   1000#endif#define EMAC_IF_RX_EVENT        1UL#define EMAC_IF_TX_EVENT        2UL#define EMAC_IF_ERR_EVENT       4UL#define EMAC_IF_ALL_EVENT       ( EMAC_IF_RX_EVENT | EMAC_IF_TX_EVENT | EMAC_IF_ERR_EVENT )#define ETH_DMA_ALL_INTS \( ETH_DMA_IT_TST | ETH_DMA_IT_PMT | ETH_DMA_IT_MMC | ETH_DMA_IT_NIS | ETH_DMA_IT_ER | \ETH_DMA_IT_FBE | ETH_DMA_IT_RWT | ETH_DMA_IT_RPS | ETH_DMA_IT_RBU | ETH_DMA_IT_R | \ETH_DMA_IT_TU | ETH_DMA_IT_RO | ETH_DMA_IT_TJT | ETH_DMA_IT_TPS | ETH_DMA_IT_T )#define ipFRAGMENT_OFFSET_BIT_MASK       ( ( uint16_t ) 0x0fff ) /* The bits in the two byte IP header field that make up the fragment offset value. */#if !defined( ipconfigETHERNET_AN_ENABLE )#define ipconfigETHERNET_AN_ENABLE            1#endif#if !defined( ipconfigETHERNET_AUTO_CROSS_ENABLE )#define ipconfigETHERNET_AUTO_CROSS_ENABLE    1#endif#if( ipconfigETHERNET_AN_ENABLE == 0 )#if !defined( ipconfigETHERNET_CROSSED_LINK )#define ipconfigETHERNET_CROSSED_LINK          1#endif#if !defined( ipconfigETHERNET_USE_100MB )#define ipconfigETHERNET_USE_100MB            1#endif#if !defined( ipconfigETHERNET_USE_FULL_DUPLEX )#define ipconfigETHERNET_USE_FULL_DUPLEX      1#endif#endif /* ipconfigETHERNET_AN_ENABLE == 0 */#ifndef configEMAC_TASK_STACK_SIZE#define configEMAC_TASK_STACK_SIZE ( 2 * configMINIMAL_STACK_SIZE )#endifstatic void prvEMACHandlerTask( void *pvParameters );static void prvEthernetUpdateConfig( BaseType_t xForce );static BaseType_t prvNetworkInterfaceInput( void );static BaseType_t xMayAcceptPacket( uint8_t *pcBuffer );static void prvDMATxDescListInit( void );static void prvDMARxDescListInit( void );static void vClearTXBuffers( void );#if( ipconfigUSE_LLMNR != 0 )static void prvMACAddressConfig(ETH_HandleTypeDef *heth, uint32_t ulIndex, uint8_t *Addr);#endifvolatile uint32_t ulISREvents;static EthernetPhy_t xPhyObject;static ETH_HandleTypeDef xETH;static SemaphoreHandle_t xTXDescriptorSemaphore = NULL;#if( ipconfigUSE_LLMNR == 1 )static const uint8_t xLLMNR_MACAddress[] = { 0x01, 0x00, 0x5E, 0x00, 0x00, 0xFC };#endif__attribute__ ((aligned (32)))__attribute__ ((section(".first_data")))ETH_DMADescTypeDef  DMARxDscrTab[ ETH_RXBUFNB ];#if( ipconfigZERO_COPY_RX_DRIVER == 0 )__ALIGN_BEGIN uint8_t Rx_Buff[ ETH_RXBUFNB ][ ETH_RX_BUF_SIZE ] __ALIGN_END;#endif__attribute__ ((aligned (32)))__attribute__ ((section(".first_data")))ETH_DMADescTypeDef  DMATxDscrTab[ ETH_TXBUFNB ];#if( ipconfigZERO_COPY_TX_DRIVER == 0 )__ALIGN_BEGIN uint8_t Tx_Buff[ ETH_TXBUFNB ][ ETH_TX_BUF_SIZE ] __ALIGN_END;#endifstatic __IO ETH_DMADescTypeDef  *DMATxDescToClear;extern const uint8_t ucMACAddress[ 6 ];static TaskHandle_t xEMACTaskHandle = NULL;static uint32_t ulPHYLinkStatus = 0;const PhyProperties_t xPHYProperties ={#if( ipconfigETHERNET_AN_ENABLE != 0 ).ucSpeed = PHY_SPEED_AUTO,.ucDuplex = PHY_DUPLEX_AUTO,#else#if( ipconfigETHERNET_USE_100MB != 0 ).ucSpeed = PHY_SPEED_100,#else.ucSpeed = PHY_SPEED_10,#endif#if( ipconfigETHERNET_USE_FULL_DUPLEX != 0 ).duplex = PHY_DUPLEX_FULL,#else.duplex = PHY_DUPLEX_HALF,#endif#endif#if( ipconfigETHERNET_AN_ENABLE != 0 ) && ( ipconfigETHERNET_AUTO_CROSS_ENABLE != 0 ).ucMDI_X = PHY_MDIX_AUTO,#elif( ipconfigETHERNET_CROSSED_LINK != 0 ).ucMDI_X = PHY_MDIX_CROSSED,#else.ucMDI_X = PHY_MDIX_DIRECT,#endif};/*-----------------------------------------------------------*/void HAL_ETH_RxCpltCallback( ETH_HandleTypeDef *heth ){BaseType_t xHigherPriorityTaskWoken = pdFALSE;ulISREvents |= EMAC_IF_RX_EVENT;if( xEMACTaskHandle != NULL ){vTaskNotifyGiveFromISR( xEMACTaskHandle, &xHigherPriorityTaskWoken );portYIELD_FROM_ISR( xHigherPriorityTaskWoken );}}/*-----------------------------------------------------------*/void HAL_ETH_TxCpltCallback( ETH_HandleTypeDef *heth ){BaseType_t xHigherPriorityTaskWoken = pdFALSE;ulISREvents |= EMAC_IF_TX_EVENT;if( xEMACTaskHandle != NULL ){vTaskNotifyGiveFromISR( xEMACTaskHandle, &xHigherPriorityTaskWoken );portYIELD_FROM_ISR( xHigherPriorityTaskWoken );}}/*-----------------------------------------------------------*/static void vClearTXBuffers(){__IO ETH_DMADescTypeDef  *txLastDescriptor = xETH.TxDesc;size_t uxCount = ( ( UBaseType_t ) ETH_TXBUFNB ) - uxSemaphoreGetCount( xTXDescriptorSemaphore );#if( ipconfigZERO_COPY_TX_DRIVER != 0 )NetworkBufferDescriptor_t *pxNetworkBuffer;uint8_t *ucPayLoad;#endifwhile( ( uxCount > 0 ) && ( ( DMATxDescToClear->Status & ETH_DMATXDESC_OWN ) == 0 ) ){if( ( DMATxDescToClear == txLastDescriptor ) && ( uxCount != ETH_TXBUFNB ) ){break;}#if( ipconfigZERO_COPY_TX_DRIVER != 0 ){ucPayLoad = ( uint8_t * )DMATxDescToClear->Buffer1Addr;if( ucPayLoad != NULL ){pxNetworkBuffer = pxPacketBuffer_to_NetworkBuffer( ucPayLoad );if( pxNetworkBuffer != NULL ){vReleaseNetworkBufferAndDescriptor( pxNetworkBuffer ) ;}DMATxDescToClear->Buffer1Addr = ( uint32_t )0u;}}#endif /* ipconfigZERO_COPY_TX_DRIVER */DMATxDescToClear = ( ETH_DMADescTypeDef * )( DMATxDescToClear->Buffer2NextDescAddr );uxCount--;/* Tell the counting semaphore that one more TX descriptor is available. */xSemaphoreGive( xTXDescriptorSemaphore );}}/*-----------------------------------------------------------*/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_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 *) ucMACAddress;xETH.Init.RxMode = ETH_RXINTERRUPT_MODE;xETH.Init.ChecksumMode = ETH_CHECKSUM_BY_HARDWARE;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 ){prvMACAddressConfig( &xETH, ETH_MAC_ADDRESS1, ( uint8_t *) xLLMNR_MACAddress );}#endifprvEthernetUpdateConfig( pdTRUE );xTaskCreate( prvEMACHandlerTask, "EMAC", configEMAC_TASK_STACK_SIZE, NULL, configMAX_PRIORITIES - 1, &xEMACTaskHandle );} /* if( xEMACTaskHandle == NULL ) *///检查PHY连接状态xSTM32_PhyRead( 0x00,0x01, &ulPHYLinkStatus);xPhyObject.ulLinkStatusMask = ulPHYLinkStatus;return ( ulPHYLinkStatus & BMSR_LINK_STATUS ) != 0;}/*-----------------------------------------------------------*/static void prvDMATxDescListInit(){ETH_DMADescTypeDef *pxDMADescriptor;BaseType_t xIndex;/* Get the pointer on the first member of the descriptor list */pxDMADescriptor = DMATxDscrTab;/* Fill each DMA descriptor with the right values */for( xIndex = 0; xIndex < ETH_TXBUFNB; xIndex++, pxDMADescriptor++ ){/* Set Second Address Chained bit */pxDMADescriptor->Status = ETH_DMATXDESC_TCH;#if( ipconfigZERO_COPY_TX_DRIVER == 0 ){/* Set Buffer1 address pointer */pxDMADescriptor->Buffer1Addr = ( uint32_t )( Tx_Buff[ xIndex ] );}#endifif( xETH.Init.ChecksumMode == ETH_CHECKSUM_BY_HARDWARE ){/* Set the DMA Tx descriptors checksum insertion for TCP, UDP, and ICMP */pxDMADescriptor->Status |= ETH_DMATXDESC_CHECKSUMTCPUDPICMPFULL;}/* Initialize the next descriptor with the Next Descriptor Polling Enable */if( xIndex < ETH_TXBUFNB - 1 ){/* Set next descriptor address register with next descriptor base address */pxDMADescriptor->Buffer2NextDescAddr = ( uint32_t ) ( pxDMADescriptor + 1 );}else{/* For last descriptor, set next descriptor address register equal to the first descriptor base address */pxDMADescriptor->Buffer2NextDescAddr = ( uint32_t ) DMATxDscrTab;}}/* Set Transmit Descriptor List Address Register */xETH.Instance->DMATDLAR = ( uint32_t ) DMATxDscrTab;}/*-----------------------------------------------------------*/static void prvDMARxDescListInit(){ETH_DMADescTypeDef *pxDMADescriptor;BaseType_t xIndex;/** RX-descriptors.*//* Get the pointer on the first member of the descriptor list */pxDMADescriptor = DMARxDscrTab;/* Fill each DMA descriptor with the right values */for( xIndex = 0; xIndex < ETH_RXBUFNB; xIndex++, pxDMADescriptor++ ){/* Set Buffer1 size and Second Address Chained bit */pxDMADescriptor->ControlBufferSize = ETH_DMARXDESC_RCH | (uint32_t)ETH_RX_BUF_SIZE; #if( ipconfigZERO_COPY_RX_DRIVER != 0 ){/* Set Buffer1 address pointer */NetworkBufferDescriptor_t *pxBuffer;pxBuffer = pxGetNetworkBufferWithDescriptor( ETH_RX_BUF_SIZE, 100ul );/* If the assert below fails, make sure that there are at least 'ETH_RXBUFNB'Network Buffers available during start-up ( ipconfigNUM_NETWORK_BUFFER_DESCRIPTORS ) */configASSERT( pxBuffer != NULL );if( pxBuffer != NULL ){pxDMADescriptor->Buffer1Addr = (uint32_t)pxBuffer->pucEthernetBuffer;pxDMADescriptor->Status = ETH_DMARXDESC_OWN;}}#else{/* Set Buffer1 address pointer */pxDMADescriptor->Buffer1Addr = ( uint32_t )( Rx_Buff[ xIndex ] );/* Set Own bit of the Rx descriptor Status */pxDMADescriptor->Status = ETH_DMARXDESC_OWN;}#endif/* Initialize the next descriptor with the Next Descriptor Polling Enable */if( xIndex < ETH_RXBUFNB - 1 ){/* Set next descriptor address register with next descriptor base address */pxDMADescriptor->Buffer2NextDescAddr = ( uint32_t )( pxDMADescriptor + 1 );}else{/* For last descriptor, set next descriptor address register equal to the first descriptor base address */pxDMADescriptor->Buffer2NextDescAddr = ( uint32_t ) DMARxDscrTab;}}/* Set Receive Descriptor List Address Register */xETH.Instance->DMARDLAR = ( uint32_t ) DMARxDscrTab;}/*-----------------------------------------------------------*/static void prvMACAddressConfig(ETH_HandleTypeDef *heth, uint32_t ulIndex, uint8_t *Addr){uint32_t ulTempReg;/* Calculate the selected MAC address high register. */ulTempReg = 0x80000000ul | ( ( uint32_t ) Addr[ 5 ] << 8 ) | ( uint32_t ) Addr[ 4 ];/* Load the selected MAC address high register. */( *(__IO uint32_t *)( ( uint32_t ) ( ETH_MAC_ADDR_HBASE + ulIndex ) ) ) = ulTempReg;/* Calculate the selected MAC address low register. */ulTempReg = ( ( uint32_t ) Addr[ 3 ] << 24 ) | ( ( uint32_t ) Addr[ 2 ] << 16 ) | ( ( uint32_t ) Addr[ 1 ] << 8 ) | Addr[ 0 ];/* Load the selected MAC address low register */( *(__IO uint32_t *) ( ( uint32_t ) ( ETH_MAC_ADDR_LBASE + ulIndex ) ) ) = ulTempReg;}/*-----------------------------------------------------------*/BaseType_t xNetworkInterfaceOutput( NetworkBufferDescriptor_t * const pxDescriptor, BaseType_t bReleaseAfterSend ){BaseType_t xReturn = pdFAIL;uint32_t ulTransmitSize = 0;__IO ETH_DMADescTypeDef *pxDmaTxDesc;/* Do not wait too long for a free TX DMA buffer. */const TickType_t xBlockTimeTicks = pdMS_TO_TICKS( 50u );#if( ipconfigDRIVER_INCLUDED_TX_IP_CHECKSUM != 0 ){ProtocolPacket_t *pxPacket;#if( ipconfigZERO_COPY_RX_DRIVER != 0 ){configASSERT( bReleaseAfterSend != 0 );}#endif /* ipconfigZERO_COPY_RX_DRIVER *//* If the peripheral must calculate the checksum, it wantsthe protocol checksum to have a value of zero. */pxPacket = ( ProtocolPacket_t * ) ( pxDescriptor->pucEthernetBuffer );if( pxPacket->xICMPPacket.xIPHeader.ucProtocol == ipPROTOCOL_ICMP ){pxPacket->xICMPPacket.xICMPHeader.usChecksum = ( uint16_t )0u;}}#endif/* Open a do {} while ( 0 ) loop to be able to call break. */do{if( xPhyObject.ulLinkStatusMask != 0 ){if( xSemaphoreTake( xTXDescriptorSemaphore, xBlockTimeTicks ) != pdPASS ){/* Time-out waiting for a free TX descriptor. */break;}/* This function does the actual transmission of the packet. The packet iscontained in 'pxDescriptor' that is passed to the function. */pxDmaTxDesc = xETH.TxDesc;/* Is this buffer available? */configASSERT ( ( pxDmaTxDesc->Status & ETH_DMATXDESC_OWN ) == 0 );{/* Is this buffer available? *//* Get bytes in current buffer. */ulTransmitSize = pxDescriptor->xDataLength;if( ulTransmitSize > ETH_TX_BUF_SIZE ){ulTransmitSize = ETH_TX_BUF_SIZE;}#if( ipconfigZERO_COPY_TX_DRIVER == 0 ){/* Copy the bytes. */memcpy( ( void * ) pxDmaTxDesc->Buffer1Addr, pxDescriptor->pucEthernetBuffer, ulTransmitSize );}#else{/* Move the buffer. */pxDmaTxDesc->Buffer1Addr = ( uint32_t )pxDescriptor->pucEthernetBuffer;/* The Network Buffer has been passed to DMA, no need to release it. */bReleaseAfterSend = pdFALSE_UNSIGNED;}#endif /* ipconfigZERO_COPY_TX_DRIVER *//* Ask to set the IPv4 checksum.Also need an Interrupt on Completion so that 'vClearTXBuffers()' will be called.. */pxDmaTxDesc->Status |= ETH_DMATXDESC_CIC_TCPUDPICMP_FULL | ETH_DMATXDESC_IC;/* Prepare transmit descriptors to give to DMA. *//* Set LAST and FIRST segment */pxDmaTxDesc->Status |= ETH_DMATXDESC_FS | ETH_DMATXDESC_LS;/* Set frame size */pxDmaTxDesc->ControlBufferSize = ( ulTransmitSize & ETH_DMATXDESC_TBS1 );/* Set Own bit of the Tx descriptor Status: gives the buffer back to ETHERNET DMA */pxDmaTxDesc->Status |= ETH_DMATXDESC_OWN;/* Point to next descriptor */xETH.TxDesc = ( ETH_DMADescTypeDef * ) ( xETH.TxDesc->Buffer2NextDescAddr );/* Ensure completion of memory access */__DSB();/* Resume DMA transmission*/xETH.Instance->DMATPDR = 0;iptraceNETWORK_INTERFACE_TRANSMIT();xReturn = pdPASS;}}else{/* The PHY has no Link Status, packet shall be dropped. */}}while( 0 );/* The buffer has been sent so can be released. */if( bReleaseAfterSend != pdFALSE ){vReleaseNetworkBufferAndDescriptor( pxDescriptor );}return xReturn;}/*-----------------------------------------------------------*/static BaseType_t xMayAcceptPacket( uint8_t *pcBuffer ){const ProtocolPacket_t *pxProtPacket = ( const ProtocolPacket_t * )pcBuffer;switch( pxProtPacket->xTCPPacket.xEthernetHeader.usFrameType ){case ipARP_FRAME_TYPE:/* Check it later. */return pdTRUE;case ipIPv4_FRAME_TYPE:/* Check it here. */break;default:/* Refuse the packet. */return pdFALSE;}#if( ipconfigETHERNET_DRIVER_FILTERS_PACKETS == 1 ){const IPHeader_t *pxIPHeader = &(pxProtPacket->xTCPPacket.xIPHeader);uint32_t ulDestinationIPAddress;/* Ensure that the incoming packet is not fragmented (only outgoing packets* can be fragmented) as these are the only handled IP frames currently. */if( ( pxIPHeader->usFragmentOffset & FreeRTOS_ntohs( ipFRAGMENT_OFFSET_BIT_MASK ) ) != 0U ){return pdFALSE;}/* HT: Might want to make the following configurable because* most IP messages have a standard length of 20 bytes *//* 0x45 means: IPv4 with an IP header of 5 x 4 = 20 bytes* 0x47 means: IPv4 with an IP header of 7 x 4 = 28 bytes */if( pxIPHeader->ucVersionHeaderLength < 0x45 || pxIPHeader->ucVersionHeaderLength > 0x4F ){return pdFALSE;}ulDestinationIPAddress = pxIPHeader->ulDestinationIPAddress;/* Is the packet for this node? */if( ( ulDestinationIPAddress != *ipLOCAL_IP_ADDRESS_POINTER ) &&/* Is it a broadcast address x.x.x.255 ? */( ( FreeRTOS_ntohl( ulDestinationIPAddress ) & 0xff ) != 0xff ) &&#if( ipconfigUSE_LLMNR == 1 )( ulDestinationIPAddress != ipLLMNR_IP_ADDR ) &&#endif( *ipLOCAL_IP_ADDRESS_POINTER != 0 ) ) {FreeRTOS_printf( ( "Drop IP %lxip\n", FreeRTOS_ntohl( ulDestinationIPAddress ) ) );return pdFALSE;}if( pxIPHeader->ucProtocol == ipPROTOCOL_UDP ){uint16_t port = pxProtPacket->xUDPPacket.xUDPHeader.usDestinationPort;if( ( xPortHasUDPSocket( port ) == pdFALSE )#if ipconfigUSE_LLMNR == 1&& ( port != FreeRTOS_ntohs( ipLLMNR_PORT ) )#endif#if ipconfigUSE_NBNS == 1&& ( port != FreeRTOS_ntohs( ipNBNS_PORT ) )#endif#if ipconfigUSE_DNS == 1&& ( pxProtPacket->xUDPPacket.xUDPHeader.usSourcePort != FreeRTOS_ntohs( ipDNS_PORT ) )#endif) {/* Drop this packet, not for this device. */return pdFALSE;}}}#endif  /* ipconfigETHERNET_DRIVER_FILTERS_PACKETS */return pdTRUE;}/*-----------------------------------------------------------*/static BaseType_t prvNetworkInterfaceInput( void ){NetworkBufferDescriptor_t *pxCurDescriptor;NetworkBufferDescriptor_t *pxNewDescriptor = NULL;BaseType_t xReceivedLength, xAccepted;__IO ETH_DMADescTypeDef *pxDMARxDescriptor;xIPStackEvent_t xRxEvent = { eNetworkRxEvent, NULL };const TickType_t xDescriptorWaitTime = pdMS_TO_TICKS( 250 );uint8_t *pucBuffer;pxDMARxDescriptor = xETH.RxDesc;if( ( pxDMARxDescriptor->Status & ETH_DMARXDESC_OWN) == 0 ){/* Get the Frame Length of the received packet: substruct 4 bytes of the CRC */xReceivedLength = ( ( pxDMARxDescriptor->Status & ETH_DMARXDESC_FL ) >> ETH_DMARXDESC_FRAMELENGTHSHIFT ) - 4;pucBuffer = (uint8_t *) pxDMARxDescriptor->Buffer1Addr;/* Update the ETHERNET DMA global Rx descriptor with next Rx descriptor *//* Chained Mode */   /* Selects the next DMA Rx descriptor list for next buffer to read */xETH.RxDesc = ( ETH_DMADescTypeDef* )pxDMARxDescriptor->Buffer2NextDescAddr;}else{xReceivedLength = 0;}/* Obtain the size of the packet and put it into the "usReceivedLength" variable. *//* get received frame */if( xReceivedLength > 0ul ){/* In order to make the code easier and faster, only packets in a single bufferwill be accepted.  This can be done by making the buffers large enough tohold a complete Ethernet packet (1536 bytes).Therefore, two sanity checks: */configASSERT( xReceivedLength <= ETH_RX_BUF_SIZE );if( ( pxDMARxDescriptor->Status & ( ETH_DMARXDESC_CE | ETH_DMARXDESC_IPV4HCE | ETH_DMARXDESC_FT ) ) != ETH_DMARXDESC_FT ){/* Not an Ethernet frame-type or a checmsum error. */xAccepted = pdFALSE;}else{/* See if this packet must be handled. */xAccepted = xMayAcceptPacket( pucBuffer );}if( xAccepted != pdFALSE ){/* The packet wil be accepted, but check first if a new Network Buffer canbe obtained. If not, the packet will still be dropped. */pxNewDescriptor = pxGetNetworkBufferWithDescriptor( ETH_RX_BUF_SIZE, xDescriptorWaitTime );if( pxNewDescriptor == NULL ){/* A new descriptor can not be allocated now. This packet will be dropped. */xAccepted = pdFALSE;}}#if( ipconfigZERO_COPY_RX_DRIVER != 0 ){/* Find out which Network Buffer was originally passed to the descriptor. */pxCurDescriptor = pxPacketBuffer_to_NetworkBuffer( pucBuffer );configASSERT( pxCurDescriptor != NULL );}#else{/* In this mode, the two descriptors are the same. */pxCurDescriptor = pxNewDescriptor;if( pxNewDescriptor != NULL ){/* The packet is acepted and a new Network Buffer was created,copy data to the Network Bufffer. */memcpy( pxNewDescriptor->pucEthernetBuffer, pucBuffer, xReceivedLength );}}#endifif( xAccepted != pdFALSE ){pxCurDescriptor->xDataLength = xReceivedLength;xRxEvent.pvData = ( void * ) pxCurDescriptor;/* Pass the data to the TCP/IP task for processing. */if( xSendEventStructToIPTask( &xRxEvent, xDescriptorWaitTime ) == pdFALSE ){/* Could not send the descriptor into the TCP/IP stack, itmust be released. */vReleaseNetworkBufferAndDescriptor( pxCurDescriptor );iptraceETHERNET_RX_EVENT_LOST();}else{iptraceNETWORK_INTERFACE_RECEIVE();}}/* Release descriptors to DMA */#if( ipconfigZERO_COPY_RX_DRIVER != 0 ){/* Set Buffer1 address pointer */if( pxNewDescriptor != NULL ){pxDMARxDescriptor->Buffer1Addr = (uint32_t)pxNewDescriptor->pucEthernetBuffer;}else{/* The packet was dropped and the same NetworkBuffer will be used to receive a new packet. */}}#endif /* ipconfigZERO_COPY_RX_DRIVER *//* Set Buffer1 size and Second Address Chained bit */pxDMARxDescriptor->ControlBufferSize = ETH_DMARXDESC_RCH | (uint32_t)ETH_RX_BUF_SIZE; pxDMARxDescriptor->Status = ETH_DMARXDESC_OWN;/* Ensure completion of memory access */__DSB();/* When Rx Buffer unavailable flag is set clear it and resumereception. */if( ( xETH.Instance->DMASR & ETH_DMASR_RBUS ) != 0 ){/* Clear RBUS ETHERNET DMA flag. */xETH.Instance->DMASR = ETH_DMASR_RBUS;/* Resume DMA reception. */xETH.Instance->DMARPDR = 0;}}return ( xReceivedLength > 0 );}/*-----------------------------------------------------------*/BaseType_t xSTM32_PhyRead( BaseType_t xAddress, BaseType_t xRegister, uint32_t *pulValue ){uint16_t usPrevAddress = xETH.Init.PhyAddress;BaseType_t xResult;HAL_StatusTypeDef xHALResult;xETH.Init.PhyAddress = xAddress;xHALResult = HAL_ETH_ReadPHYRegister( &xETH, ( uint16_t )xRegister, pulValue );xETH.Init.PhyAddress = usPrevAddress;if( xHALResult == HAL_OK ){xResult = 0;}else{xResult = -1;}return xResult;}/*-----------------------------------------------------------*/BaseType_t xSTM32_PhyWrite( BaseType_t xAddress, BaseType_t xRegister, uint32_t ulValue ){uint16_t usPrevAddress = xETH.Init.PhyAddress;BaseType_t xResult;HAL_StatusTypeDef xHALResult;xETH.Init.PhyAddress = xAddress;xHALResult = HAL_ETH_WritePHYRegister( &xETH, ( uint16_t )xRegister, ulValue );xETH.Init.PhyAddress = usPrevAddress;if( xHALResult == HAL_OK ){xResult = 0;}else{xResult = -1;}return xResult;}/*-----------------------------------------------------------*/void phy_test(){BaseType_t xPhyCount;BaseType_t xPhyIndex;vPhyInitialise( &xPhyObject, xSTM32_PhyRead, xSTM32_PhyWrite );xPhyCount = xPhyDiscover( &xPhyObject );FreeRTOS_printf( ( "PHY count %ld\n", xPhyCount ) );for( xPhyIndex = 0; xPhyIndex < xPhyCount; xPhyIndex++ ){FreeRTOS_printf( ( "PHY[%d] at address %d ( 0x%08X )\n",xPhyIndex,xPhyObject.ucPhyIndexes[ xPhyIndex ],xPhyObject.ulPhyIDs[ xPhyIndex ] ) );}}void vMACBProbePhy( void ){vPhyInitialise( &xPhyObject, xSTM32_PhyRead, xSTM32_PhyWrite );xPhyDiscover( &xPhyObject );xPhyConfigure( &xPhyObject, &xPHYProperties );}/*-----------------------------------------------------------*/static void prvEthernetUpdateConfig( BaseType_t xForce ){FreeRTOS_printf( ( "prvEthernetUpdateConfig: LS mask %02lX Force %d\n",xPhyObject.ulLinkStatusMask,( int )xForce ) );if( ( xForce != pdFALSE ) || ( xPhyObject.ulLinkStatusMask != 0 ) ){/* Restart the auto-negotiation. */if( xETH.Init.AutoNegotiation != ETH_AUTONEGOTIATION_DISABLE ){xPhyStartAutoNegotiation( &xPhyObject, xPhyGetMask( &xPhyObject ) );/* Configure the MAC with the Duplex Mode fixed by theauto-negotiation process. */if( xPhyObject.xPhyProperties.ucDuplex == PHY_DUPLEX_FULL ){xETH.Init.DuplexMode = ETH_MODE_FULLDUPLEX;}else{xETH.Init.DuplexMode = ETH_MODE_HALFDUPLEX;}/* Configure the MAC with the speed fixed by theauto-negotiation process. */if( xPhyObject.xPhyProperties.ucSpeed == PHY_SPEED_10 ){xETH.Init.Speed = ETH_SPEED_10M;}else{xETH.Init.Speed = ETH_SPEED_100M;}}else /* AutoNegotiation Disable */{/* Check parameters */assert_param( IS_ETH_SPEED( xETH.Init.Speed ) );assert_param( IS_ETH_DUPLEX_MODE( xETH.Init.DuplexMode ) );if( xETH.Init.DuplexMode == ETH_MODE_FULLDUPLEX ){xPhyObject.xPhyPreferences.ucDuplex = PHY_DUPLEX_HALF;}else{xPhyObject.xPhyPreferences.ucDuplex = PHY_DUPLEX_FULL;}if( xETH.Init.Speed == ETH_SPEED_10M ){xPhyObject.xPhyPreferences.ucSpeed = PHY_SPEED_10;}else{xPhyObject.xPhyPreferences.ucSpeed = PHY_SPEED_100;}xPhyObject.xPhyPreferences.ucMDI_X = PHY_MDIX_AUTO;/* Use predefined (fixed) configuration. */xPhyFixedValue( &xPhyObject, xPhyGetMask( &xPhyObject ) );}/* ETHERNET MAC Re-Configuration */HAL_ETH_ConfigMAC( &xETH, (ETH_MACInitTypeDef *) NULL);/* Restart MAC interface */HAL_ETH_Start( &xETH);}else{/* Stop MAC interface */HAL_ETH_Stop( &xETH );}}/*-----------------------------------------------------------*/BaseType_t xGetPhyLinkStatus( void ){BaseType_t xReturn;if( xPhyObject.ulLinkStatusMask != 0 ){xReturn = pdPASS;}else{xReturn = pdFAIL;}return xReturn;}static void prvEMACHandlerTask( void *pvParameters ){TimeOut_t xPhyTime;UBaseType_t uxLastMinBufferCount = 0;#if( ipconfigCHECK_IP_QUEUE_SPACE != 0 )UBaseType_t uxLastMinQueueSpace = 0;#endifTickType_t xPhyRemTime;UBaseType_t uxCurrentCount;BaseType_t xResult;uint32_t xStatus;const TickType_t ulMaxBlockTime = pdMS_TO_TICKS( 100UL );/* Remove compiler warnings about unused parameters. */( void ) pvParameters;for( ;; ){xResult = 0;uxCurrentCount = uxGetMinimumFreeNetworkBuffers();if( uxLastMinBufferCount != uxCurrentCount ){/* The logging produced below may be helpfulwhile tuning +TCP: see how many buffers are in use. */uxLastMinBufferCount = uxCurrentCount;FreeRTOS_printf( ( "Network buffers: %lu lowest %lu\n",uxGetNumberOfFreeNetworkBuffers(), uxCurrentCount ) );}if( xTXDescriptorSemaphore != NULL ){static UBaseType_t uxLowestSemCount = ( UBaseType_t ) ETH_TXBUFNB - 1;uxCurrentCount = uxSemaphoreGetCount( xTXDescriptorSemaphore );if( uxLowestSemCount > uxCurrentCount ){uxLowestSemCount = uxCurrentCount;FreeRTOS_printf( ( "TX DMA buffers: lowest %lu\n", uxLowestSemCount ) );}}#if( ipconfigCHECK_IP_QUEUE_SPACE != 0 ){uxCurrentCount = uxGetMinimumIPQueueSpace();if( uxLastMinQueueSpace != uxCurrentCount ){/* The logging produced below may be helpfulwhile tuning +TCP: see how many buffers are in use. */uxLastMinQueueSpace = uxCurrentCount;FreeRTOS_printf( ( "Queue space: lowest %lu\n", uxCurrentCount ) );}}#endif /* ipconfigCHECK_IP_QUEUE_SPACE */if( ( ulISREvents & EMAC_IF_ALL_EVENT ) == 0 ){/* No events to process now, wait for the next. */ulTaskNotifyTake( pdFALSE, ulMaxBlockTime );}if( ( ulISREvents & EMAC_IF_RX_EVENT ) != 0 ){ulISREvents &= ~EMAC_IF_RX_EVENT;xResult = prvNetworkInterfaceInput();if( xResult > 0 ){while( prvNetworkInterfaceInput() > 0 ){}}}if( ( ulISREvents & EMAC_IF_TX_EVENT ) != 0 ){/* Code to release TX buffers if zero-copy is used. */ulISREvents &= ~EMAC_IF_TX_EVENT;/* Check if DMA packets have been delivered. */vClearTXBuffers();}if( ( ulISREvents & EMAC_IF_ERR_EVENT ) != 0 ){/* Future extension: logging about errors that occurred. */ulISREvents &= ~EMAC_IF_ERR_EVENT;}if( xResult > 0 ){/* A packet was received. No need to check for the PHY status now,but set a timer to check it later on. */vTaskSetTimeOutState( &xPhyTime );xPhyRemTime = pdMS_TO_TICKS( PHY_LS_HIGH_CHECK_TIME_MS );xResult = 0;}else if( xTaskCheckForTimeOut( &xPhyTime, &xPhyRemTime ) != pdFALSE ){HAL_ETH_ReadPHYRegister( &xETH, 0x01,&xStatus );xPhyObject.ulLinkStatusMask = xStatus;if( ( ulPHYLinkStatus & BMSR_LINK_STATUS ) != ( xStatus & BMSR_LINK_STATUS ) ){ulPHYLinkStatus = xStatus;FreeRTOS_printf( ( "prvEMACHandlerTask: PHY LS now %d\n", ( ulPHYLinkStatus & BMSR_LINK_STATUS ) != 0 ) );prvEthernetUpdateConfig( pdFALSE );}vTaskSetTimeOutState( &xPhyTime );if( ( ulPHYLinkStatus & BMSR_LINK_STATUS ) != 0 ){xPhyRemTime = pdMS_TO_TICKS( PHY_LS_HIGH_CHECK_TIME_MS );}else{xPhyRemTime = pdMS_TO_TICKS( PHY_LS_LOW_CHECK_TIME_MS );}}}}/*-----------------------------------------------------------*/void ETH_IRQHandler( void ){HAL_ETH_IRQHandler( &xETH );}
  1. TCP还有一些配置函数在接口文件中没有实现,需要用户自己实现。创建netInfoConfig.c和netInfoConfig.h文件来实现TCP需要的一些接口配置函数参考如下代码。
#include "netInfoConfig.h" const uint8_t ucIPAddress[ 4 ] = { configIP_ADDR0, configIP_ADDR1, configIP_ADDR2, configIP_ADDR3 }; const uint8_t ucNetMask[ 4 ] = { configNET_MASK0, configNET_MASK1, configNET_MASK2, configNET_MASK3 }; const uint8_t ucGatewayAddress[ 4 ] = { configGATEWAY_ADDR0, configGATEWAY_ADDR1, configGATEWAY_ADDR2, configGATEWAY_ADDR3 }; const uint8_t ucDNSServerAddress[ 4 ] = { configDNS_SERVER_ADDR0, configDNS_SERVER_ADDR1, configDNS_SERVER_ADDR2, configDNS_SERVER_ADDR3 }; const uint8_t ucMACAddress[ 6 ] = { configMAC_ADDR0, configMAC_ADDR1, configMAC_ADDR2, configMAC_ADDR3, configMAC_ADDR4, configMAC_ADDR5 };//this queue should be create for vApplicationPingReplyHook()QueueHandle_t xPingReplyQueue;/* --------------------------FUNCTION MODULE----------------------------- *///return a rand numUBaseType_t uxRand(){ return (UBaseType_t) getRandomNum(); } //Use this name to request IP during DHCP callconst char *pcApplicationHostnameHook( void ){return mainHOST_NAME;}/** The following function should be provided by the user and return true if it* matches the domain name.*this func will be used to judge whether *pcName matche DNS request or LLMNR request.return pdTRUE if matching DNS request,return pdFALSE if matching LLMNR request.*/ BaseType_t xApplicationDNSQueryHook( const char *pcName ){ BaseType_t xReturn; if( strcmp( pcName, pcApplicationHostnameHook() ) == 0 ) { xReturn = pdPASS; } else if( strcmp( pcName, mainDEVICE_NICK_NAME ) == 0 ) { xReturn = pdPASS; } else { xReturn = pdFAIL; } return xReturn; } void vApplicationPingReplyHook( ePingReplyStatus_t eStatus, uint16_t usIdentifier ) { switch( eStatus ) { case eSuccess: xQueueSend( xPingReplyQueue, &usIdentifier, 10 / portTICK_PERIOD_MS ); break; case eInvalidChecksum :break;case eInvalidData :   break; } }void xPingReplyQueueCreate(void){ xPingReplyQueue = xQueueCreate( 20, sizeof( uint16_t ) ); }BaseType_t vSendPing( const char *pcIPAddress ){uint16_t usRequestSequenceNumber, usReplySequenceNumber;uint32_t ulIPAddress;ulIPAddress = FreeRTOS_inet_addr( pcIPAddress );if(xPingReplyQueue == NULL)xPingReplyQueueCreate();usRequestSequenceNumber = FreeRTOS_SendPingRequest( ulIPAddress, 8, 100 / portTICK_PERIOD_MS );if( usRequestSequenceNumber == pdFAIL ){}else{if( xQueueReceive( xPingReplyQueue, &usReplySequenceNumber, 200 / portTICK_PERIOD_MS ) == pdPASS ){if( usRequestSequenceNumber == usReplySequenceNumber ){}}}return ulIPAddress;}BaseType_t IP_init( void ){  return FreeRTOS_IPInit( ucIPAddress, ucNetMask, ucGatewayAddress, ucDNSServerAddress, ucMACAddress ); } /*---------------------------DEBUG ONLY-------------------------------------*/ int lUDPLoggingPrintf( const char *fmt, ... ){   return 0;} void vApplicationIPNetworkEventHook( eIPCallbackEvent_t eNetworkEvent ){uint32_t ulIPAddress, ulNetMask, ulGatewayAddress, ulDNSServerAddress;char cBuffer[ 16 ];static BaseType_t xTasksAlreadyCreated = pdFALSE;FreeRTOS_printf( ( "vApplicationIPNetworkEventHook: event %ld\n", eNetworkEvent ) );if( eNetworkEvent == eNetworkUp ){if( xTasksAlreadyCreated == pdFALSE ){#if( mainCREATE_UDP_LOGGING_TASK == 1 ){vUDPLoggingTaskCreate();}#endif#if( ( mainCREATE_FTP_SERVER == 1 ) || ( mainCREATE_HTTP_SERVER == 1 ) ){/* Let the server work task now it can now create the servers. */xTaskNotifyGive( xServerWorkTaskHandle );}#endif#if( TCP_CLIENT == 1 ){//                vStartTCPEchoClientTasks_SingleTasks( mainECHO_CLIENT_TASK_STACK_SIZE, mainECHO_CLIENT_TASK_PRIORITY );}#endif#if( TCP_SERVER == 1 ){//                vStartSimpleTCPServerTasks( mainECHO_SERVER_STACK_SIZE, mainECHO_SERVER_TASK_PRIORITY );}#endif#if( mainCREATE_UDP_CLI_TASKS == 1 ){vRegisterSampleCLICommands();vRegisterTCPCLICommands();vStartUDPCommandInterpreterTask( mainUDP_CLI_TASK_STACK_SIZE, mainUDP_CLI_PORT_NUMBER, mainUDP_CLI_TASK_PRIORITY );}#endifxTasksAlreadyCreated = pdTRUE;}/* Print out the network configuration, which may have come from a DHCPserver. */FreeRTOS_GetAddressConfiguration( &ulIPAddress, &ulNetMask, &ulGatewayAddress, &ulDNSServerAddress );FreeRTOS_inet_ntoa( ulIPAddress, cBuffer );FreeRTOS_printf( ( "IP Address: %s\n", cBuffer ) );FreeRTOS_inet_ntoa( ulNetMask, cBuffer );FreeRTOS_printf( ( "Subnet Mask: %s\n", cBuffer ) );FreeRTOS_inet_ntoa( ulGatewayAddress, cBuffer );FreeRTOS_printf( ( "Gateway Address: %s\n", cBuffer ) );FreeRTOS_inet_ntoa( ulDNSServerAddress, cBuffer );FreeRTOS_printf( ( "DNS Server Address: %s\n", cBuffer ) );}}在main.c文件中引用头文件netInfoConfig.h,在main函数中调用初始化函数。参考如下代码。
#include "bsp_clock.h"#include "randomnum.h"#include "netInfoConfig.h"int main(void){HAL_NVIC_SetPriorityGrouping(NVIC_PRIORITYGROUP_4);CLOCLK_Init();RNG_init();                                           IP_init();vTaskStartScheduler();while(1);}
  • 编译工程,有14个错误。这里是要提供两个编译器内置的命令以取消结构体自动字节对齐,如果用的IDE是keil,那么默认编译器是armcc,需要pack_struct_start.h文件内添加#pragma pack(1),并在pack_struct_end.h文件内添加#pragma pack(),在FreeRTOS-TCP\include路径下创建这两个文件,并将代码添加进去。再次编译。
  • 工程编译,有216个错误,报错类型说明符的无效组合,在报错的结构体后面加上“;”。再次编译。
  • 工程编译,有35个错误,在FreeRTOS_IP.h文件中引用FreeRTOS.h和list.h头文件
  • 工程编译,有1个错误。注释掉phyHandling.c文件下eventLogging.h的引用。再次编译。
  • 工程编译,有1个错误,eventLogAdd()函数没被定义。注释掉相关引用。再次编译。无错误。
  • 修改stm32f4xx_hal_eth.c文件下函数HAL_ETH_IRQHandler()里的else if,改成if。参考如下代码。
void HAL_ETH_IRQHandler(ETH_HandleTypeDef *heth){/* Frame received */if (__HAL_ETH_DMA_GET_FLAG(heth, ETH_DMA_FLAG_R)){/* Receive complete callback */HAL_ETH_RxCpltCallback(heth);/* Clear the Eth DMA Rx IT pending bits */__HAL_ETH_DMA_CLEAR_IT(heth, ETH_DMA_IT_R);/* Set HAL State to Ready */heth->State = HAL_ETH_STATE_READY;/* Process Unlocked */__HAL_UNLOCK(heth);}/* Frame transmitted */if (__HAL_ETH_DMA_GET_FLAG(heth, ETH_DMA_FLAG_T)){/* Transfer complete callback */HAL_ETH_TxCpltCallback(heth);/* Clear the Eth DMA Tx IT pending bits */__HAL_ETH_DMA_CLEAR_IT(heth, ETH_DMA_IT_T);/* Set HAL State to Ready */heth->State = HAL_ETH_STATE_READY;/* Process Unlocked */__HAL_UNLOCK(heth);}/* Clear the interrupt flags */__HAL_ETH_DMA_CLEAR_IT(heth, ETH_DMA_IT_NIS);/* ETH DMA Error */if(__HAL_ETH_DMA_GET_FLAG(heth, ETH_DMA_FLAG_AIS)){/* Ethernet Error callback */HAL_ETH_ErrorCallback(heth);/* Clear the interrupt flags */__HAL_ETH_DMA_CLEAR_IT(heth, ETH_DMA_FLAG_AIS);/* Set HAL State to Ready */heth->State = HAL_ETH_STATE_READY;/* Process Unlocked */__HAL_UNLOCK(heth);}}
  • 屏蔽FreeRTOSConfig.h文件下的#define xPortSysTickHandler SysTick_Handler,创建prot.h文件,文件放在FreeRTOS\portable\RVDS\ARM_CM4F路径下。文件内声明xPortSysTickHandler()函数。
  • 修改bsp_clock.c文件,加入以下函数。
void SysTick_Handler(){HAL_IncTick();xPortSysTickHandler();}
  • 编译运行,无错误,下载到开发板,连接网线到路由器,登录路由器查看ip地址,ping 开发板IP,正常ping通。

本文为个人爱好所做,欢迎各位大佬指点,如有错误之处还请见谅。

stm32f407探索者+HAL库+FreeRTOS +FreeRTOS_TCP/IP 移植相关推荐

  1. STM32F407霸天虎HAL库学习笔记——串口发送

    STM32F407霸天虎HAL库学习笔记--串口收发 一.软件准备 二.硬件准备 三.CubeMX配置 四.Keil printf重写 main函数 五.实验效果 一.软件准备 软件准备 二.硬件准备 ...

  2. STM32F407霸天虎HAL库CubeMX学习笔记——DS18B20

    STM32F407霸天虎HAL库CubeMX学习笔记--DS18B20 一.软件准备 二.硬件准备 三.CubeMX配置 四.Keil printf重写 tim.c DS18B20.h DS18B20 ...

  3. STM32F407霸天虎HAL库学习笔记——使用ADC采集MQ135的数据并通过OLED显示

    STM32F407霸天虎HAL库学习笔记--使用ADC采集MQ135的数据并通过OLED显示 一.软件准备 二.硬件准备 三.CubeMX配置 四.Keil MQ135.c MQ135.h main函 ...

  4. 2.STM32F407之HAL库——星星点灯

    使用STM32CubeMX配置工程+MDKARM编写代码实现LED灯的控制 一.LED 二.配置STM32CubeMX 三.引脚配置属性详解 四.MDK设置+代码编写 五.下载验证   如何使用STM ...

  5. 使用SES 创建STM32 HAL库+FreeRTOS工程

    1.创建空白工程 2.添加FreeRTOS文件.HAL库文件 注意1:HAL库中默认使用SysTick定时器作为时间基准,FreeRTOS也要使用SysTick定时器产生系统的时间片,存在冲突. 解决 ...

  6. stm32移植freemodbusRTU(HAL库+Freertos)主机

    modbus主机源码下载 freemodbus主机源码下载地址 注:感谢armink提供的开源主机代码. 一.移植准备 1.cubemx配置基础工程,包括串口,freertos等. 在这里主要用到串口 ...

  7. 4.STM32F407之HAL库——按键

    使用STM32CubeMX配置工程+MDKARM编写代码实现按键控制 一.按键简介 二.STM32CubeMX配置 三.代码实现 一.按键简介   轻触式按键开关:按键开关是一种电子开关,属于电子元器 ...

  8. STM32 HAL库详细介绍

    自从ST公司推出HAL库来替代原有的标准库,HAL库开始慢慢的被广大STM32开发者所接受,现在已经在实际的项目开发中大量使用,HAL库使得项目的移植变得简单容易,但是对于初学者而言,刚开始接触有些晦 ...

  9. STM32F407 DP83848驱动调试过程总结(标准库到HAL库移植避坑指南)

    文章目录 移植到正点原子例程 下载ST最新F4平台例程适配 使用CubeMX从头开始 移植标准库上层函数到CubeMX初始化的HAL库 项目要从之前的STM32F107平台移植到STM32F407平台 ...

最新文章

  1. 集体智慧编程学习笔记——第一讲
  2. 042、用volume container 共享数据 (2019-03-05 周二)
  3. 你能分清多进程与多线程吗?
  4. 分治算法---汉诺塔
  5. 服务器实现_Linux C Http 文件服务器实现(含源码)
  6. python 系统编程
  7. 第一个shell脚本——修改配置文件
  8. openwrt下ipk生成过程及原理
  9. 零基础如何用平面设计排版软件PS进行布局构图
  10. C#实现程序一次打开两个窗口,两个窗口分别放置在两个屏幕
  11. 简明Jieba中文分词教程(分词、关键词提取、词性标注、计算位置)
  12. 鸿蒙真机运行调试步骤
  13. 如何高效学习的一点思考
  14. Grafana更改主题背景
  15. 苹果手机图片如何同步鸿蒙,教你将照片批量导入iOS设备
  16. 查询批量文件中关键数据方法--uedit32工具
  17. 利用FileReader和FileWriter完成一个文件拷贝功能
  18. 深红色房间(密室逃脱1)攻略
  19. linux课后总结第三章
  20. 第一个项目: 票务管理系统

热门文章

  1. 如何提升BERT在下游任务中的性能
  2. 今日头条广告投放不能忽略的落地页分析工具
  3. warning: xxx, needed by ..yyy, not found 问题可能解决办法
  4. 推箱子游戏破解方案的MATLAB代码实现
  5. SCR1(RISC-V)介绍
  6. 360日历精选弹窗如何关闭?
  7. 入职第一天,出事了!
  8. 人生苦短-常用必备的Python库清单
  9. 2018计算机二级c语言考试大纲,2018计算机office考试大纲
  10. “游戏发布 20 年之后,开发者喜提百万富翁!”