移植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不對。
另外就是中斷的服務處理函數了,一定要換成自己的