This example code should explain the basic bare metal program in assembly language. It can be used on many ARM Cortex M processors from M0 to M7 and from different manufacturers. Not just ST Microelectronics. This is because current example is so simple right now. I have plans to test and port this tutorials also on TI TIVA (former Stellaris, former LuminaryMicro) , NXP LPC processors. You can get the code also on my Github https://github.com/hubmartin/ARM-cortex-M-bare-metal-assembler-examples/ Lets create and compile basic program that just increments number in R0 register. Content of main.S assembler file: @ Vector table start .long 0x20001000 .long _start @ Vector table end _start: loop: ADD R0, R0, #1 b loop .global _start The first vector is special. It contains initial stack pointer address and this value is copied to the Stack Pointer "SP" register. In this example I am using just register R0 and there is no need for stack or memory at all. So to keep things simple let's put here some address in memory area for now and move to the second vector. There can be other vectors like interrupts but since we don't need them we can ignore that fact right now. Compilation I have created very basic Makefile all: main.bin main.o: main.S arm-none-eabi-as -mthumb -o main.o main.S main.elf: main.o arm-none-eabi-ld -Ttext 0x8000000 main.o -o main.elf main.bin: main.elf arm-none-eabi-objcopy -S -O binary main.elf main.bin arm-none-eabi-size main.elf clean: rm main.elf main.o main.bin a.out As first main.S is compiled by gcc assembly "as" program. It creates main.o file. Then this file should be linked. Linker "moves" the addresses in my assembly labels to the real memory space which for STM32 is at 0x8000000. That's why there is -Ttext parameter. This can be done also with linker script but my solution makes things more simple right now. The term "text" for our code is there for historical reasons because in the early days "text" section was used for code that doesn't change. Sections .data and .bss are for memory, but that would be covered in later tutorials. After linking I get main.elf file. This is still object file with possible debug informations in it and it cannot be directly flashed to the MCU. I have to make binary file from that ELF file in the last step. Also there is "size" utility which shows me how big the program is. Let's try to call make: arm-none-eabi-as -mthumb -o main.o main.S arm-none-eabi-ld -Ttext 0x8000000 main.o -o main.elf arm-none-eabi-objcopy -S -O binary main.elf main.bin arm-none-eabi-size main.elf text data bss dec hex filename 12 0 0 12 c main.elf My increment application has only 12 bytes, sweet. There is also no RAM used, that's why there is value zero at "data" and "bss" sections. In Windows you can flash your program to some STM32F0 discovery boards by ST-link utility. Then in the Menu > Target > MCU Core... you can single step my little program and you will see that R0 is really incrementing. If you have OpenOCD / GDB connection, use commands below to test the program. Just remember to upload the main.elf file. Command "si" is step one instruction. We have to execute two instruction because one of them is increment (ADD) and the other branch instruction. (gdb) load main.elf Loading section .text, size 0xc lma 0x8000000 Start address 0x8000008, load size 12 Transfer rate: 35 bytes/sec, 12 bytes/write. (gdb) info reg r0 r0 0x9792b7 9933495 (gdb) si (gdb) si (gdb) info reg r0 r0 0x9792b8 9933496 (gdb) The increment program can be even smaller with just 8 bytes. It's a dirty hack but since my main loop has exactly 4 bytes and I am not using the stack and first vector. I can stuff my instructions there! :) _start: loop: ADD R0, R0, #1 b loop .long _start .global _start |
ARM > ARM Cortex bare metal GCC assembly >