3.5.2.2 cortex_m_set_vector函数详解
2026/4/29大约 4 分钟启动流程初始化PRE_KERNEL_1向量表中断
3.5.2.2 cortex_m_set_vector函数详解
📚 本节导读
学习时长: 约 20 分钟
难度级别: ⭐⭐☆☆☆(中级)
前置知识:
- 3.5.2.1 pre_kernel_1_start函数详解
- Cortex-M处理器架构基础知识
🎯 学习目标
- 理解向量表的作用和重要性
- 掌握 VTOR 寄存器的配置方法
- 理解 RAM 中保存向量表信息的设计
- 了解中断栈的配置
一、函数概述
1.1 函数定位
cortex_m_set_vector 负责设置 Cortex-M 处理器的向量表,这是中断系统的核心。
1.2 基本信息
| 属性 | 值 |
|---|---|
| 函数名 | cortex_m_set_vector |
| 源文件 | drivers/boot/cotex-m/vector_table.c |
| 初始化级别 | OS_INIT_LEVEL_PRE_KERNEL_1 |
| 子级别 | OS_INIT_SUBLEVEL_HIGH |
| 地址(来自 project.map) | 0x080227a0 |
1.3 为什么放在 HIGH 子级别?
向量表是中断响应的基础,必须在任何中断可能发生之前配置好,因此放在 HIGH 子级别。
二、函数详解
2.1 完整代码
来源: drivers/boot/cotex-m/vector_table.c (第 90-111 行)
static os_err_t cortex_m_set_vector(void)
{
#if defined(BSP_INCLUDE_VECTOR_TABLE) && !defined(ARCH_ARM_CORTEX_M0)
SCB->VTOR = (uint32_t)vector_table;
#endif
*(volatile uint32_t *)RESERVED_RAM_VECTOR_ADDR = (uint32_t)&CORTEX_M_VECTORS_BASE;
*(volatile uint32_t *)RESERVED_RAM_VECTOR_HOOK = (uint32_t)&cortex_m_irq_hook;
interrupt_stack_addr = &CORTEX_M_STACK_END;
interrupt_stack_size = CORTEX_M_STACK_SIZE;
#ifndef BSP_USING_COMMON_INT
SCB->VTOR = *(volatile uint32_t *)RESERVED_RAM_VECTOR_ADDR;
#endif
return OS_SUCCESS;
}
OS_INIT_CALL(cortex_m_set_vector, OS_INIT_LEVEL_PRE_KERNEL_1, OS_INIT_SUBLEVEL_HIGH);2.2 分步详解
第一步:设置向量表偏移寄存器(VTOR)
#if defined(BSP_INCLUDE_VECTOR_TABLE) && !defined(ARCH_ARM_CORTEX_M0)
SCB->VTOR = (uint32_t)vector_table;
#endif详细解释:
- 寄存器:
SCB->VTOR(Vector Table Offset Register) - 作用:告诉 CPU 从哪里读取中断向量
- 条件:
BSP_INCLUDE_VECTOR_TABLE定义了:说明项目包含向量表!defined(ARCH_ARM_CORTEX_M0):Cortex-M0 不支持 VTOR 寄存器
STM32F103ZET6 实际配置
BSP_INCLUDE_VECTOR_TABLE:已定义(在 projects/stm32f103zet6-atk-elite/oneos_config.h 第 172 行)ARCH_ARM_CORTEX_M0:未定义(在 projects/stm32f103zet6-atk-elite/oneos_config.h 第 8 行定义的是 ARCH_ARM_CORTEX_M3)
结论:条件满足,这一步会执行。
详细说明
关于 vector_table 的完整定义和详解,请参考:vector_table符号详解
第二步:在 RAM 中保存向量表信息
*(volatile uint32_t *)RESERVED_RAM_VECTOR_ADDR = (uint32_t)&CORTEX_M_VECTORS_BASE;
*(volatile uint32_t *)RESERVED_RAM_VECTOR_HOOK = (uint32_t)&cortex_m_irq_hook;详细解释:
| 代码行 | 作用 |
|---|---|
| 第一行 | 在 RAM 保留位置存储向量表基址 |
| 第二行 | 在 RAM 保留位置存储中断钩子函数地址 |
符号来源说明:
| 符号 | 来源 | 说明 |
|---|---|---|
CORTEX_M_VECTORS_BASE | vector_table.c | 向量表基址,映射到链接器导出的符号 |
RESERVED_RAM_VECTOR_ADDR | vector_table.c | 保留 RAM 中的向量表地址位置 |
RESERVED_RAM_VECTOR_HOOK | vector_table.c | 保留 RAM 中的中断钩子函数地址位置 |
为什么要存在 RAM 中?
- ✅ 便于运行时动态修改向量表
- ✅ 支持动态中断管理
- ✅ 提供灵活性,如引导加载程序切换向量表
详细说明
关于 CORTEX_M_VECTORS_BASE、RESERVED_RAM_VECTOR_ADDR、RESERVED_RAM_VECTOR_HOOK 的完整解析,请参考:vector_table符号详解
关于 cortex_m_irq_hook 的完整解析,请参考:cortex_m_irq_hook函数详解
第三步:保存中断栈信息
interrupt_stack_addr = &CORTEX_M_STACK_END;
interrupt_stack_size = CORTEX_M_STACK_SIZE;详细解释:
- interrupt_stack_addr:中断栈的结束地址(栈顶)
- interrupt_stack_size:中断栈的大小
符号来源说明:
| 符号 | 来源 | 说明 |
|---|---|---|
CORTEX_M_STACK_END | vector_table.c | 中断栈的结束地址,映射到链接器导出的符号 |
CORTEX_M_STACK_SIZE | vector_table.c | 中断栈的大小,由链接器计算得出 |
interrupt_stack_addr | driver.c | 中断栈地址变量 |
interrupt_stack_size | driver.c | 中断栈大小变量 |
中断栈的作用:
当发生中断时,CPU 会自动将寄存器压入中断栈。
详细说明
关于这些符号的完整解析,请参考:vector_table符号详解
第四步:根据配置决定最终的 VTOR 设置
#ifndef BSP_USING_COMMON_INT
SCB->VTOR = *(volatile uint32_t *)RESERVED_RAM_VECTOR_ADDR;
#endif详细解释:
- 条件:
!defined(BSP_USING_COMMON_INT)(不使用通用中断处理) - 操作:从 RAM 中读取向量表地址并设置 VTOR
- 意义:支持动态切换向量表
两种配置的区别:
| 配置 | 行为 |
|---|---|
BSP_USING_COMMON_INT 已定义 | VTOR 使用第一步设置的值 |
BSP_USING_COMMON_INT 未定义 | VTOR 使用 RAM 中保存的值 |
STM32F103ZET6 实际配置
BSP_USING_COMMON_INT:已定义(在 projects/stm32f103zet6-atk-elite/oneos_config.h 第 174 行)- 条件
#ifndef BSP_USING_COMMON_INT:不满足
结论:这一步的代码不会执行。VTOR 保持第一步设置的值。
三、在启动流程中的位置
3.1 执行顺序
pre_kernel_1_start()
↓
cortex_m_set_vector() ← 这里
↓
os_hw_board_init()3.2 为什么必须先执行?
后续的 os_hw_board_init() 可能会触发中断,因此必须先配置好向量表。
💡 本节总结
重点回顾
四个主要步骤:
- 设置 VTOR 寄存器
- 在 RAM 中保存向量表信息
- 保存中断栈信息
- 根据配置决定最终 VTOR
为什么放在 HIGH 子级别:向量表是中断响应的基础
关键寄存器:
SCB->VTOR
📚 扩展阅读
- vector_table符号详解 - 深入了解向量表结构
- cortex_m_vector_entry函数详解 - 了解中断分发函数
- cortex_m_irq_hook函数详解 - 理解钩子机制
下一步
接下来请学习:
- 3.5.2.3 os_hw_board_init函数详解 - 了解板级硬件初始化