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-29 02:00 PM
Ah never mind, for some reason I was looking at the MSP. Looking at the MSP+4, I can see the handler addresses.
2014-04-30 01:04 AM
Hi, may be change the name of the second load region, and care to not erase the first load region when you flash the second binary. In the
option of keil debug adapt the erase flash, only from 0x8030000 to 0x8060000.; *************************************************************
; *** Scatter-Loading Description File generated by uVision ***
; *************************************************************
LR_IROM1 0x08000000 0x00030000 { ; load region size_region
ER_IROM1 0x08000000 0x00030000 { ; load address = execution address
*.o (RESET, +First)
*(InRoot$$Sections)
.ANY (+RO)
}
RW_IRAM1 0x20000000 0x0000C000 { ; RW data
SelfErase.o (+RO)
stm32l1xx_flash_ramfunc.o (+RO)
.ANY (+RW +ZI)
}
}
; *************************************************************
; *** Scatter-Loading Description File generated by uVision ***
; *************************************************************
LR_IROM2 0x08030000 0x00030000 { ; load region size_region
ER_IROM2 0x08030000 0x00030000 { ; load address = execution address
*.o (RESET, +First)
*(InRoot$$Sections)
.ANY (+RO)
}
RW_IRAM2 0x20000000 0x0000C000 { ; RW data
SelfErase.o (+RO)
stm32l1xx_flash_ramfunc.o (+RO)
.ANY (+RW +ZI)
}
}
2014-04-30 06:13 AM
Those suggestions did not work; I'm pretty sure I have both regions properly loaded already, as I can switch between running each of them using BFB2/reset. Like Clive mentioned it seems like a privilege issue, although I don't know much about it other than that I'm always running at privileged level.
2014-04-30 06:51 AM
Your problem is more or less close to something (stupid?) I am used to do: let an application stored in flash run my target from reset, connect the debugger and load the same application (compiled to run from RAM) and *switch* to it.
To make sure the *switch* works most of the time, I added the following steps to my debugger initialization: * set PSP and MSP to a meaningful value * set PRIMASK to 1 (AFAIK it is equivalent to interrupt disable) * set CONTROL to 0 Back to your concern, the value of CONTROL can be a meaningful difference between a run from reset or from *switch*. I don't understand right now how a bad CONTROL value can lead to the reset observed, but I think it's worth to try something around. CONTROL register is accessible with an MSR instruction as MSP and PSP are. At least MSR is privileged, so stepping through your switch routine with an MSR inside will tell you clearly if you run privileged or user code. Better, before the faultly SVC, show us the values of core registers (CONTROL, MSP, PSP, xPSR).2014-04-30 07:33 AM
In fact I remember I had kind of same problem, because the software was not the same in bank1 and bank2. Try to load the bank1 into bank2 flash, then debug soft in bank1 to see if the jump is good from bank1 to bank2, because your debugger in keil have only the soft you are in train to debug.
I don't know if it work for you but you can try ;) .2014-04-30 07:51 AM
After initial reset/startup in Bank 1, inside Reset_Handler:
CONTROL = 0x00 (MSP active, privileged); BASEPRI = 0x00; PRIMASK = 0; FAULTMASK = 0; MSP = 0x2000BF58; PSP = 0x00000000; xPSR = 0x01000000 (T=1 always)After os_set_env and before SVC:CONTROL = 0x02 (PSP active, privileged); BASEPRI = 0x00; PRIMASK = 0; FAULTMASK = 0; MSP = 0x2000BF58; PSP = 0x2000BF58; xPSR = 0x41000000 (Z=1)Inside SVC_Handler:CONTROL = 0x00 (MSP active, privileged); BASEPRI = 0x00; PRIMASK = 0; FAULTMASK = 0; MSP = 0x2000BF58; PSP = 0x2000BF38; xPSR = 0x4100000B (Z=1, ISR=11)Preparing to jump to Bank 2 in Main (after Bank 1 reset), after calling __disable_irq:CONTROL = 0x00 (MSP active, privileged); BASEPRI = 0x00; PRIMASK = 1; FAULTMASK = 0; MSP = 0x2000BF40; PSP = 0x00000000; xPSR = 0x61000000 (Z=1, C=1)Preparing to jump, after calling __set_MSP:CONTROL = 0x00 (MSP active, privileged); BASEPRI = 0x00; PRIMASK = 1; FAULTMASK = 0; MSP = 0x2000BF58; PSP = 0x00000000; xPSR = 0x61000000 (Z=1, C=1)Preparing to jump, after calling NVIC_SetVectorTable:CONTROL = 0x00 (MSP active, privileged); BASEPRI = 0x00; PRIMASK = 1; FAULTMASK = 0; MSP = 0x2000BF58; PSP = 0x00000000; xPSR = 0xA1000000 (N=1, C=1)After jump to Bank 2, after SystemInit:CONTROL = 0x00 (MSP active, privileged); BASEPRI = 0x00; PRIMASK = 1; FAULTMASK = 0; MSP = 0x2000BF58; PSP = 0x00000000; xPSR = 0x61000000 (Z=1, C=1)After jump to Bank 2, after os_set_env and before SVC:CONTROL = 0x02 (PSP active, privileged); BASEPRI = 0x00; PRIMASK = 1; FAULTMASK = 0; MSP = 0x2000BF58; PSP = 0x2000BF58; xPSR = 0x81000000 (N=1)After SVC, inside HardFault_Handler:CONTROL = 0x00 (MSP active, privileged); BASEPRI = 0x00; PRIMASK = 1; FAULTMASK = 0; MSP = 0x2000BF58; PSP = 0x2000BF38; xPSR = 0x41000003 (Z=1, ISR=3)2014-04-30 07:55 AM
My code is not PIC unfortunately, so each bank has its own target with hard-coded addresses.
According to my collected results above, the thing that stands out is PRIMASK=1... could this be the problem, and if so how/where would I fix it? (via __enable_irq?)2014-04-30 08:31 AM
May be this scatterfile:
; *************************************************************
; *** Scatter-Loading Description File generated by uVision ***
; *************************************************************
LR_IROM1 0x08000000 0x00060000 { ; load region size_region
ER_IROM1 0x08000000 0x00030000 { ; load address = execution address
*.o (RESET, +First)
*(InRoot$$Sections)
.ANY (+RO)
}
RW_IRAM1 0x20000000 0x0000C000 { ; RW data
SelfErase.o (+RO)
stm32l1xx_flash_ramfunc.o (+RO)
.ANY (+RW +ZI)
}
}
; *************************************************************
; *** Scatter-Loading Description File generated by uVision ***
; *************************************************************
LR_IROM1 0x08000000 0x00060000 { ; load region size_region
ER_IROM1 +0x30000FIXED 0x00030000 { ; load address = execution address
*.o (RESET, +First)
*(InRoot$$Sections)
.ANY (+RO)
}
RW_IRAM1 0x20000000 0x0000C000 { ; RW data
SelfErase.o (+RO)
stm32l1xx_flash_ramfunc.o (+RO)
.ANY (+RW +ZI)
}
}
2014-04-30 08:33 AM
This is very interresting ... before the SVC the CPU has almost the same configuration except PRIMASK (IMHO it is hurtless).
SVC can go wrong if VTOR is bad, or if the vector @0x803002C (SVC vector, isn't it?) is bad, or if MSP is bad, or for any other reason I do not see right now. Show us VTOR and 0x800002c/0x803002c before both SVC, and dump CFSR (0xE000ED28) as soon as you entered the HardFault handler (give PC as well, it will help to disambiguate between both banks).2014-04-30 10:13 AM
After initial reset/startup in Bank 1, inside Reset_Handler:
SVCall (0x0800002C) = 0x08000355 (SVC_Handler); VTOR = 0; PC = 0x080006C4After os_set_env and before SVC:SVCall (0x0800002C) = 0x08000355 (SVC_Handler); VTOR = 0x08000000; PC = 0x08000678Inside SVC_Handler:SVCall (0x0800002C) = 0x08000355 (SVC_Handler); VTOR = 0x08000000; PC = 0x08000354Preparing to jump to Bank 2 in Main (after Bank 1 reset), after calling __disable_irq:SVCall (0x0800002C) = 0x08000355 (SVC_Handler); VTOR = 0x08000000; PC = 0x0800062EPreparing to jump, after calling __set_MSP:SVCall (0x0800002C) = 0x08000355 (SVC_Handler); VTOR = 0x08000000; PC = 0x08000638Preparing to jump, after calling NVIC_SetVectorTable:SVCall (0x0800002C) = 0x08000355 (SVC_Handler); VTOR = 0x08030000; PC = 0x08000644After jump to Bank 2, after SystemInit:SVCall (0x0803002C) = 0x08030355 (SVC_Handler); VTOR = 0x08030000; PC = 0x080306CAAfter jump to Bank 2, after os_set_env and before SVC:SVCall (0x0803002C) = 0x08030355 (SVC_Handler); VTOR = 0x08030000; PC = 0x08030686After SVC, inside HardFault_Handler:SVCall (0x0803002C) = 0x08030355 (SVC_Handler); VTOR = 0x08030000PC = 0; LR = 0x2000BCC8CFSR = 0; HFSR = 0x40000000; DFSR = 0x00000003; MMFAR = BFAR = 0xE000EDF8; AFSR = 0