STM32F2:Makefile,链接脚本和启动文件组合,而没有商业IDE


16

我已经使用STM32F2(特别是开发板上的STM32F217IGH6)工作了大约两个月。到目前为止,我最大的问题与“设置”有关,其中包括makefile,链接脚本和启动文件。

特别是,我无法正确设置我的中断向量表,并且无法调用中断处理程序。ST确实提供了针对商业IDE的示例。相反,我使用了GCC工具链的免费Yagarto重新编译(以及OpenOCD通过JTAG加载图像)。

我的主板(或它的近亲)是否有示例项目,其中包含针对非商业IDE(为调用中断处理程序而设置)的适当的makefile,链接程序脚本和启动文件组合?


2
您应该寻找Cortex M3示例,确切的板卡和处理器对于您所要求的东西并不那么重要。您可能需要修改链接描述文件中的内存布局以及在makefile中进行刷新的方法,但是仅此而已。
starblue 2012年

1
你能把所有这些都放进git repo并放在github之类的东西上吗?
AngryEE 2012年

1
这正是我尝试使用STM之后就停止使用它的原因。如果他们要用讨厌的工具链给我的生活带来困难,那么我将去别的地方。当我为PSoC3和PSoC5尝试IDE时,那是一个天壤之别。
Rocketmagnet 2012年

您致力于Yagarto吗?很好,这是一个很好的问题,但是我熟悉CodeSourcery Lite工具链。对于其他工具链的答案可能可以改编,但不能立即使用。
凯文·维米尔

Answers:


20

http://github.com/dwelch67

尤其是stm32f4和stm32vld,但是其他对您也可能有用。mbed和mbed(cortex-m0)下的mzero目录。

我喜欢保持简单愚蠢的方法,最少的链接器脚本,最少的启动代码等。工作是由代码完成的,而不是由任何特定的工具链完成的。

大多数形式的gcc和binutils(有经验的能力)都可以在这些示例中使用,因为我使用编译器而不是将其作为库调用的资源进行编译,我不使用库存链接程序脚本等。较早的gcc和binutils将不知道较新的thumb2零件,因此可能需要进行一些更改。

我建立了自己的gcc,binutils和llvm / clang,并使用了例如codesourcery(现在是指导者图形,但是您仍然可以获得免费/精简版)。

开始为一个新目标组合一个项目时,需要进行一些分解。特别是要确保项目在所需位置,例如矢量表。

例如看stm32f4d / blinker02。它从vectors.s异常/向量表以及一些asm支持例程开始:

/* vectors.s */
.cpu cortex-m3
.thumb

.word   0x20002000  /* stack top address */
.word   _start      /* 1 Reset */
.word   hang        /* 2 NMI */
.word   hang        /* 3 HardFault */
.word   hang        /* 4 MemManage */
.word   hang        /* 5 BusFault */
.word   hang        /* 6 UsageFault */
.word   hang        /* 7 RESERVED */
.word   hang        /* 8 RESERVED */
.word   hang        /* 9 RESERVED*/
.word   hang        /* 10 RESERVED */
.word   hang        /* 11 SVCall */
.word   hang        /* 12 Debug Monitor */
.word   hang        /* 13 RESERVED */
.word   hang        /* 14 PendSV */
.word   hang        /* 15 SysTick */
.word   hang        /* 16 External Interrupt(0) */
.word   hang        /* 17 External Interrupt(1) */
.word   hang        /* 18 External Interrupt(2) */
.word   hang        /* 19 ...   */

.thumb_func
.global _start
_start:
    /*ldr r0,stacktop */
    /*mov sp,r0*/
    bl notmain
    b hang

.thumb_func
hang:   b .

/*.align
stacktop: .word 0x20001000*/

;@-----------------------
.thumb_func
.globl PUT16
PUT16:
    strh r1,[r0]
    bx lr
;@-----------------------
.thumb_func
.globl PUT32
PUT32:
    str r1,[r0]
    bx lr
;@-----------------------
.thumb_func
.globl GET32
GET32:
    ldr r0,[r0]
    bx lr
;@-----------------------
.thumb_func
.globl GET16
GET16:
    ldrh r0,[r0]
    bx lr

.end

此示例没有中断,但是您需要的其他内容在这里。

blinker02.c包含C代码的主体,以及C入口点,我将其称为notmain()以避免将其称为main(某些编译器在拥有main()时将垃圾添加到二进制文件中)。

将节省您的剪切和粘贴。makefile讲述了有关编译和链接的故事。请注意,我的许多示例从同一代码中编译了两个或多个二进制文件。gcc编译器,llvm的clang编译器,仅thumb和thumb2,不同的优化等。

首先从源文件制作目标文件。

vectors.o : vectors.s
    $(ARMGNU)-as vectors.s -o vectors.o

blinker02.gcc.thumb.o : blinker02.c
    $(ARMGNU)-gcc $(COPS) -mthumb -c blinker02.c -o blinker02.gcc.thumb.o

blinker02.gcc.thumb2.o : blinker02.c
    $(ARMGNU)-gcc $(COPS) -mthumb -mcpu=cortex-m3 -march=armv7-m -c blinker02.c -o blinker02.gcc.thumb2.o

blinker02.gcc.thumb.bin : memmap vectors.o blinker02.gcc.thumb.o
    $(ARMGNU)-ld -o blinker02.gcc.thumb.elf -T memmap vectors.o blinker02.gcc.thumb.o
    $(ARMGNU)-objdump -D blinker02.gcc.thumb.elf > blinker02.gcc.thumb.list
    $(ARMGNU)-objcopy blinker02.gcc.thumb.elf blinker02.gcc.thumb.bin -O binary

blinker02.gcc.thumb2.bin : memmap vectors.o blinker02.gcc.thumb2.o
    $(ARMGNU)-ld -o blinker02.gcc.thumb2.elf -T memmap vectors.o blinker02.gcc.thumb2.o
    $(ARMGNU)-objdump -D blinker02.gcc.thumb2.elf > blinker02.gcc.thumb2.list
    $(ARMGNU)-objcopy blinker02.gcc.thumb2.elf blinker02.gcc.thumb2.bin -O binary

链接程序ld使用了一个链接程序脚本,我称其为memmap,这些脚本可能非常痛苦,有时是有充分理由的,有时则不是。我更喜欢一种方法,一种适合所有尺寸的方法,除了厨房水槽方法之外,所有方法都应适用。

我通常不使用.data(几乎从未使用过),并且此示例不需要.bss,因此这里是链接描述文件,足以将程序(.text)放在该处理器所需的位置,就像我这样使用它。

MEMORY
{
    ram : ORIGIN = 0x08000000, LENGTH = 0x1000
}

SECTIONS
{
    .text : { *(.text*) } > ram
}

我有一个内存区域来定义,关于ram的名称没有什么特别的,您可以将其称为foo或bar或bob或ted,这只是将内存项链接到各部分而已。这些部分定义了诸如.text,.data,.bss,.rodata之类的内容,以及它们在内存映射中的位置。

构建此文件时,您会看到我反汇编所有内容(objdump -D),您会看到此文件

Disassembly of section .text:

08000000 <_start-0x50>:
 8000000:       20002000        andcs   r2, r0, r0
 8000004:       08000051        stmdaeq r0, {r0, r4, r6}
 8000008:       08000057        stmdaeq r0, {r0, r1, r2, r4, r6}
 800000c:       08000057        stmdaeq r0, {r0, r1, r2, r4, r6}
 8000010:       08000057        stmdaeq r0, {r0, r1, r2, r4, r6}

需要注意的关键是左侧的地址是我们想要的地址,vectors.s代码位于二进制文件的第一位(因为它位于ld命令行的第一位,除非您在链接程序脚本中执行某些操作,否则这些项目将显示按它们在ld命令行中的顺序排列)。为了正确引导,必须确保向量表在正确的位置。第一项是我的堆栈地址,很好。第二项是_start的地址,它应该是一个奇数。在标签之前使用.thumb_func会导致这种情况发生,因此您不必做其他难看的事情。

08000050 <_start>:
 8000050:       f000 f822       bl      8000098 <notmain>
 8000054:       e7ff            b.n     8000056 <hang>

08000056 <hang>:
 8000056:       e7fe          

因此0x08000051和0x08000057是_start和hang的正确向量条目。开始调用notmain()

08000098 <notmain>:
 8000098:       b510            push    {

看起来不错(它们在反汇编中不显示奇数地址)。

一切都很好。

跳到示例blinker05,该按钮确实支持中断。并且需要一些内存,因此定义了.bss。

MEMORY
{
    rom : ORIGIN = 0x08000000, LENGTH = 0x100000
    ram : ORIGIN = 0x20000000, LENGTH = 0x1C000
}

SECTIONS
{
    .text : { *(.text*) } > rom
    .bss  : { *(.bss*) } > ram
}

请记住,ram和rom是任意名称,bob和ted,foo和bar都可以正常工作。

不会显示整个vector.s,因为如果您制作完整的皮质,则cortex-m3在向量表中会有成千上万的条目(各核之间可能有所不同,并且可能在同一核内,具体取决于芯片供应商选择的选项)拆卸后的相关部分在这里:

08000000 <_start-0x148>:
 8000000:       20020000        andcs   r0, r2, r0
 8000004:       08000149        stmdaeq r0, {r0, r3, r6, r8}
 8000008:       0800014f        stmdaeq r0, {r0, r1, r2, r3, r6, r8}
...
8000104:       0800014f        stmdaeq r0, {r0, r1, r2, r3, r6, r8}
 8000108:       08000179        stmdaeq r0, {r0, r3, r4, r5, r6, r8}
 800010c:       0800014f        stmdaeq r0, {r0, r1, r2, r3, r6, r8}

需要经过反复试验才能将处理程序准确地放置在正确的位置,并与芯片检查是否需要与该芯片不在同一位置,并且由于中断太多,您可能一直在寻找不同的中断。与普通手臂不同,cortex-m处理器可以做到这一点,因此您无需为中断使用蹦床代码,它们保留一定数量的寄存器并通过链接寄存器内容管理处理器模式的切换。只要硬件和编译器的abi足够接近,它就可以正常工作。在这种情况下,我使用C语言处理程序,与其他平台不同,过去您不需要对编译器/语法做任何特殊的事情,只是创建一个函数(但不要在函数/处理程序中做愚蠢的事情)

//-------------------------------------------------------------------
volatile unsigned int intcounter;
//-------------------------------------------------------------------
// CAREFUL, THIS IS AN INTERRUPT HANDLER
void tim5_handler ( void )
{
    intcounter++;
    PUT32(TIM5BASE+0x10,0x00000000);
}
// CAREFUL, THIS IS AN INTERRUPT HANDLER
//-------------------------------------------------------------------

blinker05的makefile应该类似于blinker02的示例,大多数情况下都是剪切和粘贴。将单个源文件转换为对象,然后链接。我确实使用gcc和clang为thumb,thumb2构建。您可以更改all:行,仅在不涉及/不希望使用clang(llvm)时才包含gcc项。我使用binutils汇编并链接clang输出btw。

所有这些项目都使用免费的,现成的开源工具。没有IDE,仅命令行。是的,我只使用Linux而不是Windows,但这些工具也可供Windows用户使用,将rm -f等内容更改为makefile中的某些内容,如在Windows上构建时的内容。或在vmware或virtualbox或qemu上运行linux。不使用IDE意味着您也要选择文本编辑器,我不会说的,我有我的最爱。请注意,gnu make程序的一个非常烦人的功能是它需要makefile中的实际制表符,我非常讨厌看不见的制表符。因此,一个文本编辑器用于保留制表符的makefile文件,另一个文本编辑器用于制造空格的源代码。我不知道窗户,

我希望这会有所帮助,不是确切的芯片/板,而是cortex-m4孔m4而不是m3,对于本次讨论而言足够接近。请参阅mbed或stm32vld目录以获取实际的cortex-m3(与m4的makefile和启动代码等差异不大),但不是由st。制作的。各个供应商的cortex-m3内核应该相同,cortex-m3和cortex-m4都是ARMv7m,并且距离更近而不是不同。cortex-m0是ARMv6m,几乎没有足以烦恼的thumb2指令,编译器还没有赶上它,因此只能使用thumb(如果需要,可以假装您正在构建ARMv4T(仅拇指))。我的拇指模拟器仅是拇指,没有拇指2,它对您也可能有用,我认为我使它以某种形式或方式执行中断。


我正在阅读答案,我猜想答案的作者是你。您的回答对我有很大帮助,并促使我转向ARM处理器,而不是成为AVR和PIC Fanboy。谢谢
MaNyYaCk

欢迎您...向前付款...
old_timer '17

2

您可以在这个站点上尝试解释该链接器和low_level_init代码的基础知识。

请注意,该页面着重于描述问题,因此nvic向量是最小的。

然后,在“ STM32F2xx标准外设库”中有一个更完整的示例,只需查看gcc部分(因为Yagarto基于gcc)。那里有示例代码,可以帮助您正确设置nvic(中断向量表)。

因此,即使这不是一个完整的答案,我还是希望它能有所帮助。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.