LiteOS-任務篇-原始碼分析-系統啟動函式

李柱明發表於2020-10-09


前言

  • 20201009
  • 移植好核心後,開始實戰核心。
  • 原始碼分析一般都在程式碼註釋中
  • 本文LiteOS採用非接管中斷方式。
  • 本文原始碼基於 LiteOS 2018 原始碼,最新官方原始碼中都有註釋,可參考
  • 本文原始碼與最新官方原始碼區別
    • 原理一樣,原始碼稍有不同,且最新官方原始碼中帶有註釋。

連結

參考

  • 上面連結

開啟排程

  /* 開啟排程 */
  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 函式原始碼

  • 分析再原始碼註釋中
    • 簡略步驟
      1. SysTickPendSVd 優先順序設定為最低
      2. g_bTaskScheduled 至為 1
      3. 設定控制暫存器為 CONTROL
      4. 更新當前執行任務 Set g_stLosTask.pstRunTask = g_stLosTask.pstNewTask;
      5. 更新當前執行任務的任務狀態 Set g_stLosTask.pstRunTask->usTaskStatus |= OS_TASK_STATUS_RUNNING;
      6. 手動更新 PSP 值,恢復到棧頂
      7. 更新 LR 暫存器
      8. 開啟中斷
      9. 跳轉到當前任務的 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
/**
 * @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;

相關文章