1910_野火FreeRTOS教程阅读笔记_prvStartFirstTask函数
全部学习汇总: g_FreeRTOS: FreeRTOS学习笔记
这是教程中的一个函数,通过汇编来实现的。注释部分以及结合后面的讲解部分,可能还是有一点点细节的地方让初学者疑惑。我结合我自己的理解,再度补充一些信息。
SCB_VTOR地址是如何得出来的?
首先,可以从手册中找到基地址0xE000ED00。
再从细分章节中找到,偏移量是0x08,两个信息组合就可以得出上面对应的地址。
至于这个地址为什么可以读取到MSP的数值,需要结合下面的信息理解。
这里描述的事向量表的内容,向量表的0地址偏移处刚好是SP的初始值。现在还在内核状态,还没有进入到task运行的线程模式。因此,这里读取出来的数值是MSP的信息。
野火的教程中说有点多于,我觉得可能这个原自于这一段描述。读取的数值是来自于地址
0x00000000的。
直接通过代码打印可以看得出来这个推测是准确的。
而上面的这个接口在执行的时候会触发SVC。
超级调用(SVC)是由SVC指令触发的异常。在操作系统环境中,应用程序可以使用SVC指令访问操作系统内核函数和设备驱动程序。
之后会触发这个SVC Handler,这个接口是在启动代码文件中定义的,这里通过了宏定义进行了转换。
因此,实际的效果是SVC_Handler。如果不增加这个宏定义,直接定义SVC_Handler也是一样的。
这是汇编代码中的信息。
再回去看上面vPortSVCHandler代码中的信息,代码到124行,其实是获取了当前任务TCB中的栈顶信息。继续往下的8个寄存器,实现了局部变量的加载。
之前查看文档的时候看到过这个24bit一直是1,其实这个代表的事Thumb状态位。
M3的处理器只能够再Thumb状态下执行指令,但是如下操作可以清除掉这个指令:
- 指令BLX, BX和POP{PC}
- 从异常上的堆叠xPSR值恢复
- 异常项上的向量值的位[0]或复位
以上,是为什么要进入到这个状态的原因,但是这个描述应该是适用于线程等分支调用。至于为什么要写入0xD,其实有其他的原因,因为这里的这段代码是一个异常的Handler。
之所以出现最后两个指令操作,主要原因还是因为这里需要完成一次异常的返回。EXC_RETURN是在异常entry上加载到LR中的值。异常机制依赖此值来检测处理器何时完成异常处理程序。该值的最低四位提供有关返回堆栈和处理器模式的信息。表17显示了EXC_RETURN[3:0]值以及异常返回行为的描述。
这是上面提到的表17。因此,这里实现的功能是返回到线程模式、从PSP获取状态、返回之后利用PSP执行。这样,SP就从MSP切换到了PSP。而BX指令是上面提到的三种返回exception的方式之一。
而返回之后,由于之前的SVC等已经设置了PSP的信息,因此接下来的软件会按照PSP中的设定去执行。任务调度也就会启动。为什么能够启动,结合之前梳理的任务创建的分析是可以理解的。因为任务创建的时候,把执行入口绑定到了TCB的栈中,在这次的退出时会返回执行。
这里的这个示意图还是比较有参考意义的,至于上面为什么没有R13,这是因为R13座位了SP寄存器在使用中。