rt_hw_context_switch_to()没有来源线程,切换到目标线程,在调度器启动第一个线程的时候被调用。只使用一次。其执行逻辑流程图如下所示:
其采用汇编语言来实现,如下所示:
;/*
; * void rt_hw_context_switch_to(rt_uint32 to);
; * r0 --> to
; * this fucntion is used to perform the first thread switch
; */
rt_hw_context_switch_to PROC
EXPORT rt_hw_context_switch_to
; set to thread
LDR r1, =rt_interrupt_to_thread
STR r0, [r1]
; set from thread to 0
LDR r1, =rt_interrupt_from_thread
MOV r0, #0x0
STR r0, [r1]
; set interrupt flag to 1
LDR r1, =rt_thread_switch_interrupt_flag
MOV r0, #1
STR r0, [r1]
; set the PendSV exception priority
LDR r0, =NVIC_SYSPRI2
LDR r1, =NVIC_PENDSV_PRI
LDR.W r2, [r0,#0x00] ; read
ORR r1,r1,r2 ; modify
STR r1, [r0] ; write-back
; trigger the PendSV exception (causes context switch)
LDR r0, =NVIC_INT_CTRL
LDR r1, =NVIC_PENDSVSET
STR r1, [r0]
; restore MSP
LDR r0, =SCB_VTOR
LDR r0, [r0]
LDR r0, [r0]
MSR msp, r0
; enable interrupts at processor level
CPSIE F
CPSIE I
; never reach here!
ENDP
2.1 函数定义与声明
;/*
; * void rt_hw_context_switch_to(rt_uint32 to);
; * r0 --> to
; * this fucntion is used to perform the first thread switch
; */
rt_hw_context_switch_to PROC ;PROC定义子程序,与ENDP成对使用,表示子程序结束
EXPORT rt_hw_context_switch_to ;导出rt_hw_context_switch_to,让其具有全局属性,可以在C文件调用
该函数输入参数的是线程结构体to_thread的栈指针(sp),进入该函数,该栈指针自动赋值给CPU的r0寄存器。
2.2 获取要切换到的线程的sp指针
; r0的值是一个指针,该指针指向to线程的线程控制块的SP成员
LDR r1, =rt_interrupt_to_thread ;将 rt_interrupt_to_thread 的地址(不是其本身的值)加载到 r1
STR r0, [r1] ;将 r0 的值存储到 rt_interrupt_to_thread
; 设置 rt_interrupt_from_thread 的值为 0,表示启动第一次线程切换
LDR r1, =rt_interrupt_from_thread ;将 rt_interrupt_from_thread 的地址加载到 r1
MOV r0, #0x0 ;配置 r0 等于 0(意味着该线程不存在)
STR r0, [r1] ;将 r0 的值存储到 rt_interrupt_from_thread
rt_interrupt_from_thread和rt_interrupt_to_thread是一个32位的全局变量(初始值都为0),用于作为保存相应线程指针的容器。
2.3 设置中断标志位为1
;设置标志为1,表示需要切换,这个变量将在PendSV异常处理函数里切换时被清零
LDR r1, =rt_thread_switch_interrupt_flag ;将rt_thread_switch_interrupt_flag的地址加载到r1
MOV r0, #1 ;配置 r0 等于 1,相当于使能切换标志
STR r0, [r1] ;将 r0的值存储到rt_thread_switch_interrupt_flag
rt_thread_switch_interrupt_flag是一个32位的全局变量(初始值都为0),用于标示是否切换。
2.4
; 设置PendSV异常优先级为最低优先级
LDR r0, =NVIC_SYSPRI2 ;把system priority register(2)的地址加载到r0
LDR r1, =NVIC_PENDSV_PRI ;把PendSV priority value (lowest)的地址加载到r1
LDR.W r2, [r0,#0x00] ; read
ORR r1,r1,r2 ; modify
STR r1, [r0] ; write-back
2.5
; 触发 PendSV 异常 (产生上下文切换)
LDR r0, =NVIC_INT_CTRL
LDR r1, =NVIC_PENDSVSET
STR r1, [r0]
2.6
; 放 弃 芯 片 启 动 到 第 一 次 上 下 文 切 换 之 前 的 栈 内 容, 将 MSP 设 置 启 动 时 的 值
LDR r0, =SCB_VTOR
LDR r0, [r0]
LDR r0, [r0]
MSR msp, r0
2.7
; 使 能 全 局 中 断 和 全 局 异 常, 使 能 之 后 将 进 入 PendSV 异 常 处 理 函 数
CPSIE F
CPSIE I
; 不 会 执 行 到 这 里
END