【发布时间】:2023-02-11 20:30:54
【问题描述】:
我正在尝试创建一个引导加载程序,它跳转到我在 MKE02Z32VFM4(Freescale 的 KEO2 系列)上的应用程序代码。我正在使用 Keil IDE 5 和 Armv6 编译器 v6.16。
在向应用程序起始地址发出跳转指令后,代码跳转到“a”复位处理程序。并且当到达跳转到__main的指令时,它会跳转到bootloader的main。闪存由链接器文件定义如下:
#define m_interrupts_start 0x00000000
#define m_interrupts_size 0x00000200
#define m_flash_config_start 0x00000400
#define m_flash_config_size 0x00000010
#define bootloader_start 0x00000410
#define bootloader_size 0x00000800 //2kb size 0x410+0x800=0xC10 ==> 256 byte aligned => 0xE00
#define ota_part_0_start 0x00000E00 //Vector Table interrupt must be 256 byte aligned
#define ota_part_0_size 0x00003800 //14KB (14336 Byte) 0xE00+0x3800 => 0x4600
#define ota_part_1_start 0x00004600
#define ota_part_1_size 0x00003800 //14KB (14336 Byte) 0x4600+0x3800 = 0x7E00 || flash_end == 0x0000 7FFF => 0x100(256) byte frei
#define m_data_start 0x1FFFFC00 //ram start
#define m_data_size 0x00001000 //4kb
应用程序链接器文件(分散文件)使用这些定义:
#define m_interrupts_start 0x00000E00 //Address of the application reset handler
#define m_interrupts_size 0x00000200
#define m_flash_config_start 0x00001000 //some config bytes, defined by manufacturer
#define m_flash_config_size 0x00000010
#define m_text_start 0x00001010 // start address of application code
#define m_text_size 0x000035F0
#define m_data_start 0x1FFFFC00 //ram start
#define m_data_size 0x00001000 //4kb
重置处理程序是用汇编程序编写的,我试图注释说明:
Reset_Handler:
cpsid i /* Mask interrupts */
.equ VTOR, 0xE000ED08 //.equ is like #define in C. VTOR = predefined ARMv6 label. 0xE000ED08 VectorTableOffsetRegister.
ldr r0, =VTOR // load word from memory. load value from word at VTOR address to r0. R0 now contains the offset for the vector table.
ldr r1, =__Vectors // load word from memory. load value of word at __Vectors address to r1. --> the first word at __Vectors is the initial stack pointer
str r1, [r0] //store Register to memory. content of r1 is stored to memory adress in r0(==VTOR) --> initial stack pointer is stored to the first word of the Vector table
ldr r2, [r1] //load word from memory. r2 is set to the value of the word in memory at address in r1. --> r2 is set to the address of the initial stack pointer
msr msp, r2 //move to special register. move value of r2 to special register msp (main stack pointer) --> main stack pointer is set to the valjue of the initial stack pointer
ldr r0,=SystemInit //set register 0 to address of SystemInit function. (
blx r0 // branch with link ( to address of r0)
cpsie i /* Unmask interrupts */
ldr r0,=__main
bx r0
.pool
.size Reset_Handler, . - Reset_Handler
bootloader代码如下: 第一个测试中的地址是值 0x00000E00(用户应用程序的开始)
__attribute__( ( naked, noreturn ) ) void BootJumpASM( uint32_t SP, uint32_t RH )
{
__asm("MSR MSP,r0");
__asm("BX r1");
}
static void BootJump( uint32_t *Address )
{
if( CONTROL_nPRIV_Msk & __get_CONTROL( ) ) //THIS is from the arm doku, but it is always false in our implementation and skipped.
{ /* not in privileged mode */
EnablePrivilegedMode( ) ;
}
NVIC->ICER[0] = 0xFFFFFFFF ;
NVIC->ICPR[0] = 0xFFFFFFFF ;
SysTick->CTRL = 0 ;
SCB->ICSR |= SCB_ICSR_PENDSTCLR_Msk ;
if( CONTROL_SPSEL_Msk & __get_CONTROL( ) ) //THIS is from the arm doku, but it is always false in our implementation and skipped. (only 1 stack pointer used)
{ /* MSP is not active */
__set_MSP( __get_PSP( ) ) ;
__set_CONTROL( __get_CONTROL( ) & ~CONTROL_SPSEL_Msk ) ;
}
SCB->VTOR = ( uint32_t )Address ; //Setting the Vector Table Offset Register to the start of the user app.
BootJumpASM( Address[ 0 ], Address[ 1 ] ) ; //This function is taken from the Arm Documentation
}
后
SCB->VTOR = (uint32_t)Address; // Set VTOR to 0xE00
VTOR 寄存器更新为 0xE00。但是执行函数后:
__attribute__( ( naked, noreturn ) ) void BootJumpASM( uint32_t SP, uint32_t RH )
{
__asm("MSR MSP,r0");
__asm("BX r1"); //<-- This is the Point where VTOR changes it value to 0x00 again
}
VTOR 再次为 0x00,我在重新处理程序中。这个 resethandler 连接到 bootloader main。所以我假设我在 0x00 处的重置处理程序中,而不是 0xE00 处的重置处理程序中。我检查了闪存,确定向量表位于 0x000 和 0xE00。我确信应用程序的固件也在闪存中的正确位置。
我假设我要么:
定义的内存空间错误。
BootJumpASM 函数跳转到非法位置,MCU 在 0x00 重新启动并重置 VTOR 寄存器。
我不确定为什么 BootJumpASM 函数使用 r0 和 r1 以及它如何处理函数的参数。我只是汇编程序和所有特定编译器属性的新手。上面描述的函数直接复制自:
https://developer.arm.com/documentation/ka002218/latest
虽然我不明白编译器如何设法将函数参数放入寄存器 r0 和 r1,但我确信错误出在我这边,而不是在官方的 arm 文档中。
有人能给我解释一下,为什么在“BootJumpASM”函数的第二条指令后“VTOR”被重置为 0x00? 以及为什么 resethandler,调试器紧随其后,连接到引导加载程序主而不是应用程序主。我如何设法跳转到内存中的正确位置。
谢谢你的时间。我希望这个解释不会太混乱。
【问题讨论】:
-
我不知道这是否与问题有关,但您的某些闪存区域大小似乎很奇怪。你的第一个链接描述文件有
ota_part_0_start从0xE00到0xE00+0x3800。但是您的应用程序链接描述文件从0xE00映射到0x1010+0x3800。另外,在第一个脚本中,m_flash_config_start的偏移量是0x400,在第二个脚本中是0x200。也许这是故意的,但对于不完全了解您的设置的人来说看起来很奇怪。 -
你可以读回 vtor 并看到它不为零吗?
-
我假设您的矢量和其他馈送到 bx 的地址设置了 msbit?
-
BootJumpASM 参数在跳转至 BootJumpASM 之前加载到 r0 和 r1。当你进入 BootJumpASM 时,r0 和 r1 的值是多少?
-
抱歉 lsbit 设置
标签: microcontroller bootloader cortex-m keil