[转]关于嵌入式实时操作系统的实时性 - yanhc - 博客园
嵌入式实时操作系统RTOS里实时的衡量指标到底是什么呢?1s肯定达不到实时,那需要多快呢?100ms,10ms,1ms,还是100us,10us?
还有这些指标是如何测量的呢?
一个关于1553B总线消息周期实时性指标的例子
一篇论文中关于1553B总线消息周期实时性的指标,从这个例子中可以看出,对于windows这种非实时操作系统而言,10ms的精度也很难保证。因此,实时性指标要求任务需要至少满足10ms的指标,甚至更高。
韩春慧,王煜,黄书华,许权,张珅,鲁月林. 基于BM3803的1553B总线通信软件设计 [J]. 中国空间科学技术, 2019,39(234), 05 65-72.
论文中需要完成的1553总线测试终端的消息的周期数值偏差较为严格,
对于任务1广播时间码,周期为1s,周期偏差不能超过100us,
对于任务7系统同步,周期为2s,周期偏差不能超过10 000us=10ms,如下图所示。
如果使用传统的windows+1553B-PCI板卡方案的话,不能保证以上的精度;所以,论文使用了嵌入式实时操作系统的方案,BM3803+uCOS+61580,该系统可以满足上图的精度。
下表为实际测试结果,对于任务1,采用嵌入式实时操作系统方案,周期精确度偏差平均为8us,而采用windows方案则高达13ms,超过了100us=0.1ms的精度要求。
其它任务的周期精度要求均为10ms以内,对于嵌入式实时操作系统方案,周期精度平均1.5ms,而windows则为15ms,超过了精度要求。
论文
链接:https://pan.baidu.com/s/15P6VCZqdieAlSH9Mq8anmg
提取码:o1vq
关于实时性都有哪些指标
expresslogic有一个文档Measuring RTOS Real-Time Performance,其中描述了实时性的各种指标,最后,介绍了其RTOS实时性测量软件。
https://rtos.com/wp-content/uploads/2017/10/EL_Measuring_RTOS_Real-Time_Performance.pdf
主要分为两部分,
一是中断处理实时性,主要包括以下步骤:
(1)中断当前正在执行的任务,
(2)保存当前任务上下文,
(3)开始执行中断服务程序ISR,
(4)ISR中进行一些处理,以确定需要采取的动作,
(5)保存一些中断相关的关键数据,
(6)设置一些必须的输出,
(7)确定该执行哪个任务(一般中断到来之后,需要的处理会比较多,一般中断中会处理必须的事情,剩下的处理由某个任务来处理)
(8)清除中断状态寄存器,
(9)将控制转移到要执行的任务。
二是系统服务实时性,包括
(1)在某个事件发生时调度一个任务执行,
(2)任务之间传递消息(消息队列),
(3)申明公共资源三方面(信号量等)。
TNKernel-RX/Thread-Metric/,某个操作系统使用了Thread Metric
源代码:https://github.com/msalau/TNKernel-RX/tree/master/Thread-Metric
pdf链接:https://pan.baidu.com/s/1pJH2azMJb8QNmYZwXUQpFA
提取码:t421
用户程序需要做到什么
以上都是对于RTOS来说的,那么对于用户程序需要做到什么呢?
RTOS内核里一般都会有一些关键区域critical section,在这些区域是需要关中断的,中断都屏蔽了,那么响应外界中断自然会带来延时,影响系统的实时性。
因此,对于用户程序也可以这么说,用户程序关中断的时间不超过内核关中断的时间,就能保证用户程序不会使内核实时性变差。
这里有一个文档Interrupts-II-Bringing Organization to our Code (the shared-data problem) Reference An Embedded Software Primer By David E. Simon,其中有描述内核关键区关中断的时间会影响系统的实时性。
链接:https://pan.baidu.com/s/1M3f1rdl2DHsMMpLJ1Ptb0Q
提取码:dbno
对于FreeRTOS而言,如何选择保护关键区的方式
(1)taskENTER_CRITICAL,会关中断,同时支持嵌套nesting,操作方便
(2)vTaskSuspendAll,不关中断,会关调度器,操作复杂
(3)mutex,不关中断,不关调度器
对于FreeRTOS内核来说,因为(3)Mutex是可选配置项,因此,内核是不能够使用mutex的。
所以,对于FreeRTOS内核来说,只有选择(1)和(2)。
而对于(1)和(2),按照richard-damon的回复,用(1)需要保证关键区执行时间在几微秒以内(strictly bounded execution time,in small number of microseconds at most)。
而如果无法保证执行时间短且有界的,则需要使用(2)(FreeRTOS uses suspending the scheduler if the time period isn’t both strictly bounded and short.)。且在使用(2)时需要保证被保护的关键区不会阻塞(inside the section you can’t do anything that might block)。
关于这句话的进一步核实:when you suspend the schedule it sets a flag to tell the ISRs not to modify the main task lists
下面vTaskSuspendAll的时候,会对uxSchedulerSuspended+1。(这里的注释比较有意思,就是因为变量的类型是基础类型,因此不用设置关键区,为什么呢?因为是基础类型,所以不用两次move?但是++也会ldr,inc,str需要3条指令,也可能被打断呢?)
1 void vTaskSuspendAll( void )2 {3 /* A critical section is not required as the variable is of type4 portBASE_TYPE. */5 ++uxSchedulerSuspended;6 }
uxSchedulerSuspended != 0的话,那么,上下文切换vTaskSwitchContext就不会执行。
1 void vTaskSwitchContext( void )2 {3 if( uxSchedulerSuspended != ( unsigned portBASE_TYPE ) pdFALSE )4 {5 /* The scheduler is currently suspended - do not allow a context6 switch. */7 xMissedYield = pdTRUE;8 }9 else
同时,注意到在xTaskResumeFromISR用到了这个调度器挂起变量,如果调度器挂起,那么,不能操作就绪任务列表(为什么呢?),因此,将任务放在即将就绪列表上。
1 portBASE_TYPE xTaskResumeFromISR( xTaskHandle pxTaskToResume ) 2 { 3 portBASE_TYPE xYieldRequired = pdFALSE; 4 tskTCB *pxTCB; 5 unsigned portBASE_TYPE uxSavedInterruptStatus; 6 7 configASSERT( pxTaskToResume ); 8 9 pxTCB = ( tskTCB * ) pxTaskToResume;10 11 uxSavedInterruptStatus = portSET_INTERRUPT_MASK_FROM_ISR();12 {13 if( xTaskIsTaskSuspended( pxTCB ) == pdTRUE )14 {15 traceTASK_RESUME_FROM_ISR( pxTCB );16 17 if( uxSchedulerSuspended == ( unsigned portBASE_TYPE ) pdFALSE )18 {19 xYieldRequired = ( pxTCB->uxPriority >= pxCurrentTCB->uxPriority );20 uxListRemove( &( pxTCB->xGenericListItem ) );21 prvAddTaskToReadyQueue( pxTCB );22 }23 else24 {25 /* We cannot access the delayed or ready lists, so will hold this26 task pending until the scheduler is resumed, at which point a27 yield will be performed if necessary. */28 vListInsertEnd( ( xList * ) &( xPendingReadyList ), &( pxTCB->xEventListItem ) );29 }30 }31 }32 portCLEAR_INTERRUPT_MASK_FROM_ISR( uxSavedInterruptStatus );33 34 return xYieldRequired;35 }
同时,在vTaskIncrementTick时,也会判断调度器是否挂起,若挂起,则记录丢失的tick数,在调取器继续时,补偿丢失的tick数。
1 void vTaskIncrementTick( void ) 2 { 3 tskTCB * pxTCB; 4 5 /* Called by the portable layer each time a tick interrupt occurs. 6 Increments the tick then checks to see if the new tick value will cause any 7 tasks to be unblocked. */ 8 traceTASK_INCREMENT_TICK( xTickCount ); 9 if( uxSchedulerSuspended == ( unsigned portBASE_TYPE ) pdFALSE )10 {11 ++xTickCount;12 13 }14 else15 {16 ++uxMissedTicks;17 18 /* The tick hook gets called at regular intervals, even if the19 scheduler is locked. */20 #if ( configUSE_TICK_HOOK == 1 )21 {22 vApplicationTickHook();23 }24 #endif25 }26 }
在xTaskResumeAll时,补偿丢失的tick数。
1 signed portBASE_TYPE xTaskResumeAll( void ) 2 { 3 4 /* It is possible that an ISR caused a task(只有ISR会引起) to be removed from an event 5 list while the scheduler was suspended. If this was the case then the 6 removed task will have been added to the xPendingReadyList. Once the 7 scheduler has been resumed it is safe(?) to move all the pending ready 8 tasks from this list into their appropriate ready list. */ 9 taskENTER_CRITICAL();10 {11 --uxSchedulerSuspended;12 13 if( uxSchedulerSuspended == ( unsigned portBASE_TYPE ) pdFALSE )14 {15 if( uxCurrentNumberOfTasks > ( unsigned portBASE_TYPE ) 0U )16 {17 portBASE_TYPE xYieldRequired = pdFALSE;18 19 /* If any ticks occurred while the scheduler was suspended then20 they should be processed now. This ensures the tick count does not21 slip, and that any delayed tasks are resumed at the correct time. */22 if( uxMissedTicks > ( unsigned portBASE_TYPE ) 0U )23 {24 while( uxMissedTicks > ( unsigned portBASE_TYPE ) 0U )25 {26 vTaskIncrementTick();27 --uxMissedTicks;28 }29 }31 }32 }33 }34 taskEXIT_CRITICAL();35 36 return xAlreadyYielded;37 }
---------------------
作者:yanhc
来源:CNBLOGS
原文:https://www.cnblogs.com/yanhc/p/12594768.html
版权声明:本文为作者原创文章,转载请附上博文链接!
内容解析By:CSDN,CNBLOG博客文章一键转载插件