STM32F20x custom bootloader
Hi Everyone!
I am writing a custom bootloader for STM32F207ZGT6. I divided the 1 Mb flash into 2 sections. The first one is 128 kbytes, my bootloader is loaded to this section. The second one is 896 kbytes, my main application is loaded here. I use the following code to the jump:
typedef void (*pFunction)(void); pFunction Jump_To_Application; uint32_t JumpAddress; . . . JumpAddress = 0x08020000 + 4; Jump_To_Application = (pFunction) JumpAddress; __set_MSP(0x20000000); Jump_To_Application();
I pasted the "+ 4" to the code because of endianness, but I may be wrong. My main application starts from 0x08020000. I set this in uVision. I ran to the following problem: When the Jump_To_Application() function is called, a HardFault is generated and its handler is called.
Anyone has a tip?
I am all ears.
Sorry for my very limited technical ability and English ability.
#include <stdint.h> #define FW_START 0x80000000 static const uint16_t launch_fw_code[] = { 0xF850, 0xDB04, /* LDR.W SP, [R0], #4 */ 0x6800, /* LDR.W R0, [R0] */ 0x4700, /* BX R0 */ }; int main(void) { ((void (*)(uint32_t))(1+ (int)launch_fw_code))(FW_START); // type_A ((void (*)(uint32_t))(1+(unsigned int)launch_fw_code))(FW_START); // type_B ((void (*)(uint32_t))(1+ launch_fw_code))(FW_START); // type_C return 0; }
Why the (int) is needed? What is the difference between type_A, type_B, and type_C?
launch_fw_code is an uint16_t array, so it is also a constant address. I guess it must be an even address, and the 1 is to make it odd.
(int) is needed because we want to add 1 to the address. We could have used (uint8_t*) instead. If you use the address of launch_fw_code without a type cast, 2 will be added instead of 1, that is sizeof(uint16_t). There is no difference between type_A and type_B: they yield the same result.
I guess it must be an even address, and the 1 is to make it odd.
Exactly.
I completely forgot one more thing: of course, the calculated address of the entry point should be compatible with the type of the function argument. I should have used int everywhere: it's shorter and it does the job:
((void (*)(int))(1+(int)launch_fw_code))(FW_START);
It's kind of misleading to pass a pointer to code as an int. But making it a pointer to a function would not clear things up much: we still would have to do some type casting in order to add 1 to the address. It's still a mess.
Hi Mike,
Many thanks for your explanation.
(I regularly discover that, I am not a good C programmer.)
(1+launch_fw_code) == &launch_fw_code[1]