歡迎您光臨本站 註冊首頁

· RTOS與linux區別雜誌閱讀

在Linux下實現FreeRTOS的簡單模擬器

admin @ 2019-05-23 reply:0
FreeRTOS的官方提供了一個在Linux下的Simulator的示例,但是用的Kernel的版本非常老,是V6的版本,FreeRTOS現在已經進化到V10了,作為一個標準碼農,不用最新版本簡直不舒服斯基 >_<。
先把官方示例下載下來,在官方示例中,有一個Debug和Release的目錄,在這兩個目錄下使用make all命令就可以直接編出來可執行文件在Linux下直接運行,當然,使用Eclipse直接打開對應的工程來編譯也是可以的。
更新Kernel

先創建一個文件夾Simulator_Linux,其下有三個目錄

FreeRTOS_Kernel
inc
src

    1
    2
    3

FreeRTOS_Kernel中保存內核代碼,inc和src保存APP的代碼,當然,可以按照自己的愛好自行調整目錄結構。

再去FreeRTOS官網下載最新的Kernel代碼,解壓後進入FreeRTOS\Source目錄。
按照官方的示例,將最新的代碼拷貝到FreeRTOS_Kernel目錄中。
include目錄中的頭文件不管三七二十一全拷貝過來即可(我懶,不想一個個去梳理>_<)。
.c文件只需要拷貝croutine.c, list.c, queue.c以及tasks.c即可。(croutine其實也可以不用拷貝,但是要做一些配置)
portable文件夾不從FreeRTOS\Source拷貝,而從simulator的示例中拷貝(\Posix_GCC_Simulator\FreeRTOS_Posix\FreeRTOS_Kernel)

退回到上層目錄,在將官方示例的simulator的根目錄下的FreeRTOSConfig.h拷貝到inc目錄下。
在src目錄下創建main.c文件,在其中定義一個空的main函數即可。

此時,我們就擁有了一個完整的Kernel的代碼,當然這個時候還是沒法編譯的,一來缺少makefile,二來portable的文件與最新的Kernel其實並不完全匹配。當然,APP的代碼也就是main函數的代碼也還是空的。
Makefile

參考官方示例的makefile,在根目錄下創建Makefile文件,同樣在子目錄下也包含兩個subdir.mk用來編譯需要的對應的.o,具體不再贅述:
Makefile:

RM := rm -rf

PROJ_ROOT  :=.
BUILD_TMP  :=$(PROJ_ROOT)/tmp
TARGET_INC := -I$(PROJ_ROOT)/inc \
              -I$(PROJ_ROOT)/FreeRTOS_Kernel/include \
              -I$(PROJ_ROOT)/FreeRTOS_Kernel/portable/GCC/Posix

-include subdir.mk
-include FreeRTOS_Kernel/subdir.mk

ifneq ($(MAKECMDGOALS),clean)
ifneq ($(strip $(C_DEPS)),)
-include $(C_DEPS)
endif
endif

all:simulator_linux.bin

simulator_linux.bin: $(OBJS)
    @echo 'Building target: $@'
    gcc -pthread -lrt -o"simulator_linux.bin" $(OBJS) $(LIBS)
    @echo 'Finished building target: $@'
    @echo ' '

clean:
    -$(RM) $(OBJS)$(C_DEPS)$(EXECUTABLES) simulator_linux.bin
    -@echo ' '

.PHONY: all clean dependents
.SECONDARY:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31

subdir.mk:

C_SRCS += \
$(PROJ_ROOT)/src/main.c

OBJS += \
$(BUILD_TMP)/main.o

C_DEPS += \
$(BUILD_TMP)/main.d

# Each subdirectory must supply rules for building sources it contributes
$(BUILD_TMP)/%.o: $(PROJ_ROOT)/src/%.c
    @echo 'Building file: $<'
    gcc -DUSE_STDIO=1 -D__GCC_POSIX__=1 $(TARGET_INC) -O2 -Wall -c -fmessage-length=0 -pthread -lrt -MMD -MP -MF"$(@:%.o=%.d)" -MT"$(@:%.o=%.d)" -o"$@" "$<"
    @echo 'Finished building: $<'
@echo ' '

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15

FreeRTOS_Kernel/subdir.mk

C_SRCS += \
$(PROJ_ROOT)/FreeRTOS_Kernel/croutine.c \
$(PROJ_ROOT)/FreeRTOS_Kernel/list.c \
$(PROJ_ROOT)/FreeRTOS_Kernel/queue.c \
$(PROJ_ROOT)/FreeRTOS_Kernel/tasks.c \
$(PROJ_ROOT)/FreeRTOS_Kernel/portable/GCC/Posix/port.c \
$(PROJ_ROOT)/FreeRTOS_Kernel/portable/MemMang/heap_3.c

OBJS += \
$(BUILD_TMP)/croutine.o \
$(BUILD_TMP)/list.o \
$(BUILD_TMP)/queue.o \
$(BUILD_TMP)/tasks.o \
$(BUILD_TMP)/port.o \
$(BUILD_TMP)/heap_3.o

C_DEPS += \
$(BUILD_TMP)/croutine.d \
$(BUILD_TMP)/list.d \
$(BUILD_TMP)/queue.d \
$(BUILD_TMP)/tasks.d \
$(BUILD_TMP)/port.d \
$(BUILD_TMP)/heap_3.d

$(BUILD_TMP)/%.o: $(PROJ_ROOT)/FreeRTOS_Kernel/%.c
    @echo 'Building file: $<'
    gcc -DUSE_STDIO=1 -D__GCC_POSIX__=1 $(TARGET_INC) -O2 -Wall -c -fmessage-length=0 -pthread -lrt -MMD -MP -MF"$(@:%.o=%.d)" -MT"$(@:%.o=%.d)" -o"$@" "$<"
    @echo 'Finished building: $<'
    @echo ' '

$(BUILD_TMP)/%.o: $(PROJ_ROOT)/FreeRTOS_Kernel/portable/GCC/Posix/%.c
    @echo 'Building file: $<'
    gcc -DUSE_STDIO=1 -D__GCC_POSIX__=1 $(TARGET_INC) -O2 -Wall -c -fmessage-length=0 -pthread -lrt -MMD -MP -MF"$(@:%.o=%.d)" -MT"$(@:%.o=%.d)" -o"$@" "$<"
    @echo 'Finished building: $<'
    @echo ' '

$(BUILD_TMP)/%.o: $(PROJ_ROOT)/FreeRTOS_Kernel/portable/MemMang/%.c
    @echo 'Building file: $<'
    gcc -DUSE_STDIO=1 -D__GCC_POSIX__=1 $(TARGET_INC) -O2 -Wall -c -fmessage-length=0 -pthread -lrt -MMD -MP -MF"$(@:%.o=%.d)" -MT"$(@:%.o=%.d)" -o"$@" "$<"
    @echo 'Finished building: $<'
@echo ' '

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41

OK,編譯體系已經搞好。此時在根目錄下直接敲 make all 就應該可以進行編譯啦。
配置更新

此時直接make all會發現有一大堆錯誤,這是因為FreeRTOS的版本更新后一些結構體的名字發生了變化,在FreeRTOS.h中有一個兼容性的宏可以控制一部分的兼容性,但是因為版本跨度比較大, 我們依然需要在portmacro.h中做適當的適配:

/*-----------------------------------------------------------*/
typedef portSTACK_TYPE StackType_t;
typedef portBASE_TYPE BaseType_t;
typedef unsigned long UBaseType_t;

#define portTICK_PERIOD_MS                                ( ( TickType_t ) 1000 / configTICK_RATE_HZ )
#if( configUSE_16_BIT_TICKS == 1 )
        typedef unsigned portSHORT TickType_t;
        #define portMAX_DELAY ( TickType_t ) 0xffff
#else
        typedef unsigned portLONG TickType_t;
        #define portMAX_DELAY ( TickType_t ) 0xffffffff
#endif

/*-----------------------------------------------------------*/
/*
#if( configUSE_16_BIT_TICKS == 1 )
    typedef unsigned portSHORT portTickType;
    #define portMAX_DELAY ( portTickType ) 0xffff
#else
    typedef unsigned portLONG portTickType;
    #define portMAX_DELAY ( portTickType ) 0xffffffff
#endif
*/
/*-----------------------------------------------------------*/

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25

編譯運行

此時再make clean后重新make all,編譯即可通過。但是實際上main.c里並沒有執行任何代碼,所以感受不到FreeRTOS的實際效果,我們在main.c中添加一些代碼,來創建兩個任務並通過消息隊列來傳遞一些數據:

#include <stdio.h>
#include <stdlib.h>
#include "main.h"

#include "FreeRTOS.h"
#include "task.h"
#include "queue.h"

static void vTask1( void *pvParameters );
static void vTask2( void *pvParameters );

int main()
{
    static xQueueHandle xTestQueue;
    xTestQueue = xQueueCreate( 10, ( unsigned portBASE_TYPE ) sizeof( unsigned short ) );
    xTaskCreate( vTask1, "vTask1", configMINIMAL_STACK_SIZE, ( void * ) &xTestQueue, tskIDLE_PRIORITY, NULL );
    xTaskCreate( vTask2, "vTask2", configMINIMAL_STACK_SIZE, ( void * ) &xTestQueue, tskIDLE_PRIORITY, NULL );

    vTaskStartScheduler();
    return 1;
}

static void vTask1( void *pvParameters )
{
unsigned short usValue = 0, usLoop;
xQueueHandle *pxQueue;
const unsigned short usNumToProduce = 3;
short sError = pdFALSE;

    pxQueue = ( xQueueHandle * ) pvParameters;

    for( ;; )
    {       
        for( usLoop = 0; usLoop < usNumToProduce; ++usLoop )
        {
            /* Send an incrementing number on the queue without blocking. */
            printf("Task1 will send: %d\r\n", usValue);
            if( xQueueSendToBack( *pxQueue, ( void * ) &usValue, ( portTickType ) 0 ) != pdPASS )
            {
                sError = pdTRUE;
            }
            else
            {
                ++usValue;
            }
        }
        vTaskDelay( 2000 );
    }
}
static void vTask2( void *pvParameters )
{
unsigned short usData = 0;
xQueueHandle *pxQueue;

    pxQueue = ( xQueueHandle * ) pvParameters;

    for( ;; )
    {       
        while( uxQueueMessagesWaiting( *pxQueue ) )
        {
            if( xQueueReceive( *pxQueue, &usData, ( portTickType ) 0 ) == pdPASS )
            {
                printf("Task2 received:%d\r\n", usData);
            }
        }
        vTaskDelay( 5000 );
    }
}

/********************************************************/
/* This is a stub function for FreeRTOS_Kernel */
void vMainQueueSendPassed( void )
{
    return;
}

/* This is a stub function for FreeRTOS_Kernel */
void vApplicationIdleHook( void )
{
    return;
}

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81

再次重新編譯,執行編譯后在根目錄下生成的simulator_linux.bin,即可看到兩個Task之間的交互過程:
Result
總結

FreeRTOS的內核極其小巧,只需要幾個簡單的文件就可以進行編譯運行,當在不同的硬體上進行移植的時候,只需要修改portable目錄里的文件即可完成對硬體的適配,實際上官方也提供了大量的已經完成移植的設備的portable文件,我們只需要簡單的拷貝過來即可。

[admin via ] 在Linux下實現FreeRTOS的簡單模擬器已經有1116次圍觀

http://coctec.com/magazine/show-post-item-7.html