zoukankan      html  css  js  c++  java
  • 【LiteOS】LiteOS任务篇源码分析系统启动函数


    前言

    • 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;
    
  • 相关阅读:
    垂直搜索引擎蜘蛛
    利用Lucene.net搜索引擎进行多条件搜索的做法
    收缩数据库日志文件
    页头加上<!DOCTYPE html PUBLIC "//W3C//>后 js不符合w3c标准 对联不滚动
    winfrom中使用cache
    Vista与XP局域网文件共享设置方法
    如何快速高效的群发Email
    StringTemplate学习笔记(转载)
    清除sql 日志文件
    利用 Sandcastle 编写软件 SDK 文档
  • 原文地址:https://www.cnblogs.com/lizhuming/p/13787097.html
Copyright © 2011-2022 走看看