• FreeRtos进阶——中断的内部逻辑


    中断与非中断API的区别

    BaseType_t xQueueSendToBack(
                                    QueueHandle_t    xQueue,
                                    const void       *pvItemToQueue,
                                    TickType_t       xTicksToWait
                                );
    BaseType_t xQueueSendToBackFromISR(
                                          QueueHandle_t xQueue,
                                          const void *pvItemToQueue,
                                          BaseType_t *pxHigherPriorityTaskWoken
                                       );
    

    以写队列的API为例,在非中断的api中最后一项参数为等待时间,而在中断api中最后一项参数仅仅是说明有无优先级更高的任务被唤醒。
    在这里插入图片描述
    在非中断api中,执行的逻辑是这样,如果遇到更高优先级的任务被唤醒,那么更高优先级的任务将会抢占当前任务。而在中断api中,会先记录更高优先级的任务,在中断里的任务处理完成后,在中断末尾对任务进行切换。

    中断的范围

    FreeRtos中,关中断并不是关闭所有中断,能够关闭的中断都是对于系统来说都是等级相对较低的,等级高的中断不能关断。因为在FrerRtos中,根本就没有涉及到高等级的中断,在操作系统的api中仅仅只包含了低级的中断。
    在这里插入图片描述

    注意:即使最低优先级的中断 也比最高优先级的任务 优先级要高

    中断服务函数 xPortPendSVHandler()

    在系统滴答定时器中断服务函数中调用API函数xPortSysTickHandler(),xPortSysTickHandler()函数中通过向中断和状态寄存器的bit28写入1来启动PendSV中断,具体PendSV中断服务函数是 PendSV_Handler,并且任务切换的具体任务是在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()来获取下一个要运行的任务,也就是查找已经就绪了的优先级最高的任务,最后切换新的任务。

  • 相关阅读:
    PMP考试有用吗?
    Oracle 2019c安装闪退解决过程
    【毕业设计】基于单片机的室内环境温湿度检测系统 - 物联网 嵌入式 stm32
    深度学习跟踪DLT (deep learning tracker)
    42.cuBLAS开发指南中文版--cuBLAS中的Level-3函数gemm()
    并查集
    Java 迭代器、Object类、泛型、序列化
    黑马瑞吉外卖之菜品的分页查询展示(难点)
    使用C#调用P6 Primavera WebService(自建服务IntegrationAPI)
    QT实现的截屏工具与录像功能
  • 原文地址:https://blog.csdn.net/zhoutan001/article/details/139360290