2015-10-26 12:39 PM
This code snippet is from STM32 IAP example. It is common for most bootloaders.
// Check if valid stack address (RAM address) then jump to user application
if( ((*(__IO uint32_t*)MAIN_PROGRAM_START_ADDRESS) & 0x2FFE0000 ) == 0x20000000 ) I can't understand what is0x2FFE0000
. It works fine while stack is located in default RAM. But I have relocate it to core-coupled memory (CCM
). The next snippet is part of mdk-arm scatter file: RW_IRAM2 0x10000000 0x00010000 { ; Core-coupled memory (CCM). No DMA avaliable. .ANY (CCM_DATA) startup_stm32f4xx.o (STACK) ; reallocating the STACK to the CCM }How should 1st snippet be changed?
#ccm #stack #bootloader2015-10-26 01:46 PM
It's using a mask to see if the stack falls within 128KB of SRAM at 0x20000000
It's a bit of a half-assed test, and you can change it too whatever you want, and will work for YOUR design choices. Ideally it should just make sure it is 32-bit aligned and not 0xFFFFFFFF (ie erased state of FLASH) // Check if valid stack address (RAM address) then jump to user application if( ((*(__IO uint32_t*)MAIN_PROGRAM_START_ADDRESS) & 0xFFFE0000 ) == 0x10000000 ) As the value 0x10010000 is valid for 64KB of CCM RAM, as the stack is auto-decremented before use.2015-10-27 04:54 AM
I dont know any reason to put main stack into else address than end of RAM. Please explain. So my code will look like:
uint32_t stack_pointer = *(__IO uint32_t*)MAIN_PROGRAM_START_ADDRESS;
if( stack_pointer == 0x10010000 || stack_pointer == 0x20020000 )2015-10-27 08:54 AM
Pretty sure the way Keil places the stack, it's *not* a the end of the load region, but rather immediately after the statics and heap.
Look at the .MAP file. I'm not here to argue about how the tools work, or how you think or would like them to work. The purpose of the test is to sanity check that the image will start without faulting the processor immediately. Read the manuals. Understand the processor. Make your own determinations.2015-10-27 02:41 PM
Your right. So resuming
volatile uint32_t *stack_pointer = (volatile uint32_t*)MAIN_PROGRAM_START_ADDRESS;
if( *stack_pointer &0x2FFE0000 == 0x20000000
)the same as
if( 0x20000000<=*stack_pointer &&*stack_pointer
<=0x20020000 )I think second snippet is more clear to understand without additional comments, but first is faster to execute.
2015-10-27 03:08 PM
O. NO. Playing with bit-masks is not good idea. Big chance to make mistake
0x2FFE_0000 & 7000_0000 = 0x2000_0000 // will pass. NOT a RAM
0xFFFE_0000 & 1002_0000 = 0x1000_0000 // will pass. NOT a RAM
Mask
0x2FFE_0000
should be changed to0xFFFE_0000
to check 128k of memory and
0xFFFF_0000
to check 64k of CCM RAM. Code in example is WRONG. And it does not check what you say properly! I prefer more clear code for human but not so fast to execute:if( ((0x10000000 <= *stack_pointer && *stack_pointer < 0x10010000) // in CCM RAM region
|| (0x20000000 <= *stack_pointer && *stack_pointer < 0x20020000)) // in regular RAM region && *stack_pointer % 4 == 0 ) // is 32-bit word aligned I believe somebody will find it useful. UPD. Fixed code.2015-10-27 04:20 PM
0xFFFE_0000 & 1002_0000 = 0x1002_0000
I prefer to sign the image, and check that it's intact, before jumping to it.2015-10-28 04:43 AM
{
unsigned long initsp =*stack_pointer;
if ( ((initsp & 3) == 0) && // is 32-bit word aligned
(((initsp > 0x10000000) && (initsp <= 0x10010000)) || // in CCM RAM region 64KB
((initsp > 0x20000000) && (initsp <= 0x20020000))) ) // in regular RAM region 128KB
{
// Transfer Control
}
}