flash.s
.cpu cortex-m4
.thumb
.thumb_func
.global _start
_start:
stacktop: .word 0x20001000
.word reset
.word hang
.word hang
.word hang
.word hang
.word hang
.word hang
.word hang
.word hang
.word hang
.word hang
.word hang
.word hang
.word hang
.word hang
.thumb_func
reset:
bl notmain
b hang
.thumb_func
hang: b .
.align
.thumb_func
.globl PUT32
PUT32:
str r1,[r0]
bx lr
.thumb_func
.globl GET32
GET32:
ldr r0,[r0]
bx lr
.thumb_func
.globl dummy
dummy:
bx lr
so.c
void PUT32 ( unsigned int, unsigned int );
unsigned int GET32 ( unsigned int );
void dummy ( unsigned int );
int notmain ( void )
{
unsigned int ra;
for(ra=0;ra<1000;ra++) dummy(ra);
return(0);
}
flash.ld
MEMORY
{
rom : ORIGIN = 0x08000000, LENGTH = 0x1000
ram : ORIGIN = 0x20000000, LENGTH = 0x1000
}
SECTIONS
{
.text : { *(.text*) } > rom
.rodata : { *(.rodata*) } > rom
.bss : { *(.bss*) } > ram
}
build (dont need the none-eabi, with this code you can use the arm-linux-gnueabi or whichever arm-whatever-gcc/as/ld you want (within reason))
arm-none-eabi-gcc -Wall -Werror -O2 -nostdlib -nostartfiles -ffreestanding -mthumb -mcpu=cortex-m4 -c so.c -o so.o
arm-none-eabi-ld -o so.elf -T flash.ld flash.o so.o
arm-none-eabi-objdump -D so.elf > so.list
arm-none-eabi-objcopy so.elf so.bin -O binary
And from notes I took a while back you can use dfu-util to write your binary
dfu-util -d 0483:df11 -c 1 -i 0 -a 0 -s 0x08000000 -D myprogram.bin
The above does nothing much, but is a framework for you to add the enable of the gpio block, make the led pin an output, then turn it off and on with some code to kill time in a loop. and/or poll one gpio pin and drive another to match (use the button to light or turn off an led).
openocd connects up fine to this board/family with stlink...
you wont need interrupts or clock configs at first (if ever).
Ahh, right...After building no matter what path you take examine the binary and make sure it has a chance of working.
08000000 <_start>:
8000000: 20001000 andcs r1, r0, r0
8000004: 08000041 stmdaeq r0, {r0, r6}
8000008: 08000047 stmdaeq r0, {r0, r1, r2, r6}
800000c: 08000047 stmdaeq r0, {r0, r1, r2, r6}
8000010: 08000047 stmdaeq r0, {r0, r1, r2, r6}
8000014: 08000047 stmdaeq r0, {r0, r1, r2, r6}
8000018: 08000047 stmdaeq r0, {r0, r1, r2, r6}
800001c: 08000047 stmdaeq r0, {r0, r1, r2, r6}
8000020: 08000047 stmdaeq r0, {r0, r1, r2, r6}
8000024: 08000047 stmdaeq r0, {r0, r1, r2, r6}
8000028: 08000047 stmdaeq r0, {r0, r1, r2, r6}
800002c: 08000047 stmdaeq r0, {r0, r1, r2, r6}
8000030: 08000047 stmdaeq r0, {r0, r1, r2, r6}
8000034: 08000047 stmdaeq r0, {r0, r1, r2, r6}
8000038: 08000047 stmdaeq r0, {r0, r1, r2, r6}
800003c: 08000047 stmdaeq r0, {r0, r1, r2, r6}
08000040 <reset>:
8000040: f000 f808 bl 8000054 <notmain>
8000044: e7ff b.n 8000046 <hang>
08000046 <hang>:
8000046: e7fe b.n 8000046 <hang>
vector table up front with the stack pointer and thats fine, dont have to use it, ignore the stmdaeq disassembly it is just trying to disassemble the vector entries because I used objdump to examine the binary. the vector table needs odd numbers the address of the entry ORRED with one. Technically if small enough you can use 0x00000000 on these parts as that is really where it will be mapped when it boots this code, but because it is also mapped at 0x08000000, full amount of flash for these ST parts you will typically see it done like this. if you switch to another cortex-m based part from another family (NXP, Atmel/Microchip, etc) then you may need to use another address be it 0x00000000 or some other that that part family uses.
if you dont see the beginning of the binary looking like this with the stack pointer init value and the vector table, then you are not likely to have much luck with booting...no matter what library/software path you take.
Note the correct answer was given in a comment to this question. It is primarily opinion based. there are multiple library solutions and over time vendors will keep changing them for various (generally non-technical) reaasons. Professionally you should be able to go down either path, truly bare metal or some sandbox or somewhere in the middle. If you dont write all of the code and use someone elses you are still responsible for that project, so you should spend the time to dig into it and check the quality and accuracy of that code. You should be surprised by what you find, you own it you should fix it if you dont like it and/or replace it.
Neither path is automatically simpler nor faster nor more reliable. There is no right answer to this so you need to be flexible.
Both documents and library code are buggy, expect this, expect to deal with this.