stm32f407探索者+HAL库+FreeRTOS +FreeRTOS_TCP/IP 移植

本文详细介绍了在STM32F4上移植FreeRTOS实时操作系统和TCP协议栈的过程,包括创建文件夹、添加源码、配置工程、实现随机数生成和网络接口配置等关键步骤。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

  • 在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 -------------------------> PA2

  ETH_MDC --------------------------> PC1

  ETH_RMII_REF_CLK------------------> PA1

  ETH_RMII_CRS_DV ------------------> PA7

  ETH_RMII_RXD0 --------------------> PC4

  ETH_RMII_RXD1 --------------------> PC5

  ETH_RMII_TX_EN -------------------> PG11

  ETH_RMII_TXD0 --------------------> PG13

  ETH_RMII_TXD1 --------------------> PG14

  ETH_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 __cplusplus

extern "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 )

#endif



static 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);

#endif



volatile 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;

#endif



static __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;

#endif



  while( ( 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 );

      }

      #endif



      prvEthernetUpdateConfig( 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 ] );

      }

      #endif



      if( 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 wants

      the 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 is

          contained 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 buffer

      will be accepted.  This can be done by making the buffers large enough to

      hold 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 can

          be 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 );

          }

      }

      #endif



      if( 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, it

              must 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 Network

              Buffer 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 resume

      reception. */

      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 the

          auto-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 the

          auto-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;

  #endif

  TickType_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 helpful

              while 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 helpful

                  while 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 num

UBaseType_t uxRand(){ 

    return (UBaseType_t) getRandomNum(); 

} 



//Use this name to request IP during DHCP call

const 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 );

          }

          #endif

          xTasksAlreadyCreated = pdTRUE;

      }



      /* Print out the network configuration, which may have come from a DHCP

      server. */

      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通。

 

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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值