Learning of uC/OS _ii Based on stm32f103zet6 2 (Preliminary Analysis of OS-lighting method)

Source: Internet
Author: User

Now let's take a closer look at how the entire lighting method is implemented.

I. hardware initialization.

In this case, the GPIO is initialized.

LED_GPIO_Config (); // initialize the LED Port

The specific configuration is not detailed.

Ii. operating system initialization

OSInit();

Next, let's take a look at what the mask has done:

void  OSInit (void){    OSInitHookBegin();                                           /* Call port specific initialization code   */    OS_InitMisc();                                               /* Initialize miscellaneous variables       */    OS_InitRdyList();                                            /* Initialize the Ready List                */    OS_InitTCBList();                                            /* Initialize the free list of OS_TCBs      */    OS_InitEventList();                                          /* Initialize the free list of OS_EVENTs    */    OS_InitTaskIdle();                                           /* Create the Idle Task                     */    OS_InitTaskStat();                                           /* Create the Statistic Task                */    OSInitHookEnd();                                             /* Call port specific init. code            */}

The above is the simplified code for removing some macro switches:

1. The first is the hook function. Next I will talk about this hook function in combination with the official documentation and my own understanding.

I understand that for our beginners, hook functions do not need to be taken care of. They directly turn off the macro switch because of the extended functions of the operating system.
This hook function is used to expand the functions of the operating system. The hook function is added
Prevent us from directly modifying the source code. This damages the source code!

That is to say, we can comment out the two hook functions directly. Try it by yourself. I have tried it!

2. The OS _InitMisc () is followed. The comments are used to initialize various variables. Let's take a look at the Code as follows:

static  void  OS_InitMisc (void){#if OS_TIME_GET_SET_EN > 0    OSTime        = 0L;                                    /* Clear the 32-bit system clock            */#endif    OSIntNesting  = 0;                                     /* Clear the interrupt nesting counter      */    OSLockNesting = 0;                                     /* Clear the scheduling lock counter        */    OSTaskCtr     = 0;                                     /* Clear the number of tasks                */    OSRunning     = OS_FALSE;                              /* Indicate that multitasking not started   */    OSCtxSwCtr    = 0;                                     /* Clear the context switch counter         */    OSIdleCtr     = 0L;                                    /* Clear the 32-bit idle counter            */#if OS_TASK_STAT_EN > 0    OSIdleCtrRun  = 0L;    OSIdleCtrMax  = 0L;    OSStatRdy     = OS_FALSE;                              /* Statistic task is not ready              */#endif}

From the above code, we can obtain the following information:

These lines of code are used to clear the initial values of the system timer, the interrupt counter, and the number of current tasks.

3. OS _InitRdyList indicates the initialization ready state list.

In this case, the sequence table refers to the ready state task of the task in the three States. For details about the three states, refer to Baidu!

So we can follow up to see what the code has done,

static  void  OS_InitRdyList (void){    INT8U    i;#if OS_LOWEST_PRIO <= 63    INT8U   *prdytbl;#else    INT16U  *prdytbl;#endif    OSRdyGrp      = 0;                                     /* Clear the ready list                     */    prdytbl       = &OSRdyTbl[0];    for (i = 0; i < OS_RDY_TBL_SIZE; i++) {        *prdytbl++ = 0;    }    OSPrioCur     = 0;    OSPrioHighRdy = 0;    OSTCBHighRdy  = (OS_TCB *)0;    OSTCBCur      = (OS_TCB *)0;}

Again, we can get the following information from the code:

Clears the priority of the current task, the highest priority of the ready state task, and the control block.

4. Next, let's look at an important function. OS _InitTCBList

static  void  OS_InitTCBList (void){    INT8U    i;    OS_TCB  *ptcb1;    OS_TCB  *ptcb2;    OS_MemClr((INT8U *)&OSTCBTbl[0],     sizeof(OSTCBTbl));      /* Clear all the TCBs                 */    OS_MemClr((INT8U *)&OSTCBPrioTbl[0], sizeof(OSTCBPrioTbl));  /* Clear the priority table           */    ptcb1 = &OSTCBTbl[0];    ptcb2 = &OSTCBTbl[1];    for (i = 0; i < (OS_MAX_TASKS + OS_N_SYS_TASKS - 1); i++) {  /* Init. list of free TCBs            */        ptcb1->OSTCBNext = ptcb2;#if OS_TASK_NAME_SIZE > 1        ptcb1->OSTCBTaskName[0] = '?';                           /* Unknown name                       */        ptcb1->OSTCBTaskName[1] = OS_ASCII_NUL;#endif        ptcb1++;        ptcb2++;    }    ptcb1->OSTCBNext = (OS_TCB *)0;                              /* Last OS_TCB                        */#if OS_TASK_NAME_SIZE > 1    ptcb1->OSTCBTaskName[0] = '?';                               /* Unknown name                       */    ptcb1->OSTCBTaskName[1] = OS_ASCII_NUL;#endif    OSTCBList               = (OS_TCB *)0;                       /* TCB lists initializations          */    OSTCBFreeList           = &OSTCBTbl[0];}

The code here involves some complicated data structures, which are not detailed at the moment. Find a time for special research, which is to complete the initialization of some linked lists.

5. The OS _InitEventList function is similar to step 1.

At this point, I have probably understood what has been done in initialization, and the next step is this

Iii. Task creation code

OSTaskCreate(Task_LED,(void *)0, &startup_task_stk[STARTUP_TASK_STK_SIZE-1], STARTUP_TASK_PRIO);

Let's take a good look at how task creation works.

1. Analysis of function prototype

INT8U  OSTaskCreate (void (*task)(void *p_arg), void *p_arg, OS_STK *ptos, INT8U prio)

The above is the function prototype.

The first parameter is the name of the task to be created. The parameter is the pointer function pointer, so when we assign a value, we can directly assign a function name to it.

The second parameter is the parameter passed by the task. A void pointer. The value assignment can be null.

Third parameter: stack space allocated for the task. The stack address is passed, so we need to allocate an address to the stack in advance, and then pass the address in

The fourth parameter is the priority of the task we created.

OK function prototype description completed

2. Follow the task creation function to see what has been done?

INT8U  OSTaskCreate (void (*task)(void *p_arg), void *p_arg, OS_STK *ptos, INT8U prio){    OS_STK    *psp;    INT8U      err;#if OS_CRITICAL_METHOD == 3                  /* Allocate storage for CPU status register               */    OS_CPU_SR  cpu_sr = 0;#endif#if OS_ARG_CHK_EN > 0    if (prio > OS_LOWEST_PRIO) {             /* Make sure priority is within allowable range           */        return (OS_ERR_PRIO_INVALID);    }#endif    OS_ENTER_CRITICAL();    if (OSIntNesting > 0) {                  /* Make sure we don't create the task from within an ISR  */        OS_EXIT_CRITICAL();        return (OS_ERR_TASK_CREATE_ISR);    }    if (OSTCBPrioTbl[prio] == (OS_TCB *)0) { /* Make sure task doesn't already exist at this priority  */        OSTCBPrioTbl[prio] = OS_TCB_RESERVED;/* Reserve the priority to prevent others from doing ...  */                                             /* ... the same thing until task is created.              */        OS_EXIT_CRITICAL();        psp = OSTaskStkInit(task, p_arg, ptos, 0);              /* Initialize the task's stack         */        err = OS_TCBInit(prio, psp, (OS_STK *)0, 0, 0, (void *)0, 0);        if (err == OS_ERR_NONE) {            if (OSRunning == OS_TRUE) {      /* Find highest priority task if multitasking has started */                OS_Sched();            }        } else {            OS_ENTER_CRITICAL();            OSTCBPrioTbl[prio] = (OS_TCB *)0;/* Make this priority available to others                 */            OS_EXIT_CRITICAL();        }        return (err);    }    OS_EXIT_CRITICAL();    return (OS_ERR_PRIO_EXIST);}

You can see that you have done something.

1. Clear the Status Register and check whether the priority is valid.

2. OS _ENTER_CRITICAL (); indicates that the code below the CPU cannot be interrupted. That is to say, after entering the critical section, the interrupt is disabled in this function. This is mentioned in the previous blog.

3. The code below is to ensure that there is no task created above the defined priority. If this task is not created, we will mark it as a task.

4.

        psp = OSTaskStkInit(task, p_arg, ptos, 0);              /* Initialize the task's stack         */        err = OS_TCBInit(prio, psp, (OS_STK *)0, 0, 0, (void *)0, 0);

Initialize a function of the task stack. Analyze it carefully.

OS_STK *OSTaskStkInit (void (*task)(void *p_arg), void *p_arg, OS_STK *ptos, INT16U opt){    OS_STK *stk;    (void)opt;                                   /* 'opt' is not used, prevent warning                 */    stk       = ptos;                            /* Load stack pointer                                 */                                                 /* Registers stacked as if auto-saved on exception    */    *(stk)    = (INT32U)0x01000000L;             /* xPSR                                               */    *(--stk)  = (INT32U)task;                    /* Entry Point                                        */    *(--stk)  = (INT32U)0xFFFFFFFEL;             /* R14 (LR) (init value will cause fault if ever used)*/    *(--stk)  = (INT32U)0x12121212L;             /* R12                                                */    *(--stk)  = (INT32U)0x03030303L;             /* R3                                                 */    *(--stk)  = (INT32U)0x02020202L;             /* R2                                                 */    *(--stk)  = (INT32U)0x01010101L;             /* R1                                                 */    *(--stk)  = (INT32U)p_arg;                   /* R0 : argument                                      */                                                 /* Remaining registers saved on process stack         */    *(--stk)  = (INT32U)0x11111111L;             /* R11                                                */    *(--stk)  = (INT32U)0x10101010L;             /* R10                                                */    *(--stk)  = (INT32U)0x09090909L;             /* R9                                                 */    *(--stk)  = (INT32U)0x08080808L;             /* R8                                                 */    *(--stk)  = (INT32U)0x07070707L;             /* R7                                                 */    *(--stk)  = (INT32U)0x06060606L;             /* R6                                                 */    *(--stk)  = (INT32U)0x05050505L;             /* R5                                                 */    *(--stk)  = (INT32U)0x04040404L;             /* R4                                                 */    return (stk);}

Compare the above Code with the official comments to explain it

A is a stack initialization function, simulating the inbound stack operation.

The growth direction of stack B is downward, and the top address of stack is returned.

C each register into the stack order is determined, because our above code is to simulate R0-R12 + spSR these registers into the stack, which is based on the authoritative manual above to simulate

For more information, see the authoritative manual.

D. This function does not need to return values, so LR (R14) is an invalid value.

E xPSR Status Register should be set to thread mode, T location 1

Another important function is to initialize the function of the task control block. It passes in the previous parameters such as the stack top pointer and does not detail them.

Once the OSTaskStkInit () function completes the stack creation task, OSTaskCreate () calls OSTCBInit () to obtain and initialize an OS _TCB from the idle OS _TCB pool.

If the OS _TCB pool has an idle OS _TCB, It is initialized. Note that once the OS _TCB is assigned, the task creator has it, even if the kernel is created again

These new tasks cannot perform any operation on the assigned OS _TCB. Therefore, OSTCBInit () allows interruption and continues to initialize the data unit of OS _TCB.

Now that the task is created, let's start running the task.

Iv. OSStart code analysis

void  OSStart (void){    if (OSRunning == OS_FALSE) {        OS_SchedNew();                               /* Find highest priority's task priority number   */        OSPrioCur     = OSPrioHighRdy;        OSTCBHighRdy  = OSTCBPrioTbl[OSPrioHighRdy]; /* Point to highest priority task ready to run    */        OSTCBCur      = OSTCBHighRdy;        OSStartHighRdy();                            /* Execute target specific code to start task     */    }}

Note that when no task is running, a high-priority task is selected for execution, and the single task system is implemented, the next step is to see how to implement the first task system.

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.