Select Page

FreeRTOS Exercise Lab31 From EdWiki

Write FreeRTOS aware UART Driver Library

FreeRTOS Exercise Lab31

The pseudo code shown in the following Listing which provides the outline of an FreeRTOS aware function that transmits data on a UART port.

  • xUART is a structure that describes the UART peripheral, and holds state information.
  • The xUART_Send() function does not include any mutual exclusion logic. If more than one task is going to use the xUART_Send() function, then the application writer will have to manage mutual exclusion within the application itself. For example, a task may be required to obtain a mutex before calling xUART_Send().

UART Transmit functions

/* Driver library function to send data to a UART. */
BaseType_t xUART_Send( xUART *pxUARTInstance, uint8_t *pucDataSource, size_t uxLength )
{
    BaseType_t xReturn;
 
    /* Save the handle of the task that called this function. */
       pxUARTInstance->xTaskToNotify = xTaskGetCurrentTaskHandle();
 
    /* Ensure the calling task does not already have a notification pending by calling
     * ulTaskNotifyTake() with the xClearCountOnExit parameter set to pdTRUE, and a block
     * time of 0 (don't block). */
     ulTaskNotifyTake( pdTRUE, 0 );
 
     /* Start the transmission. */
     UART_low_level_send(pxUARTInstance, pucDataSource, uxLength);
 
     /* Block until notified that the transmission is complete. If the notification is
      * received then xReturn will be set to 1 because the ISR will have incremented this
      * task's notification value to 1 (pdTRUE). If the operation times out then xReturn
      * will be 0 (pdFALSE) because this task's notification value will not have been changed
      * since it was cleared to 0 above.
      * Note that, if the ISR executes between the calls to UART_low_level_send() and the call to
      * ulTaskNotifyTake(), then the event will be latched in the task’s notification value, and the
      * call to ulTaskNotifyTake() will return immediately.
      */
      xReturn = (BaseType_t) ulTaskNotifyTake(pdTRUE, pxUARTInstance->xTxTimeout);
 
      return xReturn;
}
 
/* The ISR that executes after the last byte has been sent to the UART. */
void xUART_TransmitEndISR( xUART *pxUARTInstance )
{
    BaseType_t xHigherPriorityTaskWoken = pdFALSE;
 
    /* This function should not execute unless there is a task waiting to be notified. */
 
     /* Clear the interrupt. */
     UART_low_level_interrupt_clear(pxUARTInstance);
 
     /* Send a notification directly to the task that called xUART_Send(). If the task
      * is Blocked waiting for the notification then the task will be removed from the
      * Blocked state. */
      vTaskNotifyGiveFromISR(pxUARTInstance->xTaskToNotify, &xHigherPriorityTaskWoken);
 
      /* Now there are no tasks waiting to be notified. Set the xTaskToNotify member of the xUART
       * structure back to NULL. This step is not strictly necessary but will aid debugging. */
      pxUARTInstance->xTaskToNotify = NULL;
      portYIELD_FROM_ISR(xHigherPriorityTaskWoken);
}

UART Receive functions

/* Driver library function to receive data from a UART. */
size_t xUART_Receive( xUART *pxUARTInstance, uint8_t *pucBuffer, size_t uxWantedBytes )
{
    size_t uxReceived = 0;
    TickType_t xTicksToWait;
    TimeOut_t xTimeOut;
 
    /* Record the time at which this function was entered. */
    vTaskSetTimeOutState(&xTimeOut);
 
    /* xTicksToWait is the timeout value - it is initially set to the maximum receive
     * timeout for this UART instance. */
     xTicksToWait = pxUARTInstance->xRxTimeout;
 
    /* Save the handle of the task that called this function. */
    pxUARTInstance->xTaskToNotify = xTaskGetCurrentTaskHandle();
 
    /* Loop until the buffer contains the wanted number of bytes, or a timeout occurs. */
    while( UART_bytes_in_rx_buffer(pxUARTInstance) < uxWantedBytes ) {
        /* Look for a timeout, adjusting xTicksToWait to account for the time spent in this
           function so far. */
        if( xTaskCheckForTimeOut(&xTimeOut, &xTicksToWait) != pdFALSE ) {
            /* Timed out before the wanted number of bytes were available, exit the loop. */
            break;
        }
 
        /* The receive buffer does not yet contain the required amount of bytes. Wait for a
         * maximum of xTicksToWait ticks to be notified that the receive interrupt service
         * routine has placed more data into the buffer. It does not matter if the calling
         * task already had a notification pending when it called this function, if it did, it
         * would just iteration around this while loop one extra time.
         */
         ulTaskNotifyTake(pdTRUE, xTicksToWait);
    }
 
    /* No tasks are waiting for receive notifications, so set xTaskToNotify back to NULL. */
    pxUARTInstance->xTaskToNotify = NULL;
 
    /* Attempt to read uxWantedBytes from the receive buffer into pucBuffer. The actual
     * number of bytes read (which might be less than uxWantedBytes) is returned. */
    uxReceived = UART_read_from_receive_buffer(pxUARTInstance, pucBuffer, uxWantedBytes);
 
    return uxReceived;
}
 
/* The interrupt service routine for the UART's receive interrupt */
void xUART_ReceiveISR( xUART *pxUARTInstance )
{
    BaseType_t xHigherPriorityTaskWoken = pdFALSE;
 
    /* Copy received data into this UART's receive buffer and clear the interrupt. */
    UART_low_level_receive(pxUARTInstance);
 
    /* If a task is waiting to be notified of the new data then notify it now. */
    if( pxUARTInstance->xTaskToNotify != NULL ) {
        vTaskNotifyGiveFromISR(pxUARTInstance->xTaskToNotify, &xHigherPriorityTaskWoken);
        portYIELD_FROM_ISR(xHigherPriorityTaskWoken);
    }
}
  • The xUART_Receive() function does not include any mutual exclusion logic. If more than one task is going to use the xUART_Receive() function, then the application writer will have to manage mutual exclusion within the application itself. For example, a task may be required to obtain a mutex before calling xUART_Receive().
  • The UART’s receive interrupt service routine places the characters that are received by the UART into a RAM buffer. The xUART_Receive() function returns characters from the RAM buffer.
  • The xUART_Receive() uxWantedBytes parameter is used to specify the number of characters to receive. If the RAM buffer does not already contain the requested number characters, then the calling task is placed into the Blocked state to wait to be notified that the number of characters in the buffer has increased. The while() loop is used to repeat this sequence until either the receive buffer contains the requested number of characters, or a timeout occurs.
  • The calling task may enter the Blocked state more than once. The block time is therefore adjusted to take into account the amount of time that has already passed since xUART_Receive() was called. The adjustments ensure the total time spent inside xUART_Receive() does not exceed the block time specified by the xRxTimeout member of the xUART structure. The block time is adjusted using the FreeRTOS vTaskSetTimeOutState() and xTaskCheckForTimeOut() helper functions.