打印
[STM32F0]

【转】基于STM32的简易RTOS

[复制链接]
1729|6
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
说书先生|  楼主 | 2016-12-23 12:38 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式

之前看过一篇卢晓铭写的简易RTOS设计,自己也实践了一下,感觉多任务运行起来毫无压力,在此做份笔记以备他日之需也为他人提供一份参考


要想完成一个RTOS,我们核心任务是需要编写任务调度。

所以,我们需要知道,任务到底什么地方会被调度。

1.        我们开始OSStart();时,肯定需要调度一次任务。这样才能进入第一个最高优先级就绪任务中。

2.        在任务中的OSTimeDly();延时函数中,我们需要进行任务调度。当前任务延时了,肯定就要换一个别的任务来运行呀。

3.        在中断退出时,需要进行任务调度(该处主要指定时器中断),可以理解为每个时钟周期都在进行任务最高优先级别的检验。


任务状态的标志,我想我们可以用1bit来代表,0:代表任务挂起或不存在,1:代表任务就绪。

U32 OSRdyTbl;        这是一个32bit的任务就绪表,每一位代表任务的状态.

/*在就绪表中登记任务*/

__inline void OSSetPrioRdy(u8 prio)                                      //__inline是内联函数,用在该处是为了提高效率。关于内联函数的详情和使用,可以百度。

{

        OSRdyTbl|= 1 << prio;

}


/*在就绪表中删除任务*/

__inline void OSDelPrioRdy(u8 prio)

{

        OSRdyTbl&= ~(1<<prio);

}


在每个任务调度前,肯定需要知道当前最高优先级的就绪任务是什么,所以我们需要一个查找函数

/*在就绪表中查找更高级的就绪任务*/

__inline void OSGetHighRdy(void)

{

        u8OSNextTaskPrio = 0;                           /*任务优先级*/


        for(OSNextTaskPrio = 0; (OSNextTaskPrio < OS_TASKS) &&(!(OSRdyTbl&(0x01<<OSNextTaskPrio))); OSNextTaskPrio++ );  //注意for最后有个分号

        OSPrioHighRdy= OSNextTaskPrio;        //获得最高优先级,OSPrioHighRdy是一个全局变量

}


根据分析,我们知道我们的简易RTOS有3个地方会出现任务调度

首先是任务刚开始时.

我们先定义几个全局变量:

1.        OSRunning指示OS是否开始运行

2.        OSPrioCur指示当前任务优先级

3.        OSPrioHighRdy指示当前已就绪的最高优先级任务,由OSGetHighRdy函数更新

void OSStart(void)

{

        if(OSRunning== 0)                     //OSRuning是一个全局变量

        {

                      OSRunning= 1;


        //先不忙讲任务创建 OSTaskCreate(IdleTask, (void *)0,(u32 *)&IDELTASK_STK[31], IdelTask_Prio);             //创建空闲任


                      OSGetHighRdy();                                       /*获得最高级的就绪任务*/

                      OSPrioCur= OSPrioHighRdy;                  /*获得最高优先级就绪任务ID*/

                      p_OSTCBCur= &TCB[OSPrioCur];

                      p_OSTCBHighRdy= &TCB[OSPrioHighRdy];

                      OSStartHighRdy();                       //在汇编语句中

        }

}

其次出现任务调度的地方是延时函数OSTimeDly()

在这个函数前,要先介绍一个结构体TCB,这是任务控制怪(Task Control Block)

每一个任务都有一个任务控制块,这个控制块记录着任务的重要信息,由于该处是简易OS设计,所以仅仅有两种

typedef struct TaskCtrBlockHead                 /*任务控制块数据结构*/

{

        u32OSTCBStkPtr;                                                    /*保存任务栈顶地址*/

        u32OSTCBDly;                                                                       /*任务延时时钟*/

}TaskCtrBlock;

#define OS_TASKS 32                                                    //最多任务数

TaskCtrBlock TCB[OS_TASKS];                                       //定义任务TCB,由于最多有32个任务,所以该处定义32个TCB



void OSTimeDly(u32 ticks)

{

        if(ticks> 0)

        {

                      OS_ENTER_CRITICAL();                                                         //进入临界区

                      OSDelPrioRdy(OSPrioCur);                                   //将任务挂起

                      TCB[OSPrioCur].OSTCBDly= ticks;                      //设置TCB中任务延时节拍数

                      OS_EXIT_CRITICAL();                                               //退出临界区

                      OSSched();                                                                //任务调度

        }

}

/*任务切换*/

void OSSched(void)

{

        OSGetHighRdy();                                                                   //找出任务就绪表中优先级最高的任务

        if(OSPrioHighRdy!=OSPrioCur)              //如果不是当前运行任务,进行任务调度

        {

                      p_OSTCBCur= &TCB[OSPrioCur];                       //以便在汇编中引用,可以理解为用于将现在的任务环境保存在该指针指向的堆栈中

//直接把当前任务的堆栈指针保存到当前任务的TCB(TCB的OSTCBStkPtr)

                      p_OSTCBHighRdy= &TCB[OSPrioHighRdy];     //以便在汇编中引用,可以理解为用于将该指针中的数据释放出来,恢复指定任务环境

//直接把最高优先级就绪任务的TCB(TCB的OSTCBStkPtr)设为当前任务的堆栈指针

                      OSPrioCur= OSPrioHighRdy;                                //更新OSPrio

                      OSCtxSw();                                                                //调度任务,在汇编中引用

        }

}


最后是在时钟中断中出现

由于每次时钟中断我们都需要解决任务时钟延时问题,所以我们需要一个函数

/*定时器中断对任务延时处理函数*/

void TicksInterrupt(void)

{

        static u8i;


        OSTime++;

        for(i=0;i<OS_TASKS;i++)                                       

        {

                      if(TCB.OSTCBDly)

                      {

                                    TCB.OSTCBDly--;

                                    if(TCB.OSTCBDly==0)             //延时时钟到达

                                    {

                                                  OSSetPrioRdy(i);            //任务重新就绪

                                    }            

                      }

        }

}


//系统时钟中断服务函数

void SysTick_Handler(void)

{

        OS_ENTER_CRITICAL();                             //进入临界区

   OSIntNesting++;                         //任务前套数

   OS_EXIT_CRITICAL();                  //退出临界区

   TicksInterrupt();                          //

    OSIntExit();                                   //在中断中处理任务调度

}

void OSIntExit(void)

{

        OS_ENTER_CRITICAL();                             //进入临界区


        if(OSIntNesting> 0)

        OSIntNesting--;

        if(OSIntNesting== 0)                               //没有中断嵌套时,才可以进行任务调度

        {

                      OSGetHighRdy();                                                                   /*找出任务优先级最高的就绪任务*/

                      if(OSPrioHighRdy!=OSPrioCur)              /*当前任务并非优先级最高的就绪任务*/

                      {

                                    p_OSTCBCur= &TCB[OSPrioCur];

                                    p_OSTCBHighRdy= &TCB[OSPrioHighRdy];

                                    OSPrioCur= OSPrioHighRdy;

                                    OSIntCtxSw();                                             /*中断级任务调度,注意这里和OSCtxSw不一样,但是作用是一样的*/

                      }

        }

OS_EXIT_CRITICAL();                   //退出临界区

}


现在任务调度已经写完了,那么应该要创建任务了吧,这里使用创建任务函数

/*任务创建*/

void OSTaskCreate(void (*Task)(void  *parg), void *parg,u32 *p_Stack, u8 TaskID)

{

        if(TaskID<= OS_TASKS)

        {

            *(p_Stack) = (u32)0x01000000L;                                                        /*  xPSR                        */

            *(--p_Stack) = (u32)Task;                                                          /*  Entry Point of the task  任务入口地址   */

            *(--p_Stack) = (u32)0xFFFFFFFEL;                                                         /*  R14 (LR) (init value will  */


            *(--p_Stack) = (u32)0x12121212L;                                                     /*  R12                         */

            *(--p_Stack) = (u32)0x03030303L;                                                     /*  R3                          */

            *(--p_Stack) = (u32)0x02020202L;                                                     /*  R2                          */

            *(--p_Stack) = (u32)0x01010101L;                                                     /*  R1                          */

            *(--p_Stack) = (u32)parg;                                                         /*  R0 : argument 输入参数    */


            *(--p_Stack) = (u32)0x11111111L;                                                     /*  R11                         */

            *(--p_Stack) = (u32)0x10101010L;                                                     /*  R10                         */

            *(--p_Stack) = (u32)0x09090909L;                                                     /*  R9                          */

            *(--p_Stack) = (u32)0x08080808L;                                                     /*  R8                          */

            *(--p_Stack) = (u32)0x07070707L;                                                     /*  R7                          */

            *(--p_Stack) = (u32)0x06060606L;                                                     /*  R6                          */

            *(--p_Stack) = (u32)0x05050505L;                                                     /*  R5                          */

            *(--p_Stack) = (u32)0x04040404L;                                                     /*  R4                         */


                      TCB[TaskID].OSTCBStkPtr= (u32)p_Stack;                                    /*保存堆栈地址*/

                      TCB[TaskID].OSTCBDly= 0;                                                                              /*初始化任务延时*/

                      OSSetPrioRdy(TaskID);                                                                                     /*在任务就绪表中登记*/

        }

}

这里主要是入栈寄存器地址


沙发
说书先生|  楼主 | 2016-12-23 12:39 | 只看该作者

为了保证系统的正常运行,我们需要一个空闲任务,空闲任务可以什么事情都不做,也可以随便做点什么简单的事。

/*系统空闲任务*/

void IdleTask(void *pdata)

{

        u32IdleCount = 0;

        while(1)

        {

                      IdleCount++;

        }

}


既然如此,那么系统开始前应该申请一个空闲任务,所以OSStart()函数改为

void OSStart(void)

{

        if(OSRunning== 0)

        {

                      OSRunning= 1;


                      OSTaskCreate(IdleTask,(void *)0, (u32 *)&IDELTASK_STK[31], IdelTask_Prio);             //创建空闲任务


                      OSGetHighRdy();                                                                   /*获得最高级的就绪任务*/

                      OSPrioCur= OSPrioHighRdy;                  /*获得最高优先级就绪任务ID*/

                      p_OSTCBCur= &TCB[OSPrioCur];

                      p_OSTCBHighRdy= &TCB[OSPrioHighRdy];

                      OSStartHighRdy();

        }

}


以上就是任务调度器的核心.

至于汇编代码,可以直接参考ucosii在STM32上的汇编代码。


文件RTOS.c
[objc] view plain copy


  • /*********************** (C) COPYRIGHT 2013 Libraworks *************************
  • * File Name     : RTOS.c
  • * Author        : 卢晓铭  
  • * Version       : V1.0
  • * Date          : 01/26/2013
  • * Description   : LXM-RTOS 任务管理
  • *******************************************************************************/  
  •   
  • #include"RTOS.h"  
  •   
  • TaskCtrBlock TCB[OS_TASKS - 1]; /*任务控制块定义*/  
  • TaskCtrBlock *p_OSTCBCur;       /*指向当前任务控制块的指针*/  
  • TaskCtrBlock *p_OSTCBHighRdy;   /*指向最高优先级就绪任务控制块的指针*/  
  • u8 OSPrioCur;                   /*当前执行任务*/  
  • u8 OSPrioHighRdy;               /*最高优先级*/  
  • u8 OSRunning;                   /*多任务运行标志0:为运行,1:运行*/  
  •   
  • u32 OSInterruptSum;             /*进入中断次数*/  
  •   
  • u32 OSTime;                     /*系统时间(进入时钟中断次数)*/  
  •   
  • u32 OSRdyTbl;                   /*任务就绪表,0表示挂起,1表示就绪*/  
  •   
  • u32 OSIntNesting;               /*任务嵌套数*/  
  •   
  • /*在就绪表中登记任务*/  
  • void OSSetPrioRdy(u8 prio)  
  • {  
  •     OSRdyTbl |= 1 << prio;  
  • }  
  •   
  • /*在就绪表中删除任务*/  
  • void OSDelPrioRdy(u8 prio)  
  • {  
  •     OSRdyTbl &= ~(1<<prio);  
  • }  
  •   
  • /*在就绪表中查找更高级的就绪任务*/  
  • void OSGetHighRdy(void)  
  • {  
  •     u8 OSNextTaskPrio = 0;      /*任务优先级*/  
  •   
  •     for (OSNextTaskPrio = 0; (OSNextTaskPrio < OS_TASKS) && (!(OSRdyTbl&(0x01<<OSNextTaskPrio))); OSNextTaskPrio++ );  
  •     OSPrioHighRdy = OSNextTaskPrio;   
  • }  
  •   
  • /*设置任务延时时间*/  
  • void OSTimeDly(u32 ticks)  
  • {  
  •     if(ticks > 0)  
  •     {  
  •         OS_ENTER_CRITICAL();                //进入临界区  
  •         OSDelPrioRdy(OSPrioCur);            //将任务挂起  
  •         TCB[OSPrioCur].OSTCBDly = ticks;    //设置TCB中任务延时节拍数  
  •         OS_EXIT_CRITICAL();                 //退出临界区  
  •         OSSched();  
  •     }  
  • }  
  •   
  • /*定时器中断对任务延时处理函数*/  
  • void TicksInterrupt(void)  
  • {  
  •     static u8 i;  
  •   
  •     OSTime++;  
  •     for(i=0;i<OS_TASKS;i++)  
  •     {  
  •         if(TCB.OSTCBDly)  
  •         {  
  •             TCB.OSTCBDly--;  
  •             if(TCB.OSTCBDly==0)  //延时时钟到达  
  •             {  
  •                 OSSetPrioRdy(i);    //任务重新就绪  
  •             }     
  •         }  
  •     }  
  • }  
  •   
  • /*任务切换*/  
  • void OSSched(void)  
  • {  
  •     OSGetHighRdy();                 //找出任务就绪表中优先级最高的任务  
  •     if(OSPrioHighRdy!=OSPrioCur)    //如果不是当前运行任务,进行任务调度  
  •     {  
  •         p_OSTCBCur = &TCB[OSPrioCur];               //汇编中引用           
  •         p_OSTCBHighRdy = &TCB[OSPrioHighRdy];       //汇编中引用  
  •         OSPrioCur = OSPrioHighRdy;  //更新OSPrio  
  •         OSCtxSw();                  //调度任务  
  •     }  
  • }  




使用特权

评论回复
板凳
说书先生|  楼主 | 2016-12-23 12:40 | 只看该作者
/*任务创建*/  
void OSTaskCreate(void  (*Task)(void  *parg), voidvoid *parg, u32 *p_Stack, u8 TaskID)  
{  
    if(TaskID <= OS_TASKS)  
    {  
        *(p_Stack) = (u32)0x01000000L;                  /*  xPSR                        */   
        *(--p_Stack) = (u32)Task;                       /*  Entry Point of the task  任务入口地址   */  
        *(--p_Stack) = (u32)0xFFFFFFFEL;                /*  R14 (LR)  (init value will  */  
                                                                                 
        *(--p_Stack) = (u32)0x12121212L;                /*  R12                         */  
        *(--p_Stack) = (u32)0x03030303L;                /*  R3                          */  
        *(--p_Stack) = (u32)0x02020202L;                /*  R2                          */  
        *(--p_Stack) = (u32)0x01010101L;                /*  R1                          */  
        *(--p_Stack) = (u32)parg;                       /*  R0 : argument  输入参数     */  
  
        *(--p_Stack) = (u32)0x11111111L;                /*  R11                         */  
        *(--p_Stack) = (u32)0x10101010L;                /*  R10                         */  
        *(--p_Stack) = (u32)0x09090909L;                /*  R9                          */  
        *(--p_Stack) = (u32)0x08080808L;                /*  R8                          */  
        *(--p_Stack) = (u32)0x07070707L;                /*  R7                          */  
        *(--p_Stack) = (u32)0x06060606L;                /*  R6                          */  
        *(--p_Stack) = (u32)0x05050505L;                /*  R5                          */  
        *(--p_Stack) = (u32)0x04040404L;                /*  R4                          */  
  
        TCB[TaskID].OSTCBStkPtr = (u32)p_Stack;         /*保存堆栈地址*/  
        TCB[TaskID].OSTCBDly = 0;                       /*初始化任务延时*/  
        OSSetPrioRdy(TaskID);                           /*在任务就绪表中登记*/  
    }  
}  
  
void OSTaskSuspend(u8 prio)  
{  
    OS_ENTER_CRITICAL();        /*进入临界区*/  
    TCB[prio].OSTCBDly = 0;  
    OSDelPrioRdy(prio);         /*挂起任务*/  
    OS_EXIT_CRITICAL();         /*退出临界区*/  
  
    if(OSPrioCur == prio)       /*挂起的任务为当前运行的任务*/  
    {  
        OSSched();              /*重新调度*/  
    }  
}  
  
void OSTaskResume(u8 prio)  
{  
    OS_ENTER_CRITICAL();  
    TCB[prio].OSTCBDly = 0;     /*设置任务延时时间为0*/  
    OSSetPrioRdy(prio);         /*就绪任务*/  
    OS_EXIT_CRITICAL();  
  
    if(OSPrioCur > prio)     /*当前任务优先级小于恢复的任务优先级*/  
    {  
        OSSched();  
    }  
}  
  
u32 IDELTASK_STK[32];  
  
void OSStart(void)  
{  
    if(OSRunning == 0)  
    {  
        OSRunning = 1;  
         
        OSTaskCreate(IdleTask, (voidvoid *)0, (u32 *)&IDELTASK_STK[31], IdelTask_Prio); //创建空闲任务  
  
        OSGetHighRdy();                 /*获得最高级的就绪任务*/  
        OSPrioCur = OSPrioHighRdy;      /*获得最高优先级就绪任务ID*/  
        p_OSTCBCur = &TCB[OSPrioCur];  
        p_OSTCBHighRdy = &TCB[OSPrioHighRdy];  
        OSStartHighRdy();  
    }  
}  
  
void OSIntExit(void)  
{  
    OS_ENTER_CRITICAL();  
      
    if(OSIntNesting > 0)  
        OSIntNesting--;  
    if(OSIntNesting == 0)  
    {  
        OSGetHighRdy();                 /*找出任务优先级最高的就绪任务*/  
        if(OSPrioHighRdy!=OSPrioCur)    /*当前任务并非优先级最高的就绪任务*/  
        {  
            p_OSTCBCur = &TCB[OSPrioCur];  
            p_OSTCBHighRdy = &TCB[OSPrioHighRdy];  
            OSPrioCur = OSPrioHighRdy;  
            OSIntCtxSw();               /*中断级任务调度*/  
        }  
    }  
  
    OS_EXIT_CRITICAL();  
}  
  
/*系统空闲任务*/  
void IdleTask(voidvoid *pdata)  
{  
    u32 IdleCount = 0;  
    while(1)  
    {  
        IdleCount++;  
    }  
}  
  
void OSTaskSwHook(void)  
{  
}  

文件RTOS.h
[objc] view plain copy


  • ;/*********************** (C) COPYRIGHT 2013 Libraworks *************************
  • ;* File Name    : RTOS.h
  • ;* Author       : 卢晓铭  
  • ;* Version      : V1.0
  • ;* Date         : 01/26/2013
  • ;* Description  : LXM-RTOS asm port
  • ;*******************************************************************************/  
  • #ifndef __RTOS_H  
  • #define __RTOS_H  
  • #include "stm32f10x.h"//加入头文件  
  •   
  • typedef struct TaskCtrBlockHead     /*任务控制块数据结构*/  
  • {  
  •     u32 OSTCBStkPtr;                /*保存任务栈顶*/  
  •     u32 OSTCBDly;                   /*任务延时时钟*/  
  • }TaskCtrBlock;  
  •   
  • #define OS_TASKS 32             /*总任务数*/  
  • #define IdelTask_Prio 31        /*空闲任务优先级*/  
  •   
  • extern TaskCtrBlock TCB[OS_TASKS - 1];  /*任务控制块定义*/  
  • extern TaskCtrBlock *p_OSTCBCur;        /*指向当前任务控制块的指针*/  
  • extern TaskCtrBlock *p_OSTCBHighRdy;    /*指向最高优先级就绪任务控制块的指针*/  
  • extern u8 OSPrioCur;                    /*当前执行任务*/  
  • extern u8 OSPrioHighRdy;                /*最高优先级*/  
  • extern u8 OSRunning;                    /*多任务运行标志0:为运行,1:运行*/  
  • extern u32 OSInterruptSum;              /*进入中断次数*/  
  • extern u32 OSTime;                      /*系统时间(进入时钟中断次数)*/  
  • extern u32 OSRdyTbl;                    /*任务就绪表,0表示挂起,1表示就绪*/  
  • extern u32 OSIntNesting;                /*任务嵌套数*/  
  •   
  •   
  • void OSTimeDly(u32 ticks);      /*设置任务延时时间*/  
  • void TicksInterrupt(void);      /*定时器中断对任务延时处理函数*/  
  • void IdleTask(voidvoid *pdata);     /*系统空闲任务*/  
  • void OSSched(void);             /*任务切换*/  
  • void OSStart(void);             /*多任务系统开始*/  
  • void OSIntExit(void);           /*中断退出函数*/  
  •   
  • void OSTaskCreate(void  (*Task)(void  *parg), voidvoid *parg, u32 *p_Stack, u8 TaskID); /*创建任务函数*/  
  • void OSTaskSuspend(u8 prio);    /*挂起指定任务*/  
  • void OSTaskResume(u8 prio);     /*回复指定的挂起任务*/  
  •   
  • void OSTaskSwHook(void);        /*空函数*/  
  • /*in asm function*/  
  • void OS_EXIT_CRITICAL(void);    /*退出临界区*/  
  • void OS_ENTER_CRITICAL(void);   /*进入临界区*/  
  • void OSStartHighRdy(void);      /*调度第一个任务*/  
  • void OSCtxSw(void);             /*函数级任务切换*/  
  • void OSIntCtxSw(void);          /*中断级任务切换*/  
  •   
  • #endif  




使用特权

评论回复
地板
说书先生|  楼主 | 2016-12-23 12:41 | 只看该作者
文件RTOS_ASM.s
[objc] view plain copy


  • ;/*********************** (C) COPYRIGHT 2013 Libraworks *************************
  • ;* File Name    : RTOS_ASM.s
  • ;* Author       : 卢晓铭  
  • ;* Version      : V1.0
  • ;* Date         : 01/26/2013
  • ;* Description  : LXM-RTOS asm port
  • ;*******************************************************************************/  
  •     IMPORT OSInterruptSum  
  •     IMPORT OSRunning  
  •     IMPORT p_OSTCBCur  
  •     IMPORT p_OSTCBHighRdy  
  •     IMPORT OSTaskSwHook  
  •     IMPORT OSPrioCur  
  •     IMPORT OSPrioHighRdy  
  •   
  •     EXPORT OS_ENTER_CRITICAL  
  •     EXPORT OS_EXIT_CRITICAL  
  •     EXPORT OSStartHighRdy  
  •     EXPORT OSCtxSw  
  •     EXPORT OSIntCtxSw  
  •     EXPORT PendSV_Handler  
  •   
  • NVIC_INT_CTRL       EQU     0xE000ED04  ; 中断控制寄存器  
  • NVIC_SYSPRI2        EQU     0xE000ED20  ; 系统优先级寄存器(2)  
  • NVIC_PENDSV_PRI     EQU     0xFFFF0000  ; 软件中断和系统节拍中断  
  •                                         ; (都为最低,0xff).  
  • NVIC_PENDSVSET      EQU     0x10000000  ; 触发软件中断的值.  
  •   
  •         PRESERVE8   
  •         SECTION .text:CODE:NOROOT(2)  
  •         THUMB   
  • ;/***************************************************************************************
  • ;* 函数名称: OS_ENTER_CRITICAL
  • ;*
  • ;* 功能描述: 进入临界区  
  • ;*            
  • ;* 参    数: None
  • ;*
  • ;* 返 回 值: None
  • ;*****************************************************************************************/   
  •   
  • OS_ENTER_CRITICAL  
  •    
  •         CPSID   I                       ; Disable all the interrupts  
  •                                                                           
  •         PUSH    {R1,R2}        
  •   
  •         LDR     R1, =OSInterruptSum     ; OSInterrputSum++  
  •         LDRB    R2, [R1]  
  •         ADD     R2, R2, #1  
  •         STRB    R2, [R1]  
  •         POP     {R1,R2}  
  •         BX LR  
  •   
  • ;/***************************************************************************************
  • ;* 函数名称: OS_EXIT_CRITICAL
  • ;*
  • ;* 功能描述: 退出临界区  
  • ;*            
  • ;* 参    数: None
  • ;*
  • ;* 返 回 值: None
  • ;*****************************************************************************************/  
  •   
  • OS_EXIT_CRITICAL  
  •         PUSH    {R1, R2}  
  •         LDR     R1, =OSInterruptSum     ; OSInterrputSum--  
  •         LDRB    R2, [R1]  
  •         SUB     R2, R2, #1  
  •         STRB    R2, [R1]  
  •         MOV     R1,  #0         
  •         CMP     R2,  #0                 ; if OSInterrputSum=0,enable   
  •                                         ; interrupts如果OSInterrputSum=0,  
  •         ;MSREQ  PRIMASK, R1     
  •         CPSIE   I  
  •         POP     {R1, R2}  
  •         BX LR  
  • ;/**************************************************************************************
  • ;* 函数名称: OSStartHighRdy
  • ;*
  • ;* 功能描述: 使用调度器运行第一个任务
  • ;*  
  • ;* 参    数: None
  • ;*
  • ;* 返 回 值: None
  • ;**************************************************************************************/   
  •   
  • OSStartHighRdy  
  •         LDR     R4, =NVIC_SYSPRI2      ; set the PendSV exception priority  
  •         LDR     R5, =NVIC_PENDSV_PRI  
  •         STR     R5, [R4]  
  •   
  •         MOV     R4, #0                 ; set the PSP to 0 for initial context switch call  
  •         MSR     PSP, R4  
  •   
  •         LDR     R4, =OSRunning         ; OSRunning = TRUE  
  •         MOV     R5, #1  
  •         STRB    R5, [R4]  
  •   
  •                                        ;切换到最高优先级的任务  
  •         LDR     R4, =NVIC_INT_CTRL     ;rigger the PendSV exception (causes context switch)  
  •         LDR     R5, =NVIC_PENDSVSET  
  •         STR     R5, [R4]  
  •   
  •         CPSIE   I                      ;enable interrupts at processor level  
  • OSStartHang  
  •         B       OSStartHang            ;should never get here  
  •   
  • ;/**************************************************************************************
  • ;* 函数名称: OSCtxSw
  • ;*
  • ;* 功能描述: 函数级任务切换         
  • ;*
  • ;* 参    数: None
  • ;*
  • ;* 返 回 值: None
  • ;***************************************************************************************/  
  •    
  • OSCtxSw  
  •         PUSH    {R4, R5}  
  •         LDR     R4, =NVIC_INT_CTRL      ;触发PendSV异常 (causes context switch)  
  •         LDR     R5, =NVIC_PENDSVSET  
  •         STR     R5, [R4]  
  •         POP     {R4, R5}  
  •         BX      LR  
  • ;/**************************************************************************************
  • ;* 函数名称: OSIntCtxSw
  • ;*
  • ;* 功能描述: 中断级任务切换
  • ;*
  • ;* 参    数: None
  • ;*
  • ;* 返 回 值: None
  • ;***************************************************************************************/  
  •   
  • OSIntCtxSw  
  •         PUSH    {R4, R5}  
  •         LDR     R4, =NVIC_INT_CTRL      ;触发PendSV异常 (causes context switch)  
  •         LDR     R5, =NVIC_PENDSVSET  
  •         STR     R5, [R4]  
  •         POP     {R4, R5}  
  •         BX      LR  
  •         NOP  
  •   
  • ;/**************************************************************************************
  • ;* 函数名称: OSPendSV
  • ;*
  • ;* 功能描述: OSPendSV is used to cause a context switch.
  • ;*
  • ;* 参    数: None
  • ;*
  • ;* 返 回 值: None
  • ;***************************************************************************************/  
  •   
  • PendSV_Handler  
  •     CPSID   I                                                   ; Prevent interruption during context switch  
  •     MRS     R0, PSP                                             ; PSP is process stack pointer 如果在用PSP堆栈,则可以忽略保存寄存器,参考CM3权威中的双堆栈-白菜注  
  •     CBZ     R0, PendSV_Handler_Nosave                           ; Skip register save the first time  
  •   
  •     SUBS    R0, R0, #0x20                                       ; Save remaining regs r4-11 on process stack  
  •     STM     R0, {R4-R11}  
  •   
  •     LDR     R1, =p_OSTCBCur                                     ; OSTCBCur->OSTCBStkPtr = SP;  
  •     LDR     R1, [R1]  
  •     STR     R0, [R1]                                            ; R0 is SP of process being switched out  
  •   
  •                                                                 ; At this point, entire context of process has been saved  
  • PendSV_Handler_Nosave  
  •     PUSH    {R14}                                               ; Save LR exc_return value  
  •     LDR     R0, =OSTaskSwHook                                   ; OSTaskSwHook();  
  •     BLX     R0  
  •     POP     {R14}  
  •   
  •     LDR     R0, =OSPrioCur                                      ; OSPrioCur = OSPrioHighRdy;  
  •     LDR     R1, =OSPrioHighRdy  
  •     LDRB    R2, [R1]  
  •     STRB    R2, [R0]  
  •   
  •     LDR     R0, =p_OSTCBCur                                     ; OSTCBCur  = OSTCBHighRdy;  
  •     LDR     R1, =p_OSTCBHighRdy  
  •     LDR     R2, [R1]  
  •     STR     R2, [R0]  
  •   
  •     LDR     R0, [R2]                                            ; R0 is new process SP; SP = OSTCBHighRdy->OSTCBStkPtr;  
  •     LDM     R0, {R4-R11}                                        ; Restore r4-11 from new process stack  
  •     ADDS    R0, R0, #0x20  
  •     MSR     PSP, R0                                             ; Load PSP with new process SP  
  •     ORR     LR, LR, #0x04                                       ; Ensure exception return uses process stack  
  •     CPSIE   I  
  •     BX      LR                                                  ; Exception return will restore remaining context  
  •   
  •   
  • ;************************************************************  
  •   
  • END  


使用特权

评论回复
5
zhuotuzi| | 2016-12-23 21:34 | 只看该作者
认真看完了,讲的清楚明白透彻,比那谁收费忽悠人强多了

使用特权

评论回复
6
戈卫东| | 2016-12-23 21:40 | 只看该作者
就是太简陋了点。信号互斥体信箱啥都没有。

使用特权

评论回复
7
ticomi| | 2016-12-24 09:16 | 只看该作者
写的很好,很类似UCOS,赞一个!!

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

71

主题

191

帖子

0

粉丝