打印
[STM32F4]

STM32F4+FreeRTOS+FreeRTosTcpIp移植教程

[复制链接]
1303|11
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
硬件是stm32F407最小系统(内带phy控制器),所以还需要一个phy芯片,选了DP83848这款不带协议栈的芯片。



选了一款淘宝上的以太网模块,内置芯片就是DP83848,只提供RMII接口(mac和phy的通信方式),自带50M振晶

(所以不需要stm32PA8口输出时钟源)。

两者硬件接口如下:







软件方面:



(1)需要完成stm32MAC控制器的初始化。(st库自带有)

(2)需要完成DP83848的驱动。(st库自带有)

(3)FreeRTos和Tcp/IP stack的移植。


使用特权

评论回复
沙发
木木guainv|  楼主 | 2021-7-1 11:31 | 只看该作者
(1)创建project

我选的st库是Keil.STM32F4xx_DFP.2.9.0.pack,里面就有关于以太网mac和phy的驱动程序,在keil里面创建工程并添加USER,

FreeRTOS和FreeRTOS-Plus-TCP三个文件夹,最后如下:



Device目录下是stm32外设的库,CMSIS Driver目录下就是关于mac和DP83848的库,这两个驱动的代码请自行结合里面(点击打开链接)

Referance目录下Ethernet interface查看,其实就是C文件里各有一个结构体,里面有一些函数作初始化,读,写等。如下所示



两个控制块里面的函数何时调用,怎么使用,将在后面TCP移植处说明。

这里说一下简单的配置:

1.打开新建工程Device目录下RTE_Device.h文件,查找RTE_ETH宏,修改成1。

2.因为我们要使用RMII接口,所以确保RTE_Device.h下,宏RTE_ETH_MII为0,宏RTE_ETH_RMII为1,并查看一下GPIO的配置,默认如下:



你没修改其他配置的话,请按照上图GPIO配置接好stm32和DP83848。


使用特权

评论回复
板凳
木木guainv|  楼主 | 2021-7-1 11:33 | 只看该作者
(2)接下来是freertos的移植:我下载的是FreeRTOSv9.0.0

1.首先看看FreeRTOSv9.0.0里面source目录下的东西:



至少需要tasks,queue,list才能构成freertos的内核,但是因为后面还要移植TCP/IP协议栈,所以其他部分也需要。portable目录里的东西和

硬件平台和编译软件有关,目录里面内容如下:



在这里,我们需要RVDS目录下ARM_CM4F文件夹内的port.c和portmacro.h和MemMang目录下的heap_4.c

2.然后,我们把这些.c和.h添加到工程中的FreeRTOS目录下,现在工程目录如下图所示:



3.最后,我们需要一个配置文件来配置我们FreeRTOS内核的功能,在工程FreeRTOS目录的include文件夹内添加FreeRTOSConfig.h文件,

并将下面代码粘贴进去。



/*
    FreeRTOS V9.0.0 - Copyright (C) 2016 Real Time Engineers Ltd.
    All rights reserved
    VISIT http://www.FreeRTOS.org TO ENSURE YOU ARE USING THE LATEST VERSION.
    This file is part of the FreeRTOS distribution.
    FreeRTOS is free software; you can redistribute it and/or modify it under
    the terms of the GNU General Public License (version 2) as published by the
    Free Software Foundation >>>> AND MODIFIED BY <<<< the FreeRTOS exception.
    ***************************************************************************
    >>!   NOTE: The modification to the GPL is included to allow you to     !<<
    >>!   distribute a combined work that includes FreeRTOS without being   !<<
    >>!   obliged to provide the source code for proprietary components     !<<
    >>!   outside of the FreeRTOS kernel.                                   !<<
    ***************************************************************************
    FreeRTOS is distributed in the hope that it will be useful, but WITHOUT ANY
    WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
    FOR A PARTICULAR PURPOSE.  Full license text is available on the following
    link: http://www.freertos.org/a00114.html
    ***************************************************************************
     *                                                                       *
     *    FreeRTOS provides completely free yet professionally developed,    *
     *    robust, strictly quality controlled, supported, and cross          *
     *    platform software that is more than just the market leader, it     *
     *    is the industry's de facto standard.                               *
     *                                                                       *
     *    Help yourself get started quickly while simultaneously helping     *
     *    to support the FreeRTOS project by purchasing a FreeRTOS           *
     *    tutorial book, reference manual, or both:                          *
     *    http://www.FreeRTOS.org/Documentation                              *
     *                                                                       *
    ***************************************************************************
    http://www.FreeRTOS.org/FAQHelp.html - Having a problem?  Start by reading
    the FAQ page "My application does not run, what could be wrong?".  Have you
    defined configASSERT()?
    http://www.FreeRTOS.org/support - In return for receiving this top quality
    embedded software for free we request you assist our global community by
    participating in the support forum.
    http://www.FreeRTOS.org/training - Investing in training allows your team to
    be as productive as possible as early as possible.  Now you can receive
    FreeRTOS training directly from Richard Barry, CEO of Real Time Engineers
    Ltd, and the world's leading authority on the world's leading RTOS.
    http://www.FreeRTOS.org/plus - A selection of FreeRTOS ecosystem products,
    including FreeRTOS+Trace - an indispensable productivity tool, a DOS
    compatible FAT file system, and our tiny thread aware UDP/IP stack.
    http://www.FreeRTOS.org/labs - Where new FreeRTOS products go to incubate.
    Come and try FreeRTOS+TCP, our new open source TCP/IP stack for FreeRTOS.
    http://www.OpenRTOS.com - Real Time Engineers ltd. license FreeRTOS to High
    Integrity Systems ltd. to sell under the OpenRTOS brand.  Low cost OpenRTOS
    licenses offer ticketed support, indemnification and commercial middleware.
    http://www.SafeRTOS.com - High Integrity Systems also provide a safety
    engineered and independently SIL3 certified version for use in safety and
    mission critical applications that require provable dependability.
    1 tab == 4 spaces!
*/


#ifndef FREERTOS_CONFIG_H
#define FREERTOS_CONFIG_H

/*-----------------------------------------------------------
* Application specific definitions.
*
* These definitions should be adjusted for your particular hardware and
* application requirements.
*
* THESE PARAMETERS ARE DESCRIBED WITHIN THE 'CONFIGURATION' SECTION OF THE
* FreeRTOS API DOCUMENTATION AVAILABLE ON THE FreeRTOS.org WEB SITE.
*
* See http://www.freertos.org/a00110.html.
*----------------------------------------------------------*/

/* Ensure stdint is only used by the compiler, and not the assembler. */
#ifdef __ICCARM__
        #include <stdint.h>
        extern uint32_t SystemCoreClock;
#endif

#define configUSE_PREEMPTION                        1
#define configUSE_IDLE_HOOK                                0
#define configUSE_TICK_HOOK                                0
#define configCPU_CLOCK_HZ                                ( (uint32_t) 168000000)
#define configTICK_RATE_HZ                                ( ( TickType_t ) 250 )
#define configMAX_PRIORITIES                        ( 5 )
#define configMINIMAL_STACK_SIZE                ( ( unsigned short ) 130 )
#define configTOTAL_HEAP_SIZE                        ( ( size_t ) ( 50 * 1024 ) )
#define configMAX_TASK_NAME_LEN                        ( 16 )
#define configUSE_TRACE_FACILITY                0
#define configUSE_16_BIT_TICKS                        0
#define configIDLE_SHOULD_YIELD                        1
#define configUSE_MUTEXES                                1
//#define configQUEUE_REGISTRY_SIZE                8
//#define configCHECK_FOR_STACK_OVERFLOW        0
//#define configUSE_RECURSIVE_MUTEXES                1
//#define configUSE_MALLOC_FAILED_HOOK        0
//#define configUSE_APPLICATION_TASK_TAG        0
#define configUSE_COUNTING_SEMAPHORES        1
//#define configGENERATE_RUN_TIME_STATS        0

/* Co-routine definitions. */
#define configUSE_CO_ROUTINES                 0
#define configMAX_CO_ROUTINE_PRIORITIES ( 2 )


/* Set the following definitions to 1 to include the API function, or zero
to exclude the API function. */
#define INCLUDE_vTaskPrioritySet                1
#define INCLUDE_uxTaskPriorityGet                1
#define INCLUDE_vTaskDelete                                1
#define INCLUDE_vTaskCleanUpResources        1
#define INCLUDE_vTaskSuspend                        1
#define INCLUDE_vTaskDelayUntil                        1
#define INCLUDE_vTaskDelay                                1

#define INCLUDE_xEventGroupSetBitsFromISR                                                1
#define INCLUDE_xTimerPendFunctionCall                                                        1

/* Cortex-M specific definitions. */
#ifdef __NVIC_PRIO_BITS
        /* __BVIC_PRIO_BITS will be specified when CMSIS is being used. */
        #define configPRIO_BITS                       __NVIC_PRIO_BITS
#else
        #define configPRIO_BITS                       4        /* 15 priority levels */
#endif

/* The lowest interrupt priority that can be used in a call to a "set priority"
function. */
#define configLIBRARY_LOWEST_INTERRUPT_PRIORITY                        0xf

/* The highest interrupt priority that can be used by any interrupt service
routine that makes calls to interrupt safe FreeRTOS API functions.  DO NOT CALL
INTERRUPT SAFE FREERTOS API FUNCTIONS FROM ANY INTERRUPT THAT HAS A HIGHER
PRIORITY THAN THIS! (higher priorities are lower numeric values. */
#define configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY        5

/* Interrupt priorities used by the kernel port layer itself.  These are generic
to all Cortex-M ports, and do not rely on any particular library functions. */
#define configKERNEL_INTERRUPT_PRIORITY                 ( configLIBRARY_LOWEST_INTERRUPT_PRIORITY << (8 - configPRIO_BITS) )
/* !!!! configMAX_SYSCALL_INTERRUPT_PRIORITY must not be set to zero !!!!
See http://www.FreeRTOS.org/RTOS-Cortex-M3-M4.html. */
#define configMAX_SYSCALL_INTERRUPT_PRIORITY         ( configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY << (8 - configPRIO_BITS) )
       
/* Normal assert() semantics without relying on the provision of an assert.h
header file. */
//#define configASSERT( x ) if( ( x ) == 0 ) { taskDISABLE_INTERRUPTS(); for( ;; ); }       

/* used by software timers */
#define configUSE_TIMERS          1
#define configSUPPORT_DYNAMIC_ALLOCATION 1
#define configTIMER_TASK_PRIORITY  2
#define configTIMER_QUEUE_LENGTH   10
#define configTIMER_TASK_STACK_DEPTH        configMINIMAL_STACK_SIZE
/* used by software timers */

       
/* Definitions that map the FreeRTOS port interrupt handlers to their CMSIS
standard names. */
#define vPortSVCHandler SVC_Handler
#define xPortPendSVHandler PendSV_Handler
#define xPortSysTickHandler SysTick_Handler

#endif /* FREERTOS_CONFIG_H */



OK,到现在,FreeRTOS已经可以在STM32上跑起来了。你自己随便写个LED灯的代码测试一下吧。FreeRTOS的API请参考这里。




使用特权

评论回复
地板
木木guainv|  楼主 | 2021-7-1 11:37 | 只看该作者
(3)最后是FreeRTOS自带的TCP/IP协议栈的移植:

首先看看FreeRTOS-Plus-Tcp目录下的文件:



protocols目录下为一些上层协议(Http,FTP等)暂时先不用,portable目录下的东西和上面内核代码一样,与硬件平台和编译软件有关,打开portable目录,显示如下:



BufferManagement目录下为以太网buffer管理方案,在此选择BufferAllocation_2.c(动态分配内存方案),更多详细信息请点击这里。

Compiler目录下的东西和编译器有关,这里是要提供两个编译器内置的命令以取消结构体自动字节对齐,如果你用的IDE是keil,那么默认编译器是armcc,你需要在Compiler目录下的pack_struct_start.h文件内添加#pragma pack(1),并在pack_struct_end.h文件内添加#pragma pack(),最后如下图所示:






使用特权

评论回复
5
木木guainv|  楼主 | 2021-7-1 11:38 | 只看该作者
NetworkInterface目录下的NetworkInterface.c文件和硬件有关,需要提供驱动的初始化,读,写等方法给FreeRTOS的TCP/IP协议栈调用,配置方法请参考这里。如果你不想花时间看,那就直接复制下面我写的,我并没有去实现FreeRTOS官方推荐的zero copy方法,实现的是另一种。具体如下:



/*
* Some constants, hardware definitions and comments taken from ST's HAL driver
* library, COPYRIGHT(c) 2015 STMicroelectronics.
*/

/*
* FreeRTOS+TCP Labs Build 160919 (C) 2016 Real Time Engineers ltd.
* Authors include Hein Tibosch and Richard Barry
*
*******************************************************************************
***** NOTE ******* NOTE ******* NOTE ******* NOTE ******* NOTE ******* NOTE ***
***                                                                         ***
***                                                                         ***
***   FREERTOS+TCP IS STILL IN THE LAB (mainly because the FTP and HTTP     ***
***   demos have a dependency on FreeRTOS+FAT, which is only in the Labs    ***
***   download):                                                            ***
***                                                                         ***
***   FreeRTOS+TCP is functional and has been used in commercial products   ***
***   for some time.  Be aware however that we are still refining its       ***
***   design, the source code does not yet quite conform to the strict      ***
***   coding and style standards mandated by Real Time Engineers ltd., and  ***
***   the documentation and testing is not necessarily complete.            ***
***                                                                         ***
***   PLEASE REPORT EXPERIENCES USING THE SUPPORT RESOURCES FOUND ON THE    ***
***   URL: http://www.FreeRTOS.org/contact  Active early adopters may, at   ***
***   the sole discretion of Real Time Engineers Ltd., be offered versions  ***
***   under a license other than that described below.                      ***
***                                                                         ***
***                                                                         ***
***** NOTE ******* NOTE ******* NOTE ******* NOTE ******* NOTE ******* NOTE ***
*******************************************************************************
*
* FreeRTOS+TCP can be used under two different free open source licenses.  The
* license that applies is dependent on the processor on which FreeRTOS+TCP is
* executed, as follows:
*
* If FreeRTOS+TCP is executed on one of the processors listed under the Special
* License Arrangements heading of the FreeRTOS+TCP license information web
* page, then it can be used under the terms of the FreeRTOS Open Source
* License.  If FreeRTOS+TCP is used on any other processor, then it can be used
* under the terms of the GNU General Public License V2.  Links to the relevant
* licenses follow:
*
* The FreeRTOS+TCP License Information Page: http://www.FreeRTOS.org/tcp_license
* The FreeRTOS Open Source License: http://www.FreeRTOS.org/license
* The GNU General Public License Version 2: http://www.FreeRTOS.org/gpl-2.0.txt
*
* FreeRTOS+TCP is distributed in the hope that it will be useful.  You cannot
* use FreeRTOS+TCP unless you agree that you use the software 'as is'.
* FreeRTOS+TCP is provided WITHOUT ANY WARRANTY; without even the implied
* warranties of NON-INFRINGEMENT, MERCHANTABILITY or FITNESS FOR A PARTICULAR
* PURPOSE. Real Time Engineers Ltd. disclaims all conditions and terms, be they
* implied, expressed, or statutory.
*
* 1 tab == 4 spaces!
*
* http://www.FreeRTOS.org
* http://www.FreeRTOS.org/plus
* http://www.FreeRTOS.org/labs
*
*/

/* Standard includes. */
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

/* FreeRTOS includes. */
#include "FreeRTOS.h"
#include "task.h"
#include "queue.h"
#include "semphr.h"

/* FreeRTOS+TCP includes. */
#include "FreeRTOS_IP.h"
#include "FreeRTOS_Sockets.h"
#include "FreeRTOS_IP_Private.h"
#include "NetworkBufferManagement.h"
#include "NetworkInterface.h"

#include "Driver_ETH.h"
#include "Driver_ETH_MAC.h"
#include "Driver_ETH_PHY.h"

static void receiveHandlerTask( void *pvParameters );
static TaskHandle_t receiveHandler = NULL;

static ARM_ETH_MAC_ADDR   own_mac_address ;//device mac adress stores here. MSB first
static ARM_DRIVER_ETH_MAC *mac;
static ARM_ETH_MAC_CAPABILITIES  capabilities;

extern ARM_DRIVER_ETH_MAC Driver_ETH_MAC0;
extern ARM_DRIVER_ETH_PHY ARM_Driver_ETH_PHY_(0);
#define Driver_ETH_PHY0         ARM_Driver_ETH_PHY_(0)

/*callback function for ARM_ETH_MAC_SignalEvent_t*/
void ethernet_mac_notify (uint32_t event)  {
  switch (event)  {
     case ARM_ETH_MAC_EVENT_RX_FRAME:
                         /*received frame,call receive fuction*/
                        //led1_toggle();
                        xTaskNotifyGive( receiveHandler );
                 break;
                 
                 case ARM_ETH_MAC_EVENT_TX_FRAME:
                         /* deliver finished */
                 break;
                 
                 case ARM_ETH_MAC_EVENT_WAKEUP:
                 break;
                 
                 case ARM_ETH_MAC_EVENT_TIMER_ALARM:
                         /* do nothing */
                        break;
  }  
}

/* init the mac */
int32_t macIntialise(void){
        own_mac_address.b[0] = configMAC_ADDR0;
        own_mac_address.b[1] = configMAC_ADDR1;
        own_mac_address.b[2] = configMAC_ADDR2;
        own_mac_address.b[3] = configMAC_ADDR3;
        own_mac_address.b[4] = configMAC_ADDR4;
        own_mac_address.b[5] = configMAC_ADDR5;
       
        mac = &Driver_ETH_MAC0;
  capabilities = mac->GetCapabilities ();
         
       
       
        if(mac->Initialize (ethernet_mac_notify) == ARM_DRIVER_OK && mac->PowerControl (ARM_POWER_FULL) == ARM_DRIVER_OK){
               
                if (capabilities.mac_address == 0)  {
                        // populate own_mac_address with the address to use.-----the fact situation
                        mac->SetMacAddress(&own_mac_address);
                }
                else {
                        mac->GetMacAddress(&own_mac_address);
                }
               
                return ARM_DRIVER_OK;
        }
        else{
                return ARM_DRIVER_ERROR;
        }
}

/* init the phy */
int32_t phyIntialise(void){
        int32_t state = ARM_DRIVER_OK;
       
        /* link the mac and phy through MAC0.PHY_Read() and MAC0.PHY_write */
        if(Driver_ETH_PHY0.Initialize(Driver_ETH_MAC0.PHY_Read,Driver_ETH_MAC0.PHY_Write)!= ARM_DRIVER_OK){
                state = ARM_DRIVER_ERROR;
                return state;
        }
       
        /* power on */
        if(Driver_ETH_PHY0.PowerControl(ARM_POWER_FULL)!=ARM_DRIVER_OK){
                state = ARM_DRIVER_ERROR;
                return state;
        }
       
        /* set RMII interface */
        if(Driver_ETH_PHY0.SetInterface (capabilities.media_interface)!=ARM_DRIVER_OK){
                state = ARM_DRIVER_ERROR;
                return state;
        }
       
        /* set mode */
        if(Driver_ETH_PHY0.SetMode (ARM_ETH_PHY_AUTO_NEGOTIATE)!=ARM_DRIVER_OK){
                state = ARM_DRIVER_ERROR;
                return state;
        }
       
        return state;
}

/*init the mac and phy*/
BaseType_t xNetworkInterfaceInitialise( void )
{
        static ARM_ETH_LINK_INFO info;
        BaseType_t state = pdFALSE;
        if(state == pdFALSE){
                state = xTaskCreate( receiveHandlerTask, "receiveHandlerTask", 1000, NULL, 1, &receiveHandler );
        }
       
        if(macIntialise() == ARM_DRIVER_OK  && phyIntialise() ==ARM_DRIVER_OK){
                ARM_ETH_LINK_STATE link = Driver_ETH_PHY0.GetLinkState ();
               
                while(link != ARM_ETH_LINK_UP){
                        link = Driver_ETH_PHY0.GetLinkState ();
                }
               
                info = Driver_ETH_PHY0.GetLinkInfo ();
    mac->Control(ARM_ETH_MAC_CONFIGURE,
                 info.speed  << ARM_ETH_MAC_SPEED_Pos  |
                 info.duplex << ARM_ETH_MAC_DUPLEX_Pos |
                 ARM_ETH_MAC_ADDRESS_BROADCAST);
    mac->Control(ARM_ETH_MAC_CONTROL_TX, 1);
    mac->Control(ARM_ETH_MAC_CONTROL_RX, 1);
                return pdPASS;
        }
        else{
                //error
                return pdFALSE;
        }
}
/*-----------------------------------------------------------*/


/* send tcp/ip buffer to mac buffer */
static void sendData(uint8_t *pucEthernetBuffer,size_t xDataLength){
        if(mac->SendFrame(pucEthernetBuffer,xDataLength,ARM_ETH_MAC_TX_FRAME_EVENT|ARM_ETH_MAC_TX_FRAME_TIMESTAMP) == ARM_DRIVER_OK){
                //success
        }
        else{
                //error
        }
}


/* send frame */
#if ( ipconfigZERO_COPY_TX_DRIVER == 0)
/*the Simple network interfaces ,just use Ethernet peripheral driver library functions to copy
data from the FreeRTOS+TCP buffer into the peripheral driver's own buffer.*/
BaseType_t xNetworkInterfaceOutput( NetworkBufferDescriptor_t * const pxDescriptor,BaseType_t xReleaseAfterSend ){
        /* Simple network interfaces (as opposed to more efficient zero copy network
    interfaces) just use Ethernet peripheral driver library functions to copy
    data from the FreeRTOS+TCP buffer into the peripheral driver's own buffer.
    This example assumes SendData() is a peripheral driver library function that
    takes a pointer to the start of the data to be sent and the length of the
    data to be sent as two separate parameters.  The start of the data is located
    by pxDescriptor->pucEthernetBuffer.  The length of the data is located
    by pxDescriptor->xDataLength. */
    sendData( pxDescriptor->pucEthernetBuffer, pxDescriptor->xDataLength );

    /* Call the standard trace macro to log the send event. */
    iptraceNETWORK_INTERFACE_TRANSMIT();

    if( xReleaseAfterSend != pdFALSE )
    {
        /* It is assumed SendData() copies the data out of the FreeRTOS+TCP Ethernet
        buffer.  The Ethernet buffer is therefore no longer needed, and must be
        freed for re-use. */
        vReleaseNetworkBufferAndDescriptor( pxDescriptor );
    }

    return pdTRUE;
}
#else
/*zero copy method here*/

#endif
/*-----------------------------------------------------------*/

/*receive data func , will be notify after ARM_ETH_MAC_EVENT_RX_FRAME event*/
#if (ipconfigZERO_COPY_RX_DRIVER==0)
static void receiveHandlerTask( void *pvParameters ){
        NetworkBufferDescriptor_t *receiveBufferDescriptor;
        size_t xBytesReceived;
        /* Used to indicate that xSendEventStructToIPTask() is being called becauseof an Ethernet receive event. */
        IPStackEvent_t xRxEvent;
       
        while(1){
                /* Wait for the Ethernet MAC interrupt to indicate that another packet
       has been received.  The task notification is used in a similar way to a
       counting semaphore to count Rx events, but is a lot more efficient than
       a semaphore. */
                        ulTaskNotifyTake( pdFALSE, portMAX_DELAY );
               
                /* See how much data was received.  Here it is assumed ReceiveSize() is
       a peripheral driver function that returns the number of bytes in the
       received Ethernet frame. */
       xBytesReceived = mac->GetRxFrameSize();
               
                if( xBytesReceived > 0 ){
                        /* Allocate a network buffer descriptor that points to a buffer
       large enough to hold the received frame.  As this is the simple
       rather than efficient example the received data will just be copied
       into this buffer. */
       receiveBufferDescriptor = pxGetNetworkBufferWithDescriptor( xBytesReceived, 0 );
                         if( receiveBufferDescriptor != NULL ){
                                        /* pxBufferDescriptor->pucEthernetBuffer now points to an Ethernet
          buffer large enough to hold the received data.  Copy the
          received data into pcNetworkBuffer->pucEthernetBuffer.  Here it
          is assumed ReceiveData() is a peripheral driver function that
          copies the received data into a buffer passed in as the function's
          parameter.  Remember! While is is a simple robust technique -
          it is not efficient.  An example that uses a zero copy technique
          is provided further down this page. */
          mac->ReadFrame(receiveBufferDescriptor->pucEthernetBuffer,xBytesReceived);
                                        receiveBufferDescriptor->xDataLength = xBytesReceived;
                                 
                                        /* See if the data contained in the received Ethernet frame needs
          to be processed.  NOTE! It is preferable to do this in
          the interrupt service routine itself, which would remove the need
          to unblock this task for packets that don't need processing. */
          if( eConsiderFrameForProcessing( receiveBufferDescriptor->pucEthernetBuffer )== eProcessBuffer ){
                                                        /* The event about to be sent to the TCP/IP is an Rx event. */
              xRxEvent.eEventType = eNetworkRxEvent;

              /* pvData is used to point to the network buffer descriptor that
              now references the received data. */
              xRxEvent.pvData = ( void * ) receiveBufferDescriptor;
                                                       
                                                        /* Send the data to the TCP/IP stack. */
              if( xSendEventStructToIPTask( &xRxEvent, 0 ) == pdFALSE ){
                                                                        /* The buffer could not be sent to the IP task so the buffer must be released. */
                  vReleaseNetworkBufferAndDescriptor( receiveBufferDescriptor );

                  /* Make a call to the standard trace macro to log the occurrence. */
                  iptraceETHERNET_RX_EVENT_LOST();
                                                        }else{
                                                                        /* The message was successfully sent to the TCP/IP stack.
                                                                        Call the standard trace macro to log the occurrence. */
                  iptraceNETWORK_INTERFACE_RECEIVE();                                       
                                                        }
                                        }else{
                   /* The Ethernet frame can be dropped, but the Ethernet buffer
                   must be released. */
                   vReleaseNetworkBufferAndDescriptor( receiveBufferDescriptor );
          }
                                                               
                         }else{
                                        /* The event was lost because a network buffer was not available.
          Call the standard trace macro to log the occurrence. */
          iptraceETHERNET_RX_EVENT_LOST();
                         }
                }
        }
}
#else
/*zero copy method here*/

#endif


使用特权

评论回复
6
木木guainv|  楼主 | 2021-7-1 11:38 | 只看该作者
然后,NetworkInterface.h里面内容如下:



#ifndef NETWORK_INTERFACE_H
#define NETWORK_INTERFACE_H

#ifdef __cplusplus
extern "C" {
#endif

       
/* NOTE PUBLIC API FUNCTIONS. */
BaseType_t xNetworkInterfaceInitialise( void );
BaseType_t xNetworkInterfaceOutput( NetworkBufferDescriptor_t * const pxNetworkBuffer, BaseType_t xReleaseAfterSend );
void vNetworkInterfaceAllocateRAMToBuffers( NetworkBufferDescriptor_t pxNetworkBuffers[ ipconfigNUM_NETWORK_BUFFER_DESCRIPTORS ] );
       
int32_t        macIntialise(void);
int32_t phyIntialise(void);

#ifdef __cplusplus
} // extern "C"
#endif

#endif /* NETWORK_INTERFACE_H */


使用特权

评论回复
7
木木guainv|  楼主 | 2021-7-1 11:38 | 只看该作者
最后,和FreeRTOS内核类似,需要提供一个配置文件,名为FreeRTOSIPConfig.h,内容如下:



/*
    FreeRTOS V9.0.0 - Copyright (C) 2016 Real Time Engineers Ltd.
    All rights reserved
    VISIT http://www.FreeRTOS.org TO ENSURE YOU ARE USING THE LATEST VERSION.
    This file is part of the FreeRTOS distribution.
    FreeRTOS is free software; you can redistribute it and/or modify it under
    the terms of the GNU General Public License (version 2) as published by the
    Free Software Foundation >>!AND MODIFIED BY!<< the FreeRTOS exception.
    ***************************************************************************
    >>!   NOTE: The modification to the GPL is included to allow you to     !<<
    >>!   distribute a combined work that includes FreeRTOS without being   !<<
    >>!   obliged to provide the source code for proprietary components     !<<
    >>!   outside of the FreeRTOS kernel.                                   !<<
    ***************************************************************************
    FreeRTOS is distributed in the hope that it will be useful, but WITHOUT ANY
    WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
    FOR A PARTICULAR PURPOSE.  Full license text is available on the following
    link: http://www.freertos.org/a00114.html
    ***************************************************************************
     *                                                                       *
     *    FreeRTOS provides completely free yet professionally developed,    *
     *    robust, strictly quality controlled, supported, and cross          *
     *    platform software that is more than just the market leader, it     *
     *    is the industry's de facto standard.                               *
     *                                                                       *
     *    Help yourself get started quickly while simultaneously helping     *
     *    to support the FreeRTOS project by purchasing a FreeRTOS           *
     *    tutorial book, reference manual, or both:                          *
     *    http://www.FreeRTOS.org/Documentation                              *
     *                                                                       *
    ***************************************************************************
    http://www.FreeRTOS.org/FAQHelp.html - Having a problem?  Start by reading
    the FAQ page "My application does not run, what could be wrong?".  Have you
    defined configASSERT()?
    http://www.FreeRTOS.org/support - In return for receiving this top quality
    embedded software for free we request you assist our global community by
    participating in the support forum.
    http://www.FreeRTOS.org/training - Investing in training allows your team to
    be as productive as possible as early as possible.  Now you can receive
    FreeRTOS training directly from Richard Barry, CEO of Real Time Engineers
    Ltd, and the world's leading authority on the world's leading RTOS.
    http://www.FreeRTOS.org/plus - A selection of FreeRTOS ecosystem products,
    including FreeRTOS+Trace - an indispensable productivity tool, a DOS
    compatible FAT file system, and our tiny thread aware UDP/IP stack.
    http://www.FreeRTOS.org/labs - Where new FreeRTOS products go to incubate.
    Come and try FreeRTOS+TCP, our new open source TCP/IP stack for FreeRTOS.
    http://www.OpenRTOS.com - Real Time Engineers ltd. license FreeRTOS to High
    Integrity Systems ltd. to sell under the OpenRTOS brand.  Low cost OpenRTOS
    licenses offer ticketed support, indemnification and commercial middleware.
    http://www.SafeRTOS.com - High Integrity Systems also provide a safety
    engineered and independently SIL3 certified version for use in safety and
    mission critical applications that require provable dependability.
    1 tab == 4 spaces!
*/


/*****************************************************************************
*
* See the following URL for configuration information.
* http://www.freertos.org/FreeRTOS-Plus/FreeRTOS_Plus_TCP/TCP_IP_Configuration.html
*
*****************************************************************************/

#ifndef FREERTOS_IP_CONFIG_H
#define FREERTOS_IP_CONFIG_H

#ifdef __cplusplus
extern "C" {
#endif

#include "FreeRTOS.h"       

/* Define the byte order of the target MCU (the MCU FreeRTOS+TCP is executing
on).  Valid options are pdFREERTOS_BIG_ENDIAN and pdFREERTOS_LITTLE_ENDIAN. */
#define ipconfigBYTE_ORDER pdFREERTOS_LITTLE_ENDIAN

/* The checksums will be checked and calculated by the STM32F4x ETH peripheral. */
#define ipconfigDRIVER_INCLUDED_TX_IP_CHECKSUM                ( 1 )
#define ipconfigDRIVER_INCLUDED_RX_IP_CHECKSUM                ( 1 )

/* Several API's will block until the result is known, or the action has been
performed, for example FreeRTOS_send() and FreeRTOS_recv().  The timeouts can be
set per socket, using setsockopt().  If not set, the times below will be
used as defaults. */
#define ipconfigSOCK_DEFAULT_RECEIVE_BLOCK_TIME        ( 5000 )
#define        ipconfigSOCK_DEFAULT_SEND_BLOCK_TIME        ( 5000 )

#define ipconfigZERO_COPY_RX_DRIVER                        ( 0 )
#define ipconfigZERO_COPY_TX_DRIVER                        ( 0 )

/* Include support for LLMNR: Link-local Multicast Name Resolution
(non-Microsoft) */
#define ipconfigUSE_LLMNR                                        ( 1 )

/* Include support for NBNS: NetBIOS Name Service (Microsoft) */
#define ipconfigUSE_NBNS                                        ( 0 )

/* Include support for DNS caching.  For TCP, having a small DNS cache is very
useful.  When a cache is present, ipconfigDNS_REQUEST_ATTEMPTS can be kept low
and also DNS may use small timeouts.  If a DNS reply comes in after the DNS
socket has been destroyed, the result will be stored into the cache.  The next
call to FreeRTOS_gethostbyname() will return immediately, without even creating
a socket. */
#define ipconfigUSE_DNS_CACHE                                ( 1 )
#define ipconfigDNS_CACHE_NAME_LENGTH                ( 16 )
#define ipconfigDNS_CACHE_ENTRIES                        ( 4 )
#define ipconfigDNS_REQUEST_ATTEMPTS                ( 4 )

/* The IP stack executes it its own task (although any application task can make
use of its services through the published sockets API). ipconfigIP_TASK_PRIORITY
sets the priority of the task that executes the IP stack.  The priority is a
standard FreeRTOS task priority so can take any value from 0 (the lowest
priority) to (configMAX_PRIORITIES - 1) (the highest priority).
configMAX_PRIORITIES is a standard FreeRTOS configuration parameter defined in
FreeRTOSConfig.h, not FreeRTOSIPConfig.h. Consideration needs to be given as to
the priority assigned to the task executing the IP stack relative to the
priority assigned to tasks that use the IP stack. */
#define ipconfigIP_TASK_PRIORITY                        ( configMAX_PRIORITIES - 2 )

/* The size, in words (not bytes), of the stack allocated to the FreeRTOS+TCP
task.  This setting is less important when the FreeRTOS Win32 simulator is used
as the Win32 simulator only stores a fixed amount of information on the task
stack.  FreeRTOS includes optional stack overflow detection, see:
http://www.freertos.org/Stacks-and-stack-overflow-checking.html */
#define ipconfigIP_TASK_STACK_SIZE_WORDS        ( configMINIMAL_STACK_SIZE * 5 )

/* ipconfigRAND32() is called by the IP stack to generate random numbers for
things such as a DHCP transaction number or initial sequence number.  Random
number generation is performed via this macro to allow applications to use their
own random number generation method.  For example, it might be possible to
generate a random number by sampling noise on an analogue input. */
extern UBaseType_t uxRand(void);
#define ipconfigRAND32()        uxRand()

/* If ipconfigUSE_NETWORK_EVENT_HOOK is set to 1 then FreeRTOS+TCP will call the
network event hook at the appropriate times.  If ipconfigUSE_NETWORK_EVENT_HOOK
is not set to 1 then the network event hook will never be called.  See
http://www.FreeRTOS.org/FreeRTOS-Plus/FreeRTOS_Plus_UDP/API/vApplicationIPNetworkEventHook.shtml
*/
#define ipconfigUSE_NETWORK_EVENT_HOOK 1

/* Sockets have a send block time attribute.  If FreeRTOS_sendto() is called but
a network buffer cannot be obtained then the calling task is held in the Blocked
state (so other tasks can continue to executed) until either a network buffer
becomes available or the send block time expires.  If the send block time expires
then the send operation is aborted.  The maximum allowable send block time is
capped to the value set by ipconfigMAX_SEND_BLOCK_TIME_TICKS.  Capping the
maximum allowable send block time prevents prevents a deadlock occurring when
all the network buffers are in use and the tasks that process (and subsequently
free) the network buffers are themselves blocked waiting for a network buffer.
ipconfigMAX_SEND_BLOCK_TIME_TICKS is specified in RTOS ticks.  A time in
milliseconds can be converted to a time in ticks by dividing the time in
milliseconds by portTICK_PERIOD_MS. */
#define ipconfigUDP_MAX_SEND_BLOCK_TIME_TICKS ( 5000 / portTICK_PERIOD_MS )

/* If ipconfigUSE_DHCP is 1 then FreeRTOS+TCP will attempt to retrieve an IP
address, netmask, DNS server address and gateway address from a DHCP server.  If
ipconfigUSE_DHCP is 0 then FreeRTOS+TCP will use a static IP address.  The
stack will revert to using the static IP address even when ipconfigUSE_DHCP is
set to 1 if a valid configuration cannot be obtained from a DHCP server for any
reason.  The static configuration used is that passed into the stack by the
FreeRTOS_IPInit() function call. */
#define ipconfigUSE_DHCP                                1
#define ipconfigDHCP_REGISTER_HOSTNAME        1
#define ipconfigDHCP_USES_UNICAST       1

/* When ipconfigUSE_DHCP is set to 1, DHCP requests will be sent out at
increasing time intervals until either a reply is received from a DHCP server
and accepted, or the interval between transmissions reaches
ipconfigMAXIMUM_DISCOVER_TX_PERIOD.  The IP stack will revert to using the
static IP address passed as a parameter to FreeRTOS_IPInit() if the
re-transmission time interval reaches ipconfigMAXIMUM_DISCOVER_TX_PERIOD without
a DHCP reply being received. */
#define ipconfigMAXIMUM_DISCOVER_TX_PERIOD                ( pdMS_TO_TICKS( 30000 ) )

/* The ARP cache is a table that maps IP addresses to MAC addresses.  The IP
stack can only send a UDP message to a remove IP address if it knowns the MAC
address associated with the IP address, or the MAC address of the router used to
contact the remote IP address.  When a UDP message is received from a remote IP
address the MAC address and IP address are added to the ARP cache.  When a UDP
message is sent to a remote IP address that does not already appear in the ARP
cache then the UDP message is replaced by a ARP message that solicits the
required MAC address information.  ipconfigARP_CACHE_ENTRIES defines the maximum
number of entries that can exist in the ARP table at any one time. */
#define ipconfigARP_CACHE_ENTRIES                6

/* ARP requests that do not result in an ARP response will be re-transmitted a
maximum of ipconfigMAX_ARP_RETRANSMISSIONS times before the ARP request is
aborted. */
#define ipconfigMAX_ARP_RETRANSMISSIONS ( 5 )

/* ipconfigMAX_ARP_AGE defines the maximum time between an entry in the ARP
table being created or refreshed and the entry being removed because it is stale.
New ARP requests are sent for ARP cache entries that are nearing their maximum
age.  ipconfigMAX_ARP_AGE is specified in tens of seconds, so a value of 150 is
equal to 1500 seconds (or 25 minutes). */
#define ipconfigMAX_ARP_AGE                        150

/* Implementing FreeRTOS_inet_addr() necessitates the use of string handling
routines, which are relatively large.  To save code space the full
FreeRTOS_inet_addr() implementation is made optional, and a smaller and faster
alternative called FreeRTOS_inet_addr_quick() is provided.  FreeRTOS_inet_addr()
takes an IP in decimal dot format (for example, "192.168.0.1") as its parameter.
FreeRTOS_inet_addr_quick() takes an IP address as four separate numerical octets
(for example, 192, 168, 0, 1) as its parameters.  If
ipconfigINCLUDE_FULL_INET_ADDR is set to 1 then both FreeRTOS_inet_addr() and
FreeRTOS_indet_addr_quick() are available.  If ipconfigINCLUDE_FULL_INET_ADDR is
not set to 1 then only FreeRTOS_indet_addr_quick() is available. */
#define ipconfigINCLUDE_FULL_INET_ADDR        1

/* ipconfigNUM_NETWORK_BUFFER_DESCRIPTORS defines the total number of network buffer that
are available to the IP stack.  The total number of network buffers is limited
to ensure the total amount of RAM that can be consumed by the IP stack is capped
to a pre-determinable value. */
#if( ipconfigZERO_COPY_RX_DRIVER != 0 )
        /* _HT_ Actually we should know the value of 'configNUM_RX_DESCRIPTORS' here. */
        #define ipconfigNUM_NETWORK_BUFFER_DESCRIPTORS                ( 25 + 6 )
#else
        #define ipconfigNUM_NETWORK_BUFFER_DESCRIPTORS                25
#endif

/* A FreeRTOS queue is used to send events from application tasks to the IP
stack.  ipconfigEVENT_QUEUE_LENGTH sets the maximum number of events that can
be queued for processing at any one time.  The event queue must be a minimum of
5 greater than the total number of network buffers. */
#define ipconfigEVENT_QUEUE_LENGTH                ( ipconfigNUM_NETWORK_BUFFER_DESCRIPTORS + 5 )

/* The address of a socket is the combination of its IP address and its port
number.  FreeRTOS_bind() is used to manually allocate a port number to a socket
(to 'bind' the socket to a port), but manual binding is not normally necessary
for client sockets (those sockets that initiate outgoing connections rather than
wait for incoming connections on a known port number).  If
ipconfigALLOW_SOCKET_SEND_WITHOUT_BIND is set to 1 then calling
FreeRTOS_sendto() on a socket that has not yet been bound will result in the IP
stack automatically binding the socket to a port number from the range
socketAUTO_PORT_ALLOCATION_START_NUMBER to 0xffff.  If
ipconfigALLOW_SOCKET_SEND_WITHOUT_BIND is set to 0 then calling FreeRTOS_sendto()
on a socket that has not yet been bound will result in the send operation being
aborted. */
#define ipconfigALLOW_SOCKET_SEND_WITHOUT_BIND 1

/* Defines the Time To Live (TTL) values used in outgoing UDP packets. */
#define ipconfigUDP_TIME_TO_LIVE                128
#define ipconfigTCP_TIME_TO_LIVE                128 /* also defined in FreeRTOSIPConfigDefaults.h */

/* USE_TCP: Use TCP and all its features */
#define ipconfigUSE_TCP                                ( 1 )

/* USE_WIN: Let TCP use windowing mechanism. */
#define ipconfigUSE_TCP_WIN                        ( 1 )

/* The MTU is the maximum number of bytes the payload of a network frame can
contain.  For normal Ethernet V2 frames the maximum MTU is 1500.  Setting a
lower value can save RAM, depending on the buffer management scheme used.  If
ipconfigCAN_FRAGMENT_OUTGOING_PACKETS is 1 then (ipconfigNETWORK_MTU - 28) must
be divisible by 8. */

#define ipconfigNETWORK_MTU                                        1500

/* Set ipconfigUSE_DNS to 1 to include a basic DNS client/resolver.  DNS is used
through the FreeRTOS_gethostbyname() API function. */
#define ipconfigUSE_DNS                                                                1

/* If ipconfigREPLY_TO_INCOMING_PINGS is set to 1 then the IP stack will
generate replies to incoming ICMP echo (ping) requests. */
#define ipconfigREPLY_TO_INCOMING_PINGS                                1

/* If ipconfigSUPPORT_OUTGOING_PINGS is set to 1 then the
FreeRTOS_SendPingRequest() API function is available. */
#define ipconfigSUPPORT_OUTGOING_PINGS                                1

/* If ipconfigSUPPORT_SELECT_FUNCTION is set to 1 then the FreeRTOS_select()
(and associated) API function is available. */
#define ipconfigSUPPORT_SELECT_FUNCTION                                1

/* If ipconfigFILTER_OUT_NON_ETHERNET_II_FRAMES is set to 1 then Ethernet frames
that are not in Ethernet II format will be dropped.  This option is included for
potential future IP stack developments. */
#define ipconfigFILTER_OUT_NON_ETHERNET_II_FRAMES  1

/* If ipconfigETHERNET_DRIVER_FILTERS_FRAME_TYPES is set to 1 then it is the
responsibility of the Ethernet interface to filter out packets that are of no
interest.  If the Ethernet interface does not implement this functionality, then
set ipconfigETHERNET_DRIVER_FILTERS_FRAME_TYPES to 0 to have the IP stack
perform the filtering instead (it is much less efficient for the stack to do it
because the packet will already have been passed into the stack).  If the
Ethernet driver does all the necessary filtering in hardware then software
filtering can be removed by using a value other than 1 or 0. */
#define ipconfigETHERNET_DRIVER_FILTERS_FRAME_TYPES        1

/* The windows simulator cannot really simulate MAC interrupts, and needs to
block occasionally to allow other tasks to run. */
#define configWINDOWS_MAC_INTERRUPT_SIMULATOR_DELAY ( 2 / portTICK_PERIOD_MS )

/* Advanced only: in order to access 32-bit fields in the IP packets with
32-bit memory instructions, all packets will be stored 32-bit-aligned, plus
16-bits.  This has to do with the contents of the IP-packets: all 32-bit fields
are 32-bit-aligned, plus 16-bit(!). */
#define ipconfigPACKET_FILLER_SIZE 2

/* Define the size of the pool of TCP window descriptors.  On the average, each
TCP socket will use up to 2 x 6 descriptors, meaning that it can have 2 x 6
outstanding packets (for Rx and Tx).  When using up to 10 TP sockets
simultaneously, one could define TCP_WIN_SEG_COUNT as 120. */
#define ipconfigTCP_WIN_SEG_COUNT 64

/* Each TCP socket has a circular buffers for Rx and Tx, which have a fixed
maximum size.  Define the size of Rx buffer for TCP sockets. */
#define ipconfigTCP_RX_BUFFER_LENGTH                        ( 3 * 1460 )

/* Define the size of Tx buffer for TCP sockets. */
#define ipconfigTCP_TX_BUFFER_LENGTH                        ( 2 * 1460 )

/* When using call-back handlers, the driver may check if the handler points to
real program memory (RAM or flash) or just has a random non-zero value. */
#define ipconfigIS_VALID_PROG_ADDRESS(x) ( (x) != NULL )

/* Include support for TCP hang protection.  All sockets in a connecting or
disconnecting stage will timeout after a period of non-activity. */
#define ipconfigTCP_HANG_PROTECTION                                ( 1 )
#define ipconfigTCP_HANG_PROTECTION_TIME                ( 30 )

/* Include support for TCP keep-alive messages. */
#define ipconfigTCP_KEEP_ALIVE                                ( 1 )
#define ipconfigTCP_KEEP_ALIVE_INTERVAL                ( 20 ) /* in seconds */

/* Set to 1 or 0 to include/exclude FTP and HTTP functionality from the standard
server task. */
#define ipconfigUSE_FTP                                                1
#define ipconfigUSE_HTTP                                        1

/* Buffer and window sizes used by the FTP and HTTP servers respectively.  The
FTP and HTTP servers both execute in the standard server task. */
#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 )

/* UDP Logging related constants follow.  The standard UDP logging facility
writes formatted strings to a buffer, and creates a task that removes messages
from the buffer and sends them to the UDP address and port defined by the
constants that follow. */

/* Prototype for the function used to print out.  In this case the standard
UDP logging facility is used. */
extern int lUDPLoggingPrintf( const char *pcFormatString, ... );

/* Set to 1 to print out debug messages.  If ipconfigHAS_DEBUG_PRINTF is set to
1 then FreeRTOS_debug_printf should be defined to the function used to print
out the debugging messages. */
#define ipconfigHAS_DEBUG_PRINTF        0
#if( ipconfigHAS_DEBUG_PRINTF == 1 )
        #define FreeRTOS_debug_printf(X)        lUDPLoggingPrintf X
#endif

/* Set to 1 to print out non debugging messages, for example the output of the
FreeRTOS_netstat() command, and ping replies.  If ipconfigHAS_PRINTF is set to 1
then FreeRTOS_printf should be set to the function used to print out the
messages. */
#define ipconfigHAS_PRINTF                        1
#if( ipconfigHAS_PRINTF == 1 )
        #define FreeRTOS_printf(X)                        lUDPLoggingPrintf X
#endif

/* When set to 1, the application writer must provide the implementation of a
function with the following name and prototype:
BaseType_t xApplicationDNSQueryHook( const char *pcName );
The function must return pdTRUE if pcName matches a test name assigned to the
device, and pdFALSE in all other cases.  */
#define ipconfigDNS_USE_CALLBACKS                        1
#define ipconfigSUPPORT_SIGNALS                                1

/* This demo creates a virtual network connection by accessing the raw Ethernet
or WiFi data to and from a real network connection.  Many computers have more
than one real network port, and configNETWORK_INTERFACE_TO_USE is used to tell
the demo which real port should be used to create the virtual port.  The ports
available are displayed on the console when the application is executed.  For
example, on my development laptop setting configNETWORK_INTERFACE_TO_USE to 4
results in the wired network being used, while setting
configNETWORK_INTERFACE_TO_USE to 2 results in the wireless network being
used. */
#define configNETWORK_INTERFACE_TO_USE 4L

/* Default MAC address configuration.  The demo creates a virtual network
connection that uses this MAC address by accessing the raw Ethernet/WiFi data
to and from a real network connection on the host PC.  See the
configNETWORK_INTERFACE_TO_USE definition above for information on how to
configure the real network connection to use. */
#define configMAC_ADDR0                0x00
#define configMAC_ADDR1                0x11
#define configMAC_ADDR2                0x22
#define configMAC_ADDR3                0x33
#define configMAC_ADDR4                0x44
#define configMAC_ADDR5                0x41

/* Default IP address configuration.  Used in ipconfigUSE_DNS is set to 0, or
ipconfigUSE_DNS is set to 1 but a DNS server cannot be contacted. */
#define configIP_ADDR0                192
#define configIP_ADDR1                168
#define configIP_ADDR2                0
#define configIP_ADDR3                55

/* Default gateway IP address configuration.  Used in ipconfigUSE_DNS is set to
0, or ipconfigUSE_DNS is set to 1 but a DNS server cannot be contacted. */
#define configGATEWAY_ADDR0        192
#define configGATEWAY_ADDR1        168
#define configGATEWAY_ADDR2        0
#define configGATEWAY_ADDR3        1

/* Default DNS server configuration.  OpenDNS addresses are 208.67.222.222 and
208.67.220.220.  Used in ipconfigUSE_DNS is set to 0, or ipconfigUSE_DNS is set
to 1 but a DNS server cannot be contacted.*/
#define configDNS_SERVER_ADDR0         208
#define configDNS_SERVER_ADDR1         67
#define configDNS_SERVER_ADDR2         222
#define configDNS_SERVER_ADDR3         222

/* Default netmask configuration.  Used in ipconfigUSE_DNS is set to 0, or
ipconfigUSE_DNS is set to 1 but a DNS server cannot be contacted. */
#define configNET_MASK0                255
#define configNET_MASK1                255
#define configNET_MASK2                0
#define configNET_MASK3                0

/* The UDP port to which print messages are sent. */
#define configPRINT_PORT        ( 15000 )


/* The example IP trace macros are included here so the definitions are
available in all the FreeRTOS+TCP source files. */
#include "DemoIPTrace.h"


#ifdef __cplusplus
} /* extern "C" */
#endif

#endif /* FREERTOS_IP_CONFIG_H */


使用特权

评论回复
8
木木guainv|  楼主 | 2021-7-1 11:39 | 只看该作者
此时,工程目录如下所示:







根据FreeRTOS官方的tutorial,此时已近配置完成,但编译后会发现,仍然有几个函数没有完成定义,这是在配置文件下产生的,需要由用户

自己完成的函数,分别是以下函数:

int lUDPLoggingPrintf( const char *fmt, ... ) //调试用

const char *pcApplicationHostnameHook( void ) //返回主机名称

BaseType_t xApplicationDNSQueryHook( const char *pcName ) //DNS或LLMNR请求的查询回调

void vApplicationPingReplyHook( ePingReplyStatus_t eStatus, uint16_t usIdentifier ) //ping回复回调

void vApplicationIPNetworkEventHook( eIPCallbackEvent_t eNetworkEvent )  //网络事件回调

UBaseType_t uxRand() //随机数产生


使用特权

评论回复
9
木木guainv|  楼主 | 2021-7-1 11:40 | 只看该作者
在User目录下新建一个文件,我的是netInfoConfig.c用来完成上面的这些函数,复制下面的代码进去:



#include "FreeRTOSLib.h"          //自己把Freertos的头文件加进来
#include "FreeRTOSTcpLib.h"          //协议栈的头文件加进来

#include <stdio.h>
#include <string.h>
#include <stdarg.h>

#include "randomNum.h"
#include "netInfoConfig.h"

#include "led.h"

/* Define a name that will be used for LLMNR and NBNS searches. */
#define mainHOST_NAME                                "CocolYoungStm32"
#define mainDEVICE_NICK_NAME                "YYFStm32"


static BaseType_t UDP_DEBUG_INIT();

/*
        return a rand num
*/
UBaseType_t uxRand(){
        return (UBaseType_t) getRandomNum();
}


/* The default IP and MAC address used by the demo.  The address configuration
defined here will be used if ipconfigUSE_DHCP is 0, or if ipconfigUSE_DHCP is
1 but a DHCP server could not be contacted.  See the online documentation for
more information. */
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 };

/* Default MAC address configuration.  The demo creates a virtual network
connection that uses this MAC address by accessing the raw Ethernet data
to and from a real network connection on the host PC.  See the
configNETWORK_INTERFACE_TO_USE definition for information on how to configure
the real network connection to use. */
const uint8_t ucMACAddress[ 6 ] = { configMAC_ADDR0, configMAC_ADDR1, configMAC_ADDR2, configMAC_ADDR3, configMAC_ADDR4, configMAC_ADDR5 };


/*
*Brief:
        vApplicationIPNetworkEventHook() is an application
        defined hook (or callback) function that is called by the
        TCP/IP stack when the network either connects or disconnects.
        As the function is called by the TCP/IP stack the TCP/IP sets
        sets the value of the function's parameter.
*param:
        eNetworkEvent = 0 , the net connected.
        eNetworkEvent = 1 , the net disconnected.
*/       
void vApplicationIPNetworkEventHook( eIPCallbackEvent_t eNetworkEvent )
{
uint32_t ulIPAddress, ulNetMask, ulGatewayAddress, ulDNSServerAddress;
static BaseType_t xTasksAlreadyCreated = pdFALSE;
int8_t cBuffer[ 16 ];

    /* Check this was a network up event, as opposed to a network down event. */
    if( eNetworkEvent == eNetworkUp )
    {
        /* Create the tasks that use the TCP/IP stack if they have not already been
        created. */
        if( xTasksAlreadyCreated == pdFALSE )
        {
            /*
             * Create the tasks here.
             */
                                        UDP_DEBUG_INIT();//debug printf init
                                       
                                        //led1_flash();
                                        //xTaskCreate( aFunction, "aFunction", 1000, NULL, 3, NULL );
                                        //xTaskCreate( eth_send_task, "test_send", 1000, NULL, 3, NULL );
          xTasksAlreadyCreated = pdTRUE;
        }

        /* The network is up and configured.  Print out the configuration,
        which may have been obtained from a DHCP server. */
        FreeRTOS_GetAddressConfiguration( &ulIPAddress,
                                          &ulNetMask,
                                          &ulGatewayAddress,
                                          &ulDNSServerAddress );

        /* Convert the IP address to a string then print it out. */
        FreeRTOS_inet_ntoa( ulIPAddress, cBuffer );
        lUDPLoggingPrintf( "IP Address: %s\r\n", cBuffer );

        /* Convert the net mask to a string then print it out. */
        FreeRTOS_inet_ntoa( ulNetMask, cBuffer );
        lUDPLoggingPrintf( "Subnet Mask: %s\r\n", cBuffer );

        /* Convert the IP address of the gateway to a string then print it out. */
        FreeRTOS_inet_ntoa( ulGatewayAddress, cBuffer );
        lUDPLoggingPrintf( "Gateway IP Address: %s\r\n", cBuffer );

        /* Convert the IP address of the DNS server to a string then print it out. */
        FreeRTOS_inet_ntoa( ulDNSServerAddress, cBuffer );
        lUDPLoggingPrintf( "DNS server IP Address: %s\r\n", cBuffer );
    }
}
/*--------------------------------------------------------*/

/*
        there are series of func should be defined when ipconfigSUPPORT_OUTGOING_PINGS is set to 1.
*/
QueueHandle_t xPingReplyQueue;//this queue should be create for vApplicationPingReplyHook()

/* this func should be used before FreeRTOS_SendPingRequest() to init the xPingReplyQueue*/
void xPingReplyQueueCreate(){
        xPingReplyQueue = xQueueCreate( 20, sizeof( uint16_t ) );
}
void vApplicationPingReplyHook( ePingReplyStatus_t eStatus, uint16_t usIdentifier )
{
    switch( eStatus )
    {
        case eSuccess    :
            /* A valid ping reply has been received.  Post the sequence number
            on the queue that is read by the vSendPing() function below.  Do
            not wait more than 10ms trying to send the message if it cannot be
            sent immediately because this function is called from the TCP/IP
            RTOS task - blocking in this function will block the TCP/IP RTOS task. */
            xQueueSend( xPingReplyQueue, &usIdentifier, 10 / portTICK_PERIOD_MS );
            break;

        case eInvalidChecksum :
        case eInvalidData :
            /* A reply was received but it was not valid. */
            break;
    }
}


/*
* 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;

                /* Determine if a name lookup is for this node.  Two names are given
                to this node: that returned by pcApplicationHostnameHook() and that set
                by mainDEVICE_NICK_NAME. */
                if( strcmp( pcName, pcApplicationHostnameHook() ) == 0 )
                {
                        xReturn = pdPASS;
                }
                else if( strcmp( pcName, mainDEVICE_NICK_NAME ) == 0 )
                {
                        xReturn = pdPASS;
                }
                else
                {
                        xReturn = pdFAIL;
                }

                return xReturn;
}
/*----------------------------------------------*/

const char *pcApplicationHostnameHook( void ){

        return mainHOST_NAME;
}


/*-----------------------------------------------------------*/
       
void IP_init( void ){
        /***NOTE*** Tasks that use the network are created in the network event hook
        when the network is connected and ready for use (see the definition of
        vApplicationIPNetworkEventHook() below).  The address values passed in here
        are used if ipconfigUSE_DHCP is set to 0, or if ipconfigUSE_DHCP is set to 1
        but a DHCP server cannot be        contacted. */
        FreeRTOS_IPInit( ucIPAddress, ucNetMask, ucGatewayAddress, ucDNSServerAddress, ucMACAddress );
}


/*------------DEBUG ONLY----------------*/
Socket_t UDP_DEBUG_SOCKET;

/*
Brief : func used for init the udp
Return : if sucess,return pdTRUE
*/
static BaseType_t UDP_DEBUG_INIT(){
        struct freertos_sockaddr xBindAddress;

    /* Create a UDP socket. */
    UDP_DEBUG_SOCKET = FreeRTOS_socket( FREERTOS_AF_INET,
                               FREERTOS_SOCK_DGRAM,
                               FREERTOS_IPPROTO_UDP );

    /* Check the socket was created successfully. */
    if( UDP_DEBUG_SOCKET != FREERTOS_INVALID_SOCKET )
    {
        /* The socket was created successfully and can now be used to send data
        using the FreeRTOS_sendto() API function.  Sending to a socket that has
        not first been bound will result in the socket being automatically bound
        to a port number.  Use FreeRTOS_bind() to bind the socket to a
        specific port number.  This example binds the socket to port 9999.  The
        port number is specified in network byte order, so FreeRTOS_htons() is
        used. */
        xBindAddress.sin_port = FreeRTOS_htons( 9999 );
        if( FreeRTOS_bind( UDP_DEBUG_SOCKET, &xBindAddress, sizeof( &xBindAddress ) ) == 0 )
        {
                                        /* bind success */
                                        return pdTRUE;
                                }
                                else{
                                        return pdFALSE;
                                }
                }else{
                        return pdFALSE;
                }
}

/*
Brief:
this func only for debug printf
Param:
msg: the message.
len: the message length
Return:
the length
*/
static size_t UDP_SEND_DATA(const char* msg , size_t len){
        static struct freertos_sockaddr xDestinationAddress;
        int32_t iReturned;
       
        /* dest address and port */
        xDestinationAddress.sin_addr = FreeRTOS_inet_addr_quick( 192, 168, 0, 33 );
  xDestinationAddress.sin_port = FreeRTOS_htons( 60000 );
       
        /* Send the buffer with ulFlags set to 0, so the FREERTOS_ZERO_COPY bit
  is clear. */
  iReturned = FreeRTOS_sendto(
                                  /* The socket being send to. */
                                  UDP_DEBUG_SOCKET,
                                  /* The data being sent. */
                                  msg,
                                  /* The length of the data being sent. */
                                  len,
                                  /* ulFlags with the FREERTOS_ZERO_COPY bit clear. */
                                  0,
                                  /* Where the data is being sent. */
                                  &xDestinationAddress,
                                  /* Not used but should be set as shown. */
                                  sizeof( xDestinationAddress )
                             );

    if( iReturned == len )
    {
       return len;
    }       
                else{
                        return 0;
                }
}

/*
        only for debug
*/
int lUDPLoggingPrintf( const char *fmt, ... ){
        va_list ap;
        char msg[128];
        int len;

        va_start(ap, fmt);
        len = vsnprintf(msg, sizeof(msg), fmt, ap);
        UDP_SEND_DATA(msg, len);
        va_end(ap);
        return len;
}
/*------------DEBUG ONLY----------------*/




使用特权

评论回复
10
木木guainv|  楼主 | 2021-7-1 11:40 | 只看该作者
记住,一切与网络有关的任务请创建在void vApplicationIPNetworkEventHook( eIPCallbackEvent_t eNetworkEvent )内。





stm32外设自带随机数发生器,在工程User目录下创建randomNum.c和randomNum.h,添加如下内容:



#include "randomNum.h"

/* RNG handler declaration */
RNG_HandleTypeDef RngHandle;

static void Error_Handler(){
                while(1){
                       
                }
}

void RNG_init(){
        __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 getRandomNum(){
        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();      
      }
}




#ifndef __RANDOMNUM__H
#define __RANDOMNUM__H

#include "stm32f4xx_hal_rng.h"
#include "stm32f4xx_hal_rcc.h"

void RNG_init(void);
uint32_t getRandomNum(void);
void getRandomNumTo(uint32_t * num);
#endif



使用特权

评论回复
11
木木guainv|  楼主 | 2021-7-1 11:41 | 只看该作者
最后,在工程的User目录下创建main.c,内容如下:





/* stm32F4 HAL lib includes */
#include "stm32f4xx_hal.h"

/* FreeRTOS includes. */
#include "FreeRTOS.h"

/* user includes */
#include "randomNum.h"
#include "netInfoConfig.h"
#include "led.h"


int main(){       
               
        //led_init();
  HAL_NVIC_SetPriorityGrouping(NVIC_PRIORITYGROUP_4);
        RNG_init();
       
        /***NOTE*** Tasks that use the network are created in the network event hook
        when the network is connected and ready for use (see the definition of
        vApplicationIPNetworkEventHook() below).  The address values passed in here
        are used if ipconfigUSE_DHCP is set to 0, or if ipconfigUSE_DHCP is set to 1
        but a DHCP server cannot be        contacted. */
        IP_init();
       
       
        vTaskStartScheduler();

        /* If all is well, the scheduler will now be running, and the following
        line will never be reached.  If the following line does execute, then
        there was insufficient FreeRTOS heap memory available for the idle and/or
        timer tasks        to be created.  See the memory management section on the
        FreeRTOS web site for more details (this is standard text that is not not
        really applicable to the Win32 simulator port). */
        while(1);
}


使用特权

评论回复
12
木木guainv|  楼主 | 2021-7-1 11:41 | 只看该作者
再次提醒,有关网络的void vApplicationIPNetworkEventHook( eIPCallbackEvent_t eNetworkEvent )内,

因为要保证网络已经连接之后才能创建网络有关的任务。随机数的初始化应该在网络初始化前面。

最后工程目录如下:



最后,ping一下看看能否ping通,或者随便写个任务看看能不能抓到包。



随便写个任务,1s发一次“fffffffffffffffffffffffffffffffffffffffffffff”



OK,到此搞定。




使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

146

主题

4098

帖子

5

粉丝