Hongmeng Hi3861 learning five-Huawei LiteOS-M (task management)

1. Task introduction

        Regarding the introduction of the task, the previous article has a more detailed introduction, so I won’t explain too much here, you can refer to the following article: FreeRTOS Learning 2 (Task)_t_guest’s Blog-CSDN Blog

The main features          of LiteOS can be summarized as follows:

  1. The task module of LiteOS can provide users with multiple tasks , realize the switching and communication between tasks , and help users manage business procedures.
  2. The task in LiteOS is a preemptive scheduling mechanism . High-priority tasks can interrupt low-priority tasks . Low-priority tasks can only be scheduled after high-priority tasks are blocked or completed. At the same time, time slice round-robin scheduling is supported .
  3. LiteOS tasks have 32 priorities (0-31) by default, the highest priority is 0 , and the lowest priority is 31.

2. Tasks

task status        

        Task status is usually divided into the following four types:

  • Ready (Ready) : The task is in the ready list, only waiting for the CPU
  • Running : The task is executing .
  • Blocked (Blocked) : The task is not in the ready list . Including tasks are suspended, tasks are delayed, tasks are waiting for semaphores, read and write queues or wait for read and write events, etc.
  • Exit state (Dead) : The task is finished , waiting for the system to reclaim resources .

noun introduction

Task ID : Returned to the user through parameters when the task is created, as a very important identification of the task

Task Priority : Priority identifies the order in which tasks are executed

Task entry function : the function that will be executed after each new task is scheduled

Task Control Block TCB : Each task contains a task control block (TCB-Task Control Block). TCB contains information such as task context stack pointer (stack pointer), task status, task priority, task ID, task name, and task stack size. TCB can reflect the running status of each task .

Task stack : Each task has an independent stack space , called task stack.

Task context : some resources used by the task during running , such as registers, etc., we call it task context. When the task is suspended, LitsOS will save the task context information of this task in its own task stack, so that after the task resumes, the context information at the time of suspension will be restored from the stack space, so as to continue execution. broken code.

Task switching : Task switching includes actions such as obtaining the highest priority task in the ready list, saving the context of the switched-out task, and restoring the context of the switched-in task.

Task State Migration

Ready state -> running state : After the task is created, it enters the ready state. When a task switch occurs, the task with the highest priority in the ready list is executed, thus entering the running state, but the task is still in the ready list at this moment.

Running state -> blocking state : the task is deleted from the ready list and enters the blocking state due to suspension, read semaphore waiting, etc.

Blocking state -> ready state (blocking state -> running state): After the blocked task is restored (task recovery, delay time timeout, read semaphore timeout or read semaphore, etc.), the restored task will is added to the ready list, thus changing from the blocking state to the ready state. At this time, if the priority of the restored task is higher than that of the running task, a task switch will occur, changing the task from the ready state to the running state.

Ready state -> blocking state : the task is suspended in the ready state, and then enters the blocking state.

Running state -> Ready state : After a higher priority task is created or restored, a task switch occurs and enters the ready list.

Running state -> Exiting state : The task is automatically deleted when the task is finished running, and the state changes from running to exiting.

Blocked -> Exited : The blocked task calls the delete interface, and the task status changes from blocked to exited.

3. Practical operation

        The kernel code of LiteOS-m is encapsulated from the CMSIS-RTOS2 interface.

1. What is CMSIS-RTOS2 interface

        CMSIS is the Cortex Microcontroller Software Interface Standard (Cortex Microcontroller Software Interface Standard). It is a set of standards that ARM and some compiler manufacturers and semiconductor manufacturers follow. It is a standard proposed by ARM specifically for the Cortex-M series. Under the agreement of this standard, ARM and chip manufacturers will provide some common API interfaces to access the Cortex core and some special peripherals, so as to reduce the money and time consumption of transplanting work such as replacing chips and development tools.

        CMSIS-RTOS2 (CMSIS-RTOS API Version 2) is a general-purpose RTOS interface for Arm® Cortex®-M processors. Standardized APIs are provided for software components that require RTOS functionality.

        CMSIS-RTOS2 is a general-purpose API, which has nothing to do with the underlying RTOS kernel. Programmers who write applications call CMSIS-RTOS2 API functions in user code, which can more easily transfer applications from one RTOS to another. Use The middleware of CMSIS-RTOS2 API can also avoid a lot of unnecessary porting work.

        Official API Reference: Main Page

         The source code files of the kernel in the SDK are in kernel/liteos_m/components/cmsis.

2. Common functions

        osThreadNew

       Function function :

        Create a new task.

        Function prototype :

osThreadId_t osThreadNew(osThreadFunc_t func, void *argument, const osThreadAttr_t *attr)

        Parameters :

        func : the callback function of the thread

        argument : A pointer passed to the thread function as a startup argument . Usually NULL

        attr : Thread attributes. Thread-related attributes are set here, including thread stack size, priority, and so on . Mainly look at the osThreadAttr_t data type.

typedef struct {
  /** Thread name */
  const char                   *name;
  /** Thread attribute bits */
  uint32_t                 attr_bits;
  /** Memory for the thread control block */
  void                      *cb_mem;
  /** Size of the memory for the thread control block */
  uint32_t                   cb_size;
  /** Memory for the thread stack */
  void                   *stack_mem;
  /** Size of the thread stack */
  uint32_t                stack_size;
  /** Thread priority */
  osPriority_t              priority;
  /** TrustZone module of the thread */
  TZ_ModuleId_t            tz_module;
  /** Reserved */
  uint32_t                  reserved;
} osThreadAttr_t;
name

thread name

pointer to a readable string with the thread object

Default value: NULL

attr_bits

Attribute bits, options for thread objects can be set.

osThreadDetached(0): create thread in detached mode (default)

osThreadJoinable(1): Create a thread in joinable mode

cb_mem

memory control block location

Points to the memory location of the thread control block object. Used when static memory allocation

Default: NULL (dynamic memory allocation)

cb_size

The size of memory provided for the control block

The size of the memory block is passed along with cb_mem. Must be greater than or equal to the size of the thread control block. (used when static memory allocation)

stack_mem

memory stack location

A pointer to the memory location of the thread's stack, which must be 64-byte aligned. Used for static memory allocation.

Default: NULL (dynamic memory allocation)

stack_size

stack size

Stack size specified by stack_mem. That is, the stack size allocated to the created thread

priority        

thread priority.

Default: osPriorityNormal(24)

Note: The priority here is different from that of liteos. Liteos priority is 31 the lowest and 0 the highest. Here 0 is the lowest and 38 is the highest .

tz_module

TrustZone module identifier

A thread context management identifier allocates context memory for a thread. The RTOS kernel running in a non-secure state calls the interface functions defined by the header file TZ_context.h. Safe to set to zero for threads that do not use safe calls at all.

reserved        

reserve

Default: 0

       return value :

        Thread ID, which can be called by other functions.

        Example :

    attr.name = "thread1";
    attr.attr_bits = 0U;
    attr.cb_mem = NULL;
    attr.cb_size = 0U;
    attr.stack_mem = NULL;
    attr.stack_size = 1024 * 1;
    attr.priority = 25; 

    g_thread1_id  = osThreadNew((osThreadFunc_t)thread1, NULL, &attr);
    if (g_thread1_id == NULL)
    {
        LOG_E("Falied to create thread1!");
    }

        osThreadYield

        Function function :

        Passes control to the next thread of the same priority that is in the READY state . If there are no other threads of the same priority in state READY, the current thread continues execution and no thread switch occurs . osThreadYield does not set the thread to state BLOCKED . Therefore, even if a READY thread is available, a lower priority thread will not be scheduled . This function cannot be called from an interrupt service routine .

        Function prototype :

osStatus_t osThreadYield(void)

        Parameters :

        none

        return value :

        osOK: success

        Other values: fail

        Example :

osThreadYield();

        osThreadGetId

        Function function :

        get thread id

        Function prototype :

osThreadGetId

        Parameters :

        none

        return value :

        thread ID

        Example :

osThreadId_t temp_t2_id = osThreadGetId();

        osThreadGetName

        Function function :

        Get the name of the thread. The name is set when the thread is created .

        Function prototype :

const char *osThreadGetName(osThreadId_t thread_id)

        Parameters :

        thread_id: Thread ID. Obtained through osThreadGetId or osThreadNew .

        return value :

        ID of the thread. Returns NULL on error

        Example :

osThreadId_t temp_t2_id = osThreadGetId();
const char *temp_name = osThreadGetName(temp_t2_id);

        osThreadGetStackSize

        Function function :

        Get the total thread stack size

        Function prototype :

uint32_t osThreadGetStackSize(osThreadId_t thread_id)

        Parameters :

        thread ID. Obtained through osThreadGetId or osThreadNew .

        return value :

        total thread stack size

        Example :

osThreadId_t temp_t2_id = osThreadGetId();
osThreadGetStackSize(temp_t2_id);

        osThreadGetStackSpace

       Function function :

        Get thread remaining stack size

        Function prototype :

uint32_t osThreadGetStackSpace(osThreadId_t thread_id)

        Parameters :

        thread ID. Obtained through osThreadGetId or osThreadNew .

       return value :

        thread remaining stack size

        Example :

osThreadId_t temp_t2_id = osThreadGetId();
osThreadGetStackSpace(temp_t2_id);

        osKernelGetTickCount

        Function function :

        Get the Tick number of the system clock. Usually the Tick count period is 1ms .

        Function prototype :

uint32_t osKernelGetTickCount(void)

        Parameters :

        none

       return value :

        number of ticks

        Example :

osKernelGetTickCount()

        osDelay

        Function function :

        Thread hang time.

        Function prototype :

osStatus_t osDelay(uint32_t ticks)

        Parameters :

        Number of pending ticks. The real hang time is ticks*10ms

        return value :

        osOK: normal

        osError: exception

        Example :

osDelay(200);

        osDelayUntil

        Function function :

        The thread is suspended until the number of ticks.

        Note: After calling this function, the thread will hang until the number of ticks of the system reaches the set number of ticks . For example, if the number of ticks is set to 1000, the thread will query the current number of system ticks after running to the osDelayUntil function. If it is less than 1000, it will suspend and wait until the number of system ticks is equal to 1000 before continuing to execute.

        Function prototype :

osStatus_t osDelayUntil(uint32_t ticks)

       Parameters :

        number of ticks

        return value :

        osOK: normal

        osError: exception

        Example :

osDelayUntil(1000);

        osThreadTerminate

        Function function :

        Delete thread. After the thread terminates, all resources are returned to the system .

        Note: This function cannot be called in interrupt service

        Function prototype :

osStatus_t osThreadTerminate(osThreadId_t thread_id)

        Parameters :

        thread ID

        return value :

        osOK: success

        Other values: exception. The meaning is as follows:

typedef enum {
  /** Operation completed successfully */
  osOK                      =  0,
  /** Unspecified error */
  osError                   = -1,
  /** Timeout */
  osErrorTimeout            = -2,
  /** Resource error */
  osErrorResource           = -3,
  /** Incorrect parameter */
  osErrorParameter          = -4,
  /** Insufficient memory */
  osErrorNoMemory           = -5,
  /** Service interruption */
  osErrorISR                = -6,
  /** Reserved. It is used to prevent the compiler from optimizing enumerations. */
  osStatusReserved          = 0x7FFFFFFF
} osStatus_t;

        Example :

osThreadId_t temp_t2_id = osThreadGetId();
osStatus_t ret = osThreadTerminate(temp_t2_id);

        

4. Comprehensive examples

        Here we create two threads, and print the stack size, name, and remaining stack size of the two threads respectively. And task 1 uses the task ID returned by osThreadNew when it is created , and task 2 uses the task ID obtained by osThreadGetId . See if the effect is the same.

#define LOG_I(fmt, args...)   printf("<%8ld> - [APP]:"fmt"\r\n",osKernelGetTickCount(),##args);

#define LOG_E(fmt, args...)   printf("<%8ld>-[APP_ERR]>>>>>>>>>>>>:"fmt"\r\n",osKernelGetTickCount(), ##args);

osThreadId_t g_thread1_id = NULL;
osThreadId_t g_thread2_id = NULL;

/*****任务一*****/
void thread1(void)
{
    LOG_I("thread 1 start");
    const char *temp_name = osThreadGetName(g_thread1_id);
    int sum = 0;
    osDelayUntil(1000);

    while (1)
    {
        LOG_I("this is Thread 1,name:[%s],thread stack size:[%ld],left stack:[%ld],sum:%d", temp_name,osThreadGetStackSize(g_thread1_id),osThreadGetStackSpace(g_thread1_id),sum);
        osDelay(100);
        if(sum++ > 10)
            break;
    }
    LOG_I("thread 1 break");
    osThreadTerminate(g_thread1_id);
}


/*****任务二*****/
void thread2(void)
{
    LOG_I("thread 2 start");
    osThreadId_t temp_t2_id = osThreadGetId();
    const char *temp_name = osThreadGetName(temp_t2_id);
    while (1)
    {
         LOG_I("this is Thread 2,name:[%s],thread stack size:[%ld],left stack:[%ld]", temp_name,osThreadGetStackSize(temp_t2_id),osThreadGetStackSpace(temp_t2_id));
        osDelay(100);
    }
    LOG_I("thread 2 end");
}


void Hello_World(void)
{
    osThreadAttr_t attr;

    LOG_I("hello!!!!!!!!!!!!!!!!!!!!!!!!!");

    attr.name = "thread1";
    attr.attr_bits = 0U;
    attr.cb_mem = NULL;
    attr.cb_size = 0U;
    attr.stack_mem = NULL;
    attr.stack_size = 1024 * 1;
    attr.priority = 25; 

    g_thread1_id  = osThreadNew((osThreadFunc_t)thread1, NULL, &attr);
    if (g_thread1_id == NULL)
    {
        LOG_E("Falied to create thread1!");
    }
    else
    {
        LOG_I("thread1 id:0x%.8x",*(uint32_t *)(g_thread1_id));
    }

    attr.name = "thread2";
    attr.stack_size = 1024 * 2;

    g_thread2_id = osThreadNew((osThreadFunc_t)thread2, NULL, &attr);
    if (g_thread2_id == NULL)
    {
        LOG_E("Falied to create thread2!");
    }
    else
    {
        LOG_I("thread2 id:0x%.8x",*(uint32_t *)(g_thread2_id));
    }  
}

SYS_RUN(Hello_World);

        The following points can be seen from the results:

  1. After thread 1 starts running, it encounters osDelayUntil and hangs directly. Wait until the system ticks reaches 1000 before continuing to run.
  2. The thread ID used in thread 1 is the one returned by osThreadNew when the thread was created. The thread ID used in thread 2 is obtained through the osThreadGetId function. can achieve the expected effect.
  3. osThreadGetStackSize and osThreadGetStackSpace will print out the total stack size and remaining stack size respectively.
  4. After thread 1 runs 10 times, it deletes itself and releases all resources.

Reference link:

Reference for CMSIS-RTOS2 Document Translation (Thread Management of CMSIS-RTOS2 API) - Programmer Sought

Guess you like

Origin blog.csdn.net/qq_26226375/article/details/130485683