UART Tx Task Runs Only Once, But UART Rx Task Repeats

Hi !

https:__forums.freertos.org_t_no-tasks-seem-to-run_14326_22

Platform details (hardware, IDE including simulator etc) are the same as from the above post ! (Replace _ with /, since I’m a new user, I can’t insert links ! )

In the following code:

  1. Both tasks are created properly !

  2. The Tx task runs once. I see letters A to X printed to the UART !

    1. taskYIELD() is called. It seems to work !
  3. The Rx task runs. By placing breakpoints, I can verify that it accepts chars from A to X !

    1. taskYIELD() is called. But it doesn’t seem to work !
  4. The Rx task runs again ! (Observations similar to the ones in step 3 are seen.)

  5. The Rx task runs again ! (Observations similar to the ones in step 3 are seen.)

and so on … ! (the Rx task repeats)

To prevent the timer interrupt from interfering:

  1. I’ve made configUSE_TIMERS equal to 0.

  2. I’ve commented prvSetupTimerInterrupt().

But I’m not sure if the Tx task needs the timer ! (Does it ?)

Since the UART code of FreeRTOS did not work for us:

  1. I replaced xSerialPutChar() with uart_printf()

  2. I replaced xSerialGetChar() with UARTReceiveChar()

Both of these functions seem to work ! (Like I’ve mentioned earlier, printing chars to the UART & accepting chars from the UART seem to work !)

Have you seen this issue before ? Please advice. Thanks in advance !

In main() from main.c

vAltStartComTestTasks( mainCOM_TEST_PRIORITY, mainCOM_TEST_BAUD_RATE, mainCOM_TEST_LED );

From comtest.c:

TaskHandle_t *tx_handle;


void vAltStartComTestTasks( UBaseType_t uxPriority,
                            uint32_t ulBaudRate,
                            UBaseType_t uxLED )
{
    /* Initialise the com port then spawn the Rx and Tx tasks. */
    uxBaseLED = uxLED;
    xSerialPortInitMinimal( ulBaudRate, comBUFFER_LEN );

    tx_handle = (TaskHandle_t *) pvPortMalloc(1*sizeof(TaskHandle_t));
    /* The Tx task is spawned with a lower priority than the Rx task. */
    
    // Sid - I've tried 3 priorities for the Tx task: uxPriority - 1, uxPriority & uxPriority + 1
    //       But the Tx task runs just once !
    
    //xTaskCreate( vComTxTask, "COMTx", comSTACK_SIZE, NULL, uxPriority - 1, ( TaskHandle_t * ) NULL );
    xTaskCreate( vComTxTask, "COMTx", comSTACK_SIZE, NULL, uxPriority+1, tx_handle );
    
    xTaskCreate( vComRxTask, "COMRx", comSTACK_SIZE, NULL, uxPriority, ( TaskHandle_t * ) NULL );
}
/*-----------------------------------------------------------*/

static portTASK_FUNCTION( vComTxTask, pvParameters )
{
    unsigned char cByteToSend; //char cByteToSend;
    TickType_t xTimeToWait;

    /* Just to stop compiler warnings. */
    ( void ) pvParameters;

    for( ; ; )
    {
        /* Simply transmit a sequence of characters from comFIRST_BYTE to
         * comLAST_BYTE. */
        for( cByteToSend = comFIRST_BYTE; cByteToSend <= comLAST_BYTE; cByteToSend++ )
        {
            //if( xSerialPutChar( xPort, cByteToSend, comNO_BLOCK ) == pdPASS )
            uart_printf((BYTE *) &cByteToSend, 1);    //if( xSerialPutChar( xPort, cByteToSend, comRX_BLOCK_TIME ) == pdPASS )
            {
                vParTestToggleLED( uxBaseLED + comTX_LED_OFFSET );
            }
        }

        /* Turn the LED off while we are not doing anything. */
        vParTestSetLED( uxBaseLED + comTX_LED_OFFSET, pdFALSE );

        /* We have posted all the characters in the string - wait before
         * re-sending.  Wait a pseudo-random time as this will provide a better
         * test. */
        xTimeToWait = xTaskGetTickCount() + comOFFSET_TIME;

        /* Make sure we don't wait too long... */
        xTimeToWait %= comTX_MAX_BLOCK_TIME;

        /* ...but we do want to wait. */
        if( xTimeToWait < comTX_MIN_BLOCK_TIME )
        {
            xTimeToWait = comTX_MIN_BLOCK_TIME;
        }

        vTaskDelay( xTimeToWait );
        taskYIELD();
    }
} /*lint !e715 !e818 pvParameters is required for a task function even if it is not referenced. */
/*-----------------------------------------------------------*/

static portTASK_FUNCTION( vComRxTask, pvParameters )
{
    unsigned char cExpectedByte, cByteRxed;    //signed char cExpectedByte, cByteRxed;
    BaseType_t xResyncRequired = pdFALSE, xErrorOccurred = pdFALSE;

    /* Just to stop compiler warnings. */
    ( void ) pvParameters;

    for( ; ; )
    {
        /* We expect to receive the characters from comFIRST_BYTE to
         * comLAST_BYTE in an incrementing order.  Loop to receive each byte. */
        for( cExpectedByte = comFIRST_BYTE; cExpectedByte <= comLAST_BYTE; cExpectedByte++ )
        {
            /* Block on the queue that contains received bytes until a byte is
             * available. */
            //if( xSerialGetChar( xPort, &cByteRxed, comRX_BLOCK_TIME ) )
            cByteRxed = UARTReceiveChar(0, 2.0);        // Get a char from port 0, wait up to 2.0 minutes if needed !
            {
                /* Was this the byte we were expecting?  If so, toggle the LED,
                * otherwise we are out on sync and should break out of the loop
                * until the expected character sequence is about to restart. */
                if( cByteRxed == cExpectedByte )
                {
                    vParTestToggleLED( uxBaseLED + comRX_LED_OFFSET );
                }
                else
                {
                    xResyncRequired = pdTRUE;
                    break; /*lint !e960 Non-switch break allowed. */
                }
            }
        }

        /* Turn the LED off while we are not doing anything. */
        vParTestSetLED( uxBaseLED + comRX_LED_OFFSET, pdFALSE );

        /* Did we break out of the loop because the characters were received in
         * an unexpected order?  If so wait here until the character sequence is
         * about to restart. */
        if( xResyncRequired == pdTRUE )
        {
            while( cByteRxed != comLAST_BYTE )
            {
                cByteRxed = UARTReceiveChar(0, 2.0);
                /* Block until the next char is available. */
                //xSerialGetChar( xPort, &cByteRxed, comRX_BLOCK_TIME );
            }

            /* Note that an error occurred which caused us to have to resync.
             * We use this to stop incrementing the loop counter so
             * sAreComTestTasksStillRunning() will return false - indicating an
             * error. */
            xErrorOccurred++;

            /* We have now resynced with the Tx task and can continue. */
            xResyncRequired = pdFALSE;
        }
        else
        {
            if( xErrorOccurred < comTOTAL_PERMISSIBLE_ERRORS )
            {
                /* Increment the count of successful loops.  As error
                 * occurring (i.e. an unexpected character being received) will
                 * prevent this counter being incremented for the rest of the
                 * execution.   Don't worry about mutual exclusion on this
                 * variable - it doesn't really matter as we just want it
                 * to change. */
                uxRxLoops++;
            }
        }
        taskYIELD();
    }
} /*lint !e715 !e818 pvParameters is required for a task function even if it is not referenced. */

There is no FreeRTOS UART code. FreeRTOS comes without any platform specific drivers. Where did you get the code from ?

Is rather useless since vTaskDelay blocks the calling task and schedules the next ready task anyway.
Also what’s the purpose of explicitely calling taskYIELD() ?
I doubt that it does what you seem to expect…

This
tx_handle = (TaskHandle_t *) pvPortMalloc(1*sizeof(TaskHandle_t));
is a also not really needed since a handle is just a pointer.
Hint: Better check the return code of functions (like xTaskCreate) and don’t assume that they’re never failing.

BTW configUSE_TIMERS has nothing to do with any HW timer interrupt.
The timer task uses the SysTick. And without any timer added it would be just idle.

Looks like there is something wrong in your Rx buffer management. Without seeing the corresponding ISR code, we can only guess.

Hi Hartmut ! Thanks ! Your observation about vTaskDelay() & taskYIELD() solved my problem ! Details follow …

In the post from the link I gave, I’ve mentioned that:

  1. I used the following folder !

“FreeRTOSv202112.00\FreeRTOS\Demo\ARM7_LPC2129_Keil_RVDS”

  1. I’m trying to port this code to the LPC2368 !

Based on your observation about vTaskDelay() & taskYIELD():

  1. I commented out the vTaskDelay() statement & used taskYIELD() alone.

  2. Now when both the Tx task & Rx task have equal priority, they switch as expected !

Without the pvPortMalloc(), tx_handle was assigned to NULL. So it seemed like it went in as NULL & came out as NULL (xTaskCreate() assumes we have no use for it when it’s passed in as NULL. So probably, xTaskCreate() leaves it alone) !

Since I’ve seen tasks run in the simulator, I’ve not yet had the need to check the result of xTaskCreate() !

I don’t understand your remarks about configUSE_TIMERS & ticks ! May need to study the relevant code some more !

Regarding the task handle usage with xTaskCreate just read/follow the example code to see how it’s done right.
And … check the return codes :wink:
Good luck !