为STM32F0搭建FreeRTOS实录
最近為實現小應用囤了一點尚屬低價的STM32F030C8T6單片機,自制了最小系統板,也就順帶搗鼓在這種小芯片上如何移植FreeRTOS。其實由于這款單片機SRAM容量太小,再上FreeRTOS有點不劃算了,但這個移植的過程卻對入門FreeRTOS很有幫助。
工具鏈:Keil MDK 5.34 + STM32CubeMX 6.3.0 + 自制最小系統板(如圖)
一、配置管腳+生成代碼
打開Keil,選擇單片機(我這里就選STM32F030C8T6),接著在Manage Run-Time Environment中選擇軟件組件,選中CMSIS->CORE、Device->STM32CubeHAL、Device->Startup以及下面STM32Cube Framework (API)里的STM32CubeMX。注意,不要馬上點擊確定!!!
我們先要點STM32CubeMX旁邊的綠色啟動按鈕,啟動CubeMX配置。CubeMX要從意法半導體官網下載安裝。
作為一個簡單的例子,我們可以只配置最少的管腳,并且只用片內振蕩器。我在PC13上掛了一個LED,將該管腳配置為GPIO_Output,然后啟用USART1,配置為異步(UART)模式,波特率115200Bits/s。默認條件下,PA9被設置為TX,PA10為RX。
(配置GPIO和UART)
接著我們用STM32CubeMX生成FreeRTOS的代碼。左側目錄中點開Middleware,就有FreeRTOS,點中它,接口(Interface)選擇CMSIS_V2。在下面設置參數中內存管理里,設置總堆大小(TOTAL_HEAP_SIZE)為2048字節,內存管理方法(Memory Management scheme)為heap_1。
(配置FreeRTOS)
這里我們插句嘴,說明一下我們在設置什么。盡管我們要用FreeRTOS,ARM為Cortex M系列的芯片還另外開發了一套API,就是CMSIS,這樣,即使內核操作系統不同,在用戶級的代碼卻可以共享同一套API,降低了代碼移植的難度。待會我們也可以看到,我們是用CMSIS的API創建任務線程,而非直接用FreeRTOS的API;但本質上,只是一層封裝,最后還是要調用FreeRTOS的API的。
內存管理是這里的關鍵。FreeRTOS提供了多種內存管理方式,我們這次就用最簡單的Heap_1,它只支持malloc,不支持free,也就是說建立線程之后,即使要刪除該線程,也沒法釋放其資源,但對我們已經足夠。
接著我們點Tasks and Queues選項卡,去創建任務。這里面已經有一個defaultTask,我把它改名Task1,并把入口函數改名task1fxn;再創建第二個任務task2,入口函數task2fxn。
現在我們看一下FreeRTOS Heap Usage,可以看到每個任務都占了632字節的RAM,堆棧還剩784字節。
至此,其實STM32CubeMX中的設置已經基本完畢。點擊GENERATE CODE,它給出提示,在使用RTOS時,強烈建議改用HAL Timebase Source而非直接用Systick。這里我暫時不知道為什么,不過為了盡快拉通,就按它說的做,把Timebase Source改為TIM1。然后生成代碼,退出STM32CubeMX,在Keil中Manage Run-Time Environment點擊OK。
二、FreeRTOS代碼加入工作區
此時代碼已經生成,但FreeRTOS的代碼卻還沒加進來。在Project欄中,為我們的工程加入幾個分組:CMSIS_V2、FreeRTOS_src和FreeRTOS_inc。命名并不一定如此,只是看著方便。然后找到生成的FreeRTOS代碼,在(工程目錄)\RTE\Device\STM32F030C8Tx\ STCubeGenerated\Middlewares\Third_Party\FreeRTOS\Source中(對的,非常深)。
其中,CMSIS_RTOS_V2文件夾下定義的就是CMSIS_V2的API,加入CMSIS_V2分組中;這個目錄下所有.c文件都是FreeRTOS的代碼,加入FreeRTOS_src分組;…/protable/MemMang文件夾下是FreeRTOS的5種內存管理方式源代碼,我們采用Heap_1,就把heap_1.c加入FreeRTOS_src,別的不管;接著在…/protable/RVDS/ARM_CM0下是與硬件接口相關的代碼,prot.c加入FreeRTOS_src,portmacro.h加入FreeRTOS_inc,再把…/include文件夾下的所有.h文件都加入FreeRTOS中。最后,在編譯器選項中把包含了FreeRTOS頭文件的3個文件夾加入Include Paths。
此時配置本該成功了,可以編譯一次,卻編譯錯誤,所有錯誤都來自port.c。原來,這個接口代碼有大量的c語言中嵌套匯編的操作,這些匯編指令編譯器都沒有被正確識別。查詢網上的信息,似乎老版本的MDK編譯器還是可以編譯這些代碼的,STM32CubeMX卻還是按老版本生成代碼的,但最新的反而不支持了。
此時我猜想,Keil應該是把自己的編譯器變得更“標準”導致無法編譯的。那什么是最標準的代碼呢?當然是GCC能編譯的代碼就是最標準的代碼啦~從網絡上下載到FreeRTOSv10.0.1的官方代碼,其中portable文件夾就有十幾種編譯器的代碼,包含GCC,用GCC/ARM_CM0的port.c和portmacro.h替換我們工程下的接口,再編譯,果然成功。
三、線程代碼編寫
為了有比較明顯的實驗現象,我在main.c編寫了一個串口輸出函數:
void UART_print(UART_HandleTypeDef *huart, uint8_t *pData) {uint16_t len = 0;while (pData[len]) len++;HAL_UART_Transmit(huart, pData, len, 0x7fff); // enough time to transmit }以及兩個線程的函數:
void task1_fxn(void *argument) {/* Infinite loop */for(;;){osDelay(1000); // delay 1000msUART_print(&huart1,"task1: Hello world\n\r");HAL_GPIO_TogglePin(GPIOC,GPIO_PIN_13);} } void task2_fxn(void *argument) {/* Infinite loop */for(;;){osDelay(1000); // delay 1000msUART_print(&huart1,"task2: Hello world\n\r\n\r");} }在task1中,我們不僅串口輸出,還改變GPIO的電平;task2中,則會換行兩次方便識別。osDelay()就是CMSIS的API,提供類似sleep的進程掛起作用,延遲單位是ms。接上串口,看到串口輸出數據,表明FreeRTOS已經正常啟動,且兩個線程被輪流調用了,移植成功。
總結
以上是生活随笔為你收集整理的为STM32F0搭建FreeRTOS实录的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 智慧农贸市场管理系统的设计与实现
- 下一篇: maya! board_maya人物跑步