“野火FreeRTOS教程”第7章补充知识点-异常流程

一、知识点

1. Cortex-M3/4在复位后CONTROL寄存器初始值为0,也就是说MCU会处于线程模式、具有特权访问权限且使用主栈指针(MSP)

2. 当进入异常时CM3会自动入栈,如下图所示:

 3. 当异常返回时CM3会自动出栈,如下图所示:

 4. CM3进入异常或者中断服务函数(ISR)时,R14(LR)会被自动更新为EXC_RETURN,且EXC_RETURN具有以下位域。

当发生程序调用后,LR为子程序的返回地址。(程序调用的实质是将PC赋值给LR,执行完子程序后,又将LR赋值给PC。这些由硬件自动完成)

二、教程分析

1. 文中指出任务栈在初始化完成后,如下状态,可以看到此时栈顶指针指在最低地址处,当然这时PSP还没有被赋值为栈顶指针。

图、二-1

 2. 接下来调用"SVC 0",产生SVC异常服务,教程中SVC异常服务函数如下。

按照出现顺序,这里用到知识点2图8.7、知识点4、知识点3图8.10(#1出栈时)。进入SVC异常服务函数前,CPU会自动将R0,…,xPSR(8个32位寄存器)存储到MSP指向空间,R4-R11不会自动入栈。当然在SVC异常服务函数中,我们是去启动第一个任务,因此主要考虑出栈操作,如下。

  • 上图(2)-(4)是获取任务栈顶指针,(5)LDMIA是指先加载指针指向内容至CPU寄存器中,然后增加指针(加载一个内容增加一个指针,!表示指针变量会更新),(6)把当前的栈指针赋值给PSP,(9)给EXC_RETURN或上0xd,表示“返回线程模式且返回后使用进程栈(PSP)”。
  • 当使用"bx r14"后会触发异常返回机制,CPU会使用PSP来完成自动出栈,即将R0,…,xPSR存储到PSP指向空间,CPU也是使用LDMIA完成出栈操作的,因而此时PSP指向任务栈的位置如下。
  • 此后CPU会取走R15(PC),程序自然跳转到任务1循环体中执行。

3.  任务1入栈

在任务1循环体的最后触发了PendSVC异常服务这里用到知识点2图8.8,知识点3图8.10(#1压栈时和出栈时)。教程中PendSVC异常服务函数如下。

图、二-3
  •  进入PendSVC异常服务函数前,CPU会自动将R0,…,xPSR存储到PSP指向空间,CPU是使用STMDB完成入栈操作的,R4-R11不会自动入栈,此时PSP还是指向第一个任务的栈空间,如下图。STMDB是指先减小指针,然后存储CPU寄存器值至指针指向空间中(减小一个指针存储一个内容,!表示指针变量会更新)

  • 剩下的R4-R11也需要使用STMDB手动入栈,见图二-3中的(4)、(7)。
  • 然后将R0的值赋值给第一个任务的栈顶指针,见图二-3中的(5)、(6)、(8),以恢复任务栈顶指针为初始状态,如图二-1。(其实可以不用重新赋值任务的栈顶指针,因为没有变过,但考虑到要逻辑严谨,还是重新赋值比较好)。此时的PSP、R0和第一个任务的栈顶指针状态如下。

  •  到这里任务1的入栈已经完成。

 4 任务2出栈

  •  接着看图二-3,(9)其实就是保护EXC_RETURN的bit2不会变成0,因为一旦发生程序调用,R14即为子程序的返回地址,原本的EXC_RETURN就会被打乱,导致异常返回时,CPU的SP不一定就是PSP,所以必须加以保护。
  • R3也要加以保护,因为它保存了一个指针变量(pxCurrentTCB)的地址,指向要(或正在)执行的任务控制块。
  • (12)将pxCurrentTCB指向第二个任务控制块。
  • 进入异常或中断后,CPU自动使用主栈,因此(9)和(14)使用的SP就是MSP。
  • (15)-(19)与二-2(SVC异常服务)是一样的。
  • 至于为什么最后没有给EXC_RETURN或上0xd,其实EXC_RETURN_bit2没改变过,当然你要或上0xd也可以。

5. 总结

 

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Hi,Man go!

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值