在 STM32 使用 FreeRTOS 时如何重定位向量表实现 Bootloader 跳转

目录

什么是向量表?

向量表的结构

向量表的工作原理

为什么要重定位向量表?

1.中断向量表重定位

2.Bootloader与应用程序的分离

3.FreeRTOS的中断需求

如何实现向量表重定位?

1.定义应用程序的起始地址

2.在main()中重定位向量表

3.确认启动文件和链接脚本

关键步骤解析

总结


最近搞freertos+lvgl的一个项目,当我想为这个项目移植一个bootloader功能是出现了之前没有遇到的问题---任务调度无法被正确开启。最开始我以为是某一些内存泄漏造成的,排查之后没有找到问题所在,之后经过查阅相关资料便有了这篇文章---重定位向量。

在STM32使用FreeRTOS时如何重定位向量表实现Bootloader跳转

在STM32和其他Cortex-M系列微控制器上,通常会使用Bootloader加载应用程序,以便实现固件更新或多应用启动等功能。当我们的应用程序地址不是默认的`0x08000000`时(比如从`0x08008000`开始),FreeRTOS的`vTaskStartScheduler()`有时无法正常启动,这主要是由于中断向量表的基地址问题。本文将详细解释该问题的原因以及如何解决。

什么是向量表?

向量表(Vector Table)是存储在微控制器闪存(Flash)或存储器中的一个地址表,包含了系统异常和中断的服务程序地址。在 Cortex-M 系列的微控制器(如 STM32)上,向量表通常位于 Flash 的起始地址 0x08000000 或 SRAM 起始地址。向量表的作用是告诉微控制器,当发生特定的中断或异常时,应该跳转到哪个位置去执行相应的代码。

向量表的结构

向量表的结构是一组固定顺序的地址,每个地址指向一个中断或异常的服务函数(即中断服务例程,ISR)。通常向量表的前几个地址具有固定功能:

  1. 主堆栈指针(MSP)初始值

    向量表的第一个地址(地址 0x00000000)通常存储主堆栈指针(Main Stack Pointer)的初始值,用于初始化堆栈。

  2. 复位向量(Reset Vector)

    向量表的第二个地址(地址 0x00000004)存储复位向量(即复位中断处理函数的地址),当系统上电复位或手动复位时,微控制器将跳转到这个地址开始执行。

  3. 其他异常和中断向量

    后续的地址对应系统异常(如硬件故障、系统调用等)和各种中断的入口地址。

向量表的工作原理

当系统发生异常或中断时,微控制器会根据中断号去查找对应的向量表项,获取服务函数的地址,然后跳转到这个地址执行中断服务程序(ISR)。这种方式可以快速找到对应的中断处理代码,实现高效的中断响应。

为什么要重定位向量表?

在STM32微控制器中,默认的中断向量表位于`0x08000000`(Flash 的起始地址)。当启动FreeRTOS等实时操作系统时,系统中断(如`SysTick`定时器)会调度任务,若中断向量表地址不正确,系统将无法找到中断服务例程(ISR),导致任务调度失败。即应用程序并不是从默认的起始地址运行。例如,如果 Bootloader 占据了 Flash 的前 32KB,那么应用程序的起始地址可能会被设置为 0x08008000。因此,如果应用程序的起始地址更改,必须在程序启动时将中断向量表基地址更新为新的起始地址。

在这种情况下,微控制器仍然会将中断请求指向 0x08000000 的向量表,从而导致中断无法正常处理。为了解决这个问题,我们可以通过修改 SCB->VTOR 寄存器,将向量表的基地址设置为应用程序的起始地址,使中断和异常能够正确跳转到新的服务函数地址。

重定位向量表的原因总结如下:

1.中断向量表重定位

Cortex-M系列的`SCB->VTOR`(向量表基地址寄存器)决定了中断向量表的位置。通过重定位向量表,我们确保了从非默认地址启动的应用程序依旧能够正确处理中断。

2.Bootloader与应用程序的分离

在Bootloader-应用程序结构中,Bootloader和应用程序通常存放在Flash的不同区域。例如,Bootloader在`0x08000000`到`0x08003FFF`,而应用程序在`0x08008000`开始。为了让应用程序正确运行,Bootloader跳转到应用程序地址后,必须重定位向量表。

3.FreeRTOS的中断需求

FreeRTOS依赖系统中断(例如`SysTick`)进行任务调度,若向量表未更新则会导致调度失败。

如何实现向量表重定位?

在STM32使用FreeRTOS并指定不同的起始地址时,向量表的重定位通常放在应用程序的初始化代码中,即`main()`函数开头。在启动FreeRTOS调度器之前,我们需要确保`SCB->VTOR`指向应用程序的起始地址。

具体步骤如下:

1.定义应用程序的起始地址

假设应用程序的起始地址为`0x08008000`,可以在代码中定义:

defineAPP_START_ADDRESS0x08008000

2.在main()中重定位向量表

在`main()`函数(当然也可也再boor程序中进行重新定位)中将`SCB->VTOR`设置为应用程序的起始地址:

int main(void)
{
    //重定位中断向量表基地址到应用程序的起始地址
    SCB->VTOR=APP_START_ADDRESS;
    HAL_Init();//初始化HAL库
    sys_stm32_clock_init(336,8,2,7);//配置系统时钟
    delay_init(168);//延时初始化

    //继续初始化和创建任务
    usart_init(115200);//初始化USART
    led_init();//初始化LED
    key_init();//初始化按键
    //启动FreeRTOS的任务调度器之前完成所有初始化
    vTaskStartScheduler();//启动调度器

    //不应该到达这里
    while(1);
}

3.确认启动文件和链接脚本

确保启动文件和链接脚本(例如`.ld`文件)中定义的应用程序地址与实际的`APP_START_ADDRESS`一致。例如,将应用程序起始地址在链接脚本中配置为:

FLASH(rx):ORIGIN=0x08008000,LENGTH=448K

关键步骤解析

1.早期重定位`SCB->VTOR`

向量表的基地址应尽早重定位。在初始化HAL和FreeRTOS调度器之前完成,以确保在初始化过程中任何中断都能跳转到正确的服务例程。

2.Bootloader跳转到应用程序

如果系统包含Bootloader,Bootloader在跳转至应用程序时应设置堆栈指针(MSP)和程序计数器(PC),具体代码如下:

voidJumpToApplication(uint32_tappAddress)
{
//获取应用程序的复位向量地址(首地址+4)
uint32_tjumpAddress=(volatileuint32_t)(appAddress+4);

//设置主堆栈指针
__set_MSP((volatileuint32_t)appAddress);
//设置程序计数器为应用程序的复位向量地址
void(appResetHandler)(void)=(void)jumpAddress;
appResetHandler();
}

3.确保调试输出和错误排查

在Bootloader和应用程序中添加调试输出,如`printf()`,便于跟踪执行流程和查找可能的问题。

总结

在STM32系统上运行FreeRTOS且应用程序起始地址不为`0x08000000`时,重定位向量表是至关重要的一步。通过将`SCB->VTOR`设置为应用程序的起始地址,我们可以确保在FreeRTOS或其他实时操作系统中正确处理系统中断和异常。这一方法在Bootloader系统中尤为常见,因为它允许Bootloader和应用程序共存且相互隔离,提升了系统的可靠性和灵活性。

如果出现`vTaskStartScheduler()`无法启动的问题,很可能是因为向量表未正确重定位,导致中断跳转出错。通过以上方法,可以在非默认起始地址上可靠地启动FreeRTOS应用程序。

这样就可以确保我们的应用程序无论存储在哪个位置,都能正确初始化并运行FreeRTOS提供的功能。

相关推荐
YuCaiH6 分钟前
【STM32】USART串口数据包
笔记·stm32·单片机·嵌入式硬件
Kasen's experience2 小时前
STM32 GPIO 配置
stm32·单片机·嵌入式硬件
知行电子-2 小时前
Proteus中数码管动态扫描显示不全(已解决)
单片机·proteus·嵌入式
学习路上_write3 小时前
FPGA/Verilog,Quartus环境下if-else语句和case语句RT视图对比/学习记录
单片机·嵌入式硬件·qt·学习·fpga开发·github·硬件工程
非概念3 小时前
stm32学习笔记----51单片机和stm32单片机的区别
笔记·stm32·单片机·学习·51单片机
jjjxxxhhh1235 小时前
FPGA,使用场景,相比于单片机的优势
单片机·嵌入式硬件·fpga开发
无敌最俊朗@5 小时前
stm32学习之路——八种GPIO口工作模式
c语言·stm32·单片机·学习
EterNity_TiMe_5 小时前
【论文复现】STM32设计的物联网智能鱼缸
stm32·单片机·嵌入式硬件·物联网·学习·性能优化
changingshow6 小时前
Arduino IDE Windows 系统 离线安装 esp32 开发板 亲测好用。
单片机·嵌入式硬件
7yewh8 小时前
嵌入式硬件杂谈(一)-推挽 开漏 高阻态 上拉电阻
驱动开发·stm32·嵌入式硬件·mcu·物联网·硬件架构·pcb工艺