【嵌入式八股11】STM32
一、STM32 启动流程
- 启动区域选择:STM32 依据 boot 引脚的设置来确定启动区域,具体如下:
x 0 | 片内 Flash | 从代码区启动,支持 ICP 下载方式(如 SWD、JTAG 烧录),这是最常用的启动方式,代码存储在片内 Flash 中,稳定可靠。 |
0 1 | 系统存储器 | 通过内置 ROM 启动,采用 ISP 下载(出厂预置代码,常见的如使用 UART 烧录)。此方式一般用于出厂时的程序烧录或者在没有 SWD、JTAG 接口的情况下进行程序更新。 |
1 1 | SRAM | 从 RAM 启动,但数据在掉电后会丢失。这种启动方式常用于一些调试场景,方便快速测试代码,不过由于数据易失性,不适用于正式的产品运行。 |
- 运行 bootloader:当确定启动区域后,处理器开始运行 bootloader,主要包括以下几个步骤:
- 初始化寄存器:处理器会将各个寄存器的值初始化为默认值,为后续的程序运行做好准备。
- 硬件设置 SP、PC,进入复位中断函数 Rest_Hander():
- 从 0x0800 0000 读取数据赋值给栈指针 SP(MSP),并设置为栈顶指针 0x2000 0000 + RAM_Size。这一步确定了栈的起始位置,为函数调用等操作提供了空间。
- 从 0x0800 0004 读取数据赋值给 PC(指向 Reset_Handler 中断服务函数)。通过以下代码实现:
LDR R0, = SystemInit
BLX R0
- **设置系统时钟,进入 SystemInit()**:
- 设置 RCC 寄存器各位,配置系统的时钟源、分频系数等,以确保系统能够稳定运行在合适的时钟频率下。
- 设置中断向量表偏移地址,根据启动区域的不同,使用以下代码进行设置:
#ifdef VECT_TAB_SRAM
SCB->VTOR = SRAM_BASE | VECT_TAB_OFFSET; /* Vector Table Relocation in Internal SRAM. */
#else
SCB->VTOR = FLASH_BASE | VECT_TAB_OFFSET; /* Vector Table Relocation in Internal FLASH. */
#endif
- **软件设置 SP,__main 入栈(系统初始化函数)**:通过以下代码将 __main 函数入栈,进一步进行系统的初始化操作:
LDR R0,=__main
BX R0
- **加载 data、bss 段并初始化_main 栈区**:由于哈弗体系结构决定了数据与代码分开存储,所以需要将 Flash 中的数据拷贝进入 SRAM,完成数据段和 bss 段的初始化。
3. 跳转到 main():完成上述一系列初始化操作后,程序跳转到 main() 函数,开始执行用户编写的应用程序代码。
二、OTA(Over-The-Air)的情况
在 FLASH 中添加引导程序后,引导程序与 APP 程序将各自对应一个中断向量表。假设引导程序占用 N + M Byte 的 FLASH 空间。
- 上电启动流程:上电后,单片机从复位中断向量表处获取地址,并跳转执行复位中断服务函数,执行完毕后执行主函数。随后执行 Bootloader 中程序跳转的相关代码跳转至 APP,即地址 0x08000004 + N + M 处。进入主函数的步骤与 Bootloader 函数一致。
- 中断处理流程:当运行在主函数时,若有中断请求被响应,此时 PC 指针本应当指向位于地址 0x08000004 处的中断向量表,但由于程序预先通过“SCB->VTOR = 0x08000000 | ADDR_OFF;”这一语句,使得中断向量表偏移 ADDR_OFF(N + M)地址,因此 PC 指针会跳转到 0x08000004 + N + M 处所存放的中断向量表处,随后执行本应执行的中断服务函数,在跳出函数后再进入主函数运行。 以下是实现程序跳转至 APP 的示例代码:
void iapLoadApp(uint32_t appxAddr)
{
iapfun jumptoapp;
// 检查 appxaddr 处存放的数据(栈顶地址 0x2000****)是不是在 RAM 的地址范围内
if( 0x20000000 == ( (*(vu32*)appxAddr) & 0x2FFE0000) )
{
// 拷贝 APP 程序的复位中断函数地址,用户代码区第二个字为程序开始地址(复位地址)(强制跳转到函数地址处执行,函数指针的方式)
jumptoapp = (iapfun)*(vu32*)(appxAddr + 4);
// 初始化 APP 堆栈指针(用户代码区的第一个字用于存放栈顶地址),重新分配 RAM
MSR_MSP(*(vu32*)appxAddr);
// 执行 APP 的复位中断函数,跳转到 APP
jumptoapp();
}
}
三、中断相关知识
- 中断的过程:
- 中断初始化:
- 设置中断源,使某个外设具备产生中断的能力,例如配置 GPIO 引脚为外部中断模式。
- 设置中断控制器,对某个外设的中断通道进行使能或屏蔽操作,同时设置中断优先级,以确定多个中断同时发生时的处理顺序。
- 使能 CPU 中断总开关,允许 CPU 响应中断请求。
- CPU 运行与中断响应:CPU 在运行正常程序的过程中,每执行完一条指令(指令的执行包含多个时钟周期,如取指、译码、执行等)都会检查是否有异常或中断产生。当产生中断(如用户按下按键)时,中断信号先经过中断控制器,然后传递给 CPU。
- 中断处理步骤:
- 保存现场:将 PC、LR、MSP、通用寄存器、FPU 等相关寄存器的值压栈,保存当前程序的运行状态,以便中断处理完成后能够恢复继续执行。
- 分辨异常/中断,调用对应的异常/中断处理函数
- 中断初始化:
剩余60%内容,订阅专栏后可继续查看/也可单篇购买
嵌入式八股/模拟面试拷打 文章被收录于专栏
一些八股模拟拷打Point,万一有点用呢