跳转至

Interface

FreeRTOS 可以被认为是一个线程库而不是一个操作系统。

事实上,FreeRTOS 本身根本没有文件系统。

不过,它拥有众多的附加库,例如 Lab-Project-FreeRTOS-POSIX 与 Lab-Project-FreeRTOS-FAT,其中 Lab-Project-FreeRTOS-POSIX 提供了如何为 C POSIX Library 提供支持的思路。

从 Github 复制这两个库:

git clone git@github.com:FreeRTOS/Lab-Project-FreeRTOS-POSIX.git 
git clone git@github.com:FreeRTOS/Lab-Project-FreeRTOS-FAT.git 

已提供的 C POSIX Library 接口

Lab-Project-FreeRTOS-POSIX 已经提供的 C POSIX Library 有:

要在项目中采用 FreeRTOS+POSIX,需要这些头文件以进行移植。

FreeRTOS platform-specific POSIX configuration High-Level Description
FreeRTOS_POSIX.h. This header file brings in dependencies required by FreeRTOS+POSIX. This file must be included before all other FreeRTOS+POSIX includes.
FreeRTOS_POSIX_portable_default.h Defaults for port-specific configuration of FreeRTOS+POSIX.
FreeRTOS_POSIX_portable.h Port-specific configuration overwrite of FreeRTOS+POSIX. As an example, /lib/FreeRTOS-Plus-POSIX/include/portable/pc/windows/FreeRTOS_POSIX_portable.h, Windows simulator uses the defaults, thus does not need to overwrite anything.

相似的,若要使用其他 C POSIX Library 中的头文件时,也需要对其进行更改。

事实上,使用 POSIX Library 接口的主要目的是可以更便利地利用已有的在此基础上开发的 C 应用程序。在此项目中,由于只需要完成虚拟文件系统开发以及对文件系统的支持,很少或不涉及移植应用程序,因此不必要考虑进行进一步移植接口。

若必须使用 C POSIX Library,可以参考 FreeRTOS/FreeRTOS-Kernel/portable/ThirdParty/GCC/Posix/portmacro.h

现有接口

以下仅为部分可能需要调用的系统函数。这些系统函数足以完成一个简易的虚拟文件系统。但是由于 FreeRTOS 并没有复杂的内存管理机制,故类似 Linux VFS 的一些优化功能可能实现比较困难。

pcPortMalloc()

FreeRTOS/FreeRTOS-Kernel/portable/MemMang/heap_1.c

void * pvPortMalloc( size_t xWantedSize )
{
  void * pvReturn = NULL;
  static uint8_t * pucAlignedHeap = NULL;

  /* Ensure that blocks are always aligned. */
  #if ( portBYTE_ALIGNMENT != 1 )
  {
      if( xWantedSize & portBYTE_ALIGNMENT_MASK )
      {
          /* Byte alignment required. Check for overflow. */
          if( ( xWantedSize + ( portBYTE_ALIGNMENT - ( xWantedSize & portBYTE_ALIGNMENT_MASK ) ) ) > xWantedSize )
          {
              xWantedSize += ( portBYTE_ALIGNMENT - ( xWantedSize & portBYTE_ALIGNMENT_MASK ) );
          }
          else
          {
              xWantedSize = 0;
          }
      }
  }
  #endif /* if ( portBYTE_ALIGNMENT != 1 ) */

  vTaskSuspendAll();
  {
      if( pucAlignedHeap == NULL )
      {
          /* Ensure the heap starts on a correctly aligned boundary. */
          pucAlignedHeap = ( uint8_t * ) ( ( ( portPOINTER_SIZE_TYPE ) & ucHeap[ portBYTE_ALIGNMENT - 1 ] ) & ( ~( ( portPOINTER_SIZE_TYPE ) portBYTE_ALIGNMENT_MASK ) ) );
      }

      /* Check there is enough room left for the allocation and. */
      if( ( xWantedSize > 0 ) &&                                /* valid size */
          ( ( xNextFreeByte + xWantedSize ) < configADJUSTED_HEAP_SIZE ) &&
          ( ( xNextFreeByte + xWantedSize ) > xNextFreeByte ) ) /* Check for overflow. */
      {
          /* Return the next free byte then increment the index past this
           * block. */
          pvReturn = pucAlignedHeap + xNextFreeByte;
          xNextFreeByte += xWantedSize;
      }

      traceMALLOC( pvReturn, xWantedSize );
  }
  ( void ) xTaskResumeAll();

  #if ( configUSE_MALLOC_FAILED_HOOK == 1 )
  {
      if( pvReturn == NULL )
      {
          vApplicationMallocFailedHook();
      }
  }
  #endif

  return pvReturn;
}

FreeRTOS/FreeRTOS-Kernel/portable/MemMang/heap_2.c

void vPortFree( void * pv )
{
    uint8_t * puc = ( uint8_t * ) pv;
    BlockLink_t * pxLink;

    if( pv != NULL )
    {
        /* The memory being freed will have an BlockLink_t structure immediately
         * before it. */
        puc -= heapSTRUCT_SIZE;

        /* This unexpected casting is to keep some compilers from issuing
         * byte alignment warnings. */
        pxLink = ( void * ) puc;

        configASSERT( heapBLOCK_IS_ALLOCATED( pxLink ) != 0 );
        configASSERT( pxLink->pxNextFreeBlock == NULL );

        if( heapBLOCK_IS_ALLOCATED( pxLink ) != 0 )
        {
            if( pxLink->pxNextFreeBlock == NULL )
            {
                /* The block is being returned to the heap - it is no longer
                 * allocated. */
                heapFREE_BLOCK( pxLink );
                #if ( configHEAP_CLEAR_MEMORY_ON_FREE == 1 )
                {
                    ( void ) memset( puc + heapSTRUCT_SIZE, 0, pxLink->xBlockSize - heapSTRUCT_SIZE );
                }
                #endif

                vTaskSuspendAll();
                {
                    /* Add this block to the list of free blocks. */
                    prvInsertBlockIntoFreeList( ( ( BlockLink_t * ) pxLink ) );
                    xFreeBytesRemaining += pxLink->xBlockSize;
                    traceFREE( pv, pxLink->xBlockSize );
                }
                ( void ) xTaskResumeAll();
            }
        }
    }
}

Note: 在 FreeRTOS 内核,有 5 个堆,每个堆各有自己的申请内存空间函数,具体参考:https://www.freertos.org/a00111.html。

FreeRTOS/FreeRTOS-Kernel/tasks.c

在该文件中,有管理任务的系统函数。

void * pvTaskGetThreadLocalStoragePointer( TaskHandle_t xTaskToQuery,
                                               BaseType_t xIndex )
{
    void * pvReturn = NULL;
    TCB_t * pxTCB;

    if( ( xIndex >= 0 ) &&
        ( xIndex < configNUM_THREAD_LOCAL_STORAGE_POINTERS ) )
    {
        pxTCB = prvGetTCBFromHandle( xTaskToQuery );
        pvReturn = pxTCB->pvThreadLocalStoragePointers[ xIndex ];
    }
    else
    {
        pvReturn = NULL;
    }

    return pvReturn;
}
BaseType_t xTaskGetSchedulerState( void )
{
    BaseType_t xReturn;

    if( xSchedulerRunning == pdFALSE )
    {
        xReturn = taskSCHEDULER_NOT_STARTED;
    }
    else
    {
        if( uxSchedulerSuspended == ( UBaseType_t ) pdFALSE )
        {
            xReturn = taskSCHEDULER_RUNNING;
        }
        else
        {
            xReturn = taskSCHEDULER_SUSPENDED;
        }
    }

    return xReturn;
}

Run FreeRTOS

Building and executing the demo application - GCC Makefile

  1. Ensure both the arm-none-eabi-gcc compiler and GNU make utility is installed on your host machine.

  2. Open FreeRTOS/Demo/CORTEX_MPS2_QEMU_IAR_GCC/main.c, and set mainCREATE_SIMPLE_BLINKY_DEMO_ONLY to generate either the simply blinky demo, or the comprehensive test and demo application, as required.

  3. Open a command prompt and navigate to the FreeRTOS/Demo/CORTEX_MPS2_QEMU_IAR_GCC/build/gcc directory.

  4. Type "make" in the command prompt. The project should build without any compiler errors or warnings. Hint: Use the "-j" parameter to speed the compilation by using more cores on your host computer. For example, if you have four cores available you can build four C files at once by entering "make -j4". A successful build creates the elf file FreeRTOS/Demo/CORTEX_MPS2_QEMU_IAR_GCC/build/gcc/output/RTOSDemo.out

  5. Ensure QEMU is installed on your host computer.

  6. Start QEMU with the following command line, replacing [path-to] with the correct path to the RTOSDemo.out

file generated by the GCC build.

qemu-system-arm -machine mps2-an385 -cpu cortex-m3 -kernel [path-to]/RTOSDemo.out -monitor none -nographic -serial stdio -s -S

QEMU command line

Omit the "-s -S" if you just want to run the FreeRTOS application in QEMU without attaching the debugger.

  1. You can now use arm-none-eabi-gdb to start a command line debug session, although my preference is to start a graphical debug session, as described next for those using the Eclipse IDE.