为什么stm32f103的elf文件可以正常工作,而二进制文件却不能工作?

时间:2019-10-23 14:24:35

标签: arm gdb stm32 firmware openocd

我正在用尽stm32f103内的固件。因此,当我使用opencod + gdb上载和调试elf文件时,一切都很好,固件正在运行,并且可以设置和删除断点。

但是,当我尝试使用st-flash上​​载此固件(与elf文件一起构建)并将其写入0x8000000时,它不起作用。尽管我收到消息“固件已成功上传”。

当LED开始闪烁时,我可以查看代码是否运行。

根据数据手册,BOOT0通过npn晶体管连接到cp2102的DTR引脚,以启用引导程序。我必须将BOOT0设置为高。但是,当我通过st-link上传我的固件时,我的序列号(cp2102)没有连接。因此我认为DTR引脚处于悬空或下拉状态。我的错误在哪里?

我试图在上传之前大规模擦除自己的Flash,但结果相同

schematic

这是我的链接器的ld文件:

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
}

https://pastebin.ubuntu.com/p/N32zQf9sCm/部分

3 个答案:

答案 0 :(得分:0)

您是否尝试过使用STM32CubeProgrammer

它允许您使用UART,SWD,JTAG和USB对固件进行编程。请先尝试SWD,然后再尝试UART模式,看看是否是ST错误或您的UART接线。

答案 1 :(得分:0)

尝试

.globl _start
_start:

.word 0x20001000
.word reset
.word loop
.word loop

.thumb_func
reset:
    add r0,#1
    b reset

.thumb_func
loop:
    b loop

构建,可以使用任何方式(arm-none-eabi,arm-linux-gnueabi等)

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>

向量不是奇数,它们是处理程序的地址或以1为序。如果您没有看到此信息,则处理器将无法启动。

您已经说过openocd + gdb可以通过该路径运行,也可以通过openocd + telnet运行,或者例如,如果您使用uart引导程序进行另一种方式。但是,请使用reset或在为应用程序设置了boot0的情况下打开电源,然后在不重置open0的情况下附加openocd,然后暂停并检查r0,恢复,暂停并再次检查,是否计数,是否已从闪存加载并运行此代码。 >

如果您有蓝色药丸,则可以使用此代码来使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
}

构建

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

检查向量表

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>

看起来不错。现在编程并重置。

您的原理图不是一个蓝色药丸,因此请进行相应调整以启用gpio时钟并使该引脚作为输出,依此类推。

无论使用这些程序还是使用您自己的程序,我都不会使用gdb。如果有的话,我会使用openocd + telnet。但两者都应该让您使用telnet转储闪存

mdw 0x00000000 20
mdw 0x08000000 20
两者均应具有相同的数据。如果没有,那么您就遇到了boot0问题。

编辑

如果DTR为高电平,则boot0为0 / GND是吗?那是正常启动所需要的。 boot0处于低电平状态,并在上电或由低至高的状态下复位至高电平。

您可以编写一种程序以强制DTR的一种方式。

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);

用通常的termios物品打开手柄。

或者假设您的哑终端(minicom等)支持DTR,则将其连接到uart,然后打开电源和/或重置板(回形针,或任何方便的东西)。

由于我经常使用串行引导加载程序来加载我的stm32部件,或者即使我使用SWD,所以我总是为自己提供一种控制boot0和重置的解决方案,无论是按钮,跳线,打击垫还是某种组合。

答案 2 :(得分:0)

@old_timer非常感谢您的详细回答。我发现问题出在固件过大。我的芯片只有64k的闪存,而fw是68k,因此eclipse并没有告诉我固件过大并试图对其进行闪存。另外,基于我的项目的模板使用newlib,其中startup.s被C文件替换了,我想这是有问题的。因此,我从openstm32 tamplate创建了一个新项目(它从stdperiph lib,cmsis等+ ld复制了所有必需的文件),之后我添加了文件,通过删除未使用的文件并设置-Os标志来优化构建,这似乎适用于我,但是固件大小几乎太大了。我会尝试您的解释)