SVC异常是? 
PendSV异常是? 
ucos 任务切换时机? 
ucos 如何满足实时性(实现)? 
ucos中,systick的优先级?

SVC和PendSV
SVC(系统服务调用,亦简称系统调用)和PendSV(可悬起系统调用),它们多用于在操作系统之上的软件开发中。

SVC:
SVC 用于产生系统函数的调用请求。 
例如,操作系统不让用户程序直接访问硬件,而是通过提供一些系统服务函数,用户程序使用SVC 发出对系统服务函数的呼叫请求,以这种方法调用它们来间接访问硬件。 
因此, 
当用户程序想要控制特定的硬件时,它就会产生一个SVC 异常, 
然后操作系统提供的SVC 异常服务例程得到执行, 
它再调用相关的操作系统函数, 
后者完成用户程序请求的服务。 
这种“提出要求——得到满足”的方式,很好、很强大、很方便、很灵活、很能可持续发展。 
首先,它使用户程序从控制硬件的繁文缛节中解脱出来,而是由操作系统 负责控制具体的硬件。 
第二,操作系统的代码可以经过充分的测试,从而能使系统更加健壮和可靠。 
第三,它使用户程序无需在特权级下执行,用户程序无需承担因误操作而瘫痪整个系统的风险。 
第四,通过SVC 的机制,还让用户程序变得与硬件无关,因此在开发应用程序时无需了解硬件的操作细节,从而简化了开发的难度和繁琐度,并且使应用程序跨硬件平台移植成为可能。开发应用程序唯一需要知道的就是操作系统提供的应用编程接口(API),并且了解各个请求代号和参数表,然后就可以使用SVC 来提出要求了(事实上,为使用方便,操作系统往往会提供一层封皮,以使系统调用的形式看起来和普通的函数调用一致。各封皮函数会正确使用SVC指令来执行系统调用——译者注)。 
其实,严格地讲,操作硬件的工作是由设备驱动程序完成的,只是对应用程序来说,它们也是操作系统的一部分。如图7.14 所示 
 
SVC 异常通过执行”SVC”指令来产生。该指令需要一个立即数,充当系统调用代号。SVC异常服务例程稍后会提取出此代号,从而解释本次调用的具体要求,再调用相应的服务函数。例如,

1.SVC 0x3 ; 调用3 号系统服务

在SVC 服务例程执行后,上次执行的SVC 指令地址可以根据自动入栈的返回地址计算出。找到了SVC 指令后,就可以读取该SVC 指令的机器码,从机器码中萃取出立即数,就获知了请求执行的功能代号。如果用户程序使用的是PSP,服务例程还需要先执行

1.MRS Rn,PSP

指令来获取应用程序的堆栈指针。通过分析LR 的值,可以获知在SVC 指令执行时,正在使用哪个堆栈。 
由CM3 的中断优先级模型可知,你不能在SVC 服务例程中嵌套使用SVC 指令(事实上这样做也没意义),因为同优先级的异常不能抢占自身。这种作法会产生一个用法fault。同理,在NMI 服务例程中也不得使用SVC,否则将触发硬fault。

PendSV:
另一个相关的异常是PendSV(可悬起的系统调用),它和SVC 协同使用。 
一方面,SVC异常是必须立即得到响应的(若因优先级不比当前正处理的高,或是其它原因使之无法立即响应,将上访成硬fault——译者注),应用程序执行SVC 时都是希望所需的请求立即得到响应。 
另一方面,PendSV 则不同,它是可以像普通的中断一样被抢占挂起的(不像SVC 那样会上访)。 
操作系统 可以利用它“缓期执行”一个异常——直到其它重要的任务完成后才执行动作。

PendSV是什么? 
根据 权威指南。PendSV是为系统设备而设的“可悬挂请求”(pendable request)。

上下文切换 不能在中断中进行,会导致中断延期。为了解决这个问题,使用 PendSV。PendSV可以挂起,也就是等到别的 ISR结束后缓期执行。
为了实现缓期执行PendSV,PendSV一定要被设置为最低优先级的异常。
挂起PendSV 的方法是:软件实现OSIntCtxSw()函数,向NVIC 的PendSV 悬起寄存器中写1。

NVIC_INT_CTRL   EQU     0xE000ED04   ; Interrupt control state register.
NVIC_PENDSVSET  EQU     0x10000000   ; Value to trigger PendSV exception.
OSIntCtxSw
    LDR     R0, =NVIC_INT_CTRL       ; Trigger the PendSV exception (causes context switch)
    LDR     R1, =NVIC_PENDSVSET
    STR     R1, [R0]
    BX      LR

挂起后,如果优先级不够高,则将缓期等待执行。 
PendSV 的典型使用场合是在上下文切换时(在不同任务之间切换)。

操作系统,上下文切换 实例:
场景假设:一个系统(按时间片轮转调度的系统)中有两个就绪的任务(A任务、B任务), 
上下文切换被触发的场合可以是:

执行一个系统调用
系统滴答定时器(SYSTICK)中断,(轮转调度中需要)
A、B两个就绪任务,通过SysTick 异常启动上下文切换。如图7.15 所示。 
 
上图是两个任务轮转调度的示意图。 
但若在产生SysTick 异常时正在响应一个中断,则SysTick 异常会抢占其ISR。 
在这种情况下,操作系统 不可以执行上下文切换,否则将使中断请求被延迟, 
而且在真实系统中延迟时间还往往不可预知——任何有一丁点实时要求的系统都决不能容忍这种事。 
因此,在CM3 中也是严禁没商量——如果操作系统 在某中断活跃时尝试切入线程模式,将触犯用法fault 异常。 
 
为解决此问题,早期的操作系统 大多会在SysTick 异常中 检测当前是否有中断在活跃中,只有没有任何中断需要响应时,才执行上下文切换(切换期间无法响应中断)。 
然而,这种方法的弊端在于, 
它可能把任务切换动作拖延很久(因为如果抢占了IRQ,则本次SysTick 在执行后不得作上下文切换,只能等待下一次SysTick 异常),尤其是当某中断源的频率和SysTick 异常的频率比较接近时,会发生“共振”。 
现在好了,PendSV 来完美解决这个问题了(产生SysTick 异常时正在响应一个中断,SysTick 异常会抢占其ISR。此时,操作系统 不可以执行上下文切换,否则将使中断请求被延迟): 
把PendSV 编程为最低优先级的异常,PendSV 异常会自动延迟上下文切换的请求,直到其它的ISR 都完成了处理后才放行。 
如果操作系统 检测到某IRQ 正在活动并且被SysTick 抢占,它将悬起一个PendSV 异常,以便缓期执行上下文切换。如图7.17 所示 

流水账记录如下: 
1. 任务 A 呼叫SVC 来请求任务切换(例如,等待某些工作完成) 
2. OS 接收到请求,做好上下文切换的准备,并且pend 一个PendSV 异常。 
3. 当 CPU 退出SVC 后,它立即进入PendSV,从而执行上下文切换。 
4. 当 PendSV 执行完毕后,将返回到任务B,同时进入线程模式。 
5. 发生了一个中断,并且中断服务程序开始执行 
6. 在 ISR 执行过程中,发生SysTick 异常,并且抢占了该ISR。 
7. OS 执行必要的操作,然后pend 起PendSV 异常以作好上下文切换的准备。 
8. 当 SysTick 退出后,回到先前被抢占的ISR 中,ISR 继续执行 
9. ISR 执行完毕并退出后,PendSV 服务例程开始执行,并且在里面执行上下文切换 
10. 当 PendSV 执行完毕后,回到任务A,同时系统再次进入线程模式。

其实,ucos中的实现,于此有些差异,但从结果上看,是一致的(如果systick抢占了其他ISRs,不会在其中执行上下文切换。会等到全部的ISRs执行完毕后(期间一定是无任务调度的),才执行pendsv异常,完成上下文的切换。==差别在于生成pendsv异常的时机。)

ucos 关于 PendSV 异常的应用(上下文切换时机、怎样满足实时性):
在systick异常中,执行必要的任务维护更新工作,在退出时,考虑生成pensv异常。 
当且仅当无中断被抢占时,生成pensv异常,并于pendsv异常中,完成上下文切换工作; 
当每一个中断/异常处理函数中,均在退出时考虑生成pensv异常,则最终无中断可执行时,pensv异常一定会生成,并且期间无任务调度。

这可能与上边描述的不一致,但结果上来看,是一致的。 
下边以ucos系统的源码,进行大概的讲解:

中断/异常处理通用模板:
    OS_CPU_SR  cpu_sr; 
    OS_ENTER_CRITICAL(); /* Tell uC/OS-II that we are starting an ISR          */
    OSIntNesting++;
    OS_EXIT_CRITICAL();
    用户处理代码;
    void  OSIntExit (void);//OSIntNesting--;以及可能的调度

systick异常实现(ucos心脏):
void  OS_CPU_SysTickHandler (void)
{
    OS_CPU_SR  cpu_sr;
    OS_ENTER_CRITICAL(); /* Tell uC/OS-II that we are starting an ISR */
    OSIntNesting++;
    OS_EXIT_CRITICAL();
    OSTimeTick();  /* Call uC/OS-II's OSTimeTick()       */

OSIntExit();  /* Tell uC/OS-II that we are leaving the ISR */
}

void OSTimeTick (void)
void  OSTimeTick (void)
{
更新系统时间,OSTime++;
遍历OSTCBList 任务控制块链表(已经建立的任务),
    如果任务控制块OSTCBDly非零,则减一;
    如果等于零,更新OSTCBStat(任务状态)、OSTCBStatPend(任务挂起状态)成员;
    如果OSTCBStat等于OS_STAT_RDY(就绪状态),则将任务放入就绪表中。
}

OSIntExit
/*$PAGE*/
/*
*********************************************************************************************************
*                                               EXIT ISR
*
* Description: This function is used to notify uC/OS-II that you have completed serviving an ISR.  When
*              the last nested ISR has completed, uC/OS-II will call the scheduler to determine whether
*              a new, high-priority task, is ready to run.
*
* Arguments  : none
*
* Returns    : none
*
* Notes      : 1) You MUST invoke OSIntEnter() and OSIntExit() in pair.  In other words, for every call
*                 to OSIntEnter() at the beginning of the ISR you MUST have a call to OSIntExit() at the
*                 end of the ISR.
*              2) Rescheduling is prevented when the scheduler is locked (see OS_SchedLock())
*********************************************************************************************************
*/

void  OSIntExit (void)
{
#if OS_CRITICAL_METHOD == 3                                /* Allocate storage for CPU status register */
    OS_CPU_SR  cpu_sr = 0;
#endif

if (OSRunning == OS_TRUE) {
        OS_ENTER_CRITICAL();
        if (OSIntNesting > 0) {                            /* Prevent OSIntNesting from wrapping       */
            OSIntNesting--;
        }
        if (OSIntNesting == 0) {                           /* Reschedule only if all ISRs complete ... */
            if (OSLockNesting == 0) {                      /* ... and not locked.                      */
                OS_SchedNew();
                OSTCBHighRdy  = OSTCBPrioTbl[OSPrioHighRdy];
                if (OSPrioHighRdy != OSPrioCur) {          /* No Ctx Sw if current task is highest rdy */

#if OS_TASK_PROFILE_EN > 0
                    OSTCBHighRdy->OSTCBCtxSwCtr++;         /* Inc. # of context switches to this task  */
#endif
                    OSCtxSwCtr++;                          /* Keep track of the number of ctx switches */
                    OSIntCtxSw();                          /* Perform interrupt level ctx switch       */
                }
            }
        }
        OS_EXIT_CRITICAL();
    }
}

我们在进入systick异常时,有执行OSIntNesting++;准备出来时,自然需要OSIntNesting–; 
如果OSIntNesting不等于零,退出systick异常。 
只有OSIntNesting等于零(无其他异常/中断发生)并且OSLockNesting等于零(无任务调度锁),才执行OS_SchedNew()查就任务绪表中最高优先级并返回,比较返回的优先级是否为当前运行任务的优先级, 
仅不相等时,执行OSIntCtxSw()函数,生成pendsv异常。OSIntCtxSw()函数的实现见上边篇幅。 
pendsv异常OS_CPU_PendSVHandler,实现上下文的切换。这里不做解释。

ucos中,systick的优先级?
PENDSV和SYSTICK属于系统异常; 
定时器中断,串口中断这些属于外部中断。 
PENDSV和SYSTICK的中断优先级可以编程, 
一般要把PENDSV的优先级设置成最低(没什么好说的)。 
但SYSTICK异常的优先级:

一般无需设置(高于外部中断的优先级),毕竟这是系统的时钟源(ucos心脏);
当然,也可根据项目需要(有些外部中断,项目上要求务必实时),将SYSTICK优先级设置与合适的位置。
确实存在的普遍现象是,很多项目对于实时没有很高的要求,干脆将PENDSV和SYSTICK的优先级都设置成OxFF。
都是最低优先级,此时因为PENDSV在中断向量表中排在SYSTICK前面,所以如果PENDSV,SYSTICK同时产生中断,PENDSV优先中断。

cortex-M3 的SVC、PendSV异常,与操作系统(ucos实时系统)相关推荐

  1. Cortex-M3 的SVC、PendSV异常,与操作系统(ucos实时系统)(转)

    Cortex-M3 的SVC.PendSV异常,与操作系统(ucos实时系统) 转载于:https://www.cnblogs.com/LittleTiger/p/10070824.html

  2. Cortex‐M3的Faults异常究竟是什么?

    关注+星标公众号,不错过精彩内容 作者 | strongerHuang 微信公众号 | strongerHuang 有许多朋友在学习,或者开发STM32时都遇到过HardFault_Handler的情 ...

  3. Cortex M3 NVIC与中断控制

    Cortex M3 NVIC与中断控制 宗旨:技术的学习是有限的,分享的精神是无限的. 一.NVIC概览 --嵌套中断向量表控制器 NVIC 的寄存器以存储器映射的方式来访问,除了包含控制寄存器和中断 ...

  4. cortex m3的操作模式和状态

    1.操作状态(operation state): debug state:处理器在调试器发起halt或匹配到断点时,会进入debug state并停止执行指令. thumb state:处理器正在运行 ...

  5. Cortex、ARMv8、arm架构、ARM指令集、soc?Cortex A8、A9都是ARMv7a 架构;Cortex M3、M4是ARMv7m架构;前者是处理器(内核)后者是指令集的架构(架构)

    架构组成元素的指令集状态或者语法thumb指令集与arm指令集的区别例如thumb指令集是什么_thumb指令集与arm指令集的区别以及thumb-2的关系在下一文中介绍,本文暂时不讨论 有粉丝问我到 ...

  6. PendSV异常介绍、用于上下文切换

    PendSV异常介绍.用于上下文切换 参考文章: (1)PendSV异常介绍.用于上下文切换 (2)https://www.cnblogs.com/sanshijvshi/p/11730210.htm ...

  7. Cortex M3内核架构

    CortexM3内核架构 宗旨:技术的学习是有限的,分享的精神是无限的. 1.ARMCortex-M3处理器 Cortex-M3处理器内核是单片机的中央处理单元( CPU). 完整的基于CM3的MCU ...

  8. Cortex M3 Bit-banding简介

    http://blog.csdn.net/shevsten/article/details/7676397 Cortex M3 Bit-banding简介 分类: ARM MCU2012-06-19 ...

  9. cortex m3 开源_开源增强现实耳机,Steam的125M有效帐户等

    cortex m3 开源 您好,开放游戏迷! 在本周的版本中,我们将了解Steam的1.25亿活跃帐户和Game Developers Conference,这是一个开源增强现实头戴设备,Linux游 ...

最新文章

  1. 5分钟学会打游戏的活体人脑细胞,比 AI 学习速度更快
  2. Android Studio实用插件使用
  3. 我的学习笔记_Windows_HOOK编程 2009-12-03 11:19
  4. web前端入门学习 css(1)
  5. boost::hana::make_range用法的测试程序
  6. OpenGL Multi Texture多重纹理的实例
  7. 6、HIVE JDBC开发、UDF、体系结构、Thrift服务器、Driver、元数据库Metastore、数据库连接模式、单/多用户模式、远程服务模式、Hive技术原理解析、优化等(整理的笔记)
  8. 安装apache2.4.10
  9. android 缩进轮播图,如何利用纯css实现图片轮播
  10. linux 去掉 ^M 的方法
  11. CSS中属性个属性值怎么区分,[CSS] 详细解释 @media 属性与 (max
  12. 程序员上班都在做什么?
  13. jQuery .tmpl(), .template()学习
  14. Java将日期拆分成按周或月时间段统计
  15. 【Linux】linux下解压.xz文件
  16. Atitit 编程语言语言规范总结 语法部分 目录 1. 语言规范 3 2. Types 3 2.1.1. Primitive types 3 2.1.2. Compound types 4 3.
  17. xcrun: error: invalid active developer path (/Library/Developer/CommandLineTools), missing xcrun at:
  18. 联盟链Quorum(基于raft共识)部署流程(三)- 部署基于Quorum链的区块链浏览器
  19. 联想Y430P 下为 Ubuntu 安装无线网络
  20. 在家赚钱,收藏好这三个兼职

热门文章

  1. GIS叠加分析功能学习
  2. DirectX Shader 入门学习
  3. Hyper-V安装ReactOS未成功
  4. vue-jwt 实战
  5. Python全栈开发 day3
  6. anaconda应答文件
  7. 啦啦啦 啦啦 啦 啦 啦 啦啦 啦 啦 啦
  8. 键盘-App监听软键盘按键的三种方式
  9. 8-12-COMPETITION
  10. python列表get方法_python的get set方法示例