freeertos中关于PendSV中断服务函数的解析

__asm void xPortPendSVHandler( void )
{
    extern uxCriticalNesting;
    extern pxCurrentTCB;
    extern vTaskSwitchContext;

    PRESERVE8        //栈的8字节对齐

    mrs r0, psp          //读取当前psp进程指针,存入r0
    isb
    /* 获取当前任务控制块 */
    ldr    r3, =pxCurrentTCB  //把当前任务控制块的指针给r3
    ldr    r2, [r3]        //把r3地址中的值给r2,r2中就存储当前的任务控制块

    /* 是否使用了FPU,使用的话要手动保存s16~s31 */
    tst r14, #0x10
    it eq
    vstmdbeq r0!, {s16-s31}

    /* Save the core registers. */
    stmdb r0!, {r4-r11, r14}    //含义::依次压栈r0 = r0 - 4,先压r14,r0 = r14(即将r14中的内容放入r0所指的内存地址)
                                             // r0 = r0 - 4,再压r11,r0 = r11。
                                             // r0 = r0 - 4,再压r10,r0 = r10......r0 = r0 - 4,最后压r4,r0 = r4。
                                             // 则r0中就保存最新的栈顶指针值                

    /* 保存最新的栈顶指针到当前任务控制块的第一字段*/
    str r0, [r2]          //把r0的值存入r2的地址,相当于*r2 = r0,[r2]中已经保存了最新的任务的控制块,经过上面的两个ldr指令,r2中已经保存最新的任务控制块的地址

    stmdb sp!, {r3}      //将寄存器R3的值临时压栈,寄存器r3中仍然保存着当前任务的任务控制块,
                         //而接下来要调用函数vTaskSwitchContext,防止r3的值被改写,故临时压栈

    mov r0, #configMAX_SYSCALL_INTERRUPT_PRIORITY
    msr basepri, r0         //关中断,进入临界区

    dsb
    isb
    bl vTaskSwitchContext  //调用函数vTaskSwitchContext,此函数用来获取下一个要运行的任务,并将pxCurrentTCB更新为要运行的这个任务

    mov r0, #0
    msr basepri, r0      //开中断,退出临界区

    ldmia sp!, {r3}   //刚刚保存的寄存器R3的值出栈,恢复寄存器R3的值。注意,经过调用函数vTaskSwitchContext,此时
                      //pxCurrentTCB的值已经改变了,所以读取R3所保存的地址处的数据就会发现其值改变了,成
                      //为了下一个要运行的任务的任务控制块。

    ldr r1, [r3]
    ldr r0, [r1]     //获取新的运行任务的栈顶,并存到r0中去

    /* 弹出内核寄存器 */
    ldmia r0!, {r4-r11, r14}  //含义::依次出栈    r0 = r0 + 4,先弹出r14,r0 = r14(即将r14中的内容放入r0所指的内存地址)
                                              // r0 = r0 + 4,再弹r11,r0 = r11。
                                              // r0 = r0 + 4,再弹r10,r0 = r10......r0 = r0 - 4,最后出r4,r0 = r4。

    /*是够使用了FPU,使用了徐要手动保存s16~s31*/
    tst r14, #0x10
    it eq
    vldmiaeq r0!, {s16-s31}

    msr psp, r0 //更新进程栈指针PSP的值
    isb
    #ifdef WORKAROUND_PMU_CM001 /* XMC4000 specific errata *///这块暂时不用管
        #if WORKAROUND_PMU_CM001 == 1
            push { r14 }
            pop { pc }
            nop
        #endif
    #endif

    bx r14    //执行此行代码以后硬件自动恢复寄存器R0~R3、R12、LR、PC和xPSR的值,确定异常返回以后应该进入处理器模式还是进程模式,使用主栈指针(MSP)还是进程栈指针(PSP)。          很明显这里会进入进程模式,并且使用进程栈指针(PSP), 寄存器PC值会被恢复为即将运行的任务的任务函数,新的任务开始运行!至此,任务切换成功。
}

原文地址:https://www.cnblogs.com/sanshijvshi/p/11764143.html

时间: 2024-10-14 01:06:07

freeertos中关于PendSV中断服务函数的解析的相关文章

嵌入式中断服务函数的一些特点

中断是嵌入式系统中重要的组成部分,但是在标准C中不包含中断.许多编译开发商在标准C上增加了对中断的支持,提供新的关键字用于标示中断服务程序 (ISR),类似于__interrupt.#program interrupt等.当一个函数被定义为ISR的时候,编译器会自动为该函数增加中断服务程序所需要的中断现场入栈和出栈代码. 中断服务程序需要满足如下要求: (1)不能返回值: (2)不能向ISR传递参数: (3) ISR应该尽可能的短小精悍: (4) printf(char * lpFormatSt

UCOS iii 钩子函数 中断服务函数 临界区 延时函数

钩子函数 功能: 扩展任务功能,被其他任务调用  算是消息机制 1.OSIdleTaskHook(),空闲任务调用这个函数,可以用来让CPU进入低功耗模式 2.OSInitHook(), 系统初始化函数OSInit()调用此函数. 3.OSStatTaskHook(),统计任务每秒中都会调用这个函数,此函数允许你向统计任务中添加自己的应用函数. 4.OSTaskCreateHook(),任务创建的钩子函数. 5.OSTaskDelHook(), 任务删除的钩子函数. 6.OSTaskReturn

一种根据不同阶级注册不同的中断服务函数的写法

一.注册一个硬件中断服务函数irq_handler,作为硬件中断产生后,实际中断服务函数的总入口. void intc_setup_irq(vector, priority, irq_handler) 二.中断服务函数irq_handler入口,根据不同的条件调用不同分支 void irq_handler(void) { get isr val switch(val) { case condition_1: call_service(condition_1) case condition_2:

中断服务函数的编写要求

中断是嵌入式系统中重要的组成部分,但是在标准C中不包含中断.许多编译开发商在标准C上增加了对中断的支持,提供新的关键字用于标示中断服务程序 (ISR),类似于__interrupt.#program interrupt等.当一个函数被定义为ISR的时候,编译器会自动为该函数增加中断服务程序所需要的中断现场入栈和出栈代码 例: _interrupt double compute_area(double radius) { double area=PI*radius*radius; printf("

request_irq() | 注册中断服务

一.中断注册方法 在linux内核中用于申请中断的函数是request_irq(),函数原型在Kernel/irq/manage.c中定义: int request_irq(unsigned int irq, irq_handler_t handler,                         unsigned long irqflags, const char *devname, void *dev_id) irq是要申请的硬件中断号. handler是向系统注册的中断处理函数,是一个

函数可重入问题reentrant functions(函数执行过程中可以被中断,允许多个副本)

最近经常听到这个名词,以前也听到过,不过接触更多的是“线程安全问题”,而且本人也一直理解的是两个名字的含义是一样的.今天仔细总结一下这个名词相关的概念. 引用博文:可重入函数和不可重入函数 (http://www.cppblog.com/franksunny/archive/2007/08/03/29269.html) 主要用于多任务环境中, 一个可重入的函数简单来说就是可以被中断的函数,也就是说,可以在这个函数执行的任何时刻中断它,转入OS调度下去执行另外一段代码,而返回控制时不会出现什么错误

中断服务子程序

中断是嵌入式系统中重要的组成部分,这导致了很多编译开发商提供一种扩展—让标准C支持中断. 具代表事实是,产生了一个新的关键字 __interrupt. 下面的代码就使用了__interrupt关键字去定义了一个中断服务子程序(ISR),请评论一下这段代码的. __interrupt double compute_area (double radius) {    double area = PI * radius * radius;    printf("\nArea = %f", a

SylixOS中GIC通用中断控制器(二)——GIC实现

1.概述 本篇文档主要介绍IMX6UL平台上基于SylixOS集成开发环境中GIC通用中断控制器的实现流程和方法. 2.GIC控制器基地址获取 GIC控制器基地址通过调用armPrivatePeriphBaseGet函数获得.如图 2.1所示,Ctrl+h局搜索armPrivatePeriphBaseGet函数,搜索结果如图 2.2所示. 图 2.1全局搜索armPrivatePeriphBaseGet函数 图 2.2 armPrivatePeriphBaseGet函数搜索结果 参考DDI046

STM32中断管理函数

CM3 内核支持256 个中断,其中包含了16 个内核中断和240 个外部中断,并且具有256 级的可编程中断设置.但STM32 并没有使用CM3 内核的全部东西,而是只用了它的一部分. STM32 有76 个中断,包括16 个内核中断和60 个可屏蔽中断,具有16 级可编程的中断优先级. 而我们常用的就是这60 个可屏蔽中断,所以我们就只针对这60 个可屏蔽中断进行介绍. 在 MDK 内,与NVIC 相关的寄存器,MDK 为其定义了如下的结构体: typedef struct { vu32 I