HELP STM Discovery FreeRTOS + UDP

I’m trying to use FreeRTOS + UDP in a STM Discovery board. It initilize fine and get a ip address from DHCP when I plug it on my router. But there is a problem when I send a PING request from my computer, I receive about 12 packets and after that all the next packets are lost. Other issue is that I have tried to send a ping request from my board with no sucess. Both times, send a ping from my computer or to my computer, I put a led blink task to run togheter my application and it doesn’t stop even when my UDP/IP stops to handle the packets. *Using a led to debug I saw that my UDP stops when, in my handle task, the function pxNetworkBufferGet( xBytesReceived, 0 ) starts to return NULL. Probably my problem is on my network interface implementation. Here is the code. ~~~ /* * FreeRTOS+UDP V1.0.4 (C) 2014 Real Time Engineers ltd. * All rights reserved * * This file is part of the FreeRTOS+UDP distribution. The FreeRTOS+UDP license * terms are different to the FreeRTOS license terms. * * FreeRTOS+UDP uses a dual license model that allows the software to be used * under a standard GPL open source license, or a commercial license. The * standard GPL license (unlike the modified GPL license under which FreeRTOS * itself is distributed) requires that all software statically linked with * FreeRTOS+UDP is also distributed under the same GPL V2 license terms.
* Details of both license options follow: * * – Open source licensing – * FreeRTOS+UDP is a free download and may be used, modified, evaluated and * distributed without charge provided the user adheres to version two of the * GNU General Public License (GPL) and does not remove the copyright notice or * this text. The GPL V2 text is available on the gnu.org web site, and on the * following URL: http://www.FreeRTOS.org/gpl-2.0.txt. * * – Commercial licensing – * Businesses and individuals that for commercial or other reasons cannot comply * with the terms of the GPL V2 license must obtain a commercial license before * incorporating FreeRTOS+UDP into proprietary software for distribution in any * form. Commercial licenses can be purchased from http://shop.freertos.org/udp * and do not require any source files to be changed. * * FreeRTOS+UDP is distributed in the hope that it will be useful. You cannot * use FreeRTOS+UDP unless you agree that you use the software ‘as is’. * FreeRTOS+UDP 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/udp * */ /* Standard includes. */

include <stdint.h>

include <stdlib.h>

include <stdio.h>

/* FreeRTOS includes. */

include “FreeRTOS.h”

include “task.h”

include “queue.h”

include “semphr.h”

/* Hardware abstraction. */ /* FreeRTOS+UDP includes. */

include “FreeRTOSUDPIP.h”

include “FreeRTOSIPPrivate.h”

include “FreeRTOS_Sockets.h”

include “NetworkBufferManagement.h”

/* Driver includes. */

include “enet_mac.h”

include “metal/systime.h”

include “metal/delay.h”

/* Demo includes. */

include “NetworkInterface.h”

/* When a packet is ready to be sent, if it cannot be sent immediately then the task performing the transmit will block for niTXBUFFERFREEWAIT milliseconds. It will do this a maximum of niMAXTX_ATTEMPTS before giving up. */

define niTXBUFFERFREEWAIT ( ( TickTypet ) 2UL / portTICKRATEMS )

define niMAXTXATTEMPTS ( 5 )

/———————————————————–/ /* * A deferred interrupt handler task that processes */ static void prvEMACHandlerTask( void *pvParameters ); /———————————————————–/ /* The queue used to communicate Ethernet events with the IP task. */ extern xQueueHandle xNetworkEventQueue; /* The semaphore used to wake the deferred interrupt handler task when an Rx interrupt is received. / static xSemaphoreHandle xEMACRxEventSemaphore = NULL; /———————————————————–*/

ifndef ENETPHYADDR

define ENETPHYADDR 0x00

endif

define ENET_NBUF 1024

define ENETDMANRXD 15

define ENETDMANTXD 15

typedef struct enetdmadesc { volatile uint32t des0; volatile uint32t des1; volatile uint32t des2; volatile uint32t des3; } enetdmadesc_t;

define ALIGN4 attribute((aligned(4)));

static volatile enetdmadesct genetdmarxdesc[ENETDMANRXD] ALIGN4; static volatile enetdmadesct genetdmatxdesc[ENETDMANTXD] ALIGN4; static volatile uint8t genetdmarxbuf[ENETDMANRXD][ENETNBUF] ALIGN4; static volatile uint8t genetdmatxbuf[ENETDMANTXD][ENETNBUF] ALIGN4; static volatile enetdmadesct *genetdmarxnextdesc = &genetdmarxdesc[0]; static volatile enetdmadesct *genetdmatxnextdesc = &genetdmatxdesc[0]; uint8_t *buffer; uint16t enetreadphyreg( const uint8t regidx ) { while( ETH->MACMIIAR & ETHMACMIIARMB ){} ETH->MACMIIAR = ( ENETPHYADDR << 11 ) | ( ( regidx & 0x1F ) << 6 ) | ETHMACMIIARCRDiv102 | ETHMACMIIARMB; while( ETH->MACMIIAR & ETHMACMIIARMB ){} return ETH->MACMIIDR & 0xFFFF; } /———————————————————–/ void enetwritephyreg( const uint8t regidx, const uint16t regval ) { while( ETH->MACMIIAR & ETHMACMIIARMB ){} ETH->MACMIIDR = regval; ETH->MACMIIAR = ( ENETPHYADDR << 11 ) | ( ( regidx & 0x1F ) << 6 ) | ETHMACMIIARCRDiv102 | ETHMACMIIARMW | ETHMACMIIARMB; while( ETH->MACMIIAR & ETHMACMIIARMB ){} enetreadphyreg( regidx ); } /———————————————————–/ BaseType_t xNetworkInterfaceInitialise( void ) { buffer = ( char* )malloc( 1024 );
BaseType_t xReturn;
enet_mac_init_pins();

RCC->APB2ENR |= RCC_APB2ENR_SYSCFGEN;
RCC->AHB1RSTR |= RCC_AHB1RSTR_ETHMACRST;

for( volatile int i = 0; i < 1000; i++ ){}
for( volatile int i = 0; i < 1000; i++ ){}

ifndef ENETUSEMII

SYSCFG->PMC |= SYSCFG_PMC_MII_RMII_SEL; // set the MAC in RMII mode

endif

for( volatile int i = 0; i < 100000; i++ ){}
RCC->AHB1ENR |= RCC_AHB1ENR_ETHMACRXEN | RCC_AHB1ENR_ETHMACTXEN | RCC_AHB1ENR_ETHMACEN;
for( volatile int i = 0; i < 100000; i++ ){}
RCC->AHB1RSTR &= ~RCC_AHB1RSTR_ETHMACRST;
for( volatile int i = 0; i < 100000; i++ ){}
RCC->AHB1RSTR |= RCC_AHB1RSTR_ETHMACRST;
for( volatile int i = 0; i < 100000; i++ ){}
RCC->AHB1RSTR &= ~RCC_AHB1RSTR_ETHMACRST;
for( volatile int i = 0; i < 100000; i++ ){}

ETH->DMABMR |= ETH_DMABMR_SR;
for( volatile int i = 0; i < 100000; i++ ){}
while( ETH->DMABMR & ETH_DMABMR_SR ){}
for( volatile int i = 0; i < 100000; i++ ){}
ETH->DMAOMR |= ETH_DMAOMR_FTF;
while( ETH->DMAOMR & ETH_DMAOMR_FTF ){}

ETH->MACCR |= 0x02000000 | ETH_MACCR_FES | ETH_MACCR_DM | ETH_MACCR_IPCO | ETH_MACCR_APCS;
ETH->MACFFR |= ETH_MACFFR_RA;
delay_ms( 1 );

while( enet_read_phy_reg( 0 ) == 0xffff ){}

for( int i = 0; i < ENET_DMA_NTXD; i++ )
{
    g_enet_dma_tx_desc[i].des0 = 0x00100000 | 0x00c00000;
    g_enet_dma_tx_desc[i].des1 = 0;
    g_enet_dma_tx_desc[i].des2 = ( uint32_t )&g_enet_dma_tx_buf[ i ][ 0 ];

    if( i < ENET_DMA_NTXD - 1 )
    {
        g_enet_dma_tx_desc[ i ].des3 = ( uint32_t )&g_enet_dma_tx_desc[ i + 1 ];
    }
    else
    {
        g_enet_dma_tx_desc[ i ].des3 = ( uint32_t )&g_enet_dma_tx_desc[ 0 ];
    }
}

for( int i = 0; i < ENET_DMA_NRXD; i++ )
{
    g_enet_dma_rx_desc[ i ].des0 = 0x80000000;
    g_enet_dma_rx_desc[ i ].des1 = 0x00004000 | ENET_NBUF;
    g_enet_dma_rx_desc[ i ].des2 = (uint32_t)&g_enet_dma_rx_buf[ i ][ 0 ];

    if( i < ENET_DMA_NRXD - 1 )
    {
        g_enet_dma_rx_desc[ i ].des3 = ( uint32_t )&g_enet_dma_rx_desc[ i + 1 ];
    }
    else
    {
        g_enet_dma_rx_desc[ i ].des3 = ( uint32_t )&g_enet_dma_rx_desc[ 0 ];
    }
}

ETH->DMATDLAR = ( uint32_t )&g_enet_dma_tx_desc[ 0 ];
ETH->DMARDLAR = ( uint32_t )&g_enet_dma_rx_desc[ 0 ];
ETH->DMAOMR = ETH_DMAOMR_TSF;
ETH->DMABMR |= ETH_DMABMR_AAB;

ETH->DMAIER = ETH_DMAIER_NISE | ETH_DMAIER_RIE;
ETH->MACCR |= ETH_MACCR_TE | ETH_MACCR_RE;

//How to know if the hardware was not initilizes corretly
if( 1 )
{
    if( xEMACRxEventSemaphore == NULL )
    {
        vSemaphoreCreateBinary( xEMACRxEventSemaphore );
    }

    configASSERT( xEMACRxEventSemaphore );

    /* The handler task is created at the highest possible priority to
    ensure the interrupt handler can return directly to it. */

    xTaskCreate( prvEMACHandlerTask, "EMAC", configMINIMAL_STACK_SIZE, NULL, configMAX_PRIORITIES - 1, NULL );

    /* Enable the interrupt and set its priority to the minimum
    interrupt priority.  */
    NVIC_SetPriority( ETH_IRQn, 8 );
    NVIC_EnableIRQ( ETH_IRQn );
    ETH->DMAOMR |= ETH_DMAOMR_ST | ETH_DMAOMR_SR;

    xReturn = pdPASS;
}
else
{
    xReturn = pdFAIL;
}

return xReturn;
} /———————————————————–/ BaseTypet xNetworkInterfaceOutput( xNetworkBufferDescriptort * const pxNetworkBuffer ) { BaseTypet xReturn = pdFAIL; int32t x; volatile uint32_t tps;
/* Attempt to obtain access to a Tx buffer. */
for( x = 0; x < niMAX_TX_ATTEMPTS; x++ )
{
    /* Verify if the DMA descriptor are free to send a frame */
    if( !( g_enet_dma_tx_next_desc->des0 & 0x80000000 ) )
    {
        /* Will the data fit in the Tx buffer? */
        if( pxNetworkBuffer->xDataLength < ENET_NBUF ) /*_RB_ The size needs to come from FreeRTOSIPConfig.h. */
        {
            buffer = (uint8_t *)g_enet_dma_tx_next_desc->des2;

            /* Assign the buffer to the Tx descriptor that is now known to
            be free. */
            memcpy( (uint8_t *)buffer, (uint8_t *)pxNetworkBuffer->pucEthernetBuffer, pxNetworkBuffer->xDataLength );
            g_enet_dma_tx_next_desc->des1  = (uint32_t)pxNetworkBuffer->xDataLength;

            /* Initiate the Tx. */
            g_enet_dma_tx_next_desc->des0 |= 0x30000000 | 0x80000000;
            delay_ns( 1 );
            tps = ETH->DMASR & ETH_DMASR_TPS;

            /* Verify if the DMA is suspended.If it is, put it to run again and transmit the descriptors*/              
            if( tps == ETH_DMASR_TPS_Suspended )
            {
                ETH->DMATPDR = 0;
            }

            /* Set DMA descriptor to the next transmition descriptor */
            g_enet_dma_tx_next_desc = (enet_dma_desc_t *)g_enet_dma_tx_next_desc->des3;

            /* The EMAC now owns the buffer. */
            pxNetworkBuffer->pucEthernetBuffer = NULL;

            /* The Tx has been initiated. */
            xReturn = pdPASS;
        }
        break;
    }
    else
    {
        vTaskDelay( niTX_BUFFER_FREE_WAIT );
    }
}

/* Finished with the network buffer. */
vNetworkBufferRelease( pxNetworkBuffer );

return xReturn;
} /———————————————————–/ void ethvector( void ) { volatile uint32t dmasr = ETH->DMASR; portBASE_TYPE xHigherPriorityTaskWoken; xHigherPriorityTaskWoken = pdFALSE;
ETH->DMASR = dmasr;

if( dmasr & ETH_DMASR_RS )
{
    xSemaphoreGiveFromISR( xEMACRxEventSemaphore, &xHigherPriorityTaskWoken );
}

/* ulInterruptCause is used for convenience here.  A context switch is
wanted, but coding portEND_SWITCHING_ISR( 1 ) would likely result in a
compiler warning. */
portEND_SWITCHING_ISR( xHigherPriorityTaskWoken );
} /———————————————————–/ static void prvEMACHandlerTask( void *pvParameters ) { xNetworkBufferDescriptor_t *pxNetworkBuffer; size_t xBytesReceived; xIPStackEvent_t xRxEvent;
( void )pvParameters;
configASSERT( xEMACRxEventSemaphore );

for( ;; )
{
    /* Wait for the Ethernet MAC interrupt to indicate that another packet
    has been received.  It is assumed xEMACRxEventSemaphore is a counting
    semaphore (to count the Rx events) and that the semaphore has already
    been created. */
    while( xSemaphoreTake( xEMACRxEventSemaphore, portMAX_DELAY ) == pdFALSE );

    /* At least one packet has been received. */
    while( !( g_enet_dma_rx_next_desc->des0 & 0x80000000 ) )
    {
        /* See how much data was received. */
        xBytesReceived = ( size_t )( ( g_enet_dma_rx_next_desc->des0 & 0x3FFF0000 ) >> 16 );

        if( xBytesReceived > 0 )
        {
            /* Allocate a network buffer descriptor that references an Ethernet
            buffer large enough to hold the received data. */
            pxNetworkBuffer = pxNetworkBufferGet( xBytesReceived, 0 )N;
            //led_toggle();

            if( pxNetworkBuffer != NULL )
            {
                /* pxNetworkBuffer->pucEthernetBuffer now points to an Ethernet
                buffer large enough to hold the received data.  Copy the
                received data into pcNetworkBuffer->pucEthernetBuffer. */
                memcpy( ( uint8_t * )pxNetworkBuffer->pucEthernetBuffer, ( uint8_t * )g_enet_dma_rx_next_desc->des2, xBytesReceived );
                pxNetworkBuffer->xDataLength = xBytesReceived;

                /* See if the data contained in the received Ethernet frame needs
                to be processed. */
                if( eConsiderFrameForProcessing( pxNetworkBuffer->pucEthernetBuffer ) == eProcessBuffer )
                {
                    /* The event about to be sent to the IP stack is an Rx event. */
                    xRxEvent.eEventType = eEthernetRxEvent;

                    /* pvData is used to point to the network buffer descriptor that
                    references the received data. */
                    xRxEvent.pvData = ( void * ) pxNetworkBuffer;

                    /* Send the data to the IP stack. */
                    if( xQueueSendToBack( xNetworkEventQueue, &xRxEvent, 0 ) == pdFALSE )
                    {
                        /* The buffer could not be sent to the IP task so the buffer
                        must be released. */
                        vNetworkBufferRelease( pxNetworkBuffer );
                    }
                    else
                    {
                        /* The message was successfully sent to the IP stack. */
                    }
                }
                else
                {
                    /* The Ethernet frame can be dropped, but the Ethernet buffer
                    must be released. */
                    vNetworkBufferRelease( pxNetworkBuffer );
                }
            }
            else
            {
                /* RX event lost */
            }
        }

        g_enet_dma_rx_next_desc->des0 |= 0x80000000;
        g_enet_dma_rx_next_desc = ( enet_dma_desc_t * )g_enet_dma_rx_next_desc->des3;
    }
}
} /———————————————————–/ ~~~

HELP STM Discovery FreeRTOS + UDP

I’m afraid it is a bit tricky to read through all the driver code without also having to look through the STM32 user manuals. When pings stop, are you still getting interrupts from the MAC? Or at leaste still receiving data? If so, you can try following the data through the stack to see how far it gets and if a reply is generated, if not actually sent. There is also a FreeRTOS+TCP example for the STM32 here. This is what FreeRTOS+UDP evolved into, and you can configure the TCP stack to be UDP only by setting ipconfigUSETCP to 0: http://www.freertos.org/FreeRTOS-Plus/FreeRTOSPlusTCP/TCP-IPFATExamplesST_STM32F407.html

HELP STM Discovery FreeRTOS + UDP

Hi.Thaks fot reply. Yes, I’m still getting interrupts from MAC after pings stop. I used a led to find the problem in the code. After pings stops the function pxNetworkBufferGet starts to return NULL, so the UDP try to allocate a descriptor to the received data but can’t. My application will use just UDP protocol, if I set the ipconfigUSE_TCP to 0, FreeRTOS+TCP will work like FreeRTOS+UDP. Best regards.

HELP STM Discovery FreeRTOS + UDP

Just to help if anyone have the same problem. After my post here, my advisor told me to use other heap and see the result. Putting the heap3.c I reached about 400 pings, instead of 12 that I had before. I leave the problem to focus in my application, once that the problem just occur after long time after system startup. This week I have finished my application and returned to look back to find the problem. And after read again my NetworkInterface.c I saw that my problem was memory allocation. My output function in NetworkInterface.c was not releasing the memory after send the packet. As I show below, the problem was that, I don’t know why, I got a line from the zero copy network interface. And there, after send the packet to DMA, you must point the buffer to NULL. But as I am using just the simple network interface implementation, if I set the buffer pointer to NULL, the FreeRTOS + UDP try to release a NULL pointer instead of the buffer address. Removing ~~~ pxNetworkBuffer->pucEthernetBuffer = NULL, ~~~ from xNetworkInterfaceOutput function, my application works fine now. Ps.: When I was looking for the error, I saw that my program always finished in HardFault interruption.

HELP STM Discovery FreeRTOS + UDP

Lucas, I assume that you use BufferAllocation_2.c? That version calls pvPortMalloc() to allocate pucEthernetBuffer. Have you already started using FreeRTOS+TCP? That library can also be used for UDP-only applications. I’m not sure how things worked in the earlier UDP-only version. The same, but a little different sometimes. The following: ~~~~ /* The EMAC now owns the buffer. */ pxNetworkBuffer->pucEthernetBuffer = NULL; ~~~~ can only be done in case the buffer space will be released (freed) after the data have been sent. When vNetworkBufferRelease() will be called, pucEthernetBuffer will be NULL, and vPortFree() will ignore the NULL pointer. But who will finally release the pucEthernetBuffer? Normally a TX-completion interrupt would follow after sending. That would wake-up the prvEMACHandlerTask() function, which will check all DMA TX descriptors. You can have a look at this zero-copy STM32F4 driver. It transfers the ownership of the pxNetworkBuffer to DMA. An interrupt follows, and vClearTXBuffers() will be called. It will take the following steps: ~~~~ /* Get the payload buffer. */ ucPayLoad = ( uint8_t * )DMATxDescToClear->Buffer1Addr;
/* Look-up the Network Buffer that owned this payload. */
pxNetworkBuffer = pxPacketBuffer_to_NetworkBuffer( ucPayLoad );

/* Release the Network buffer, which includes the 'pucEthernetBuffer'. */
vReleaseNetworkBufferAndDescriptor( pxNetworkBuffer ) ;

/* Make sure that this memory space won't be used again. */
DMATxDescToClear->Buffer1Addr = ( uint32_t )0u;
~~~~ Regards.