前言
- 20201009
- 移植好核心後,開始實戰核心。
- 原始碼分析一般都在程式碼註釋中。
- 本文LiteOS採用非接管中斷方式。
- 本文原始碼基於 LiteOS 2018 原始碼,最新官方原始碼中都有註釋,可參考。
- 本文原始碼與最新官方原始碼區別
- 原理一樣,原始碼稍有不同,且最新官方原始碼中帶有註釋。
連結
- LiteOS原始碼連結
- 常見問題
- 華為開發者社群
- 華為LiteOS官方教程
- 我的原始碼
- 包含 裸機原始碼
- LiteOS 工程模板
- 其它關於 LiteOS 的 demo 及 note
參考
- 上面連結
開啟排程
/* 開啟排程 */
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;
}
osTickStart
函式原始碼
- 巨集說明
OS_SYS_CLOCK
: 系統時脈頻率,單位:Hz (硬系統時脈頻率,即是CPU頻率)LOSCFG_BASE_CORE_TICK_PER_SECOND
: 每秒心跳次數 (軟系統時脈頻率,即是RTOS頻率)
- 主要內容為:
- 檢查引數
- 配置RTOS系統時鐘滴答定時器
/*****************************************************************************
Function : osTickStart
Description: Configure Tick Interrupt Start
Input : none
output : none
return : LOS_OK - Success , or LOS_ERRNO_TICK_CFG_INVALID - failed
*****************************************************************************/
LITE_OS_SEC_TEXT_INIT UINT32 osTickStart(VOID)
{
UINT32 uwRet;
if ((0 == OS_SYS_CLOCK)
|| (0 == LOSCFG_BASE_CORE_TICK_PER_SECOND)
|| (LOSCFG_BASE_CORE_TICK_PER_SECOND > OS_SYS_CLOCK))/*lint !e506*/ /* 如果每秒心跳次數設定大於系統時脈頻率的設定,則,ERROR */
{
return LOS_ERRNO_TICK_CFG_INVALID;
}
#if (LOSCFG_PLATFORM_HWI == YES) // 開啟中斷接管
#if (OS_HWI_WITH_ARG == YES) // 引數配置項
osSetVector(SysTick_IRQn, (HWI_PROC_FUNC)osTickHandler, NULL); // 設定中斷向量表
#else
osSetVector(SysTick_IRQn, osTickHandler); // 設定中斷向量表
#endif
#endif
g_uwCyclesPerTick = OS_SYS_CLOCK / LOSCFG_BASE_CORE_TICK_PER_SECOND; // 算出每個心跳的週期
g_ullTickCount = 0;
uwRet = SysTick_Config(OS_SYS_CLOCK/LOSCFG_BASE_CORE_TICK_PER_SECOND); // 配置滴答定時器。引數為:兩個中斷之間的節拍數
if (uwRet == 1)
{
return LOS_ERRNO_TICK_PER_SEC_TOO_SMALL;
}
return LOS_OK;
}
LOS_StartToRun
函式原始碼
- 分析再原始碼註釋中
- 簡略步驟
- 將 SysTick 和 PendSVd 優先順序設定為最低
- 將 g_bTaskScheduled 至為 1
- 設定控制暫存器為 CONTROL
- 更新當前執行任務
Set g_stLosTask.pstRunTask = g_stLosTask.pstNewTask;
- 更新當前執行任務的任務狀態
Set g_stLosTask.pstRunTask->usTaskStatus |= OS_TASK_STATUS_RUNNING;
- 手動更新 PSP 值,恢復到棧頂
- 更新 LR 暫存器
- 開啟中斷
- 跳轉到當前任務的 PC ,教繼續執行任務。
- 簡略步驟
LOS_StartToRun ;系統啟動函式
;; C:*OS_NVIC_SYSPRI2 = OS_NVIC_PENDSV_PRI; // 配置 SysTick 與 PendSVd 的優先順序(看圖Priority config)
LDR R4, =OS_NVIC_SYSPRI2 ;OS_NVIC_SYSPRI2這個值給 R4
LDR R5, =OS_NVIC_PENDSV_PRI ;OS_NVIC_PENDSV_PRI這個值給 R5
STR R5, [R4] ;把 R5 的值存到 R4指定的地址中
;; C:g_bTaskScheduled = 1;
LDR R0, =g_bTaskScheduled ;; 把變數 g_bTaskScheduled 的地址賦給 R0
MOV R1, #1 ;把 1 賦值給 R1 暫存器
STR R1, [R0]
;; 把 2 賦給 程式狀態暫存器 CONTROL
MOV R0, #2
MSR CONTROL, R0
;; C:g_stLosTask.pstRunTask = g_stLosTask.pstNewTask;
LDR R0, =g_stLosTask ;; R2 = g_stLosTask.pstNewTask;
LDR R2, [R0, #4] ;
LDR R0, =g_stLosTask ;; g_stLosTask.pstRunTask = g_stLosTask.pstNewTask;
STR R2, [R0]
;; C:g_stLosTask.pstRunTask->usTaskStatus = g_stLosTask.pstRunTask->usTaskStatus | OS_TASK_STATUS_RUNNING; // 把當前任務狀態更新為 OS_TASK_STATUS_RUNNING
LDR R3, =g_stLosTask ;; R0 = g_stLosTask.pstRunTask;
LDR R0, [R3]
LDRH R7, [R0 , #4] ;; R7 = g_stLosTask.pstRunTask->usTaskStatus;;
MOV R8, #OS_TASK_STATUS_RUNNING
ORR R7, R7, R8 ;; R7 = g_stLosTask.pstRunTask->usTaskStatus | OS_TASK_STATUS_RUNNING
STRH R7, [R0 , #4] ;; g_stLosTask.pstRunTask->usTaskStatus = g_stLosTask.pstRunTask->usTaskStatus | OS_TASK_STATUS_RUNNING;
;; C: R12 = *(g_stLosTask.pstRunTask->pStackPointer) + 36; // 先偏移棧指標(手動出棧) (R4-R11, PRIMASK)
LDR R12, [R0] ;; R12 = *(g_stLosTask.pstRunTask->pStackPointer);
ADD R12, R12, #36 ;; R12 = R12 + 36; // 跳過任務中原本屬於暫存器 (R4-R11, PRIMASK)的值
;; 把 R12 作為基地址,出棧。LDMFD:先出棧後遞增
;; R12 出棧到 R0,R12 遞增 4;R12 出棧到 R1,R12 遞增 4;......
LDMFD R12!, {R0-R7} ;; 把任務中原本屬於暫存器 (R0-R3, R12, LR, PC, xPSR) 中的值分別複製到 (R0-R7)
MSR PSP, R12 ;; 更新 PSP 指標
MOV LR, R5 ;; 任務中的 LR 指標值賦給 LR 暫存器
;MSR xPSR, R7 ;; 任務中的 xPSR 指標值賦給 xPSR 暫存器(遮蔽了)
CPSIE I ;; 開中斷
BX R6 ;; 跳轉到 當前任務的 PC 指標執行,並切換指令集
-
圖-Priority config
-
該函式部分變數原始碼程式碼(參考)
- 檔案 los_dispatch_keil.S 中
OS_NVIC_SYSPRI2 EQU 0xE000ED20
OS_NVIC_PENDSV_PRI EQU 0xF0F00000
- 檔案 los_task.c 中
LITE_OS_SEC_BSS BOOL g_bTaskScheduled;
LITE_OS_SEC_BSS ST_LOS_TASK g_stLosTask;
- 檔案 los_task.ph 中
- 檔案 los_dispatch_keil.S 中
/**
* @ingroup los_task
* Define the task control block structure.
*/
typedef struct tagTaskCB
{
VOID *pStackPointer; /**< Task stack pointer */
UINT16 usTaskStatus;
UINT16 usPriority;
UINT32 uwStackSize; /**< Task stack size */
UINT32 uwTopOfStack; /**< Task stack top */
UINT32 uwTaskID; /**< Task ID */
TSK_ENTRY_FUNC pfnTaskEntry; /**< Task entrance function */
VOID *pTaskSem; /**< Task-held semaphore */
VOID *pTaskMux; /**< Task-held mutex */
UINT32 uwArg; /**< Parameter */
CHAR *pcTaskName; /**< Task name */
LOS_DL_LIST stPendList;
LOS_DL_LIST stTimerList;
UINT32 uwIdxRollNum;
EVENT_CB_S uwEvent;
UINT32 uwEventMask; /**< Event mask */
UINT32 uwEventMode; /**< Event mode */
VOID *puwMsg; /**< Memory allocated to queues */
} LOS_TASK_CB;