历史上的今天
返回首页

历史上的今天

今天是:2024年12月11日(星期三)

正在发生

2019年12月11日 | Cortex-M3 的SVC、PendSV异常,与操作系统(ucos实时系统)

2019-12-11 来源:eefocus

SVC异常是? 

PendSV异常是? 

ucos 任务切换时机? 

ucos 如何满足实时性(实现)? 

ucos中,systick的优先级?


SVC和PendSV

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


SVC:

SVC 用于产生系统函数的调用请求。 

例如,操作系统不让用户程序直接访问硬件,而是通过提供一些系统服务函数,用户程序使用SVC 发出对系统服务函数的呼叫请求,以这种方法调用它们来间接访问硬件。 

因此, 

当用户程序想要控制特定的硬件时,它就会产生一个SVC 异常, 

然后操作系统提供的SVC 异常服务例程得到执行, 

它再调用相关的操作系统函数, 

后者完成用户程序请求的服务。 

这种“提出要求——得到满足”的方式,很好、很强大、很方便、很灵活、很能可持续发展。 

首先,它使用户程序从控制硬件的繁文缛节中解脱出来,而是由操作系统 负责控制具体的硬件。 

第二,操作系统的代码可以经过充分的测试,从而能使系统更加健壮和可靠。 

第三,它使用户程序无需在特权级下执行,用户程序无需承担因误操作而瘫痪整个系统的风险。 

第四,通过SVC 的机制,还让用户程序变得与硬件无关,因此在开发应用程序时无需了解硬件的操作细节,从而简化了开发的难度和繁琐度,并且使应用程序跨硬件平台移植成为可能。开发应用程序唯一需要知道的就是操作系统提供的应用编程接口(API),并且了解各个请求代号和参数表,然后就可以使用SVC 来提出要求了(事实上,为使用方便,操作系统往往会提供一层封皮,以使系统调用的形式看起来和普通的函数调用一致。各封皮函数会正确使用SVC指令来执行系统调用——译者注)。 

其实,严格地讲,操作硬件的工作是由设备驱动程序完成的,只是对应用程序来说,它们也是操作系统的一部分。如图7.14 所示 

这里写图片描述 

SVC 异常通过执行”SVC”指令来产生。该指令需要一个立即数,充当系统调用代号。SVC异常服务例程稍后会提取出此代号,从而解释本次调用的具体要求,再调用相应的服务函数。例如,


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


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


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优先中断。

推荐阅读

史海拾趣

CHONGQING PINGYANG ELECTRONICS CO.,LTD.公司的发展小趣事

在技术创新的基础上,重庆平洋电子有限公司积极拓展市场,不断提升品牌影响力。公司积极参与国内外各种电子展览和交流活动,与多家知名企业建立了战略合作关系。同时,公司还注重产品质量和售后服务,赢得了客户的信任和好评。随着品牌知名度的提升,公司的市场份额也逐年增长。

维峰电子(WCON)公司的发展小趣事

质量是企业的生命线。维峰电子始终将质量管理作为公司发展的重中之重。公司建立了完善的质量管理体系,从原材料采购、生产过程到产品检验等各个环节都进行严格把控。同时,公司还引入了先进的检测设备和技术,确保产品的质量和性能达到最高标准。这些措施的实施不仅提升了产品的竞争力,也赢得了客户的信任和好评。

DIALIGHT公司的发展小趣事

随着业务的不断发展和市场的不断扩大,DIALIGHT公司逐渐实现了全球化布局。他们在美国、英国、丹麦、德国、马来西亚、新加坡、澳大利亚、墨西哥和巴西等地设立了分支机构或办事处,为全球客户提供及时、高效的服务。此外,DIALIGHT还积极寻求与其他企业的合作与共赢,通过战略合作协议的签署,为双方带来新的业务机遇和合作空间。这些举措不仅增强了DIALIGHT的市场竞争力,也为其未来的发展奠定了坚实的基础。

请注意,由于篇幅限制,以上三个故事仅为DIALIGHT公司发展历程的简要概述。如需更详细的信息和更多故事,建议查阅相关资料或访问公司官网。

ZTE高新兴(Gosuncn)公司的发展小趣事

随着业务的不断发展和市场的不断扩大,DIALIGHT公司逐渐实现了全球化布局。他们在美国、英国、丹麦、德国、马来西亚、新加坡、澳大利亚、墨西哥和巴西等地设立了分支机构或办事处,为全球客户提供及时、高效的服务。此外,DIALIGHT还积极寻求与其他企业的合作与共赢,通过战略合作协议的签署,为双方带来新的业务机遇和合作空间。这些举措不仅增强了DIALIGHT的市场竞争力,也为其未来的发展奠定了坚实的基础。

请注意,由于篇幅限制,以上三个故事仅为DIALIGHT公司发展历程的简要概述。如需更详细的信息和更多故事,建议查阅相关资料或访问公司官网。

Advanced Ceramic X Corporation公司的发展小趣事

DIALIGHT公司的故事始于1938年的纽约布鲁克林,当时该公司专注于为飞机生产仪表板灯。随着技术的不断进步和市场的变化,公司在1971年,即LED推出仅一年后,推出了他们的第一个LED产品。这一举措标志着DIALIGHT正式从传统的飞机仪表板灯制造转向LED照明技术的研发和应用。从此,DIALIGHT彻底改变了LED的用途,将其广泛应用于世界各地的交通控制、指示灯、结构塔和工业场所,为全球提供了优质的照明解决方案。

Anaren公司的发展小趣事

DIALIGHT公司一直专注于工业LED照明领域的发展。他们深入了解工业空间照明的需求和挑战,设计了一系列专为工业应用而定制的LED照明产品。这些产品不仅易于安装和维护,而且能在恶劣的环境下持续使用。此外,DIALIGHT还提供集成系统解决方案,帮助客户降低能源成本、维护成本和碳足迹,同时提高设施的安全性和生产力。通过不断创新和优质服务,DIALIGHT在工业LED照明领域赢得了广泛的认可和信赖。

问答坊 | AI 解惑

常见电源问题征集帖。。。把问题汇聚于此贴,各个击破。。。

常见电源问题征集帖。。。汇聚于此贴,各个击破   疑问者,把您们的问题描述出来高手者,把您们的思路敲打出来灌水者,把您的精力放在学习上 问题集中,集中问题集中解决集中的问题 有问题的请到此处呐喊吧,相信您的疑问会被更快的解决   ...…

查看全部问答>

为什么系统(或者芯片)工作频率越高功耗越大

为什么系统(或者芯片)工作频率越高功耗越大 牛人接招!各抒己见吧…

查看全部问答>

EP1C6Q240C8N电路图

由于是第一次画FPGA产品,让大家看一下我这电路图有问题吗. EP1C6Q240C8核心板…

查看全部问答>

新人报道。我用28027做项目

单位要用28027做电力线载波,可我英文不好,看了2个星期了,一点头绪都没有,那位能帮一下忙。 工作3年了,有单片机基础,前后用过5种单片机了(都还算是主流的牌子),要是学单片机的话,就是全英文的文档我也能对付,毕竟就是那些固定的寄存器之 ...…

查看全部问答>

请教VS2008,如何调用文件来操作。

我用vs2008进行wince编程,想通过程序访问一个文件,并读取文件的内容,但是我把文件放在项目的DEBUG目录以及虚拟pocket pc的根目录下,老是出现错误,这是什么原因,是不是我哪个环节弄错了,那应该怎么办呢。 源文本文件: 1,校长,张三明 2,主 ...…

查看全部问答>

问题很难!!

1.最近刚刚用了Quartus II 9.1新版本,在使用时我想建立一个SOPC,但怎么也建立不起来,和Quartus II 8.1不一样,好像缺少了什么!在project显示的是New component..但双击它时,系统给出一些提示,有一些warnings,意思好像提示要建立一个新的compo ...…

查看全部问答>

向有微软嵌入式MCTS认证经验的各位大侠学习

推荐下载--Windows Embedded的微软认证技术专家(MCTS)及认证免费中文简体版备考工具包 http://topic.eeworld.net/u/20091125/21/fb074b0c-ad66-494c-aea5-c8137fe77582.html?seed=867673799&r=61440219#r_61440219 请过了的大虾们多多讲点备考 ...…

查看全部问答>

新手上路:我不会用MDISWIZVX.EXE,哪位大侠能指教一下

编译总会出现Warning,为什么呢?想了好几天,没有进展。 QQ:379993061…

查看全部问答>

求培训学校

要求从基础开始 在上海上课周末    教师有能力 有实力 具有一定的开发经验 我想学习硬件设计 最终目标 能自己设计系统 请大家推荐下好的培训学校 …

查看全部问答>

LED照明特点与驱动器类型

半导体照明与一般光伏电源配用的节能灯泡相比具有节能、长寿、安全、环保、色彩丰富、体积小、耐闪烁、可靠性高、调控方便等诸多优点。发光二极管作为一种新型照明光源正在获得越来越广泛的应用。   一、半导体照明特点   电子元件二极管中半 ...…

查看全部问答>