【9】从0到1教你写uC/OS-III————>任务切换PendSV异常

  1. OSStartHighRdy()用于启动任务切换,即配置PendSV异常为最低优先级,然后触发PendSV异常
  2. PendSV函数内进行任务切换,无返回值,使用汇编程序编写
  3. 常见ARM汇编指令详解:
    1. EQU:给数字常量取一个符号名,相当于C语言中的define
    2. AREA:汇编一个新的代码段 或者 数据段
    3. SPACE:分配内存空间
    4. PRESERVE8:当前文件堆栈按照8字节对齐
    5. EXPORT:声明一个标号具有全局属性,可被外部的文件使用
    6. DCD:以字为单位分配内存,要求4字节对齐,并要求初始化这些内存
    7. PROC:定义子程序,与ENDP成对使用,表示子程序结束
    8. WEAK:弱定义,如果外部文件声明了一个标号,则优先使用外部文件定义的标号,如果外部文件没有定义也不出错;需要注意的是:这个不是ARM的指令,是编译器的,这里放在一起只是为了方便
    9. IMPORT:声明标号来自外部文件,跟C语言中的EXTERN关键字类似
    10. B:跳转到一个标号
    11. ALIGN:编译器对指令或者数据的存放地址进行对齐,一般需要跟一个立即数,缺省表示 4字节对齐;要注意的是:这个不是ARM的指令,是编译器,这里放在一起只是为了方便
    12. END:到达文件的末尾,文件结束
    13. IF、ELSE、ENDIF:汇编条件分支语句,跟C语言的if else类似
  4. PendSV_Handler函数中用到的ARM汇编指令
    1. MRS:加载特殊功能寄存器的值 到通用寄存
    2. MSR:存储通用寄存器的值到特殊功能寄存器
    3. CBZ:比较,如果结果为0就转移
    4. CBNZ:比较,非0转移
    5. LDR:从存储器中加载字到一个寄存器中
    6. LDR[伪指令]:加载一个立即数或者一个地址值到一个寄存器。例如:LDR Rd, = label,如果label是立即数,那Rd等于立即数,如果label是一个标识 符,比如指针,那存到Rd的就是label这个标识 符的地址
    7. LDRH:从存储器中加载半字到一个寄存器中
    8. LDRB:---------------------字节---------------------
    9. STR:把一个寄存器按字存储到存储器中
    10. STRH:----------------的低半字存储到存储器中
    11. STRB:-------------------低字节---------------------
    12. LDMIA:加载多个字,并且在加载后自增基址寄存器
    13. STMIA:存储---------------------------------------------------
    14. ORR:按位或
    15. BX:直接跳转到由寄存器给定的地址
    16. BL:跳转到标号对应的地址,并且把跳转前的下条指令地址保存到LR
    17. BLX:跳转到由寄存器REG给出的地址,并根据REG的LSB切换处理器状态,还要把转移前的下条指令地址保存到LR;ARM(LSB=0),Thumb(LSB=1),CM3只在Thumb中运行,就必须保证reg的LSB=1,否则一个fault打过来
  5. 例程:
    ;************************************************************************************************************************
    ;                                              全局变量、函数 
    ;************************************************************************************************************************
    	IMPORT		OSTCBCurPtr			;外部文件引入的参考
    	IMPORT		OSTCBHighRdyPtr		;同上
    
    	EXPORT		OSStartHighRdy		;本文件定义的函数
    	EXPORT		PendSV_Handler		;同上
    		
    
    ;************************************************************************************************************************
    ;                                              常亮
    ;有关内核外设寄存器定义可参考官方文档:STM32F10xxx Crotex_M3 programing manual
    ;系统控制块外设SCB地址范围:0xE000 ED00 - 0xE000 ED3F
    ;************************************************************************************************************************
    
    NVIC_INT_CTRL	EQU		0xE000ED04	;中断控制及状态寄存器SCB_ICSR
    NVIC_SYSPRI14	EQU		0xE000ED22	;系统优先级寄存器SCB_SHPR3:BIT16~23
    NVIC_PENDSV_PRI	EQU			  0xFF	;PendSV 优先级的值(最低)
    NVIC_PENDSVSET	EQU		0x10000000	;触发PendSVn异常的值 BIT28:PENDSVSET
    
    
    ;************************************************************************************************************************
    ;                                              代码产生指令 
    ;************************************************************************************************************************
    	PRESERVE8
    	THUMB
    		
    	AREA	CODE,	CODE,	READONLY
    
    ;************************************************************************************************************************
    ;                                              开始第一次上下文切换
    ;1、配置PendSV异常的优先级为最低
    ;2、在开始第一次上、下文切换之前,设置PSP = 0
    ;3、触发PendSV异常,开始上、下文切换
    ;************************************************************************************************************************
    OSStartHighRdy
    	LDR		R0,	= NVIC_SYSPRI14		;设置PendSV异常优先级为最低
    	LDR		R1,	= NVIC_PENDSV_PRI
    	STRB	R1,	[R0]
    	
    	MOVS	R0, #0					;设置psp的值为0,开始第一次上、下文切换
    	MSR		PSP, R0
    	
    	LDR		R0,	=NVIC_INT_CTRL		;触发PendSV异常
    	LDR		R1,	=NVIC_PENDSVSET		
    	STR		R1, [R0]
    	
    	CPSIE	I						;开中断
    
    OSStartHang
    	B		OSStartHang				;程序应 永远不会运行到此处
    
    ;************************************************************************************************************************
    ;                                              PendSVHandler异常
    ;************************************************************************************************************************
    PendSV_Handler
    ;任务的保存,即把CPU寄存器的值存储到任务的堆栈中
    	CPSID	I						;关中断,NMI和HardFault除外,防止上、下文切换被中断
    	MRS		R0,	PSP					;将PSP的值加载到R0
    	CBZ		R0, OS_CPU_PendSVHandle_nosave	;判断R0,如果值为0则跳转到OS_CPU_PendSVHandle_nosave
    									;进行第一次任务切换的时候,r0肯定为0
    									
    ;在进入PendSV异常的时候,当前CPU的xPSR,PC(任务入口地址),R14\R12\R3\R2\R1\R0会自动存储到当前任务堆栈,同时递减PSP的值 
    	STMDB	R0!, {R4-R11}			;手动存储CPU寄存器R4-R11的值 到当前任务的堆栈
    	
    	LDR		R1,	= OSTCBCurPtr		;加载OSTCBCurPtr指针的地址到R1,这里LDR属于伪指令
    	LDR		R1,	[R1]				;加载OSTCBCurPtr指针到R1,这里LDR属于ARM指令
    	STR		R0,	[R1]				;存储R0的值到 OSTCBCurPtr->OSTCBStkPtr,这个时候R0存的是任务空闲栈的栈顶
    	
    ;任务的切换,即把下一个要运行任务的堆栈内容加载到CPU寄存器中
    OS_CPU_PendSVHandle_nosave
    	;OSTCBCurPtr	=	OSTCBHighRdyPtr;
    	LDR		R0,	= OSTCBCurPtr		;加载OSTCBCurPtr指针的地址到R0,这里LDR属于伪指令
    	LDR		R1,	= OSTCBHighRdyPtr	;加载OSTCBHighRdyPtr指针的地址到R1,这里LDR属于伪指令
    	LDR		R2,	[R1]				;加载OSTCBHighRdyPtr指针到R2,
    	STR		R2,	[R0]				;存储OSTCBHighRdyPtr到OSTCBCurPtr
    	
    	LDR		R0,	[R2]				;加载OSTCBHighRdyPtr到R0
    	LDMIA	R0!, {R4-R11}			;加载需要手动保存的信息到CPU寄存器R4-R11
    	
    	;更新PSP的值,这时PSP指向下一个要执行的任务的堆栈的栈底(这个栈底已经加上刚刚手动加载到CPU寄存器R4-R11的偏移)
    	MSR		PSP, R0					
    	ORR		LR,	 LR,	#0x04		;确保异常返回使用的堆栈指针是PSP,即LR寄存器的bit2为1
    	CPSIE	I						;开中断
    	
    	;异常返回,这个时候任务堆栈中的剩下内容将会自动加载到xPSR,PC(任务入口地址)R14\R12\R3\R2\R1\R0(任务的形参)
    	;同时PSP的值也将更新,即指向任务堆栈的栈顶,在STM32中,堆栈是由高地址向低地址生长
    	BX		LR						
    
    	NOP								;汇编指令对齐,不然会有警告
    	
    	END								;汇编文件结束

     

  6. 总结:涉及到ARM汇编指令,略显复杂
  7. ARM汇编指令电脑壁纸1920*1080,相当炫酷,来自硬汉论坛
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值