zoukankan      html  css  js  c++  java
  • 【LiteOS】LiteOS任务篇


    前言

    移植好内核后,开始实战内核。

    链接

    参考

    • 野火
    • 上面链接

    笔录草稿

    基本概念

    • 任务是竞争系统资源的最小运行单元。任务可以使用或等待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, 不要试图挂起软件定时器任务
  • 相关阅读:
    Oracle sql的基本优化写法和思路。
    Linux的简单介绍和开发基本运维时候用到的命令
    Nginx的使用(反向代理,负载均衡)
    Mybatis传值为空需要配置JdbcType来解决吗?(XML文件不需要配置JdbcType)
    Mybatis Blob和String互转,实现文件上传等。
    Ckeditor上传图片返回的JS直接显示出来,未执行!!!
    学习中的错误——ubuntu 14.04 LTS 启动eclipse报错
    2016计算机大会后记——机器学习:发展与未来
    2016计算机大会后记——大数据时代的模式识别
    近期编程问题——epoll failed:bad file descriptor
  • 原文地址:https://www.cnblogs.com/lizhuming/p/13784500.html
Copyright © 2011-2022 走看看