移植freertos到stm32 f103 的基本流程和總結


為什么要在stm32 f103上面移植freertos

  stm32 f103 以他的全面的文檔,親民的價格,強大的功能。成為無數微設備的方案首選。在市場上有極大的使用量。市場占有率也是非常的高。freertos作為一個開源的微型操作系統,憑借着它的資源占用小,功能強大,文檔齊全,成為各大芯片公司都支持的操作系統,也是程序員操作系統學習的不二首選。所以,把這兩者結合起來,除了能給我們的產品提供強大的支撐之外,還積累的很多基礎技術。筆者花了不少心思才把這個移植好,在這里做個記錄。希望能給你一些啟發。

基本介紹

  我這里使用的是freertos的版本是9.0。移動植入之前,先看一下freertos的文件目錄:

├── croutine.c
├── event_groups.c
├── include
│   ├── FreeRTOS.h
│   ├── StackMacros.h
│   ├── croutine.h
│   ├── deprecated_definitions.h
│   ├── event_groups.h
│   ├── list.h
│   ├── mpu_prototypes.h
│   ├── mpu_wrappers.h
│   ├── portable.h
│   ├── projdefs.h
│   ├── queue.h
│   ├── semphr.h
│   ├── stdint.readme
│   ├── task.h
│   └── timers.h
├── list.c
├── portable
│   ├── GCC
│   │   └── ARM_CM3
│   │       ├── port.c
│   │       └── portmacro.h
│   ├── MemMang
│   │   ├── heap_1.c
│   │   ├── heap_2.c
│   │   ├── heap_2.lst
│   │   ├── heap_2.o
│   │   ├── heap_3.c
│   │   ├── heap_4.c
│   │   └── heap_5.c
│   └── readme.txt
├── queue.c
├── readme.txt
├── tasks.c
└── timers.c

大致一看,這個操作系統是非常簡潔的。從文件名字就可以看出:
queue.c 這個文件是隊列,負責線程之間的通信和數據傳輸的。
task.c 就是線程及任務模塊,線程相關的都在這個文件里面。
list.c 就是一個鏈表,用來實現可變數據的存放和操作。
根目錄下的和具體的芯片沒關系,和芯片的接口及相關的元素主要在兩個函數里面。
一個是portable文件下的port.c 這個里面要注意下,在stm32 f103中,這里最重要的就是這里的中斷處理函數的匹配了。在無操作系統的stm32 f103中,systick, SVC 和 PendSV 這三個中斷的處理函數 這三個函數一般在start.s文件或中斷向量表中vector.c 中。基本額寫法如下所示:

void SVC_Handler (void) attribute((weak));

void PendSV_Handler (void) attribute((weak));

void SysTick_Handler (void) attribute((weak));

在freertos中,需要替換成port.c 里面的另外三個中斷處理函數:

voidxPortPendSVHandler( void ) attribute (( naked ));

voidxPortSysTickHandler( void );

voidvPortSVCHandler( void ) attribute (( naked ));

另外一個就是heap,heap主要是系統的內存管理單元。heap_1.c, heap_2.c and heap_3.c屬於三個基本的樣例子,用戶也可以根據自己的實際情況做修改。這里的的heap雖然很多,但是每個系統只會使用一個,具體使用哪一個要看你的芯片平台的屬性,stm32 f103 使用的是heap_2.c

移植流程

  第一步就是把代碼拷貝到目標文件中,編譯通過。這里屬於一些基本功夫,詳細的步驟我就不多說了,謹記中斷處理函數的處理,這里非常容易出問題。再者就是FreeRTOSconfig.h文件中的heap_size大小,不能太大,太大了這個芯片的資源不夠的。建議一般不要10k左右就行了吧。

  第二步就是FreeRTOSConfig.h文件的配置選擇,這里面的是非常關鍵的,最容易出錯。下面是我的這個文件的配置:

#define configUSE_PREEMPTION            1
#define configUSE_IDLE_HOOK         0
#define configUSE_TICK_HOOK         0
#define configCPU_CLOCK_HZ          ( ( unsigned long ) 72000000 )
#define configSYSTICK_CLOCK_HZ ( configCPU_CLOCK_HZ / 8 )  /* fix for vTaskDelay() */
#define configTICK_RATE_HZ          ( ( TickType_t ) 1000 )
#define configMAX_PRIORITIES            ( 5 )
#define configMINIMAL_STACK_SIZE        ( ( unsigned short ) 128 )
#define configTOTAL_HEAP_SIZE           ( ( size_t ) ( 17 * 1024 ) )
#define configMAX_TASK_NAME_LEN         ( 16 )
#define configUSE_TRACE_FACILITY        0
#define configUSE_16_BIT_TICKS          0
#define configIDLE_SHOULD_YIELD         1
#define configUSE_MUTEXES           1

/* Co-routine definitions. */
#define configUSE_CO_ROUTINES           0
#define configMAX_CO_ROUTINE_PRIORITIES     2

/* Set the following definitions to 1 to include the API function, or zero
to exclude the API function. */

#define INCLUDE_vTaskPrioritySet        1
#define INCLUDE_uxTaskPriorityGet       1
#define INCLUDE_vTaskDelete         1
#define INCLUDE_vTaskCleanUpResources       0
#define INCLUDE_vTaskSuspend            0
#define INCLUDE_vTaskDelayUntil         1
#define INCLUDE_vTaskDelay          1

這里要注意幾點: configCPU_CLOCK_HZ 就是CPU的的時鍾,系統的時鍾和CPU的時鍾是不同的,這里做一個8分頻:#define configSYSTICK_CLOCK_HZ ( configCPU_CLOCK_HZ / 8 )
還有就是后面的heap大小和stack大小,要根據實際的產品情況進行調整的。這個調整好了,可以讓你的小芯片發揮出極大的威力。

  第三點,應用部分:
這里手先看一下主函數:

int main()
{
    RCC_Configuration();
    GPIO_Configuration();
    usart1_init();

     printf("start main sdf \n\r");
     usart1_puts(" 512k flash, 64k ram ..........\n\r");

     xTaskCreate(tadventure,"game",configMINIMAL_STACK_SIZE,NULL,configMAX_PRIORITIES-1,NULL);
     xTaskCreate(flasher,"flash",configMINIMAL_STACK_SIZE,NULL,configMAX_PRIORITIES-1,NULL);
     xTaskCreate(vT_usart, (const char*) "USART Task", configMINIMAL_STACK_SIZE, NULL, 1, NULL);

    vTaskStartScheduler();

    while (1);

    return 0;
}

三個task的處理函數:

static void flasher(void *arg __attribute__((unused))) {

    for (;;) {
        GPIO_ResetBits(GPIOA, GPIO_Pin_1);
        vTaskDelay(pdMS_TO_TICKS(400));
        GPIO_SetBits(GPIOA, GPIO_Pin_1);
        vTaskDelay(pdMS_TO_TICKS(400));
    }
}

static void tadventure(void *arg __attribute__((unused))) {
{
    for (;;) {
        GPIO_ResetBits(GPIOA, GPIO_Pin_0);
        vTaskDelay(pdMS_TO_TICKS(1000));
        GPIO_SetBits(GPIOA, GPIO_Pin_0);
        vTaskDelay(pdMS_TO_TICKS(1000));
    }
}

static void vT_usart(void *p)
{
    // Block for 500ms.
    const portTickType xDelay = 500 / portTICK_RATE_MS;

    for(;;) {
        usart1_puts("FreeRTOS V9.0.0 demo on STM32F103c8t6\r\n");
        usart1_puts(" 64k flash, 20k ram ..........\r\n");
        vTaskDelay(xDelay);
    }
}

這里的結果如下所示:

串口日志

問題備忘

  最大的問題就是一個是FreertosConfig.h文件設置錯誤導致的系統timer不對。
另外就是中斷的服務處理函數了,一定要換成自己的。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM