嵌入式Linux八股完整文章目录
嵌入式Linux八股(一)——语言篇_嵌入式软件八股-CSDN博客
嵌入式Linux八股(二)——Linux_linux嵌入式的八股文有哪些-CSDN博客
嵌入式Linux八股(三)——计算机基础_计算机基础八股-CSDN博客
嵌入式Linux八股(四)——MCU&RTOS-CSDN博客
四、MCU&RTOS(更新中...)
01.MCU裸机
01.STM32启动模式
02.STM32启动流程
STM32启动文件由ST官方提供,在官方的固件包里。启动文件由汇编编写,是系统上电复位后第一个执行的程序。启动文件主要做了以下工作:
- 初始化堆栈指针SP=_initial_sp
- 初始化程序计数器指针PC=Reset_Handler
- 设置堆和栈的大小
- 初始化中断向量表
- 配置外部SRAM作为数据存储器(可选)
- 配置系统时钟,通过调用SystemInit函数(可选)
- 调用C库中的main函数初始化用户堆栈,最终调用main函数
【不是问题的问题】为什么STM32的Flash地址要设置到0x08000000 - STM32H7 - 硬汉嵌入式论坛 - Powered by Discuz! (armbbs.cn)
- M3,M4内核芯片上电复位后,要固定从0x0000 0000地址获取堆栈顶的地址,0x0000 0004获取复位中断服务程序地址。
- 获取复位中断服务程序的入口地址后,进入复位中断服务程序Reset_Handler
- 在复位时初始化系统(通过调用
SystemInit
函数)。 - 跳转到程序的主入口点
__main
,开始执行主程序逻辑。
; Reset handler
Reset_Handler PROC
EXPORT Reset_Handler [WEAK]
IMPORT __main
IMPORT SystemInit
LDR R0, =SystemInit
BLX R0
LDR R0, =__main
BX R0
ENDP
03.三级流水线
流水线技术通过多个功能部件并行工作来缩短程序执行时间,提高处理器的效率和吞吐率。
pc代表程序计数器,流水线使用三个阶段,因此指令分为三个阶段执行:
- 取指(从存储器装载一条指令);
- 译码(识别将要被执行的指令);
- 执行(处理指令并将结果写回寄存器)。
pc总是指向“正在取指”的指令,而不是指向“正在执行”的指令或正在“译码”的指令。因此pc总是指向第三条指令。当ARM状态时,每条指令为4字节长,所以pc始终指向该指令地址加8字节的地址,即:pc值=当前程序执行位置+8;
04.中断和异常
中断(也称外中断):处理器核在顺序执行程序指令流的过程中突然被别的请求打断而中止执行当前的程序,转而去处理别的事情,待其处理完了别的事情,然后重新回到之前程序中断的点继续执行之前的程序指令流
异常(Exception)也称内中断,指源自CPU执行指令内部的事件,如程序的非法操作码、地址越界、算术溢出、虚存系统的缺页及专门的陷入指令等引起的事件。对异常的处理一般要依赖于当前程序的运行现场,而且异常不能被屏蔽,一旦出现应立即处理。
05.Cortex-M3的寄存器组
CM3 拥有通用寄存器 R0‐R15 以及一些特殊功能寄存器。R0‐R12 是最“通用目的”的,特殊功能寄存器有预定义的功能,而且必须通过专用的指令来访问。
06.工作模式和特权等级
Cortex‐M3 支持两个模式和两个特权等级
- handler与线程模式
- 特权级与用户级
特权级和用户级的区别体现在对访问内核寄存器的限制,如果在用户模式下,非法访问了寄存器将会抛出硬件异常 。
02.FreeRTOS
01.创建任务
动态创建时,任务控制块和栈的内存是创建任务时动态分配的,任务删除时,内存可以释放。
静态创建时,任务控制块和栈的内存需要事先定义好,是静态的内存 ,任务删除时 ,内存不能释放 。
02.优先级反转
FreeRTOS任务优先级反转是指当一个低优先级的任务正在访问共享资源时,一个高优先级的任务因等待该资源而被阻塞,从而导致低优先级任务的执行时间超出预期。这种情况可能会导致系统响应性能下降或者死锁。
为了解决这个问题,FreeRTOS提供了一个特殊的机制,称为优先级继承。在优先级继承中,当一个高优先级的任务需要获取一个由低优先级任务持有的共享资源时,它会临时提升该低优先级任务的优先级,以便允许该低优先级任务快速释放该资源。这样,高优先级任务可以更快地访问共享资源,并及时完成其任务。
03.SVC和PendSV
SVC(请求管理调用)异常作用:
- 对于需要高可靠性的系统,应用任务可以运行在非特权访问等级,而且有些硬件资源可被设置为只支持特权访问,应用任务只能通过OS的服务访问这些受保护的硬件资源。(操作系统不让用户程序直接访问硬件,而是通过提供一些系统服务函数,用户程序使用 SVC 发出对系统服务函数的呼叫请求,以这种方法调用它们来间接访问硬件。)
- 它使用户程序无需在特权级下执行,用户程序无需承担因误操作而瘫痪整个系统的风险。
- 通过 SVC 的机制,还让用户程序变得与硬件无关,因此在开发应用程序时无需了解硬件的操作细节,从而简化了开发的难度和繁琐度,并且使应用程序跨硬件平台移植成为可能。
- 开发应用程序唯一需要知道的就是操作系统提供的应用编程接口(API),并且了解各个请求代号和参数表,然后就可以使用 SVC 来提出要求了(事实上,为使用方便,操作系统往往会提供一层封皮,以使系统调用的形式看起来和普通的函数调用一致,各封皮函数会正确使用 SVC指令来执行系统调用)
PendSV是Cortex-M3/M4处理器中的可悬起系统调用,常用于RTOS的任务调度上下文切换。由于其支持缓期执行,可以在无中断时执行,避免中断延迟。在典型的RTOS中,PendSV优先级最低,确保外部中断先执行,提高系统实时性。通过PendSV,即使SysTick优先级低,也能保证任务调度的精确性和外部中断的响应速度。
OS抢占IRQ进行任务调度会触发Fault,因此采用PendSV,滴答定时器中断,制作业务调度前的判断工作,不做任务切换。触发PendSV,PendSV并不会立即执行,因为PendSV的优先级最低,如果此时正好有IRQ请求,那么先响应IRQ,最后等到所有优先级高于PendSV的IRQ都执行完毕,再执行PendSV,进行任务调度。
04.中断调用过程
- 保存中断现场,把寄存器的值压入栈,包括局部变量、函数返回值、返回地址。
- 取向量,从向量表中找出对应的服务程序入口地址。
- 选择堆栈指针MSP/PSP,更新堆栈指针SP(因为入栈了8个寄存器),更新连接寄存器LR(在前面都已经将LR入栈之后,更新LR为一个特殊值用于触发中断返回),更新程序计数器PC(将服务程序入口地赋给PC寄存器准备跳转到中断服务函数中执行)。
- 中断返回。
05.任务切换过程
在OS设计中,需要在不同任务间切换,这一般被称作上下文切换,其通常在PendSV异常处理中执行,该异常可由SysTick 异常触发。在上下文切换操作中需要:
- 其他8个寄存器由硬件帮我们保存在栈里,寄存器R4~R11由我们自己保存在栈中,而这个所谓的栈就是当前任务的栈。
-
保存当前PSP数值(保存当前任务的栈的位置,等下一次切换到它的时候方便找到该任务的栈)
-
将PSP设置为下一个任务的上一次SP数值(将PSP指向下一个任务的栈)
-
恢复下一个任务的上一次保存在栈里的R4~R11
-
利用异常返回切换任务,硬件自动恢复上次保存在栈中的8个寄存器
06.Cortex-M3 的双堆栈机制
- 裸机程序,在所有操作中只使用MSP,MSP是默认使用的堆栈指针,可以工作在线程模式,而handler模式一定是使用MSP。
- 对于具有RTOS的系统,异常处理(包括部分RTOS内核)使用MSP ,而应用任务则使用PSP。每个应用任务都有自己的栈空间。RTOS中的上下文切换代码在每次上下文切换时都会更新PSP(指向下一个任务的栈)。