sunnuntai 12. huhtikuuta 2015

C startup code

In post about const/non-const data I mentioned that non-const data must be initialized on system startup. So when and where does this happen exactly?

The exact startup process of course varies from MCU to MCU and from compiler to another, but since I've been working with STM32F4 I'll use it's code as example. I'm not exactly sure what example code I got but they're mostly similar so it doesn't really matter that much, this should apply to most examples floating around the net.

To start from very beginning, when electrons start flowing on your board... No, scratch that, let's start from slightly level.

When processor is powered on, it is typically held in reset until things get stable enough to start actual startup process. In case of STM32F4 there is additional logic on board that immediately following power-on samples BOOT0 and BOOT1 pins and selects proper boot code from there; internal ROM, RAM or Flash. I'll skip ROM and RAM options here and assume that Flash is used as boot device, so MCU starts executing code at specific address that is often called reset vector. Different processors have different address, but usually it's either very first or very last instruction in memory space.

Now, C has no concept of such address, so where does that come in? If you take a look at source package (and makefile), you'll most likely find file named startup_stm32f4xx.s. In beginning of it you will find reference to Reset_Handler:

  .section  .text.Reset_Handler
  .weak  Reset_Handler
  .type  Reset_Handler, %function
Reset_Handler:  

/* Copy the data segment initializers from flash to SRAM */
  movs  r1, #0
  b  LoopCopyDataInit

CopyDataInit:
  ldr  r3, =_sidata
  ldr  r3, [r3, r1]
  str  r3, [r0, r1]
  adds  r1, r1, #4
    
LoopCopyDataInit:
  ldr  r0, =_sdata
  ldr  r3, =_edata
  adds  r2, r0, r1
  cmp  r2, r3
  bcc  CopyDataInit
  ldr  r2, =_sbss
  b  LoopFillZerobss
 
 /* Zero fill the bss segment. */ 
FillZerobss:
  movs  r3, #0
  str  r3, [r2], #4
    
LoopFillZerobss:
  ldr  r3, = _ebss
  cmp  r2, r3
  bcc  FillZerobss

/* Call the clock system intitialization function.*/
  bl  SystemInit   
/* Call static constructors */
  bl __libc_init_array  
/* Call the application's entry point.*/
  bl  main


There are handy commends already there telling you what is going on. All the basic stuff that needs to be done is here; first copying init data (that's your non-const data) from Flash to RAM, then clearing rest of used RAM. (and here is where my version of init code differs, I like that after short power outage I can resume where where I left off so neither init data copy nor clear sections exist; I recommend against this unless you know Damn Well what you are doing as this can result some really obscure bugs when things aren't handled properly).

After these there are three branches; to SystemInit, __libc_init_array and finally to your main (since main in case of embedded code isn't really expected to return I stop here).

SystemInit then can be found in system_stm32f4xx.c. In Discovery board examples this sets oscillators and clocks properly and initializes external memory controller. I won't go in details of those as STM32F4's clock setup is fairly complex and not really of interest unless you are designing your own board with specific criteria. For now it's sufficient to say that this is where you will find them if you are interested.

Then there is call to __libc_init_array, which... well, I haven't studied libc that much so I can't really say what it exactly does, but knowing that it does basic setup of stardard library is most of the time sufficient.

And finally  the main(). And this is the point where your code takes over.

Like I said, the low-level init process is specific for each MCU and board is different, but the basic structure remains. This same applies even to Arduino, although there the lower level complexity is hidden even more carefully by hiding the main() from sketches. For most simple applications these details are unnecessary, but it's always handy to know about them (or at least know of them) anyway.




Ei kommentteja:

Lähetä kommentti