LiteOS-任務篇

李柱明發表於2020-10-09


前言

移植好核心後,開始實戰核心。

連結

參考

  • 野火
  • 上面連結

筆錄草稿

基本概念

  • 任務是競爭系統資源的最小執行單元。任務可以使用或等待CPU、使用記憶體空間等系統資源,並獨立於其它任務執行
  • 任務與執行緒
    • 在 LiteOS 中,一個任務可以表示一條執行緒。
  • Huawei LiteOS的任務一共有 32 個優先順序(0-31),最高優先順序為0,最低優先順序為31。

任務相關概念

  • 任務狀態

    • 就緒 (Ready)
    • 執行(Running)
    • 執行(Running)
    • 退出態(Dead)
  • 任務ID

    • 可通過 任務ID 獲取 任務控制程式碼
      • ***任務控制程式碼*** = (((LOS_TASK_CB *)g_pstTaskCBArray) + (TaskID))
  • 任務控制塊TCB

    • TCB 包含了任務上下文棧指標(stack pointer)、任務狀態、任務優先順序、任務ID、任務名、任務棧大小等資訊。TCB 可以反映出每個任務執行情況。(TCB 其實就是一個襪子
  • 任務棧

    • 每一個任務都擁有一個獨立的棧空間,稱為任務棧。
  • 任務上下文切換個人把上下文分開理解

    • ** Huawei LiteOS** 在任務由執行態轉為其它狀態時會將本任務的上文資訊,儲存在自己的任務棧裡面,也稱壓棧或入棧;
    • 當任務切換到執行態時,把儲存到任務棧中的上文資訊載入到CPU暫存器中,即可恢復該任務的執行,稱為出棧。新的任務資訊也就是下文。
    • 以上流程就是 上文壓棧 --> 下文出棧

LiteOS 任務運作機制

  • Huawei LiteOS 任務管理模組提供
    • 任務建立
    • 任務刪除
    • 任務延時
    • 任務掛起
    • 任務恢復
    • 更改任務優先順序
    • 鎖定任務排程
    • 解鎖任務排程
    • 根據任務控制塊查詢任務ID
    • 根據ID查詢任務查詢任務控制塊資訊功能。
  • 任務建立時,如果 OS 的系統可用空間少於任務,則建立失敗,反之亦然。
  • 使用者建立任務時,系統會將任務棧進行初始化,預置上下文。
    • 任務入口函式 也放到了相應的位置,在任務第一次執行時便可執行 任務入口函式

核心初始化

  • 一般的 RTOS 啟動流程:MCU進入 main 函式 --> 建立任務 --> 啟動 RTOS

    • 當然,在啟動的過程中可以插入一些操作,如板級初始化 bspInit(); 等等
  • Huawei LiteOS 的啟動流程則要多一步:MCU進入 main 函式 --> LiteOS核心初始化 --> 建立任務 --> 啟動 RTOS

    • 在操作 LiteOS 必須先初始化其核心。
    • 函式 LOS_KernelInit();帶返回值)。
  • 核心初始化主要工作

    • 配置任務數量上限
    • 記憶體起始地址
    • 初始化動態記憶體池(如果記憶體溢位,則核心初始化失敗
    • 接管中斷處理(非接管中斷跳過
    • 任務初始化
      • 先建立一個空閒任務
    • 任務監視初始化
    • CPU利用率初始化
    • IPC通訊初始化:訊號量、互斥量、訊息佇列等等。
    • 軟體定時器初始化
      • 該函式內會建立一個佇列 和 一個定時任務
        • 後續會在軟體定時器相關篇章分析原始碼

建立任務

建立任務有兩種方案

  • 方案一:
    • 先建立所有任務
    • 再啟動排程
  • 方案二:
    • 先建立一個建立任務
    • 然後啟動排程
    • 建立任務裡面建立所有任務
    • 然後刪除建立任務

本章實操的是方案二。

任務相關函式

介面名 描述
LOS_TaskCreateOnly 建立任務,並使該任務進入suspend狀態,並不排程
LOS_TaskCreate 建立任務,並使該任務進入ready狀態,並排程
LOS_TaskDelete 刪除指定的任務
LOS_TaskResume 恢復掛起的任務
LOS_TaskSuspend 掛起指定的任務
LOS_TaskDelay 任務延時等待
LOS_TaskYield 顯式放權,調整指定優先順序的任務排程順序
LOS_TaskLock 鎖任務排程
LOS_TaskUnlock 解鎖任務排程
LOS_CurTaskPriSet 設定當前任務的優先順序
LOS_TaskPriSet 設定指定任務的優先順序
LOS_TaskPriGet 獲取指定任務的優先順序
LOS_CurTaskIDGet 獲取當前任務的ID
LOS_TaskInfoGet 獲取指定任務的資訊
LOS_TaskStatusGet 獲取指定任務的狀態
LOS_TaskNameGet 獲取指定任務的名稱
LOS_TaskInfoMonitor 監控所有任務,獲取所有任務的資訊
LOS_NextTaskIDGet 獲取即將被排程的任務的ID

各函式使用可以看原始碼或者例程

任務開發流程

  • 配置任務塊
  • 鎖任務(防止高優先順序任務排程
  • 建立任務
  • 解鎖任務

建立建立任務

部分原始碼

  • 使用LOS_TaskCreate函式
    • 需要一個 任務初始化引數結構體 TSK_INIT_PARAM_S 和 一個任務控制程式碼。
  • TSK_INIT_PARAM_S 原始碼
/**
 * @ingroup los_task
 * Define the structure of the parameters used for task creation.
 *
 * Information of specified parameters passed in during task creation.
 */
typedef struct tagTskInitParam
{
   TSK_ENTRY_FUNC       pfnTaskEntry;               /**< Task entrance function    */
   UINT16               usTaskPrio;                 /**< Task priority             */
   UINT32               uwArg;                      /**< Task parameters           */
   UINT32               uwStackSize;                /**< Task stack size           */
   CHAR                 *pcName;                    /**< Task name                 */
   UINT32               uwResved;                   /**< Reserved                  */
} TSK_INIT_PARAM_S;

例子

  • 把建立建立任務的工作放到一個函式裡
    • 這裡使用巨集,是因為方便管理,框架是基於本人編寫的框架。需要移植的可以直接填寫數值。
      • lssConfigvStartTaskPRIO 一個數值,表示優先順序。
      • lssConfigvStartTaskSIZE 一個數值,表示堆空間位元組數
        • 注意:這裡表示的是位元組數,其它 RTOS 可能會表示 字數
          • 如:FreeRTOS 中任務堆空間賦值就是以 字數 為單位。
          • 一個 字數 表示多個 位元組,看CPU架構是多少位的
            • 如:32位CPU,一個字 = 四個位元組 / word = 4byte
/**
* @brief  建立一個LED任務
* @param 
* @retval 
* @author lzm
*/
static UINT32 Creat_vStartTask_Task()
{
	UINT32 uwRet = LOS_OK;// 定義一個返回值變數
	TSK_INIT_PARAM_S task_init_param;// 定義一個任務引數結構體

	task_init_param.usTaskPrio = lssConfigvStartTaskPRIO;	     /* 任務優先順序,值越少,優先順序越高 */
	task_init_param.pcName = "Start_Task";                       /* 任務名 */
	task_init_param.pfnTaskEntry = (TSK_ENTRY_FUNC)vStartTask;   /* 回撥函式 */
	task_init_param.uwStackSize = lssConfigvStartTaskSIZE;		 /* 任務堆空間 */

	uwRet = LOS_TaskCreate(&StartTask_Handle, &task_init_param); /* 建立任務 */
	return uwRet;
}

建立任務的任務回撥函式 vStartTask

/**
* @brief  建立任務
* @param 
* @retval 
* @author lzm
*/
void vStartTask (void )
{
    UINT32 uwRet = LOS_OK;
    UINTPTR uvIntSave;
    
    /* 進入臨界 */
    uvIntSave = LOS_IntLock();
    
    uwRet = Creat_vLedTask_Task();
	if (uwRet != LOS_OK)
    {
        ; // 建立失敗
    }
    
    /* 刪除建立任務 */
    LOS_TaskDelete(StartTask_Handle); 
    
    /* 退出臨界 */
    (VOID)LOS_IntRestore(uvIntSave);
}

Led任務建立函式 Creat_vLedTask_Task

/**
* @brief  Led任務
* @param 
* @retval 
* @author lzm
*/
static UINT32 Creat_vLedTask_Task()
{
	UINT32 uwRet = LOS_OK;			
	TSK_INIT_PARAM_S task_init_param;	

	task_init_param.usTaskPrio = lssConfigvLedTaskPRIO;
	task_init_param.pcName = "Led Task";
	task_init_param.pfnTaskEntry = (TSK_ENTRY_FUNC)vLedTask;
	task_init_param.uwStackSize = lssConfigvLedTaskSIZE;

	uwRet = LOS_TaskCreate(&LedTask_Handle, &task_init_param);
	return uwRet;
}

Led任務回撥函式 vLedTask

  • 該函式在 LedTask.c 檔案中
/**
  ******************************************************************************
  * @file    LedTask.c
  * @author  lzm
  * @version V1.0
  * @date    2020-xx-xx
  * @brief
  * @attention
  * 實驗平臺:LZM
  ******************************************************************************
  */
#include "LedTask.h"
void vLedTask( void )
{ 
	/* 裝置初始化 */
	LSS_LED_Init();    
    /* 進入死迴圈 */
	while(1)
	{   
        LSS_LED_Flash(&LedA, LedA.cycle); // 裝置業務
        LOS_TaskDelay( 10 ); // 進入阻塞態
    }
}

開啟排程

  /* 開啟排程 */
  LOS_Start();

LOS_Start 函式原始碼

  • 具體的原始碼分析可看原始碼篇
  • 主要內容
    • 配置RTOS的節拍定時器
    • 啟動排程
/*****************************************************************************
 Function    : LOS_Start
 Description : Task start function
 Input       : None
 Output      : None
 Return      : LOS_OK on success or error code on failure
 *****************************************************************************/
LITE_OS_SEC_TEXT_INIT UINT32 LOS_Start(VOID)
{
    UINT32 uwRet;
/* 判斷是否使用專用定時器 */
#if (LOSCFG_BASE_CORE_TICK_HW_TIME == NO) // 不使用專門的定時器
    uwRet = osTickStart(); // 開啟排程

    if (uwRet != LOS_OK)
    {
        PRINT_ERR("osTickStart error\n");
        return uwRet;
    }
#else // 使用專門的定時器
    extern int os_timer_init(void); 
    uwRet = os_timer_init(); // RTOS 配置的專用定時器
    if (uwRet != LOS_OK)
    {
        PRINT_ERR("os_timer_init error\n");
        return uwRet;
    }
#endif
    LOS_StartToRun(); // 啟動排程,彙編
    return uwRet;
}

附件

任務錯誤碼列表

序號 定義 實際數值 描述 參考解決方案
1 LOS_ERRNO_TSK_NO_MEMORY 0x03000200 記憶體空間不足 分配更大的記憶體分割槽
2 LOS_ERRNO_TSK_PTR_NULL 0x02000201 任務引數為空 檢查任務引數
3 LOS_ERRNO_TSK_STKSZ_NOT_ALIGN 0x02000202 任務棧大小未對齊 對齊任務棧
4 LOS_ERRNO_TSK_PRIOR_ERROR 0x02000203 不正確的任務優先順序 檢查任務優先順序
5 LOS_ERRNO_TSK_ENTRY_NULL 0x02000204 務入口函式為空 定義任務入口函式
6 LOS_ERRNO_TSK_NAME_EMPTY 0x02000205 任務名為空 設定任務名
7 LOS_ERRNO_TSK_STKSZ_TOO_SMALL 0x02000206 任務棧太小 擴大任務棧
8 LOS_ERRNO_TSK_ID_INVALID 0x02000207 無效的任務ID 檢查任務ID
9 LOS_ERRNO_TSK_ALREADY_SUSPENDED 0x02000208 任務已經被掛起 等待這個任務被恢復後,再去嘗試掛起這個任務
10 LOS_ERRNO_TSK_NOT_SUSPENDED 0x02000209 任務未被掛起 掛起這個任務
11 LOS_ERRNO_TSK_NOT_CREATED 0x0200020a 任務未被建立 建立這個任務
12 LOS_ERRNO_TSK_OPERATE_SWTMR 0x02000222 不允許操作軟體定時器任務 使用者不要試圖去操作軟體定時器任務的設定
13 LOS_ERRNO_TSK_MSG_NONZERO 0x0200020c 任務資訊非零 暫不使用該錯誤碼
14 LOS_ERRNO_TSK_DELAY_IN_INT 0x0300020d 中斷期間,進行任務延時 等待退出中斷後再進行延時操作
15 LOS_ERRNO_TSK_DELAY_IN_LOCK 0x0200020e 任務被鎖的狀態下,進行延時 等待解鎖任務之後再進行延時操作
16 LOS_ERRNO_TSK_YIELD_INVALID_TASK 0x0200020f 將被排入行程的任務是無效的 檢查這個任務
17 LOS_ERRNO_TSK_YIELD_NOT_ENOUGH_TASK 0x02000210 沒有或者僅有一個可用任務能進行行程安排 增加任務數
18 LOS_ERRNO_TSK_TCB_UNAVAILABLE 0x02000211 沒有空閒的任務控制塊可用 增加任務控制塊數量
19 LOS_ERRNO_TSK_HOOK_NOT_MATCH 0x02000212 任務的鉤子函式不匹配 暫不使用該錯誤碼
20 LOS_ERRNO_TSK_HOOK_IS_FULL 0x02000213 任務的鉤子函式數量超過界限 暫不使用該錯誤碼
21 LOS_ERRNO_TSK_OPERATE_IDLE 0x02000214 這是個IDLE任務 檢查任務ID,不要試圖操作IDLE任務
22 LOS_ERRNO_TSK_SUSPEND_LOCKED 0x03000215 將被掛起的任務處於被鎖狀態 等待任務解鎖後再嘗試掛起任務
23 LOS_ERRNO_TSK_FREE_STACK_FAILED 0x02000217 任務棧free失敗 該錯誤碼暫不使用
24 LOS_ERRNO_TSK_STKAREA_TOO_SMALL 0x02000218 任務棧區域太小 該錯誤碼暫不使用
25 LOS_ERRNO_TSK_ACTIVE_FAILED 0x03000219 任務觸發失敗 建立一個IDLE任務後執行任務轉換
26 LOS_ERRNO_TSK_CONFIG_TOO_MANY 0x0200021a 過多的任務配置項 該錯誤碼暫不使用
27 LOS_ERRNO_TSK_CP_SAVE_AREA_NOT_ALIGN 0x0200021b 暫無 該錯誤碼暫不使用
28 LOS_ERRNO_TSK_MSG_Q_TOO_MANY 0x0200021d 暫無 該錯誤碼暫不使用
29 LOS_ERRNO_TSK_CP_SAVE_AREA_NULL 0x0200021e 暫無 該錯誤碼暫不使用
30 LOS_ERRNO_TSK_SELF_DELETE_ERR 0x0200021f 暫無 該錯誤碼暫不使用
31 LOS_ERRNO_TSK_STKSZ_TOO_LARGE 0x02000220 任務棧大小設定過大 減小任務棧大小
32 LOS_ERRNO_TSK_SUSPEND_SWTMR_NOT_ALLOWED 0x02000221 不允許掛起軟體定時器任務 檢查任務ID, 不要試圖掛起軟體定時器任務

相關文章