Real time embedded FreeRTOS RSS feed 
Homepage FreeRTOS+ Products FreeRTOS Labs Integration Services Contact / Enquiries

FreeRTOS+UDP Primer - A Step by Step Tutorial

Context

The embedded networking basics and glossary page provides an introduction to embedded networking concepts. The API reference provides detailed information on each FreeRTOS+UDP API function. This page provides a top level overview of the steps required to build and use FreeRTOS+UDP in a network enabled embedded application. Complete buildable and executable example projects are also available from this website.

On this page:



Source Code Organisation

The FreeRTOS+UDP code is distributed with the directory structure shown below. Pre-packaged projects may be delivered with a slightly different structure.


FreeRTOS-Plus-UDP        [Contains the source files that implement the IP stack]
  |
  +-include              [Contains the header files for the IP stack]
  |
  +-portable
      |
      +-BufferManagement [Source files that implement optional buffer allocation schemes]
      |
      +-Compiler         [Contains sub directories that port the stack to different compilers]
      |   +-Compiler_x   [Contains structure packing header files for Compiler_x]
      |   +-Compiler_y   [Contains structure packing header files for Compiler_y]
      |   +-Compiler_z   [Contains structure packing header files for Compiler_z]
      |
      +-NetworkInterface [Contains sub directories that port the stack to different hardware]
          +-MCU_x        [Contains a network interface for the MCU_x family of microcontrollers]
          +-MCU_y        [Contains a network interface for the MCU_y family of microcontrollers]
          +-MCU_z        [Contains a network interface for the MCU_z family of microcontrollers]
						
The FreeRTOS+UDP Directory Structure


Adding FreeRTOS+UDP To a FreeRTOS Project

FreeRTOS+UDP runs on FreeRTOS, so start with a standard FreeRTOS application. The application must be using the heap_4 memory allocator. When you are sure the standard FreeRTOS application is configured and executing correctly:
  1. Add the following core FreeRTOS+UDP source files into your project:
    • FreeRTOS-Plus/FreeRTOS-Plus-UDP/FreeRTOS_UDP_IP.c
    • FreeRTOS-Plus/FreeRTOS-Plus-UDP/FreeRTOS_Sockets.c
    • FreeRTOS-Plus/FreeRTOS-Plus-UDP/FreeRTOS_DHCP.c
    • FreeRTOS-Plus/FreeRTOS-Plus-UDP/FreeRTOS_DNS.c

  2. Add your chosen network buffer allocation scheme to your project. Source files that implement buffer allocation schemes are located in: FreeRTOS-Plus/FreeRTOS-Plus-UDP/portable/BufferManagement/.
    At this time BufferAllocation_2.c is recommended for simplicity because it obtains its RAM from the FreeRTOS heap. BufferAllocation_2.c can only be used with the heap_4 memory allocator.

  3. Add the driver for your network interface (the MAC or Ethernet driver) into your project. Source files that implement network drivers are called NetworkInterface.c and are located in:
    FreeRTOS-Plus/FreeRTOS-Plus-UDP/portable/NetworkInterface/[microcontroller]/ , where [microcontroller] is the family of microcontroller on which FreeRTOS+UDP will run. Instructions are provided for creating network drivers for other chips.

  4. Ensure the following core and chip specific paths are in your compiler's include path (so the compiler can locate the necessary header files):
    • FreeRTOS-Plus/FreeRTOS-Plus-UDP/
    • FreeRTOS-Plus/FreeRTOS-Plus-UDP/portable/Compiler/[compiler]
    where [compiler] is the compiler being used. Instructions are provided for porting to new compilers.

  5. Add a FreeRTOSIPConfig.h header file to your project, and ensure the constants it contains are configured appropriately for your application.

    FreeRTOSIPConfig.h tailors the core UDP/IP stack for your application. It is application specific, not IP stack specific, and should therefore be located in an application directory rather than a FreeRTOS+UDP directory. Existing FreeRTOSIPConfig.h header files are found in the reference projects available on this website.


Initialising the IP Stack

FreeRTOS_IPInit() must be the first FreeRTOS+UDP function called. FreeRTOS_IPInit() can be called before or after the RTOS scheduler is started.


/* Define the network addressing.  These parameters will be used if either
ipconfigUDE_DHCP is 0 or if ipconfigUSE_DHCP is 1 but DHCP auto configuration
failed. */
static const uint8_t ucIPAddress[ 4 ] = { 192, 168, 0, 200 };
static const uint8_t ucNetMask[ 4 ] = { 255, 255, 255, 255 };
static const uint8_t ucGatewayAddress[ 4 ] = { 192, 168, 0, 1 };

/* The following is the address of an OpenDNS server. */
static const uint8_t ucDNSServerAddress[ 4 ] = { 208, 67, 222, 222 };

/* The MAC address array is not declared const as the MAC address will
normally be read from an EEPROM and not hard coded (in real deployed
applications).*/
static uint8_t ucMACAddress[ 6 ] = { 0x00, 0x11, 0x22, 0x33, 0x44, 0x55 };

int main( void )
{
    /* Initialise the embedded Ethernet interface.  The tasks that use the
    network are created in the vApplicationIPNetworkEventHook() hook function
    below.  The hook function is called when the network connects. */
    FreeRTOS_IPInit( ucIPAddress,
                     ucNetMask,
                     ucGatewayAddress,
                     ucDNSServerAddress,
                     ucMACAddress );

    /*
     * Other RTOS tasks can be created here.
     */

    /* Start the RTOS scheduler. */
    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. */
    for( ;; );
}
						
Example use of the FreeRTOS_IPInit() API function



FreeRTOS_IPInit() creates the FreeRTOS+UDP RTOS task. The FreeRTOS+UDP task configures and initialises the network interface. If ipconfigUSE_NETWORK_EVENT_HOOK is set to 1 in FreeRTOSIPConfig.h then the IP stack will execute the vIPNetworkEventHook() callback function when the network is ready for use.


void vApplicationIPNetworkEventHook( eIPCallbackEvent_t eNetworkEvent )
{
static BaseType_t xTasksAlreadyCreated = pdFALSE;

    /* Check this was a network up event, as opposed to a network down event. */
    if( eNetworkEvent == eNetworkUp )
    {
        /* Create the tasks that use the IP stack if they have not already been
        created. */
        if( xTasksAlreadyCreated == pdFALSE )
        {
            /*
             * For convenience, tasks that use FreeRTOS+UDP can be created here
             * to ensure they are not created before the network is usable.
             */

            xTasksAlreadyCreated = pdTRUE;
        }
    }
}
						
Example vApplicationIPNetworkEventHook() definition


Creating, Configuring and Binding a Socket

Sockets are created using the FreeRTOS_socket() API function, configured using the FreeRTOS_setsockopt() function, and bound to a port (if necessary) using the FreeRTOS_bind() function.


static void prvSimpleServerTask( void *pvParameters )
{
long lBytes;
struct freertos_sockaddr xBindAddress;
xSocket_t xListeningSocket;
const TickType_t xSendTimeOut = 200 / portTICK_PERIOD_MS;

    /* Attempt to open the socket. */
    xListeningSocket = FreeRTOS_socket( FREERTOS_AF_INET,
                                        FREERTOS_SOCK_DGRAM,
                                        FREERTOS_IPPROTO_UDP );

    /* Check for errors. */
    configASSERT( xListeningSocket != FREERTOS_INVALID_SOCKET );

    /* Ensure calls to FreeRTOS_sendto() timeout if a network buffer cannot be
    obtained within 200ms. */
    FreeRTOS_setsockopt( xListeningSocket,
                         0,
                         FREERTOS_SO_SNDTIMEO,
                         &xSendTimeOut,
                         sizeof( xSendTimeOut ) );

    /* Bind the socket to port 0x1234. */
    xBindAddress.sin_port = FreeRTOS_htons( 0x1234 );
    FreeRTOS_bind( xListeningSocket, &xBindAddress, sizeof( xBindAddress ) );

    for( ;; )
    {
        /*
         * The socket can now receive data here.
         */
    }
}
						
Creating, configuring and binding a socket


Sending Data (standard interface)

After a socket has been created, configured, and optionally bound it can be used in a call to FreeRTOS_sendto() to send data onto the network.

As detailed on the FreeRTOS_sendto() API reference page, FreeRTOS_sendto() can be used with standard calling semantics, or zero copy calling semantics. This subsection demonstrates the standard calling semantics.

The source code below shows a task that creates a socket before entering a loop that sends a string to the socket (using the standard calling semantics) every 1 second (1000ms).


static void vSendUsingStandardInterface( void *pvParameters )
{
xSocket_t xSocket;
struct freertos_sockaddr xDestinationAddress;
uint8_t cString[ 50 ];
uint32_t ulCount = 0UL;
const TickType_t x1000ms = 1000UL / portTICK_PERIOD_MS;

    /* Send strings to port 10000 on IP address 192.168.0.200. */
    xDestinationAddress.sin_addr = FreeRTOS_inet_addr( "192.168.0.200" );
    xDestinationAddress.sin_port = FreeRTOS_htons( 10000 );

    /* Create the socket. */
    xSocket = FreeRTOS_socket( FREERTOS_AF_INET,
                               FREERTOS_SOCK_DGRAM,
                               FREERTOS_IPPROTO_UDP );

    /* Check the socket was created. */
    configASSERT( xSocket != FREERTOS_INVALID_SOCKET );

    /* NOTE: FreeRTOS_bind() is not called.  This will only work if
    ipconfigALLOW_SOCKET_SEND_WITHOUT_BIND is set to 1 in FreeRTOSIPConfig.h. */

    for( ;; )
    {
        /* Create the string that is sent. */
        sprintf( cString,
                 "Standard send message number %lu\r\n",
                 ulCount );

        /* Send the string to the socket.  ulFlags is set to 0, so the standard
        semantics are used.  That means the data from cString[] is copied
        into a network buffer inside FreeRTOS_sendto(), and cString[] can be
        reused as soon as FreeRTOS_sendto() has returned. */
        FreeRTOS_sendto( xSocket,
                         cString,
                         strlen( cString ),
                         0,
                         &xDestinationAddress,
                         sizeof( xDestinationAddress ) );

        ulCount++;

        /* Wait until it is time to send again. */
        vTaskDelay( x1000ms );
    }
}
						
Example using FreeRTOS_sendto() with the standard (as opposed to zero copy) calling semantics


Sending Data (zero copy interface)

After a socket has been created, configured, and optionally bound it can be used in a call to FreeRTOS_sendto() to send data onto the network.

As detailed on the FreeRTOS_sendto() API reference page, FreeRTOS_sendto() can be used with standard calling semantics, or zero copy calling semantics. This subsection demonstrates the zero copy calling semantics.

The source code below shows a task that creates a socket before entering a loop that sends a string to the socket (using the zero copy calling semantics) every 1 second (1000ms).


static void vSendingUsingZeroCopyInterface( void *pvParameters )
{
xSocket_t xSocket;
uint8_t *pucBuffer;
struct freertos_sockaddr xDestinationAddress;
BaseType_t lReturned;
uint32_t ulCount = 0UL;
const uint8_t *pucStringToSend = "Zero copy send message number ";
const TickType_t x1000ms = 1000UL / portTICK_PERIOD_MS;
/* 15 is added to ensure the number, \r\n and terminating zero fit. */
const size_t xStringLength = strlen( ( char * ) pucStringToSend ) + 15;

    /* Send strings to port 10000 on IP address 192.168.0.200. */
    xDestinationAddress.sin_addr = FreeRTOS_inet_addr( "192.168.0.200" );
    xDestinationAddress.sin_port = FreeRTOS_htons( 10000 );

    /* Create the socket. */
    xSocket = FreeRTOS_socket( FREERTOS_AF_INET,
                               FREERTOS_SOCK_DGRAM,
                               FREERTOS_IPPROTO_UDP );

    /* Check the socket was created. */
    configASSERT( xSocket != FREERTOS_INVALID_SOCKET );

    /* NOTE: FreeRTOS_bind() is not called.  This will only work if
    ipconfigALLOW_SOCKET_SEND_WITHOUT_BIND is set to 1 in FreeRTOSIPConfig.h. */

    for( ;; )
    {
        /* This task is going to send using the zero copy interface.  The
        data being sent is therefore written directly into a buffer that is
        passed into, rather than copied into, the FreeRTOS_sendto()
        function.

        First obtain a buffer of adequate length from the IP stack into which
        the string will be written. */
        pucBuffer = FreeRTOS_GetUDPPayloadBuffer( xStringLength, portMAX_DELAY );

        /* Check a buffer was obtained. */
        configASSERT( pucBuffer );

        /* Create the string that is sent. */
        memset( pucBuffer, 0x00, xStringLength );
        sprintf( pucBuffer, "%s%lu\r\n", ucStringToSend, ulCount );

        /* Pass the buffer into the send function.  ulFlags has the
        FREERTOS_ZERO_COPY bit set so the IP stack will take control of the
        buffer rather than copy data out of the buffer. */
        lReturned = FreeRTOS_sendto( xSocket,
                                    ( void * ) pucBuffer,
                                    strlen( ( const char * ) pucBuffer ) + 1,
                                    FREERTOS_ZERO_COPY,
                                    &xDestinationAddress,
                                    sizeof( xDestinationAddress ) );

        if( lReturned == 0 )
        {
            /* The send operation failed, so this task is still responsible
            for the buffer obtained from the IP stack.  To ensure the buffer
            is not lost it must either be used again, or, as in this case,
            returned to the IP stack using FreeRTOS_ReleaseUDPPayloadBuffer().
            pucBuffer can be safely re-used after this call. */
            FreeRTOS_ReleaseUDPPayloadBuffer( ( void * ) pucBuffer );
        }
        else
        {
            /* The send was successful so the IP stack is now managing the
            buffer pointed to by pucBuffer, and the IP stack will
            return the buffer once it has been sent.  pucBuffer can
            be safely re-used. */
        }

        ulCount++;

        /* Wait until it is time to send again. */
        vTaskDelay( x1000ms );
    }
}
						
Example using FreeRTOS_sendto() with the zero copy calling semantics


Receiving Data (standard interface)

After a socket has been created, configured, and bound it can be used in a call to FreeRTOS_recvfrom() to receive data from the network.

As detailed on the FreeRTOS_recvfrom() API reference page, FreeRTOS_recvfrom() can be used with standard calling semantics, or zero copy calling semantics. This subsection demonstrates the standard calling semantics.

The source code below shows a task that creates a socket before entering a loop that receives data using the standard calling semantics.


static void vReceivingUsingStandardInterface( void *pvParameters )
{
long lBytes;
uint8_t cReceivedString[ 60 ];
struct freertos_sockaddr xClient, xBindAddress;
uint32_t xClientLength = sizeof( xClient );
xSocket_t xListeningSocket;

    /* Attempt to open the socket. */
    xListeningSocket = FreeRTOS_socket( FREERTOS_AF_INET,
                                        FREERTOS_SOCK_DGRAM,
                                        FREERTOS_IPPROTO_UDP );

    /* Check the socket was created. */
    configASSERT( xListeningSocket != FREERTOS_INVALID_SOCKET );

    /* Bind to port 10000. */
    xBindAddress.sin_port = FreeRTOS_htons( 10000 );
    FreeRTOS_bind( xListeningSocket, &xBindAddress, sizeof( xBindAddress ) );

    for( ;; )
    {
        /* Receive data from the socket.  ulFlags is zero, so the standard
        interface is used.  By default the block time is portMAX_DELAY, but it
        can be changed using FreeRTOS_setsockopt(). */
        lBytes = FreeRTOS_recvfrom( xListeningSocket,
                                    cReceivedString,
                                    sizeof( cReceivedString ),
                                    0,
                                    &xClient,
                                    &xClientLength );

        if( lBytes > 0 )
        {
            /* Data was received and can be process here. */
        }
    }
}
						
Example using FreeRTOS_recvfrom() with the standard (as opposed to zero copy) calling semantics


Receiving Data (zero copy interface)

After a socket has been created, configured, and bound it can be used in a call to FreeRTOS_recvfrom() to receive data from the network.

As detailed on the FreeRTOS_recvfrom() API reference page, FreeRTOS_recvfrom() can be used with standard calling semantics, or zero copy calling semantics. This subsection demonstrates the zero copy calling semantics.

The source code below shows a task that creates a socket before entering a loop that receives data using the zero copy calling semantics.


static void vReceivingUsingZeroCopyInterface( void *pvParameters )
{
int32_t lBytes;
uint8_t *pucUDPPayloadBuffer;
struct freertos_sockaddr xClient, xBindAddress;
uint32_t xClientLength = sizeof( xClient ), ulIPAddress;
xSocket_t xListeningSocket;

    /* Attempt to open the socket. */
    xListeningSocket = FreeRTOS_socket( FREERTOS_AF_INET,
                                        FREERTOS_SOCK_DGRAM,
                                        FREERTOS_IPPROTO_UDP );

    /* Check the socket was created. */
    configASSERT( xListeningSocket != FREERTOS_INVALID_SOCKET );

    /* Bind to port 10000. */
    xBindAddress.sin_port = FreeRTOS_htons( 10000 );
    FreeRTOS_bind( xListeningSocket, &xBindAddress, sizeof( xBindAddress ) );

    for( ;; )
    {
        /* Receive data from the socket.  ulFlags has the zero copy bit set
        (FREERTOS_ZERO_COPY) indicating to the stack that a reference to the
        received data should be passed out to this task using the second
        parameter to the FreeRTOS_recvfrom() call.  When this is done the
        IP stack is no longer responsible for releasing the buffer, and
        the task must return the buffer to the stack when it is no longer
        needed.  By default the block time is portMAX_DELAY but it can be
        changed using FreeRTOS_setsockopt(). */
        lBytes = FreeRTOS_recvfrom( xListeningSocket,
                                    &pucUDPPayloadBuffer,
                                    0,
                                    FREERTOS_ZERO_COPY,
                                    &xClient,
                                    &xClientLength );

        if( lBytes > 0 )
        {
            /* Data was received and can be processed here. */
        }

        if( lBytes >= 0 )
        {
            /* The receive was successful so this task is now responsible for
            the buffer.  The buffer must be freed once it is no longer
            needed. */

            /*
             * The data can be processed here.
             */

            /* Return the buffer to the IP stack. */
            FreeRTOS_ReleaseUDPPayloadBuffer( pucUDPPayloadBuffer );
        }
    }
}
						
Example using FreeRTOS_recvfrom() with the zero copy (as opposed to standard) calling semantics


[ Back to the top ]    [ About FreeRTOS ]    [ FreeRTOS+ Sitemap ]    [ Main FreeRTOS Sitemap ]    [ ]


Copyright (C) Amazon Web Services, Inc. or its affiliates. All rights reserved.