論壇原始地址(持續更新):http://www.armbbs.cn/forum.php?mod=viewthread&tid=99514php
本章節將爲你們介紹ThreadX內核的MDK AC6方式移植和設計框架,理論上不建議初學者直接學習,由於本章節涉及到的知識點不少,建議對ThreadX的應用有一些瞭解後再來看,這樣將事半功倍。可是本章的工程模板框架必定要學習。api
雖然本章節是以咱們開發板爲例進行移植的,可是教會你們如何移植到本身的板子上以及移植過程當中的注意事項是本章節的重點。app
5.1初學者重要提示框架
5.2移植前的準備工做以及移植ThreadX的流程函數
5.3第1步:瞭解ThreadX內核模板框架設計性能
5.4第2步:添加ThreadX庫全部相關文件到裸機工程模板學習
5.5第3步:修改驅動初始化文件bsp.c(含MPU配置)測試
5.6 第4步:更新bsp_timer.c和bsp.h文件優化
5.7第5步:修改文件stm32f4xx_it.cui
5.8第6步:修改文件tx_initalize_low_level.s
5.9第7步:ThreadX配置文件tx_user.h
5.10第8步:添加應用程序
5.11實驗例程
5.12總結
一、 爲了方便你們移植,推薦直接添加咱們的工程文件到本身的工程或者直接使用咱們的工程模板,按照本章的修改說明移植便可。
移植前注意如下兩個問題:
一、 本章節的IDE開發環境務必是MDK5.30及其以上版本,鏡像下載地址:
http://www.armbbs.cn/forum.php?mod=viewthread&tid=96992 。
二、 準備一個簡單的裸機工程,越簡單越好,咱們就在這個簡單的工程上面移植便可:
配套模板名稱:V6-3001_Base Template
GUIX的移植經過如下8步完成,下面各個小節詳細講解每一步:
移植ThreadX前,咱們優先了解下ThreadX內核模板程序的框圖。
首先準備好一個簡單的ThreadX工程模板,工程模板的製做在ThreadX內核教程裏面有詳細說明,這裏的重點是教你們移植ThreadX,對應的例子名稱:V6-3002_ThreadX Kernal Template。準備好的工程模板以下圖所示。
爲了幫助你們更好的理解ThreadX內核例子模板,專門製做了一個框圖,可讓你們總體把控模板設計:
下面把幾個關鍵點逐一爲你們作個說明。
這個文件主要實現工程中各類頭文件的彙總,你們用到的均可以將其放到這個頭文件裏面。其它應用源文件有調用到的,直接調用這個頭文件includes.h便可。
使用這個頭文件主要是方便各類頭文件的管理。
/* ********************************************************************************************************* * 標準庫 ********************************************************************************************************* */ #include <stdarg.h> #include <stdio.h> #include <stdlib.h> #include <math.h> /* ********************************************************************************************************* * OS ********************************************************************************************************* */ #include "tx_api.h" #include "tx_timer.h" /* ********************************************************************************************************* * APP / BSP ********************************************************************************************************* */ #include <bsp.h> /* ********************************************************************************************************* * 變量和函數 ********************************************************************************************************* */ /* 方便RTOS裏面使用 */ extern void SysTick_ISR(void); #define bsp_ProPer1ms SysTick_ISR
此文件主要用於ThreadX內核的配置,內核相關的幾個宏配置基本都已經整理到這個文件裏面。
/* ********************************************************************************************************* * 宏定義 ********************************************************************************************************* */ /* 最快速度優化須要開啓的選項 : TX_MAX_PRIORITIES 32 TX_DISABLE_PREEMPTION_THRESHOLD TX_DISABLE_REDUNDANT_CLEARING TX_DISABLE_NOTIFY_CALLBACKS TX_NOT_INTERRUPTABLE TX_TIMER_PROCESS_IN_ISR TX_REACTIVATE_INLINE TX_DISABLE_STACK_FILLING TX_INLINE_THREAD_RESUME_SUSPEND 最小代碼優化須要開啓的選項: TX_MAX_PRIORITIES 32 TX_DISABLE_PREEMPTION_THRESHOLD TX_DISABLE_REDUNDANT_CLEARING TX_DISABLE_NOTIFY_CALLBACKS TX_NOT_INTERRUPTABLE TX_TIMER_PROCESS_IN_ISR */ /* 覆蓋tx_port.h 裏面的宏定義 */ /* #define TX_MAX_PRIORITIES 32 #define TX_MINIMUM_STACK ???? #define TX_THREAD_USER_EXTENSION ???? #define TX_TIMER_THREAD_STACK_SIZE ???? #define TX_TIMER_THREAD_PRIORITY ???? */ /* 肯定定時器是否到期的處理,好比應用定時器,溢出時間和函數tx_thread_sleep調用等,是在系統定時器任務裏面仍是在定時器中斷裏面調用。 默認是在定時任務裏面,當定義了下面函數後,將直接在定時器中斷裏面處理,能夠去掉定時器任務所消耗資源。 */ //#define TX_TIMER_PROCESS_IN_ISR /* 用於設置定時器激活是否採用內聯方式,默認此功能是關閉的。若是使能後,內聯方式的執行速度快,但增長代碼量 */ //#define TX_REACTIVATE_INLINE /* 用於設置是否關閉棧填充,默認狀況下是使能的,全部任務的棧空間所有填充爲0xEF, * 帶有ThreadX調試組件或者運行時棧檢測會用到。 */ //#define TX_DISABLE_STACK_FILLING /* 用於使能棧檢測,默認是關閉的。此選項使能後,而TX_DISABLE_STACK_FILLING沒使能時,棧填充將開啓,方便棧檢測 */ //#define TX_ENABLE_STACK_CHECKING /* 用於設置是否關閉搶佔閥值,默認是開啓的。若是應用程序不須要此功能,關閉後能夠下降代碼需求,提高性能 */ //#define TX_DISABLE_PREEMPTION_THRESHOLD /* 用於設置是否清零ThreadX全局變量,若是編譯器啓動代碼在ThreadX運行前清除了.bss段,那麼能夠關閉沒必要要的清零 */ //#define TX_DISABLE_REDUNDANT_CLEARING /* 肯定是否不須要定時器組,禁止後須要用戶註釋掉tx_initialize_low_level文件裏面tx_timer_interrupt的調用。 另外,禁止後,必須使能TX_TIMER_PROCESS_IN_ISR */ /* #define TX_NO_TIMER #ifndef TX_TIMER_PROCESS_IN_ISR #define TX_TIMER_PROCESS_IN_ISR #endif */ /* 用於設置是否關閉通知回調,默認是使能的。若是應用程序沒有用到消息回調,關閉掉後能夠減少代碼,而且能夠提高性能。 */ //#define TX_DISABLE_NOTIFY_CALLBACKS /* 使能tx_thread_resume和tx_thread_suspend使用內聯代碼,優點是提高這兩個函數的執行性能,劣勢是增長代碼量 */ //#define TX_INLINE_THREAD_RESUME_SUSPEND /* 設置TreadX內核不可中斷,好處是下降處理負擔,而且產生的代碼小。但增長鎖時間 */ //#define TX_NOT_INTERRUPTABLE /* 使能事件Trace,會稍微增長點代碼 */ //#define TX_ENABLE_EVENT_TRACE /* 使能BLOCK_POOL信息獲取 */ //#define TX_BLOCK_POOL_ENABLE_PERFORMANCE_INFO /* 使能BYTE_POOL信息獲取 */ //#define TX_BYTE_POOL_ENABLE_PERFORMANCE_INFO /* 使能事件標誌信息獲取 */ //#define TX_EVENT_FLAGS_ENABLE_PERFORMANCE_INFO /* 使能互斥信號量信息獲取 */ //#define TX_MUTEX_ENABLE_PERFORMANCE_INFO /* 使能消息對象信息獲取 */ //#define TX_QUEUE_ENABLE_PERFORMANCE_INFO /* 使能信號量信息獲取 */ //#define TX_SEMAPHORE_ENABLE_PERFORMANCE_INFO /* 使能任務信息獲取 */ //#define TX_THREAD_ENABLE_PERFORMANCE_INFO /* 使能定時器信息獲取 */ //#define TX_TIMER_ENABLE_PERFORMANCE_INFO
這個彙編文件裏面有個重要參數須要你們配置,即芯片主頻和系統時鐘節拍。
SYSTEM_CLOCK EQU 400000000
SYSTICK_CYCLES EQU ((SYSTEM_CLOCK / 1000) -1)
400000000是系統時鐘主頻,1000對應的就是系統時鐘節拍,這裏1000就表示1000Hz。
ThreadX全部任務基本都在main.c裏面建立,方便統一管理。若是有GUIX,FileX等組件的任務須要運行,實際運行函數會在其它源文件裏面,並將這個函數extern到main.C文件裏面,放到相應的任務裏面執行。
另外,任務優先級,任務棧大小,任務控制塊等也都放到main.C文件裏面,方便管理:
/* ********************************************************************************************************* * 任務優先級,數值越小優先級越高 ********************************************************************************************************* */ #define APP_CFG_TASK_START_PRIO 2u #define APP_CFG_TASK_MsgPro_PRIO 3u #define APP_CFG_TASK_USER_IF_PRIO 4u #define APP_CFG_TASK_COM_PRIO 5u #define APP_CFG_TASK_STAT_PRIO 30u #define APP_CFG_TASK_IDLE_PRIO 31u /* ********************************************************************************************************* * 任務棧大小,單位字節 ********************************************************************************************************* */ #define APP_CFG_TASK_START_STK_SIZE 4096u #define APP_CFG_TASK_MsgPro_STK_SIZE 4096u #define APP_CFG_TASK_COM_STK_SIZE 4096u #define APP_CFG_TASK_USER_IF_STK_SIZE 4096u #define APP_CFG_TASK_IDLE_STK_SIZE 1024u #define APP_CFG_TASK_STAT_STK_SIZE 1024u /* ********************************************************************************************************* * 靜態全局變量 ********************************************************************************************************* */ static TX_THREAD AppTaskStartTCB; static uint64_t AppTaskStartStk[APP_CFG_TASK_START_STK_SIZE/8]; static TX_THREAD AppTaskMsgProTCB; static uint64_t AppTaskMsgProStk[APP_CFG_TASK_MsgPro_STK_SIZE/8]; static TX_THREAD AppTaskCOMTCB; static uint64_t AppTaskCOMStk[APP_CFG_TASK_COM_STK_SIZE/8]; static TX_THREAD AppTaskUserIFTCB; static uint64_t AppTaskUserIFStk[APP_CFG_TASK_USER_IF_STK_SIZE/8]; static TX_THREAD AppTaskIdleTCB; static uint64_t AppTaskIdleStk[APP_CFG_TASK_IDLE_STK_SIZE/8]; static TX_THREAD AppTaskStatTCB; static uint64_t AppTaskStatStk[APP_CFG_TASK_STAT_STK_SIZE/8];
啓動任務裏面主要作了四個工做:
代碼以下:
/* ********************************************************************************************************* * 函 數 名: AppTaskStart * 功能說明: 啓動任務。 * 形 參: thread_input 是在建立該任務時傳遞的形參 * 返 回 值: 無 優 先 級: 2 ********************************************************************************************************* */ static void AppTaskStart (ULONG thread_input) { (void)thread_input; /* 先掛起定時器組 */ #ifndef TX_NO_TIMER tx_thread_suspend(&_tx_timer_thread); #endif /* 優先執行任務統計 */ OSStatInit(); /* 恢復定時器組 */ #ifndef TX_NO_TIMER tx_thread_resume(&_tx_timer_thread); #endif /* 內核開啓後,恢復HAL裏的時間基準 */ HAL_ResumeTick(); /* 外設初始化 */ bsp_Init(); /* 建立任務 */ AppTaskCreate(); /* 建立任務間通訊機制 */ AppObjCreate(); while (1) { /* 須要週期性處理的程序,對應裸機工程調用的SysTick_ISR */ bsp_ProPer1ms(); tx_thread_sleep(1); } }
ThreadX系統時鐘節拍默認是用的滴答定時器,STM32的HAL庫時間基準也是用的滴答定時器。對於這種狀況,咱們通常的狀況下是使用其餘的通用定時器替代,不過要額外的佔用一點系統性能。簡單的處理辦法是從新下面兩個函數便可,讓HAL庫和ThreadX都使用滴答定時器:
/* ********************************************************************************************************* * 函 數 名: HAL_Delay * 功能說明: 重定向毫秒延遲函數。替換HAL中的函數。由於HAL中的缺省函數依賴於Systick中斷,若是在USB、SD * 卡中斷中有延遲函數,則會鎖死。也能夠經過函數HAL_NVIC_SetPriority提高Systick中斷 * 形 參: 無 * 返 回 值: 無 ********************************************************************************************************* */ void HAL_Delay(uint32_t Delay) { bsp_DelayMS(Delay); } HAL_StatusTypeDef HAL_InitTick (uint32_t TickPriority) { return HAL_OK; } uint32_t HAL_GetTick (void) { static uint32_t ticks = 0U; uint32_t i; if (_tx_thread_system_state == TX_INITIALIZE_IS_FINISHED) { return ((uint32_t)_tx_time_get()); } /* 若是ThreadX尚未運行,採用下面方式 */ for (i = (SystemCoreClock >> 14U); i > 0U; i--) { __NOP(); __NOP(); __NOP(); __NOP(); __NOP(); __NOP(); __NOP(); __NOP(); __NOP(); __NOP(); __NOP(); __NOP(); } return ++ticks; }
這個是移植的坑王,你們移植後,能夠測試下多任務的FPU計算是否有異常。好比兩個任務運行相同的浮點運算和刷新速度,看看兩個任務的輸出是否同步變化,這個測試很是重要:
那麼問題來了,正確的使能姿式是什麼?務必保證C和彙編的預約義宏裏面都使能。
C裏面對應的使能:
彙編裏面對應的使能:
瞭解了ThreadX內核框架後,介紹下如何將移植到裸機工程模板裏面。咱們這裏一步到位,直接把全部相關的文件都加上,而後再介紹如何修改,方便你們移植到本身的板子上。
按照第2章2.3.1小節講解的方法下載軟件包threadx-6.0.2_rel(若是軟件包升級了,數字6.0.2略有不一樣),下面是ThreadX軟件包內容:
主要用到兩個文件夾:
common文件夾裏面是源碼文件。
ports文件夾裏面是移植文件。
在工程模板建立文件夾
將2.1步的ThreadX軟件包裏面的全部內容複製進來,總體效果就是下面這樣:
將源碼文件和ports文件添加到MDK的工程項目中,添加後的效果以下:
推薦使用下面的方法添加,有效防止MDK大批量添加源文件形成的卡頓問題:
在User文件夾下添加文件tx_user.h,直接從本章節教程配套例子的User文件夾複製便可。此文件主要用於ThreadX配置。
爲了方便管理,咱們這裏將路徑ThreadX\ports\cortex_m4\ac6\inc裏面的tx_port.h文件也添加進來了。
在User文件夾下添加文件incudes.h,直接從本章節教程配套例子的User文件夾複製便可。此文件主要用於ThreadX的各類頭文件彙總。
在User\bsp文件夾下添加文件stm32f4xx_hal_timebase_tim.c,直接從本章節教程配套例子的User\bsp文件夾複製便可。此文件主要用於爲HAL庫從新安排一個時間基準:
添加bsp_dwt.c文件和bsp_dwt.h文件主要是由於2.6步中的stm32f4xx_hal_timebase_tim.c文件裏面的函數bsp_DelayMS要使用,此函數是基於DWT系統時鐘週期計數器實現。
相關BSP驅動關聯到的HAL庫文件都添加了進來,簡單省事些,你們也能夠把HAL庫全部文件都添加進來:
C/C++文件中添加的預約義宏以下:
ASM彙編文件裏面添加的宏定義:
須要添加的路徑以下:
至此,咱們須要的GUIX文件都已經添加完畢。下面爲你們介紹如何修改用於本身的板子。
這個bsp.c文件比較重要,移植階段,直接將咱們移植好的模板內容複製過去便可,這裏把相關的內容爲你們作個說明。
系統初始化,須要在ThreadX初始化以前調用。
/* ********************************************************************************************************* * 函 數 名: System_Init * 功能說明: 系統初始化,主要是MPU,Cache和系統時鐘配置 * 形 參:無 * 返 回 值: 無 ********************************************************************************************************* */ void System_Init(void) { /* STM32H429 HAL 庫初始化,此時系統用的仍是F429自帶的16MHz,HSI時鐘: - 調用函數HAL_InitTick,初始化滴答時鐘中斷1ms。 - 設置NVIV優先級分組爲4。 */ HAL_Init(); /* 配置系統時鐘到168MHz - 切換使用HSE。 - 此函數會更新全局變量SystemCoreClock,並從新配置HAL_InitTick。 */ SystemClock_Config(); /* Event Recorder: - 可用於代碼執行時間測量,MDK5.25及其以上版本才支持,IAR不支持。 - 默認不開啓,若是要使能此選項,務必看V7開發板用戶手冊第8章 */ #if Enable_EventRecorder == 1 /* 初始化EventRecorder並開啓 */ EventRecorderInitialize(EventRecordAll, 1U); EventRecorderStart(); #endif }
硬件外設的初始化,這個函數在ThreadX啓動任務裏面調用。
/* ********************************************************************************************************* * 函 數 名: bsp_Init * 功能說明: 初始化全部的硬件設備。該函數配置CPU寄存器和外設的寄存器並初始化一些全局變量。只須要調用一次 * 形 參: 無 * 返 回 值: 無 ********************************************************************************************************* */ void bsp_Init(void) { bsp_InitDWT(); /* 初始化DWT時鐘週期計數器 */ bsp_InitKey(); /* 按鍵初始化,要放在滴答定時器以前,由於按鈕檢測是經過滴答定時器掃描 */ bsp_InitUart(); /* 初始化串口 */ bsp_InitExtIO(); /* 初始化FMC總線74HC574擴展IO. 必須在 bsp_InitLed()前執行 */ bsp_InitLed(); /* 初始化LED */ bsp_InitTimer(); /* 初始化滴答定時器 */ }
這個函數主要是完成系統時鐘配置。
/* ********************************************************************************************************* * 函 數 名: SystemClock_Config * 功能說明: 初始化系統時鐘 * System Clock source = PLL (HSE) * SYSCLK(Hz) = 168000000 (CPU Clock) * HCLK = SYSCLK / 1 = 168000000 (AHB1Periph) * PCLK2 = HCLK / 2 = 84000000 (APB2Periph) * PCLK1 = HCLK / 4 = 42000000 (APB1Periph) * HSE Frequency(Hz) = 25000000 * PLL_M = 25 * PLL_N = 336 * PLL_P = 2 * PLL_Q = 4 * VDD(V) = 3.3 * Flash Latency(WS) = 5 * 形 參: 無 * 返 回 值: 無 ********************************************************************************************************* */ static void SystemClock_Config(void) { 省略未寫 /* 使能SYS時鐘和IO補償 */ __HAL_RCC_SYSCFG_CLK_ENABLE() ; HAL_EnableCompensationCell(); }
這個函數裏面默認有個按鍵掃描,若是你們移植的程序裏面沒有按鍵初始化,務必要把這個按鍵掃描函數註釋掉。
/* ********************************************************************************************************* * 函 數 名: bsp_RunPer10ms * 功能說明: 該函數每隔10ms被Systick中斷調用1次。詳見 bsp_timer.c的定時中斷服務程序。一些處理時間要求 * 不嚴格的任務能夠放在此函數。好比:按鍵掃描、蜂鳴器鳴叫控制等。 * 形 參: 無 * 返 回 值: 無 ********************************************************************************************************* */ void bsp_RunPer10ms(void) { bsp_KeyScan10ms(); }
更新bsp_timer.c文件是由於此文件跟ThreadX都要使用滴答定時器,有衝突。因此你們直接將咱們工程模板裏面此文件覆蓋移植的這個文件便可。
bsp.h文件裏面要添加一個宏定義,由於bsp_timer.c文件裏面作了些條件編譯:
#define USE_THREADX 1
另外,bsp.h文件將大部分頭文件都添加進來了,你們能夠根據須要,用到那些頭文件,使能那些,用不到的,能夠註釋掉。固然,不註釋也是沒問題的:
/* 經過取消註釋或者添加註釋的方式控制是否包含底層驅動模塊 */ //#include "bsp_msg.h" #include "bsp_user_lib.h" #include "bsp_timer.h" #include "bsp_led.h" #include "bsp_key.h" #include "bsp_dwt.h" //#include "bsp_cpu_rtc.h" //#include "bsp_cpu_adc.h" //#include "bsp_cpu_dac.h" #include "bsp_uart_fifo.h" //#include "bsp_uart_gps.h" //#include "bsp_uart_esp8266.h" //#include "bsp_uart_sim800.h" //#include "bsp_spi_bus.h" //#include "bsp_spi_ad9833.h" //#include "bsp_spi_ads1256.h" //#include "bsp_spi_dac8501.h" //#include "bsp_spi_dac8562.h" //#include "bsp_spi_flash.h" //#include "bsp_spi_tm7705.h" //#include "bsp_spi_vs1053b.h" //#include "bsp_fmc_sdram.h" //#include "bsp_fmc_nand_flash.h" //#include "bsp_fmc_ad7606.h" //#include "bsp_fmcdma_ad7606.h" //#include "bsp_fmc_oled.h" #include "bsp_fmc_io.h" //#include "bsp_i2c_gpio.h" //#include "bsp_i2c_bh1750.h" //#include "bsp_i2c_bmp085.h" //#include "bsp_i2c_eeprom_24xx.h" //#include "bsp_i2c_hmc5883l.h" //#include "bsp_i2c_mpu6050.h" //#include "bsp_i2c_si4730.h" //#include "bsp_i2c_wm8978.h" //#include "bsp_tft_429.h" //#include "bsp_tft_lcd.h" //#include "bsp_ts_touch.h" //#include "bsp_ts_ft5x06.h" //#include "bsp_ts_gt811.h" //#include "bsp_ts_gt911.h" //#include "bsp_ts_stmpe811.h" #include "bsp_beep.h" #include "bsp_tim_pwm.h" //#include "bsp_sdio_sd.h" //#include "bsp_dht11.h" //#include "bsp_ds18b20.h" //#include "bsp_ps2.h" //#include "bsp_ir_decode.h" //#include "bsp_camera.h" //#include "bsp_rs485_led.h" //#include "bsp_can.h"
刪除此文件裏面帶的以下函數,ThreadX要使用,衝突了。
/** * @brief This function handles PendSVC exception. * @param None * @retval None */ void PendSV_Handler(void) { }
這個文件有以下幾處須要修改(置紅的部分是修改的):
.global _tx_thread_system_stack_ptr .global _tx_initialize_unused_memory .global _tx_timer_interrupt .global __main .global __tx_SVCallHandler .global __tx_PendSVHandler .global __tx_NMIHandler @ NMI .global __tx_BadHandler @ HardFault .global __tx_SVCallHandler @ SVCall .global __tx_DBGHandler @ Monitor .global __tx_PendSVHandler @ PendSV .global __tx_SysTickHandler @ SysTick .global __tx_IntHandler @ Int 0 .global __initial_sp .global __Vectors @ @ SYSTEM_CLOCK = 168000000 SYSTICK_CYCLES = ((SYSTEM_CLOCK / 1000) -1) .text 32 .align 4 .syntax unified @VOID _tx_initialize_low_level(VOID) @{ .global _tx_initialize_low_level .thumb_func _tx_initialize_low_level: @ @ /* Disable interrupts during ThreadX initialization. */ @ CPSID i @ @ /* Set base of available memory to end of non-initialised RAM area. */ @ LDR r0, =_tx_initialize_unused_memory @ Build address of unused memory pointer LDR r1, =__initial_sp @ Build first free address ADD r1, r1, #4 @ STR r1, [r0] @ Setup first unused memory pointer @ @ /* Setup Vector Table Offset Register. */ @ MOV r0, #0xE000E000 @ Build address of NVIC registers LDR r1, =__Vectors @ Pickup address of vector table STR r1, [r0, #0xD08] @ Set vector table address @ @ /* Set system stack pointer from vector value. */ @ LDR r0, =_tx_thread_system_stack_ptr @ Build address of system stack pointer LDR r1, =__Vectors @ Pickup address of vector table LDR r1, [r1] @ Pickup reset stack pointer STR r1, [r0] @ Save system stack pointer 省略未寫
改成LDR r1, =__Vectors
這裏修改了兩處。
ThreadX內核相關的配置,已經所有整理到了這個文件中,而且作中文註釋,你們能夠更新須要使能宏定義。
應用程序比較簡單,你們能夠直接複製本章教程配置例子的main.c文件中的內容到本身工程裏面測試。主要建立了以下幾個任務:
App Task Start任務 :啓動任務,這裏用做BSP驅動包處理。
App Task MspPro任務 :消息處理,這裏用做浮點數串口打印。
App Task UserIF任務 :按鍵消息處理。
App Task COM任務 :浮點數串口打印。
App Task STAT任務 :統計任務
App Task IDLE任務 :空閒任務
System Timer Thread任務:系統定時器任務
任務棧大小和任務控制塊定義以下:
/* ********************************************************************************************************* * 任務優先級,數值越小優先級越高 ********************************************************************************************************* */ #define APP_CFG_TASK_START_PRIO 2u #define APP_CFG_TASK_MsgPro_PRIO 3u #define APP_CFG_TASK_USER_IF_PRIO 4u #define APP_CFG_TASK_COM_PRIO 5u #define APP_CFG_TASK_STAT_PRIO 30u #define APP_CFG_TASK_IDLE_PRIO 31u /* ********************************************************************************************************* * 任務棧大小,單位字節 ********************************************************************************************************* */ #define APP_CFG_TASK_START_STK_SIZE 4096u #define APP_CFG_TASK_MsgPro_STK_SIZE 4096u #define APP_CFG_TASK_COM_STK_SIZE 4096u #define APP_CFG_TASK_USER_IF_STK_SIZE 4096u #define APP_CFG_TASK_IDLE_STK_SIZE 1024u #define APP_CFG_TASK_STAT_STK_SIZE 1024u /* ********************************************************************************************************* * 靜態全局變量 ********************************************************************************************************* */ static TX_THREAD AppTaskStartTCB; static uint64_t AppTaskStartStk[APP_CFG_TASK_START_STK_SIZE/8]; static TX_THREAD AppTaskMsgProTCB; static uint64_t AppTaskMsgProStk[APP_CFG_TASK_MsgPro_STK_SIZE/8]; static TX_THREAD AppTaskCOMTCB; static uint64_t AppTaskCOMStk[APP_CFG_TASK_COM_STK_SIZE/8]; static TX_THREAD AppTaskUserIFTCB; static uint64_t AppTaskUserIFStk[APP_CFG_TASK_USER_IF_STK_SIZE/8]; static TX_THREAD AppTaskIdleTCB; static uint64_t AppTaskIdleStk[APP_CFG_TASK_IDLE_STK_SIZE/8]; static TX_THREAD AppTaskStatTCB; static uint64_t AppTaskStatStk[APP_CFG_TASK_STAT_STK_SIZE/8];
優先建立的啓動任務,統計任務和空閒任務:
/* ********************************************************************************************************* * 函 數 名: tx_application_define * 功能說明: ThreadX專用的任務建立,通訊組件建立函數 * 形 參: first_unused_memory 未使用的地址空間 * 返 回 值: 無 ********************************************************************************************************* */ void tx_application_define(void *first_unused_memory) { /* 若是實現任務CPU利用率統計的話,此函數僅用於實現啓動任務,統計任務和空閒任務,其它任務在函數 AppTaskCreate裏面建立。 */ /**************建立啓動任務*********************/ tx_thread_create(&AppTaskStartTCB, /* 任務控制塊地址 */ "App Task Start", /* 任務名 */ AppTaskStart, /* 啓動任務函數地址 */ 0, /* 傳遞給任務的參數 */ &AppTaskStartStk[0], /* 堆棧基地址 */ APP_CFG_TASK_START_STK_SIZE, /* 堆棧空間大小 */ APP_CFG_TASK_START_PRIO, /* 任務優先級*/ APP_CFG_TASK_START_PRIO, /* 任務搶佔閥值 */ TX_NO_TIME_SLICE, /* 不開啓時間片 */ TX_AUTO_START); /* 建立後當即啓動 */ /**************建立統計任務*********************/ tx_thread_create(&AppTaskStatTCB, /* 任務控制塊地址 */ "App Task STAT", /* 任務名 */ AppTaskStat, /* 啓動任務函數地址 */ 0, /* 傳遞給任務的參數 */ &AppTaskStatStk[0], /* 堆棧基地址 */ APP_CFG_TASK_STAT_STK_SIZE, /* 堆棧空間大小 */ APP_CFG_TASK_STAT_PRIO, /* 任務優先級*/ APP_CFG_TASK_STAT_PRIO, /* 任務搶佔閥值 */ TX_NO_TIME_SLICE, /* 不開啓時間片 */ TX_AUTO_START); /* 建立後當即啓動 */ /**************建立空閒任務*********************/ tx_thread_create(&AppTaskIdleTCB, /* 任務控制塊地址 */ "App Task IDLE", /* 任務名 */ AppTaskIDLE, /* 啓動任務函數地址 */ 0, /* 傳遞給任務的參數 */ &AppTaskIdleStk[0], /* 堆棧基地址 */ APP_CFG_TASK_IDLE_STK_SIZE, /* 堆棧空間大小 */ APP_CFG_TASK_IDLE_PRIO, /* 任務優先級*/ APP_CFG_TASK_IDLE_PRIO, /* 任務搶佔閥值 */ TX_NO_TIME_SLICE, /* 不開啓時間片 */ TX_AUTO_START); /* 建立後當即啓動 */ }
在啓動任務中優先執行一次任務統計,而後建立其它任務:
/* ********************************************************************************************************* * 函 數 名: AppTaskStart * 功能說明: 啓動任務。 * 形 參: thread_input 是在建立該任務時傳遞的形參 * 返 回 值: 無 優 先 級: 2 ********************************************************************************************************* */ static void AppTaskStart (ULONG thread_input) { (void)thread_input; /* 先掛起定時器組 */ #ifndef TX_NO_TIMER tx_thread_suspend(&_tx_timer_thread); #endif /* 優先執行任務統計 */ OSStatInit(); /* 恢復定時器組 */ #ifndef TX_NO_TIMER tx_thread_resume(&_tx_timer_thread); #endif /* 內核開啓後,恢復HAL裏的時間基準 */ HAL_ResumeTick(); /* 外設初始化 */ bsp_Init(); /* 建立任務 */ AppTaskCreate(); /* 建立任務間通訊機制 */ AppObjCreate(); while (1) { /* 須要週期性處理的程序,對應裸機工程調用的SysTick_ISR */ bsp_ProPer1ms(); tx_thread_sleep(1); } }
本章節配套了以下幾個例子供你們移植參考:
裸機模板,方便你們添加ThreadX內核源碼,含有GCC,IAR,MDK AC5和AC6四個版本工程。
ThreadX內核模板,用於你們移植GUIX的參考Demo,含有GCC,IAR,MDK AC5和AC6四個版本工程。
IAR,MDK AC5和AC6工程能夠串口打印任務執行狀況:按開發板的按鍵K1能夠打印,波特率 115200,數據位 8,奇偶校驗位無,中止位 1:
Embedded Studio(GCC)平臺的串口打印是經過其調試組件SEGGER RTT作的串口打印,速度也很是快,打印效果以下:
展現裏面有亂碼是由於Embedded Studio不支持中文。
本章節爲你們講解的內容涉及到的知識較多,信息量較大,部分知識點沒有弄明白是沒有關係的,可是必定要掌握ThreadX內核框架設計,掌握後再分析細節,事半功倍。