mirror of
https://github.com/rfivet/stm32bringup.git
synced 2024-12-18 23:06:28 -05:00
251 lines
8.3 KiB
HTML
251 lines
8.3 KiB
HTML
<!DOCTYPE html>
|
||
<html lang="en">
|
||
<head>
|
||
<meta charset="UTF-8">
|
||
<title>1.7 C Startup</title>
|
||
<link type="text/css" rel="stylesheet" href="style.css">
|
||
</head>
|
||
<body>
|
||
<h1>1.7 C Startup</h1>
|
||
|
||
The C compiler uses a memory model where the RAM is divided into four
|
||
contiguous sections. The linker provides the symbols needed to make sure
|
||
the initial state meet the requirements of this memory model. So I need
|
||
to write a piece of code to use those symbols to initialize or clear the
|
||
RAM accordingly.
|
||
|
||
<pre>
|
||
│ <b>Section</b> │ <b>Description</b> │
|
||
├─────────┼──────────────────────────────────────────────┤
|
||
│ data │ static initialized, initial values in flash │
|
||
│ bss │ static unassigned, cleared │
|
||
│ heap │ dynamically allocated, user managed │
|
||
│ stack │ automatically allocated, stack frame managed │
|
||
</pre>
|
||
My bootstrap since the first <b>boot.c</b> already initializes the stack. I
|
||
need now to copy the initial values from flash to the <b>data</b> section and
|
||
clear the <b>bss</b> section.
|
||
<p>
|
||
You can check your understanding of the C memory model by looking at the
|
||
C test code below and figuring where the linker will allocate the
|
||
variables.
|
||
|
||
<pre>
|
||
/** Test code: main.c *********************************************************/
|
||
|
||
const char hexa[] = "0123456789abcdef" ;
|
||
long first = 1 ;
|
||
long i ;
|
||
|
||
int main( void) {
|
||
static char c = 'a' ;
|
||
char *cp = &c ;
|
||
|
||
*cp += i ;
|
||
i += hexa[ 13] - c + first++ ;
|
||
return 0 ;
|
||
}
|
||
</pre>
|
||
<ul>
|
||
<li> <b>data</b> section holds <code>first</code> and <code>c</code>, for a
|
||
total of 8 bytes as sections are word aligned.
|
||
</ul><ul>
|
||
<li> <b>bss</b> section holds <code>i</code> for a total of 4 bytes.
|
||
</ul><ul>
|
||
<li> <b>text</b> section holds <code>hexa</code> with all the const data
|
||
located after the code. As it is a zero terminated string, it occupies 17 bytes
|
||
and is padded with 3 zero for word alignment.
|
||
</ul><ul>
|
||
<li> <b>text</b> section holds the initial value of <code>first</code> and
|
||
<code>c</code> for a total of 8 bytes located after the const data.
|
||
</ul><ul>
|
||
<li> <b>stack</b> section holds <code>cp</code>, it is dynamically managed by
|
||
the code generated by the C compiler.
|
||
</ul><ul>
|
||
<li> after executing <code>main()</code>, <code>hexa</code> and <code>c</code>
|
||
are unchanged, <code>first</code> has the value 2, <code>i</code> has the
|
||
value 4 and <code>cp</code> has been deallocated.
|
||
</ul>
|
||
<h2>Evolving the bootstrap</h2>
|
||
|
||
First I make a copy of <b>boot.c</b> into <b>cstartup.c</b>.
|
||
<p>
|
||
I add the symbols defined by the linker script:
|
||
<ul>
|
||
<li> <code>__etext</code>, start of initial value copy in FLASH.
|
||
<li> <code>__data_start</code>, start of initialized data in RAM.
|
||
<li> <code>__bss_start</code>, start of unitialized data in RAM, it is the same
|
||
location as <code>__data_end</code>.
|
||
<li> <code>__bss_end</code>, first location after the bss section.
|
||
</ul>
|
||
I rework <code>Reset_handler()</code> to:
|
||
<ul>
|
||
<li> Initialize the <b>data</b> section with the initial values stored in flash.
|
||
|
||
<li> Clear the <b>bss</b> section
|
||
|
||
<li> Call the <code>main()</code> C function.
|
||
|
||
<li> Fallback to idle loop after <code>main()</code> has been executed.
|
||
</ul>
|
||
Finally I append the test code for validation.
|
||
|
||
<pre>
|
||
/* Memory locations defined by linker script */
|
||
extern long __StackTop ; /* &__StackTop points after end of stack */
|
||
void Reset_Handler( void) ; /* Entry point for execution */
|
||
extern const long __etext[] ; /* start of initialized data copy in flash */
|
||
extern long __data_start__[] ;
|
||
extern long __bss_start__[] ;
|
||
extern long __bss_end__ ; /* &__bss_end__ points after end of bss */
|
||
|
||
/* Interrupt vector table:
|
||
* 1 Stack Pointer reset value
|
||
* 15 System Exceptions
|
||
* NN Device specific Interrupts
|
||
*/
|
||
typedef void (*isr_p)( void) ;
|
||
isr_p const isr_vector[ 2] __attribute__((section(".isr_vector"))) = {
|
||
(isr_p) &__StackTop,
|
||
/* System Exceptions */
|
||
Reset_Handler
|
||
} ;
|
||
|
||
|
||
extern int main( void) ;
|
||
|
||
void Reset_Handler( void) {
|
||
const long *f ; /* from, source constant data from FLASH */
|
||
long *t ; /* to, destination in RAM */
|
||
|
||
/* Assume:
|
||
** __bss_start__ == __data_end__
|
||
** All sections are 4 bytes aligned
|
||
*/
|
||
f = __etext ;
|
||
for( t = __data_start__ ; t < __bss_start__ ; t += 1)
|
||
*t = *f++ ;
|
||
|
||
while( t < &__bss_end__)
|
||
*t++ = 0 ;
|
||
|
||
main() ;
|
||
for( ;;) ;
|
||
}
|
||
|
||
/** Test code: main.c *********************************************************/
|
||
|
||
const char hexa[] = "0123456789abcdef" ;
|
||
long first = 1 ;
|
||
long i ;
|
||
|
||
int main( void) {
|
||
static char c = 'a' ;
|
||
char *cp = &c ;
|
||
|
||
*cp += i ;
|
||
i += hexa[ 13] - c + first++ ;
|
||
return 0 ;
|
||
}
|
||
</pre>
|
||
|
||
<h2>Build</h2>
|
||
|
||
Building a binary, I can see that the <b>data</b> and <b>bss</b> sections are
|
||
not empty anymore and their sizes match my estimations.
|
||
|
||
<pre>
|
||
$ make cstartup.bin
|
||
cstartup.elf
|
||
text data bss dec hex filename
|
||
121 8 4 133 85 cstartup.elf
|
||
cstartup.bin
|
||
rm cstartup.o cstartup.elf
|
||
</pre>
|
||
|
||
If I look further in the <b>cstartup.map</b> generated by the linker.
|
||
|
||
<pre>
|
||
.text 0x08000000 0x79
|
||
*(.isr_vector)
|
||
.isr_vector 0x08000000 0x8 cstartup.o
|
||
0x08000000 isr_vector
|
||
*(.text*)
|
||
.text 0x08000008 0x34 cstartup.o
|
||
0x08000008 Reset_Handler
|
||
.text.startup 0x0800003c 0x2c cstartup.o
|
||
0x0800003c main
|
||
*(.rodata*)
|
||
.rodata 0x08000068 0x11 cstartup.o
|
||
0x08000068 hexa
|
||
.data 0x20000000 0x8 load address 0x0800007c
|
||
0x20000000 __data_start__ = .
|
||
*(.data*)
|
||
.data 0x20000000 0x8 cstartup.o
|
||
0x20000004 first
|
||
0x20000008 . = ALIGN (0x4)
|
||
0x20000008 __data_end__ = .
|
||
.bss 0x20000008 0x4 load address 0x08000084
|
||
0x20000008 . = ALIGN (0x4)
|
||
0x20000008 __bss_start__ = .
|
||
*(.bss*)
|
||
.bss 0x20000008 0x0 cstartup.o
|
||
*(COMMON)
|
||
COMMON 0x20000008 0x4 cstartup.o
|
||
0x20000008 i
|
||
0x2000000c . = ALIGN (0x4)
|
||
0x2000000c __bss_end__ = .
|
||
*(.stack*)
|
||
0x20001000 __StackTop = (ORIGIN (RAM) + LENGTH (RAM))
|
||
</pre>
|
||
<ul>
|
||
<li> <code>hexa</code> is located in <b>.rodata</b> at 0x08000068
|
||
|
||
<li> <code>first</code> is located in <b>.data</b> at 0x20000004
|
||
|
||
<li> <code>i</code> is located in <b>.bss</b> at 0x20000008
|
||
|
||
<li> <code>c</code> is not listed as it doesn’t have global scope, but I can
|
||
guess it’s located at 0x20000000.
|
||
|
||
<li> Initial values for the <b>.data</b> section are located at 0x0800007c.
|
||
</ul>
|
||
A hexadecimal dump of <b>cstartup.bin</b> confirms that the initial value
|
||
of <code>c</code> is at offset 0x7c, which also means that <code>c</code> has
|
||
been located at 0x20000000.
|
||
|
||
<pre>
|
||
$ hexdump -C cstartup.bin
|
||
00000000 00 10 00 20 09 00 00 08 10 b5 08 4a 08 4b 09 49 |... .......J.K.I|
|
||
00000010 8b 42 06 d3 00 21 08 4a 93 42 05 d3 00 f0 0e f8 |.B...!.J.B......|
|
||
00000020 fe e7 01 ca 01 c3 f3 e7 02 c3 f5 e7 7c 00 00 08 |............|...|
|
||
00000030 00 00 00 20 08 00 00 20 0c 00 00 20 30 b5 08 49 |... ... ... 0..I|
|
||
00000040 08 48 0a 78 04 68 4b 68 12 19 d2 b2 5d 1c 9b 1a |.H.x.hKh....]...|
|
||
00000050 64 33 1b 19 4d 60 03 60 0a 70 00 20 30 bd c0 46 |d3..M`.`.p. 0..F|
|
||
00000060 00 00 00 20 08 00 00 20 30 31 32 33 34 35 36 37 |... ... 01234567|
|
||
00000070 38 39 61 62 63 64 65 66 00 00 00 00 61 00 00 00 |89abcdef....a...|
|
||
00000080 01 00 00 00 |....|
|
||
00000084
|
||
</pre>
|
||
|
||
<h2>Debug</h2>
|
||
|
||
I use the STM32 Cube Programmer to check that the code behaves as
|
||
expected by checking the RAM content after <code>main()</code> has been
|
||
executed.
|
||
<p>
|
||
<img alt="RAM display in STM32 Cube Programmer" src="img/17_cube.png"
|
||
width="1024">
|
||
|
||
<h2>Checkpoint</h2>
|
||
|
||
I have now a sample bootstrap that puts the RAM memory in a state
|
||
required for a C startup.
|
||
<p>
|
||
<a href="18_3stages.html">Next</a>, I will merge the C startup initialization with
|
||
the <b>ledtick</b> code.
|
||
|
||
<hr>© 2020-2024 Renaud Fivet
|
||
</body>
|
||
</html>
|