2014-04-23 10:53 AM
My goal is to jump from bank 1 to bank 2 at the start of main. I'm trying to follow the example in this forum post:
/public/STe2ecommunities/mcu/Lists/cortex_mx_stm32/Flat.aspx?RootFolder=https%3a//my.st.com/public/STe2ecommunities/mcu/Lists/cortex_mx_stm32/Jump%20address%20to%20choose%20one%20of%202%20binary%20in%20flash&FolderCTID=0x01200200770978C69A1141439FE559EB459D7580009C4E14902C3CDE46A77F0FFD06506F5B¤tviews=110
However, when I try to specify an address in the opposite flash bank, an address that is offset from PC seems to be loaded instead of the exact address. As you can see, the 0x08000000 address is loaded correctly but the 0x08030000 address is not. Even if I replace the C code with inline ASM, it still does this. Am I doing something wrong or using the wrong ASM instruction? How do I go about accomplishing this? Here is my relevant C code in main:
/* Jump to opposite bank without modifying BFB2 bit */
if
(currFwBank == 1)
{
U32 jumpAddr = *(U32*)(FLASH_BANK_2_START_ADDR+4);
JumpFunc_t jumpToOtherBank = (JumpFunc_t)jumpAddr;
//__ASM volatile ('''');
__disable_irq();
__set_MSP(*(U32*)FLASH_BANK_2_START_ADDR);
jumpToOtherBank();
}
else
{
U32 jumpAddr = *(U32*)(FLASH_BANK_1_START_ADDR+4);
JumpFunc_t jumpToOtherBank = (JumpFunc_t)jumpAddr;
__disable_irq();
__set_MSP(*(U32*)FLASH_BANK_1_START_ADDR);
jumpToOtherBank();
}
Here are my mixed C/assembly instructions from the Keil debugger:
203: if (currFwBank == 1)
204: {
0x0800061E F89D0000 LDRB r0,[sp,#0x00]
0x08000622 2801 CMP r0,#0x01
0x08000624 D10A BNE 0x0800063C
205: U32 jumpAddr = *(U32*)(FLASH_BANK_2_START_ADDR+4);
0x08000626 481F LDR r0,[pc,#124] ; @0x080006A4
0x08000628 6844 LDR r4,[r0,#0x04]
206: JumpFunc_t jumpToOtherBank = (JumpFunc_t)jumpAddr;
207: //__ASM volatile ('''');
0x0800062A 4625 MOV r5,r4
208: __disable_irq();
0x0800062C B672 CPSID I
209: __set_MSP(*(U32*)FLASH_BANK_2_START_ADDR);
0x0800062E 491D LDR r1,[pc,#116] ; @0x080006A4
0x08000630 6808 LDR r0,[r1,#0x00]
171: __regMainStackPointer = topOfMainStack;
0x08000632 F3808808 MSR MSP,r0
172: }
0x08000636 BF00 NOP
210: jumpToOtherBank();
0x08000638 47A8 BLX r5
211: }
212: else
213: {
0x0800063A E00C B 0x08000656
214: U32 jumpAddr = *(U32*)(FLASH_BANK_1_START_ADDR+4);
0x0800063C F04F6000 MOV r0,#0x8000000
0x08000640 6844 LDR r4,[r0,#0x04]
215: JumpFunc_t jumpToOtherBank = (JumpFunc_t)jumpAddr;
0x08000642 4625 MOV r5,r4
216: __disable_irq();
0x08000644 B672 CPSID I
217: __set_MSP(*(U32*)FLASH_BANK_1_START_ADDR);
0x08000646 F04F6100 MOV r1,#0x8000000
0x0800064A 6808 LDR r0,[r1,#0x00]
0x0800064C F3808808 MSR MSP,r0
0x08000650 BF00 NOP
218: jumpToOtherBank();
0x08000652 47A8 BLX r5
219: }
#jump-address-stm32l1-flash-bank
2014-04-30 10:22 AM
Also, when I remove the line to set VTOR before jumping to Bank 2, I get the same results (not including VTOR obviously)...
After SVC, inside HardFault_Handler:SVCall (0x0803002C) = 0x08030355 (SVC_Handler); VTOR = 0x08000000PC = 0; LR = 0x2000BCC8CFSR = 0; HFSR = 0x40000000; DFSR = 0x00000003; MMFAR = BFAR = 0xE000EDF8; AFSR = 02014-04-30 10:44 AM
OK, I was wrong saying that PRIMASK set to one is harmless. Indeed, it is exactly what makes SVCall to enter HardFault according to ARM architecture manual.
It does not happen on my platform because the first task is launched with ''cpsie i'' right before SVC. Of course PRIMASK is very convenient to avoid any interruptions during the *switched reboot*. You have to do it differently, probably by disabling every NVIC source. Anyway that does not explain the reboot. That does not explain why PC=0 right after the SVC/HardFault. Normally the HardFault can be catch very early by setting a breakpoint at the first instruction of the handler. The handler address(+1) is declared at 0x800000c/0x803000c, so you can set that breakpoint. Another reason for rebooting is the use of the debugger. It is *possible* (I don't know your debugging system) that the debugger is configured in a way that it resets the processor when a lockup is detected (e.g. re-entering HardFault handler infinitely).2014-04-30 11:01 AM
After SVC, inside HardFault_Handler:
SVCall (0x0803002C) = 0x08030355 (SVC_Handler);VTOR = 0x08030000
PC = 0; LR = 0x2000BCC8 CFSR = 0; HFSR = 0x40000000; DFSR = 0x00000003; MMFAR = BFAR = 0xE000EDF8; AFSR = 0
Well PC and LR appear totally bogus, what does your Hard Fault handler look like? Here we decode the registers, and stacked context, emitting it out USART1.
2014-04-30 11:36 AM
Thanks Laurent, it works perfectly now! I just had to replace __disable_irq with
NVIC_DisableIRQ();__DSB();__ISB();as recommended byhttp://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.dai0321a/BIHHFHJD.html
Hopefully this post will help others if they get stuck on the same issue; I realize now that Tom Rfid removed his __disable_irq in his answer, but I thought it wasn't related since it wasn't explained.I'm not sure why the PC and LR were screwed up, but I was using the Joseph Yiu hard fault handler you pointed to Clive.2014-05-21 03:15 AM
Nice!
I have remove the __disable_irq because my jump is done before to set the vector table and initialize it, so I had no need.