【问题标题】:Why stm32f103's elf file works well, but binary not?为什么stm32f103的elf文件运行良好,二进制不行?
【发布时间】:2019-10-23 14:24:35
【问题描述】:

我正在尝试用完我在 stm32f103 中的固件。所以当我使用opencod+gdb上传调试elf文件时,一切都很好,我的固件正在工作,我可以设置和删除断点。

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

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

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

我试图在上传之前批量擦除我的闪存,它给出了相同的结果

这是我的链接器的 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/

【问题讨论】:

  • 您应该也可以使用 openocd + telnet。并且通过 telnet,您可以使用其他格式的文件。我怀疑这是因为 elf 文件包含很多关于二进制文件去向等的信息,并且对于原始闪存图像只有字节,你必须告诉工具更多,即使你可能这样做了。
  • 另一个可能的问题是您在二进制文件中的入口点错误,但是通过使用 gdb,它启动了您定义它的程序而不是它应该在哪里,向量的反汇编/转储是什么桌子长什么样?
  • 除此之外,您还需要更多信息来了解您已尝试和/或正在尝试做什么,您的二进制文件至少在开始时的样子,以及您需要哪些微小的测试二进制文件试过。 gdb 伤害和帮助一样多,所以在 gdb 上工作只会让你到目前为止,没有它运行你必须弄清楚 gdb 为你做什么而不为你做什么。
  • stlink 与 boot0 无关,boot0 让您进入片上引导加载程序,该引导加载程序通常是 uart,有时是其他,但不是 swd/jtag,除非您在芯片上放置了挂起的二进制文件,否则您随时都可以使用它那么可能无法通过 swd 进入(除非您只是使用 boot0 将其放入非错误/挂起的代码中)。如果你想在 boot0 中使用 cp2102,你需要不同的软件,st 的网站上提供的信息很容易编写你自己的程序员,而且那里有很多。
  • 在尝试了这种其他方式之后,你能回到使用 openocd+gdb 和一个 elf 文件吗?您是否已挂上筹码或能够通过该组合重新获得成功?

标签: arm gdb stm32 firmware openocd


【解决方案1】:

试试这个

.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-whatever-whatever(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>

向量不是奇数,它们是处理程序的地址或加一。如果您没有看到这个,处理器将无法启动。

你说过你有 openocd+gdb 工作,所以要么通过该路径,要么通过 openocd+telnet,或者如果你有其他方式使用 uart 引导加载程序。但是使用重置或开机并为应用程序设置boot0,然后使用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 时钟并使引脚成为 LED 的输出等等。

使用这些程序或您自己的程序,我不使用 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】:

    您是否尝试过使用STM32CubeProgrammer

    它允许您使用 UART、SWD、JTAG 和 USB 对固件进行编程。请先尝试SWD,再尝试UART模式,看看是ST bug还是你的UART接线。

    【讨论】:

    • 我发现了链接器和 ld 文件的问题,但这是一个奇怪的问题。如果我从闪烁模板创建一个新项目,并将其上传到我的 stm32 中,那么一切正常,LED 正在闪烁。如果我使用相同的 ld 文件上传我的固件,则没有任何工作。如果我通过 Keil uVision 构建并上传它,那么一切正常。
    【解决方案3】:

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

    【讨论】:

      猜你喜欢
      • 2017-04-08
      • 1970-01-01
      • 1970-01-01
      • 2020-10-22
      • 2012-07-21
      • 2012-05-15
      • 2015-05-18
      • 2020-06-04
      • 1970-01-01
      相关资源
      最近更新 更多