{"id":1001,"date":"2013-03-11T00:00:00","date_gmt":"2013-03-11T00:00:00","guid":{"rendered":"https:\/\/www.fussylogic.co.uk\/blog\/?p=1001"},"modified":"2013-03-13T00:59:51","modified_gmt":"2013-03-13T00:59:51","slug":"arm-cross-compiling-for-bare-metal","status":"publish","type":"post","link":"https:\/\/www.fussylogic.co.uk\/blog\/?p=1001","title":{"rendered":"STM32F0 Discovery Development"},"content":{"rendered":"<p>In my <a href=\"?p=994\">previous article<\/a> about the STM32F0-discovery board, I wrote this:<\/p>\n<blockquote>\n<p>I believe it will be possible, with a bit of research, to use the <code>arm-linux-eabi<\/code> version, and hence to get the cross-compiler direct from the <em>emdebian<\/em> project.<\/p>\n<\/blockquote>\n<p>Today\u00e2\u20ac\u2122s article is going to be looking at exactly that. I\u00e2\u20ac\u2122d like to be able to use the non-bare-metal version of the ARM cross-compiler that is available in <a href=\"http:\/\/www.emdebian.org\/crosstools.html\">emdebian\u00e2\u20ac\u2122s<\/a> toolchain repository (follow the instructions on that link to get access to the repository). The advantage of a packaged version is that it will almost certainly \u00e2\u20ac\u0153just work\u00e2\u20ac\u009d, it will be installed in a good place to fit with the rest of your installation, and it will be easy to upgrade when new versions are released. Once you\u00e2\u20ac\u2122ve added the appropriate repositories to your <code>\/etc\/apt\/sources.list<\/code>, you should do this:<\/p>\n<pre><code>$ apt-get install emdebian-archive-keyring\n$ apt-get install gcc-4.7-arm-linux-gnueabi<\/code><\/pre>\n<p>You can now use <code>arm-linux-gnueabi-<\/code> as your <code>BINUTILSPREFIX<\/code>, and get cross compiled versions of your normal Linux software. I\u00e2\u20ac\u2122m more concerned with using this compiler in place of the bare-metal version for building for the (for now) STM32F0-discovery board. Balau82\u00e2\u20ac\u2122s blog has an <a href=\"http:\/\/balau82.wordpress.com\/2010\/12\/05\/using-ubuntu-arm-cross-compiler-for-bare-metal-programming\/\">article<\/a> that gives us as an excellent start, and I\u00e2\u20ac\u2122m essentially going to rehash that but for the SM32F0 instead.<\/p>\n<p>I\u00e2\u20ac\u2122m also going to use it as an opportunity to build us a development environment containing just the core of the <a href=\"https:\/\/github.com\/szczys\/stm32f0-discovery-basic-template\">stm32f0-discovery-basic-template<\/a> that we used previously.<\/p>\n<p>First, let\u00e2\u20ac\u2122s make ourselves the most basic program we can.<\/p>\n<pre><code>void main( void )\n{\n    while(1) {\n    }\n}<\/code><\/pre>\n<p>Let\u00e2\u20ac\u2122s compile it, to see the lay of the land. The magic flag for removing the Linux libraries and startup from the build is <code>-nostdlib<\/code>, which turns out to be the essential piece for using non-bare metal for bare-metal work. We also need a few extra flags to define the CPU:<\/p>\n<pre><code>arm-linux-gnueabi-gcc -g \\\n    -mcpu=cortex-m0 -march=armv6s-m -mlittle-endian -mthumb \\\n    -o main.o -c main.c\narm-linux-gnueabi-gcc -Wl,--gc-sections -Wl,-Map=main.map \\\n    -Xlinker &quot;--build-id=none&quot; -ffunction-sections -fdata-sections \\\n    -nostdlib -o main.elf main.o\n\/usr\/lib\/gcc\/arm-linux-gnueabi\/4.7\/..\/..\/..\/..\/arm-linux-gnueabi\/bin\/ld: warning: cannot find entry symbol _start; defaulting to 0000000000008034<\/code><\/pre>\n<p>Unsurprisingly, the compile is fine, but the link fails with missing symbols. This is because the default linker script refers to a symbol that is no longer linked in, \u00e2\u20ac\u0153<code>_start<\/code>\u00e2\u20ac\u009d. Let\u00e2\u20ac\u2122s address that by replacing the default linker script. I\u00e2\u20ac\u2122ve removed a lot of, ultimately, necessary parts of this script, but we need a place to begin. Note: all our symbols are prefixed with \u00e2\u20ac\u0153<code>_<\/code>\u00e2\u20ac\u009d, the C standard dictates that symbols prefixed with underscore are for system use only \u00e2\u20ac\u201c in this case, that\u00e2\u20ac\u2122s us.<\/p>\n<pre><code>\/* stm32f0.ld *\/\nMEMORY\n{\n    FLASH (rx) : ORIGIN = 0x08000000, LENGTH = 64K\n    RAM  (xrw) : ORIGIN = 0x20000000, LENGTH = 8K\n}\n\nSECTIONS\n{\n    \/* program code -- in FLASH *\/\n    .text : {\n        . = ALIGN(4);\n        *(.text)\n        *(.text.*)\n        . = ALIGN(4);\n        _end_of_text = .;\n    } &gt;FLASH\n\n    \/* initialised data -- in RAM *\/\n    .data : {\n        . = ALIGN(4);\n        _start_of_data = .;\n        *(.data)\n        *(.data.*)\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        *(.bss)\n        *(.bss.*)\n        *(COMMON)\n        . = ALIGN(4);\n        _end_of_bss = .;\n    } &gt;RAM\n}<\/code><\/pre>\n<p>With this in place; we can successfully build an object file.<\/p>\n<pre><code>arm-linux-gnueabi-gcc -g -mcpu=cortex-m0 -march=armv6s-m -mlittle-endian \\\n    -mthumb -o main.o -c main.c\narm-linux-gnueabi-gcc -Tstm32f0.ld -ffunction-sections -fdata-sections \\\n    -nostdlib -Xlinker &quot;--build-id=none&quot; -Wl,--gc-sections \\\n    -Wl,-Map=main.map -o main.elf main.o\narm-linux-gnueabi-size main.elf\n   text    data     bss     dec     hex filename\n      0       0       0       0       0 main.elf<\/code><\/pre>\n<p>Note that we\u00e2\u20ac\u2122ve got no actual code. That\u00e2\u20ac\u2122s because our code is in a section that is subsequently garbage collected. Here\u00e2\u20ac\u2122s the symbol table, though:<\/p>\n<pre><code>main.elf:     file format elf32-littlearm\n\nSYMBOL TABLE:\n20000000 g       *ABS*  00000000 _start_of_data\n20000000 g       *ABS*  00000000 _end_of_bss\n20000000 g       *ABS*  00000000 _end_of_data\n08000000 g       *ABS*  00000000 _end_of_text\n20000000 g       *ABS*  00000000 _start_of_bss<\/code><\/pre>\n<p>Our next step is to put some startup code. We\u00e2\u20ac\u2122ll use the <code>_start<\/code> symbol. We add it as an entry point to the linker script:<\/p>\n<pre><code>ENTRY(_start)\n\n_top_of_stack = 0x20002000;<\/code><\/pre>\n<p>Then we need to define the symbol, which we\u00e2\u20ac\u2122ll do in assembly.<\/p>\n<pre><code>.syntax unified\n\n.section .text\n_start:\n    .global _start\n    .weak   _start\n    .type   _start, %function\n\n    ldr     r0, =_top_of_stack\n    mov     sp, r0\n    bl      main\n\n    .size   _start, . - _start<\/code><\/pre>\n<p>Most of this is assembler directives. The meat is a simple set of the stack pointer, and a jump to <code>main<\/code>.<\/p>\n<pre><code>arm-linux-gnueabi-as -mcpu=cortex-m0 -march=armv6s-m -mlittle-endian \\\n    -mthumb -o startup.o -c startup.s<\/code><\/pre>\n<p>Moving next to the ISR vector table. In the STM32F0 it\u00e2\u20ac\u2122s stored as the first 196 bytes of the flash.<\/p>\n<pre><code>.section .text.isr,&quot;ax&quot;,%progbits\nunhandled_interrupt:\n    .global unhandled_interrupt\ninfinite_loop:\n    b       infinite_loop\n    \/* Calculate size of function*\/\n    .size   unhandled_interrupt, . - unhandled_interrupt\n\n\n.section .isr_vector,&quot;a&quot;,%progbits\ninterrupt_vector_table:\n    .type   interrupt_vector_table, %object\n    \/* ----------- *\/\n    \/* 0x00000000 is the initial stack pointer *\/\n    .word   _top_of_stack\n    \/* ISR table ; zero entries are reserved *\/\n    .word   _ISR_Reset\n    .word   _ISR_NMI\n    .word   _ISR_HardFault\n    .word   0\n    .word   0\n    .word   0\n    .word   0\n    .word   0\n    .word   0\n    .word   0\n    .word   _ISR_SVC\n    .word   0\n    .word   0\n    .word   _ISR_PendSV\n    .word   _ISR_SysTick\n    \/* Peripheral IRQs *\/\n    .word   _ISR_WWDG\n    .word   _ISR_PVD\n    .word   _ISR_RTC\n    .word   _ISR_FLASH\n    .word   _ISR_RCC\n    .word   _ISR_EXTI0_1\n    .word   _ISR_EXTI2_3\n    .word   _ISR_EXTI4_15\n    .word   _ISR_TS\n    .word   _ISR_DMA1_Channel1\n    .word   _ISR_DMA1_Channel2_3\n    .word   _ISR_DMA1_Channel4_5\n    .word   _ISR_ADC1_COMP\n    .word   _ISR_TIM1_BRK_UP_TRG_COM\n    .word   _ISR_TIM1_CC\n    .word   _ISR_TIM2\n    .word   _ISR_TIM3\n    .word   _ISR_TIM6_DAC\n    .word   0\n    .word   _ISR_TIM14\n    .word   _ISR_TIM15\n    .word   _ISR_TIM16\n    .word   _ISR_TIM17\n    .word   _ISR_I2C1\n    .word   _ISR_I2C2\n    .word   _ISR_SPI1\n    .word   _ISR_SPI2\n    .word   _ISR_USART1\n    .word   _ISR_USART2\n    .word   0\n    .word   _ISR_CEC\n    .word   0\n    \/* ----------- *\/\n    .word   _start_of_boot_ram\n    \/* ----------- *\/\n    .size   interrupt_vector_table, .-interrupt_vector_table\n\n\n\/* ---------------------------------------------------------------- *\/\n\/*\n    Provide weak references for all the ISRs to the unhandled_interrupt\n    function.\n *\/\n\n    .weak _ISR_NMI\n    .thumb_set _ISR_NMI, unhandled_interrupt\n\n    .weak _ISR_HardFault\n    .thumb_set _ISR_HardFault, unhandled_interrupt\n\n    .weak _ISR_SVC\n    .thumb_set _ISR_SVC, unhandled_interrupt\n\n    .weak _ISR_PendSV\n    .thumb_set _ISR_PendSV, unhandled_interrupt\n\n    .weak _ISR_SysTick\n    .thumb_set _ISR_SysTick, unhandled_interrupt\n\n    .weak _ISR_WWDG\n    .thumb_set _ISR_WWDG, unhandled_interrupt\n\n    .weak _ISR_PVD\n    .thumb_set _ISR_PVD, unhandled_interrupt\n\n    .weak _ISR_RTC\n    .thumb_set _ISR_RTC, unhandled_interrupt\n\n    .weak _ISR_FLASH\n    .thumb_set _ISR_FLASH, unhandled_interrupt\n\n    .weak _ISR_RCC\n    .thumb_set _ISR_RCC, unhandled_interrupt\n\n    .weak _ISR_EXTI0_1\n    .thumb_set _ISR_EXTI0_1, unhandled_interrupt\n\n    .weak _ISR_EXTI2_3\n    .thumb_set _ISR_EXTI2_3, unhandled_interrupt\n\n    .weak _ISR_EXTI4_15\n    .thumb_set _ISR_EXTI4_15, unhandled_interrupt\n\n    .weak _ISR_TS\n    .thumb_set _ISR_TS, unhandled_interrupt\n\n    .weak _ISR_DMA1_Channel1\n    .thumb_set _ISR_DMA1_Channel1, unhandled_interrupt\n\n    .weak _ISR_DMA1_Channel2_3\n    .thumb_set _ISR_DMA1_Channel2_3, unhandled_interrupt\n\n    .weak _ISR_DMA1_Channel4_5\n    .thumb_set _ISR_DMA1_Channel4_5, unhandled_interrupt\n\n    .weak _ISR_ADC1_COMP\n    .thumb_set _ISR_ADC1_COMP, unhandled_interrupt\n\n    .weak _ISR_TIM1_BRK_UP_TRG_COM\n    .thumb_set _ISR_TIM1_BRK_UP_TRG_COM, unhandled_interrupt\n\n    .weak _ISR_TIM1_CC\n    .thumb_set _ISR_TIM1_CC, unhandled_interrupt\n\n    .weak _ISR_TIM2\n    .thumb_set _ISR_TIM2, unhandled_interrupt\n\n    .weak _ISR_TIM3\n    .thumb_set _ISR_TIM3, unhandled_interrupt\n\n    .weak _ISR_TIM6_DAC\n    .thumb_set _ISR_TIM6_DAC, unhandled_interrupt\n\n    .weak _ISR_TIM14\n    .thumb_set _ISR_TIM14, unhandled_interrupt\n\n    .weak _ISR_TIM15\n    .thumb_set _ISR_TIM15, unhandled_interrupt\n\n    .weak _ISR_TIM16\n    .thumb_set _ISR_TIM16, unhandled_interrupt\n\n    .weak _ISR_TIM17\n    .thumb_set _ISR_TIM17, unhandled_interrupt\n\n    .weak _ISR_I2C1\n    .thumb_set _ISR_I2C1, unhandled_interrupt\n\n    .weak _ISR_I2C2\n    .thumb_set _ISR_I2C2, unhandled_interrupt\n\n    .weak _ISR_SPI1\n    .thumb_set _ISR_SPI1, unhandled_interrupt\n\n    .weak _ISR_SPI2\n    .thumb_set _ISR_SPI2, unhandled_interrupt\n\n    .weak _ISR_USART1\n    .thumb_set _ISR_USART1, unhandled_interrupt\n\n    .weak _ISR_USART2\n    .thumb_set _ISR_USART2, unhandled_interrupt\n\n    .weak _ISR_CEC\n    .thumb_set _ISR_CEC, unhandled_interrupt<\/code><\/pre>\n<p>To put this in the correct place in flash, we need to put the table section in the linker script.<\/p>\n<pre><code>\/* interrupt vectors *\/\n.isr_vector : {\n    . = ALIGN(4);\n    KEEP(*(.isr_vector))\n    . = ALIGN(4);\n} &gt;FLASH<\/code><\/pre>\n<p>Use of <code>KEEP<\/code> here is what gets us, for the first time, a non-zero build (because of <code>-Wl,--gc-sections<\/code>). <code>isr_vector<\/code> sections are kept regardless of use, and hence anything they refer to becomes a dependency.<\/p>\n<pre><code>arm-linux-gnueabi-as -mcpu=cortex-m0 -march=armv6s-m -mlittle-endian -mthumb -o startup.o -c startup.s\narm-linux-gnueabi-gcc -Tstm32f0.ld -ffunction-sections -fdata-sections -nostdlib -Xlinker &quot;--build-id=none&quot; -Wl,--gc-sections -Wl,-Map=main.map -o main.elf main.o startup.o\narm-linux-gnueabi-size main.elf\n   text    data     bss     dec     hex filename\n    220       0       0     220      dc main.elf<\/code><\/pre>\n<p>After compile we get 220 bytes of code used. That might sound a lot for a does-nothing program, but remember we made a 196 byte interrupt vector table, which would exist whether the program did anything or not. That leaves 24 bytes of our program. Thumb instructions are 16-bits, so that\u00e2\u20ac\u2122s at most (assuming no absolute jumps or loads from memory) twelve assembly instructions. Not unreasonable. Here\u00e2\u20ac\u2122s the disassembly for interest\u00e2\u20ac\u2122s sake.<\/p>\n<pre><code>080000c4 &lt;main&gt;:\nvoid main( void )\n{\n 80000c4:   b580        push    {r7, lr}\n 80000c6:   af00        add r7, sp, #0\n    while(1) {\n    }\n 80000c8:   e7fe        b.n 80000c8 &lt;main+0x4&gt;\n 80000ca:   46c0        nop         ; (mov r8, r8)\n\n080000cc &lt;_ISR_Reset&gt;:\n 80000cc:   4801        ldr r0, [pc, #4]    ; (80000d4 &lt;_ISR_Reset+0x8&gt;)\n 80000ce:   4685        mov sp, r0\n 80000d0:   f7ff fff8   bl  80000c4 &lt;main&gt;\n 80000d4:   20002000    .word   0x20002000\n\n080000d8 &lt;_ISR_ADC1_COMP&gt;:\n 80000d8:   e7fe        b.n 80000d8 &lt;_ISR_ADC1_COMP&gt;<\/code><\/pre>\n<p>That\u00e2\u20ac\u2122s about as far as I want to go at this point. The main thing is that we\u00e2\u20ac\u2122ve used <code>arm-linux-gnueabi-gcc<\/code> to build a bare metal application; we\u00e2\u20ac\u2122ve made up a minimal linker script for an STM32F0; and have verified our small object file has almost nothing in it.<\/p>\n<p>If you wished, you could program this into your discovery board, but it does absolutely nothing, so you won\u00e2\u20ac\u2122t get a lot of enjoyment.<\/p>\n<p>We\u00e2\u20ac\u2122ve got a minimal system, but there is far more we\u00e2\u20ac\u2122re going to need. I\u00e2\u20ac\u2122ll try to cover those things next time.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>In my previous article about the STM32F0-discovery board, I wrote this: I believe it will be possible, with a bit of research, to use the arm-linux-eabi version, and hence to get the cross-compiler direct from the emdebian project. Today\u00e2\u20ac\u2122s article is going to be looking at exactly that. I\u00e2\u20ac\u2122d like to be able to use\u2026 <span class=\"read-more\"><a href=\"https:\/\/www.fussylogic.co.uk\/blog\/?p=1001\">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,6],"_links":{"self":[{"href":"https:\/\/www.fussylogic.co.uk\/blog\/index.php?rest_route=\/wp\/v2\/posts\/1001"}],"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=1001"}],"version-history":[{"count":6,"href":"https:\/\/www.fussylogic.co.uk\/blog\/index.php?rest_route=\/wp\/v2\/posts\/1001\/revisions"}],"predecessor-version":[{"id":1016,"href":"https:\/\/www.fussylogic.co.uk\/blog\/index.php?rest_route=\/wp\/v2\/posts\/1001\/revisions\/1016"}],"wp:attachment":[{"href":"https:\/\/www.fussylogic.co.uk\/blog\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=1001"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.fussylogic.co.uk\/blog\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=1001"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.fussylogic.co.uk\/blog\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=1001"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}