目錄
前言
移植好核心後,開始實戰核心。
連結
參考
- 野火
- 上面連結
筆錄草稿
基本概念
- 任務是競爭系統資源的最小執行單元。任務可以使用或等待CPU、使用記憶體空間等系統資源,並獨立於其它任務執行
- 任務與執行緒
- 在 LiteOS 中,一個任務可以表示一條執行緒。
- Huawei LiteOS的任務一共有 32 個優先順序(0-31),最高優先順序為0,最低優先順序為31。
任務相關概念
-
任務狀態
- 就緒 (Ready)
- 執行(Running)
- 執行(Running)
- 退出態(Dead)
-
任務ID
- 可通過 任務ID 獲取 任務控制程式碼
***任務控制程式碼*** = (((LOS_TASK_CB *)g_pstTaskCBArray) + (TaskID))
- 可通過 任務ID 獲取 任務控制程式碼
-
任務控制塊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
- 注意:這裡表示的是位元組數,其它 RTOS 可能會表示 字數
- 這裡使用巨集,是因為方便管理,框架是基於本人編寫的框架。需要移植的可以直接填寫數值。
/**
* @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, 不要試圖掛起軟體定時器任務 |