PendSV中断服务函数

之前在系统滴答定时器中断服务函数中调用API函数xPortSysTickHandler(),xPortSysTickHandler()函数中通过向中断和状态寄存器的bit28写入1来启动PendSV中断,具体PendSV中断服务函数是 PendSV_Handler,并且任务切换的具体任务是在PendSV中断服务函数中完成的,都是拿汇编写的,简单看一下。

PendSV中断服务函数

#define xPortPendSVHandler 	PendSV_Handler 

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

	PRESERVE8

	mrs r0, psp
	isb
	/* Get the location of the current TCB. */
	ldr	r3, =pxCurrentTCB
	ldr	r2, [r3]

	/* Is the task using the FPU context?  If so, push high vfp registers. */
	tst r14, #0x10
	it eq
	vstmdbeq r0!, {s16-s31}

	/* Save the core registers. */
	stmdb r0!, {r4-r11, r14}

	/* Save the new top of stack into the first member of the TCB. */
	str r0, [r2]

	stmdb sp!, {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}

	/* The first item in pxCurrentTCB is the task top of stack. */
	ldr r1, [r3]
	ldr r0, [r1]

	/* Pop the core registers. */
	ldmia r0!, {r4-r11, r14}

	/* Is the task using the FPU context?  If so, pop the high vfp registers
	too. */
	tst r14, #0x10
	it eq
	vldmiaeq r0!, {s16-s31}

	msr psp, r0
	isb
	#ifdef WORKAROUND_PMU_CM001 /* XMC4000 specific errata */
		#if WORKAROUND_PMU_CM001 == 1
			push { r14 }
			pop { pc }
			nop
		#endif
	#endif

	bx r14  //至此,任务切换成功。
}

查找下一个要运行的任务

在PendSV中断服务函数中调用了函数vTaskSwitchContext()来获取下一个要运行的任务,也就是查找已经就绪了的优先级最高的任务,缩减后(去掉条件编译)后的函数源码:

void vTaskSwitchContext( void )
{
	if( uxSchedulerSuspended != ( UBaseType_t ) pdFALSE )  //如果调度器被挂起
	{
		/* The scheduler is currently suspended - do not allow a context
		switch. */
		//调度器被挂起就不能进行任务切换
		xYieldPending = pdTRUE;  //当xYieldPending为pdTRUE时代表不进行任务切换;
	}
	else
	{        //调度器没有被挂起,
		xYieldPending = pdFALSE; //xYieldPending赋值为pdFALSE时进行任务切换;
		traceTASK_SWITCHED_OUT();//在选择运行任务之前调用。pxcurrenttcb保存一个指针,指向正在关闭的任务的任务控制块;

	
		/* Check for stack overflow, if configured. */
		taskCHECK_FOR_STACK_OVERFLOW(); //检查堆栈溢出(如果已配置)

		/* Select a new task to run using either the generic C or port
		optimised asm code. */
		taskSELECT_HIGHEST_PRIORITY_TASK();//调用该宏来获取下一个要运行的任务,即获取就绪列表的最高优先级任务列表中的下一个列表项,将列表项所对应的任务控制块赋值给pxcurrenttcb,就确定了下一个运行的任务;
		traceTASK_SWITCHED_IN();//在选择要运行的任务后调用。pxcurrenttcb保存指针到选定任务的任务控制块;
	}
}
  • 0
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
中断向量表注册不同GPIO引脚的中断服务函数可以按照以下步骤进行: 1. 定义中断服务函数: ```c void __attribute__((interrupt)) EXTI0_IRQHandler(void) { // 中断服务函数的代码 } ``` 其 `EXTI0_IRQHandler` 是针对 `GPIO0` 引脚的中断服务函数,如果需要为其他引脚注册中断服务函数,将 `EXTI0_IRQHandler` 的 `0` 替换成对应的引脚号即可。 2. 在中断向量表注册中断服务函数: 在 `startup_stm32xxxx.s` 文件找到中断向量表的定义,然后将需要注册的中断服务函数的地址填入对应的中断向量表项。 例如,假设需要注册 `GPIO0` 引脚的中断服务函数,可以在中断向量表找到 `EXTI0_IRQHandler` 对应的位置,然后将该中断服务函数的地址填入其: ```assembly /* STM32xxxx Devices Interrupt Vectors */ .section .isr_vector,"a",@progbits .type g_pfnVectors, %object .size g_pfnVectors, .-g_pfnVectors g_pfnVectors: .word _estack .word Reset_Handler .word NMI_Handler .word HardFault_Handler .word MemManage_Handler .word BusFault_Handler .word UsageFault_Handler .word 0 .word 0 .word 0 .word 0 .word SVC_Handler .word DebugMon_Handler .word 0 .word PendSV_Handler .word SysTick_Handler /* External Interrupts */ .word EXTI0_IRQHandler // 注册GPIO0引脚的中断服务函数 .word EXTI1_IRQHandler .word EXTI2_IRQHandler .word EXTI3_IRQHandler // ... ``` 注意,不同的芯片型号中断向量表的定义可能会有所不同,具体需要参考对应芯片的文档和官方示例代码。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值