• 正文
  • 相关推荐
申请入驻 产业图谱

分享一个用C++编写的轻量级RTOS

03/17 10:55
2210
加入交流群
扫码加入
获取工程师必备礼包
参与热点资讯讨论

微信公众号 | strongerHuang

当C++遇上轻量级,你可能觉得“不可思议”。

今天就来分享一个GitHub上开源的用C++编写的轻量级的RTOS:scmRTOS。

关于scmRTOS

scmRTOS是一个用C++编写的,适用于MCU的轻量级实时操作系统

最低只需要512字节RAM(内存)、1K的代码量、具有上下文切换极低的延时。

开源地址:https://github.com/scmrtos/scmrtos

支持的MCU平台或类型:

MSP430

AVR

Blackfin

ARM7

Cortex-M0

Cortex-M3

Cortex-M4

STM8

上下文切换耗时情况:

900 ns在Cortex-M4上@ 168 MHz

1.8 us在Blackfin上@ 200 MHz

2.7 us在Cortex-M3上@72 MHz

5 us在ARM7上@ 50 MHz

38-42 us在AVR上@ 8 MHz

45-50 us在MSP430上@ 5 MHz

18-20 us在STM8上@ 16 MHz

内核全用C++编写:

内核os_kernel.cpp的源代码量也很小:

#include "scmRTOS.h"
using namespace OS;
OS::TKernel OS::Kernel;
#if scmRTOS_SUSPENDED_PROCESS_ENABLE != 0OS::TProcessMap OS::TBaseProcess::SuspendedProcessMap = (1ul << (PROCESS_COUNT)) - 1; #endif
TBaseProcess * TKernel::ProcessTable[scmRTOS_PROCESS_COUNT + 1];
//------------------------------------------------------------------------------////    TKernel functions//#if scmRTOS_CONTEXT_SWITCH_SCHEME == 0void TKernel::sched(){    uint_fast8_t NextPrty = highest_priority(ReadyProcessMap);    if(NextPrty != CurProcPriority)    {    #if scmRTOS_CONTEXT_SWITCH_USER_HOOK_ENABLE == 1        context_switch_user_hook();    #endif
        stack_item_t*  Next_SP      = ProcessTable[NextPrty]->StackPointer;        stack_item_t** Curr_SP_addr = &(ProcessTable[CurProcPriority]->StackPointer);        CurProcPriority = NextPrty;        os_context_switcher(Curr_SP_addr, Next_SP);    }}#else//------------------------------------------------------------------------------void TKernel::sched(){    uint_fast8_t NextPrty = highest_priority(ReadyProcessMap);    if(NextPrty != CurProcPriority)    {        SchedProcPriority = NextPrty;
        raise_context_switch();        do        {            enable_context_switch();            DUMMY_INSTR();            disable_context_switch();        }         while(CurProcPriority != SchedProcPriority); // until context switch done    }}//------------------------------------------------------------------------------stack_item_t* os_context_switch_hook(stack_item_t* sp) { return Kernel.context_switch_hook(sp); }//------------------------------------------------------------------------------#endif // scmRTOS_CONTEXT_SWITCH_SCHEME
//------------------------------------------------------------------------------////       OS Process's constructor////       Performs:  //           * initializing process data;//           * registering process in the kernel;//           * initializing stack frame;//                  //#if SEPARATE_RETURN_STACK == 0
TBaseProcess::TBaseProcess( stack_item_t * StackPoolEnd                          , TPriority pr                          , void (*exec)()                      #if scmRTOS_DEBUG_ENABLE == 1                          , stack_item_t * aStackPool                          , const char   * name_str                      #endif                          ) : Timeout(0)                            , Priority(pr)                      #if scmRTOS_DEBUG_ENABLE == 1                            , WaitingFor(0)                            , StackPool(aStackPool)                            , StackSize(StackPoolEnd - aStackPool)                            , Name(name_str)                      #endif                       #if scmRTOS_PROCESS_RESTART_ENABLE == 1                            , WaitingProcessMap(0)                      #endif
{    TKernel::register_process(this);    init_stack_frame( StackPoolEnd                    , exec                #if scmRTOS_DEBUG_ENABLE == 1                         , aStackPool                #endif                      );}
#else  // SEPARATE_RETURN_STACK
TBaseProcess::TBaseProcess( stack_item_t * Stack                          , stack_item_t * RStack                          , TPriority pr                          , void (*exec)()                      #if scmRTOS_DEBUG_ENABLE == 1                          , stack_item_t * aStackPool                          , stack_item_t * aRStackPool                          , const char   * name_str                      #endif                          ) : StackPointer(Stack)                            , Timeout(0)                            , Priority(pr)                      #if scmRTOS_DEBUG_ENABLE == 1                            , WaitingFor(0)                            , StackPool(aStackPool)                            , StackSize(Stack - aStackPool)                            , Name(name_str)                            , RStackPool(aRStackPool)                            , RStackSize(RStack - aRStackPool)                      #endif                       #if scmRTOS_PROCESS_RESTART_ENABLE == 1                            , WaitingProcessMap(0)                      #endif
{    TKernel::register_process(this);    init_stack_frame( Stack                    , RStack                    , exec                #if scmRTOS_DEBUG_ENABLE == 1                         , aStackPool                    , aRStackPool                #endif                      );}#endif // SEPARATE_RETURN_STACK//------------------------------------------------------------------------------void TBaseProcess::sleep(timeout_t timeout){    TCritSect cs;
    Kernel.ProcessTable[Kernel.CurProcPriority]->Timeout = timeout;    Kernel.set_process_unready(Kernel.CurProcPriority);    Kernel.scheduler();}//------------------------------------------------------------------------------void OS::TBaseProcess::wake_up(){    TCritSect cs;
    if(this->Timeout)    {        this->Timeout = 0;        Kernel.set_process_ready(this->Priority);        Kernel.scheduler();    }}//------------------------------------------------------------------------------void OS::TBaseProcess::force_wake_up(){    TCritSect cs;
    this->Timeout = 0;    Kernel.set_process_ready(this->Priority);    Kernel.scheduler();}//------------------------------------------------------------------------------//////   Idle Process////namespace OS{#ifndef __GNUC__  // avoid GCC bug ( http://gcc.gnu.org/bugzilla/show_bug.cgi?id=15867 )    template<> void TIdleProc::exec();#endif
#if scmRTOS_DEBUG_ENABLE == 1    TIdleProc IdleProc("Idle");#else    TIdleProc IdleProc;#endif

}
namespace OS{    template<> void TIdleProc::exec()    {        for(;;)        {        #if scmRTOS_IDLE_HOOK_ENABLE == 1            idle_process_user_hook();        #endif
        #if scmRTOS_TARGET_IDLE_HOOK_ENABLE == 1            idle_process_target_hook();        #endif        }    }}//------------------------------------------------------------------------------#if scmRTOS_DEBUG_ENABLE == 1#if SEPARATE_RETURN_STACK == 0size_t TBaseProcess::stack_slack() const{     size_t slack = 0;     const stack_item_t * Stack = StackPool;     while (*Stack++ == scmRTOS_STACK_PATTERN)         slack++;     return slack;}#else  // SEPARATE_RETURN_STACKstatic size_t calc_stack_slack(const stack_item_t * Stack){     size_t slack = 0;     while (*Stack++ == scmRTOS_STACK_PATTERN)         slack++;     return slack;}size_t TBaseProcess::stack_slack() const{     return calc_stack_slack(StackPool);}size_t TBaseProcess::rstack_slack() const{     return calc_stack_slack(RStackPool);}#endif // SEPARATE_RETURN_STACK#endif // scmRTOS_DEBUG_ENABLE//------------------------------------------------------------------------------#if scmRTOS_PROCESS_RESTART_ENABLE == 1void TBaseProcess::reset_controls(){    Kernel.set_process_unready(this->Priority);    if(WaitingProcessMap)    {        clr_prio_tag( *WaitingProcessMap, get_prio_tag(Priority) );  // remove current process from service's process map        WaitingProcessMap = 0;    }    Timeout    = 0;#if scmRTOS_DEBUG_ENABLE == 1    WaitingFor = 0;#endif}#endif  // scmRTOS_PROCESS_RESTART_ENABLE//------------------------------------------------------------------------------

内核主要是处理调度相关的内容,有认真学习过RTOS内核机制的同学应该都能看得懂。

官方针对不同的MCU平台,都提供了对应的端口(Port),只需要适当修改,即可移植到你工程。

内核还支持用户扩展,提供了调试分析、互斥、“消息队列”等功能。

最后,你觉得这款用C++编写的RTOS怎么样?

相关推荐

登录即可解锁
  • 海量技术文章
  • 设计资源下载
  • 产业链客户资源
  • 写文章/发需求
立即登录

作者黄工,从事嵌入式软件开发工作8年有余,高级嵌入式软件工程师,业余维护公众号『strongerHuang』,分享嵌入式软硬件、单片机、物联网等内容。