{"id":1006,"date":"2013-03-13T00:00:00","date_gmt":"2013-03-13T00:00:00","guid":{"rendered":"https:\/\/www.fussylogic.co.uk\/blog\/?p=1006"},"modified":"2013-03-11T23:09:34","modified_gmt":"2013-03-11T23:09:34","slug":"stm32f0-discovery-development-iii","status":"publish","type":"post","link":"https:\/\/www.fussylogic.co.uk\/blog\/?p=1006","title":{"rendered":"STM32F0 Discovery Development III"},"content":{"rendered":"<p>The ARM startup code <a href=\"?p=1001\">we discussed last time<\/a> was enough to get a program to compile, link and run, but it wasn\u00e2\u20ac\u2122t enough to support a real C program. There is one primary feature that we\u00e2\u20ac\u2122re missing, pre-initialised variables need their initial values copying from flash to RAM.<\/p>\n<p>The <a href=\"https:\/\/github.com\/szczys\/stm32f0-discovery-basic-template\">discovery-basic-template<\/a> is full of useful information, and forms the basis for this article.<\/p>\n<p>Here\u00e2\u20ac\u2122s the section summary from an object file we\u00e2\u20ac\u2122ll make later:<\/p>\n<pre><code>Sections:\nIdx Name          Size      VMA       LMA       File off  Algn\n  0 .isr_vector   000000c4  08000000  08000000  00008000  2**0\n                  CONTENTS, ALLOC, LOAD, READONLY, DATA\n  1 .text         00000024  080000c4  080000c4  000080c4  2**2\n                  CONTENTS, ALLOC, LOAD, READONLY, CODE\n  2 .data         00000004  20000000  080000e8  00010000  2**2\n                  CONTENTS, ALLOC, LOAD, DATA<\/code><\/pre>\n<p>The thing to note here is the difference between the <code>.text<\/code> section and the <code>.data<\/code> section: the <code>.text<\/code> section has its <code>LMA<\/code> (load address) and <code>VMA<\/code> (virtual address) at the same place \u00e2\u20ac\u201c the <code>.data<\/code> section does not. In essence that means that the linker has arranged things so that the variable memory that the rest of the program modified is at 0x20000000 (absolutely correct for an STM32F0), but that the section content is stored at 0x80000e8. We achieve this by making our linker script look like this:<\/p>\n<pre><code>.text : {\n    \/* ... removed for brevity ... *\/\n    _end_of_text = .;\n\n    \/* Create a symbol for where the .data initial values will start *\/\n    _start_of_data_init = _end_of_text;\n} &gt;FLASH\n\n.data : AT (_start_of_data_init) {\n    _start_of_data = .;\n    \/* ... removed for brevity ... *\/\n    _end_of_data = .;\n} &gt;RAM<\/code><\/pre>\n<p>We have to understand the linker script syntax a little, the <code>AT()<\/code> tells the linker the load address, and the <code>&gt;RAM<\/code> tells it the runtime memory block for this section. We can use the additional symbols that we\u00e2\u20ac\u2122ve added to the linker script to do the run-time initialisation of <code>.data<\/code>. Specifically, <code>.data<\/code> is loaded at <code>_start_of_data_init<\/code>, defined in the <code>FLASH<\/code> region; but it is linked at <code>_start_of_data<\/code>, defined in the <code>RAM<\/code> region. Therefore we fill the RAM from <code>_start_of_data<\/code> to <code>_end_of_data<\/code> with the data in FLASH from <code>_start_of_data_init<\/code>.<\/p>\n<p>Here\u00e2\u20ac\u2122s the code, it should go before jumping to <code>main<\/code>, and after establishing the stack.<\/p>\n<pre><code>    \/* --- START: initialise .data *\/\n    movs    r1, #0\n    b       isDataInitCopyComplete\ncopyDataInitToData:\n    \/* here with current index in r1; start_of_data in r0 *\/\n    ldr     r3, =_start_of_data_init\n    \/* _start_of_data[r1] = _start_of_data_init[r1] *\/\n    ldr     r3, [r3, r1]\n    str     r3, [r0, r1]\n    \/* index += 4 *\/\n    adds    r1, r1, #4\n    \/* fall through to check end condition *\/\nisDataInitCopyComplete:\n    \/* here with current index in r1 *\/\n    ldr     r0, =_start_of_data\n    ldr     r3, =_end_of_data\n    \/* r2 = _start_of_data + index *\/\n    adds    r2, r0, r1\n    \/* if( _start_of_data + index &lt;= _end_of_data ) *\/\n    cmp     r2, r3\n    bcc     copyDataInitToData\n    \/* --- END: initialise .data *\/<\/code><\/pre>\n<p>This is still not quite sufficient for C. The <code>.bss<\/code> section needs clearing too. You might expect that the bss section, being \u00e2\u20ac\u0153uninitialised data\u00e2\u20ac\u009d can just be left \u00e2\u20ac\u201c not so, the compiler is allowed to put variables initialised to zero in <code>bss<\/code> and assume the startup code sets all of <code>bss<\/code> to zero. Let\u00e2\u20ac\u2122s add that startup code too:<\/p>\n<pre><code>    \/* --- START: initialise .bss *\/\n    ldr     r2, =_start_of_bss\n    b       isBSSFillComplete\nfillZeroBSS:\n    \/* _start_of_bss[i] = 0 *\/\n    movs    r3, #0\n    str     r3, [r2]\n    \/* ptr += 4 *\/\n    adds    r2, r2, #4\nisBSSFillComplete:\n    \/* here with r2 at current bss address *\/\n    ldr     r3, = _end_of_bss\n    \/* if( r2 pointing at _end_of_bss ) *\/\n    cmp     r2, r3\n    bcc     fillZeroBSS\n    \/* --- END: initialise .bss *\/<\/code><\/pre>\n<p><a href=\"https:\/\/github.com\/szczys\/stm32f0-discovery-basic-template\">szczys<\/a>\u00e2\u20ac\u2122s basic template adds an additional step \u00e2\u20ac\u201c a call to a function, <code>SystemInit()<\/code>. I\u00e2\u20ac\u2122m choosing not to add that to our startup code. In an embedded application, initialisation is main()\u00e2\u20ac\u2122s job too, startup code should be initialising for C, not for the CPU.<\/p>\n<p>We are done \u00e2\u20ac\u201c a call to <code>main()<\/code> is already present, and then we\u00e2\u20ac\u2122re running C code. Everything we talk about now will be about using the particular peripherals of the STM32F0. The above discussion is useful in a wider sense though, because we\u00e2\u20ac\u2122ve now seen the technique for performing a startup for <em>any<\/em> CPU type at all; and we\u00e2\u20ac\u2122re able to look at other linker scripts and appreciate their operation.<\/p>\n<p>All that remains is to be able to cope with all the various sections the C compiler might throw out. Here then is my complete linker script.<\/p>\n<pre><code>ENTRY(_ISR_Reset)\n\nMEMORY\n{\n    FLASH (rx) : ORIGIN = 0x08000000, LENGTH = 64K\n    RAM  (xrw) : ORIGIN = 0x20000000, LENGTH = 8K\n}\n_top_of_stack = 0x20002000;\n\nSECTIONS\n{\n    \/* interrupt vectors *\/\n    .isr_vector : {\n        . = ALIGN(4);\n        KEEP(*(.isr_vector))\n        . = ALIGN(4);\n    } &gt;FLASH\n\n    \/* program code -- in FLASH *\/\n    .text : {\n        . = ALIGN(4);\n        *(.text)\n        *(.text.*)\n        *(.rodata)\n        *(.rodata.*)\n        *(.glue_7)\n        *(.glue_7t)\n        KEEP (*(.init))\n        KEEP (*(.fini))\n\n        . = ALIGN(4);\n        _end_of_text = .;\n\n        \/* Create a symbol for where the .data initial values will start *\/\n        _start_of_data_init = _end_of_text;\n    } &gt;FLASH\n\n    \/* initialised data -- in RAM *\/\n    .data : AT (_start_of_data_init) {\n        . = ALIGN(4);\n        _start_of_data = .;\n\n        *(.data)\n        *(.data.*)\n        *(.RAMtext)\n\n        . = ALIGN(4);\n        _end_of_data = .;\n    } &gt;RAM\n\n    \/* uninitialised data -- in RAM *\/\n    .bss : {\n        . = ALIGN(4);\n        _start_of_bss = .;\n\n        *(.bss)\n        *(.bss.*)\n        *(COMMON)\n\n        . = ALIGN(4);\n        _end_of_bss = .;\n    } &gt;RAM\n}<\/code><\/pre>\n","protected":false},"excerpt":{"rendered":"<p>The ARM startup code we discussed last time was enough to get a program to compile, link and run, but it wasn\u00e2\u20ac\u2122t enough to support a real C program. There is one primary feature that we\u00e2\u20ac\u2122re missing, pre-initialised variables need their initial values copying from flash to RAM. The discovery-basic-template is full of useful information,\u2026 <span class=\"read-more\"><a href=\"https:\/\/www.fussylogic.co.uk\/blog\/?p=1006\">Read More &raquo;<\/a><\/span><\/p>\n","protected":false},"author":2,"featured_media":0,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":[],"categories":[1],"tags":[67,68,37,42,6],"_links":{"self":[{"href":"https:\/\/www.fussylogic.co.uk\/blog\/index.php?rest_route=\/wp\/v2\/posts\/1006"}],"collection":[{"href":"https:\/\/www.fussylogic.co.uk\/blog\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.fussylogic.co.uk\/blog\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.fussylogic.co.uk\/blog\/index.php?rest_route=\/wp\/v2\/users\/2"}],"replies":[{"embeddable":true,"href":"https:\/\/www.fussylogic.co.uk\/blog\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=1006"}],"version-history":[{"count":4,"href":"https:\/\/www.fussylogic.co.uk\/blog\/index.php?rest_route=\/wp\/v2\/posts\/1006\/revisions"}],"predecessor-version":[{"id":1012,"href":"https:\/\/www.fussylogic.co.uk\/blog\/index.php?rest_route=\/wp\/v2\/posts\/1006\/revisions\/1012"}],"wp:attachment":[{"href":"https:\/\/www.fussylogic.co.uk\/blog\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=1006"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.fussylogic.co.uk\/blog\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=1006"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.fussylogic.co.uk\/blog\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=1006"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}