【STM32F429】第5章 ThreadX操做系統移植(MDK AC6)

論壇原始地址(持續更新):http://www.armbbs.cn/forum.php?mod=viewthread&tid=99514php

第5章   ThreadX操做系統移植(MDK AC6)

本章節將爲你們介紹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總結

 

 

5.1   初學者重要提示。

一、  爲了方便你們移植,推薦直接添加咱們的工程文件到本身的工程或者直接使用咱們的工程模板,按照本章的修改說明移植便可。

5.2   移植前的準備工做以及移植ThreadX的流程

移植前注意如下兩個問題:

一、  本章節的IDE開發環境務必是MDK5.30及其以上版本,鏡像下載地址:

http://www.armbbs.cn/forum.php?mod=viewthread&tid=96992

二、  準備一個簡單的裸機工程,越簡單越好,咱們就在這個簡單的工程上面移植便可:

配套模板名稱:V6-3001_Base Template

GUIX的移植經過如下8步完成,下面各個小節詳細講解每一步:

5.3   第1步:瞭解ThreadX內核模板框架設計

移植ThreadX前,咱們優先了解下ThreadX內核模板程序的框圖。

5.3.1  準備一個ThreadX內核工程模板

首先準備好一個簡單的ThreadX工程模板,工程模板的製做在ThreadX內核教程裏面有詳細說明,這裏的重點是教你們移植ThreadX,對應的例子名稱:V6-3002_ThreadX Kernal Template。準備好的工程模板以下圖所示。

 

5.3.2  內核框架總體把控(重要)

爲了幫助你們更好的理解ThreadX內核例子模板,專門製做了一個框圖,可讓你們總體把控模板設計:

下面把幾個關鍵點逐一爲你們作個說明。

5.3.3  各類頭文件彙總includes.h

這個文件主要實現工程中各類頭文件的彙總,你們用到的均可以將其放到這個頭文件裏面。其它應用源文件有調用到的,直接調用這個頭文件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

5.3.4  TheadX配置文件tx_user.h

此文件主要用於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

5.3.5  系統時鐘節拍配置tx_initialize_low_level.s

這個彙編文件裏面有個重要參數須要你們配置,即芯片主頻和系統時鐘節拍。

SYSTEM_CLOCK       EQU     400000000

SYSTICK_CYCLES     EQU     ((SYSTEM_CLOCK / 1000) -1)

400000000是系統時鐘主頻,1000對應的就是系統時鐘節拍,這裏1000就表示1000Hz。

5.3.6  TheadX任務管理main.c

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];

5.3.7  TheadX啓動任務

啓動任務裏面主要作了四個工做:

  •   優先執行一次任務統計OSStatInit。
  •   外設初始化bsp_Init。
  •   任務建立AppTaskCreate和通訊組件建立AppObjCreate。
  •   須要週期性處理的程序bsp_ProPer1ms,對應裸機工程調用的SysTick_ISR。這個的實現很是重要,這樣以前裸機裏面使用的API,就能夠直接在ThreadX裏面直接調用。

 

代碼以下:

/*
*********************************************************************************************************
*    函 數 名: 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);
    }
}

5.3.8  HAL庫時間基準stm32f4xx_hal_timebase_tim.c

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;
}

5.3.9  ThreadX使能硬件浮點

這個是移植的坑王,你們移植後,能夠測試下多任務的FPU計算是否有異常。好比兩個任務運行相同的浮點運算和刷新速度,看看兩個任務的輸出是否同步變化,這個測試很是重要:

 

那麼問題來了,正確的使能姿式是什麼?務必保證C和彙編的預約義宏裏面都使能。

C裏面對應的使能:

 

彙編裏面對應的使能:

 

5.4   第2步:添加ThreadX庫全部相關文件到裸機工程模板

瞭解了ThreadX內核框架後,介紹下如何將移植到裸機工程模板裏面。咱們這裏一步到位,直接把全部相關的文件都加上,而後再介紹如何修改,方便你們移植到本身的板子上。

5.4.1  第2.1步,下載ThreadX源碼包

按照第2章2.3.1小節講解的方法下載軟件包threadx-6.0.2_rel(若是軟件包升級了,數字6.0.2略有不一樣),下面是ThreadX軟件包內容:

 

主要用到兩個文件夾:

common文件夾裏面是源碼文件。

ports文件夾裏面是移植文件。

5.4.2  第2.2步,建立ThreadX文件夾到工程模板

在工程模板建立文件夾

 

將2.1步的ThreadX軟件包裏面的全部內容複製進來,總體效果就是下面這樣:

 

5.4.3  第2.3步,添加Port文件和源碼文件到工程

將源碼文件和ports文件添加到MDK的工程項目中,添加後的效果以下:

 

  •   ThreadX/Ports分組文件位置
    •  文件tx_initialize_low_level.s在路徑ThreadX\ports\cortex_m4\ac6\example_build。
    •  其它文件在路徑ThreadX\ports\cortex_m4\ac6\src。
  •   ThreadX/Source分組文件位置
    •  所有在路徑ThreadX\common\src,全部文件所有添加進來

 

推薦使用下面的方法添加,有效防止MDK大批量添加源文件形成的卡頓問題:

 

5.4.4  第2.4步,添加配置文件tx_user.h

在User文件夾下添加文件tx_user.h,直接從本章節教程配套例子的User文件夾複製便可。此文件主要用於ThreadX配置。

 

爲了方便管理,咱們這裏將路徑ThreadX\ports\cortex_m4\ac6\inc裏面的tx_port.h文件也添加進來了。

5.4.5  第2.5步,添加頭文件的繪製文件includes.h

在User文件夾下添加文件incudes.h,直接從本章節教程配套例子的User文件夾複製便可。此文件主要用於ThreadX的各類頭文件彙總。

 

5.4.6  第2.6步,加HAL基準文件stm32f4xx_hal_timbase_tim.c

在User\bsp文件夾下添加文件stm32f4xx_hal_timebase_tim.c,直接從本章節教程配套例子的User\bsp文件夾複製便可。此文件主要用於爲HAL庫從新安排一個時間基準:

 

5.4.7  第2.7步,添加BSP驅動文件bsp_dwt.c

添加bsp_dwt.c文件和bsp_dwt.h文件主要是由於2.6步中的stm32f4xx_hal_timebase_tim.c文件裏面的函數bsp_DelayMS要使用,此函數是基於DWT系統時鐘週期計數器實現。

 

5.4.8  第2.8步,添加HAL庫文件

相關BSP驅動關聯到的HAL庫文件都添加了進來,簡單省事些,你們也能夠把HAL庫全部文件都添加進來:

 

5.4.9  第2.9步,添加預約義宏

C/C++文件中添加的預約義宏以下:

  •   USE_HAL_DRIVER
  •   STM32F429xx
  •   USE_FULL_LL_DRIVER
  •   TX_ENABLE_FPU_SUPPORT    用於支持硬件FPU
  •   TX_ENABLE_STACK_CHECKING 用於棧檢測
  •   TX_INCLUDE_USER_DEFINE_FILE 用於包含tx_user.h

 

ASM彙編文件裏面添加的宏定義:

  •   TX_ENABLE_FPU_SUPPORT

 

5.4.10        第2.10步,添加頭文件路徑

須要添加的路徑以下:

 

至此,咱們須要的GUIX文件都已經添加完畢。下面爲你們介紹如何修改用於本身的板子。

5.5   第3步,修改驅動初始化文件bsp.c

這個bsp.c文件比較重要,移植階段,直接將咱們移植好的模板內容複製過去便可,這裏把相關的內容爲你們作個說明。

5.5.1      函數System_Init

系統初始化,須要在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

}

5.5.2      函數bsp_Init

硬件外設的初始化,這個函數在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();      /* 初始化滴答定時器 */
}

5.5.3      函數SystemClock_Config

這個函數主要是完成系統時鐘配置。

/*
*********************************************************************************************************
*    函 數 名: 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();
}

5.5.4      函數bsp_RunPer10ms

這個函數裏面默認有個按鍵掃描,若是你們移植的程序裏面沒有按鍵初始化,務必要把這個按鍵掃描函數註釋掉。

/*
*********************************************************************************************************
*    函 數 名: bsp_RunPer10ms
*    功能說明: 該函數每隔10ms被Systick中斷調用1次。詳見 bsp_timer.c的定時中斷服務程序。一些處理時間要求
*             不嚴格的任務能夠放在此函數。好比:按鍵掃描、蜂鳴器鳴叫控制等。
*    形    參: 無
*    返 回 值: 無
*********************************************************************************************************
*/
void bsp_RunPer10ms(void)
{
    bsp_KeyScan10ms();
}

5.6   第4步,更新bsp_timer.c和bsp.h文件

更新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"

5.7   第5步,修改文件stm3h7xx_it.c

刪除此文件裏面帶的以下函數,ThreadX要使用,衝突了。

/**
  * @brief  This function handles PendSVC exception.
  * @param  None
  * @retval None
  */
void PendSV_Handler(void)
{
}

5.8   第6步,修改文件tx_initalize_low_level.s

這個文件有以下幾處須要修改(置紅的部分是修改的):

    .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

省略未寫
  •   將xxxx.S啓動文件的棧地址__initial_sp和中斷向量表地址__Vectors引用過來。
  •   168000000是系統時鐘主頻,1000對應的就是系統時鐘節拍,這裏1000就表示1000Hz。
  •   修改以前的LDR  r1, = Image$$ARM_LIB_STACKHEAP$$ZI$$Limit  改成LDR   r1, =__initial_sp 
  •   修改以前的LDR  r1, =vector_table

改成LDR  r1, =__Vectors

這裏修改了兩處。

5.9   第7步,ThreadX配置文件tx_user.h

ThreadX內核相關的配置,已經所有整理到了這個文件中,而且作中文註釋,你們能夠更新須要使能宏定義。

5.10 第8步,添加應用程序

應用程序比較簡單,你們能夠直接複製本章教程配置例子的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);
    }
}

5.11 實驗例程

本章節配套了以下幾個例子供你們移植參考:

  •   V6-3001_Base Template

裸機模板,方便你們添加ThreadX內核源碼,含有GCC,IAR,MDK AC5和AC6四個版本工程。

  •   V6-3002_Threadx Kernel Template

ThreadX內核模板,用於你們移植GUIX的參考Demo,含有GCC,IAR,MDK AC5和AC6四個版本工程。

 

IAR,MDK AC5和AC6工程能夠串口打印任務執行狀況:按開發板的按鍵K1能夠打印,波特率 115200,數據位 8,奇偶校驗位無,中止位 1:

 

Embedded Studio(GCC)平臺的串口打印是經過其調試組件SEGGER RTT作的串口打印,速度也很是快,打印效果以下:

 

展現裏面有亂碼是由於Embedded Studio不支持中文。

5.12 總結

本章節爲你們講解的內容涉及到的知識較多,信息量較大,部分知識點沒有弄明白是沒有關係的,可是必定要掌握ThreadX內核框架設計,掌握後再分析細節,事半功倍。

相關文章
相關標籤/搜索