Search code examples
armgdbstm32firmwareopenocd

Why stm32f103's elf file works well, but binary not?


I'm trying to run out my firmware inside stm32f103. So when I use opencod+gdb uploading and debugging elf file, everything is fine, my firmware is working and I can set and remove breakpoints.

But it doens't work when I try to upload this firmware (which was built together with elf file) using st-flash and writing it into 0x8000000. Although I get the message that 'the firmware was uploaded successfully'.

I can see if my code runs when my leds start blinking.

BOOT0 is connected to the DTR pin of a cp2102 via npn transistor, according to the datasheet to enable bootloader. I have to set BOOT0 to high. But my serial (cp2102) is not connected when I upload my fw via st-link. So I think that DTR pin is floating or pulled down. Where is my mistake?

I was trying to mass erase my flash before uploading, it gives the same results

schematic

here is my linker's ld file:

MEMORY
{
  RAM (xrw) : ORIGIN = 0x20000000, LENGTH = 20K
  CCMRAM (xrw) : ORIGIN = 0x00000000, LENGTH = 0
  FLASH (rx) : ORIGIN = 0x08000000, LENGTH = 64K
  FLASHB1 (rx) : ORIGIN = 0x00000000, LENGTH = 0
  EXTMEMB0 (rx) : ORIGIN = 0x00000000, LENGTH = 0
  EXTMEMB1 (rx) : ORIGIN = 0x00000000, LENGTH = 0
  EXTMEMB2 (rx) : ORIGIN = 0x00000000, LENGTH = 0
  EXTMEMB3 (rx) : ORIGIN = 0x00000000, LENGTH = 0
  MEMORY_ARRAY (xrw)  : ORIGIN = 0x00000000, LENGTH = 0
}

and sections https://pastebin.ubuntu.com/p/N32zQf9sCm/


Solution

  • Try this

    .globl _start
    _start:
    
    .word 0x20001000
    .word reset
    .word loop
    .word loop
    
    .thumb_func
    reset:
        add r0,#1
        b reset
    
    .thumb_func
    loop:
        b loop
    

    build, can use arm-whatever-whatever (arm-none-eabi, arm-linux-gnueabi, etc)

    arm-none-eabi-as so.s -o so.o
    arm-none-eabi-ld -Ttext=0x08000000 so.o -o so.elf
    arm-none-eabi-objcopy -O binary so.elf so.bin
    arm-none-eabi-objdump -D so.elf
    
    so.elf:     file format elf32-littlearm
    
    
    Disassembly of section .text:
    
    08000000 <_start>:
     8000000:   20001000    andcs   r1, r0, r0
     8000004:   08000011    stmdaeq r0, {r0, r4}
     8000008:   08000015    stmdaeq r0, {r0, r2, r4}
     800000c:   08000015    stmdaeq r0, {r0, r2, r4}
    
    08000010 <reset>:
     8000010:   3001        adds    r0, #1
     8000012:   e7fd        b.n 8000010 <reset>
    
    08000014 <loop>:
     8000014:   e7fe        b.n 8000014 <loop>
    

    Not that the vectors are odd, they are the address of the handler orred with one. If you don't see this the processor won't boot.

    You have said you have openocd+gdb working so either through that path or via openocd+telnet or if you have another way using the uart bootloader for example. But use reset or a power on with boot0 set for application and then attach with openocd without resetting it, then halt and examine r0, resume, halt and examine again, is it counting, did this code load and run from flash.

    If you have a blue pill then you can use this code to blink the led.

    flash.s

    .cpu cortex-m0
    .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
    
    .end
    

    blinker01.c

    void PUT32 ( unsigned int, unsigned int );
    unsigned int GET32 ( unsigned int );
    void dummy ( unsigned int );
    
    #define GPIOCBASE 0x40011000
    #define RCCBASE 0x40021000
    
    int notmain ( void )
    {
        unsigned int ra;
        unsigned int rx;
    
        ra=GET32(RCCBASE+0x18);
        ra|=1<<4; //enable port c
        PUT32(RCCBASE+0x18,ra);
        //config
        ra=GET32(GPIOCBASE+0x04);
        ra&=~(3<<20);   //PC13
        ra|=1<<20;      //PC13
        ra&=~(3<<22);   //PC13
        ra|=0<<22;      //PC13
        PUT32(GPIOCBASE+0x04,ra);
    
        for(rx=0;;rx++)
        {
            PUT32(GPIOCBASE+0x10,1<<(13+0));
            for(ra=0;ra<200000;ra++) dummy(ra);
            PUT32(GPIOCBASE+0x10,1<<(13+16));
            for(ra=0;ra<200000;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

    arm-none-eabi-as --warn --fatal-warnings  flash.s -o flash.o
    arm-none-eabi-gcc -Wall -Werror -O2 -nostdlib -nostartfiles -ffreestanding  -mthumb -c blinker01.c -o blinker01.o
    arm-none-eabi-ld -o blinker01.elf -T flash.ld flash.o blinker01.o
    arm-none-eabi-objdump -D blinker01.elf > blinker01.list
    arm-none-eabi-objcopy blinker01.elf blinker01.bin -O binary
    

    examine vector table

    Disassembly of section .text:
    
    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 f80a   bl  8000058 <notmain>
     8000044:   e7ff        b.n 8000046 <hang>
    
    08000046 <hang>:
     8000046:   e7fe        b.n 8000046 <hang>
    

    Looks good. Now program and reset.

    Your schematic is not a blue pill so adjust accordingly to enable the gpio clocks and make the pin an output and so on for your led.

    with either of these programs or your own, I don't use gdb have no use for it I use openocd+telnet if anything. but either should let you dump the flash with telnet

    mdw 0x00000000 20
    mdw 0x08000000 20
    

    both should have the same data. If not then you have a boot0 problem.

    Edit

    If DTR is high then boot0 is 0/GND yes? That is what is required to boot normally. boot0 tied low and reset tied high with a power on or low to high.

    You can write a program to force DTR one way or the other.

    int dtr_bit=TIOCM_DTR;
    ...
    dtr_bit=TIOCM_DTR;
    ioctl(ser_hand,TIOCMBIC,&dtr_bit);
    ...
    dtr_bit=TIOCM_DTR;
    ioctl(ser_hand,TIOCMBIS,&dtr_bit);
    

    with the usual termios stuff to open the handle.

    Or assuming DTR is supported by your dumb terminal (minicom, etc), attach to the uart, then power on and/or reset the board (paperclip, or whatever you have handy).

    Since I often use the serial bootloader to load my stm32 parts or even if I use SWD, I always provide myself a solution to control boot0 and reset, be it push-buttons or jumpers or pads or some combination.