What is the purpose of the if statement in the Reset_Handler (surrounding the for loop)? One points to ROM and the other to RAM, so I wouldn’t expect them to ever be equal.
@bmcdonnell this is to guard against the case where you’re running from RAM (rather than ROM) in which case those values would be the same. Some MCUs (e.g. dialog’s DA141580 BLE MCU) are set up that way.
1 replyThanks for the info. That makes sense.
Maybe add a comment to your code explaining that? Just a thought.
Thanks for nice article.
Recently I started reading this blog and its really helpful.
I mostly code in IDE so I am not familiar with commands line. Like you wrote some command to look into .elf file. I tried same. I was able to get address for function but unable to find _sbss, _ebss. Can you please help?
Also I am planing to learn commands line program for arm. Would be great if you can suggest any blog,
1 replyHi @chandan_bhatia. _sbss
, _ebss
, and others are added in the linker script. We set that up in the next episode in the series. Check this out: https://interrupt.memfault.com/blog/how-to-write-linker-scripts-for-firmware.
ooh right… 0x0020 is actually two bytes (in my head i somehow assumed it was a single byte) and so I was simply doing the first two steps of your explanation. Thanks
Thank you @francois for sharing your knowledge through this article and this series.
I have a question about the initialisation of static variables in the Reset_Handler function.
I might be being pedantic, but would it make more sense to write:
if (data_ptr != init_values_ptr ) { // I have changed this line
for (; data_ptr < &_edata;) {
*data_ptr++ = *init_values_ptr++;
}
}
instead of
if (init_values_ptr != data_ptr) {
for (; data_ptr < &_edata;) {
*data_ptr++ = *init_values_ptr++;
}
}
since, we are setting the values at the addresses of the static variables with the init values, not the other way around?
1 replyThey’re both stored at the end of .text
. What that section is called vary by linker script and by compiler. Typically only const ends up in rodata
, and initialized variables are in .data
which is both in ROM (init values) and in RAM (working memory).
@francois You referenced the Reset boot-up behavior as Section 5.9.2 of the Cortex-M3 TRM
For the Cortex-M4 TRM I cannot find anything similar. Would it be fine to just assume the same steps as in the Cortex-M3?
Yes, I noticed they removed that section for the M4 TRM. I think it’s moved to a ARM-v7m manual rather than specific core. In any case, it’s fine to use the same steps.
@francois Why is it uint32_t *init_values_ptr = &_etext;
taken at the end of the text section and not uint32_t *init_values_ptr = &_stext;
taken at the start of the text section?
From part 2:
.text :
{
KEEP(*(.vectors .vectors.*))
*(.text.*)
*(.rodata.*)
_etext = .;
} > rom
1 reply
Because initial values for data are added to flash after the .text
section, this is what the AT > rom
bit does. Since _etext
points to the end of the text section, that’s where we expect the initialization values to be found. It would be better if we had a variable explicitly pointing to the address that AT > rom
resolves to, but that’s not something you can do AFAIK.
François,
Could a Nucleo-G070RB be used for “From zero to main(): Bare metal C” in place of the Metro M0 Express and the CMSIS-DAP Adapter.
1 replyI see no reason why not. You’ll need to change the memory map of course.
Great article thanks.
I think you have a mistake in your pseudo code. For the Cortex-M0+ the IPSR size is 6 bits not 9 (M3/4/7). As a result the for loop in the pseudo code should be:
for i = 0 to 63 (not 511)
David.