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!
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
{
}
Related
I would like a create a software where some functions (or block) can be programmed later on my micro controller without having to flash the entire software again (flash will be done by a communication interface e.g. SPI).
The new blocks will all have the same API (e.g. 5 bytes as arguments, 1 byte returned).
Memory architecture will be organized as shown on this picture: Block architecuture.
Currently, I see no issues if I only use local variables in my new functions, because the variables will be pushed in the stack and will not be initialized in the .bss segment. But if I want to add a static variable in my function, I will have some troubles because the startup code will not initialize this variable in the .bss (or .data) segment.
My question is, is that event possible to implement an architecture like this one in a C code ? If yes, how can I adapt my startup code to initialize my new variables ? Do you think C++ is more appropriate to do such kind of things ?
Thanks a lot !
Include one function in the API which initializes the block. Host must call this function before any other functions of the block.
Also, keep in mind that if you do this, you must also reserve part of the RAM (in addition to flash) for the block, which the host shall not touch. These variables are normally marked as __no_init or something similar to prevent linker even trying to generate initialization data for .data placement.
Language you use (C or C++) most likely won't matter. Memory placement is not feature of either language, but instead is done with compiler extensions and linker features, which are toolchain specific.
I am using gcc to compile some code for an ARM Cortex-M4F microcontroller. My application uses a large collection of data that I have conveniently written into a C file: large arrays of ints and floats, circular linked lists pointing to those various arrays, various structs, that sort of thing.
When I compile this it adds up to about 500K of data, plus a few hundred K for the actual application. gcc is putting all this data conveniently into the .data section; ld then tries to build the elf putting the .data section into RAM and .text (code) section into FLASH. The mcu I am using doesn't have 500K of RAM so it cannot build the ELF, but it does have 1M of FLASH. I tried changing my linker script so that both .data and .text are put into FLASH which "worked" but there are some other bit of code that expect its data to go into RAM, so ultimately execution failed; I can't make that sweeping change.
What I need is to tell gcc to put every single object in this C file into the .text section so it can go into FLASH with the rest of the non-mutable stuff, or at least some other section which I can then instruct my linker script what to do with so that it doesn't interfere with existing blobs that have no problem fitting in RAM. I don't know how to do that. Here is a very slimmed down example of what I have
/* data.c */
static char* option_array_0_0[] =
{
"O=0.40",
"K=FOO",
"JAR=JAR",
};
static int width_array_0_0[] =
{
0,
1,
1,
};
Window window_array_0[] =
{
{
option_array,
width_array,
},
};
/* main.c */
extern Window window_array_0[];
int main()
{
/* Do stuff */
}
The stuff in data.c, window_array_0 and everything (or most everything, maybe the string arrays are going to .text?) it links to, is being put in .data which my linker script puts into RAM. I want it all in a different section which I can then put into FLASH. There are thousands of these types of arrays in there, plus hundreds of structs and dozens of other bits of information. Is this possible to change? As a test I replaced my "window_array_0" with a char[500000] of random data and that compiled without complaint so I assume it put it all into .text (as would be expected), I just don't know how to make it do so for arbitrary objects.
Thanks for your help.
As other commenters pointed, 'static const' items usually end up in .rodata section which is likely to be placed right next to .text in potentially read-only memory. The caveat is that it may or may not be true in your case as that is specific to particular target and may be changed by particular build process (i.e. linker options, specific section specified via __attribute__((section("name"))) in C code, linker script, binaries tweaked after build with various binutils, etc).
If you need to have precise control over in-memory layout and you know what you're doing, you can use LD script to do it. Among other things it will let you specify that .rodata from file data.o should be placed just before/after .text from all other .o files linked into the executable.
You can use arm-<your toolchain variant>-ld -verbose to dump default linker script and use it as a starting point for tweaking.
Most compilers/linkers, if you declare a variable as static const, it will place it in the text section instead of data. Obviously, these must be preinitialized and not modified at run-time, but that's the only way it makes sense to go in flash.
Somewhere in the code (.text section) put like a sample:
__attribute__((section(".text")))
const int test[0x0A] = {0,0,0,0,0,0,0,0,0,0};
or without const if you want a variable to change:
__attribute__((section(".text")))
int test[0x0A] = {0,0,0,0,0,0,0,0,0,0};
Then try changing it:
test[0] = 0xffffffff;
This works on my Linux 32 intel machine.
IIRC, code in flash is usually required to be ROPI (read only position independent). So option_array_0_0 and width_array_0_0 would need const qualifiers (read only). However:
Window window_array_0[] =
{
{
option_array,
width_array,
},
};
needs to be changed somehow (I'm assuming option_array and width_array are indeed arrays). That makes window_array_0 not position independent.
All non-trivial embedded projects shall have a linker script. It defines where different symbols (function, global variables, debug symbols, ...) shall be placed in memory. Here is some tutorial about gcc linker script.
forcing all data to be placed in one section might not be the best solution!
NOTE: Since these arrays are NOT constants, it doesn't make sense to store them in data section! because this means you will end up over-writing code section by you code (which is PRETTY dangerous). Either make them const or create a no-init section which is not initialized by the loader, and you initialize it on reset.
I have programmed avr microcontroller , but new to arm.I just looked a sample code for sam7s64 that comes with winarm.I am confused about these files rom.ld , ram.ld , scatter file , cstartup.s file. I never saw these kind of files when i programmed avr .Please clarify my doubts what each of them file do.
I have even more samples for you to ponder over http://github.com/dwelch67
Assume you have a toolchain that supports a specific instruction set. Tools often try to support different implementations. You might have a microcontroller with X amount of flash and Y amount of ram. One chip might have the ram at a different place than another, etc. The instruction set may be the same (or itself may have subtle changes) in order for the toolchain to encode some of the instructions it eventually wants to know what your memory layout is. It is possible to write code for some processors that is purely position independent, in general though that is not necessarily a goal as it has a cost. tools also tend to have a unix approach to things. From source language to object file, which doesnt know the memory layout yet, it leaves some holes to be filled in later. You can get from different languages depending on the toolchain and instruction set, maybe mixing ada and C and other languages that compile to object. Then the linker needs to combine all of those things. You as the programmer can and sometimes have to control what goes where. You want the vector table to be at the right place, you want your entry code perhaps to be at a certain place, you definitely want .data in ram ultimately and .text in flash.
For the gnu tools you tell the linker where things go using a linker script, other toolchains may have other methods. With gnu ld you can also use the ld command line...the .ld files you are seeing are there to control this. Now sometimes this is buried in the bowels of the toolchain install, there is a default place where the default linker script will be found, if that is fine then you dont need to craft a linker script and carry it around with the project. Depending on the tools you were using on the avr, you either didnt need to mess with it (were using assembly, avra or something where you control this with .org or other similar statements) or the toolchain/sandbox took care of it for you, it was buried (for example with the arduino sandbox). For example if you write a hello world program
#include <stdio.h>
int main ( void )
{
printf("Hello World!\n");
return(0);
}
and compile that on your desktop/laptop
gcc hello.c -o hello
there was a linker script involved, likely a nasty, scary, ugly one. But since you are content with the default linker script and layout for your operating system, you dont need to mess with it it just works. For these microcontrollers where one toolchain can support a vast array of chips and vendors, you start to have to deal with this. It is a good idea to keep the linker script with the project as you dont know from one machine or person to the next what exact gnu cross compiler they have, it is not difficult to create projects that work on many gnu cross compiler installs if you keep a few things with the project rather than force them into the toolchain.
The other half of this, in particular with the gnu tools an intimate relationship with the linker script is the startup code. Before your C program is called there are some expectations. for example the .data is in place and .bss has been zeroed. For a microcontroller you want .data saved in non volatile memory so it is there when you start your C program, so it needs to be in flash, but it cant run from there as .data is read/write, so before the entry point of the C code is called you need to copy .data from flash to the proper place in ram. The linker script describes both where in flash to keep .data and where in ram to copy it. The startup code, which you can name whatever you want startup.s, start.s, crt0.s, etc, gets variables filled in during the link stage so that code can copy .data to ram, can zero out .bss, can set the stack pointer so you have a stack (another item you need for C to work), then that code calls the C entry point. This is true for any other high level language as well, if nothing else everyone needs a stack pointer so you need some startup code.
If you look at some of my examples you will see me doing linker scripts and startup code for avr processors as well.
It's hard to know exactly what the content of each of the files (rom.ld , ram.ld , scatter file , cstartup.s) are in your specific case. However assuming their names are descriptive enough I will give you an idea of what they are intended to do:
1- rom.ld/ram.ld: by the files extensions these are "linker scripts". These files tell the linker how where to put each of the memory sections of the object files (see GNU LD to learn all about linker scripts and their syntax)
2- cstartup.s: Again, from the extension of this file. It appears to be code written in assembly. Generally in this file the software developer will initialize that microcontroller before passing control to the your main application. Examples of actions performed by this file are:
Setup the ARM vectors
Configure the oscillator frequency
Initialize volatile memory
Call main()
3- Scatter : Personally I have never used this file. However it appears to be a file used to control the memory layout of your application and how that is laid out in your micro (see reference). This appears to be a Keil specific file no different from any other linker script.
I am working with an ARM Cortex M3 chip (STM32F2) and ST provides a "standard peripheral library". It has some useful .c and .h files. It also has .s files.
What is the purpose of these .s files in the context of a C project? How do I get my compiler/linker/? to take them into account?
The .s extension is the convention used by GNU and many other tool-chains for assembler files.
Last I looked the STM32 Standard Peripheral Library itself contains no assembler files, however the CMSIS library contains start-up code for various STM32 parts, for example startup_stm32f2xx.s is start-up code for all STM32F2xx series devices. There are different implementations for different tool-chains; you need to build and link the file associated with your specific part and tool-chain. If you are using an example project that builds and runs or an IDE that creates part-specific projects for you, this will probably already have been done - if you have code that runs it certainly has.
How you build and link the code will depend on what tool-chain you are using. Most IDE based tools will automatically recognise the extension and invoke the assembler to generate an object file that will be linked like any other. The exact content differs slightly between tool-chain versions, but primarily creates the C runtime environment (stack and heap), initialises the processor, defines an initial interrupt/exception vector table, initialises static data and jumps to main().
The core of the file for the Keil/ARM RealView version for example looks like this:
; Reset handler
Reset_Handler PROC
EXPORT Reset_Handler [WEAK]
IMPORT SystemInit
IMPORT __main
LDR R0, =SystemInit
BLX R0
LDR R0, =__main
BX R0
ENDP
Reset_Handler is the address Program Counter (PC) register will be set to after a processor reset.
SystemInit is an external C code function that does the bulk of the initialisation - this may need customisation for your hardware. Cortex-M is unusual in that it can start running C code immediately after reset because the vector table includes both the reset address and the initial stack pointer address, which is automatically loaded to the SP register on reset. As a result you do not need much assembler knowledge to get one running.
__main() is the compiler supplied entry point for your C code. It is not the main() function you write, but performs initialisation for the standard library, static data, the heap before calling your `main()' function.
The GCC version is somewhat more involved since it does much of the work done by __main() in the Keil/ARM RealView version, but essentially it performs the same function.
Note that in the CMSIS SystemInit() is defined in system_stm32f2xx.c, and may need customisation for your board (correct crystal frequency, PLL setup, external SRAM configuration etc.). Because this is C code, and well commented, you will probably be more comfortable with it.
They usually contain assembly code. The assembler turns them into object files which are later linked by the linker with the main stuff. But I imagine it does depend on the compiler, toolchain etc.
The .s files usually contain the Vector tables. It defines what should the system do when an interrupt occurs. This table (code) is placed in a memory address defined by you in linker file. For example, every time a reset occurs what or rather where should your processor begin from , what code should it run. similarly, there are other handlers ( interrupt vectors). In STM32 , usually the controller loops on particular handlers.
As given in the below example:See this link for detailed explanation
.section INTERRUPT_VECTOR, "x"
.global _Reset
_Reset:
B Reset_Handler /* Reset */
B . /* Undefined */
B . /* SWI */
B . /* Prefetch Abort */
B . /* Data Abort */
B . /* reserved */
B . /* IRQ */
B . /* FIQ */
Reset_Handler:
LDR sp, =stack_top
BL c_entry
B .
This assembly code later is converted to object files and linked with your .c files and .ld to create a .elf or .bin files.
You've probably got a Keil-based development environment for your ST kit. Depending on the version of your compiler, the project file should have different sections for C, C++, and assembler code. In your IDE, open your project and look for "Project Properties" or something like it.
You can import and export symbols to and from the assembler code so that it and the C/C++ code will link. With Keil it all integrates reasonably well.
The EXPORT directive tells the assembler to make the specified symbol public so that your C/C++ code can link to it.
The IMPORT directive tells the assembler that the specified symbol is defined elsewhere and will be resolved at link time.
Is it possible to RUN 2 different C programs(ie 2 main()), stored in Flash(micro controller), one at a time?
I have a bootloader code which is a separate program and resides in separate protected section of ROM. Then I have my application program which resides in separate ROM section. Although, residing in memory is not an issue, but how will linker interpret this? How can I switch between 2 programs. Is this possible?
For example:
Once I am done with bootloader, I can make it jump to Application function, but how will linker know this function?
Just to add, I am using Freescale HCS08 series and IDE is Codewarrior.
Further, here are the sequence of steps:
I load a Bootloader code in ROM. Then this bootloader code is required to load my application code. And then my application code should take over.
Bootloader Code:
Program Application Area ROM
Start Application Program
Application Code:
Check if to run Bootloader code or application itself.
Main is just a function. You may rename it and write another main which call either of them.
If you do not want rename main in the source you may mangle its name by define or compiler key:
cc -Dmain=main1 ...
(for first program), and
cc -Dmain=main2 ...
(for the second). Selector main:
int main(void) {
if(x) return main1();
else return main2();
}
Then link all together and download to your controller.
But there's problem with ISR's: you cannot assign two routines to single irq vector. If vectors are hardcoded to some flash location (like in most 8-bit controllers) you cannot switch ISR's. You will have to write ISR wrapper, recognizing which program is run and calling appropriate ISR.
UPD
Second issue is that statically linked variables from first and second program will be in RAM simultaneously while only one set of them is used. This may exhaust RAM (small amount of which often exists in microcontroller) too early.
UPD2
Oh, now I really understand. If you want to link and download them separately, you should deal with linker maps. In this case same symbol names (such as many main's) s not an issue. In linker map you should define known entry point [set it to absolute address], from which either application code starts. Startup code (commonly it is assemble code) should be linked from this address. From selector you should decide and jump to defined location directly. (Do this only for bootloader if your app is also a selector).
Entry point provided by linker may be accessible by program as extern function:
int app2_start(void);
{
.... /* condition check */
app2_start(); /* this symbol defined in linker map, not in any source */
}
But this is not the address of it's main(), because C RTL have do make many initialisations (stack, initialised variables, heap, IO, etc.) before main() can start.
There's more common way that the bootloader decides, should it run itself or application, because if application code fails, boodloader may became inaccessible.
The way I've seen this done is to stick the entry point into a header for the application. Then have the boot loader pull that entry point out and jump to it with an appropriate inline assembly instruction. You may need a linker script to get the entry point itself from the application. Gnu ld uses ENTRY.