1. 程式人生 > 其它 >ThreadX應用開發筆記之二:移植ThreadX到STM32H7平臺

ThreadX應用開發筆記之二:移植ThreadX到STM32H7平臺

  前面我們將ThreadX成功移植到了STM32F4平臺,但這只是我們的部分應用。我們希望將ThreadX的優勢發揮到我們的更多應用中,所以在這一篇中我們就來實現將ThreadX移植到STM32H7平臺中。

1、前期準備

  在開始將ThreadX移植到STM32H7平臺之前,我們需要做一些軟硬體方面的準備。

  首先,我們需要準備STM32H7的硬體平臺。這次我們採用STM32H750VBT6為控制單元來作為目標平臺。這是一款我們在實際專案中使用的,經過驗證的,硬體能夠穩定執行的平臺。

  其次,我們需要準備相應的軟體資源,也就是ThreadX的原始碼。ThreadX的原始碼已經開源到Github上,其地址為:

https://github.com/azure-rtos/threadx,直接下載原始碼就可以了。我們將採用目前最新的版本。下載好ThreadX的原始碼後,我們將其解壓,如下圖:

  上圖中一目瞭然,無需做太多解釋。我們需要用到的檔案主要存放在common資料夾和ports資料夾。其中common資料夾存放的是核心原始碼,ports資料夾存放的是不同平臺的介面檔案。我們的硬體採用的是STM32H750VBT6,軟體開發環境用的是IAR EWARM,所以我們選擇ports資料夾下cortex_m7下的IAR資料夾中的介面檔案。

2、系統移植

  我們準備好軟體硬體平臺後,就可以開始系統的移植了。首先我們找到一個基礎的裸機專案,能正確實現硬體的啟動及時鐘初始化就好了。接下來的移植工作主要包括:新增原始碼,修改配置等。

  第一步,我們先向專案中新增ThreadX的相關原始碼檔案。所以我們在專案下新增ThreadX組、並在ThreadX組下新增Source和Ports兩個組用於新增檔案。並將common資料夾和ports資料夾中的檔案新增到對應的分組。如下所示:

  然後要在專案屬性中為編譯器指定標頭檔案的引用路徑,主要是核心函式的標頭檔案以及介面檔案的標頭檔案兩個路徑,在我們這個專案中配置如下:

  \(PROJ_DIR\)....\ThreadX\common\inc

  \(PROJ_DIR\)....\ThreadX\ports\cortex_m4\iar\inc

  第二步,修改stm32h7xx_it.c檔案。將其中的中斷響應函式void PendSV_Handler(void)和void SysTick_Handler(void)去除。因為在ThreadX中已經實現和使用。

  第三步,修改tx_initialize_low_level.s檔案。這個檔案負責建立各種系統資料結構,並提供定時中斷源。這個檔案應該是要針對不同的底層平臺編寫。但在微軟提供的cortex_m7下IAR的介面例程中已經提供 了一個,所以我們基於這個檔案進行修改就可以了,主要根據實際應用修改的是時鐘頻率。

  SYSTEM_CLOCK EQU 480000000

  SYSTICK_CYCLES EQU ((SYSTEM_CLOCK / 1000) -1)

  第四步,修改ThreadX的配置檔案。ThreadX中要求使者提供一個tx_user.h的配置檔案。當然這個檔案並不需要從頭編寫,在common\inc目錄下有一個tx_user_sample.h檔案,我們根據這個檔案修改就可以了。

  經過上述這四步操作,我們實際上已經完成了對ThreadX核心的移植,但還沒有辦法正確使用,因為我們還沒有定義具體的任務。

3、任務實現

  我們已經完成了對ThreadX核心檔案以及介面檔案的移植,接下來我們就來實現具體的應用任務。ThreadX核心實現基本應用很簡單,只涉及到2個函式:tx_kernel_enter和tx_application_define,這兩個函式在標頭檔案“tx_api.h”中被宣告。事實上ThreadX核心所有的對外函式都在“tx_api.h”中宣告,所以凡是我們需要使用核心的地方必須引用“tx_api.h”標頭檔案。

  其中tx_kernel_enter實際是一個巨集,真正的函式是_tx_initialize_kernel_enter,用於啟動核心,這個函式需要我們在主函式中呼叫。呼叫這個函式後,核心開始執行,多工也將按照我們的設計迴圈執行。

  而tx_application_define函式只有宣告沒有實現,在_tx_initialize_kernel_enter函式中被呼叫,用於任務的建立。所有的任務都將在這個函式中被建立,而且不僅僅是任務在這個函式中建立,訊號量、佇列、互斥量等都在這個函式中建立。

  我們將在tx_application_define函式建立任務,這就需要用到tx_thread_create函式。這個函式的引數有10個,包括任務控制塊、任務函式地址、任務棧的大小及地址、任務優先順序等。這些引數都是我們需要定義或宣告的。然後我們就可以編寫tx_application_define函式:

/*tx_application_define函式實現*/
void tx_application_define(void *first_unused_memory)
{
  /* 建立系統任務 */
  tx_thread_create(&ThreadSystemTCB,       /* 任務控制塊地址 */  
                   "Thread System",       /* 任務名 */
                   ThreadSystem,         /* 啟動任務函式地址 */
                   0,               /* 傳遞給任務的引數 */
                   &ThreadSystemStack[0],      /* 堆疊基地址 */
                   THREAD_SYSTEM_STK_SIZE,  /* 堆疊空間大小 */ 
                   THREAD_SYSTEM_PRIO,    /* 任務優先順序*/
                   THREAD_SYSTEM_PRIO,    /* 任務搶佔閥值 */
                   TX_NO_TIME_SLICE,        /* 不開啟時間片 */
                   TX_AUTO_START);         /* 建立後立即啟動 */
   
  
  /* 建立模擬量處理任務 */
  tx_thread_create(&ThreadAnalogTCB,        /* 任務控制塊地址 */  
                   "Thread Analog",         /* 任務名 */
                   ThreadAnalog,         /* 啟動任務函式地址 */
                   0,               /* 傳遞給任務的引數 */
                   &ThreadAnalogStack[0],      /* 堆疊基地址 */
                   THREAD_ANALOG_STK_SIZE,  /* 堆疊空間大小 */ 
                   THREAD_ANALOG_PRIO,    /* 任務優先順序*/
                   THREAD_ANALOG_PRIO,    /* 任務搶佔閥值 */
                   TX_NO_TIME_SLICE,        /* 不開啟時間片 */
                   TX_AUTO_START);        /* 建立後立即啟動 */
  
  
  /* 建立邏輯處理任務 */
  tx_thread_create(&ThreadLogicTCB,        /* 任務控制塊地址 */   
                   "Thread Logic",       /* 任務名 */
                   ThreadLogic,         /* 啟動任務函式地址 */
                   0,               /* 傳遞給任務的引數 */
                   &ThreadLogicStack[0],       /* 堆疊基地址 */
                   THREAD_LOGIC_STK_SIZE, /* 堆疊空間大小 */ 
                   THREAD_LOGIC_PRIO,   /* 任務優先順序*/
                   THREAD_LOGIC_PRIO,   /* 任務搶佔閥值 */
                   TX_NO_TIME_SLICE,        /* 不開啟時間片 */
                   TX_AUTO_START);         /* 建立後立即啟動 */
  
  /* 建立通訊處理任務 */
  tx_thread_create(&ThreadCommTCB,        /* 任務控制塊地址 */   
                   "Thread Comm",       /* 任務名 */
                   ThreadComm,          /* 啟動任務函式地址 */
                   0,               /* 傳遞給任務的引數 */
                   &ThreadCommStack[0],      /* 堆疊基地址 */
                   THREAD_COMM_STK_SIZE, /* 堆疊空間大小 */ 
                   THREAD_COMM_PRIO,   /* 任務優先順序*/
                   THREAD_COMM_PRIO,   /* 任務搶佔閥值 */
                   TX_NO_TIME_SLICE,        /* 不開啟時間片 */
                   TX_AUTO_START);         /* 建立後立即啟動 */
  
  /* 建立統計任務 */
  tx_thread_create(&ThreadStatTCB,        /* 任務控制塊地址 */  
                   "Thread STAT",       /* 任務名 */
                   ThreadStat,         /* 啟動任務函式地址 */
                   0,              /* 傳遞給任務的引數 */
                   &ThreadStatStack[0],      /* 堆疊基地址 */
                   THREAD_IDLE_STK_SIZE,  /* 堆疊空間大小 */ 
                   THREAD_STAT_PRIO,    /* 任務優先順序*/
                   THREAD_STAT_PRIO,    /* 任務搶佔閥值 */
                   TX_NO_TIME_SLICE,       /* 不開啟時間片 */
                   TX_AUTO_START);        /* 建立後立即啟動 */
  
  
  /* 建立空閒任務 */
  tx_thread_create(&ThreadIdleTCB,     /* 任務控制塊地址 */  
                   "Thread IDLE",      /* 任務名 */
                   ThreadIdle,       /* 啟動任務函式地址 */
                   0,            /* 傳遞給任務的引數 */
                   &ThreadIdleStack[0],   /* 堆疊基地址 */
                   THREAD_IDLE_STK_SIZE,  /* 堆疊空間大小 */ 
                   THREAD_IDLE_PRIO,    /* 任務優先順序*/
                   THREAD_IDLE_PRIO,    /* 任務搶佔閥值 */
                   TX_NO_TIME_SLICE,    /* 不開啟時間片 */
                   TX_AUTO_START);     /* 建立後立即啟動 */
}

  還要在主函式中呼叫 tx_kernel_enter函式以達到啟動ThreadX核心的目的。

4、最後測試

  完成前述的全部內容後,我們編譯下載到目標平臺,系統能夠正常執行。新增ThreadX除錯外掛可以檢視個任務的執行情況如下:

  經過上述測試,我們已經成功的將ThreadX一直到立刻STM32H7平臺,這樣餘下的事情就是開發具體的應用了。

歡迎關注:

如果閱讀這篇文章讓您略有所得,還請點選下方的【好文要頂】按鈕。

當然,如果您想及時瞭解我的部落格更新,不妨點選下方的【關注我】按鈕。

如果您希望更方便且及時的閱讀相關文章,也可以掃描上方二維碼關注我的微信公眾號【木南創智