微信公众号 | strongerHuang
当C++遇上轻量级,你可能觉得“不可思议”。
今天就来分享一个GitHub上开源的用C++编写的轻量级的RTOS:scmRTOS。
关于scmRTOS
scmRTOS是一个用C++编写的,适用于MCU的轻量级实时操作系统。
最低只需要512字节RAM(内存)、1K的代码量、具有上下文切换极低的延时。
开源地址:https://github.com/scmrtos/scmrtos
支持的MCU平台或类型:
MSP430
Blackfin
ARM7
Cortex-M0
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;#endifTBaseProcess * 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 == 1context_switch_user_hook();#endifstack_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 == 0TBaseProcess::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_STACKTBaseProcess::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 == 1TIdleProc IdleProc("Idle");#elseTIdleProc IdleProc;#endif}namespace OS{template<> void TIdleProc::exec(){for(;;){#if scmRTOS_IDLE_HOOK_ENABLE == 1idle_process_user_hook();#endif#if scmRTOS_TARGET_IDLE_HOOK_ENABLE == 1idle_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 mapWaitingProcessMap = 0;}Timeout = 0;#if scmRTOS_DEBUG_ENABLE == 1WaitingFor = 0;#endif}#endif // scmRTOS_PROCESS_RESTART_ENABLE//------------------------------------------------------------------------------
内核主要是处理调度相关的内容,有认真学习过RTOS内核机制的同学应该都能看得懂。
官方针对不同的MCU平台,都提供了对应的端口(Port),只需要适当修改,即可移植到你工程。
内核还支持用户扩展,提供了调试分析、互斥、“消息队列”等功能。
最后,你觉得这款用C++编写的RTOS怎么样?
2210