1
votes

I've just started to delve into the world of ARM Cortex-M microcontrollers, and I've decided not to use an existing development board or easy-to-use IDE, but to get right into the bare metal of these things, so I've got myself an STM32F103 soldered onto a prototyping board and am now trying to get things working with the gcc-arm-embedded Toolchain from Launchpad. After a hard time of reading manuals about linker scripts and the like, I have now written my own linker script and startup code that basically does nothing but copy the .data section from ROM to RAM, zero out .bss, then call SystemInit() from ST's Standard Peripheral Library to do the basic uC initialization and finally calling main().
Now, from the few tutorials I found about Cortex M-3 development, I saw that they use the -nostartfiles flag to the linker, but now I'm wondering: Do I have to initialize newlib by myself in that case? Or should I rather use the default start files from GCC/newlib and drop -nostartfiles? But in that case, I'd still have to do some initialization, like copying .data to RAM and setting up the vector table, which requires a custom linker script. So where do I do that?
And I do not even want to start thinking about C++!

So, what is the recommended way of initializing such a Cortex-M3 based microcontroller and its libc (not counting peripheral stuff)?

Thanks in advance!

1
github.com/dwelch67 I have some bare metal stuff you might be interested in. This is not as high level as the newlib/libc stuff you are trying to do this is bare metal. Maybe it is useful to you, maybe not. I might have some newlib stuff in the raspberry pi dir, also may or may not help. Unless you have a turnkey package getting newlib+gcc working can be a challenge, if you have a turnkey package and that is what you are interested in (using newlib, and other canned libraries) then just use it, as intended by the authors.old_timer
In the newlib0 example from your repository you define mainly the syscall functions needed by newlib. If that's all I'd have to do, it wouldn't be that big of a problem. What I don't see in your code though is the initialization of the microcontroller, but that is what I'm interested in. I'm using the binary distribution of gcc-arm-embedded, so GCC and newlib are already built and (supposedly) tied together. My problem is mixing newlib's startup code (crt0.o and the like) with my own.Alemarius Nexus
that is bare metal. you do it yourself. If you want to use ST's sandbox then use their sandbox. Grab their code and use it as intended or merge it in functionally with your own...old_timer
I initialize the microcontroller as needed.old_timer
I use -nostdlib -nostartfiles -ffreestanding and dont have to worry about crt anything. All three of those may mess with what you are trying to do though with other libraries so you may only need one or two...old_timer

1 Answers

0
votes

As far as I know you shouldn't call any stdlib function for an bare C app. But you should for an C++ app, because there're static initializers, vtable for RTTI and so on to be initialized. newlib itself contains such functions from stdlib like mem*, *printf, and so on, fitted for a MCU with small ROM size, as far as I know.

But there's often nothing to be actively initialized. If an std-function does have a global data, it hopefully declares and stores it in some variables, that are stored in the .data section. E.g. __errno is a candidate for this. But you can't be sure what your newlib-implementation does, because it is up to developers to decide, how do they design the internal workflow in their lib.

Take a look at the code snippet below. This is a startup routine (Reset-Handler) written in C. ST delivers their startup file as an assembler file (*.s), but you could also do it in C. NXP on the other hand generate their projects with an .c startup file.

The function call below the comment for C++ could be omitted, if your app is only a C app. Symbols for _data and _idata are generated by linker (defined in a linker script).

__set_PSP((uint32_t)&_vStackTop);               // set stack pointer
SCB->VTOR = (uint32_t)&VectorTable;             // set the pointer to the vector table

pDest = &_data;
pSrc = &_idata;

// fill .data section
for ( ; pDest < &_edata; )
{
    *pDest = *pSrc;
    ++pSrc;
    ++pDest;
}

// fill .bss section
for (pDest = &_bss; pDest < &_ebss; ++pDest)
{
    *pDest = 0;
}

//
// Call C++ library initialization, if your app is an C++ app
//
__libc_init_array();

main();                                                 // enter main

for(;;)                                                 // you shouldn't land here at anytime
{

}