我为我的SAM4S编写了一个引导加载程序,它位于扇区0并在扇区1中加载一个应用程序。然而问题是,当我尝试跳转到新函数时,它似乎生成一个异常(调试器转到Dummy_Handler ())。
Bootloader在地图中包含以下条目:
.application 0x00410000 0x0
0x00410000 . = ALIGN (0x4)
0x00410000 _sappl = .
0x00410004 _sjump = (. + 0x4)
应用程序图像映射文件具有:
.vectors 0x00410000 0xd0 src/ASF/sam/utils/cmsis/sam4s/source/templates/gcc/startup_sam4s.o
0x00410000 exception_table
…
.text.Reset_Handler
0x0041569c 0x100 src/ASF/sam/utils/cmsis/sam4s/source/templates/gcc/startup_sam4s.o
0x0041569c Reset_Handler
异常表定义如下:
const DeviceVectors exception_table = {
/* Configure Initial Stack Pointer, using linker-generated symbols */
.pvStack = (void*) (&_estack),
.pfnReset_Handler = (void*) Reset_Handler,
引导加载程序将应用程序跳转点声明为:
extern void (*_sjump) ();
然后拨打以下电话:
_sjump();
0x00410004处的存储器内容为0x0041569d,我注意到这不是字对齐的。这是因为我们使用Thumb指令吗?无论哪种方式,为什么它不是0x0041569c?或者更重要的是为什么会出现异常?
谢谢,
德万
更新 找到this但它似乎对我不起作用:
void (*user_code_entry)(void);
unsigned *p;
p = (uint32_t)&_sappl + 4;
user_code_entry = (void (*)(void))(*p - 1);
if(applGood && tempGood) {
SCB->VTOR = &_sappl;
PrintHex(p);
PrintHex(*p);
PrintHex(user_code_entry);
user_code_entry();
}
代码打印: 00410004 0041569D 0041569C
更新更新 尝试使用C函数指针跳转的代码生成了以下反汇编:
--- D:\Zebra\PSPT_SAM4S\PSPT_SAM4S\SAM4S_PSPT\BOOTLOADER\Debug/.././BOOTLOADER.c
user_code_entry();
004005BA ldr r3, [r7, #4]
004005BC blx r3
我能够使用以下程序集进行此操作:
"mov r1, r0 \n"
"ldr r0, [r1, #4] \n"
"ldr sp, [r1] \n"
"blx r0"
基于此,我想知道是否需要堆栈重置,如果是这样,是否可以在C中完成?
答案 0 :(得分:3)
我遇到了与SAM4E相同的问题。我猜不出你的问题是什么,但我可以指出我遇到的困难和我使用的信息。
我的bootloader没有在固件的几个部分存储在正确的内存位置。这导致了dummy_handler异常。当我在地址计算中修复错误时,引导程序工作得很好。
我的建议:
其他可能有用的想法:
您必须指向的地址是0x00410000而不是0x00410004。 Atmel的示例代码(请参阅函数binary_exec
)结合Intel Hex格式(记录类型05)应该可以解决这个问题。
我希望这条信息会有所帮助!
答案 1 :(得分:2)
我在SAM4S上遇到了同样的问题,这让我想到了这个问题。所以,如果有人再次来到这里,我就找到了。 正如ChrisB提到的那样,遵循Atmel示例代码是一个良好的开端,但我发现问题是请求跳转的实际代码对SAM4S不起作用。 缺少的是在向量表之前重新设置堆栈指针,然后加载重置处理程序地址。 尝试这样的事情:
static void ExecuteApp(void)
{
uint32_t i;
// Pointer to the Application Section
void (*application_code_entry)(void);
// -- Disable interrupts and system timer
__disable_irq();
SysTick->CTRL = 0; // Disable System timer
// disable and clear pending IRQs
for (i = 0; i < 8; i++)
{
NVIC->ICER[i] = 0xFFFFFFFF; // disable IRQ
NVIC->ICPR[i] = 0xFFFFFFFF; // clear pending IRQ
}
// Barriers
__DSB(); // data synchronization barrier
__ISB(); // instruction synchronization barrier
// Rebase the Stack Pointer
__set_MSP(*(uint32_t *) APPCODE_START_ADDR);
// Rebase the vector table base address
SCB->VTOR = ((uint32_t) APPCODE_START_ADDR & SCB_VTOR_TBLOFF_Msk);
// Load the Reset Handler address of the application
application_code_entry = (void (*)(void))(unsigned *)(*(unsigned *)
(APP_START_RESET_VEC_ADDRESS));
__DSB();
__ISB();
// -- Enable interrupts
__enable_irq();
// Jump to user Reset Handler in the application
application_code_entry();
}