打印
[牛人杂谈]

PendSV中断以及其用法

[复制链接]
25|8
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
小灵通2018|  楼主 | 2025-1-24 12:23 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
PendSV(Pendable Service Call)是ARM Cortex-M系列处理器特有的异常类型,专门为实时操作系统(RTOS)设计,用于任务切换或其他需要延后执行的低优先级任务。
用途:PendSV主要用于上下文切换(Context Switch),即在多任务系统中,切换当前运行任务到下一个任务。
优点:它的优先级最低,不会干扰高优先级中断。通过软件触发,提供灵活性和精确控制。不需要额外的硬件支持,可以高效实现任务切换。

使用特权

评论回复
沙发
小灵通2018|  楼主 | 2025-1-24 12:23 | 只看该作者
PendSV中断的特点

最低优先级:
它的优先级是可编程的,但通常被设置为最低,以避免干扰其他中断。
在Cortex-M中,优先级通过NVIC(Nested Vectored Interrupt Controller)配置。

软件触发:

PendSV不能由硬件触发,只能通过软件设置触发(写入SCB中的ICSR寄存器)。

中断延后:
PendSV可以被挂起,直到高优先级中断处理完成后再执行。
它的“挂起特性”使得它非常适合实现任务切换,而不会影响关键实时任务。

与SysTick的配合:
SysTick定时器用于产生周期性中断,触发调度器运行。
PendSV负责执行实际的任务切换。

使用特权

评论回复
板凳
小灵通2018|  楼主 | 2025-1-24 12:25 | 只看该作者
PendSV的触发机制
触发PendSV中断:
向SCB->ICSR寄存器的PENDSVSET位写入1即可触发PendSV中断。
SCB->ICSR |= SCB_ICSR_PENDSVSET_Msk;  // 设置PendSV挂起位
清除PendSV挂起:
PendSV中断执行后,硬件会自动清除挂起状态。
也可以通过软件清除挂起状态:
SCB->ICSR |= SCB_ICSR_PENDSVCLR_Msk;  // 清除PendSV挂起位
设置优先级:
通过NVIC_SetPriority函数设置PendSV为最低优先级:
NVIC_SetPriority(PendSV_IRQn, NVIC_EncodePriority(NVIC_GetPriorityGrouping(), 0xFF, 0xFF));


使用特权

评论回复
地板
小灵通2018|  楼主 | 2025-1-24 12:25 | 只看该作者
PendSV的用法
在RTOS中,PendSV通常用于任务调度和任务切换,以下是一个典型的流程:

任务切换的大致步骤
SysTick中断触发:定时器(如SysTick)触发中断,唤醒调度器。
调度器决定下一个任务:根据任务优先级、状态等信息选择下一个任务。
PendSV中断触发:调度器触发PendSV中断。
执行任务切换:
保存当前任务的上下文(寄存器、堆栈指针等)。
加载下一个任务的上下文,切换任务。


使用特权

评论回复
5
小灵通2018|  楼主 | 2025-1-24 12:26 | 只看该作者
以下是一个典型的PendSV中断服务例程(Cortex-M架构下):
void PendSV_Handler(void) {
    // 保存当前任务上下文
    __asm volatile (
        "MRS R0, PSP\n"                  // 获取当前任务的进程堆栈指针 (Process Stack Pointer)
        "STMDB R0!, {R4-R11}\n"          // 保存低寄存器(R4-R11)到堆栈
        "LDR R1, =current_tcb\n"         // 加载当前任务控制块的地址
        "LDR R2, [R1]\n"                 // 获取当前任务的TCB地址
        "STR R0, [R2]\n"                 // 保存当前任务的堆栈指针到TCB
    );

    // 加载下一个任务上下文
    __asm volatile (
        "LDR R2, =next_tcb\n"            // 加载下一个任务控制块的地址
        "LDR R2, [R2]\n"                 // 获取下一个任务的TCB地址
        "LDR R0, [R2]\n"                 // 获取下一个任务的堆栈指针
        "LDMIA R0!, {R4-R11}\n"          // 恢复低寄存器(R4-R11)
        "MSR PSP, R0\n"                  // 恢复进程堆栈指针
        "BX LR\n"                        // 返回下一个任务
    );
}

使用特权

评论回复
6
小灵通2018|  楼主 | 2025-1-24 12:26 | 只看该作者
配合调度器触发PendSV
RTOS的调度器通常在决定切换任务后触发PendSV。例如:
void task_switch(void) {
    // 触发PendSV中断,进行任务切换
    SCB->ICSR |= SCB_ICSR_PENDSVSET_Msk;
}

使用特权

评论回复
7
小灵通2018|  楼主 | 2025-1-24 12:26 | 只看该作者
配合调度器触发PendSV
RTOS的调度器通常在决定切换任务后触发PendSV。例如:
void task_switch(void) {
    // 触发PendSV中断,进行任务切换
    SCB->ICSR |= SCB_ICSR_PENDSVSET_Msk;
}

使用特权

评论回复
8
小灵通2018|  楼主 | 2025-1-24 12:27 | 只看该作者
PendSV的作用与SysTick配合示例
以下示例演示了如何结合SysTick和PendSV实现任务调度:
#include "stm32f4xx.h"

void SysTick_Handler(void) {
    // 调度器逻辑:决定是否需要切换任务
    if (should_switch_task()) {
        SCB->ICSR |= SCB_ICSR_PENDSVSET_Msk;  // 触发PendSV中断
    }
}

void PendSV_Handler(void) {
    // 保存当前任务上下文并切换到下一个任务
    save_context();
    schedule_next_task();
    restore_context();
}

使用特权

评论回复
9
小灵通2018|  楼主 | 2025-1-24 12:27 | 只看该作者
总结
触发条件:

PendSV由软件触发(SCB->ICSR寄存器),不能由硬件自动触发。
优先级设置:

确保PendSV优先级最低(通常与调度器无关的中断优先级较高)。
任务切换效率:

PendSV的主要作用是保存当前任务上下文并加载下一个任务的上下文,效率对RTOS性能至关重要。
与SysTick配合:

SysTick定时器负责定时触发调度器运行,调度器触发PendSV完成实际任务切换。

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

144

主题

1656

帖子

4

粉丝