FreeRTOS Learning: Data Types and Coding Style

Scan to FollowLearn Embedded Together, learn and grow together

FreeRTOS Learning: Data Types and Coding Style

FreeRTOS defines its own set of data types primarily to ensure portability across different processor architectures and compilers.

These data types are defined in the <span>portmacro.h</span> file, and the specific implementation will be adjusted according to different compilers and processors.

Basic Data Types

FreeRTOS defines the following basic data types:

Type Description
TickType_t Used for system tick counting, typically defined as <span>uint32_t</span> (16-bit systems may use <span>uint16_t</span>)
BaseType_t The most basic integer data type, usually the most efficient integer for the processor (typically int)
UBaseType_t The unsigned version of BaseType_t
StackType_t Data type used for task stacks, typically <span>uint32_t</span>
size_t size_t from the standard C library
configMAX_SYSCALL_INTERRUPT_PRIORITY Defines the highest interrupt priority that can call FreeRTOS API

Special Data Types

Type Description
TaskHandle_t Task handle, which is actually a pointer to the task control block (TCB)
QueueHandle_t Queue handle, a pointer to the queue structure
SemaphoreHandle_t Semaphore handle, which is actually an alias for QueueHandle_t
TimerHandle_t Software timer handle
EventGroupHandle_t Event group handle
StreamBufferHandle_t Stream buffer handle
MessageBufferHandle_t Message buffer handle

Example of Data Type Definitions

In the FreeRTOS source code, these types are typically defined as follows:

#define portCHAR        char
#define portFLOAT       float
#define portDOUBLE      double
#define portLONG        long
#define portSHORT       short
#define portSTACK_TYPE  uint32_t
#define portBASE_TYPE   long

typedef portSTACK_TYPE StackType_t;
typedef long BaseType_t;
typedef unsigned long UBaseType_t;

Coding Style

FreeRTOS has a very consistent coding style that runs throughout the project, making the code easy to read and maintain.

Naming Conventions

FreeRTOS adopts a strict naming convention:

  1. Variable Naming:

    Example:

    BaseType_t xResult;
    char cByte;
    uint8_t ucCount;
    void *pvBuffer;
    
  • <span>x</span>: Non-standard types (e.g., <span>BaseType_t</span>, <span>TickType_t</span>, etc.)
  • <span>c</span>: Character type
  • <span>s</span>: String
  • <span>uc</span>: Unsigned character
  • <span>p</span>: Pointer
  • <span>pc</span>: Pointer to character
  • <span>ul</span>: Unsigned long
  • <span>v</span>: void
  • Variable names use lowercase letters
  • Multiple words are separated by underscores
  • The prefix indicates the variable type or purpose:
  • Function Naming:

    Example:

    void vTaskDelete(TaskHandle_t xTask);
    BaseType_t xQueueSend(QueueHandle_t xQueue, const void *pvItemToQueue, TickType_t xTicksToWait);
    void *pvPortMalloc(size_t xSize);
    
    • <span>v</span>: void return type
    • <span>x</span>: returns BaseType_t
    • <span>pv</span>: returns void pointer
    • <span>vTask</span>: Task related
    • <span>xQueue</span>: Queue related
    • <span>vSemaphore</span>: Semaphore related
    • <span>pvPortMalloc</span>: Memory management related
    • Use prefixes to indicate the module to which the function belongs:
    • The prefix is followed by the action and object, using camel case naming
    • The return type is also reflected in the naming:
  • Macro Naming:

    Example:

    #define configUSE_PREEMPTION        1
    #define pdTRUE                     (1)
    #define errQUEUE_FULL              (0)
    
    • <span>config</span>: Macros in the configuration file
    • <span>pd</span> (port dependent): Macros related to portability
    • <span>err</span>: Error codes
    • All uppercase
    • Words are separated by underscores
    • The prefix indicates the module to which it belongs:

    Coding Style

    1. Indentation and Braces:

      Example:

      if( xCondition == pdTRUE )
      {
          /* Indent 4 spaces */
          vFunction();
      }
      
    • Use 4 spaces for indentation
    • The opening brace is on the same line as the statement
    • The closing brace is on a new line, aligned with the starting statement
  • Comment Style:

    Example:

    /*
     * Create a new task and add it to the ready task list.
     *
     * @param pxTaskCode Task function pointer
     * @param pcName Descriptive name of the task
     * @param usStackDepth Task stack size (in words)
     * @param pvParameters Parameters passed to the task
     * @param uxPriority Task priority
     * @param pxCreatedTask Used to return the task handle
     * @return Returns pdPASS on success, error code on failure
     */
    BaseType_t xTaskCreate( TaskFunction_t pxTaskCode,
                            const char * const pcName,
                            const uint16_t usStackDepth,
                            void * const pvParameters,
                            UBaseType_t uxPriority,
                            TaskHandle_t * const pxCreatedTask );
    
    • Use standard C comments (/* */)
    • Important parts use multi-line comments
    • Function header comments describe functionality, parameters, and return values
  • Code Layout:

    Example:

    xQueue = xQueueCreate(
                uxQueueLength,
                uxItemSize
            );
    
    • If function parameters are too long, they are displayed on separate lines, each parameter on its own line
    • Spaces around operators
    • Spaces after commas

    Specific Coding Habits

    1. Return Value Check:

      Example:

      if( xQueueSend( xQueue, &amp;xData, xTicksToWait ) != pdPASS )
      {
          /* Error handling */
      }
      
    • FreeRTOS functions typically return <span>pdPASS</span> or <span>pdFAIL</span>
    • Error codes are typically defined as macros
  • Critical Section Protection:

    Example:

    taskENTER_CRITICAL();
    {
        /* Critical section code */
    }
    taskEXIT_CRITICAL();
    
    • Use macros to enter and exit critical sections
    • Keep critical sections as short as possible
  • Assertions:

    Example:

    configASSERT( xQueue != NULL );
    
    • Use the <span>configASSERT()</span> macro for runtime checks
    • Enabled during development, can be disabled in production

    Example Code Analysis

    Below is a typical FreeRTOS task creation code that demonstrates data types and coding style:

    /* Task function prototype */
    void vTaskFunction( void *pvParameters );
    
    /* Task handle */
    TaskHandle_t xHandle = NULL;
    
    /* Create task */
    BaseType_t xReturned = xTaskCreate(
        vTaskFunction,       /* Task function pointer */
        "Demo Task",         /* Task name */
        configMINIMAL_STACK_SIZE, /* Stack size */
        NULL,                /* Parameters passed to the task */
        tskIDLE_PRIORITY + 1, /* Task priority */
        &amp;xHandle             /* Return task handle */
    );
    
    /* Check if task was created successfully */
    if( xReturned == pdPASS )
    {
        /* Task created successfully */
        vTaskStartScheduler(); /* Start scheduler */
    }
    else
    {
        /* Handle error */
        for( ;; );
    }
    
    /* Task implementation */
    void vTaskFunction( void *pvParameters )
    {
        TickType_t xLastWakeTime;
        const TickType_t xFrequency = pdMS_TO_TICKS( 1000 ); /* 1 second period */
        
        /* Initialize variable */
        xLastWakeTime = xTaskGetTickCount();
        
        for( ;; )
        {
            /* Task functionality code */
            
            /* Delay until next period */
            vTaskDelayUntil( &amp;xLastWakeTime, xFrequency );
        }
    }
    

    Porting Related Data Types

    When porting FreeRTOS to different platforms, special attention should be paid to the following data types and macro definitions:

    1. Defined in portmacro.h:
    • Processor-specific data types
    • Macros for entering/exiting critical sections
    • Macros related to task switching
    • Definitions related to system ticks
  • Implemented in port.c:
    • Stack initialization
    • Starting the first task
    • System tick timer configuration
    • Context switching

    Conclusion

    The design of FreeRTOS’s data types and coding style has the following characteristics:

    1. Portability: Ensures compatibility across different platforms through custom data types
    2. Consistency: Strict naming rules and coding style make the code easy to read and maintain
    3. Clarity: Naming prefixes clearly express the type and purpose of variables and functions
    4. Efficiency: Choosing the most suitable base data types for the target processor to improve efficiency

    Understanding and following FreeRTOS’s data types and coding style is crucial for developing high-quality FreeRTOS applications, especially when porting to different platforms or collaborating with teams.

    This consistent style also makes the FreeRTOS source code itself an excellent example for learning embedded real-time system programming.

    FreeRTOS Learning: Data Types and Coding Style

    Follow 【Learn Embedded Together】 to become better together

    If you find this article helpful, click “Share”, “Like”, or “Recommend”!

    Leave a Comment