在应用程序编程问题
In Application Programming issue
我正在 STM32L152RCT6 项目上工作,我必须在其中构建一种机制,以从新门控文件(HEX 文件)自我更新代码。
为此,我已经实现了像引导加载程序这样的机制,它检查新固件是否存在它必须交叉验证,如果发现有效它必须存储在 "Application location" 上。
我正在执行以下步骤。
- 引导加载程序地址 = 0x08000000
- 申请地址=0x08008000
- 它必须在指定位置的某处通过引导加载程序检查新文件。
- 如果发现有效,则必须复制所有 HEX 到位(按照指南)。
- 比运行应用代码跳转到那个位置。
现在问题来自第 5 步,我已经完成的所有上述步骤甚至数据存储都已正确完成(在 STM32 实用程序中验证),但是当我跳转到应用程序代码时它不会工作.
我是否需要交叉检查或遗漏了什么?
你有没有根据新的闪光灯位置更改应用程序?
例如,矢量 Table 必须通过
正确设置
SCB->VTOR = ...
当您的引导加载程序启动应用程序时,它必须将所有内容配置回重置状态,因为应用程序可能会依赖默认重置值。尤其是您需要:
- Return 所有硬件寄存器的值到它的重置值
- 关闭所有外设时钟(不要忘记 SysTick)
- 禁用所有已启用的中断
- Return 所有时钟域为其复位值。
- 设置向量table地址
- 从APP向量的开头加载堆栈指针table。
- 调用APP入口点。(vertor table start + 4)
您的应用必须使用 FLASH 起始点为 0x8008000 的自定义链接描述文件进行编译和链接
例如:
FLASH (rx) : ORIGIN = 0x8000000 + 32K, LENGTH = 512K - 32K
与其他在复位时直接跳转到地址 0 的 ARM 控制器不同,Cortex-M 系列从向量中获取起始地址 table。如果直接加载程序(没有引导加载程序),向量 table 位于二进制文件的开头(加载或映射到地址 0)。偏移量 0 处的第一个条目是堆栈指针的初始值,地址 4 处的第二个条目称为重置向量,它包含要执行的第一条指令的地址。
使用引导加载程序加载的程序通常 会保留这种排列方式,并将矢量table 放在二进制文件的开头,在您的例子中是0x08008000
。那么重置向量将位于 0x08008004
。但这是你的应用程序,你应该检查你把你的矢量放在哪里 table。提示:看看链接器生成的.map
文件就可以确定了。如果它确实在 0x08008000
,那么您可以将控制转移到应用程序重置向量,因此:
void (*app)(void); // declare a pointer to a function
app = *(void (**)(void))0x08008004; // see below
app(); // invoke the function through the pointer
第二行中的复杂转换将物理地址转换为 pointer to a pointer to a function,获取指向它的值(现在是指向函数的指针),并将其分配给 app
。
那么您应该管理到应用向量 table 的切换。您可以在引导加载程序或应用程序中执行此操作,或者在它们之间划分步骤。
- 禁用所有中断并停止 SysTick。注意SysTick is not an interrupt,不要在上面调用
NVIC_DisableIRQ()
。我会在引导加载程序中执行此步骤,因此它负责禁用它已启用的任何内容。
- 将新向量 table 地址分配给
SCB->VTOR
。请注意 system_stm32l1xx.c
中的样板 SystemInit()
函数无条件地将 SCB->VTOR
更改回 flash 的开头,即 0x08000000
,您应该对其进行编辑以使用正确的偏移量。
您也可以从向量 table 中加载堆栈指针值,但要正确地执行此操作很棘手,而且也不是必须的,应用程序可以继续使用在引导程序。只是检查它以确保它是合理的。
SCB->VTOR = FLASH_BASE | VECT_TAB_OFFSET;
其中FLASH_BASE的值必须等于你的IROM的值在KEIL中的地址
示例:
#define FLASH_BASE 0x08004000
Keil configuration
我正在 STM32L152RCT6 项目上工作,我必须在其中构建一种机制,以从新门控文件(HEX 文件)自我更新代码。 为此,我已经实现了像引导加载程序这样的机制,它检查新固件是否存在它必须交叉验证,如果发现有效它必须存储在 "Application location" 上。
我正在执行以下步骤。
- 引导加载程序地址 = 0x08000000
- 申请地址=0x08008000
- 它必须在指定位置的某处通过引导加载程序检查新文件。
- 如果发现有效,则必须复制所有 HEX 到位(按照指南)。
- 比运行应用代码跳转到那个位置。
现在问题来自第 5 步,我已经完成的所有上述步骤甚至数据存储都已正确完成(在 STM32 实用程序中验证),但是当我跳转到应用程序代码时它不会工作.
我是否需要交叉检查或遗漏了什么?
你有没有根据新的闪光灯位置更改应用程序?
例如,矢量 Table 必须通过
正确设置SCB->VTOR = ...
当您的引导加载程序启动应用程序时,它必须将所有内容配置回重置状态,因为应用程序可能会依赖默认重置值。尤其是您需要:
- Return 所有硬件寄存器的值到它的重置值
- 关闭所有外设时钟(不要忘记 SysTick)
- 禁用所有已启用的中断
- Return 所有时钟域为其复位值。
- 设置向量table地址
- 从APP向量的开头加载堆栈指针table。
- 调用APP入口点。(vertor table start + 4)
您的应用必须使用 FLASH 起始点为 0x8008000 的自定义链接描述文件进行编译和链接
例如:
FLASH (rx) : ORIGIN = 0x8000000 + 32K, LENGTH = 512K - 32K
与其他在复位时直接跳转到地址 0 的 ARM 控制器不同,Cortex-M 系列从向量中获取起始地址 table。如果直接加载程序(没有引导加载程序),向量 table 位于二进制文件的开头(加载或映射到地址 0)。偏移量 0 处的第一个条目是堆栈指针的初始值,地址 4 处的第二个条目称为重置向量,它包含要执行的第一条指令的地址。
使用引导加载程序加载的程序通常 会保留这种排列方式,并将矢量table 放在二进制文件的开头,在您的例子中是0x08008000
。那么重置向量将位于 0x08008004
。但这是你的应用程序,你应该检查你把你的矢量放在哪里 table。提示:看看链接器生成的.map
文件就可以确定了。如果它确实在 0x08008000
,那么您可以将控制转移到应用程序重置向量,因此:
void (*app)(void); // declare a pointer to a function
app = *(void (**)(void))0x08008004; // see below
app(); // invoke the function through the pointer
第二行中的复杂转换将物理地址转换为 pointer to a pointer to a function,获取指向它的值(现在是指向函数的指针),并将其分配给 app
。
那么您应该管理到应用向量 table 的切换。您可以在引导加载程序或应用程序中执行此操作,或者在它们之间划分步骤。
- 禁用所有中断并停止 SysTick。注意SysTick is not an interrupt,不要在上面调用
NVIC_DisableIRQ()
。我会在引导加载程序中执行此步骤,因此它负责禁用它已启用的任何内容。 - 将新向量 table 地址分配给
SCB->VTOR
。请注意system_stm32l1xx.c
中的样板SystemInit()
函数无条件地将SCB->VTOR
更改回 flash 的开头,即0x08000000
,您应该对其进行编辑以使用正确的偏移量。
您也可以从向量 table 中加载堆栈指针值,但要正确地执行此操作很棘手,而且也不是必须的,应用程序可以继续使用在引导程序。只是检查它以确保它是合理的。
SCB->VTOR = FLASH_BASE | VECT_TAB_OFFSET;
其中FLASH_BASE的值必须等于你的IROM的值在KEIL中的地址
示例:
#define FLASH_BASE 0x08004000
Keil configuration