Monitoring EMAC-task in FreeRTOS+TCP on STM32H745ZI to Feed Watchdog

Hello,

I am working on an STM32H745ZI project using FreeRTOS Kernel V11.1.0 and FreeRTOS+TCP V4.2.2. I need to monitor the EMAC-task created by the FreeRTOS+TCP layer in the NetworkInterface.c file located in the STM32Hxx folder. My goal is to ensure this task is running properly and to feed the watchdog.

However, I am facing an issue where the EMAC-task might fail, but it does not trigger any events, making it difficult to handle. Could you provide guidance or examples on how to effectively monitor this task and ensure it feeds the watchdog correctly?

Any help or insights on this matter would be greatly appreciated.

Thank you!

Hi @Kerem ,
The solution is going to be dependent upon your overall architecture but a common solution is to put the watchdog update in the idle task. This can be easily done by adding a function. vApplicationIdleHook() to your application. The idle hook will run when all the higher priority tasks are blocked or sleeping.
For more information about the idle hook, you can take a look at this page FreeRTOS - RTOS hook (callback) functions for task stack overflows, tick interrupts, idle task, daemon task startup, and malloc failure (pvPortMalloc() returning NULL)

1 Like

I assume you are talking about this task - FreeRTOS-Plus-TCP/source/portable/NetworkInterface/STM32Hxx/NetworkInterface.c at main · FreeRTOS/FreeRTOS-Plus-TCP · GitHub.

If yes, one possible solution to feed watchdog from this task can be to add a macro ipconfigEMAC_HANDLER_TASK_COMPLETED_ONE_ITERATION in this function which you can override in FreeRTOSIPConfig.h:

#ifndef ipconfigEMAC_HANDLER_TASK_COMPLETED_ONE_ITERATION
    #define ipconfigEMAC_HANDLER_TASK_COMPLETED_ONE_ITERATION()
#endif

static void prvEMACHandlerTask( void * pvParameters )
{
/* When sending a packet, all descriptors in the transmission channel may
 * be occupied.  In stat case, the program will wait (block) for the counting
 * semaphore. */
    const TickType_t ulMaxBlockTime = pdMS_TO_TICKS( 100U );

    #if ( ipconfigHAS_PRINTF != 0 )
        size_t uxTXDescriptorsUsed = 0U;
        size_t uxRXDescriptorsUsed = ETH_RX_DESC_CNT;
    #endif

    ( void ) pvParameters;

    for( ; ; )
    {
        BaseType_t xResult = 0;

        #if ( ipconfigHAS_PRINTF != 0 )
        {
            size_t uxUsed;
            size_t uxOwnCount;

            /* Call a function that monitors resources: the amount of free network
             * buffers and the amount of free space on the heap.  See FreeRTOS_IP.c
             * for more detailed comments. */
            vPrintResourceStats();

            /* Some more statistics: number of free descriptors. */
            uxUsed = ETH_TX_DESC_CNT - uxSemaphoreGetCount( xTXDescriptorSemaphore );

            if( uxTXDescriptorsUsed < uxUsed )
            {
                uxTXDescriptorsUsed = uxUsed;
                FreeRTOS_printf( ( "TX descriptors %u/%u\n",
                                   uxTXDescriptorsUsed,
                                   ETH_TX_DESC_CNT ) );
            }

            uxOwnCount = uxGetOwnCount( &( xEthHandle ) );

            if( uxRXDescriptorsUsed > uxOwnCount )
            {
                uxRXDescriptorsUsed = uxOwnCount;
                FreeRTOS_printf( ( "RX descriptors %u/%u\n",
                                   uxRXDescriptorsUsed,
                                   ETH_RX_DESC_CNT ) );
            }
        }
        #endif /* ( ipconfigHAS_PRINTF != 0 ) */

        ulTaskNotifyTake( pdFALSE, ulMaxBlockTime );

        /* Wait for the Ethernet MAC interrupt to indicate that another packet
         * has been received. */
        if( ( ulISREvents & EMAC_IF_RX_EVENT ) != 0U )
        {
            vClearOptionBit( &( ulISREvents ), EMAC_IF_RX_EVENT );
            xResult = prvNetworkInterfaceInput();
        }

        /* When a packet has been transmitted, the descriptor must be
         * prepared for a next transmission.
         * When using zero-copy, the network buffer must be released
         * ( i.e. returned to the pool of network buffers ). */

        if( ( ulISREvents & EMAC_IF_TX_EVENT ) != 0U )
        {
            vClearOptionBit( &( ulISREvents ), EMAC_IF_TX_EVENT );

            if( xSemaphoreTake( xTransmissionMutex, 10000U ) != pdFAIL )
            {
                ETH_Clear_Tx_Descriptors( &( xEthHandle ) );
                xSemaphoreGive( xTransmissionMutex );
            }
        }

        /* Some error has occurred, possibly an overflow or an underflow. */
        if( ( ulISREvents & EMAC_IF_ERR_EVENT ) != 0U )
        {
            vClearOptionBit( &( ulISREvents ), EMAC_IF_ERR_EVENT );

            xEthHandle.gState = HAL_ETH_STATE_READY;
            /* Enable all interrupts */
            HAL_ETH_Start_IT( &( xEthHandle ) );
            xResult += prvNetworkInterfaceInput();
        }

        if( xPhyCheckLinkStatus( &xPhyObject, xResult ) != pdFALSE )
        {
            /*
             * The function xPhyCheckLinkStatus() returns pdTRUE if the
             * Link Status has changes since it was called the last time.
             */
            if( xSTM32H_GetPhyLinkStatus( pxMyInterface ) == pdFALSE )
            {
                /* Stop the DMA transfer. */
                HAL_ETH_Stop_IT( &( xEthHandle ) );
                /* Clear the Transmit buffers. */
                memset( &( DMATxDscrTab ), '\0', sizeof( DMATxDscrTab ) );
                /* Since the link is down, clear the descriptors. */
                ETH_Clear_Tx_Descriptors( &( xEthHandle ) );
            }
            else
            {
                /* Something has changed to a Link Status, need re-check. */
                prvEthernetUpdateConfig( pdFALSE );
            }
        }

        ipconfigEMAC_HANDLER_TASK_COMPLETED_ONE_ITERATION();
    }
}

Would this work for you?

1 Like

Thank you for your suggestion and interest.

Yes, this works for me.
Thank you

Thanks for reporting back.

1 Like

Hi again @karahulx @aggarg @htibosch
I have revised the NetworkInterface.c file and added a macro and overridden this macro in the FreeRTOSIPConfig.h file. This allows me to monitor the EMAC task functionality. I can implement this for the STM32H7xx port included in the FreeRTOS+TCP library.

Feel free to raise a PR to upstream this change.