mirror of
https://github.com/rfivet/stm32bringup.git
synced 2024-12-21 00:06:22 -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>
|